<commit_before>package charmap

import (
	"strconv"
	"strings"
)

// Private types for rune and string slices
type unicodeSequence []string
type runeSequence []rune

type sequenceIndex interface {
	index(char interface{}) int
}

// Private map to hold all sequences
type charMap map[string]sequenceIndex

type UnknownCharError struct {
	char    interface{}
	lang    string
	message string
}

func (e *UnknownCharError) Error() string {
	var returnString string

	switch e.char.(type) {
	case rune:
		returnString = strconv.QuoteRune(e.char.(rune))
	case string:
		returnString = e.char.(string)
	}

	if len(e.lang) == 0 {
		return returnString + " : " + e.message
	}

	return returnString + " " + e.message + " " + e.lang
}

// Languagewise unicode ranges
var langBases = map[string]int{
	"en_US": 0,
	"en_IN": 0,
	"hi_IN": '\u0901',
	"bn_IN": '\u0981',
	"pa_IN": '\u0a01',
	"gu_IN": '\u0a81',
	"or_IN": '\u0b01',
	"ta_IN": '\u0b81',
	"te_IN": '\u0c01',
	"kn_IN": '\u0c81',
	"ml_IN": '\u0D01',
}

// Slices to hold unicode range for each languagges
var devaAlphabets = make(runeSequence, 80)
var bengAlphabets = make(runeSequence, 80)
var guruAlphabets = make(runeSequence, 80)
var gujrAlphabets = make(runeSequence, 80)
var oryaAlphabets = make(runeSequence, 80)
var tamlAlphabets = make(runeSequence, 80)
var teluAlphabets = make(runeSequence, 80)
var kndaAlphabets = make(runeSequence, 80)
var mlymAlphabets = make(runeSequence, 80)

var enUsAlphabets = runeSequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}

// Soundex values for English alphabet series
var soundexEnglish = runeSequence{'0', '1', '2', '3', '0', '1', '2', '0', '0', '2', '2', '4', '5', '5', '0', '1', '2', '6', '2', '3', '0', '1', '0', '2', '0', '2'}

// Soundex values for Indian language unicode series.
var soundexIndic = runeSequence{'0', 'N', '0', '0', 'A', 'A', 'B', 'B', 'C', 'C', 'P', 'Q', '0', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'H', 'H', 'H', 'H', 'G', 'I', 'I', 'I', 'I', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'O', 'P', 'P', 'Q', 'Q', 'Q', 'R', 'S', 'S', 'S', 'T', '0', '0', '0', '0', 'A', 'B', 'B', 'C', 'C', 'P', 'P', 'E', 'D', 'D', 'D', 'D', 'E', 'E', 'E', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'E', '0', '0', '0', '0', '0', '0', '0', '0', 'P', 'Q', 'Q', 'Q', '0', '0', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'J', 'J', 'Q', 'P', 'P', 'F'}

// ISO15919 series specific to Indian languages
var iso15919IndicSeries = unicodeSequence{`m̐`, `ṁ`, `ḥ`, ``, `a`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ḷ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, `ka`, `kha`, `ga`, `gha`, `ṅa`, `ca`, `cha`, `ja`, `jha`, `ña`, `ṭa`, `ṭha`, `ḍa`, `ḍha`, `ṇa`, `ta`, `tha`, `da`, `dha`, `na`, `ṉa`, `pa`, `pha`, `ba`, `bha`, `ma`, `ya`, `ra`, `ṟa`, `la`, `ḷa`, `ḻa`, `va`, `śa`, `ṣa`, `sa`, `ha`, ``, ``, ``, `'`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ṝ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, ``, ``, ``, `oṃ`, ``, ``, ``, ``, ``, ``, ``, `qa`, `ḵẖa`, `ġ`, `za`, `ṛa`, `ṛha`, `fa`, `ẏa`, `ṝ`, `ḹ`, `ḷ`, `ḹ`, `.`, `..`, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `…`, ``, ``, ``, ``, ``, ``, ``}

// IPA series specific for Indian languages
var ipaIndicSeries = unicodeSequence{`m`, `m`, ``, ``, `ə`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `æ`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, `kə`, `kʰə`, `gə`, `gʱə`, `ŋə`, `ʧə`, `ʧʰə`, `ʤə`, `ʤʱə`, `ɲə`, `ʈə`, `ʈʰə`, `ɖə`, `ɖʱə`, `ɳə`, `t̪ə`, `t̪ʰə`, `d̪ə`, `d̪ʱə`, `n̪ə`, `nə`, `pə`, `pʰə`, `bə`, `bʱə`, `mə`, `jə`, `ɾə`, `rə`, `lə`, `ɭə`, `ɻə`, `ʋə`, `ɕə`, `ʂə`, `sə`, `ɦə`, ``, ``, ``, `ഽ`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, `r̩ː`, `l̩ː`, ``, ``, ``, ``, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `൰`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``}

// Map to hold rune sequence of each languages
var langMap = charMap{
	"hi_IN": devaAlphabets,
	"bn_IN": bengAlphabets,
	"pa_IN": guruAlphabets,
	"gu_IN": gujrAlphabets,
	"or_IN": oryaAlphabets,
	"ta_IN": tamlAlphabets,
	"te_IN": teluAlphabets,
	"kn_IN": kndaAlphabets,
	"ml_IN": mlymAlphabets,
}

func initializeUnicodeRange(slice runeSequence, begin int) {
	for i := 0; i < len(slice); i++ {
		slice[i] = rune(begin + i)
	}
}

func init() {
	for key, value := range langMap {
		initializeUnicodeRange(value.(runeSequence), langBases[key])
	}

	langMap["soundex_en"] = soundexEnglish
	langMap["soundex_in"] = soundexIndic
	langMap["ISO15919"] = iso15919IndicSeries
	langMap["IPA"] = ipaIndicSeries
	langMap["en_US"] = enUsAlphabets
}

func (r unicodeSequence) index(char string) int {
	for i, value := range r {
		if value == char {
			return i
		}
	}

	return -1
}

func LanguageOf(char string) string {
	for lang, langRange := range langMap {
		if langRange.index(char) != -1 {
			return lang
		}
	}
	// Still not found then something wrong
	return "unknown"
}

func CharCompare(char1, char2 string) bool {

	if char1 == char2 {
		return true
	}

	char1Index := langMap[LanguageOf(char1)].index(char1)
	char2Index := langMap[LanguageOf(char2)].index(char2)

	if char1Index == char2Index {
		return true
	}

	return false
}

func SoundexCode(char string) (string, error) {
	var lang string
	char = strings.ToLower(char)
	if lang = LanguageOf(char); lang != "unknown" {
		if charIndex := langMap[lang].index(char); charIndex != -1 {
			var sequence unicodeSequence

			switch lang {
			case "en_US":
				sequence = langMap["soundex_en"].(unicodeSequence)
			default:
				sequence = langMap["soundex_in"].(unicodeSequence)
			}
			return sequence[charIndex], nil
		}
		return "0", &UnknownCharError{char, lang, "not found"}
	}
	return "0", &UnknownCharError{char, lang, "unknown language"}
}
<commit_msg>Generic interface{} type arguments and runeSequence usage implemented<commit_after>package charmap

import (
	"strconv"
	"strings"
)

// Private types for rune and string slices
type unicodeSequence []string
type runeSequence []rune

type sequenceIndex interface {
	index(char interface{}) int
}

// Private map to hold all sequences
type charMap map[string]sequenceIndex

type UnknownCharError struct {
	char    interface{}
	lang    string
	message string
}

func (e *UnknownCharError) Error() string {
	var returnString string

	switch e.char.(type) {
	case rune:
		returnString = strconv.QuoteRune(e.char.(rune))
	case string:
		returnString = e.char.(string)
	}

	if len(e.lang) == 0 {
		return returnString + " : " + e.message
	}

	return returnString + " " + e.message + " " + e.lang
}

// Languagewise unicode ranges
var langBases = map[string]int{
	"en_US": 0,
	"en_IN": 0,
	"hi_IN": '\u0901',
	"bn_IN": '\u0981',
	"pa_IN": '\u0a01',
	"gu_IN": '\u0a81',
	"or_IN": '\u0b01',
	"ta_IN": '\u0b81',
	"te_IN": '\u0c01',
	"kn_IN": '\u0c81',
	"ml_IN": '\u0D01',
}

// Slices to hold unicode range for each languagges
var devaAlphabets = make(runeSequence, 80)
var bengAlphabets = make(runeSequence, 80)
var guruAlphabets = make(runeSequence, 80)
var gujrAlphabets = make(runeSequence, 80)
var oryaAlphabets = make(runeSequence, 80)
var tamlAlphabets = make(runeSequence, 80)
var teluAlphabets = make(runeSequence, 80)
var kndaAlphabets = make(runeSequence, 80)
var mlymAlphabets = make(runeSequence, 80)

var enUsAlphabets = runeSequence{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}

// Soundex values for English alphabet series
var soundexEnglish = runeSequence{'0', '1', '2', '3', '0', '1', '2', '0', '0', '2', '2', '4', '5', '5', '0', '1', '2', '6', '2', '3', '0', '1', '0', '2', '0', '2'}

// Soundex values for Indian language unicode series.
var soundexIndic = runeSequence{'0', 'N', '0', '0', 'A', 'A', 'B', 'B', 'C', 'C', 'P', 'Q', '0', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'H', 'H', 'H', 'H', 'G', 'I', 'I', 'I', 'I', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'O', 'P', 'P', 'Q', 'Q', 'Q', 'R', 'S', 'S', 'S', 'T', '0', '0', '0', '0', 'A', 'B', 'B', 'C', 'C', 'P', 'P', 'E', 'D', 'D', 'D', 'D', 'E', 'E', 'E', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'E', '0', '0', '0', '0', '0', '0', '0', '0', 'P', 'Q', 'Q', 'Q', '0', '0', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'J', 'J', 'Q', 'P', 'P', 'F'}

// ISO15919 series specific to Indian languages
var iso15919IndicSeries = unicodeSequence{`m̐`, `ṁ`, `ḥ`, ``, `a`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ḷ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, `ka`, `kha`, `ga`, `gha`, `ṅa`, `ca`, `cha`, `ja`, `jha`, `ña`, `ṭa`, `ṭha`, `ḍa`, `ḍha`, `ṇa`, `ta`, `tha`, `da`, `dha`, `na`, `ṉa`, `pa`, `pha`, `ba`, `bha`, `ma`, `ya`, `ra`, `ṟa`, `la`, `ḷa`, `ḻa`, `va`, `śa`, `ṣa`, `sa`, `ha`, ``, ``, ``, `'`, `ā`, `i`, `ī`, `u`, `ū`, `ṛ`, `ṝ`, `ê`, `e`, `ē`, `ai`, `ô`, `o`, `ō`, `au`, ``, ``, ``, `oṃ`, ``, ``, ``, ``, ``, ``, ``, `qa`, `ḵẖa`, `ġ`, `za`, `ṛa`, `ṛha`, `fa`, `ẏa`, `ṝ`, `ḹ`, `ḷ`, `ḹ`, `.`, `..`, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `…`, ``, ``, ``, ``, ``, ``, ``}

// IPA series specific for Indian languages
var ipaIndicSeries = unicodeSequence{`m`, `m`, ``, ``, `ə`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `æ`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, `kə`, `kʰə`, `gə`, `gʱə`, `ŋə`, `ʧə`, `ʧʰə`, `ʤə`, `ʤʱə`, `ɲə`, `ʈə`, `ʈʰə`, `ɖə`, `ɖʱə`, `ɳə`, `t̪ə`, `t̪ʰə`, `d̪ə`, `d̪ʱə`, `n̪ə`, `nə`, `pə`, `pʰə`, `bə`, `bʱə`, `mə`, `jə`, `ɾə`, `rə`, `lə`, `ɭə`, `ɻə`, `ʋə`, `ɕə`, `ʂə`, `sə`, `ɦə`, ``, ``, ``, `ഽ`, `aː`, `i`, `iː`, `u`, `uː`, `r̩`, `l̩`, `e`, `eː`, `ɛː`, `ɔ`, `o`, `oː`, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, `ow`, ``, ``, ``, ``, ``, ``, ``, ``, `r̩ː`, `l̩ː`, ``, ``, ``, ``, `0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `൰`, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``}

// Map to hold rune sequence of each languages
var langMap = charMap{
	"hi_IN": devaAlphabets,
	"bn_IN": bengAlphabets,
	"pa_IN": guruAlphabets,
	"gu_IN": gujrAlphabets,
	"or_IN": oryaAlphabets,
	"ta_IN": tamlAlphabets,
	"te_IN": teluAlphabets,
	"kn_IN": kndaAlphabets,
	"ml_IN": mlymAlphabets,
}

func initializeUnicodeRange(slice runeSequence, begin int) {
	for i := 0; i < len(slice); i++ {
		slice[i] = rune(begin + i)
	}
}

func init() {
	for key, value := range langMap {
		initializeUnicodeRange(value.(runeSequence), langBases[key])
	}

	langMap["soundex_en"] = soundexEnglish
	langMap["soundex_in"] = soundexIndic
	langMap["ISO15919"] = iso15919IndicSeries
	langMap["IPA"] = ipaIndicSeries
	langMap["en_US"] = enUsAlphabets
}

func (r unicodeSequence) index(char interface{}) int {
	for i, value := range r {
		if value == char {
			return i
		}
	}

	return -1
}

func (r runeSequence) index(char interface{}) int {

	for i, value := range r {
		if value == char.(rune) {
			return i
		}
	}

	return -1
}

func LanguageOf(char interface{}) string {
	for lang, langRange := range langMap {
		if langRange.index(char) != -1 {
			return lang
		}
	}
	// Still not found then something wrong
	return "unknown"
}

func CharCompare(char1, char2 interface{}) bool {

	if char1 == char2 {
		return true
	}

	char1Index := langMap[LanguageOf(char1)].index(char1)
	char2Index := langMap[LanguageOf(char2)].index(char2)

	if char1Index == char2Index {
		return true
	}

	return false
}

func SoundexCode(char interface{}) (rune, error) {
	var lang string

	switch char.(type) {
	case string:
		char = strings.ToLower(char.(string))
	}

	if lang = LanguageOf(char); lang != "unknown" {
		if charIndex := langMap[lang].index(char); charIndex != -1 {
			var sequence runeSequence

			switch lang {
			case "en_US":
				sequence = langMap["soundex_en"].(runeSequence)
			default:
				sequence = langMap["soundex_in"].(runeSequence)
			}
			return sequence[charIndex], nil
		}
		return '0', &UnknownCharError{char, lang, "not found"}
	}
	return '0', &UnknownCharError{char, lang, "unknown language"}
}
<|endoftext|>


<commit_before>package qmp

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/digitalocean/go-qemu/qmp"

	"github.com/lxc/lxd/shared"
)

var monitors = map[string]*Monitor{}
var monitorsLock sync.Mutex

// RingbufSize is the size of the agent serial ringbuffer in bytes
var RingbufSize = 16

// Monitor represents a QMP monitor.
type Monitor struct {
	path string
	qmp  *qmp.SocketMonitor

	agentReady    bool
	disconnected  bool
	chDisconnect  chan struct{}
	eventHandler  func(name string, data map[string]interface{})
	serialCharDev string
}

// Connect creates or retrieves an existing QMP monitor for the path.
func Connect(path string, serialCharDev string, eventHandler func(name string, data map[string]interface{})) (*Monitor, error) {
	monitorsLock.Lock()
	defer monitorsLock.Unlock()

	// Look for an existing monitor.
	monitor, ok := monitors[path]
	if ok {
		monitor.eventHandler = eventHandler
		return monitor, nil
	}

	// Setup the connection.
	qmpConn, err := qmp.NewSocketMonitor("unix", path, time.Second)
	if err != nil {
		return nil, err
	}

	err = qmpConn.Connect()
	if err != nil {
		return nil, err
	}

	// Setup the monitor struct.
	monitor = &Monitor{}
	monitor.path = path
	monitor.qmp = qmpConn
	monitor.chDisconnect = make(chan struct{}, 1)
	monitor.eventHandler = eventHandler
	monitor.serialCharDev = serialCharDev

	// Spawn goroutines.
	err = monitor.run()
	if err != nil {
		return nil, err
	}

	// Register in global map.
	monitors[path] = monitor

	return monitor, nil
}

func (m *Monitor) run() error {
	// Ringbuffer monitoring function.
	checkBuffer := func() {
		// Read the ringbuffer.
		resp, err := m.qmp.Run([]byte(fmt.Sprintf(`{"execute": "ringbuf-read", "arguments": {"device": "%s", "size": %d, "format": "utf8"}}`, m.serialCharDev, RingbufSize)))
		if err != nil {
			// Failure to send a command, assume disconnected/crashed.
			m.Disconnect()
			return
		}

		// Decode the response.
		var respDecoded struct {
			Return string `json:"return"`
		}

		err = json.Unmarshal(resp, &respDecoded)
		if err != nil {
			// Received bad data, assume disconnected/crashed.
			m.Disconnect()
			return
		}

		// Extract the last entry.
		entries := strings.Split(respDecoded.Return, "\n")
		if len(entries) > 1 {
			status := entries[len(entries)-2]

			if status == "STARTED" {
				m.agentReady = true
			} else if status == "STOPPED" {
				m.agentReady = false
			}
		}
	}

	// Start event monitoring go routine.
	chEvents, err := m.qmp.Events()
	if err != nil {
		return err
	}

	go func() {
		// Initial read from the ringbuffer.
		go checkBuffer()

		for {
			// Wait for an event, disconnection or timeout.
			select {
			case <-m.chDisconnect:
				return
			case e := <-chEvents:
				if e.Event == "" {
					continue
				}

				if m.eventHandler != nil {
					go m.eventHandler(e.Event, e.Data)
				}

				// Check if the ringbuffer was updated (non-blocking).
				go checkBuffer()
			case <-time.After(10 * time.Second):
				// Check if the ringbuffer was updated (non-blocking).
				go checkBuffer()

				continue
			}
		}
	}()

	return nil
}

// Wait returns a channel that will be closed on disconnection.
func (m *Monitor) Wait() (chan struct{}, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	return m.chDisconnect, nil
}

// Disconnect forces a disconnection from QEMU.
func (m *Monitor) Disconnect() {
	// Stop all go routines and disconnect from socket.
	if !m.disconnected {
		close(m.chDisconnect)
	}
	m.disconnected = true
	m.qmp.Disconnect()

	// Remove from the map.
	monitorsLock.Lock()
	defer monitorsLock.Unlock()
	delete(monitors, m.path)
}

// Status returns the current VM status.
func (m *Monitor) Status() (string, error) {
	// Check if disconnected
	if m.disconnected {
		return "", ErrMonitorDisconnect
	}

	// Query the status.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-status'}"))
	if err != nil {
		m.Disconnect()
		return "", ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			Status string `json:"status"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return "", ErrMonitorBadReturn
	}

	return respDecoded.Return.Status, nil
}

// Console fetches the File for a particular console.
func (m *Monitor) Console(target string) (*os.File, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	// Query the consoles.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-chardev'}"))
	if err != nil {
		m.Disconnect()
		return nil, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return []struct {
			Label    string `json:"label"`
			Filename string `json:"filename"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return nil, ErrMonitorBadReturn
	}

	// Look for the requested console.
	for _, v := range respDecoded.Return {
		if v.Label == target {
			ptyPath := strings.TrimPrefix(v.Filename, "pty:")

			if !shared.PathExists(ptyPath) {
				continue
			}

			// Open the PTS device
			console, err := os.OpenFile(ptyPath, os.O_RDWR, 0600)
			if err != nil {
				return nil, err
			}

			return console, nil
		}
	}

	return nil, ErrMonitorBadConsole
}

func (m *Monitor) runCmd(cmd string) error {
	// Check if disconnected
	if m.disconnected {
		return ErrMonitorDisconnect
	}

	// Query the status.
	_, err := m.qmp.Run([]byte(fmt.Sprintf("{'execute': '%s'}", cmd)))
	if err != nil {
		m.Disconnect()
		return ErrMonitorDisconnect
	}

	return nil
}

// Powerdown tells the VM to gracefully shutdown.
func (m *Monitor) Powerdown() error {
	return m.runCmd("system_powerdown")
}

// Start tells QEMU to start the emulation.
func (m *Monitor) Start() error {
	return m.runCmd("cont")
}

// Pause tells QEMU to temporarily stop the emulation.
func (m *Monitor) Pause() error {
	return m.runCmd("stop")
}

// Quit tells QEMU to exit immediately.
func (m *Monitor) Quit() error {
	return m.runCmd("quit")
}

// AgentReady indicates whether an agent has been detected.
func (m *Monitor) AgentReady() bool {
	return m.agentReady
}

// GetCPUs fetches the vCPU information for pinning.
func (m *Monitor) GetCPUs() ([]int, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	// Query the consoles.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-cpus'}"))
	if err != nil {
		m.Disconnect()
		return nil, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return []struct {
			CPU int `json:"CPU"`
			PID int `json:"thread_id"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return nil, ErrMonitorBadReturn
	}

	// Make a slice of PIDs.
	pids := []int{}
	for _, cpu := range respDecoded.Return {
		pids = append(pids, cpu.PID)
	}

	return pids, nil
}

// GetMemorySizeBytes returns the current size of the base memory in bytes.
func (m *Monitor) GetMemorySizeBytes() (int64, error) {
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-memory-size-summary'}"))
	if err != nil {
		m.Disconnect()
		return -1, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			BaseMemory int64 `json:"base-memory"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return -1, ErrMonitorBadReturn
	}

	return respDecoded.Return.BaseMemory, nil
}

// GetMemoryBalloonSizeBytes returns effective size of the memory in bytes (considering the current balloon size).
func (m *Monitor) GetMemoryBalloonSizeBytes() (int64, error) {
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-balloon'}"))
	if err != nil {
		m.Disconnect()
		return -1, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			Actual int64 `json:"actual"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return -1, ErrMonitorBadReturn
	}

	return respDecoded.Return.Actual, nil
}

// SetMemoryBalloonSizeBytes sets the size of the memory in bytes (which will resize the balloon as needed).
func (m *Monitor) SetMemoryBalloonSizeBytes(sizeBytes int64) error {
	respRaw, err := m.qmp.Run([]byte(fmt.Sprintf("{'execute': 'balloon', 'arguments': {'value': %d}}", sizeBytes)))
	if err != nil {
		m.Disconnect()
		return ErrMonitorDisconnect
	}

	if string(respRaw) != `{"return": {}}` {
		return ErrMonitorBadReturn
	}

	return nil
}
<commit_msg>lxd/instance/qmp: Update for go-qmp change<commit_after>package qmp

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/digitalocean/go-qemu/qmp"

	"github.com/lxc/lxd/shared"
)

var monitors = map[string]*Monitor{}
var monitorsLock sync.Mutex

// RingbufSize is the size of the agent serial ringbuffer in bytes
var RingbufSize = 16

// Monitor represents a QMP monitor.
type Monitor struct {
	path string
	qmp  *qmp.SocketMonitor

	agentReady    bool
	disconnected  bool
	chDisconnect  chan struct{}
	eventHandler  func(name string, data map[string]interface{})
	serialCharDev string
}

// Connect creates or retrieves an existing QMP monitor for the path.
func Connect(path string, serialCharDev string, eventHandler func(name string, data map[string]interface{})) (*Monitor, error) {
	monitorsLock.Lock()
	defer monitorsLock.Unlock()

	// Look for an existing monitor.
	monitor, ok := monitors[path]
	if ok {
		monitor.eventHandler = eventHandler
		return monitor, nil
	}

	// Setup the connection.
	qmpConn, err := qmp.NewSocketMonitor("unix", path, time.Second)
	if err != nil {
		return nil, err
	}

	err = qmpConn.Connect()
	if err != nil {
		return nil, err
	}

	// Setup the monitor struct.
	monitor = &Monitor{}
	monitor.path = path
	monitor.qmp = qmpConn
	monitor.chDisconnect = make(chan struct{}, 1)
	monitor.eventHandler = eventHandler
	monitor.serialCharDev = serialCharDev

	// Spawn goroutines.
	err = monitor.run()
	if err != nil {
		return nil, err
	}

	// Register in global map.
	monitors[path] = monitor

	return monitor, nil
}

func (m *Monitor) run() error {
	// Ringbuffer monitoring function.
	checkBuffer := func() {
		// Read the ringbuffer.
		resp, err := m.qmp.Run([]byte(fmt.Sprintf(`{"execute": "ringbuf-read", "arguments": {"device": "%s", "size": %d, "format": "utf8"}}`, m.serialCharDev, RingbufSize)))
		if err != nil {
			// Failure to send a command, assume disconnected/crashed.
			m.Disconnect()
			return
		}

		// Decode the response.
		var respDecoded struct {
			Return string `json:"return"`
		}

		err = json.Unmarshal(resp, &respDecoded)
		if err != nil {
			// Received bad data, assume disconnected/crashed.
			m.Disconnect()
			return
		}

		// Extract the last entry.
		entries := strings.Split(respDecoded.Return, "\n")
		if len(entries) > 1 {
			status := entries[len(entries)-2]

			if status == "STARTED" {
				m.agentReady = true
			} else if status == "STOPPED" {
				m.agentReady = false
			}
		}
	}

	// Start event monitoring go routine.
	chEvents, err := m.qmp.Events(context.Background())
	if err != nil {
		return err
	}

	go func() {
		// Initial read from the ringbuffer.
		go checkBuffer()

		for {
			// Wait for an event, disconnection or timeout.
			select {
			case <-m.chDisconnect:
				return
			case e := <-chEvents:
				if e.Event == "" {
					continue
				}

				if m.eventHandler != nil {
					go m.eventHandler(e.Event, e.Data)
				}

				// Check if the ringbuffer was updated (non-blocking).
				go checkBuffer()
			case <-time.After(10 * time.Second):
				// Check if the ringbuffer was updated (non-blocking).
				go checkBuffer()

				continue
			}
		}
	}()

	return nil
}

// Wait returns a channel that will be closed on disconnection.
func (m *Monitor) Wait() (chan struct{}, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	return m.chDisconnect, nil
}

// Disconnect forces a disconnection from QEMU.
func (m *Monitor) Disconnect() {
	// Stop all go routines and disconnect from socket.
	if !m.disconnected {
		close(m.chDisconnect)
	}
	m.disconnected = true
	m.qmp.Disconnect()

	// Remove from the map.
	monitorsLock.Lock()
	defer monitorsLock.Unlock()
	delete(monitors, m.path)
}

// Status returns the current VM status.
func (m *Monitor) Status() (string, error) {
	// Check if disconnected
	if m.disconnected {
		return "", ErrMonitorDisconnect
	}

	// Query the status.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-status'}"))
	if err != nil {
		m.Disconnect()
		return "", ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			Status string `json:"status"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return "", ErrMonitorBadReturn
	}

	return respDecoded.Return.Status, nil
}

// Console fetches the File for a particular console.
func (m *Monitor) Console(target string) (*os.File, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	// Query the consoles.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-chardev'}"))
	if err != nil {
		m.Disconnect()
		return nil, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return []struct {
			Label    string `json:"label"`
			Filename string `json:"filename"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return nil, ErrMonitorBadReturn
	}

	// Look for the requested console.
	for _, v := range respDecoded.Return {
		if v.Label == target {
			ptyPath := strings.TrimPrefix(v.Filename, "pty:")

			if !shared.PathExists(ptyPath) {
				continue
			}

			// Open the PTS device
			console, err := os.OpenFile(ptyPath, os.O_RDWR, 0600)
			if err != nil {
				return nil, err
			}

			return console, nil
		}
	}

	return nil, ErrMonitorBadConsole
}

func (m *Monitor) runCmd(cmd string) error {
	// Check if disconnected
	if m.disconnected {
		return ErrMonitorDisconnect
	}

	// Query the status.
	_, err := m.qmp.Run([]byte(fmt.Sprintf("{'execute': '%s'}", cmd)))
	if err != nil {
		m.Disconnect()
		return ErrMonitorDisconnect
	}

	return nil
}

// Powerdown tells the VM to gracefully shutdown.
func (m *Monitor) Powerdown() error {
	return m.runCmd("system_powerdown")
}

// Start tells QEMU to start the emulation.
func (m *Monitor) Start() error {
	return m.runCmd("cont")
}

// Pause tells QEMU to temporarily stop the emulation.
func (m *Monitor) Pause() error {
	return m.runCmd("stop")
}

// Quit tells QEMU to exit immediately.
func (m *Monitor) Quit() error {
	return m.runCmd("quit")
}

// AgentReady indicates whether an agent has been detected.
func (m *Monitor) AgentReady() bool {
	return m.agentReady
}

// GetCPUs fetches the vCPU information for pinning.
func (m *Monitor) GetCPUs() ([]int, error) {
	// Check if disconnected
	if m.disconnected {
		return nil, ErrMonitorDisconnect
	}

	// Query the consoles.
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-cpus'}"))
	if err != nil {
		m.Disconnect()
		return nil, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return []struct {
			CPU int `json:"CPU"`
			PID int `json:"thread_id"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return nil, ErrMonitorBadReturn
	}

	// Make a slice of PIDs.
	pids := []int{}
	for _, cpu := range respDecoded.Return {
		pids = append(pids, cpu.PID)
	}

	return pids, nil
}

// GetMemorySizeBytes returns the current size of the base memory in bytes.
func (m *Monitor) GetMemorySizeBytes() (int64, error) {
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-memory-size-summary'}"))
	if err != nil {
		m.Disconnect()
		return -1, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			BaseMemory int64 `json:"base-memory"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return -1, ErrMonitorBadReturn
	}

	return respDecoded.Return.BaseMemory, nil
}

// GetMemoryBalloonSizeBytes returns effective size of the memory in bytes (considering the current balloon size).
func (m *Monitor) GetMemoryBalloonSizeBytes() (int64, error) {
	respRaw, err := m.qmp.Run([]byte("{'execute': 'query-balloon'}"))
	if err != nil {
		m.Disconnect()
		return -1, ErrMonitorDisconnect
	}

	// Process the response.
	var respDecoded struct {
		Return struct {
			Actual int64 `json:"actual"`
		} `json:"return"`
	}

	err = json.Unmarshal(respRaw, &respDecoded)
	if err != nil {
		return -1, ErrMonitorBadReturn
	}

	return respDecoded.Return.Actual, nil
}

// SetMemoryBalloonSizeBytes sets the size of the memory in bytes (which will resize the balloon as needed).
func (m *Monitor) SetMemoryBalloonSizeBytes(sizeBytes int64) error {
	respRaw, err := m.qmp.Run([]byte(fmt.Sprintf("{'execute': 'balloon', 'arguments': {'value': %d}}", sizeBytes)))
	if err != nil {
		m.Disconnect()
		return ErrMonitorDisconnect
	}

	if string(respRaw) != `{"return": {}}` {
		return ErrMonitorBadReturn
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_logrus

import (
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc/grpclog"
)

// ReplaceGrpcLogger sets the given logrus.Logger as a gRPC-level logger.
// This should be called *before* any other initialization, preferably from init() functions.
func ReplaceGrpcLogger(logger *logrus.Entry) {
	grpclog.SetLogger(logger.WithField("system", SystemField))
}
<commit_msg>adding v2 grpc logger (#234)<commit_after>// Copyright 2017 Michal Witkowski. All Rights Reserved.
// See LICENSE for licensing terms.

package grpc_logrus

import (
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc/grpclog"
)

// ReplaceGrpcLogger sets the given logrus.Logger as a gRPC-level logger.
// This should be called *before* any other initialization, preferably from init() functions.
func ReplaceGrpcLogger(logger *logrus.Entry) {
	grpclog.SetLoggerV2(&logrusGrpcLoggerV2{
		logger.WithField("system", SystemField),
	})
}

type logrusGrpcLoggerV2 struct {
	*logrus.Entry
}

func (l *logrusGrpcLoggerV2) V(level int) bool {
	return int(l.Level) >= level
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dchest/uniuri"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
)

type ApiResponse struct {
	Visits  int64 `json:"visits"`
	Uniques int64 `json:"uniques"`
}

const cookieMaxAge = 60 * 60 * 60 * 24 * 30

func uid(w http.ResponseWriter, req *http.Request) string {
	cookie, err := req.Cookie("uid")
	if err != nil {
		switch err {
		case http.ErrNoCookie:
			uid := fmt.Sprintf("%s", uniuri.New())
			now := time.Now()
			new_cookie := &http.Cookie{Name: "uid", Value: uid, MaxAge: cookieMaxAge, Expires: now.Add(cookieMaxAge)}
			log.Print("Setting new cookie ", new_cookie)
			http.SetCookie(w, new_cookie)
			return uid
		default:
			log.Fatal(err)
			return ""
		}
	}
	return cookie.Value
}

func track(objectId string, uid string) {
	log.Print("Tracking ", uid, " on ", objectId)
	conn := pool.Get()
	defer conn.Close()

	// http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining
	conn.Send("MULTI")

	// Track the number of unique visitors in a HyperLogLog
	// http://redis.io/commands/pfadd
	conn.Send("PFADD", "hll_"+objectId, uid)

	// Track the total number of visits in a simple key (stringy)
	// http://redis.io/commands/incr
	conn.Send("INCR", "str_"+objectId)

	_, err := conn.Do("EXEC")
	if err != nil {
		log.Print(err)
	}
}

func beaconHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	query, _ := url.ParseQuery(req.URL.RawQuery)
	objectId := query.Get("id")
	if objectId != "" {
		go track(objectId, uid(w, req))
	}
	http.ServeFile(w, req, path.Join("images", "beacon.png"))
}

func indexHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	if req.URL.Path == "/" {
		http.ServeFile(w, req, path.Join("index.html"))
	} else {
		http.NotFound(w, req)
	}
}

func apiHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	switch req.Method {
	case "GET":
		apiGetHandler(w, req)
	case "POST":
		apiPostHandler(w, req)
	default:
		http.Error(w, "Expected GET or POST", http.StatusMethodNotAllowed)
	}
}

func apiObjectId(path string) (string, error) {
	path = strings.TrimSuffix(path, "/")
	elements := strings.SplitN(path, "/", 3)
	if len(elements) != 3 {
		return "", errors.New("Object Id not found in path")
	}
	return elements[2], nil
}

func apiGetHandler(w http.ResponseWriter, req *http.Request) {
	objectId, err := apiObjectId(req.URL.Path)
	if err != nil {
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}
	log.Print("Object ID: ", objectId)
	conn := pool.Get()
	defer conn.Close()
	visits, _ := redis.Int64(conn.Do("GET", "str_"+objectId))
	uniques, _ := redis.Int64(conn.Do("PFCOUNT", "hll_"+objectId))
	apiResponse := ApiResponse{Visits: visits, Uniques: uniques}
	js, err := json.Marshal(apiResponse)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

// TODO support for backfilling values
func apiPostHandler(w http.ResponseWriter, req *http.Request) {
	objectId, err := apiObjectId(req.URL.Path)
	if err != nil {
		http.Error(w, "Not Found", http.StatusNotFound)
	}
	log.Print("Object ID: ", objectId)
}

func listenAddress() string {
	string := os.Getenv("PORT")
	if string == "" {
		return ":8080"
	} else {
		return ":" + string
	}
}

func redisConfig() (string, string) {
	string := os.Getenv("OPENREDIS_URL")
	if string != "" {
		url, err := url.Parse(string)
		password := ""
		if err != nil {
			panic(err)
		}
		if url.User != nil {
			password, _ = url.User.Password()
		}
		return url.Host, password
	} else {
		return "127.0.0.1:6379", ""

	}
}

func newPool(server, password string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

var (
	pool *redis.Pool
)

func main() {
	redisServer, redisPassword := redisConfig()
	log.Print(redisServer, redisPassword)
	pool = newPool(redisServer, redisPassword)

	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/beacon.png", beaconHandler)
	http.HandleFunc("/api/", apiHandler)

	log.Print("Listening on ", listenAddress())
	err := http.ListenAndServe(listenAddress(), nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>Allow Sidekiq-style redis provider config<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dchest/uniuri"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
)

type ApiResponse struct {
	Visits  int64 `json:"visits"`
	Uniques int64 `json:"uniques"`
}

const cookieMaxAge = 60 * 60 * 60 * 24 * 30

func uid(w http.ResponseWriter, req *http.Request) string {
	cookie, err := req.Cookie("uid")
	if err != nil {
		switch err {
		case http.ErrNoCookie:
			uid := fmt.Sprintf("%s", uniuri.New())
			now := time.Now()
			new_cookie := &http.Cookie{Name: "uid", Value: uid, MaxAge: cookieMaxAge, Expires: now.Add(cookieMaxAge)}
			log.Print("Setting new cookie ", new_cookie)
			http.SetCookie(w, new_cookie)
			return uid
		default:
			log.Fatal(err)
			return ""
		}
	}
	return cookie.Value
}

func track(objectId string, uid string) {
	log.Print("Tracking ", uid, " on ", objectId)
	conn := pool.Get()
	defer conn.Close()

	// http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining
	conn.Send("MULTI")

	// Track the number of unique visitors in a HyperLogLog
	// http://redis.io/commands/pfadd
	conn.Send("PFADD", "hll_"+objectId, uid)

	// Track the total number of visits in a simple key (stringy)
	// http://redis.io/commands/incr
	conn.Send("INCR", "str_"+objectId)

	_, err := conn.Do("EXEC")
	if err != nil {
		log.Print(err)
	}
}

func beaconHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	query, _ := url.ParseQuery(req.URL.RawQuery)
	objectId := query.Get("id")
	if objectId != "" {
		go track(objectId, uid(w, req))
	}
	http.ServeFile(w, req, path.Join("images", "beacon.png"))
}

func indexHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	if req.URL.Path == "/" {
		http.ServeFile(w, req, path.Join("index.html"))
	} else {
		http.NotFound(w, req)
	}
}

func apiHandler(w http.ResponseWriter, req *http.Request) {
	fmt.Println(req.Method, req.URL)
	switch req.Method {
	case "GET":
		apiGetHandler(w, req)
	case "POST":
		apiPostHandler(w, req)
	default:
		http.Error(w, "Expected GET or POST", http.StatusMethodNotAllowed)
	}
}

func apiObjectId(path string) (string, error) {
	path = strings.TrimSuffix(path, "/")
	elements := strings.SplitN(path, "/", 3)
	if len(elements) != 3 {
		return "", errors.New("Object Id not found in path")
	}
	return elements[2], nil
}

func apiGetHandler(w http.ResponseWriter, req *http.Request) {
	objectId, err := apiObjectId(req.URL.Path)
	if err != nil {
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}
	log.Print("Object ID: ", objectId)
	conn := pool.Get()
	defer conn.Close()
	visits, _ := redis.Int64(conn.Do("GET", "str_"+objectId))
	uniques, _ := redis.Int64(conn.Do("PFCOUNT", "hll_"+objectId))
	apiResponse := ApiResponse{Visits: visits, Uniques: uniques}
	js, err := json.Marshal(apiResponse)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(js)
}

// TODO support for backfilling values
func apiPostHandler(w http.ResponseWriter, req *http.Request) {
	objectId, err := apiObjectId(req.URL.Path)
	if err != nil {
		http.Error(w, "Not Found", http.StatusNotFound)
	}
	log.Print("Object ID: ", objectId)
}

func listenAddress() string {
	string := os.Getenv("PORT")
	if string == "" {
		return ":8080"
	} else {
		return ":" + string
	}
}

func redisConfig() (string, string) {
	redis_provider := os.Getenv("REDIS_PROVIDER")
	if redis_provider == "" {
		redis_provider = "OPENREDIS_URL"
	}
	string := os.Getenv(redis_provider)
	if string != "" {
		url, err := url.Parse(string)
		password := ""
		if err != nil {
			panic(err)
		}
		if url.User != nil {
			password, _ = url.User.Password()
		}
		return url.Host, password
	} else {
		return "127.0.0.1:6379", ""

	}
}

func newPool(server, password string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

var (
	pool *redis.Pool
)

func main() {
	redisServer, redisPassword := redisConfig()
	log.Print(redisServer, redisPassword)
	pool = newPool(redisServer, redisPassword)

	http.HandleFunc("/", indexHandler)
	http.HandleFunc("/beacon.png", beaconHandler)
	http.HandleFunc("/api/", apiHandler)

	log.Print("Listening on ", listenAddress())
	err := http.ListenAndServe(listenAddress(), nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package platformvm

import (
	"errors"
	"fmt"

	stdmath "math"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils/math"
	"github.com/ava-labs/gecko/utils/units"
)

var (
	txFee = uint64(0) * units.MicroAva // The transaction fee
)

var (
	errOutOfSpends = errors.New("ran out of spends")
	errInvalidID   = errors.New("invalid ID")
)

// Account represents the Balance and nonce of a user's funds
type Account struct {
	// Address of this account
	// Its value is [privKey].PublicKey().Address() where privKey
	// is the private key that controls this account
	Address ids.ShortID `serialize:"true"`

	// Nonce this account was last spent with
	// Initially, this is set to 0. Therefore, the first nonce a transaction should
	// use for a new account is 1.
	Nonce uint64 `serialize:"true"`

	// Balance of $AVA held by this account
	Balance uint64 `serialize:"true"`
}

// Remove generates a new account state from removing [amount + txFee] from [a]'s balance.
// [nonce] is [a]'s next unused nonce
func (a Account) Remove(amount, nonce uint64) (Account, error) {
	// Ensure account is in a valid state
	if err := a.Verify(); err != nil {
		return Account{}, err
	}

	// Ensure account's nonce isn't used up.
	// For this error to occur, an account would need to be issuing transactions
	// at 10k tps for ~ 80 million years
	newNonce, err := math.Add64(a.Nonce, 1)
	if err != nil {
		return Account{}, errOutOfSpends
	}

	if newNonce != nonce {
		return Account{}, fmt.Errorf("account's last nonce is %d so expected tx nonce to be %d but was %d", a.Nonce, newNonce, nonce)
	}

	amountWithFee, err := math.Add64(amount, txFee)
	if err != nil {
		return Account{}, fmt.Errorf("send amount overflowed: tx fee (%d) + send amount (%d) > maximum value", txFee, amount)
	}

	newBalance, err := math.Sub64(a.Balance, amountWithFee)
	if err != nil {
		return Account{}, fmt.Errorf("insufficient funds: account balance %d < tx fee (%d) + send amount (%d)", a.Balance, txFee, amount)
	}

	// Ensure this tx wouldn't lock funds
	if newNonce == stdmath.MaxUint64 && newBalance != 0 {
		return Account{}, fmt.Errorf("transaction would lock %d funds", newBalance)
	}

	return Account{
		Address: a.Address,
		Nonce:   newNonce,
		Balance: newBalance,
	}, nil
}

// Add returns the state of [a] after receiving the $AVA
func (a Account) Add(amount uint64) (Account, error) {
	// Ensure account is in a valid state
	if err := a.Verify(); err != nil {
		return Account{}, err
	}

	// Ensure account's nonce isn't used up
	// For this error to occur, a user would need to be issuing transactions
	// at 10k tps for ~ 80 million years
	if a.Nonce == stdmath.MaxUint64 {
		return a, errOutOfSpends
	}

	// account's balance after receipt of staked $AVA
	newBalance, err := math.Add64(a.Balance, amount)
	if err != nil {
		return a, fmt.Errorf("account balance (%d) + staked $AVA (%d) exceeds maximum uint64", a.Balance, amount)
	}

	return Account{
		Address: a.Address,
		Nonce:   a.Nonce,
		Balance: newBalance,
	}, nil
}

// Verify that this account is in a valid state
func (a Account) Verify() error {
	switch {
	case a.Address.IsZero():
		return errInvalidID
	default:
		return nil
	}
}

// Bytes returns the byte representation of this account
func (a Account) Bytes() []byte {
	bytes, _ := Codec.Marshal(a)
	return bytes
}

func newAccount(Address ids.ShortID, Nonce, Balance uint64) Account {
	return Account{
		Address: Address,
		Nonce:   Nonce,
		Balance: Balance,
	}
}
<commit_msg>Standardize account return value when returning with an error<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package platformvm

import (
	"errors"
	"fmt"

	stdmath "math"

	"github.com/ava-labs/gecko/ids"
	"github.com/ava-labs/gecko/utils/math"
	"github.com/ava-labs/gecko/utils/units"
)

var (
	txFee = uint64(0) * units.MicroAva // The transaction fee
)

var (
	errOutOfSpends = errors.New("ran out of spends")
	errInvalidID   = errors.New("invalid ID")
)

// Account represents the Balance and nonce of a user's funds
type Account struct {
	// Address of this account
	// Its value is [privKey].PublicKey().Address() where privKey
	// is the private key that controls this account
	Address ids.ShortID `serialize:"true"`

	// Nonce this account was last spent with
	// Initially, this is set to 0. Therefore, the first nonce a transaction should
	// use for a new account is 1.
	Nonce uint64 `serialize:"true"`

	// Balance of $AVA held by this account
	Balance uint64 `serialize:"true"`
}

// Remove generates a new account state from removing [amount + txFee] from [a]'s balance.
// [nonce] is [a]'s next unused nonce
func (a Account) Remove(amount, nonce uint64) (Account, error) {
	// Ensure account is in a valid state
	if err := a.Verify(); err != nil {
		return a, err
	}

	// Ensure account's nonce isn't used up.
	// For this error to occur, an account would need to be issuing transactions
	// at 10k tps for ~ 80 million years
	newNonce, err := math.Add64(a.Nonce, 1)
	if err != nil {
		return a, errOutOfSpends
	}

	if newNonce != nonce {
		return a, fmt.Errorf("account's last nonce is %d so expected tx nonce to be %d but was %d", a.Nonce, newNonce, nonce)
	}

	amountWithFee, err := math.Add64(amount, txFee)
	if err != nil {
		return a, fmt.Errorf("send amount overflowed: tx fee (%d) + send amount (%d) > maximum value", txFee, amount)
	}

	newBalance, err := math.Sub64(a.Balance, amountWithFee)
	if err != nil {
		return a, fmt.Errorf("insufficient funds: account balance %d < tx fee (%d) + send amount (%d)", a.Balance, txFee, amount)
	}

	// Ensure this tx wouldn't lock funds
	if newNonce == stdmath.MaxUint64 && newBalance != 0 {
		return a, fmt.Errorf("transaction would lock %d funds", newBalance)
	}

	return Account{
		Address: a.Address,
		Nonce:   newNonce,
		Balance: newBalance,
	}, nil
}

// Add returns the state of [a] after receiving the $AVA
func (a Account) Add(amount uint64) (Account, error) {
	// Ensure account is in a valid state
	if err := a.Verify(); err != nil {
		return a, err
	}

	// Ensure account's nonce isn't used up
	// For this error to occur, a user would need to be issuing transactions
	// at 10k tps for ~ 80 million years
	if a.Nonce == stdmath.MaxUint64 {
		return a, errOutOfSpends
	}

	// account's balance after receipt of staked $AVA
	newBalance, err := math.Add64(a.Balance, amount)
	if err != nil {
		return a, fmt.Errorf("account balance (%d) + staked $AVA (%d) exceeds maximum uint64", a.Balance, amount)
	}

	return Account{
		Address: a.Address,
		Nonce:   a.Nonce,
		Balance: newBalance,
	}, nil
}

// Verify that this account is in a valid state
func (a Account) Verify() error {
	switch {
	case a.Address.IsZero():
		return errInvalidID
	default:
		return nil
	}
}

// Bytes returns the byte representation of this account
func (a Account) Bytes() []byte {
	bytes, _ := Codec.Marshal(a)
	return bytes
}

func newAccount(Address ids.ShortID, Nonce, Balance uint64) Account {
	return Account{
		Address: Address,
		Nonce:   Nonce,
		Balance: Balance,
	}
}
<|endoftext|>


<commit_before>// loadbalance project loadbalance.go
package loadbalance

import (
	"net/http"
	"net/http/httputil"
	"sync"
)

const (
	ScheduleRand = iota
	ScheduleOrder
)

type node struct {
	activeTime int64 //time.Now().Unix()
	proxy      *httputil.ReverseProxy
	checkHB    bool
	valid      bool
}

type LB struct {
	index  int
	nodes  []*node
	rwLock *sync.RWMutex
}

const maxNodeLen = 10

func NewLB() *LB {
	return &LB{
		nodes:  make([]*node, 0, maxNodeLen),
		rwLock: new(sync.RWMutex),
	}
}

func (this *LB) Register(scheme, host string) {
	this.rwLock.Lock()
	director := func(req *http.Request) {
		req.URL.Scheme = scheme
		req.URL.Host = host
	}

	this.nodes = append(this.nodes, &node{
		proxy: &httputil.ReverseProxy{Director: director},
	})
	this.rwLock.Unlock()
}

func (this *LB) getNode() *node {
	this.rwLock.Lock()
	nl := len(this.nodes)
	if nl <= 0 {
		this.rwLock.Unlock()
		return nil
	} else {
		index := this.index % nl
		this.index = index + 1
		this.rwLock.Unlock()
		return this.nodes[index]
	}
}

func (this *LB) Proxy(w http.ResponseWriter, r *http.Request) {
	n := this.getNode()
	if n == nil {
		w.WriteHeader(404)
	} else {
		n.proxy.ServeHTTP(w, r)
	}
}
<commit_msg>add comment<commit_after>// loadbalance project loadbalance.go
package loadbalance

import (
	"net/http"
	"net/http/httputil"
	"sync"
)

const (
	ScheduleRand = iota
	ScheduleOrder
)

type node struct {
	activeTime int64 //time.Now().Unix()
	proxy      *httputil.ReverseProxy
	checkHB    bool
	valid      bool
}

type LB struct {
	index  int
	nodes  []*node
	rwLock *sync.RWMutex
}

const maxNodeLen = 10

func NewLB() *LB {
	return &LB{
		nodes:  make([]*node, 0, maxNodeLen),
		rwLock: new(sync.RWMutex),
	}
}

func (this *LB) Register(scheme, host string) {
	this.rwLock.Lock()
	director := func(req *http.Request) {
		req.URL.Scheme = scheme
		req.URL.Host = host
	}

	this.nodes = append(this.nodes, &node{
		proxy: &httputil.ReverseProxy{Director: director},
	})
	this.rwLock.Unlock()
}

func (this *LB) getNode() *node {
	this.rwLock.Lock()
	nl := len(this.nodes)
	if nl <= 0 {
		this.rwLock.Unlock()
		return nil
	} else {
		index := this.index % nl
		this.index = index + 1
		this.rwLock.Unlock()
		return this.nodes[index]
	}
}

//Proxy work with: http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { lb.Proxy(w, r) })
func (this *LB) Proxy(w http.ResponseWriter, r *http.Request) {
	n := this.getNode()
	if n == nil {
		w.WriteHeader(404)
	} else {
		n.proxy.ServeHTTP(w, r)
	}
}
<|endoftext|>


<commit_before>// Package options defines configuration options that are used by Gopactor
// when spawning actors. You can build a custom set of
// options for every actor you test with Gopactor.
//
// Example:
//
//   // Let's build a set of options with these requirements:
//   // - The actor should be spawned with prefix "sender".
//   // - Gopactor should only intercept outbound messages for this actor.
//   // - In addition, allow extra time when waiting for the actor to send something.
//   opt1 := OptOutboundInterceptionOnly.WithPrefix("sender").WithTimeout(time.Second)
//   actor1, _ := SpawnFromInstance(&MyActor{}, opt1)
//
//   // Another simple configuration:
//   // - Ask Gopactor to listen only to system messages received by the actor.
//   opt2 := OptNoInterception.WithOutboundInterception()
//   actor2, _ := SpawnFromInstance(&MyActor{}, opt2)
//
//   // Use the default configuration:
//   // - Inbound and outbound interception.
//   // - No interception of system messages.
//   // - In addition, reduce the timeout (default value id 3 milliseconds).
//   opt3 := OptDefault.WithTimeout(1 * time.Millisecond)
//   actor3, _ := SpawnFromInstance(&MyActor{}, opt3)
package options

import "time"

// DEFAULT_TIMEOUT value is used when no custom timeout has been specified.
// Three milliseconds is long enough to allow for some regular operations
// in an actor to complete and for messages to be emitted. At the same
// time, it is short enough to keep testing reasonably fast even when
// you use hundreds of assertions.
const DEFAULT_TIMEOUT = 3 * time.Millisecond

// Options is a container for individual configuration options used by Gopactor.
// For each actor you test with Gopactor, you can build a custom set of
// options.
type Options struct {
	// Which messages to intercept
	InboundInterceptionEnabled  bool
	OutboundInterceptionEnabled bool
	SystemInterceptionEnabled   bool

	// Spawning
	SpawnInterceptionEnabled bool
	DummySpawningEnabled     bool

	// A prefix of the spawned actor name.
	// It is useful mostly in cases when you debug your application
	// and want the actor's PID to have a meaningful value.
	Prefix string

	// The maximum amount of time to wait for an expected inbound or outbound message.
	// This applies to all assertions for a given actor.
	Timeout time.Duration
}

// OptNoInterception is one of predefined configurations:
// - interception is disabled
var OptNoInterception = Options{
	Timeout: DEFAULT_TIMEOUT,
}

// OptDefault is one of predefined configurations.
// It is used by Gopactor when no configuration is provided.
var OptDefault = Options{
	InboundInterceptionEnabled:  true,
	OutboundInterceptionEnabled: true,
	SystemInterceptionEnabled:   false,
	Timeout:                     DEFAULT_TIMEOUT,
}

// OptOutboundInterceptionOnly is one of predefined configurations:
// - intercept outbound messages only
var OptOutboundInterceptionOnly = Options{
	OutboundInterceptionEnabled: true,
	Timeout:                     DEFAULT_TIMEOUT,
}

// OptInboundInterceptionOnly is one of predefined configurations:
// - intercept inbound messages only
var OptInboundInterceptionOnly = Options{
	InboundInterceptionEnabled: true,
	Timeout:                    DEFAULT_TIMEOUT,
}

// WithInboundInterception is a helper method to add inbound interception to options
func (opt Options) WithInboundInterception() Options {
	opt.InboundInterceptionEnabled = true
	return opt
}

// WithOutboundInterception is a helper method to add outbound interception to options
func (opt Options) WithOutboundInterception() Options {
	opt.OutboundInterceptionEnabled = true
	return opt
}

// WithSystemInterception is a helper method to add system messages interception to options
func (opt Options) WithSystemInterception() Options {
	opt.SystemInterceptionEnabled = true
	return opt
}

// WithSpawnInterception is a helper method to add spawning interception to options
func (opt Options) WithSpawnInterception() Options {
	opt.SpawnInterceptionEnabled = true
	return opt
}

// WithDummySpawning is a helper method to add dummy spawning to options
func (opt Options) WithDummySpawning() Options {
	opt.DummySpawningEnabled = true
	return opt
}

// WithPrefix is a helper method to add prefix to options
func (opt Options) WithPrefix(prefix string) Options {
	opt.Prefix = prefix
	return opt
}

// WithTimeout is a helper to add timeout to options
func (opt Options) WithTimeout(timeout time.Duration) Options {
	opt.Timeout = timeout
	return opt
}
<commit_msg>Bug fix: dummy spawning should be enabled by deafault<commit_after>// Package options defines configuration options that are used by Gopactor
// when spawning actors. You can build a custom set of
// options for every actor you test with Gopactor.
//
// Example:
//
//   // Let's build a set of options with these requirements:
//   // - The actor should be spawned with prefix "sender".
//   // - Gopactor should only intercept outbound messages for this actor.
//   // - In addition, allow extra time when waiting for the actor to send something.
//   opt1 := OptOutboundInterceptionOnly.WithPrefix("sender").WithTimeout(time.Second)
//   actor1, _ := SpawnFromInstance(&MyActor{}, opt1)
//
//   // Another simple configuration:
//   // - Ask Gopactor to listen only to system messages received by the actor.
//   opt2 := OptNoInterception.WithOutboundInterception()
//   actor2, _ := SpawnFromInstance(&MyActor{}, opt2)
//
//   // Use the default configuration:
//   // - Inbound and outbound interception.
//   // - No interception of system messages.
//   // - In addition, reduce the timeout (default value id 3 milliseconds).
//   opt3 := OptDefault.WithTimeout(1 * time.Millisecond)
//   actor3, _ := SpawnFromInstance(&MyActor{}, opt3)
package options

import "time"

// DEFAULT_TIMEOUT value is used when no custom timeout has been specified.
// Three milliseconds is long enough to allow for some regular operations
// in an actor to complete and for messages to be emitted. At the same
// time, it is short enough to keep testing reasonably fast even when
// you use hundreds of assertions.
const DEFAULT_TIMEOUT = 3 * time.Millisecond

// Options is a container for individual configuration options used by Gopactor.
// For each actor you test with Gopactor, you can build a custom set of
// options.
type Options struct {
	// Which messages to intercept
	InboundInterceptionEnabled  bool
	OutboundInterceptionEnabled bool
	SystemInterceptionEnabled   bool

	// Spawning
	SpawnInterceptionEnabled bool
	DummySpawningEnabled     bool

	// A prefix of the spawned actor name.
	// It is useful mostly in cases when you debug your application
	// and want the actor's PID to have a meaningful value.
	Prefix string

	// The maximum amount of time to wait for an expected inbound or outbound message.
	// This applies to all assertions for a given actor.
	Timeout time.Duration
}

// OptNoInterception is one of predefined configurations:
// - interception is disabled
var OptNoInterception = Options{
	Timeout: DEFAULT_TIMEOUT,
}

// OptDefault is one of predefined configurations.
// It is used by Gopactor when no configuration is provided.
var OptDefault = Options{
	InboundInterceptionEnabled:  true,
	OutboundInterceptionEnabled: true,
	SystemInterceptionEnabled:   false,
	DummySpawningEnabled:        true,
	Timeout:                     DEFAULT_TIMEOUT,
}

// OptOutboundInterceptionOnly is one of predefined configurations:
// - intercept outbound messages only
var OptOutboundInterceptionOnly = Options{
	OutboundInterceptionEnabled: true,
	Timeout:                     DEFAULT_TIMEOUT,
}

// OptInboundInterceptionOnly is one of predefined configurations:
// - intercept inbound messages only
var OptInboundInterceptionOnly = Options{
	InboundInterceptionEnabled: true,
	Timeout:                    DEFAULT_TIMEOUT,
}

// WithInboundInterception is a helper method to add inbound interception to options
func (opt Options) WithInboundInterception() Options {
	opt.InboundInterceptionEnabled = true
	return opt
}

// WithOutboundInterception is a helper method to add outbound interception to options
func (opt Options) WithOutboundInterception() Options {
	opt.OutboundInterceptionEnabled = true
	return opt
}

// WithSystemInterception is a helper method to add system messages interception to options
func (opt Options) WithSystemInterception() Options {
	opt.SystemInterceptionEnabled = true
	return opt
}

// WithSpawnInterception is a helper method to add spawning interception to options
func (opt Options) WithSpawnInterception() Options {
	opt.SpawnInterceptionEnabled = true
	return opt
}

// WithDummySpawning is a helper method to add dummy spawning to options
func (opt Options) WithDummySpawning() Options {
	opt.DummySpawningEnabled = true
	return opt
}

// WithPrefix is a helper method to add prefix to options
func (opt Options) WithPrefix(prefix string) Options {
	opt.Prefix = prefix
	return opt
}

// WithTimeout is a helper to add timeout to options
func (opt Options) WithTimeout(timeout time.Duration) Options {
	opt.Timeout = timeout
	return opt
}
<|endoftext|>


<commit_before>package boomer

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/asaskevich/EventBus"
)

// Events is the global event bus instance.
var Events = EventBus.New()

var defaultBoomer *Boomer

// A Boomer is used to run tasks.
// This type is exposed, so users can create and control a Boomer instance programmatically.
type Boomer struct {
	masterHost string
	masterPort int

	hatchType   string
	rateLimiter RateLimiter
	runner      *runner
}

// NewBoomer returns a new Boomer.
func NewBoomer(masterHost string, masterPort int) *Boomer {
	return &Boomer{
		masterHost: masterHost,
		masterPort: masterPort,
		hatchType:  "asap",
	}
}

// SetRateLimiter allows user to use their own rate limiter.
// It must be called before the test is started.
func (b *Boomer) SetRateLimiter(rateLimiter RateLimiter) {
	b.rateLimiter = rateLimiter
}

// SetHatchType only accepts "asap" or "smooth".
// "asap" means spawning goroutines as soon as possible when the test is started.
// "smooth" means a constant pace.
func (b *Boomer) SetHatchType(hatchType string) {
	if hatchType != "asap" && hatchType != "smooth" {
		log.Printf("Wrong hatch-type, expected asap or smooth, was %s\n", hatchType)
		return
	}
	b.hatchType = hatchType
}

func (b *Boomer) setRunner(runner *runner) {
	b.runner = runner
}

// Run accepts a slice of Task and connects to the locust master.
func (b *Boomer) Run(tasks ...*Task) {
	b.runner = newRunner(tasks, b.rateLimiter, b.hatchType)
	b.runner.masterHost = b.masterHost
	b.runner.masterPort = b.masterPort
	b.runner.getReady()
}

// RecordSuccess reports a success.
func (b *Boomer) RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	b.runner.stats.requestSuccessChannel <- &requestSuccess{
		requestType:    requestType,
		name:           name,
		responseTime:   responseTime,
		responseLength: responseLength,
	}
}

// RecordFailure reports a failure.
func (b *Boomer) RecordFailure(requestType, name string, responseTime int64, exception string) {
	b.runner.stats.requestFailureChannel <- &requestFailure{
		requestType:  requestType,
		name:         name,
		responseTime: responseTime,
		error:        exception,
	}
}

// Quit will send a quit message to the master.
func (b *Boomer) Quit() {
	Events.Publish("boomer:quit")
	var ticker = time.NewTicker(3 * time.Second)

	// wait for quit message is sent to master
	select {
	case <-b.runner.client.disconnectedChannel():
		break
	case <-ticker.C:
		log.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
		break
	}

	b.runner.close()
}

// Run tasks without connecting to the master.
func runTasksForTest(tasks ...*Task) {
	taskNames := strings.Split(runTasks, ",")
	for _, task := range tasks {
		if task.Name == "" {
			continue
		} else {
			for _, name := range taskNames {
				if name == task.Name {
					log.Println("Running " + task.Name)
					task.Fn()
				}
			}
		}
	}
}

// Run accepts a slice of Task and connects to a locust master.
// It's a convenience function to use the defaultBoomer.
func Run(tasks ...*Task) {
	if !flag.Parsed() {
		flag.Parse()
	}

	if runTasks != "" {
		runTasksForTest(tasks...)
		return
	}

	defaultBoomer = NewBoomer(masterHost, masterPort)
	initLegacyEventHandlers()

	if memoryProfile != "" {
		StartMemoryProfile(memoryProfile, memoryProfileDuration)
	}

	if cpuProfile != "" {
		StartCPUProfile(cpuProfile, cpuProfileDuration)
	}

	rateLimiter, err := createRateLimiter(maxRPS, requestIncreaseRate)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	defaultBoomer.SetRateLimiter(rateLimiter)
	defaultBoomer.hatchType = hatchType

	defaultBoomer.Run(tasks...)

	quitByMe := false
	Events.Subscribe("boomer:quit", func() {
		if !quitByMe {
			log.Println("shut down")
			os.Exit(0)
		}
	})

	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

	<-c
	quitByMe = true
	defaultBoomer.Quit()

	log.Println("shut down")
}

// RecordSuccess reports a success.
// It's a convenience function to use the defaultBoomer.
func RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	defaultBoomer.RecordSuccess(requestType, name, responseTime, responseLength)
}

// RecordFailure reports a failure.
// It's a convenience function to use the defaultBoomer.
func RecordFailure(requestType, name string, responseTime int64, exception string) {
	defaultBoomer.RecordFailure(requestType, name, responseTime, exception)
}
<commit_msg>FIX: --run-tasks panics<commit_after>package boomer

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/asaskevich/EventBus"
)

// Events is the global event bus instance.
var Events = EventBus.New()

var defaultBoomer *Boomer = &Boomer{}

// A Boomer is used to run tasks.
// This type is exposed, so users can create and control a Boomer instance programmatically.
type Boomer struct {
	masterHost string
	masterPort int

	hatchType   string
	rateLimiter RateLimiter
	runner      *runner
}

// NewBoomer returns a new Boomer.
func NewBoomer(masterHost string, masterPort int) *Boomer {
	return &Boomer{
		masterHost: masterHost,
		masterPort: masterPort,
		hatchType:  "asap",
	}
}

// SetRateLimiter allows user to use their own rate limiter.
// It must be called before the test is started.
func (b *Boomer) SetRateLimiter(rateLimiter RateLimiter) {
	b.rateLimiter = rateLimiter
}

// SetHatchType only accepts "asap" or "smooth".
// "asap" means spawning goroutines as soon as possible when the test is started.
// "smooth" means a constant pace.
func (b *Boomer) SetHatchType(hatchType string) {
	if hatchType != "asap" && hatchType != "smooth" {
		log.Printf("Wrong hatch-type, expected asap or smooth, was %s\n", hatchType)
		return
	}
	b.hatchType = hatchType
}

func (b *Boomer) setRunner(runner *runner) {
	b.runner = runner
}

// Run accepts a slice of Task and connects to the locust master.
func (b *Boomer) Run(tasks ...*Task) {
	b.runner = newRunner(tasks, b.rateLimiter, b.hatchType)
	b.runner.masterHost = b.masterHost
	b.runner.masterPort = b.masterPort
	b.runner.getReady()
}

// RecordSuccess reports a success.
func (b *Boomer) RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	if b.runner == nil {
		return
	}
	b.runner.stats.requestSuccessChannel <- &requestSuccess{
		requestType:    requestType,
		name:           name,
		responseTime:   responseTime,
		responseLength: responseLength,
	}
}

// RecordFailure reports a failure.
func (b *Boomer) RecordFailure(requestType, name string, responseTime int64, exception string) {
	if b.runner == nil {
		return
	}
	b.runner.stats.requestFailureChannel <- &requestFailure{
		requestType:  requestType,
		name:         name,
		responseTime: responseTime,
		error:        exception,
	}
}

// Quit will send a quit message to the master.
func (b *Boomer) Quit() {
	Events.Publish("boomer:quit")
	var ticker = time.NewTicker(3 * time.Second)

	// wait for quit message is sent to master
	select {
	case <-b.runner.client.disconnectedChannel():
		break
	case <-ticker.C:
		log.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
		break
	}

	b.runner.close()
}

// Run tasks without connecting to the master.
func runTasksForTest(tasks ...*Task) {
	taskNames := strings.Split(runTasks, ",")
	for _, task := range tasks {
		if task.Name == "" {
			continue
		} else {
			for _, name := range taskNames {
				if name == task.Name {
					log.Println("Running " + task.Name)
					task.Fn()
				}
			}
		}
	}
}

// Run accepts a slice of Task and connects to a locust master.
// It's a convenience function to use the defaultBoomer.
func Run(tasks ...*Task) {
	if !flag.Parsed() {
		flag.Parse()
	}

	if runTasks != "" {
		runTasksForTest(tasks...)
		return
	}

	initLegacyEventHandlers()

	if memoryProfile != "" {
		StartMemoryProfile(memoryProfile, memoryProfileDuration)
	}

	if cpuProfile != "" {
		StartCPUProfile(cpuProfile, cpuProfileDuration)
	}

	rateLimiter, err := createRateLimiter(maxRPS, requestIncreaseRate)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	defaultBoomer.SetRateLimiter(rateLimiter)
	defaultBoomer.masterHost = masterHost
	defaultBoomer.masterPort = masterPort
	defaultBoomer.hatchType = hatchType

	defaultBoomer.Run(tasks...)

	quitByMe := false
	Events.Subscribe("boomer:quit", func() {
		if !quitByMe {
			log.Println("shut down")
			os.Exit(0)
		}
	})

	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

	<-c
	quitByMe = true
	defaultBoomer.Quit()

	log.Println("shut down")
}

// RecordSuccess reports a success.
// It's a convenience function to use the defaultBoomer.
func RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	defaultBoomer.RecordSuccess(requestType, name, responseTime, responseLength)
}

// RecordFailure reports a failure.
// It's a convenience function to use the defaultBoomer.
func RecordFailure(requestType, name string, responseTime int64, exception string) {
	defaultBoomer.RecordFailure(requestType, name, responseTime, exception)
}
<|endoftext|>


<commit_before>package boomer

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/asaskevich/EventBus"
)

// Events is the global event bus instance.
var Events = EventBus.New()

var defaultBoomer = &Boomer{}

// Mode is the running mode of boomer, both standalone and distributed are supported.
type Mode int

const (
	// DistributedMode requires connecting to a master.
	DistributedMode Mode = iota
	// StandaloneMode will run without a master.
	StandaloneMode
)

// A Boomer is used to run tasks.
// This type is exposed, so users can create and control a Boomer instance programmatically.
type Boomer struct {
	masterHost string
	masterPort int

	hatchType   string
	mode        Mode
	rateLimiter RateLimiter
	slaveRunner *slaveRunner

	localRunner *localRunner
	hatchCount  int
	hatchRate   int

	cpuProfile         string
	cpuProfileDuration time.Duration

	memoryProfile         string
	memoryProfileDuration time.Duration

	outputs []Output
}

// NewBoomer returns a new Boomer.
func NewBoomer(masterHost string, masterPort int) *Boomer {
	return &Boomer{
		masterHost: masterHost,
		masterPort: masterPort,
		hatchType:  "asap",
		mode:       DistributedMode,
	}
}

// NewStandaloneBoomer returns a new Boomer, which can run without master.
func NewStandaloneBoomer(hatchCount int, hatchRate int) *Boomer {
	return &Boomer{
		hatchType:  "asap",
		hatchCount: hatchCount,
		hatchRate:  hatchRate,
		mode:       StandaloneMode,
	}
}

// SetRateLimiter allows user to use their own rate limiter.
// It must be called before the test is started.
func (b *Boomer) SetRateLimiter(rateLimiter RateLimiter) {
	b.rateLimiter = rateLimiter
}

// SetHatchType only accepts "asap" or "smooth".
// "asap" means spawning goroutines as soon as possible when the test is started.
// "smooth" means a constant pace.
func (b *Boomer) SetHatchType(hatchType string) {
	if hatchType != "asap" && hatchType != "smooth" {
		log.Printf("Wrong hatch-type, expected asap or smooth, was %s\n", hatchType)
		return
	}
	b.hatchType = hatchType
}

// SetMode only accepts boomer.DistributedMode and boomer.StandaloneMode.
func (b *Boomer) SetMode(mode Mode) {
	switch mode {
	case DistributedMode:
		b.mode = DistributedMode
	case StandaloneMode:
		b.mode = StandaloneMode
	default:
		log.Println("Invalid mode, ignored!")
	}
}

// AddOutput accepts outputs which implements the boomer.Output interface.
func (b *Boomer) AddOutput(o Output) {
	b.outputs = append(b.outputs, o)
}

// EnableCPUProfile will start cpu profiling after run.
func (b *Boomer) EnableCPUProfile(cpuProfile string, duration time.Duration) {
	b.cpuProfile = cpuProfile
	b.cpuProfileDuration = duration
}

// EnableMemoryProfile will start memory profiling after run.
func (b *Boomer) EnableMemoryProfile(memoryProfile string, duration time.Duration) {
	b.memoryProfile = memoryProfile
	b.memoryProfileDuration = duration
}

// Run accepts a slice of Task and connects to the locust master.
func (b *Boomer) Run(tasks ...*Task) {
	if b.cpuProfile != "" {
		err := StartCPUProfile(b.cpuProfile, b.cpuProfileDuration)
		if err != nil {
			log.Printf("Error starting cpu profiling, %v", err)
		}
	}
	if b.memoryProfile != "" {
		err := StartMemoryProfile(b.memoryProfile, b.memoryProfileDuration)
		if err != nil {
			log.Printf("Error starting memory profiling, %v", err)
		}
	}

	switch b.mode {
	case DistributedMode:
		b.slaveRunner = newSlaveRunner(b.masterHost, b.masterPort, tasks, b.rateLimiter, b.hatchType)
		for _, o := range b.outputs {
			b.slaveRunner.addOutput(o)
		}
		b.slaveRunner.run()
	case StandaloneMode:
		b.localRunner = newLocalRunner(tasks, b.rateLimiter, b.hatchCount, b.hatchType, b.hatchRate)
		for _, o := range b.outputs {
			b.localRunner.addOutput(o)
		}
		b.localRunner.run()
	default:
		log.Println("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")
	}
}

// RecordSuccess reports a success.
func (b *Boomer) RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	if b.localRunner == nil && b.slaveRunner == nil {
		return
	}
	switch b.mode {
	case DistributedMode:
		b.slaveRunner.stats.requestSuccessChan <- &requestSuccess{
			requestType:    requestType,
			name:           name,
			responseTime:   responseTime,
			responseLength: responseLength,
		}
	case StandaloneMode:
		b.localRunner.stats.requestSuccessChan <- &requestSuccess{
			requestType:    requestType,
			name:           name,
			responseTime:   responseTime,
			responseLength: responseLength,
		}
	}
}

// RecordFailure reports a failure.
func (b *Boomer) RecordFailure(requestType, name string, responseTime int64, exception string) {
	if b.localRunner == nil && b.slaveRunner == nil {
		return
	}
	switch b.mode {
	case DistributedMode:
		b.slaveRunner.stats.requestFailureChan <- &requestFailure{
			requestType:  requestType,
			name:         name,
			responseTime: responseTime,
			error:        exception,
		}
	case StandaloneMode:
		b.localRunner.stats.requestFailureChan <- &requestFailure{
			requestType:  requestType,
			name:         name,
			responseTime: responseTime,
			error:        exception,
		}
	}
}

// Quit will send a quit message to the master.
func (b *Boomer) Quit() {
	Events.Publish("boomer:quit")
	var ticker = time.NewTicker(3 * time.Second)

	switch b.mode {
	case DistributedMode:
		// wait for quit message is sent to master
		select {
		case <-b.slaveRunner.client.disconnectedChannel():
			break
		case <-ticker.C:
			log.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
			break
		}
		b.slaveRunner.close()
	case StandaloneMode:
		b.localRunner.close()
	}
}

// Run tasks without connecting to the master.
func runTasksForTest(tasks ...*Task) {
	taskNames := strings.Split(runTasks, ",")
	for _, task := range tasks {
		if task.Name == "" {
			continue
		} else {
			for _, name := range taskNames {
				if name == task.Name {
					log.Println("Running " + task.Name)
					task.Fn()
				}
			}
		}
	}
}

// Run accepts a slice of Task and connects to a locust master.
// It's a convenience function to use the defaultBoomer.
func Run(tasks ...*Task) {
	if !flag.Parsed() {
		flag.Parse()
	}

	if runTasks != "" {
		runTasksForTest(tasks...)
		return
	}

	initLegacyEventHandlers()

	rateLimiter, err := createRateLimiter(maxRPS, requestIncreaseRate)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	defaultBoomer.SetRateLimiter(rateLimiter)
	defaultBoomer.masterHost = masterHost
	defaultBoomer.masterPort = masterPort
	defaultBoomer.hatchType = hatchType
	defaultBoomer.EnableMemoryProfile(memoryProfile, memoryProfileDuration)
	defaultBoomer.EnableCPUProfile(cpuProfile, cpuProfileDuration)

	defaultBoomer.Run(tasks...)

	quitByMe := false
	Events.Subscribe("boomer:quit", func() {
		if !quitByMe {
			log.Println("shut down")
			os.Exit(0)
		}
	})

	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

	<-c
	quitByMe = true
	defaultBoomer.Quit()

	log.Println("shut down")
}

// RecordSuccess reports a success.
// It's a convenience function to use the defaultBoomer.
func RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	defaultBoomer.RecordSuccess(requestType, name, responseTime, responseLength)
}

// RecordFailure reports a failure.
// It's a convenience function to use the defaultBoomer.
func RecordFailure(requestType, name string, responseTime int64, exception string) {
	defaultBoomer.RecordFailure(requestType, name, responseTime, exception)
}
<commit_msg>FIX: test report is not generated if os.Exit being called<commit_after>package boomer

import (
	"flag"
	"log"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/asaskevich/EventBus"
)

// Events is the global event bus instance.
var Events = EventBus.New()

var defaultBoomer = &Boomer{}

// Mode is the running mode of boomer, both standalone and distributed are supported.
type Mode int

const (
	// DistributedMode requires connecting to a master.
	DistributedMode Mode = iota
	// StandaloneMode will run without a master.
	StandaloneMode
)

// A Boomer is used to run tasks.
// This type is exposed, so users can create and control a Boomer instance programmatically.
type Boomer struct {
	masterHost string
	masterPort int

	hatchType   string
	mode        Mode
	rateLimiter RateLimiter
	slaveRunner *slaveRunner

	localRunner *localRunner
	hatchCount  int
	hatchRate   int

	cpuProfile         string
	cpuProfileDuration time.Duration

	memoryProfile         string
	memoryProfileDuration time.Duration

	outputs []Output
}

// NewBoomer returns a new Boomer.
func NewBoomer(masterHost string, masterPort int) *Boomer {
	return &Boomer{
		masterHost: masterHost,
		masterPort: masterPort,
		hatchType:  "asap",
		mode:       DistributedMode,
	}
}

// NewStandaloneBoomer returns a new Boomer, which can run without master.
func NewStandaloneBoomer(hatchCount int, hatchRate int) *Boomer {
	return &Boomer{
		hatchType:  "asap",
		hatchCount: hatchCount,
		hatchRate:  hatchRate,
		mode:       StandaloneMode,
	}
}

// SetRateLimiter allows user to use their own rate limiter.
// It must be called before the test is started.
func (b *Boomer) SetRateLimiter(rateLimiter RateLimiter) {
	b.rateLimiter = rateLimiter
}

// SetHatchType only accepts "asap" or "smooth".
// "asap" means spawning goroutines as soon as possible when the test is started.
// "smooth" means a constant pace.
func (b *Boomer) SetHatchType(hatchType string) {
	if hatchType != "asap" && hatchType != "smooth" {
		log.Printf("Wrong hatch-type, expected asap or smooth, was %s\n", hatchType)
		return
	}
	b.hatchType = hatchType
}

// SetMode only accepts boomer.DistributedMode and boomer.StandaloneMode.
func (b *Boomer) SetMode(mode Mode) {
	switch mode {
	case DistributedMode:
		b.mode = DistributedMode
	case StandaloneMode:
		b.mode = StandaloneMode
	default:
		log.Println("Invalid mode, ignored!")
	}
}

// AddOutput accepts outputs which implements the boomer.Output interface.
func (b *Boomer) AddOutput(o Output) {
	b.outputs = append(b.outputs, o)
}

// EnableCPUProfile will start cpu profiling after run.
func (b *Boomer) EnableCPUProfile(cpuProfile string, duration time.Duration) {
	b.cpuProfile = cpuProfile
	b.cpuProfileDuration = duration
}

// EnableMemoryProfile will start memory profiling after run.
func (b *Boomer) EnableMemoryProfile(memoryProfile string, duration time.Duration) {
	b.memoryProfile = memoryProfile
	b.memoryProfileDuration = duration
}

// Run accepts a slice of Task and connects to the locust master.
func (b *Boomer) Run(tasks ...*Task) {
	if b.cpuProfile != "" {
		err := StartCPUProfile(b.cpuProfile, b.cpuProfileDuration)
		if err != nil {
			log.Printf("Error starting cpu profiling, %v", err)
		}
	}
	if b.memoryProfile != "" {
		err := StartMemoryProfile(b.memoryProfile, b.memoryProfileDuration)
		if err != nil {
			log.Printf("Error starting memory profiling, %v", err)
		}
	}

	switch b.mode {
	case DistributedMode:
		b.slaveRunner = newSlaveRunner(b.masterHost, b.masterPort, tasks, b.rateLimiter, b.hatchType)
		for _, o := range b.outputs {
			b.slaveRunner.addOutput(o)
		}
		b.slaveRunner.run()
	case StandaloneMode:
		b.localRunner = newLocalRunner(tasks, b.rateLimiter, b.hatchCount, b.hatchType, b.hatchRate)
		for _, o := range b.outputs {
			b.localRunner.addOutput(o)
		}
		b.localRunner.run()
	default:
		log.Println("Invalid mode, expected boomer.DistributedMode or boomer.StandaloneMode")
	}
}

// RecordSuccess reports a success.
func (b *Boomer) RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	if b.localRunner == nil && b.slaveRunner == nil {
		return
	}
	switch b.mode {
	case DistributedMode:
		b.slaveRunner.stats.requestSuccessChan <- &requestSuccess{
			requestType:    requestType,
			name:           name,
			responseTime:   responseTime,
			responseLength: responseLength,
		}
	case StandaloneMode:
		b.localRunner.stats.requestSuccessChan <- &requestSuccess{
			requestType:    requestType,
			name:           name,
			responseTime:   responseTime,
			responseLength: responseLength,
		}
	}
}

// RecordFailure reports a failure.
func (b *Boomer) RecordFailure(requestType, name string, responseTime int64, exception string) {
	if b.localRunner == nil && b.slaveRunner == nil {
		return
	}
	switch b.mode {
	case DistributedMode:
		b.slaveRunner.stats.requestFailureChan <- &requestFailure{
			requestType:  requestType,
			name:         name,
			responseTime: responseTime,
			error:        exception,
		}
	case StandaloneMode:
		b.localRunner.stats.requestFailureChan <- &requestFailure{
			requestType:  requestType,
			name:         name,
			responseTime: responseTime,
			error:        exception,
		}
	}
}

// Quit will send a quit message to the master.
func (b *Boomer) Quit() {
	Events.Publish("boomer:quit")
	var ticker = time.NewTicker(3 * time.Second)

	switch b.mode {
	case DistributedMode:
		// wait for quit message is sent to master
		select {
		case <-b.slaveRunner.client.disconnectedChannel():
			break
		case <-ticker.C:
			log.Println("Timeout waiting for sending quit message to master, boomer will quit any way.")
			break
		}
		b.slaveRunner.close()
	case StandaloneMode:
		b.localRunner.close()
	}
}

// Run tasks without connecting to the master.
func runTasksForTest(tasks ...*Task) {
	taskNames := strings.Split(runTasks, ",")
	for _, task := range tasks {
		if task.Name == "" {
			continue
		} else {
			for _, name := range taskNames {
				if name == task.Name {
					log.Println("Running " + task.Name)
					task.Fn()
				}
			}
		}
	}
}

// Run accepts a slice of Task and connects to a locust master.
// It's a convenience function to use the defaultBoomer.
func Run(tasks ...*Task) {
	if !flag.Parsed() {
		flag.Parse()
	}

	if runTasks != "" {
		runTasksForTest(tasks...)
		return
	}

	initLegacyEventHandlers()

	rateLimiter, err := createRateLimiter(maxRPS, requestIncreaseRate)
	if err != nil {
		log.Fatalf("%v\n", err)
	}
	defaultBoomer.SetRateLimiter(rateLimiter)
	defaultBoomer.masterHost = masterHost
	defaultBoomer.masterPort = masterPort
	defaultBoomer.hatchType = hatchType
	defaultBoomer.EnableMemoryProfile(memoryProfile, memoryProfileDuration)
	defaultBoomer.EnableCPUProfile(cpuProfile, cpuProfileDuration)

	defaultBoomer.Run(tasks...)

	quitByMe := false
	quitChan := make(chan bool)

	Events.SubscribeOnce("boomer:quit", func() {
		if !quitByMe {
			close(quitChan)
		}
	})

	c := make(chan os.Signal)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)

	select {
	case <-c:
		quitByMe = true
		defaultBoomer.Quit()
	case <-quitChan:
	}

	log.Println("shut down")
}

// RecordSuccess reports a success.
// It's a convenience function to use the defaultBoomer.
func RecordSuccess(requestType, name string, responseTime int64, responseLength int64) {
	defaultBoomer.RecordSuccess(requestType, name, responseTime, responseLength)
}

// RecordFailure reports a failure.
// It's a convenience function to use the defaultBoomer.
func RecordFailure(requestType, name string, responseTime int64, exception string) {
	defaultBoomer.RecordFailure(requestType, name, responseTime, exception)
}
<|endoftext|>


<commit_before>package cli

import "os"
import "fmt"

type writer struct {
	ErrorHandling ErrorHandling
	usage         func()
}

// Usage calls the Usage method for the flag set
func (w *writer) Usage() {
	if w.usage != nil {
		w.usage()
	}
}

// failf prints to standard error a formatted error and usage message and
// returns the error.
func (w *writer) failf(format string, a ...interface{}) error {
	err := fmt.Errorf(format, a...)
	fmt.Fprintln(os.Stderr, err)
	fmt.Fprintln(os.Stderr, "")
	w.Usage()
	return err
}

func (w *writer) errf(format string, a ...interface{}) {
	w.handleErr(w.failf(format, a...))
}

func (w *writer) panicf(format string, a ...interface{}) {
	panic(w.failf(format, a...))
}

func (w *writer) handleErr(err error) {
	if err != nil {
		switch w.ErrorHandling {
		case ExitOnError:
			os.Exit(2)
		case PanicOnError:
			panic(err)
		}
	}
}
<commit_msg>refine naming in writer for godocs<commit_after>package cli

import "os"
import "fmt"

type writer struct {
	ErrorHandling ErrorHandling
	usage         func()
}

// Usage calls the Usage method for the flag set
func (cmd *writer) Usage() {
	if cmd.usage != nil {
		cmd.usage()
	}
}

// failf prints to standard error a formatted error and usage message and
// returns the error.
func (cmd *writer) failf(format string, a ...interface{}) error {
	err := fmt.Errorf(format, a...)
	fmt.Fprintln(os.Stderr, err)
	fmt.Fprintln(os.Stderr, "")
	cmd.Usage()
	return err
}

func (cmd *writer) errf(format string, a ...interface{}) {
	cmd.handleErr(cmd.failf(format, a...))
}

func (cmd *writer) panicf(format string, a ...interface{}) {
	panic(cmd.failf(format, a...))
}

func (cmd *writer) handleErr(err error) {
	if err != nil {
		switch cmd.ErrorHandling {
		case ExitOnError:
			os.Exit(2)
		case PanicOnError:
			panic(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/brutella/hc"
	"github.com/brutella/hc/accessory"
	"github.com/brutella/hc/service"
	"github.com/tarm/serial"
	"log"
)

type MessageType byte

const (
	// checking the availability of the desk
	TypeAliveRequest      MessageType = 0x01
	TypeAliveResponse     MessageType = 0x02

	// setting the height of the desk
	TypeSetHeightRequest  MessageType = 0x03

	// querying the height of the desk
	TypeGetHeightRequest  MessageType = 0x04
	TypeGetHeightResponse MessageType = 0x05

	// stopping the desk
	TypeStopRequest       MessageType = 0x06

	// TODO: to be implemented
	TypeGetStatusRequest  MessageType = 0x07
	TypeGetStatusResponse MessageType = 0x08

	// moving the desk
	TypeMoveUpRequest     MessageType = 0x0A
	TypeMoveDownRequest   MessageType = 0x0B

	// the desk notifying about a height change
	TypeUpdateHeightEvent MessageType = 0x0C
)

type Message struct {
	Type  MessageType
	Value byte
}

func receiver(c chan<- Message, p *serial.Port) {
	message := make([]byte, 3)
	buf := make([]byte, 1)

	for {
		// shift bytes to left
		message[0] = message[1]
		message[1] = message[2]

		// read new byte
		_, err := p.Read(buf)
		if err != nil {
			log.Fatal(err)
		}

		// append new byte
		message[2] = buf[0]

		// checksum
		if message[0]+message[1] != message[2] {
			continue
		}

		c <- Message{Type: MessageType(message[0]), Value: message[1]}
	}
}

func sender(c <-chan Message, p *serial.Port) {
	message := make([]byte, 3)

	for {
		// get a message
		m := <-c

		log.Println("Message to send", m)

		// fill the message buffer
		message[0] = byte(m.Type)
		message[1] = m.Value

		// calculate the checksum
		message[2] = message[0] + message[1]

		log.Println("Buffer to send", message)

		// write the buffer
		_, err := p.Write(message)
		if err != nil {
			log.Fatal(err)
		}
	}
}

func main() {
	info := accessory.Info{
		Name:         "Desk",
		Manufacturer: "David Knezic",
	}

	acc := accessory.New(info, accessory.TypeWindow)

	service := service.NewWindow()
	service.TargetPosition.SetValue(100)

	c := &serial.Config{Name: "/dev/ttyAMA0", Baud: 9600}
	s, err := serial.OpenPort(c)
	if err != nil {
		log.Fatal(err)
	}

	var incoming chan Message = make(chan Message)
	var outgoing chan Message = make(chan Message)

	go receiver(incoming, s)
	go sender(outgoing, s)

	outgoing <- Message{Type: TypeGetHeightRequest}
	hi := <- incoming

	log.Println("height is", hi.Value)

	service.TargetPosition.OnValueRemoteUpdate(func(position int) {
		log.Println("Setting desk to", position, "percent height")

		factor := float64(position) / 100.0
		height := byte(68) + byte(50.0*factor)

		log.Println("This corresponds to", height, "cm height")

		outgoing <- Message{Type: MessageType(TypeSetHeightRequest), Value: height}

		service.CurrentPosition.SetValue(position)
	})

	acc.AddService(service.Service)

	config := hc.Config{
		Pin: "32191123",
	}

	t, err := hc.NewIPTransport(config, acc)

	if err != nil {
		log.Fatal(err)
	}

	hc.OnTermination(func() {
		t.Stop()
	})

	t.Start()
}
<commit_msg>Set initial height asynchronously, extract height conversion<commit_after>package main

import (
	"github.com/brutella/hc"
	"github.com/brutella/hc/accessory"
	"github.com/brutella/hc/service"
	"github.com/tarm/serial"
	"log"
	"time"
)

type MessageType byte

const (
	// checking the availability of the desk
	TypeAliveRequest      MessageType = 0x01
	TypeAliveResponse     MessageType = 0x02

	// setting the height of the desk
	TypeSetHeightRequest  MessageType = 0x03

	// querying the height of the desk
	TypeGetHeightRequest  MessageType = 0x04
	TypeGetHeightResponse MessageType = 0x05

	// stopping the desk
	TypeStopRequest       MessageType = 0x06

	// TODO: to be implemented
	TypeGetStatusRequest  MessageType = 0x07
	TypeGetStatusResponse MessageType = 0x08

	// moving the desk
	TypeMoveUpRequest     MessageType = 0x0A
	TypeMoveDownRequest   MessageType = 0x0B

	// the desk notifying about a height change
	TypeUpdateHeightEvent MessageType = 0x0C
)

type Message struct {
	Type  MessageType
	Value byte
}

func receiver(c chan<- Message, p *serial.Port) {
	message := make([]byte, 3)
	buf := make([]byte, 1)

	for {
		// shift bytes to left
		message[0] = message[1]
		message[1] = message[2]

		// read new byte
		_, err := p.Read(buf)
		if err != nil {
			log.Fatal(err)
		}

		// append new byte
		message[2] = buf[0]

		// checksum
		if message[0]+message[1] != message[2] {
			continue
		}

		c <- Message{Type: MessageType(message[0]), Value: message[1]}
	}
}

func sender(c <-chan Message, p *serial.Port) {
	message := make([]byte, 3)

	for {
		// get a message
		m := <-c

		log.Println("Message to send", m)

		// fill the message buffer
		message[0] = byte(m.Type)
		message[1] = m.Value

		// calculate the checksum
		message[2] = message[0] + message[1]

		log.Println("Buffer to send", message)

		// write the buffer
		_, err := p.Write(message)
		if err != nil {
			log.Fatal(err)
		}
	}
}

func heightToPercentage(height int) int {
	return (height - 68) / 50
}

func heightPercentageToCentimeters(percentage int) int {
	factor := float64(percentage) / 100.0
	return int(68.0 + 50.0*factor)
}

func setInitialDeskPosition(outgoing chan<- Message, incoming <-chan Message, service *service.Window) {
	time.Sleep(2000 * time.Millisecond)

	outgoing <- Message{Type: TypeGetHeightRequest}
        hi := <- incoming

        log.Println("height is", hi.Value)

        percentage := heightToPercentage(int(hi.Value))

	service.TargetPosition.SetValue(percentage)
        service.CurrentPosition.SetValue(percentage)
}

func main() {
	info := accessory.Info{
		Name:         "Desk",
		Manufacturer: "David Knezic",
	}

	acc := accessory.New(info, accessory.TypeWindow)

	service := service.NewWindow()
	service.TargetPosition.SetValue(100)

	c := &serial.Config{Name: "/dev/ttyAMA0", Baud: 9600}
	s, err := serial.OpenPort(c)
	if err != nil {
		log.Fatal(err)
	}

	var incoming chan Message = make(chan Message)
	var outgoing chan Message = make(chan Message)

	go receiver(incoming, s)
	go sender(outgoing, s)

	service.TargetPosition.OnValueRemoteUpdate(func(position int) {
		log.Println("Setting desk to", position, "percent height")

		height := heightPercentageToCentimeters(position)

		log.Println("This corresponds to", height, "cm height")

		outgoing <- Message{Type: MessageType(TypeSetHeightRequest), Value: byte(height)}

		service.CurrentPosition.SetValue(position)
	})

	acc.AddService(service.Service)

	config := hc.Config{
		Pin: "32191123",
	}

	t, err := hc.NewIPTransport(config, acc)

	if err != nil {
		log.Fatal(err)
	}

	hc.OnTermination(func() {
		t.Stop()
	})

	go setInitialDeskPosition(outgoing, incoming, service)

	t.Start()
}
<|endoftext|>


<commit_before>// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 Julien Schmidt. All rights reserved.
// http://www.julienschmidt.com
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package mysql

import "io"

const defaultBufSize = 4096

type buffer struct {
	buf    []byte
	rd     io.Reader
	idx    int
	length int
}

func newBuffer(rd io.Reader) *buffer {
	return &buffer{
		buf: make([]byte, defaultBufSize),
		rd:  rd,
	}
}

// fill reads into the buffer until at least _need_ bytes are in it
func (b *buffer) fill(need int) (err error) {
	// move existing data to the beginning
	if b.length > 0 && b.idx > 0 {
		copy(b.buf[0:b.length], b.buf[b.idx:])
	}

	// grow buffer if necessary
	if need > len(b.buf) {
		b.grow(need)
	}

	b.idx = 0

	var n int
	for b.length < need {
		n, err = b.rd.Read(b.buf[b.length:])
		b.length += n

		if err == nil {
			continue
		}
		return // err
	}

	return
}

// grow the buffer to at least the given size
// credit for this code snippet goes to Maxim Khitrov
// https://groups.google.com/forum/#!topic/golang-nuts/ETbw1ECDgRs
func (b *buffer) grow(size int) {
	// If append would be too expensive, alloc a new slice
	if size > 2*cap(b.buf) {
		newBuf := make([]byte, size)
		copy(newBuf, b.buf)
		b.buf = newBuf
		return
	}

	for cap(b.buf) < size {
		b.buf = append(b.buf[:cap(b.buf)], 0)
	}
	b.buf = b.buf[:cap(b.buf)]
}

// returns next N bytes from buffer.
// The returned slice is only guaranteed to be valid until the next read
func (b *buffer) readNext(need int) (p []byte, err error) {
	if b.length < need {
		// refill
		err = b.fill(need) // err deferred
	}

	p = b.buf[b.idx : b.idx+need]
	b.idx += need
	b.length -= need
	return
}
<commit_msg>doc + micro optimization<commit_after>// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 Julien Schmidt. All rights reserved.
// http://www.julienschmidt.com
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package mysql

import "io"

const defaultBufSize = 4096

// A read buffer similar to bufio.Reader but zero-copy-ish
// Also highly optimized for this particular use case.
type buffer struct {
	buf    []byte
	rd     io.Reader
	idx    int
	length int
}

func newBuffer(rd io.Reader) *buffer {
	return &buffer{
		buf: make([]byte, defaultBufSize),
		rd:  rd,
	}
}

// fill reads into the buffer until at least _need_ bytes are in it
func (b *buffer) fill(need int) (err error) {
	// move existing data to the beginning
	if b.length > 0 && b.idx > 0 {
		copy(b.buf[0:b.length], b.buf[b.idx:])
	}

	// grow buffer if necessary
	if need > len(b.buf) {
		b.grow(need)
	}

	b.idx = 0

	var n int
	for {
		n, err = b.rd.Read(b.buf[b.length:])
		b.length += n

		if b.length < need && err == nil {
			continue
		}
		return // err
	}
}

// grow the buffer to at least the given size
// credit for this code snippet goes to Maxim Khitrov
// https://groups.google.com/forum/#!topic/golang-nuts/ETbw1ECDgRs
func (b *buffer) grow(size int) {
	// If append would be too expensive, alloc a new slice
	if size > cap(b.buf)*2 {
		newBuf := make([]byte, size)
		copy(newBuf, b.buf)
		b.buf = newBuf
		return
	}

	for {
		b.buf = append(b.buf, 0)
		b.buf = b.buf[:cap(b.buf)]

		if cap(b.buf) < size {
			continue
		}
		return
	}
}

// returns next N bytes from buffer.
// The returned slice is only guaranteed to be valid until the next read
func (b *buffer) readNext(need int) (p []byte, err error) {
	if b.length < need {
		// refill
		err = b.fill(need) // err deferred
	}

	p = b.buf[b.idx : b.idx+need]
	b.idx += need
	b.length -= need
	return
}
<|endoftext|>


<commit_before>package quaternion

/*
Quaternion array package
A Quaternion array is a struct with 4 columns defined as x y z w
it can be created simply using slice.
*/

import "math"
import "github.com/gonum/matrix/mat64"

type qMatrix struct {
	qMat []float64
}

//Dot product of a lists of arrays, returns a column array
func (qm *qMatrix) ArrayDot(q, []float64) {

}

//Inverse of quaternion array q
func (qm *qMatrix) Inverse(q []float64) []float64 {
	return q * qm.qMat{-1, -1, -1, 1}
}

func (qm *qMatrix) Amplitude(q []float64) []float64 {

}

//Normalize quaternion array q or array list to unit quaternions
func (qm *qMatrix) Norm([]float64) []float64 {

}

//
func Mul() {

}

//Exponential of a quaternion array
func (qm *qMatrix) Exp() {

}

//Neprien logarithm of a quaternion array
func (qm *qMatrix) Ln() {

}

//Real power of a quaternion array
func (qm *qMatrix) Pow() {

}

//Rotate vector or array of vectors v by quaternion q
func Rotate(q []float64) {

}

//
func Toaxisangle() {

}
<commit_msg>Update quaternion.go<commit_after>package quaternion

/*
Quaternion array package
A Quaternion array is a struct with 4 columns defined as x y z w
it can be created simply using slice.
*/

import "math"
import "github.com/gonum/matrix/mat64"

type qMatrix struct {
	qMat []float64
}

//Dot product of a lists of arrays, returns a column array
func (qm *qMatrix) ArrayDot(q, []float64) {}

//Inverse of quaternion array q
func (qm *qMatrix) Inverse(q []float64) []float64 {
	return q * qm.qMat{-1, -1, -1, 1}
}

func (qm *qMatrix) Amplitude(q []float64) []float64 {}

//Normalize quaternion array q or array list to unit quaternions
func (qm *qMatrix) Norm([]float64) []float64 {}

//
func Mul() {}

//Exponential of a quaternion array
func (qm *qMatrix) Exp() {

}

//Neprien logarithm of a quaternion array
func (qm *qMatrix) Ln() {}

//Real power of a quaternion array
func (qm *qMatrix) Pow() {}

//Rotate vector or array of vectors v by quaternion q
func Rotate(q []float64) {}

//
func Toaxisangle() {}
<|endoftext|>