<commit_before>// Package tradingdays - Check the day is open or not
// 股市開休市判斷（支援非國定假日：颱風假）
//
package tradingdays

import (
	"bytes"
	"encoding/csv"
	"io"
	"io/ioutil"
	"net/http"
	"path"
	"runtime"
	"time"

	"github.com/toomore/gogrs/utils"
)

// IsOpen 判斷是否為開休日
func IsOpen(year int, month time.Month, day int) bool {
	d := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
	if openornot, ok := exceptDays[d.Unix()]; ok {
		return openornot
	}
	if d.In(utils.TaipeiTimeZone).Weekday() == 0 || d.In(utils.TaipeiTimeZone).Weekday() == 6 {
		return false
	}
	return true
}

// FindRecentlyOpened 回傳最近一個開市時間
func FindRecentlyOpened() time.Time {
	d := time.Now().UTC()
	days := d.Day()
	for {
		if IsOpen(d.Year(), d.Month(), days) {
			return time.Date(d.Year(), d.Month(), days, 0, 0, 0, 0, time.UTC)
		}
		days--
	}
}

var exceptDays map[int64]bool
var timeLayout = "2006/1/2"

func readCSV() {
	_, filename, _, _ := runtime.Caller(1)
	data, _ := ioutil.ReadFile(path.Join(path.Dir(filename), "list.csv"))
	processCSV(bytes.NewReader(data))
}

// DownloadCSV 更新開休市表
//
// 從 https://s3-ap-northeast-1.amazonaws.com/toomore/gogrs/list.csv
// 下載表更新，主要發生在非國定假日，如：颱風假。
func DownloadCSV(replace bool) {
	resp, _ := http.Get("https://s3-ap-northeast-1.amazonaws.com/toomore/gogrs/list.csv")
	defer resp.Body.Close()
	if data, err := ioutil.ReadAll(resp.Body); err == nil {
		if replace {
			exceptDays = make(map[int64]bool)
		}
		processCSV(bytes.NewReader(data))
	}
}

func processCSV(data io.Reader) {
	csvdata := csv.NewReader(data)

	for {
		record, err := csvdata.Read()
		if err == io.EOF {
			break
		}
		if t, err := time.ParseInLocation(timeLayout, record[0], time.UTC); err == nil {
			var isopen bool
			if record[1] == "1" {
				isopen = true
			}
			exceptDays[t.Unix()] = isopen
		}
	}
}

// TimePeriod 簡單計算時間是否在當日的開盤前、盤中、盤後盤、收盤的時間
/*
相關時間：
	- 開盤前	00:00 ~ 09:00
	- 盤中	09:00 ~ 13:30
	- 盤後盤	13:30 ~ 14:30
	- 收盤	14:30 ~ 24:00

證交所會在 13:30 後產生一次報表，14:30 盤後盤零股交易後還會再產生一次報表。
*/
type TimePeriod struct {
	Date time.Time
}

// AtBefore 檢查是否為 開盤前（0000-0900） 期間
func (t TimePeriod) AtBefore() bool {
	var d = &ezTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(0, 0).Unix() && d.date.Unix() < d.time(9, 0).Unix() {
		return true
	}

	return false
}

// AtOpen 檢查是否為 開盤（0900-1330） 期間
func (t TimePeriod) AtOpen() bool {
	var d = &ezTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(9, 0).Unix() && d.date.Unix() < d.time(13, 30).Unix() {
		return true
	}
	return false
}

// AtAfterOpen 檢查是否為 盤後盤（1330-1430） 期間
func (t TimePeriod) AtAfterOpen() bool {
	var d = &ezTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(13, 30).Unix() && d.date.Unix() < d.time(14, 30).Unix() {
		return true
	}
	return false
}

// AtClose 檢查是否為 收盤（1430-2400）期間
func (t TimePeriod) AtClose() bool {
	var d = &ezTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(14, 30).Unix() && d.date.Unix() < d.time(24, 0).Unix() {
		return true
	}
	return false
}

type ezTime struct {
	date time.Time
}

func (t ezTime) time(hour, min int) time.Time {
	return time.Date(t.date.Year(), t.date.Month(), t.date.Day(), hour, min, 0, 0, t.date.Location())
}

func init() {
	exceptDays = make(map[int64]bool)
	readCSV()
}
<commit_msg>Rename.<commit_after>// Package tradingdays - Check the day is open or not
// 股市開休市判斷（支援非國定假日：颱風假）
//
package tradingdays

import (
	"bytes"
	"encoding/csv"
	"io"
	"io/ioutil"
	"net/http"
	"path"
	"runtime"
	"time"

	"github.com/toomore/gogrs/utils"
)

// IsOpen 判斷是否為開休日
func IsOpen(year int, month time.Month, day int) bool {
	d := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
	if openornot, ok := exceptDays[d.Unix()]; ok {
		return openornot
	}
	if d.In(utils.TaipeiTimeZone).Weekday() == 0 || d.In(utils.TaipeiTimeZone).Weekday() == 6 {
		return false
	}
	return true
}

// FindRecentlyOpened 回傳最近一個開市時間
func FindRecentlyOpened() time.Time {
	d := time.Now().UTC()
	days := d.Day()
	for {
		if IsOpen(d.Year(), d.Month(), days) {
			return time.Date(d.Year(), d.Month(), days, 0, 0, 0, 0, time.UTC)
		}
		days--
	}
}

var exceptDays map[int64]bool
var timeLayout = "2006/1/2"

func readCSV() {
	_, filename, _, _ := runtime.Caller(1)
	data, _ := ioutil.ReadFile(path.Join(path.Dir(filename), "list.csv"))
	processCSV(bytes.NewReader(data))
}

// DownloadCSV 更新開休市表
//
// 從 https://s3-ap-northeast-1.amazonaws.com/toomore/gogrs/list.csv
// 下載表更新，主要發生在非國定假日，如：颱風假。
func DownloadCSV(replace bool) {
	resp, _ := http.Get("https://s3-ap-northeast-1.amazonaws.com/toomore/gogrs/list.csv")
	defer resp.Body.Close()
	if data, err := ioutil.ReadAll(resp.Body); err == nil {
		if replace {
			exceptDays = make(map[int64]bool)
		}
		processCSV(bytes.NewReader(data))
	}
}

func processCSV(data io.Reader) {
	csvdata := csv.NewReader(data)

	for {
		record, err := csvdata.Read()
		if err == io.EOF {
			break
		}
		if t, err := time.ParseInLocation(timeLayout, record[0], time.UTC); err == nil {
			var isopen bool
			if record[1] == "1" {
				isopen = true
			}
			exceptDays[t.Unix()] = isopen
		}
	}
}

// TimePeriod 簡單計算時間是否在當日的開盤前、盤中、盤後盤、收盤的時間
/*
相關時間：
	- 開盤前	00:00 ~ 09:00
	- 盤中	09:00 ~ 13:30
	- 盤後盤	13:30 ~ 14:30
	- 收盤	14:30 ~ 24:00

證交所會在 13:30 後產生一次報表，14:30 盤後盤零股交易後還會再產生一次報表。
*/
type TimePeriod struct {
	Date time.Time
}

// AtBefore 檢查是否為 開盤前（0000-0900） 期間
func (t TimePeriod) AtBefore() bool {
	var d = &lazyTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(0, 0).Unix() && d.date.Unix() < d.time(9, 0).Unix() {
		return true
	}

	return false
}

// AtOpen 檢查是否為 開盤（0900-1330） 期間
func (t TimePeriod) AtOpen() bool {
	var d = &lazyTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(9, 0).Unix() && d.date.Unix() < d.time(13, 30).Unix() {
		return true
	}
	return false
}

// AtAfterOpen 檢查是否為 盤後盤（1330-1430） 期間
func (t TimePeriod) AtAfterOpen() bool {
	var d = &lazyTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(13, 30).Unix() && d.date.Unix() < d.time(14, 30).Unix() {
		return true
	}
	return false
}

// AtClose 檢查是否為 收盤（1430-2400）期間
func (t TimePeriod) AtClose() bool {
	var d = &lazyTime{date: t.Date.In(utils.TaipeiTimeZone)}

	if d.date.Unix() >= d.time(14, 30).Unix() && d.date.Unix() < d.time(24, 0).Unix() {
		return true
	}
	return false
}

type lazyTime struct {
	date time.Time
}

func (t lazyTime) time(hour, min int) time.Time {
	return time.Date(t.date.Year(), t.date.Month(), t.date.Day(), hour, min, 0, 0, t.date.Location())
}

func init() {
	exceptDays = make(map[int64]bool)
	readCSV()
}
<|endoftext|>


<commit_before>// Package translatedassert is not for human.
package translatedassert

import (
	"fmt"
	"github.com/mattn/go-runewidth"
	"reflect"
	"strings"
	"sync"
	"testing"
)

var cachedFuncRet = map[string]map[int]interface{}{}
var cachedFuncRetMutex = &sync.Mutex{}
var stdoutIsatty bool

type posValuePair struct {
	Pos     int
	Value   interface{}
	Powered bool
}

// NewPosValuePair has nodoc
// **This is not for human**
func NewPosValuePair(pos int, v interface{}, p bool) posValuePair {
	return posValuePair{Pos: pos, Value: v, Powered: p}
}

// OK has nodoc
// **This is not for human**
func OK(t *testing.T, e bool, messages []string, header, filename string, line int, origexpr string, termw int, expectedPosValueIndex, gotPosValueIndex int, pvPairs ...posValuePair) {
	stdoutIsatty = termw > 0

	if e {
		return
	}

	output := fmt.Sprintf("%s %s:%d\n%s", header, filename, line, origexpr) + "\n" + format(pvPairs)

	lines := []string{}

	for _, line := range strings.Split(output, "\n") {
		tabw := 8 // FIXME

		// $GOROOT/src/pkg/testing/testing.go
		// 194 func decorate(s string) string {
		// 217 // Second and subsequent lines are indented an extra tab.
		// 218 buf.WriteString("\n\t\t")
		terrorw := tabw * 2

		if stdoutIsatty && runewidth.StringWidth(line) > termw-terrorw {
			lines = append(lines, truncate(line, termw-terrorw, "[ommitted]..."))
		} else {
			lines = append(lines, line)
		}
	}

	if len(messages) > 0 {
		lines = append(lines, "Assersion messages:")
		for _, msg := range messages {
			lines = append(lines, "\t- "+msg)
		}
		lines = append(lines, "")
	}

	if expectedPosValueIndex >= 0 && gotPosValueIndex >= 0 {
		var expected interface{}
		var got interface{}
		efound := false
		gfound := false
		for _, pv := range pvPairs {
			if pv.Pos == expectedPosValueIndex {
				expected = pv.Value
				efound = true
			}
			if pv.Pos == gotPosValueIndex {
				got = pv.Value
				gfound = true
			}
		}

		d := false
		if _, ok := expected.(string); ok {
			if _, ok := got.(string); ok {
				d = true
			}
		}
		if efound && gfound {
			if d {
				diffOutput, diffType := diff(expected.(string), got.(string))
				if diffType == diffTypeChar {
					//				lines = append(lines, "{+ins+}/{-del-}")
				}
				lines = append(lines, diffOutput)
			} else {
				lines = append(lines, fmt.Sprintf("[expected] %v", expected))
				lines = append(lines, fmt.Sprintf("[got] %v", got))
			}
			lines = append(lines, "")
		}
	}

	t.Error(strings.Join(lines, "\n"))

	cachedFuncRetMutex.Lock()
	defer cachedFuncRetMutex.Unlock()

	key := fmt.Sprintf("%s:%d", filename, line)
	if _, ok := cachedFuncRet[key]; ok {
		delete(cachedFuncRet, key)
	}
}

// Require has nodoc
// **This is not for human**
func Require(t *testing.T, e bool, messages []string, header, filename string, line int, origexpr string, termw int, expectedPosValueIndex, gotPosValueIndex int, pvPairs ...posValuePair) {
	OK(t, e, messages, header, filename, line, origexpr, termw, expectedPosValueIndex, gotPosValueIndex, pvPairs...)
	if !e {
		t.Skip("skip by gopwt/assert.Require")
	}
}

// --------------------------------------------------------------------------------
// Reflect
// --------------------------------------------------------------------------------

// MFCall momorize and call func
func MFCall(filename string, line, col int, f reflect.Value, args ...reflect.Value) []reflect.Value {
	cachedFuncRetMutex.Lock()
	defer cachedFuncRetMutex.Unlock()

	key := fmt.Sprintf("%s:%d", filename, line)

	if _, ok := cachedFuncRet[key]; !ok {
		cachedFuncRet[key] = map[int]interface{}{}
	}

	rets := cachedFuncRet[key]

	if _, ok := rets[col]; !ok {
		for i, a := range args {
			// hack to passing nil...
			if !a.IsValid() {
				args[i] = reflectNilValue(f.Type().In(i))
			}
		}

		ret := FRVInterface(f.Call(args))
		rets[col] = ret
	}

	return []reflect.Value{reflect.ValueOf(rets[col])}
}

// RVOf is reflect.ValueOf
func RVOf(a interface{}) reflect.Value {
	return reflect.ValueOf(a)
}

// RTOf is reflect.TypeOf
func RTOf(a interface{}) reflect.Type {
	return reflect.TypeOf(a)
}

// RVBool returns reflect value as bool
func RVBool(rv reflect.Value) bool {
	return rv.Bool()
}

// FRVBool returns first of reflect values as bool
func FRVBool(rvs []reflect.Value) bool {
	return RVBool(rvs[0])
}

// RVInterface returns reflect value as interface{}
func RVInterface(rv reflect.Value) interface{} {
	if !rv.IsValid() {
		return nil
	}

	return rv.Interface()
}

// FRVInterface returns first of reflect values as interface{}
func FRVInterface(rvs []reflect.Value) interface{} {
	rv := rvs[0]

	return RVInterface(rv)
}

func reflectNilValue(t reflect.Type) reflect.Value {
	return reflect.New(t).Elem()
}

// --------------------------------------------------------------------------------
// Format
// --------------------------------------------------------------------------------

func format(_pvPairs []posValuePair) string {
	pvPairs := []posValuePair{}
	for _, p := range _pvPairs {
		if p.Powered {
			pvPairs = append(pvPairs, p)
		}
	}

	buf := make([]byte, 0, 50*len(pvPairs)*len(pvPairs)) // Try to avoid more allocations

	// first line
	cx := 0
	for x := 0; x < len(pvPairs); x++ {
		for i := 0; i < pvPairs[x].Pos-cx-1; i++ {
			buf = append(buf, byte(' '))
		}

		cx = pvPairs[x].Pos - 1
		buf = append(buf, byte('|'))
		cx++
	}
	buf = append(buf, byte('\n'))

	for y := 0; y < len(pvPairs); y++ {
		cx := 0

		for x := 0; x < len(pvPairs); x++ {
			if len(pvPairs)-y-1 != x {
				continue
			}

			// print "foo\nhoge" as "foo
			//                      hoge"
			for lnum, lstr := range strings.Split(formatValue(pvPairs[x].Value), "\\n") {
				if lnum > 0 {
					buf = append(buf, byte('\n'))
					cx = 0
				}

				// fill by space or vbar
				// e.g.
				// |  |
				// |  foo
				//[| ]bar
				for i := 0; i < pvPairs[x].Pos-1; i++ {
					found := false

					for _, n := range pvPairs[:x] {
						if n.Pos != i+1 {
							continue
						}

						found = true
						buf = append(buf, byte('|'))
						cx++
						break
					}

					if !found {
						buf = append(buf, byte(' '))
						cx++
					}
				}

				// embed value
				// e.g.
				// |  |
				// |  foo
				// | [bar]
				buf = append(buf, lstr...)
			}

			break
		}

		buf = append(buf, byte('\n'))
	}

	return string(buf)
}

// TODO use own impl instead of fmt.Sprintf("%#v", a)
func formatValue(a interface{}) string {
	return fmt.Sprintf("%#v", a)
}

func truncate(s string, w int, tail string) string {
	if w-len(tail) <= 0 {
		return tail
	}

	return _truncate(s, w-len(tail)) + tail
}

func _truncate(s string, w int) string {
	rs := []rune(s)
	i := 0

	cw := 0

	for _, r := range rs {
		rw := runewidth.RuneWidth(r)
		if cw+rw <= w {
			i++
			cw += rw
		} else {
			break
		}
	}

	return string(rs[0:i])
}
<commit_msg>refactor(gopwt/translatedassert): rename to correct<commit_after>// Package translatedassert is not for human.
package translatedassert

import (
	"fmt"
	"github.com/mattn/go-runewidth"
	"reflect"
	"strings"
	"sync"
	"testing"
)

var cachedFuncRet = map[string]map[int]interface{}{}
var cachedFuncRetMutex = &sync.Mutex{}
var stdoutIsatty bool

type posValuePair struct {
	Pos     int
	Value   interface{}
	Powered bool
}

// NewPosValuePair has nodoc
// **This is not for human**
func NewPosValuePair(pos int, v interface{}, p bool) posValuePair {
	return posValuePair{Pos: pos, Value: v, Powered: p}
}

// OK has nodoc
// **This is not for human**
func OK(t *testing.T, e bool, messages []string, header, filename string, line int, origexpr string, termw int, expectedPos, gotPos int, pvPairs ...posValuePair) {
	stdoutIsatty = termw > 0

	if e {
		return
	}

	output := fmt.Sprintf("%s %s:%d\n%s", header, filename, line, origexpr) + "\n" + format(pvPairs)

	lines := []string{}

	for _, line := range strings.Split(output, "\n") {
		tabw := 8 // FIXME

		// $GOROOT/src/pkg/testing/testing.go
		// 194 func decorate(s string) string {
		// 217 // Second and subsequent lines are indented an extra tab.
		// 218 buf.WriteString("\n\t\t")
		terrorw := tabw * 2

		if stdoutIsatty && runewidth.StringWidth(line) > termw-terrorw {
			lines = append(lines, truncate(line, termw-terrorw, "[ommitted]..."))
		} else {
			lines = append(lines, line)
		}
	}

	if len(messages) > 0 {
		lines = append(lines, "Assersion messages:")
		for _, msg := range messages {
			lines = append(lines, "\t- "+msg)
		}
		lines = append(lines, "")
	}

	if expectedPos >= 0 && gotPos >= 0 {
		var expected interface{}
		var got interface{}
		efound := false
		gfound := false
		for _, pv := range pvPairs {
			if pv.Pos == expectedPos {
				expected = pv.Value
				efound = true
			}
			if pv.Pos == gotPos {
				got = pv.Value
				gfound = true
			}
		}

		d := false
		if _, ok := expected.(string); ok {
			if _, ok := got.(string); ok {
				d = true
			}
		}
		if efound && gfound {
			if d {
				diffOutput, diffType := diff(expected.(string), got.(string))
				if diffType == diffTypeChar {
					//				lines = append(lines, "{+ins+}/{-del-}")
				}
				lines = append(lines, diffOutput)
			} else {
				lines = append(lines, fmt.Sprintf("[expected] %v", expected))
				lines = append(lines, fmt.Sprintf("[got] %v", got))
			}
			lines = append(lines, "")
		}
	}

	t.Error(strings.Join(lines, "\n"))

	cachedFuncRetMutex.Lock()
	defer cachedFuncRetMutex.Unlock()

	key := fmt.Sprintf("%s:%d", filename, line)
	if _, ok := cachedFuncRet[key]; ok {
		delete(cachedFuncRet, key)
	}
}

// Require has nodoc
// **This is not for human**
func Require(t *testing.T, e bool, messages []string, header, filename string, line int, origexpr string, termw int, expectedPos, gotPos int, pvPairs ...posValuePair) {
	OK(t, e, messages, header, filename, line, origexpr, termw, expectedPos, gotPos, pvPairs...)
	if !e {
		t.Skip("skip by gopwt/assert.Require")
	}
}

// --------------------------------------------------------------------------------
// Reflect
// --------------------------------------------------------------------------------

// MFCall momorize and call func
func MFCall(filename string, line, col int, f reflect.Value, args ...reflect.Value) []reflect.Value {
	cachedFuncRetMutex.Lock()
	defer cachedFuncRetMutex.Unlock()

	key := fmt.Sprintf("%s:%d", filename, line)

	if _, ok := cachedFuncRet[key]; !ok {
		cachedFuncRet[key] = map[int]interface{}{}
	}

	rets := cachedFuncRet[key]

	if _, ok := rets[col]; !ok {
		for i, a := range args {
			// hack to passing nil...
			if !a.IsValid() {
				args[i] = reflectNilValue(f.Type().In(i))
			}
		}

		ret := FRVInterface(f.Call(args))
		rets[col] = ret
	}

	return []reflect.Value{reflect.ValueOf(rets[col])}
}

// RVOf is reflect.ValueOf
func RVOf(a interface{}) reflect.Value {
	return reflect.ValueOf(a)
}

// RTOf is reflect.TypeOf
func RTOf(a interface{}) reflect.Type {
	return reflect.TypeOf(a)
}

// RVBool returns reflect value as bool
func RVBool(rv reflect.Value) bool {
	return rv.Bool()
}

// FRVBool returns first of reflect values as bool
func FRVBool(rvs []reflect.Value) bool {
	return RVBool(rvs[0])
}

// RVInterface returns reflect value as interface{}
func RVInterface(rv reflect.Value) interface{} {
	if !rv.IsValid() {
		return nil
	}

	return rv.Interface()
}

// FRVInterface returns first of reflect values as interface{}
func FRVInterface(rvs []reflect.Value) interface{} {
	rv := rvs[0]

	return RVInterface(rv)
}

func reflectNilValue(t reflect.Type) reflect.Value {
	return reflect.New(t).Elem()
}

// --------------------------------------------------------------------------------
// Format
// --------------------------------------------------------------------------------

func format(_pvPairs []posValuePair) string {
	pvPairs := []posValuePair{}
	for _, p := range _pvPairs {
		if p.Powered {
			pvPairs = append(pvPairs, p)
		}
	}

	buf := make([]byte, 0, 50*len(pvPairs)*len(pvPairs)) // Try to avoid more allocations

	// first line
	cx := 0
	for x := 0; x < len(pvPairs); x++ {
		for i := 0; i < pvPairs[x].Pos-cx-1; i++ {
			buf = append(buf, byte(' '))
		}

		cx = pvPairs[x].Pos - 1
		buf = append(buf, byte('|'))
		cx++
	}
	buf = append(buf, byte('\n'))

	for y := 0; y < len(pvPairs); y++ {
		cx := 0

		for x := 0; x < len(pvPairs); x++ {
			if len(pvPairs)-y-1 != x {
				continue
			}

			// print "foo\nhoge" as "foo
			//                      hoge"
			for lnum, lstr := range strings.Split(formatValue(pvPairs[x].Value), "\\n") {
				if lnum > 0 {
					buf = append(buf, byte('\n'))
					cx = 0
				}

				// fill by space or vbar
				// e.g.
				// |  |
				// |  foo
				//[| ]bar
				for i := 0; i < pvPairs[x].Pos-1; i++ {
					found := false

					for _, n := range pvPairs[:x] {
						if n.Pos != i+1 {
							continue
						}

						found = true
						buf = append(buf, byte('|'))
						cx++
						break
					}

					if !found {
						buf = append(buf, byte(' '))
						cx++
					}
				}

				// embed value
				// e.g.
				// |  |
				// |  foo
				// | [bar]
				buf = append(buf, lstr...)
			}

			break
		}

		buf = append(buf, byte('\n'))
	}

	return string(buf)
}

// TODO use own impl instead of fmt.Sprintf("%#v", a)
func formatValue(a interface{}) string {
	return fmt.Sprintf("%#v", a)
}

func truncate(s string, w int, tail string) string {
	if w-len(tail) <= 0 {
		return tail
	}

	return _truncate(s, w-len(tail)) + tail
}

func _truncate(s string, w int) string {
	rs := []rune(s)
	i := 0

	cw := 0

	for _, r := range rs {
		rw := runewidth.RuneWidth(r)
		if cw+rw <= w {
			i++
			cw += rw
		} else {
			break
		}
	}

	return string(rs[0:i])
}
<|endoftext|>


<commit_before>package treewatcher

import (
	"github.com/howeyc/fsnotify"
	"os"
	"path/filepath"
)

// TreeWatcher is a wrapper around fsnotify.Watcher that monitors all
// directories within a tree, and automatically adds watches on newly created
// directories under the tree. All events from the fsnotify.Watcher are passed
// through to the TreeWatcher's channels.
type TreeWatcher struct {
	Event chan *fsnotify.FileEvent
	Error chan error

	quit    chan int
	watcher *fsnotify.Watcher
}

func (tw *TreeWatcher) fsNotifyHandler() {
	for {
		select {
		case event := <-tw.watcher.Event:
			// Watch the tree before sending the event, so that the client
			// won't miss any changes between when the channel send happens
			// and when the watch starts.
			if event.IsCreate() {
				stat, err := os.Stat(event.Name)
				if err == nil && stat.IsDir() {
					tw.WatchTree(event.Name)
				}
			}

			tw.Event <- event
		case err := <-tw.watcher.Error:
			tw.Error <- err

		case <-tw.quit:
			return
		}
	}
}

func (tw *TreeWatcher) Close() {
	tw.watcher.Close()
	tw.quit <- 1
}

func (tw *TreeWatcher) WatchTree(path string) {
	tw.watcher.Watch(path)
	filepath.Walk(path, func(file string, info os.FileInfo, err error) error {
		if info.IsDir() {
			tw.watcher.Watch(file)
		}
		return nil
	})
}

func (tw *TreeWatcher) Watch(path string) error {
	return tw.watcher.Watch(path)
}

func New() (*TreeWatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	eventChan := make(chan *fsnotify.FileEvent, 10)
	errorChan := make(chan error, 10)
	quitChan := make(chan int)

	tw := &TreeWatcher{eventChan, errorChan, quitChan, watcher}
	go tw.fsNotifyHandler()
	return tw, nil
}
<commit_msg>Fix error in Walk handler when called on nonexistent path<commit_after>package treewatcher

import (
	"github.com/howeyc/fsnotify"
	"os"
	"path/filepath"
)

// TreeWatcher is a wrapper around fsnotify.Watcher that monitors all
// directories within a tree, and automatically adds watches on newly created
// directories under the tree. All events from the fsnotify.Watcher are passed
// through to the TreeWatcher's channels.
type TreeWatcher struct {
	Event chan *fsnotify.FileEvent
	Error chan error

	quit    chan int
	watcher *fsnotify.Watcher
}

func (tw *TreeWatcher) fsNotifyHandler() {
	for {
		select {
		case event := <-tw.watcher.Event:
			// Watch the tree before sending the event, so that the client
			// won't miss any changes between when the channel send happens
			// and when the watch starts.
			if event.IsCreate() {
				stat, err := os.Stat(event.Name)
				if err == nil && stat.IsDir() {
					tw.WatchTree(event.Name)
				}
			}

			tw.Event <- event
		case err := <-tw.watcher.Error:
			tw.Error <- err

		case <-tw.quit:
			return
		}
	}
}

func (tw *TreeWatcher) Close() {
	tw.watcher.Close()
	tw.quit <- 1
}

func (tw *TreeWatcher) WatchTree(path string) {
	tw.watcher.Watch(path)
	filepath.Walk(path, func(file string, info os.FileInfo, err error) error {
		if info != nil && info.IsDir() {
			tw.watcher.Watch(file)
		}
		return nil
	})
}

func (tw *TreeWatcher) Watch(path string) error {
	return tw.watcher.Watch(path)
}

func New() (*TreeWatcher, error) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	eventChan := make(chan *fsnotify.FileEvent, 10)
	errorChan := make(chan error, 10)
	quitChan := make(chan int)

	tw := &TreeWatcher{eventChan, errorChan, quitChan, watcher}
	go tw.fsNotifyHandler()
	return tw, nil
}
<|endoftext|>


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

package oto

import (
	"io"
)

// Context is the main object in Oto. It interacts with the audio drivers.
//
// To play sound with Oto, first create a context. Then use the context to create
// an arbitrary number of players. Then use the players to play sound.
//
// There can only be one context at any time. Closing a context and opening a new one is allowed.
type Context struct {
	context *context
}

// NewPlayer creates a new, ready-to-use Player belonging to the Context.
//
// The r's format is as follows:
//   [data]      = [sample 1] [sample 2] [sample 3] ...
//   [sample *]  = [channel 1] ...
//   [channel *] = [byte 1] [byte 2] ...
// Byte ordering is little endian.
//
// A player has some amount of an underlying buffer.
// Read data from r is queued to the player's underlying buffer.
// The underlying buffer is consumed by its playing.
// Then, r's position and the current playing position don't necessarily match.
// If you want to clear the underlying buffer for some reasons e.g., you want to seek the position of r,
// call the player's Reset function.
//
// You cannot share r by multiple players.
//
// NewPlayer is concurrent-safe.
//
// All the functions of a Player returned by NewPlayer are concurrent-safe.
func (c *Context) NewPlayer(r io.Reader) Player {
	return c.context.NewPlayer(r)
}

// Suspend suspends the entire audio play.
//
// Suspend is concurrent-safe.
func (c *Context) Suspend() error {
	return c.context.Suspend()
}

// Resume resumes the entire audio play, which was suspended by Suspend.
//
// Resume is concurrent-safe.
func (c *Context) Resume() error {
	return c.context.Resume()
}

// NewContext creates a new context, that creates and holds ready-to-use Player objects,
// and returns a context, a channel that is closed when the context is ready, and an error if it exists.
//
// The sampleRate argument specifies the number of samples that should be played during one second.
// Usual numbers are 44100 or 48000.
//
// The channelNum argument specifies the number of channels. One channel is mono playback. Two
// channels are stereo playback. No other values are supported.
//
// The bitDepthInBytes argument specifies the number of bytes per sample per channel. The usual value
// is 2. Only values 1 and 2 are supported.
func NewContext(sampleRate int, channelNum int, bitDepthInBytes int) (*Context, chan struct{}, error) {
	ctx, ready, err := newContext(sampleRate, channelNum, bitDepthInBytes)
	if err != nil {
		return nil, nil, err
	}
	return &Context{context: ctx}, ready, nil
}

// Player is a PCM (pulse-code modulation) audio player.
type Player interface {
	// Pause pauses its playing.
	Pause()

	// Play starts its playing if it doesn't play.
	Play()

	// IsPlaying reports whether this player is playing.
	IsPlaying() bool

	// Reset clears the underyling buffer and pauses its playing.
	Reset()

	// Volume returns the current volume in between [0, 1].
	// The default volume is 1.
	Volume() float64

	// SetVolume sets the current volume in between [0, 1].
	SetVolume(volume float64)

	// UnplayedBufferSize returns the byte size in the underlying buffer that is not played yet.
	UnplayedBufferSize() int

	// Err returns an error if this player has an error.
	Err() error

	io.Closer
}

type playerState int

const (
	playerPaused playerState = iota
	playerPlay
	playerClosed
)

// TODO: The term 'buffer' is confusing. Name each buffer with good terms.

// oneBufferSize returns the size of one buffer in the player implementation.
func (c *context) oneBufferSize() int {
	bytesPerSample := c.channelNum * c.bitDepthInBytes
	s := c.sampleRate * bytesPerSample / 4

	// Align s in multiples of bytes per sample, or a buffer could have extra bytes.
	return s / bytesPerSample * bytesPerSample
}

// maxBufferSize returns the maximum size of the buffer for the audio source.
// This buffer is used when unreading on pausing the player.
func (c *context) maxBufferSize() int {
	// The number of underlying buffers should be 2.
	return c.oneBufferSize() * 2
}
<commit_msg>Fix comments<commit_after>// Copyright 2021 The Oto Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oto

import (
	"io"
)

// Context is the main object in Oto. It interacts with the audio drivers.
//
// To play sound with Oto, first create a context. Then use the context to create
// an arbitrary number of players. Then use the players to play sound.
//
// There can only be one context at any time. Closing a context and opening a new one is allowed.
type Context struct {
	context *context
}

// NewPlayer creates a new, ready-to-use Player belonging to the Context.
//
// The r's format is as follows:
//   [data]      = [sample 1] [sample 2] [sample 3] ...
//   [sample *]  = [channel 1] ...
//   [channel *] = [byte 1] [byte 2] ...
// Byte ordering is little endian.
//
// A player has some amount of an underlying buffer.
// Read data from r is queued to the player's underlying buffer.
// The underlying buffer is consumed by its playing.
// Then, r's position and the current playing position don't necessarily match.
// If you want to clear the underlying buffer for some reasons e.g., you want to seek the position of r,
// call the player's Reset function.
//
// You cannot share r by multiple players.
//
// NewPlayer is concurrent-safe.
//
// All the functions of a Player returned by NewPlayer are concurrent-safe.
func (c *Context) NewPlayer(r io.Reader) Player {
	return c.context.NewPlayer(r)
}

// Suspend suspends the entire audio play.
//
// Suspend is concurrent-safe.
func (c *Context) Suspend() error {
	return c.context.Suspend()
}

// Resume resumes the entire audio play, which was suspended by Suspend.
//
// Resume is concurrent-safe.
func (c *Context) Resume() error {
	return c.context.Resume()
}

// NewContext creates a new context, that creates and holds ready-to-use Player objects,
// and returns a context, a channel that is closed when the context is ready, and an error if it exists.
//
// The sampleRate argument specifies the number of samples that should be played during one second.
// Usual numbers are 44100 or 48000.
//
// The channelNum argument specifies the number of channels. One channel is mono playback. Two
// channels are stereo playback. No other values are supported.
//
// The bitDepthInBytes argument specifies the number of bytes per sample per channel. The usual value
// is 2. Only values 1 and 2 are supported.
func NewContext(sampleRate int, channelNum int, bitDepthInBytes int) (*Context, chan struct{}, error) {
	ctx, ready, err := newContext(sampleRate, channelNum, bitDepthInBytes)
	if err != nil {
		return nil, nil, err
	}
	return &Context{context: ctx}, ready, nil
}

// Player is a PCM (pulse-code modulation) audio player.
type Player interface {
	// Pause pauses its playing.
	Pause()

	// Play starts its playing if it doesn't play.
	Play()

	// IsPlaying reports whether this player is playing.
	IsPlaying() bool

	// Reset clears the underyling buffer and pauses its playing.
	Reset()

	// Volume returns the current volume in the range of [0, 1].
	// The default volume is 1.
	Volume() float64

	// SetVolume sets the current volume in the range of [0, 1].
	SetVolume(volume float64)

	// UnplayedBufferSize returns the byte size in the underlying buffer that is not played yet.
	UnplayedBufferSize() int

	// Err returns an error if this player has an error.
	Err() error

	io.Closer
}

type playerState int

const (
	playerPaused playerState = iota
	playerPlay
	playerClosed
)

// TODO: The term 'buffer' is confusing. Name each buffer with good terms.

// oneBufferSize returns the size of one buffer in the player implementation.
func (c *context) oneBufferSize() int {
	bytesPerSample := c.channelNum * c.bitDepthInBytes
	s := c.sampleRate * bytesPerSample / 4

	// Align s in multiples of bytes per sample, or a buffer could have extra bytes.
	return s / bytesPerSample * bytesPerSample
}

// maxBufferSize returns the maximum size of the buffer for the audio source.
// This buffer is used when unreading on pausing the player.
func (c *context) maxBufferSize() int {
	// The number of underlying buffers should be 2.
	return c.oneBufferSize() * 2
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"time"
	"github.com/ninjasphere/go-ninja/devices"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go.wemo"
	"github.com/davecgh/go-spew/spew"
)

const (
	driverName       = "com.ninjablocks.wemo"
	switchDesignator = "controllee"
	motionDesignator = "sensor"
)

var log = logger.GetLogger(driverName)
var info = ninja.LoadModuleInfo("./package.json")
var seenDevices []string //Store serial numbers of all seen switches

type WemoDeviceContext struct {
	Info   *wemo.DeviceInfo
	Device *wemo.Device
}

type WemoDriver struct {
	config    *WemoDriverConfig
	conn      *ninja.Connection
	sendEvent func(event string, payload interface{}) error
	devices   *[]WemoDeviceContext
}

type WemoDriverConfig struct {
	NumberOfDevices int
}

func defaultConfig() *WemoDriverConfig {
	return &WemoDriverConfig{
		NumberOfDevices: 0,
	}
}

func NewWemoDriver() (*WemoDriver, error) {
	conn, err := ninja.Connect(driverName)
	if err != nil {
		log.HandleError(err, "Could not connect to MQTT")
		return nil,err
	}

	driver := &WemoDriver{
		conn:      conn,
		config:    defaultConfig(),
		sendEvent: nil,
		devices:   nil,
	}

	log.Infof("1");
	err = conn.ExportDriver(driver)
	log.Infof("2");
	if err != nil {
		log.Fatalf("Failed to export Wemo driver: %s", err)
	}

	return driver, nil
}

func (d *WemoDriver) Start(config *WemoDriverConfig) error {
	log.Infof("Start method on Wemo driver called")
	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.HandleError(err, "Could not get net address")
		return err
	}

	log.Infof("Discovering new Wemos with ip interface %s", ipAddr)
	api := wemo.NewByIp(ipAddr)

	devices, _ := api.DiscoverAll(3 * time.Second) //TODO: this needs to be evented
	for _, device := range devices {
		deviceInfo, err := device.FetchDeviceInfo()
		if err != nil {
			log.HandleError(err, "Unable to fetch device info")
			return err
		}
		deviceStr := deviceInfo.DeviceType

		if isUnique(deviceInfo) {
			detectedSwitch, _ := regexp.MatchString(switchDesignator, deviceStr)
			detectedMotion, _ := regexp.MatchString(motionDesignator, deviceStr)

			if detectedSwitch {
				log.Infof("Creating new switch")
				_, err = d.NewSwitch(device, deviceInfo)
			} else if detectedMotion {
				log.Infof("Creating new motion detector")
				//TODO
				// _, err = d.NewMotion(device, deviceInfo)
			} else {
				log.Errorf("Unknown device type: %s", deviceStr)
				spew.Dump(deviceInfo)
			}

		}
	}
	return nil
}

func (d *WemoDriver) NewSwitch(device *wemo.Device, info *wemo.DeviceInfo) (*WemoDeviceContext, error) {
	deviceInfo := &model.Device{
			NaturalID: info.MacAddress,
			Name: &info.FriendlyName,
			NaturalIDType: info.DeviceType,
	}

	wemoSwitch, err := devices.CreateSwitchDevice(d, deviceInfo, d.conn)
	if err != nil {
		log.FatalError(err, "Failed to create switch device")
	}

	wemoSwitch.ApplyOnOff = func(state bool) error {
		var err error
		if state {
			device.On()
		} else {
			device.Off()
		}
		if err != nil {
			return fmt.Errorf("Failed to set on-off state: %s", err)
		}
		return nil
	}

	ticker := time.NewTicker(time.Second * 5)
	go func() {
		for _ = range ticker.C {
			curState := device.GetBinaryState()
			wemoSwitch.UpdateSwitchState(curState != 0) //curstate needs bool, but get state returns int
		}
	}()

	ws := &WemoDeviceContext{
		Info:   info,
		Device: device,
	}

	return ws, err
}

//TODO : make motion with new APi
// func (d *WemoDriver) NewMotion(device *wemo.Device, info *wemo.DeviceInfo) (*WemoDeviceContext, error) {
//
// }

func isUnique(newDevice *wemo.DeviceInfo) bool {
	ret := true
	for _, s := range seenDevices {
		if newDevice.SerialNumber == s {
			ret = false
		}
	}
	return ret
}

func (d *WemoDriver) GetModuleInfo() *model.Module {
	return info
}

func (d *WemoDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<commit_msg>Add thing type "socket" to sigs<commit_after>package main

import (
	"fmt"
	"regexp"
	"time"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/devices"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go.wemo"
)

const (
	driverName       = "com.ninjablocks.wemo"
	switchDesignator = "controllee"
	motionDesignator = "sensor"
)

var log = logger.GetLogger(driverName)
var info = ninja.LoadModuleInfo("./package.json")
var seenDevices []string //Store serial numbers of all seen switches

type WemoDeviceContext struct {
	Info   *wemo.DeviceInfo
	Device *wemo.Device
}

type WemoDriver struct {
	config    *WemoDriverConfig
	conn      *ninja.Connection
	sendEvent func(event string, payload interface{}) error
	devices   *[]WemoDeviceContext
}

type WemoDriverConfig struct {
	NumberOfDevices int
}

func defaultConfig() *WemoDriverConfig {
	return &WemoDriverConfig{
		NumberOfDevices: 0,
	}
}

func NewWemoDriver() (*WemoDriver, error) {
	conn, err := ninja.Connect(driverName)
	if err != nil {
		log.HandleError(err, "Could not connect to MQTT")
		return nil, err
	}

	driver := &WemoDriver{
		conn:      conn,
		config:    defaultConfig(),
		sendEvent: nil,
		devices:   nil,
	}

	log.Infof("1")
	err = conn.ExportDriver(driver)
	log.Infof("2")
	if err != nil {
		log.Fatalf("Failed to export Wemo driver: %s", err)
	}

	return driver, nil
}

func (d *WemoDriver) Start(config *WemoDriverConfig) error {
	log.Infof("Start method on Wemo driver called")
	ipAddr, err := ninja.GetNetAddress()
	if err != nil {
		log.HandleError(err, "Could not get net address")
		return err
	}

	log.Infof("Discovering new Wemos with ip interface %s", ipAddr)
	api := wemo.NewByIp(ipAddr)

	devices, _ := api.DiscoverAll(3 * time.Second) //TODO: this needs to be evented
	for _, device := range devices {
		deviceInfo, err := device.FetchDeviceInfo()
		if err != nil {
			log.HandleError(err, "Unable to fetch device info")
			return err
		}
		deviceStr := deviceInfo.DeviceType

		if isUnique(deviceInfo) {
			detectedSwitch, _ := regexp.MatchString(switchDesignator, deviceStr)
			detectedMotion, _ := regexp.MatchString(motionDesignator, deviceStr)

			if detectedSwitch {
				log.Infof("Creating new switch")
				_, err = d.NewSwitch(device, deviceInfo)
			} else if detectedMotion {
				log.Infof("Creating new motion detector")
				//TODO
				// _, err = d.NewMotion(device, deviceInfo)
			} else {
				log.Errorf("Unknown device type: %s", deviceStr)
				spew.Dump(deviceInfo)
			}

		}
	}
	return nil
}

func (d *WemoDriver) NewSwitch(device *wemo.Device, info *wemo.DeviceInfo) (*WemoDeviceContext, error) {
	sigs := map[string]string{
		"ninja:thingType": "socket",
	}

	deviceInfo := &model.Device{
		NaturalID:     info.MacAddress,
		Name:          &info.FriendlyName,
		NaturalIDType: info.DeviceType,
		Signatures:    &sigs,
	}

	wemoSwitch, err := devices.CreateSwitchDevice(d, deviceInfo, d.conn)
	if err != nil {
		log.FatalError(err, "Failed to create switch device")
	}

	wemoSwitch.ApplyOnOff = func(state bool) error {
		var err error
		if state {
			device.On()
		} else {
			device.Off()
		}
		if err != nil {
			return fmt.Errorf("Failed to set on-off state: %s", err)
		}
		return nil
	}

	ticker := time.NewTicker(time.Second * 5)
	go func() {
		for _ = range ticker.C {
			curState := device.GetBinaryState()
			wemoSwitch.UpdateSwitchState(curState != 0) //curstate needs bool, but get state returns int
		}
	}()

	ws := &WemoDeviceContext{
		Info:   info,
		Device: device,
	}

	return ws, err
}

//TODO : make motion with new APi
// func (d *WemoDriver) NewMotion(device *wemo.Device, info *wemo.DeviceInfo) (*WemoDeviceContext, error) {
//
// }

func isUnique(newDevice *wemo.DeviceInfo) bool {
	ret := true
	for _, s := range seenDevices {
		if newDevice.SerialNumber == s {
			ret = false
		}
	}
	return ret
}

func (d *WemoDriver) GetModuleInfo() *model.Module {
	return info
}

func (d *WemoDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<|endoftext|>


<commit_before>// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// 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/.

// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// The driver should be used via the database/sql package:
//
//  import "database/sql"
//  import _ "github.com/go-sql-driver/mysql"
//
//  db, err := sql.Open("mysql", "user:password@/dbname")
//
// See https://github.com/go-sql-driver/mysql#usage for details
package mysql

import (
	"database/sql"
	"database/sql/driver"
	"net"
	"time"
)

// This struct is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package.
type MySQLDriver struct{}

// DialFunc is a function which can be used to establish the network connection.
// Custom dial functions must be registered with RegisterDial
type DialFunc func(addr string) (net.Conn, error)

var dials map[string]DialFunc

// RegisterDial registers a custom dial function. It can then be used by the
// network address mynet(addr), where mynet is the registered new network.
// addr is passed as a parameter to the dial function.
func RegisterDial(net string, dial DialFunc) {
	if dials == nil {
		dials = make(map[string]DialFunc)
	}
	dials[net] = dial
}

// Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formated
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
	var err error

	// New mysqlConn
	mc := &mysqlConn{
		maxPacketAllowed: maxPacketSize,
		maxWriteSize:     maxPacketSize - 1,
	}
	mc.cfg, err = parseDSN(dsn)
	if err != nil {
		return nil, err
	}

	// Connect to Server
	if dial, ok := dials[mc.cfg.net]; ok {
		mc.netConn, err = dial(mc.cfg.addr)
	} else {
		nd := net.Dialer{Timeout: mc.cfg.timeout}
		mc.netConn, err = nd.Dial(mc.cfg.net, mc.cfg.addr)
	}
	if err != nil {
		return nil, err
	}

	// Enable TCP Keepalives on TCP connections
	if tc, ok := mc.netConn.(*net.TCPConn); ok {
		timeout := time.Now().Add(mc.cfg.timeout)
		tc.SetReadDeadline(timeout)
		tc.SetDeadline(timeout)
		if err := tc.SetKeepAlive(true); err != nil {
			// Don't send COM_QUIT before handshake.
			mc.netConn.Close()
			mc.netConn = nil
			return nil, err
		}
	}

	mc.buf = newBuffer(mc.netConn)

	// Reading Handshake Initialization Packet
	cipher, err := mc.readInitPacket()
	if err != nil {
		mc.Close()
		return nil, err
	}

	// Send Client Authentication Packet
	if err = mc.writeAuthPacket(cipher); err != nil {
		mc.Close()
		return nil, err
	}

	// Read Result Packet
	err = mc.readResultOK()
	if err != nil {
		// Retry with old authentication method, if allowed
		if mc.cfg != nil && mc.cfg.allowOldPasswords && err == ErrOldPassword {
			if err = mc.writeOldAuthPacket(cipher); err != nil {
				mc.Close()
				return nil, err
			}
			if err = mc.readResultOK(); err != nil {
				mc.Close()
				return nil, err
			}
		} else if mc.cfg != nil && mc.cfg.allowCleartextPasswords && err == ErrCleartextPassword {
			if err = mc.writeClearAuthPacket(); err != nil {
				mc.Close()
				return nil, err
			}
			if err = mc.readResultOK(); err != nil {
				mc.Close()
				return nil, err
			}
		} else {
			mc.Close()
			return nil, err
		}

	}

	// Get max allowed packet size
	maxap, err := mc.getSystemVar("max_allowed_packet")
	if err != nil {
		mc.Close()
		return nil, err
	}
	mc.maxPacketAllowed = stringToInt(maxap) - 1
	if mc.maxPacketAllowed < maxPacketSize {
		mc.maxWriteSize = mc.maxPacketAllowed
	}

	// Handle DSN Params
	err = mc.handleParams()
	if err != nil {
		mc.Close()
		return nil, err
	}

	return mc, nil
}

func init() {
	sql.Register("mysql", &MySQLDriver{})
}
<commit_msg>Add deadline for connections<commit_after>// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
//
// 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/.

// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// The driver should be used via the database/sql package:
//
//  import "database/sql"
//  import _ "github.com/go-sql-driver/mysql"
//
//  db, err := sql.Open("mysql", "user:password@/dbname")
//
// See https://github.com/go-sql-driver/mysql#usage for details
package mysql

import (
	"database/sql"
	"database/sql/driver"
	"net"
	"time"
)

// This struct is exported to make the driver directly accessible.
// In general the driver is used via the database/sql package.
type MySQLDriver struct{}

// DialFunc is a function which can be used to establish the network connection.
// Custom dial functions must be registered with RegisterDial
type DialFunc func(addr string) (net.Conn, error)

var dials map[string]DialFunc

// RegisterDial registers a custom dial function. It can then be used by the
// network address mynet(addr), where mynet is the registered new network.
// addr is passed as a parameter to the dial function.
func RegisterDial(net string, dial DialFunc) {
	if dials == nil {
		dials = make(map[string]DialFunc)
	}
	dials[net] = dial
}

// Open new Connection.
// See https://github.com/go-sql-driver/mysql#dsn-data-source-name for how
// the DSN string is formated
func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
	var err error

	// New mysqlConn
	mc := &mysqlConn{
		maxPacketAllowed: maxPacketSize,
		maxWriteSize:     maxPacketSize - 1,
	}
	mc.cfg, err = parseDSN(dsn)
	if err != nil {
		return nil, err
	}
	if mc.cfg.timeout.Seconds() <= 0 {
		mc.cfg.timeout, err = time.ParseDuration("30s")
		if err != nil {
			return nil, err
		}
	}

	// Connect to Server
	if dial, ok := dials[mc.cfg.net]; ok {
		mc.netConn, err = dial(mc.cfg.addr)
	} else {
		nd := net.Dialer{Timeout: mc.cfg.timeout}
		mc.netConn, err = nd.Dial(mc.cfg.net, mc.cfg.addr)
	}
	if err != nil {
		return nil, err
	}

	// Enable TCP Keepalives on TCP connections
	if tc, ok := mc.netConn.(*net.TCPConn); ok {
		timeout := time.Now().Add(mc.cfg.timeout)
		tc.SetDeadline(timeout)
		if err := tc.SetKeepAlive(true); err != nil {
			// Don't send COM_QUIT before handshake.
			mc.netConn.Close()
			mc.netConn = nil
			return nil, err
		}
	}

	mc.buf = newBuffer(mc.netConn)

	// Reading Handshake Initialization Packet
	cipher, err := mc.readInitPacket()
	if err != nil {
		mc.Close()
		return nil, err
	}

	// Send Client Authentication Packet
	if err = mc.writeAuthPacket(cipher); err != nil {
		mc.Close()
		return nil, err
	}

	// Read Result Packet
	err = mc.readResultOK()
	if err != nil {
		// Retry with old authentication method, if allowed
		if mc.cfg != nil && mc.cfg.allowOldPasswords && err == ErrOldPassword {
			if err = mc.writeOldAuthPacket(cipher); err != nil {
				mc.Close()
				return nil, err
			}
			if err = mc.readResultOK(); err != nil {
				mc.Close()
				return nil, err
			}
		} else if mc.cfg != nil && mc.cfg.allowCleartextPasswords && err == ErrCleartextPassword {
			if err = mc.writeClearAuthPacket(); err != nil {
				mc.Close()
				return nil, err
			}
			if err = mc.readResultOK(); err != nil {
				mc.Close()
				return nil, err
			}
		} else {
			mc.Close()
			return nil, err
		}

	}

	// Get max allowed packet size
	maxap, err := mc.getSystemVar("max_allowed_packet")
	if err != nil {
		mc.Close()
		return nil, err
	}
	mc.maxPacketAllowed = stringToInt(maxap) - 1
	if mc.maxPacketAllowed < maxPacketSize {
		mc.maxWriteSize = mc.maxPacketAllowed
	}

	// Handle DSN Params
	err = mc.handleParams()
	if err != nil {
		mc.Close()
		return nil, err
	}

	return mc, nil
}

func init() {
	sql.Register("mysql", &MySQLDriver{})
}
<|endoftext|>


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

package prometheus_test

import "github.com/prometheus/client_golang/prometheus"

// ClusterManager is an example for a system that might have been built without
// Prometheus in mind. It models a central manager of jobs running in a
// cluster. Thus, we implement a custom Collector called
// ClusterManagerCollector, which collects information from a ClusterManager
// using its provided methods and turns them into Prometheus Metrics for
// collection.
//
// An additional challenge is that multiple instances of the ClusterManager are
// run within the same binary, each in charge of a different zone. We need to
// make use of wrapping Registerers to be able to register each
// ClusterManagerCollector instance with Prometheus.
type ClusterManager struct {
	Zone string
	// Contains many more fields not listed in this example.
}

// ReallyExpensiveAssessmentOfTheSystemState is a mock for the data gathering a
// real cluster manager would have to do. Since it may actually be really
// expensive, it must only be called once per collection. This implementation,
// obviously, only returns some made-up data.
func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() (
	oomCountByHost map[string]int, ramUsageByHost map[string]float64,
) {
	// Just example fake data.
	oomCountByHost = map[string]int{
		"foo.example.org": 42,
		"bar.example.org": 2001,
	}
	ramUsageByHost = map[string]float64{
		"foo.example.org": 6.023e23,
		"bar.example.org": 3.14,
	}
	return
}

// ClusterManagerCollector implements the Collector interface.
type ClusterManagerCollector struct {
	ClusterManager *ClusterManager
}

// Descriptors used by the ClusterManagerCollector below.
var (
	oomCountDesc = prometheus.NewDesc(
		"clustermanager_oom_crashes_total",
		"Number of OOM crashes.",
		[]string{"host"}, nil,
	)
	ramUsageDesc = prometheus.NewDesc(
		"clustermanager_ram_usage_bytes",
		"RAM usage as reported to the cluster manager.",
		[]string{"host"}, nil,
	)
)

// Describe is implemented with DescribeByCollect. That's possible because the
// Collect method will always return the same two metrics with the same two
// descriptors.
func (cc ClusterManagerCollector) Describe(ch chan<- *prometheus.Desc) {
	prometheus.DescribeByCollect(cc, ch)
}

// Collect first triggers the ReallyExpensiveAssessmentOfTheSystemState. Then it
// creates constant metrics for each host on the fly based on the returned data.
//
// Note that Collect could be called concurrently, so we depend on
// ReallyExpensiveAssessmentOfTheSystemState to be concurrency-safe.
func (cc ClusterManagerCollector) Collect(ch chan<- prometheus.Metric) {
	oomCountByHost, ramUsageByHost := cc.ClusterManager.ReallyExpensiveAssessmentOfTheSystemState()
	for host, oomCount := range oomCountByHost {
		ch <- prometheus.MustNewConstMetric(
			oomCountDesc,
			prometheus.CounterValue,
			float64(oomCount),
			host,
		)
	}
	for host, ramUsage := range ramUsageByHost {
		ch <- prometheus.MustNewConstMetric(
			ramUsageDesc,
			prometheus.GaugeValue,
			ramUsage,
			host,
		)
	}
}

// NewClusterManager first creates a Prometheus-ignorant ClusterManager
// instance. Then, it creates a ClusterManagerCollector for the just created
// ClusterManager. Finally, it registers the ClusterManagerCollector with a
// wrapping Registerer that adds the zone as a label. In this way, the metrics
// collected by different ClusterManagerCollectors do not collide.
func NewClusterManager(zone string, reg prometheus.Registerer) *ClusterManager {
	c := &ClusterManager{
		Zone: zone,
	}
	cc := ClusterManagerCollector{ClusterManager: c}
	prometheus.WrapRegistererWith(prometheus.Labels{"zone": zone}, reg).MustRegister(cc)
	return c
}

func ExampleCollector() {
	// Since we are dealing with custom Collector implementations, it might
	// be a good idea to try it out with a pedantic registry.
	reg := prometheus.NewPedanticRegistry()

	// Construct cluster managers. In real code, we would assign them to
	// variables to then do something with them.
	NewClusterManager("db", reg)
	NewClusterManager("ca", reg)
}
<commit_msg>Add the last few lines needed to show a new user how the Collector/Gatherer fits together<commit_after>// Copyright 2014 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package prometheus_test

import (
	"log"
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// ClusterManager is an example for a system that might have been built without
// Prometheus in mind. It models a central manager of jobs running in a
// cluster. Thus, we implement a custom Collector called
// ClusterManagerCollector, which collects information from a ClusterManager
// using its provided methods and turns them into Prometheus Metrics for
// collection.
//
// An additional challenge is that multiple instances of the ClusterManager are
// run within the same binary, each in charge of a different zone. We need to
// make use of wrapping Registerers to be able to register each
// ClusterManagerCollector instance with Prometheus.
type ClusterManager struct {
	Zone string
	// Contains many more fields not listed in this example.
}

// ReallyExpensiveAssessmentOfTheSystemState is a mock for the data gathering a
// real cluster manager would have to do. Since it may actually be really
// expensive, it must only be called once per collection. This implementation,
// obviously, only returns some made-up data.
func (c *ClusterManager) ReallyExpensiveAssessmentOfTheSystemState() (
	oomCountByHost map[string]int, ramUsageByHost map[string]float64,
) {
	// Just example fake data.
	oomCountByHost = map[string]int{
		"foo.example.org": 42,
		"bar.example.org": 2001,
	}
	ramUsageByHost = map[string]float64{
		"foo.example.org": 6.023e23,
		"bar.example.org": 3.14,
	}
	return
}

// ClusterManagerCollector implements the Collector interface.
type ClusterManagerCollector struct {
	ClusterManager *ClusterManager
}

// Descriptors used by the ClusterManagerCollector below.
var (
	oomCountDesc = prometheus.NewDesc(
		"clustermanager_oom_crashes_total",
		"Number of OOM crashes.",
		[]string{"host"}, nil,
	)
	ramUsageDesc = prometheus.NewDesc(
		"clustermanager_ram_usage_bytes",
		"RAM usage as reported to the cluster manager.",
		[]string{"host"}, nil,
	)
)

// Describe is implemented with DescribeByCollect. That's possible because the
// Collect method will always return the same two metrics with the same two
// descriptors.
func (cc ClusterManagerCollector) Describe(ch chan<- *prometheus.Desc) {
	prometheus.DescribeByCollect(cc, ch)
}

// Collect first triggers the ReallyExpensiveAssessmentOfTheSystemState. Then it
// creates constant metrics for each host on the fly based on the returned data.
//
// Note that Collect could be called concurrently, so we depend on
// ReallyExpensiveAssessmentOfTheSystemState to be concurrency-safe.
func (cc ClusterManagerCollector) Collect(ch chan<- prometheus.Metric) {
	oomCountByHost, ramUsageByHost := cc.ClusterManager.ReallyExpensiveAssessmentOfTheSystemState()
	for host, oomCount := range oomCountByHost {
		ch <- prometheus.MustNewConstMetric(
			oomCountDesc,
			prometheus.CounterValue,
			float64(oomCount),
			host,
		)
	}
	for host, ramUsage := range ramUsageByHost {
		ch <- prometheus.MustNewConstMetric(
			ramUsageDesc,
			prometheus.GaugeValue,
			ramUsage,
			host,
		)
	}
}

// NewClusterManager first creates a Prometheus-ignorant ClusterManager
// instance. Then, it creates a ClusterManagerCollector for the just created
// ClusterManager. Finally, it registers the ClusterManagerCollector with a
// wrapping Registerer that adds the zone as a label. In this way, the metrics
// collected by different ClusterManagerCollectors do not collide.
func NewClusterManager(zone string, reg prometheus.Registerer) *ClusterManager {
	c := &ClusterManager{
		Zone: zone,
	}
	cc := ClusterManagerCollector{ClusterManager: c}
	prometheus.WrapRegistererWith(prometheus.Labels{"zone": zone}, reg).MustRegister(cc)
	return c
}

func ExampleCollector() {
	// Since we are dealing with custom Collector implementations, it might
	// be a good idea to try it out with a pedantic registry.
	reg := prometheus.NewPedanticRegistry()

	// Construct cluster managers. In real code, we would assign them to
	// variables to then do something with them.
	NewClusterManager("db", reg)
	NewClusterManager("ca", reg)

	// Add the built in process and golang metrics to this registry
	reg.MustRegister(
		prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}),
		prometheus.NewGoCollector(),
	)

	http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>package accessctl

import (
	"fmt"
	neturl "net/url"
	"regexp"
	"strings"
	"time"

	"github.com/astaxie/beego"
	ctl "github.com/ikeikeikeike/gopkg/accessctl"
)

/*
	以下のいずれかを満たす場合はAccessLogとして集計しない

		- 正しいUserAgentか
		- Refererが存在するか
		- 自サイトのRefererではないか(conf.httphostを使用)
		- 自サイトのRefererではないか(RefererとrequestURLのドメインが同一)
*/
func IsInAccessLog(in *InLog) bool {

	if !ctl.IsUA(in.UserAgent) {
		beego.Debug("Valid UserAgent")
		return false
	} else if in.Referer == "" {
		beego.Debug("blank referer")
		return false
	} else if in.Referer == "www.google.co" {
		beego.Debug("ignore google referer")
		return false
	} else if in.Referer == "search.yahoo.co" {
		beego.Debug("ignore yahoo referer")
		return false
	} else if strings.Contains(in.Referer, beego.AppConfig.String("domain")) {
		beego.Debug("domain in referer", in.Referer, beego.AppConfig.String("domain"))
		return false
	}

	ru, err := neturl.Parse(in.Referer)
	if err != nil {
		return true
	}
	uu, err := neturl.Parse(in.Url)
	if err != nil {
		return true
	}

	if ru.Host == uu.Host {
		beego.Debug("same domain")
		return false
	}

	return true
}

type ScoringInLog struct {
	InLogs  []*InLog
	Cleaned bool
}

func NewScoringInLog() *ScoringInLog {
	return &ScoringInLog{Cleaned: true}
}

func (sin *ScoringInLog) Bootstrap() (err error) {

	config := fmt.Sprintf(`{"conn": "%s"}`, beego.AppConfig.String("RedisConn"))
	counter, err := ctl.NewCounter(config)
	if err != nil {
		return
	}

	logs := counter.Listall()

	if sin.Cleaned {
		counter.Clean()
	}

	for _, l := range logs {
		sin.InLogs = append(sin.InLogs, BytesToInLog([]uint8(l)))
	}

	return
}

func (sin *ScoringInLog) Find(key string) (inlogs []*InLog, err error) {
	re := regexp.MustCompile(key)

	for _, inlog := range sin.InLogs {
		if !IsInAccessLog(inlog) {
			continue
		} else if len(re.FindAllString(inlog.Referer, -1)) < 1 {
			continue
		}

		inlogs = append(inlogs, inlog)
	}

	return
}

/*
	- IsInAccessLogで非カウント対象を弾いている
	- UserAgent, RemoteAddr, 1時間で UU(1セッション)とする
*/
func (sin *ScoringInLog) Scoring(url string) (score int, err error) {
	var key string = url

	u, err := neturl.Parse(url)
	if err == nil {
		domain := strings.Split(u.Host, ":")[0]
		if strings.Contains(domain, "livedoor.jp") {
			key = strings.Split(u.Path, "/")[1]
		} else {
			key = domain
		}
	}

	inlogs, err := sin.Find(key)
	if err != nil {
		return
	}

	scores := make(map[string]int)

	for _, il := range inlogs {
		t, _ := time.Parse(time.RFC1123, il.Time)

		scores[fmt.Sprintf("%s||%s||%s",
			il.RemoteHost, il.UserAgent, t.Format("2006-01-02T15"))]++
	}

	return len(scores), err
}
<commit_msg>fixed ignores yahoo and google in accesslog<commit_after>package accessctl

import (
	"fmt"
	neturl "net/url"
	"regexp"
	"strings"
	"time"

	"github.com/astaxie/beego"
	ctl "github.com/ikeikeikeike/gopkg/accessctl"
)

/*
	以下のいずれかを満たす場合はAccessLogとして集計しない

		- 正しいUserAgentか
		- Refererが存在するか
		- 自サイトのRefererではないか(conf.httphostを使用)
		- 自サイトのRefererではないか(RefererとrequestURLのドメインが同一)
*/
func IsInAccessLog(in *InLog) bool {

	if !ctl.IsUA(in.UserAgent) {
		beego.Debug("Valid UserAgent")
		return false
	} else if in.Referer == "" {
		beego.Debug("blank referer")
		return false
	} else if strings.Contains(in.Referer, "www.google.co") {
		beego.Debug("ignore google referer")
		return false
	} else if strings.Contains(in.Referer, "search.yahoo.co") {
		beego.Debug("ignore yahoo referer")
		return false
	} else if strings.Contains(in.Referer, beego.AppConfig.String("domain")) {
		beego.Debug("domain in referer", in.Referer, beego.AppConfig.String("domain"))
		return false
	}

	ru, err := neturl.Parse(in.Referer)
	if err != nil {
		return true
	}
	uu, err := neturl.Parse(in.Url)
	if err != nil {
		return true
	}

	if ru.Host == uu.Host {
		beego.Debug("same domain")
		return false
	}

	return true
}

type ScoringInLog struct {
	InLogs  []*InLog
	Cleaned bool
}

func NewScoringInLog() *ScoringInLog {
	return &ScoringInLog{Cleaned: true}
}

func (sin *ScoringInLog) Bootstrap() (err error) {

	config := fmt.Sprintf(`{"conn": "%s"}`, beego.AppConfig.String("RedisConn"))
	counter, err := ctl.NewCounter(config)
	if err != nil {
		return
	}

	logs := counter.Listall()

	if sin.Cleaned {
		counter.Clean()
	}

	for _, l := range logs {
		sin.InLogs = append(sin.InLogs, BytesToInLog([]uint8(l)))
	}

	return
}

func (sin *ScoringInLog) Find(key string) (inlogs []*InLog, err error) {
	re := regexp.MustCompile(key)

	for _, inlog := range sin.InLogs {
		if !IsInAccessLog(inlog) {
			continue
		} else if len(re.FindAllString(inlog.Referer, -1)) < 1 {
			continue
		}

		inlogs = append(inlogs, inlog)
	}

	return
}

/*
	- IsInAccessLogで非カウント対象を弾いている
	- UserAgent, RemoteAddr, 1時間で UU(1セッション)とする
*/
func (sin *ScoringInLog) Scoring(url string) (score int, err error) {
	var key string = url

	u, err := neturl.Parse(url)
	if err == nil {
		domain := strings.Split(u.Host, ":")[0]
		if strings.Contains(domain, "livedoor.jp") {
			key = strings.Split(u.Path, "/")[1]
		} else {
			key = domain
		}
	}

	inlogs, err := sin.Find(key)
	if err != nil {
		return
	}

	scores := make(map[string]int)

	for _, il := range inlogs {
		t, _ := time.Parse(time.RFC1123, il.Time)

		scores[fmt.Sprintf("%s||%s||%s",
			il.RemoteHost, il.UserAgent, t.Format("2006-01-02T15"))]++
	}

	return len(scores), err
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"

	"github.com/nesurion/go-limitless"
	"github.com/nesurion/milight-daemon/milight"

	"github.com/gin-gonic/gin"
)

func main() {
	ginMode := flag.String("mode", gin.ReleaseMode, "Gin Mode (debug, release, test)")
	flag.Parse()
	SetMode(*ginMode)
	router := gin.Default()

	c, err := milight.ParseConfig("milight-daemon.conf")
	if err != nil {
		panic("failed to parse config file")
	}
	host := fmt.Sprintf("0.0.0.0:%d", c.Port)
	fmt.Println("=== Milight Daemon ===")

	// create limitless controller
	controller := limitless.LimitlessController{
		Host: c.Bridge,
	}
	groups := milight.Groups(&controller)
	controller.Groups = groups

	router.POST("/on", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "on",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.On()
				if err != nil {
					err = errors.New("failed to send on")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].On()
			if err != nil {
				err = errors.New("failed to send on")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/off", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "off",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.Off()
				if err != nil {
					err = errors.New("failed to send off")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].Off()
			if err != nil {
				err = errors.New("failed to send off")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/rgb", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		rgb, err := milight.ParseRGB(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "rgb",
			"rgb":     rgb,
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err := g.SendColor(rgb)
				if err != nil {
					err = errors.New("failed to send color")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SendColor(rgb)
			if err != nil {
				err = errors.New("failed to send color")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/brightness", func(c *gin.Context) {
		var bl uint8
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		bl, err = milight.ParseBrightnessLevel(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "brightness",
			"level":   bl,
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.SetBri(bl)
				if err != nil {
					err = errors.New("failed to set brightness")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SetBri(bl)
			if err != nil {
				err = errors.New("failed to set brightness")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/color", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		color, err := milight.ParseColor(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "color",
			"color":   fmt.Sprintf("%x", color),
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.SetHue(color)
				if err != nil {
					err = errors.New("failed to set color")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SetHue(color)
			if err != nil {
				err = errors.New("failed to set color")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/white", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "white",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.White()
				if err != nil {
					err = errors.New("failed to set white")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].White()
			if err != nil {
				err = errors.New("failed to set white")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/night", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "night",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.Night()
				if err != nil {
					err = errors.New("failed to set night mode")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].Night()
			if err != nil {
				err = errors.New("failed to set night mode")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/disco", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		speed := c.Query("speed")
		msg := gin.H{
			"command": "disco",
			"group":   0,
			"speed":   "on",
		}
		switch speed {
		case "up":
			msg["speed"] = "up"
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.DiscoFaster()
					if err != nil {
						err = errors.New("failed to speed up")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].DiscoFaster()
				if err != nil {
					err = errors.New("failed to speed up")
					c.AbortWithError(500, err)
					return
				}
			}
		case "down":
			msg["speed"] = "down"
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.DiscoSlower()
					if err != nil {
						err = errors.New("failed to speed down")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].DiscoSlower()
				if err != nil {
					err = errors.New("failed to speed down")
					c.AbortWithError(500, err)
					return
				}
			}
		case "":
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.Disco()
					if err != nil {
						err = errors.New("failed to set disco")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].Disco()
				if err != nil {
					err = errors.New("failed to set disco")
					c.AbortWithError(500, err)
					return
				}
			}
		}
		msg["group"] = controller.Groups[id].Id
		c.JSON(200, msg)
	})

	router.Run(host)
}

func SetMode(mode string) {
	switch mode {
	case "release":
		gin.SetMode(gin.ReleaseMode)
	case "debug":
		gin.SetMode(gin.DebugMode)
	case "test":
		gin.SetMode(gin.TestMode)
	default:
		panic("mode unavailable. (debug, release, test)")
	}
}
<commit_msg>print host and port we are running on<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"

	"github.com/nesurion/go-limitless"
	"github.com/nesurion/milight-daemon/milight"

	"github.com/gin-gonic/gin"
)

func main() {
	ginMode := flag.String("mode", gin.ReleaseMode, "Gin Mode (debug, release, test)")
	flag.Parse()
	SetMode(*ginMode)
	router := gin.Default()

	c, err := milight.ParseConfig("milight-daemon.conf")
	if err != nil {
		panic("failed to parse config file")
	}
	host := fmt.Sprintf("0.0.0.0:%d", c.Port)
	fmt.Println("=== Milight Daemon ===")
	fmt.Printf("Running on %s\n", host)

	// create limitless controller
	controller := limitless.LimitlessController{
		Host: c.Bridge,
	}
	groups := milight.Groups(&controller)
	controller.Groups = groups

	router.POST("/on", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "on",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.On()
				if err != nil {
					err = errors.New("failed to send on")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].On()
			if err != nil {
				err = errors.New("failed to send on")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/off", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "off",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.Off()
				if err != nil {
					err = errors.New("failed to send off")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].Off()
			if err != nil {
				err = errors.New("failed to send off")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/rgb", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		rgb, err := milight.ParseRGB(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "rgb",
			"rgb":     rgb,
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err := g.SendColor(rgb)
				if err != nil {
					err = errors.New("failed to send color")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SendColor(rgb)
			if err != nil {
				err = errors.New("failed to send color")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/brightness", func(c *gin.Context) {
		var bl uint8
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		bl, err = milight.ParseBrightnessLevel(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "brightness",
			"level":   bl,
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.SetBri(bl)
				if err != nil {
					err = errors.New("failed to set brightness")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SetBri(bl)
			if err != nil {
				err = errors.New("failed to set brightness")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/color", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		color, err := milight.ParseColor(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "color",
			"color":   fmt.Sprintf("%x", color),
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.SetHue(color)
				if err != nil {
					err = errors.New("failed to set color")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].SetHue(color)
			if err != nil {
				err = errors.New("failed to set color")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/white", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "white",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.White()
				if err != nil {
					err = errors.New("failed to set white")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].White()
			if err != nil {
				err = errors.New("failed to set white")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/night", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		msg := gin.H{
			"command": "night",
			"group":   0,
		}
		if id == -1 {
			for _, g := range controller.Groups {
				err = g.Night()
				if err != nil {
					err = errors.New("failed to set night mode")
					c.AbortWithError(500, err)
					return
				}
			}
		} else {
			err = controller.Groups[id].Night()
			if err != nil {
				err = errors.New("failed to set night mode")
				c.AbortWithError(500, err)
				return
			}
			msg["group"] = controller.Groups[id].Id
		}
		c.JSON(200, msg)
	})

	router.POST("/disco", func(c *gin.Context) {
		id, err := milight.ParseGroup(c)
		if err != nil {
			c.AbortWithError(400, err)
			return
		}
		speed := c.Query("speed")
		msg := gin.H{
			"command": "disco",
			"group":   0,
			"speed":   "on",
		}
		switch speed {
		case "up":
			msg["speed"] = "up"
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.DiscoFaster()
					if err != nil {
						err = errors.New("failed to speed up")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].DiscoFaster()
				if err != nil {
					err = errors.New("failed to speed up")
					c.AbortWithError(500, err)
					return
				}
			}
		case "down":
			msg["speed"] = "down"
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.DiscoSlower()
					if err != nil {
						err = errors.New("failed to speed down")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].DiscoSlower()
				if err != nil {
					err = errors.New("failed to speed down")
					c.AbortWithError(500, err)
					return
				}
			}
		case "":
			if id == -1 {
				for _, g := range controller.Groups {
					err = g.Disco()
					if err != nil {
						err = errors.New("failed to set disco")
						c.AbortWithError(500, err)
						return
					}
				}
			} else {
				err = controller.Groups[id].Disco()
				if err != nil {
					err = errors.New("failed to set disco")
					c.AbortWithError(500, err)
					return
				}
			}
		}
		msg["group"] = controller.Groups[id].Id
		c.JSON(200, msg)
	})

	router.Run(host)
}

func SetMode(mode string) {
	switch mode {
	case "release":
		gin.SetMode(gin.ReleaseMode)
	case "debug":
		gin.SetMode(gin.DebugMode)
	case "test":
		gin.SetMode(gin.TestMode)
	default:
		panic("mode unavailable. (debug, release, test)")
	}
}
<|endoftext|>


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

package main

import (
	"os"

	"github.com/tsuru/tsuru/cmd"
)

const (
	version = "0.6.3"
	header  = "Supported-Crane"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header, nil)
	m.Register(&ServiceCreate{})
	m.Register(&ServiceRemove{})
	m.Register(&ServiceList{})
	m.Register(&ServiceUpdate{})
	m.Register(&ServiceDocGet{})
	m.Register(&ServiceDocAdd{})
	m.Register(&ServiceTemplate{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<commit_msg>main: bump to 0.7.0<commit_after>// Copyright 2015 crane authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"os"

	"github.com/tsuru/tsuru/cmd"
)

const (
	version = "0.7.0"
	header  = "Supported-Crane"
)

func buildManager(name string) *cmd.Manager {
	m := cmd.BuildBaseManager(name, version, header, nil)
	m.Register(&ServiceCreate{})
	m.Register(&ServiceRemove{})
	m.Register(&ServiceList{})
	m.Register(&ServiceUpdate{})
	m.Register(&ServiceDocGet{})
	m.Register(&ServiceDocAdd{})
	m.Register(&ServiceTemplate{})
	return m
}

func main() {
	name := cmd.ExtractProgramName(os.Args[0])
	manager := buildManager(name)
	args := os.Args[1:]
	manager.Run(args)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/gorilla/context"
	"github.com/gorilla/sessions"
	"github.com/gorilla/securecookie"
	"komorebi"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	Version   string
	BuildTime string
)

func main() {

	port := flag.String("port", "8080", "Listening port")
	logfile := flag.String("logfile", "", "Logfile (default stdout)")
	dump := flag.Bool("dump", false, "Dump stories, make a snapshot")
	clear_board := flag.String("clear", "", "Clears dump from given board")
	flag.StringVar(&komorebi.PublicDir, "publicdir", "public/", "Public directory")
	flag.StringVar(&komorebi.HookDir, "hookdir", "hooks/", "Directory for hooks")

	flag.Parse()

	if len(*logfile) > 0 {
		f, err := os.OpenFile(*logfile, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
		if err != nil {
			log.Printf("error opening logfile: %v", err)
		}
		defer f.Close()
		komorebi.Logger = log.New(f, "komorebi:", log.Lmicroseconds)
	} else {
		komorebi.Logger = log.New(os.Stdout, "komorebi:", log.Lmicroseconds)
	}

	komorebi.Logger.Printf("starting ")

	db := komorebi.InitDb("komorebi.db")
	db.AddTable(komorebi.Board{}, "boards")
	db.AddTable(komorebi.Column{}, "columns")
	db.AddTable(komorebi.User{}, "users")
	db.AddTable(komorebi.Task{}, "tasks")
	db.AddTable(komorebi.Dump{}, "dumps")
	db.AddTable(komorebi.BoardUsers{}, "board_users")
	db.AddTable(komorebi.TaskUsers{}, "task_users")
	db.AddTable(komorebi.DodTemplate{}, "dod_templates")
	db.AddTable(komorebi.Dod{}, "dods")
	tableMap := db.AddTable(komorebi.Story{}, "stories")
	tableMap.ColMap("Desc").SetMaxSize(1024)
	tableMap.ColMap("Requirements").SetMaxSize(1024)
	db.CreateTables()

	if *dump {
		komorebi.Logger.Printf("Dump tasks")
		komorebi.DumpIt()
		os.Exit(0)
	}
	if len(*clear_board) > 0 {
		komorebi.Logger.Printf("Clear dump for board", *clear_board)
		komorebi.ClearDump(*clear_board)
		os.Exit(0)
	}
	komorebi.SessionStore = sessions.NewCookieStore(securecookie.GenerateRandomKey(64))
	komorebi.SessionStore.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   60 * 60 * 24 * 7,
		Secure:   false,
		HttpOnly: true,
	}

	ticker := time.NewTicker(time.Hour * 24)
	go func() {
		for _ = range ticker.C {
			weekday := time.Now().Weekday().String()
			if weekday == "Sunday" || weekday == "Saturday" {
				komorebi.Logger.Printf("Skip periodic task dump")
				continue
			}
			komorebi.Logger.Printf("Periodic task dump")
			komorebi.DumpIt()
		}
	}()

	router := komorebi.NewRouter()
	log.Fatal(http.ListenAndServe(":"+*port, context.ClearHandler(router)))
}
<commit_msg>add https support<commit_after>package main

import (
	"flag"
	"github.com/gorilla/context"
	"github.com/gorilla/securecookie"
	"github.com/gorilla/sessions"
	"komorebi"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	Version   string
	BuildTime string
)

func main() {

	port := flag.String("port", "", "Listening port (default 8080)")
	logfile := flag.String("logfile", "", "Logfile (default stdout)")
	dump := flag.Bool("dump", false, "Dump stories, make a snapshot")
	clear_board := flag.String("clear", "", "Clears dump from given board")
	flag.StringVar(&komorebi.PublicDir, "publicdir", "public/", "Public directory")
	flag.StringVar(&komorebi.HookDir, "hookdir", "hooks/", "Directory for hooks")

	server_crt := flag.String("crt", "", "Server cert file for https")
	server_key := flag.String("key", "", "Server key file for https")

	flag.Parse()

	if len(*logfile) > 0 {
		f, err := os.OpenFile(*logfile, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0666)
		if err != nil {
			log.Printf("error opening logfile: %v", err)
		}
		defer f.Close()
		komorebi.Logger = log.New(f, "komorebi:", log.Lmicroseconds)
	} else {
		komorebi.Logger = log.New(os.Stdout, "komorebi:", log.Lmicroseconds)
	}

	komorebi.Logger.Printf("starting ")

	db := komorebi.InitDb("komorebi.db")
	db.AddTable(komorebi.Board{}, "boards")
	db.AddTable(komorebi.Column{}, "columns")
	db.AddTable(komorebi.User{}, "users")
	db.AddTable(komorebi.Task{}, "tasks")
	db.AddTable(komorebi.Dump{}, "dumps")
	db.AddTable(komorebi.BoardUsers{}, "board_users")
	db.AddTable(komorebi.TaskUsers{}, "task_users")
	db.AddTable(komorebi.DodTemplate{}, "dod_templates")
	db.AddTable(komorebi.Dod{}, "dods")
	tableMap := db.AddTable(komorebi.Story{}, "stories")
	tableMap.ColMap("Desc").SetMaxSize(1024)
	tableMap.ColMap("Requirements").SetMaxSize(1024)
	db.CreateTables()

	if *dump {
		komorebi.Logger.Printf("Dump tasks")
		komorebi.DumpIt()
		os.Exit(0)
	}
	if len(*clear_board) > 0 {
		komorebi.Logger.Printf("Clear dump for board", *clear_board)
		komorebi.ClearDump(*clear_board)
		os.Exit(0)
	}
	komorebi.SessionStore = sessions.NewCookieStore(securecookie.GenerateRandomKey(64))
	komorebi.SessionStore.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   60 * 60 * 24 * 7,
		Secure:   false,
		HttpOnly: true,
	}

	ticker := time.NewTicker(time.Hour * 24)
	go func() {
		for _ = range ticker.C {
			weekday := time.Now().Weekday().String()
			if weekday == "Sunday" || weekday == "Saturday" {
				komorebi.Logger.Printf("Skip periodic task dump")
				continue
			}
			komorebi.Logger.Printf("Periodic task dump")
			komorebi.DumpIt()
		}
	}()

	router := komorebi.NewRouter()

	if len(*server_crt) > 0 && len(*server_key) > 0 {
		if len(*port) <= 0 {
			*port = "443"
		}
		log.Fatal(http.ListenAndServeTLS(":"+*port, *server_crt, *server_key,
			context.ClearHandler(router)))
	} else {
		if len(*port) <= 0 {
			*port = "8080"
		}
		log.Fatal(http.ListenAndServe(":"+*port, context.ClearHandler(router)))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/boltdb/bolt"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	verbose = kingpin.Flag("verbose", "Verbose mode").Short('v').Bool()

	set       = kingpin.Command("set", "initialise rest session")
	setHost   = set.Flag("host", "hostname for the service").String()
	setPort   = set.Flag("port", "port to access the service").Int()
	setScheme = set.Flag("scheme", "scheme used to access the service eg. http, https").String()

	get     = kingpin.Command("get", "Perform a GET request")
	getPath = get.Arg("url", "url to perform request on").Required().String()

	post     = kingpin.Command("post", "Perform a POST request")
	postPath = post.Arg("url", "url to perform request on").Required().String()
	postData = post.Arg("data", "data to send in the POST request").Required().String()

	put     = kingpin.Command("put", "Perform a PUT request")
	putPath = put.Arg("url", "url to perform request on").Required().String()
	putData = put.Arg("data", "data to send in the PUT request").Required().String()

	delete     = kingpin.Command("delete", "Performa DELETE request")
	deletePath = delete.Arg("url", "url to perform request on").Required().String()
)

func main() {
	command := kingpin.Parse()
	switch command {
	case "set":
		if err := setValues(); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case "get", "post", "put", "delete":
		resp, err := makeRequest(command)
		if err != nil {
			log.Println(err)
			os.Exit(1)
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		fmt.Print(string(body))
	}
}

func setValues() error {
	if *verbose {
		fmt.Println("opening database", ".rest.db")
	}

	db, err := bolt.Open(".rest.db", 0600, nil)
	if err != nil {
		return err
	}
	defer func() {
		if err := db.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	err = db.Update(func(tx *bolt.Tx) error {
		b, err := tx.CreateBucketIfNotExists([]byte("service"))
		if err != nil {
			return err
		}

		if setScheme != nil {
			if err := b.Put([]byte("scheme"), []byte(*setScheme)); err != nil {
				return err
			}
		}

		if setHost != nil {
			if err := b.Put([]byte("host"), []byte(*setHost)); err != nil {
				return err
			}
		}

		if setPort != nil {
			buf := make([]byte, 4)
			binary.PutVarint(buf, int64(*setPort))
			if err := b.Put([]byte("port"), buf); err != nil {
				return err
			}
		}

		return nil
	})

	return err
}

func getValues() (*url.URL, error) {
	db, err := bolt.Open(".rest.db", 0600, nil)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	u := &url.URL{}
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("service"))
		if b == nil {
			return errors.New("no service bucket")
		}

		u.Scheme = string(b.Get([]byte("scheme")))
		hostname := string(b.Get([]byte("host")))
		port, err := binary.ReadVarint(bytes.NewReader(b.Get([]byte("port"))))
		if err != nil {
			return err
		}
		u.Host = fmt.Sprintf("%s:%d", hostname, port)

		return nil
	})

	return u, err
}

func makeRequest(reqType string) (*http.Response, error) {
	u, err := getValues()
	if err != nil {
		return nil, err
	}

	u.Path = path()
	if *verbose {
		fmt.Println(u)
	}

	client := &http.Client{}

	req, err := http.NewRequest(strings.ToUpper(reqType), u.String(), data())
	if err != nil {
		return nil, err
	}

	return client.Do(req)
}

func path() string {
	for _, p := range []*string{getPath, postPath, putPath, deletePath} {
		if *p != "" {
			return *p
		}
	}

	return ""
}

func data() io.Reader {
	for _, d := range []*string{postData, putData} {
		if d != nil {
			return strings.NewReader(*d)
		}
	}

	return nil
}
<commit_msg>Store info for multiple services<commit_after>package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"strings"

	"github.com/boltdb/bolt"
	homedir "github.com/mitchellh/go-homedir"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	verbose = kingpin.Flag("verbose", "Verbose mode").Short('v').Bool()

	set        = kingpin.Command("set", "initialise rest session")
	setService = set.Arg("service", "the service to set values for").Required().String()
	setHost    = set.Flag("host", "hostname for the servicpe").String()
	setPort    = set.Flag("port", "port to access the service").Int()
	setScheme  = set.Flag("scheme", "scheme used to access the service eg. http, https").String()

	use          = kingpin.Command("use", "switch service")
	serviceToUse = use.Arg("service", "the service to use").Required().String()

	get     = kingpin.Command("get", "Perform a GET request")
	getPath = get.Arg("url", "url to perform request on").Required().String()

	post     = kingpin.Command("post", "Perform a POST request")
	postPath = post.Arg("url", "url to perform request on").Required().String()
	postData = post.Arg("data", "data to send in the POST request").Required().String()

	put     = kingpin.Command("put", "Perform a PUT request")
	putPath = put.Arg("url", "url to perform request on").Required().String()
	putData = put.Arg("data", "data to send in the PUT request").Required().String()

	delete     = kingpin.Command("delete", "Performa DELETE request")
	deletePath = delete.Arg("url", "url to perform request on").Required().String()

	dbFile string
)

func init() {
	dir, err := homedir.Dir()
	if err != nil {
		panic(err)
	}
	dbFile = fmt.Sprintf("%s/%s", dir, ".rest.db")
}

func main() {
	command := kingpin.Parse()
	switch command {
	case "set":
		if err := setValues(); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case "use":
		if err := useService(); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
	case "get", "post", "put", "delete":
		resp, err := makeRequest(command)
		if err != nil {
			log.Println(err)
			os.Exit(1)
		}
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		fmt.Print(string(body))
	}
}

func useService() error {
	db, err := bolt.Open(dbFile, 0600, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		serviceBucket := tx.Bucket([]byte("services"))
		if serviceBucket == nil {
			return errors.New("database malformed, no services bucket")
		}

		if b := serviceBucket.Bucket([]byte(*serviceToUse)); b == nil {
			return fmt.Errorf("no service: %s", *serviceToUse)
		}

		info, err := tx.CreateBucketIfNotExists([]byte("info"))
		if err != nil {
			return err
		}

		err = info.Put([]byte("current"), []byte(*serviceToUse))
		if err != nil {
			return err
		}

		return nil
	})

	return err
}

func setValues() error {
	if *verbose {
		fmt.Println("opening database", ".rest.db")
	}

	db, err := bolt.Open(dbFile, 0600, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		serviceBucket, err := tx.CreateBucketIfNotExists([]byte("services"))
		if err != nil {
			return err
		}

		b, err := serviceBucket.CreateBucketIfNotExists([]byte(*setService))
		if err != nil {
			return err
		}

		if setScheme != nil {
			if err := b.Put([]byte("scheme"), []byte(*setScheme)); err != nil {
				return err
			}
		}

		if setHost != nil {
			if err := b.Put([]byte("host"), []byte(*setHost)); err != nil {
				return err
			}
		}

		if setPort != nil {
			buf := make([]byte, 4)
			binary.PutVarint(buf, int64(*setPort))
			if err := b.Put([]byte("port"), buf); err != nil {
				return err
			}
		}

		// if this is the first service to be set then set then also make it current service
		if info := tx.Bucket([]byte("info")); info == nil {
			ib, err := tx.CreateBucket([]byte("info"))
			if err != nil {
				return err
			}

			if err := ib.Put([]byte("current"), []byte(*setService)); err != nil {
				return err
			}
		}

		return nil
	})

	return err
}

func getValues() (*url.URL, error) {
	db, err := bolt.Open(dbFile, 0600, nil)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	u := &url.URL{}
	err = db.View(func(tx *bolt.Tx) error {
		info := tx.Bucket([]byte("info"))
		if info == nil {
			return errors.New("malformed database, no info bucket")
		}

		current := info.Get([]byte("current"))
		if current == nil {
			return errors.New("no current database set")
		}

		serviceBucket := tx.Bucket([]byte("services"))
		if serviceBucket == nil {
			return errors.New("malformed database, no services bucket")
		}

		b := serviceBucket.Bucket(current)
		if b == nil {
			return errors.New("no service bucket")
		}

		u.Scheme = string(b.Get([]byte("scheme")))
		hostname := string(b.Get([]byte("host")))
		port, err := binary.ReadVarint(bytes.NewReader(b.Get([]byte("port"))))
		if err != nil {
			return err
		}
		u.Host = fmt.Sprintf("%s:%d", hostname, port)

		return nil
	})

	return u, err
}

func makeRequest(reqType string) (*http.Response, error) {
	u, err := getValues()
	if err != nil {
		return nil, err
	}

	u.Path = path()
	if *verbose {
		fmt.Println(u)
	}

	client := &http.Client{}

	req, err := http.NewRequest(strings.ToUpper(reqType), u.String(), data())

	if err != nil {
		return nil, err
	}

	return client.Do(req)
}

func path() string {
	for _, p := range []*string{getPath, postPath, putPath, deletePath} {
		if *p != "" {
			return *p
		}
	}

	return ""
}

func data() io.Reader {
	for _, d := range []*string{postData, putData} {
		if d != nil {
			return strings.NewReader(*d)
		}
	}

	return nil
}
<|endoftext|>