<commit_before>// Go binding for libGammu (library to work with different cell phones)
package gammu

/*
#include <gammu.h>

void sendCallback(GSM_StateMachine *sm, int status, int msgRef, void *data) {
	if (status==0) {
		*((GSM_Error *) data) = ERR_NONE;
	} else {
		*((GSM_Error *) data) = ERR_UNKNOWN;
	}
}
void setStatusCallback(GSM_StateMachine *sm, GSM_Error *status) {
	GSM_SetSendSMSStatusCallback(sm, sendCallback, status);
}
GSM_Debug_Info *debug_info;
void setDebug() {
	debug_info = GSM_GetGlobalDebug();
	GSM_SetDebugFileDescriptor(stderr, TRUE, debug_info);
	GSM_SetDebugLevel("textall", debug_info);
}

#cgo pkg-config: gammu
*/
import "C"
import (
	"io"
	"runtime"
	"time"
	"unsafe"
)

// Error
type Error C.GSM_Error

func (e Error) Error() string {
	return C.GoString(C.GSM_ErrorString(C.GSM_Error(e)))
}

// StateMachine
type StateMachine struct {
	g         *C.GSM_StateMachine
	smsc      C.GSM_SMSC
	status    C.GSM_Error
	connected bool

	Timeout time.Duration // Default 15s
}

// Creates new state maschine using cf configuration file or default
// configuration file if cf == "".
func NewStateMachine(cf string) (*StateMachine, error) {
	//C.setDebug()
	var config *C.INI_Section
	if cf != "" {
		cs := C.CString(cf)
		defer C.free(unsafe.Pointer(cs))
		if e := C.GSM_FindGammuRC(&config, cs); e != C.ERR_NONE {
			return nil, Error(e)
		}
	} else {
		if e := C.GSM_FindGammuRC(&config, nil); e != C.ERR_NONE {
			return nil, Error(e)
		}
	}
	defer C.INI_Free(config)

	sm := new(StateMachine)
	sm.g = C.GSM_AllocStateMachine()
	if sm.g == nil {
		panic("out of memory")
	}

	if e := C.GSM_ReadConfig(config, C.GSM_GetConfig(sm.g, 0), 0); e != C.ERR_NONE {
		sm.free()
		return nil, Error(e)
	}
	C.GSM_SetConfigNum(sm.g, 1)
	sm.Timeout = 15 * time.Second

	runtime.SetFinalizer(sm, (*StateMachine).free)
	return sm, nil
}

func (sm *StateMachine) free() {
	if sm.connected {
		sm.Disconnect()
	}
	C.GSM_FreeStateMachine(sm.g)
	sm.g = nil
}

func (sm *StateMachine) Connect() error {
	if e := C.GSM_InitConnection(sm.g, 1); e != C.ERR_NONE {
		return Error(e)
	}
	sm.connected = true
	C.setStatusCallback(sm.g, &sm.status)
	sm.smsc.Location = 1
	if e := C.GSM_GetSMSC(sm.g, &sm.smsc); e != C.ERR_NONE {
		return Error(e)
	}
	return nil
}

func (sm *StateMachine) Disconnect() error {
	if e := C.GSM_TerminateConnection(sm.g); e != C.ERR_NONE {
		return Error(e)
	}
	sm.connected = false
	return nil
}

func decodeUTF8(out *C.uchar, in string) {
	cn := C.CString(in)
	C.DecodeUTF8(out, cn, C.int(len(in)))
	C.free(unsafe.Pointer(cn))
}

func (sm *StateMachine) sendSMS(sms *C.GSM_SMSMessage, number string, report bool) error {
	C.CopyUnicodeString(&sms.SMSC.Number[0], &sm.smsc.Number[0])
	decodeUTF8(&sms.Number[0], number)
	if report {
		sms.PDU = C.SMS_Status_Report
	} else {
		sms.PDU = C.SMS_Submit
	}
	// Send mepssage
	sm.status = C.ERR_TIMEOUT
	if e := C.GSM_SendSMS(sm.g, sms); e != C.ERR_NONE {
		return Error(e)
	}
	// Wait for reply
	t := time.Now()
	for time.Now().Sub(t) < sm.Timeout {
		C.GSM_ReadDevice(sm.g, C.TRUE)
		if sm.status == C.ERR_NONE {
			// Message sent OK
			break
		} else if sm.status != C.ERR_TIMEOUT {
			// Error
			break
		}
	}
	if sm.status != C.ERR_NONE {
		return Error(sm.status)
	}
	return nil
}

func (sm *StateMachine) SendSMS(number, text string, report bool) error {
	var sms C.GSM_SMSMessage
	decodeUTF8(&sms.Text[0], text)
	sms.UDH.Type = C.UDH_NoUDH
	sms.Coding = C.SMS_Coding_Default_No_Compression
	sms.Class = 1
	return sm.sendSMS(&sms, number, report)
}

func (sm *StateMachine) SendLongSMS(number, text string, report bool) error {
	// Fill in SMS info
	var smsInfo C.GSM_MultiPartSMSInfo
	C.GSM_ClearMultiPartSMSInfo(&smsInfo)
	smsInfo.Class = 1
	smsInfo.EntriesNum = 1
	smsInfo.UnicodeCoding = C.FALSE
	// Check for non-ASCII rune
	for _, r := range text {
		if r > 0x7F {
			smsInfo.UnicodeCoding = C.TRUE
			break
		}
	}
	smsInfo.Entries[0].ID = C.SMS_ConcatenatedTextLong
	msgUnicode := make([]C.uchar, (len(text)+1)*2)
	decodeUTF8(&msgUnicode[0], text)
	smsInfo.Entries[0].Buffer = &msgUnicode[0]
	// Prepare multipart message
	var msms C.GSM_MultiSMSMessage
	if e := C.GSM_EncodeMultiPartSMS(nil, &smsInfo, &msms); e != C.ERR_NONE {
		return Error(e)
	}
	// Send message
	for i := 0; i < int(msms.Number); i++ {
		if e := sm.sendSMS(&msms.SMS[i], number, report); e != nil {
			return e
		}
	}
	return nil
}

func encodeUTF8(in *C.uchar) string {
	out := make([]C.char, C.UnicodeLength(in)*2)
	C.EncodeUTF8(&out[0], in)
	return C.GoString(&out[0])
}

func goTime(t *C.GSM_DateTime) time.Time {
	return time.Date(
		int(t.Year), time.Month(t.Month), int(t.Day),
		int(t.Hour), int(t.Minute), int(t.Second), 0,
		time.UTC,
	).Add(time.Duration(t.Timezone) * time.Second)
}

type SMS struct {
	Number, Text string
	Time         time.Time
	Report       bool // True if this message is a delivery report
}

// Read and deletes first avaliable message.
// Returns io.EOF if there is no more messages to read
func (sm *StateMachine) GetSMS() (sms SMS, err error) {
	var msms C.GSM_MultiSMSMessage
	if e := C.GSM_GetNextSMS(sm.g, &msms, C.TRUE); e != C.ERR_NONE {
		if e == C.ERR_EMPTY {
			err = io.EOF
		} else {
			err = Error(e)
		}
		return
	}
	s := msms.SMS[0]
	sms.Number = encodeUTF8(&s.Number[0])
	sms.Time = goTime(&s.DateTime)
	for i := 0; i < int(msms.Number); i++ {
		s = msms.SMS[i]
		if s.Coding == C.SMS_Coding_8bit {
			continue
		}
		sms.Text += encodeUTF8(&s.Text[0])
		if s.PDU == C.SMS_Status_Report {
			sms.Report = true
		}
		if e := C.GSM_DeleteSMS(sm.g, &s); e != C.ERR_NONE {
			err = Error(e)
			return
		}
	}
	return
}
<commit_msg>IsConnected method added<commit_after>// Go binding for libGammu (library to work with different cell phones)
package gammu

/*
#include <gammu.h>

void sendCallback(GSM_StateMachine *sm, int status, int msgRef, void *data) {
	if (status==0) {
		*((GSM_Error *) data) = ERR_NONE;
	} else {
		*((GSM_Error *) data) = ERR_UNKNOWN;
	}
}
void setStatusCallback(GSM_StateMachine *sm, GSM_Error *status) {
	GSM_SetSendSMSStatusCallback(sm, sendCallback, status);
}
GSM_Debug_Info *debug_info;
void setDebug() {
	debug_info = GSM_GetGlobalDebug();
	GSM_SetDebugFileDescriptor(stderr, TRUE, debug_info);
	GSM_SetDebugLevel("textall", debug_info);
}

#cgo pkg-config: gammu
*/
import "C"
import (
	"io"
	"runtime"
	"time"
	"unsafe"
)

// Error
type Error C.GSM_Error

func (e Error) Error() string {
	return C.GoString(C.GSM_ErrorString(C.GSM_Error(e)))
}

// StateMachine
type StateMachine struct {
	g         *C.GSM_StateMachine
	smsc      C.GSM_SMSC
	status    C.GSM_Error
	connected bool

	Timeout time.Duration // Default 15s
}

// Creates new state maschine using cf configuration file or default
// configuration file if cf == "".
func NewStateMachine(cf string) (*StateMachine, error) {
	//C.setDebug()
	var config *C.INI_Section
	if cf != "" {
		cs := C.CString(cf)
		defer C.free(unsafe.Pointer(cs))
		if e := C.GSM_FindGammuRC(&config, cs); e != C.ERR_NONE {
			return nil, Error(e)
		}
	} else {
		if e := C.GSM_FindGammuRC(&config, nil); e != C.ERR_NONE {
			return nil, Error(e)
		}
	}
	defer C.INI_Free(config)

	sm := new(StateMachine)
	sm.g = C.GSM_AllocStateMachine()
	if sm.g == nil {
		panic("out of memory")
	}

	if e := C.GSM_ReadConfig(config, C.GSM_GetConfig(sm.g, 0), 0); e != C.ERR_NONE {
		sm.free()
		return nil, Error(e)
	}
	C.GSM_SetConfigNum(sm.g, 1)
	sm.Timeout = 15 * time.Second

	runtime.SetFinalizer(sm, (*StateMachine).free)
	return sm, nil
}

func (sm *StateMachine) free() {
	if sm.connected {
		sm.Disconnect()
	}
	C.GSM_FreeStateMachine(sm.g)
	sm.g = nil
}

func (sm *StateMachine) Connect() error {
	if e := C.GSM_InitConnection(sm.g, 1); e != C.ERR_NONE {
		return Error(e)
	}
	sm.connected = true
	C.setStatusCallback(sm.g, &sm.status)
	sm.smsc.Location = 1
	if e := C.GSM_GetSMSC(sm.g, &sm.smsc); e != C.ERR_NONE {
		return Error(e)
	}
	return nil
}

func (sm *StateMachine) IsConnected() bool {
	return G.GSM_IsConnected(sm.g) != 0
}

func (sm *StateMachine) Disconnect() error {
	if e := C.GSM_TerminateConnection(sm.g); e != C.ERR_NONE {
		return Error(e)
	}
	sm.connected = false
	return nil
}

func decodeUTF8(out *C.uchar, in string) {
	cn := C.CString(in)
	C.DecodeUTF8(out, cn, C.int(len(in)))
	C.free(unsafe.Pointer(cn))
}

func (sm *StateMachine) sendSMS(sms *C.GSM_SMSMessage, number string, report bool) error {
	C.CopyUnicodeString(&sms.SMSC.Number[0], &sm.smsc.Number[0])
	decodeUTF8(&sms.Number[0], number)
	if report {
		sms.PDU = C.SMS_Status_Report
	} else {
		sms.PDU = C.SMS_Submit
	}
	// Send mepssage
	sm.status = C.ERR_TIMEOUT
	if e := C.GSM_SendSMS(sm.g, sms); e != C.ERR_NONE {
		return Error(e)
	}
	// Wait for reply
	t := time.Now()
	for time.Now().Sub(t) < sm.Timeout {
		C.GSM_ReadDevice(sm.g, C.TRUE)
		if sm.status == C.ERR_NONE {
			// Message sent OK
			break
		} else if sm.status != C.ERR_TIMEOUT {
			// Error
			break
		}
	}
	if sm.status != C.ERR_NONE {
		return Error(sm.status)
	}
	return nil
}

func (sm *StateMachine) SendSMS(number, text string, report bool) error {
	var sms C.GSM_SMSMessage
	decodeUTF8(&sms.Text[0], text)
	sms.UDH.Type = C.UDH_NoUDH
	sms.Coding = C.SMS_Coding_Default_No_Compression
	sms.Class = 1
	return sm.sendSMS(&sms, number, report)
}

func (sm *StateMachine) SendLongSMS(number, text string, report bool) error {
	// Fill in SMS info
	var smsInfo C.GSM_MultiPartSMSInfo
	C.GSM_ClearMultiPartSMSInfo(&smsInfo)
	smsInfo.Class = 1
	smsInfo.EntriesNum = 1
	smsInfo.UnicodeCoding = C.FALSE
	// Check for non-ASCII rune
	for _, r := range text {
		if r > 0x7F {
			smsInfo.UnicodeCoding = C.TRUE
			break
		}
	}
	smsInfo.Entries[0].ID = C.SMS_ConcatenatedTextLong
	msgUnicode := make([]C.uchar, (len(text)+1)*2)
	decodeUTF8(&msgUnicode[0], text)
	smsInfo.Entries[0].Buffer = &msgUnicode[0]
	// Prepare multipart message
	var msms C.GSM_MultiSMSMessage
	if e := C.GSM_EncodeMultiPartSMS(nil, &smsInfo, &msms); e != C.ERR_NONE {
		return Error(e)
	}
	// Send message
	for i := 0; i < int(msms.Number); i++ {
		if e := sm.sendSMS(&msms.SMS[i], number, report); e != nil {
			return e
		}
	}
	return nil
}

func encodeUTF8(in *C.uchar) string {
	out := make([]C.char, C.UnicodeLength(in)*2)
	C.EncodeUTF8(&out[0], in)
	return C.GoString(&out[0])
}

func goTime(t *C.GSM_DateTime) time.Time {
	return time.Date(
		int(t.Year), time.Month(t.Month), int(t.Day),
		int(t.Hour), int(t.Minute), int(t.Second), 0,
		time.UTC,
	).Add(time.Duration(t.Timezone) * time.Second)
}

type SMS struct {
	Number, Text string
	Time         time.Time
	Report       bool // True if this message is a delivery report
}

// Read and deletes first avaliable message.
// Returns io.EOF if there is no more messages to read
func (sm *StateMachine) GetSMS() (sms SMS, err error) {
	var msms C.GSM_MultiSMSMessage
	if e := C.GSM_GetNextSMS(sm.g, &msms, C.TRUE); e != C.ERR_NONE {
		if e == C.ERR_EMPTY {
			err = io.EOF
		} else {
			err = Error(e)
		}
		return
	}
	s := msms.SMS[0]
	sms.Number = encodeUTF8(&s.Number[0])
	sms.Time = goTime(&s.DateTime)
	for i := 0; i < int(msms.Number); i++ {
		s = msms.SMS[i]
		if s.Coding == C.SMS_Coding_8bit {
			continue
		}
		sms.Text += encodeUTF8(&s.Text[0])
		if s.PDU == C.SMS_Status_Report {
			sms.Report = true
		}
		if e := C.GSM_DeleteSMS(sm.g, &s); e != C.ERR_NONE {
			err = Error(e)
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>package session

import (
	"encoding/gob"
	"errors"
	"log"
	"net/url"

	"github.com/insionng/vodka"
)

var GlobalSessions *Manager

var defaultOtions = Options{"memory", `{"cookieName":"gosessionid","gclifetime":3600}`}

//var defaultOtions = Options{"file", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"./data/session"}`}

//var defaultOtions = Options{"redis", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:6379"}`}

const (
	CONTEXT_SESSION_KEY = "_SESSION_STORE"
	COOKIE_FLASH_KEY    = "_COOKIE_FLASH"
	CONTEXT_FLASH_KEY   = "_FLASH_VALUE"
	SESSION_FLASH_KEY   = "_SESSION_FLASH"
	SESSION_INPUT_KEY   = "_SESSION_INPUT"
)

type Options struct {
	Provider string
	Config   string
}

/*
type managerConfig struct {
	CookieName      string `json:"cookieName"`
	EnableSetCookie bool   `json:"enableSetCookie,omitempty"`
	Gclifetime      int64  `json:"gclifetime"`
	Maxlifetime     int64  `json:"maxLifetime"`
	Secure          bool   `json:"secure"`
	CookieLifeTime  int    `json:"cookieLifeTime"`
	ProviderConfig  string `json:"providerConfig"`
	Domain          string `json:"domain"`
	SessionIDLength int64  `json:"sessionIDLength"`
}
*/

func init() {
	gob.Register(url.Values{})
}

func Setup(op ...Options) error {
	option := defaultOtions
	if len(op) > 0 {
		option = op[0]
	}

	if len(option.Provider) == 0 {
		option.Provider = defaultOtions.Provider
		option.Config = defaultOtions.Config
	}

	// if len(option.Config) == 0 {
	// 	option.Config = defaultOtions.Config
	// }

	log.Println("session config ", option)

	var err error
	GlobalSessions, err = NewManager(option.Provider, option.Config)
	if err != nil {
		return err
	}
	go GlobalSessions.GC()

	return nil
}

func Sessioner() vodka.MiddlewareFunc {
	return func(next vodka.HandlerFunc) vodka.HandlerFunc {
		return func(c vodka.Context) error {
			if GlobalSessions == nil {

				return errors.New("session manager not found, use session middleware but not init ?")
			}

			sess, err := GlobalSessions.SessionStart(c.Response(), c.Request())
			if err != nil {
				return err
			}

			c.Set(CONTEXT_FLASH_KEY, Flash{})

			flashVals := url.Values{}

			flashIf := sess.Get(SESSION_FLASH_KEY)
			if flashIf != nil {
				vals, _ := url.QueryUnescape(flashIf.(string))
				flashVals, _ = url.ParseQuery(vals)
				if len(flashVals) > 0 {
					flash := Flash{}
					flash.ErrorMsg = flashVals.Get("error")
					flash.WarningMsg = flashVals.Get("warning")
					flash.InfoMsg = flashVals.Get("info")
					flash.SuccessMsg = flashVals.Get("success")
					// c.SetData("FLASH", flash)
					// vodka.v2没有直接分配变量到模板这个方法，flash先存到context里
					c.Set(CONTEXT_FLASH_KEY, flash)

				}
			}

			f := NewFlash()

			sess.Set(SESSION_FLASH_KEY, f)

			c.Set(CONTEXT_SESSION_KEY, sess)

			defer func() {
				log.Println("save session", sess)
				sess.Set(SESSION_FLASH_KEY, url.QueryEscape(f.Encode()))
				sess.SessionRelease(c.Response())
			}()

			return next(c)
		}
	}
}

func GetStore(c vodka.Context) Store {
	store := c.Get(CONTEXT_SESSION_KEY)
	if store != nil {
		return store.(Store)
	}

	return nil
}

func GetFlash(c vodka.Context) *Flash {
	return GetStore(c).Get(SESSION_FLASH_KEY).(*Flash)
}

func FlashValue(c vodka.Context) Flash {
	return c.Get(CONTEXT_FLASH_KEY).(Flash)
}

func SaveInput(c vodka.Context) {
	GetStore(c).Set(SESSION_INPUT_KEY, url.Values(c.FormParams()))
}

func GetInput(c vodka.Context) url.Values {
	input := GetStore(c).Get(SESSION_INPUT_KEY)
	if input != nil {
		return input.(url.Values)
	}

	return url.Values{}
}

func CleanInput(c vodka.Context) {
	GetStore(c).Set(SESSION_INPUT_KEY, url.Values{})
}

func NewFlash() *Flash {
	return &Flash{url.Values{}, "", "", "", ""}
}

type Flash struct {
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string) {
	f.Set(name, msg)
}

func (f *Flash) Error(msg string) {
	f.ErrorMsg = msg
	f.set("error", msg)
}

func (f *Flash) Warning(msg string) {
	f.WarningMsg = msg
	f.set("warning", msg)
}

func (f *Flash) Info(msg string) {
	f.InfoMsg = msg
	f.set("info", msg)
}

func (f *Flash) Success(msg string) {
	f.SuccessMsg = msg
	f.set("success", msg)
}
<commit_msg>just for vodka v2+<commit_after>package session

import (
	"encoding/gob"
	"errors"
	"log"
	"net/url"

	"github.com/insionng/vodka"
)

var GlobalSessions *Manager

var defaultOtions = Options{"memory", `{"cookieName":"gosessionid","gclifetime":3600}`}

//var defaultOtions = Options{"file", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"./data/session"}`}

//var defaultOtions = Options{"redis", `{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:6379"}`}

const (
	CONTEXT_SESSION_KEY = "_SESSION_STORE"
	COOKIE_FLASH_KEY    = "_COOKIE_FLASH"
	CONTEXT_FLASH_KEY   = "_FLASH_VALUE"
	SESSION_FLASH_KEY   = "_SESSION_FLASH"
	SESSION_INPUT_KEY   = "_SESSION_INPUT"
)

type Options struct {
	Provider string
	Config   string
}

/*
type managerConfig struct {
	CookieName      string `json:"cookieName"`
	EnableSetCookie bool   `json:"enableSetCookie,omitempty"`
	Gclifetime      int64  `json:"gclifetime"`
	Maxlifetime     int64  `json:"maxLifetime"`
	Secure          bool   `json:"secure"`
	CookieLifeTime  int    `json:"cookieLifeTime"`
	ProviderConfig  string `json:"providerConfig"`
	Domain          string `json:"domain"`
	SessionIDLength int64  `json:"sessionIDLength"`
}
*/

func init() {
	gob.Register(url.Values{})
}

// Setup 初始化并设置session配置
func Setup(op ...Options) error {
	option := defaultOtions
	if len(op) > 0 {
		option = op[0]
	}

	if len(option.Provider) == 0 {
		option.Provider = defaultOtions.Provider
		option.Config = defaultOtions.Config
	}

	log.Println("session config ", option)

	var err error
	GlobalSessions, err = NewManager(option.Provider, option.Config)
	if err != nil {
		return err
	}
	go GlobalSessions.GC()

	return nil
}

// Sessioner Vodka session 中间件
func Sessioner() vodka.MiddlewareFunc {
	return func(next vodka.HandlerFunc) vodka.HandlerFunc {
		return func(c vodka.Context) error {
			if GlobalSessions == nil {
				return errors.New("session manager not found, use session middleware but not init ?")
			}

			sess, err := GlobalSessions.SessionStart(c.Response(), c.Request())
			if err != nil {
				return err
			}

			c.Set(CONTEXT_FLASH_KEY, Flash{})

			flashVals := url.Values{}

			flashIf := sess.Get(SESSION_FLASH_KEY)
			if flashIf != nil {
				vals, _ := url.QueryUnescape(flashIf.(string))
				flashVals, _ = url.ParseQuery(vals)
				if len(flashVals) > 0 {
					flash := Flash{}
					flash.ErrorMsg = flashVals.Get("error")
					flash.WarningMsg = flashVals.Get("warning")
					flash.InfoMsg = flashVals.Get("info")
					flash.SuccessMsg = flashVals.Get("success")
					// flash先暂存到context里面
					c.Set(CONTEXT_FLASH_KEY, flash)

				}
			}

			f := NewFlash()

			sess.Set(SESSION_FLASH_KEY, f)

			c.Set(CONTEXT_SESSION_KEY, sess)

			defer func() {
				log.Println("save session", sess)
				sess.Set(SESSION_FLASH_KEY, url.QueryEscape(f.Encode()))
				sess.SessionRelease(c.Response())
			}()

			return next(c)
		}
	}
}

func GetStore(c vodka.Context) Store {
	store := c.Get(CONTEXT_SESSION_KEY)
	if store != nil {
		return store.(Store)
	}

	return nil
}

func GetFlash(c vodka.Context) *Flash {
	return GetStore(c).Get(SESSION_FLASH_KEY).(*Flash)
}

func FlashValue(c vodka.Context) Flash {
	return c.Get(CONTEXT_FLASH_KEY).(Flash)
}

func SaveInput(c vodka.Context) {
	GetStore(c).Set(SESSION_INPUT_KEY, url.Values(c.FormParams()))
}

func GetInput(c vodka.Context) url.Values {
	input := GetStore(c).Get(SESSION_INPUT_KEY)
	if input != nil {
		return input.(url.Values)
	}

	return url.Values{}
}

func CleanInput(c vodka.Context) {
	GetStore(c).Set(SESSION_INPUT_KEY, url.Values{})
}

func NewFlash() *Flash {
	return &Flash{url.Values{}, "", "", "", ""}
}

type Flash struct {
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string) {
	f.Set(name, msg)
}

func (f *Flash) Error(msg string) {
	f.ErrorMsg = msg
	f.set("error", msg)
}

func (f *Flash) Warning(msg string) {
	f.WarningMsg = msg
	f.set("warning", msg)
}

func (f *Flash) Info(msg string) {
	f.InfoMsg = msg
	f.set("info", msg)
}

func (f *Flash) Success(msg string) {
	f.SuccessMsg = msg
	f.set("success", msg)
}
<|endoftext|>


<commit_before>package redis_full

import (
	"errors"
	"github.com/garyburd/redigo/redis"
	"time"
)

// Wraps the Redis client to meet the Cache interface.
type RedisCache struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

var ErrCacheMiss = errors.New("redis_full: key not found.")

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host, password string, MaxIdle, MaxActive int, IdleTimeout, defaultExpiration time.Duration) RedisCache {
	var pool = &redis.Pool{
		MaxIdle:     MaxIdle,
		MaxActive:   MaxActive,
		IdleTimeout: IdleTimeout,
		Dial: func() (redis.Conn, error) {
			protocol := "tcp"
			c, err := redis.Dial(protocol, host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return RedisCache{pool, defaultExpiration}
}

func (c RedisCache) CheckRedis() error {
	conn := c.pool.Get()
	defer conn.Close()

	if _, err := conn.Do("PING"); err != nil {
		return err
	} else {
		return nil
	}
}

func (c RedisCache) Life(key string) (int64, error) {
	conn := c.pool.Get()
	defer conn.Close()

	ok, err := c.Exists(key)
	if err != nil {
		return -1, err
	}
	if !ok {
		return -1, ErrCacheMiss
	}

	res, err := conn.Do("TTL", key)
	if err != nil {
		return -1, err
	} else {
		return int64(res.(int64)), nil
	}
}

func (c RedisCache) Type(key string) (string, error) {
	conn := c.pool.Get()
	defer conn.Close()

	ok, err := c.Exists(key)
	if err != nil {
		return "", err
	}
	if !ok {
		return "", ErrCacheMiss
	}

	res, err := conn.Do("TYPE", key)
	if err != nil {
		return "", err
	} else {
		return string(res.(string)), nil
	}
}

func (c RedisCache) Exists(key string) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()

	res, err := conn.Do("EXISTS", key)
	if err != nil {
		return false, err
	} else {
		return int64(res.(int64)) == 1, nil
	}
}

func (c RedisCache) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

//some tools
func IsBody(s []interface{}, y interface{}) bool {
	m := make(map[interface{}]int)
	for _, v := range s {
		var x []interface{}
		for i := 0; i < len(s); i++ {
			if v == s[i] {
				x = append(x, v)
			}
		}
		m[v] = len(x)
	}
	return m[y] > 0
}
<commit_msg>new redis method<commit_after>package redis_full

import (
	"errors"
	"github.com/garyburd/redigo/redis"
	"time"
)

// Wraps the Redis client to meet the Cache interface.
type RedisCache struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

var ErrCacheMiss = errors.New("redis_full: key not found.")

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCache(host, password string, database, MaxIdle, MaxActive int, IdleTimeout, defaultExpiration time.Duration) RedisCache {
	var pool = &redis.Pool{
		MaxIdle:     MaxIdle,
		MaxActive:   MaxActive,
		IdleTimeout: IdleTimeout,
		Dial: func() (redis.Conn, error) {
			protocol := "tcp"
			c, err := redis.Dial(
				protocol,
				host,
				redis.DialDatabase(database),
				redis.DialPassword(password),
				redis.DialConnectTimeout(time.Second*5),
				redis.DialWriteTimeout(time.Second*3),
				redis.DialReadTimeout(time.Second*3),
			)
			if err != nil {
				return nil, err
			}
			return c, err
		},
	}
	return RedisCache{pool, defaultExpiration}
}

func (c RedisCache) CheckRedis() error {
	conn := c.pool.Get()
	defer conn.Close()

	if _, err := conn.Do("PING"); err != nil {
		return err
	} else {
		return nil
	}
}

func (c RedisCache) Life(key string) (int64, error) {
	conn := c.pool.Get()
	defer conn.Close()

	ok, err := c.Exists(key)
	if err != nil {
		return -1, err
	}
	if !ok {
		return -1, ErrCacheMiss
	}

	res, err := conn.Do("TTL", key)
	if err != nil {
		return -1, err
	} else {
		return int64(res.(int64)), nil
	}
}

func (c RedisCache) Type(key string) (string, error) {
	conn := c.pool.Get()
	defer conn.Close()

	ok, err := c.Exists(key)
	if err != nil {
		return "", err
	}
	if !ok {
		return "", ErrCacheMiss
	}

	res, err := conn.Do("TYPE", key)
	if err != nil {
		return "", err
	} else {
		return string(res.(string)), nil
	}
}

func (c RedisCache) Exists(key string) (bool, error) {
	conn := c.pool.Get()
	defer conn.Close()

	res, err := conn.Do("EXISTS", key)
	if err != nil {
		return false, err
	} else {
		return int64(res.(int64)) == 1, nil
	}
}

func (c RedisCache) Flush() error {
	conn := c.pool.Get()
	defer conn.Close()
	_, err := conn.Do("FLUSHALL")
	return err
}

//some tools
func IsBody(s []interface{}, y interface{}) bool {
	m := make(map[interface{}]int)
	for _, v := range s {
		var x []interface{}
		for i := 0; i < len(s); i++ {
			if v == s[i] {
				x = append(x, v)
			}
		}
		m[v] = len(x)
	}
	return m[y] > 0
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/url"
	"os"
	"time"
)

const (
	msgBuf = 10
)

var (
	redisUrl                   = flag.String("redisUrl", os.Getenv("REDIS_URL"), "URL of the redis server")
	redisServer, _             = url.Parse(*redisUrl)
	redisPool      *redis.Pool = newPool(redisServer)
	redisKeyExpire             = 60 // redis uses seconds for EXPIRE
)

func newPool(server *url.URL) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 4 * time.Minute,
		Dial: func() (c redis.Conn, err error) {
			c, err = redis.Dial("tcp", server.Host)
			if err != nil {
				return
			}

			if server.User == nil {
				return
			}

			pw, pwset := server.User.Password()
			if !pwset {
				return
			}

			if _, err = c.Do("AUTH", pw); err != nil {
				c.Close()
				return
			}
			return
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

type channel string

type RedisBroker struct {
	channelId   UUID
	subscribers map[chan []byte]bool
	psc         redis.PubSubConn
}

func NewRedisBroker(uuid UUID) *RedisBroker {
	broker := &RedisBroker{uuid, make(map[chan []byte]bool), redis.PubSubConn{}}

	return broker
}

func (b *RedisBroker) Subscribe() (ch chan []byte) {
	ch = make(chan []byte, msgBuf)
	b.subscribers[ch] = true
	go b.redisSubscribe(ch)
	return
}

func (b *RedisBroker) redisSubscribe(ch chan []byte) {
	conn := redisPool.Get()
	defer conn.Close()
	b.psc = redis.PubSubConn{conn}
	b.psc.PSubscribe(b.channelId + "*")
	b.replay(b.channelId, ch)
	for {
		switch msg := b.psc.Receive().(type) {
		case redis.PMessage:
			switch msg.Channel {
			case string(b.channelId) + "kill":
				log.Printf("RedisBroker.redisSubscribe.Channel.%s.kill=1", b.channelId)
				b.psc.PUnsubscribe(b.channelId + "*")
			case string(b.channelId):
				ch <- msg.Data
			}
		case redis.Subscription:
			log.Printf("RedisBroker.redisSubscribe.Channel.%s.%s=%d", msg.Channel, msg.Kind, msg.Count)
			if msg.Kind == "punsubscribe" || msg.Kind == "unsubscribe" {
				b.Unsubscribe(ch)
				return
			}
		case error:
			log.Printf("RedisBroker.redisSubscribe.RecieveError=1 err=%s", msg)
			return
		}
	}
}

func (b *RedisBroker) Unsubscribe(ch chan []byte) {
	delete(b.subscribers, ch)
	close(ch)
}

func (b *RedisBroker) UnsubscribeAll() {
	log.Printf("RedisBroker.UnsubscribeAll=%d", len(b.subscribers))
	b.publishOn([]byte{1}, string(b.channelId)+"kill")
}

func (b *RedisBroker) Publish(msg []byte) {
	b.publishOn(msg, string(b.channelId))
}

func (b *RedisBroker) publishOn(msg []byte, channel string) {
	conn := redisPool.Get()
	defer conn.Close()

	conn.Send("MULTI")
	conn.Send("PUBLISH", channel, msg)
	conn.Send("APPEND", channel, msg)
	conn.Send("EXPIRE", channel, redisKeyExpire)

	_, err := conn.Do("EXEC")
	if err != nil {
		log.Printf("publish: %s", err)
	}
}

func (b *RedisBroker) replay(channel UUID, ch chan []byte) {
	conn := redisPool.Get()
	defer conn.Close()

	buffer, err := conn.Do("GET", string(channel))
	if err != nil {
		log.Printf("publish: %s", err)
		return
	}

	if buffer != nil {
		ch <- buffer.([]byte)
	}
}
<commit_msg>Add a channel expiration time.<commit_after>package main

import (
	"flag"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/url"
	"os"
	"time"
)

const (
	msgBuf = 10
)

var (
	redisUrl                       = flag.String("redisUrl", os.Getenv("REDIS_URL"), "URL of the redis server")
	redisServer, _                 = url.Parse(*redisUrl)
	redisPool          *redis.Pool = newPool(redisServer)
	redisKeyExpire                 = 60 // redis uses seconds for EXPIRE
	redisChannelExpire             = redisKeyExpire * 5
)

func newPool(server *url.URL) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 4 * time.Minute,
		Dial: func() (c redis.Conn, err error) {
			c, err = redis.Dial("tcp", server.Host)
			if err != nil {
				return
			}

			if server.User == nil {
				return
			}

			pw, pwset := server.User.Password()
			if !pwset {
				return
			}

			if _, err = c.Do("AUTH", pw); err != nil {
				c.Close()
				return
			}
			return
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

type channel string

type RedisBroker struct {
	channelId   UUID
	subscribers map[chan []byte]bool
	psc         redis.PubSubConn
}

func NewRedisBroker(uuid UUID) *RedisBroker {
	broker := &RedisBroker{uuid, make(map[chan []byte]bool), redis.PubSubConn{}}

	return broker
}

func (b *RedisBroker) Subscribe() (ch chan []byte) {
	ch = make(chan []byte, msgBuf)
	b.subscribers[ch] = true
	go b.redisSubscribe(ch)
	return
}

func (b *RedisBroker) redisSubscribe(ch chan []byte) {
	conn := redisPool.Get()
	defer conn.Close()
	b.psc = redis.PubSubConn{conn}
	b.psc.PSubscribe(b.channelId + "*")
	b.replay(b.channelId, ch)
	for {
		switch msg := b.psc.Receive().(type) {
		case redis.PMessage:
			switch msg.Channel {
			case string(b.channelId) + "kill":
				log.Printf("RedisBroker.redisSubscribe.Channel.%s.kill=1", b.channelId)
				b.psc.PUnsubscribe(b.channelId + "*")
			case string(b.channelId):
				ch <- msg.Data
			}
		case redis.Subscription:
			log.Printf("RedisBroker.redisSubscribe.Channel.%s.%s=%d", msg.Channel, msg.Kind, msg.Count)
			if msg.Kind == "punsubscribe" || msg.Kind == "unsubscribe" {
				b.Unsubscribe(ch)
				return
			}
		case error:
			log.Printf("RedisBroker.redisSubscribe.RecieveError=1 err=%s", msg)
			return
		}
	}
}

func (b *RedisBroker) Unsubscribe(ch chan []byte) {
	delete(b.subscribers, ch)
	close(ch)
}

func (b *RedisBroker) UnsubscribeAll() {
	log.Printf("RedisBroker.UnsubscribeAll=%d", len(b.subscribers))
	b.publishOn([]byte{1}, string(b.channelId)+"kill")
}

func (b *RedisBroker) Publish(msg []byte) {
	b.publishOn(msg, string(b.channelId))
}

func (b *RedisBroker) publishOn(msg []byte, channel string) {
	conn := redisPool.Get()
	defer conn.Close()

	conn.Send("MULTI")
	conn.Send("PUBLISH", channel, msg)
	conn.Send("APPEND", channel, msg)
	conn.Send("EXPIRE", channel, redisKeyExpire)

	_, err := conn.Do("EXEC")
	if err != nil {
		log.Printf("publish: %s", err)
	}
}

func (b *RedisBroker) replay(channel UUID, ch chan []byte) {
	conn := redisPool.Get()
	defer conn.Close()

	buffer, err := conn.Do("GET", string(channel))
	if err != nil {
		log.Printf("publish: %s", err)
		return
	}

	if buffer != nil {
		ch <- buffer.([]byte)
	}
}
<|endoftext|>


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

/*
Package daemon 0.10.3 for use with Go (golang) services.

Package daemon provides primitives for daemonization of golang services.
This package is not provide implementation of user daemon,
accordingly must have root rights to install/remove service.
In the current implementation is only supported Linux and Mac Os X daemon.

Example:

	// Example of a daemon with echo service
	package main

	import (
		"fmt"
		"log"
		"net"
		"os"
		"os/signal"
		"syscall"

		"github.com/takama/daemon"
	)

	const (

		// name of the service
		name        = "myservice"
		description = "My Echo Service"

		// port which daemon should be listen
		port = ":9977"
	)

  // dependencies that are NOT required by the service, but might be used
  var dependencies = []string{"dummy.service"}

	var stdlog, errlog *log.Logger

	// Service has embedded daemon
	type Service struct {
		daemon.Daemon
	}

	// Manage by daemon commands or run the daemon
	func (service *Service) Manage() (string, error) {

		usage := "Usage: myservice install | remove | start | stop | status"

		// if received any kind of command, do it
		if len(os.Args) > 1 {
			command := os.Args[1]
			switch command {
			case "install":
				return service.Install()
			case "remove":
				return service.Remove()
			case "start":
				return service.Start()
			case "stop":
				return service.Stop()
			case "status":
				return service.Status()
			default:
				return usage, nil
			}
		}

		// Do something, call your goroutines, etc

		// Set up channel on which to send signal notifications.
		// We must use a buffered channel or risk missing the signal
		// if we're not ready to receive when the signal is sent.
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

		// Set up listener for defined host and port
		listener, err := net.Listen("tcp", port)
		if err != nil {
			return "Possibly was a problem with the port binding", err
		}

		// set up channel on which to send accepted connections
		listen := make(chan net.Conn, 100)
		go acceptConnection(listener, listen)

		// loop work cycle with accept connections or interrupt
		// by system signal
		for {
			select {
			case conn := <-listen:
				go handleClient(conn)
			case killSignal := <-interrupt:
				stdlog.Println("Got signal:", killSignal)
				stdlog.Println("Stoping listening on ", listener.Addr())
				listener.Close()
				if killSignal == os.Interrupt {
					return "Daemon was interrupted by system signal", nil
				}
				return "Daemon was killed", nil
			}
		}

		// never happen, but need to complete code
		return usage, nil
	}

	// Accept a client connection and collect it in a channel
	func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				continue
			}
			listen <- conn
		}
	}

	func handleClient(client net.Conn) {
		for {
			buf := make([]byte, 4096)
			numbytes, err := client.Read(buf)
			if numbytes == 0 || err != nil {
				return
			}
			client.Write(buf[:numbytes])
		}
	}

	func init() {
		stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
		errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
	}

	func main() {
		srv, err := daemon.New(name, description, dependencies...)
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		service := &Service{srv}
		status, err := service.Manage()
		if err != nil {
			errlog.Println(status, "\nError: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
	}

Go daemon
*/
package daemon

import "strings"

// Daemon interface has a standard set of methods/commands
type Daemon interface {

	// Install the service into the system
	Install(args ...string) (string, error)

	// Remove the service and all corresponding files from the system
	Remove() (string, error)

	// Start the service
	Start() (string, error)

	// Stop the service
	Stop() (string, error)

	// Status - check the service status
	Status() (string, error)
}

// New - Create a new daemon
//
// name: name of the service
//
// description: any explanation, what is the service, its purpose
func New(name, description string, dependencies ...string) (Daemon, error) {
	return newDaemon(strings.Join(strings.Fields(name), "_"), description, dependencies)
}
<commit_msg>Bumped version number to 0.10.4<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by
// license that can be found in the LICENSE file.

/*
Package daemon 0.10.4 for use with Go (golang) services.

Package daemon provides primitives for daemonization of golang services.
This package is not provide implementation of user daemon,
accordingly must have root rights to install/remove service.
In the current implementation is only supported Linux and Mac Os X daemon.

Example:

	// Example of a daemon with echo service
	package main

	import (
		"fmt"
		"log"
		"net"
		"os"
		"os/signal"
		"syscall"

		"github.com/takama/daemon"
	)

	const (

		// name of the service
		name        = "myservice"
		description = "My Echo Service"

		// port which daemon should be listen
		port = ":9977"
	)

  // dependencies that are NOT required by the service, but might be used
  var dependencies = []string{"dummy.service"}

	var stdlog, errlog *log.Logger

	// Service has embedded daemon
	type Service struct {
		daemon.Daemon
	}

	// Manage by daemon commands or run the daemon
	func (service *Service) Manage() (string, error) {

		usage := "Usage: myservice install | remove | start | stop | status"

		// if received any kind of command, do it
		if len(os.Args) > 1 {
			command := os.Args[1]
			switch command {
			case "install":
				return service.Install()
			case "remove":
				return service.Remove()
			case "start":
				return service.Start()
			case "stop":
				return service.Stop()
			case "status":
				return service.Status()
			default:
				return usage, nil
			}
		}

		// Do something, call your goroutines, etc

		// Set up channel on which to send signal notifications.
		// We must use a buffered channel or risk missing the signal
		// if we're not ready to receive when the signal is sent.
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

		// Set up listener for defined host and port
		listener, err := net.Listen("tcp", port)
		if err != nil {
			return "Possibly was a problem with the port binding", err
		}

		// set up channel on which to send accepted connections
		listen := make(chan net.Conn, 100)
		go acceptConnection(listener, listen)

		// loop work cycle with accept connections or interrupt
		// by system signal
		for {
			select {
			case conn := <-listen:
				go handleClient(conn)
			case killSignal := <-interrupt:
				stdlog.Println("Got signal:", killSignal)
				stdlog.Println("Stoping listening on ", listener.Addr())
				listener.Close()
				if killSignal == os.Interrupt {
					return "Daemon was interrupted by system signal", nil
				}
				return "Daemon was killed", nil
			}
		}

		// never happen, but need to complete code
		return usage, nil
	}

	// Accept a client connection and collect it in a channel
	func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				continue
			}
			listen <- conn
		}
	}

	func handleClient(client net.Conn) {
		for {
			buf := make([]byte, 4096)
			numbytes, err := client.Read(buf)
			if numbytes == 0 || err != nil {
				return
			}
			client.Write(buf[:numbytes])
		}
	}

	func init() {
		stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
		errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
	}

	func main() {
		srv, err := daemon.New(name, description, dependencies...)
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		service := &Service{srv}
		status, err := service.Manage()
		if err != nil {
			errlog.Println(status, "\nError: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
	}

Go daemon
*/
package daemon

import "strings"

// Daemon interface has a standard set of methods/commands
type Daemon interface {

	// Install the service into the system
	Install(args ...string) (string, error)

	// Remove the service and all corresponding files from the system
	Remove() (string, error)

	// Start the service
	Start() (string, error)

	// Stop the service
	Stop() (string, error)

	// Status - check the service status
	Status() (string, error)
}

// New - Create a new daemon
//
// name: name of the service
//
// description: any explanation, what is the service, its purpose
func New(name, description string, dependencies ...string) (Daemon, error) {
	return newDaemon(strings.Join(strings.Fields(name), "_"), description, dependencies)
}
<|endoftext|>


<commit_before>// Copyright 2015 Igor Dolzhikov. All rights reserved.
// Use of this source code is governed by
// license that can be found in the LICENSE file.

/*
Package daemon 0.2.12 for use with Go (golang) services.

Package daemon provides primitives for daemonization of golang services.
This package is not provide implementation of user daemon,
accordingly must have root rights to install/remove service.
In the current implementation is only supported Linux and Mac Os X daemon.

Example:

	// Example of a daemon with echo service
	package main

	import (
		"fmt"
		"log"
		"net"
		"os"
		"os/signal"
		"syscall"

		"github.com/takama/daemon"
	)

	const (

		// name of the service
		name        = "myservice"
		description = "My Echo Service"

		// port which daemon should be listen
		port = ":9977"
	)

  // dependencies that are NOT required by the service, but might be used
  var dependencies = []string{"dummy.service"}

	var stdlog, errlog *log.Logger

	// Service has embedded daemon
	type Service struct {
		daemon.Daemon
	}

	// Manage by daemon commands or run the daemon
	func (service *Service) Manage() (string, error) {

		usage := "Usage: myservice install | remove | start | stop | status"

		// if received any kind of command, do it
		if len(os.Args) > 1 {
			command := os.Args[1]
			switch command {
			case "install":
				return service.Install()
			case "remove":
				return service.Remove()
			case "start":
				return service.Start()
			case "stop":
				return service.Stop()
			case "status":
				return service.Status()
			default:
				return usage, nil
			}
		}

		// Do something, call your goroutines, etc

		// Set up channel on which to send signal notifications.
		// We must use a buffered channel or risk missing the signal
		// if we're not ready to receive when the signal is sent.
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

		// Set up listener for defined host and port
		listener, err := net.Listen("tcp", port)
		if err != nil {
			return "Possibly was a problem with the port binding", err
		}

		// set up channel on which to send accepted connections
		listen := make(chan net.Conn, 100)
		go acceptConnection(listener, listen)

		// loop work cycle with accept connections or interrupt
		// by system signal
		for {
			select {
			case conn := <-listen:
				go handleClient(conn)
			case killSignal := <-interrupt:
				stdlog.Println("Got signal:", killSignal)
				stdlog.Println("Stoping listening on ", listener.Addr())
				listener.Close()
				if killSignal == os.Interrupt {
					return "Daemon was interruped by system signal", nil
				}
				return "Daemon was killed", nil
			}
		}

		// never happen, but need to complete code
		return usage, nil
	}

	// Accept a client connection and collect it in a channel
	func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				continue
			}
			listen <- conn
		}
	}

	func handleClient(client net.Conn) {
		for {
			buf := make([]byte, 4096)
			numbytes, err := client.Read(buf)
			if numbytes == 0 || err != nil {
				return
			}
			client.Write(buf)
		}
	}

	func init() {
		stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
		errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
	}

	func main() {
		srv, err := daemon.New(name, description, dependencies...)
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		service := &Service{srv}
		status, err := service.Manage()
		if err != nil {
			errlog.Println(status, "\nError: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
	}

Go daemon
*/
package daemon

import "strings"

// Daemon interface has standard set of a methods/commands
type Daemon interface {

	// Install the service into the system
	Install() (string, error)

	// Remove the service and all corresponded files from the system
	Remove() (string, error)

	// Start the service
	Start() (string, error)

	// Stop the service
	Stop() (string, error)

	// Status - check the service status
	Status() (string, error)
}

// New - Create a new daemon
//
// name: name of the service
// description: any explanation, what is the service, its purpose
func New(name, description string, dependencies ...string) (Daemon, error) {
	return newDaemon(strings.Join(strings.Fields(name), "_"), description, dependencies)
}
<commit_msg>Bumped version number to 0.3.0<commit_after>// Copyright 2015 Igor Dolzhikov. All rights reserved.
// Use of this source code is governed by
// license that can be found in the LICENSE file.

/*
Package daemon 0.3.0 for use with Go (golang) services.

Package daemon provides primitives for daemonization of golang services.
This package is not provide implementation of user daemon,
accordingly must have root rights to install/remove service.
In the current implementation is only supported Linux and Mac Os X daemon.

Example:

	// Example of a daemon with echo service
	package main

	import (
		"fmt"
		"log"
		"net"
		"os"
		"os/signal"
		"syscall"

		"github.com/takama/daemon"
	)

	const (

		// name of the service
		name        = "myservice"
		description = "My Echo Service"

		// port which daemon should be listen
		port = ":9977"
	)

  // dependencies that are NOT required by the service, but might be used
  var dependencies = []string{"dummy.service"}

	var stdlog, errlog *log.Logger

	// Service has embedded daemon
	type Service struct {
		daemon.Daemon
	}

	// Manage by daemon commands or run the daemon
	func (service *Service) Manage() (string, error) {

		usage := "Usage: myservice install | remove | start | stop | status"

		// if received any kind of command, do it
		if len(os.Args) > 1 {
			command := os.Args[1]
			switch command {
			case "install":
				return service.Install()
			case "remove":
				return service.Remove()
			case "start":
				return service.Start()
			case "stop":
				return service.Stop()
			case "status":
				return service.Status()
			default:
				return usage, nil
			}
		}

		// Do something, call your goroutines, etc

		// Set up channel on which to send signal notifications.
		// We must use a buffered channel or risk missing the signal
		// if we're not ready to receive when the signal is sent.
		interrupt := make(chan os.Signal, 1)
		signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

		// Set up listener for defined host and port
		listener, err := net.Listen("tcp", port)
		if err != nil {
			return "Possibly was a problem with the port binding", err
		}

		// set up channel on which to send accepted connections
		listen := make(chan net.Conn, 100)
		go acceptConnection(listener, listen)

		// loop work cycle with accept connections or interrupt
		// by system signal
		for {
			select {
			case conn := <-listen:
				go handleClient(conn)
			case killSignal := <-interrupt:
				stdlog.Println("Got signal:", killSignal)
				stdlog.Println("Stoping listening on ", listener.Addr())
				listener.Close()
				if killSignal == os.Interrupt {
					return "Daemon was interruped by system signal", nil
				}
				return "Daemon was killed", nil
			}
		}

		// never happen, but need to complete code
		return usage, nil
	}

	// Accept a client connection and collect it in a channel
	func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
		for {
			conn, err := listener.Accept()
			if err != nil {
				continue
			}
			listen <- conn
		}
	}

	func handleClient(client net.Conn) {
		for {
			buf := make([]byte, 4096)
			numbytes, err := client.Read(buf)
			if numbytes == 0 || err != nil {
				return
			}
			client.Write(buf)
		}
	}

	func init() {
		stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
		errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
	}

	func main() {
		srv, err := daemon.New(name, description, dependencies...)
		if err != nil {
			errlog.Println("Error: ", err)
			os.Exit(1)
		}
		service := &Service{srv}
		status, err := service.Manage()
		if err != nil {
			errlog.Println(status, "\nError: ", err)
			os.Exit(1)
		}
		fmt.Println(status)
	}

Go daemon
*/
package daemon

import "strings"

// Daemon interface has standard set of a methods/commands
type Daemon interface {

	// Install the service into the system
	Install() (string, error)

	// Remove the service and all corresponded files from the system
	Remove() (string, error)

	// Start the service
	Start() (string, error)

	// Stop the service
	Stop() (string, error)

	// Status - check the service status
	Status() (string, error)
}

// New - Create a new daemon
//
// name: name of the service
// description: any explanation, what is the service, its purpose
func New(name, description string, dependencies ...string) (Daemon, error) {
	return newDaemon(strings.Join(strings.Fields(name), "_"), description, dependencies)
}
<|endoftext|>


<commit_before><commit_msg>remove os.Exit()<commit_after><|endoftext|>


<commit_before><commit_msg>Use the global logger (the logging config is still a mess though)<commit_after><|endoftext|>


<commit_before>package goodman

import (
	"bufio"
	"encoding/json"
	"fmt"
	"net"
)

const (
	defaultPort             = "61321"
	defaultMessageDelimiter = "\n"
)

// Server is responsible for starting a server and running lifecycle callbacks.
type Server struct {
	Runner           *Runner
	Port             string
	MessageDelimeter []byte
	conn             net.Conn
}

// NewServer returns a new server instance with the supplied runner. If no
// runner is supplied, a new one will be created.
func NewServer(runner *Runner) *Server {
	if runner == nil {
		runner = NewRunner()
	}
	return &Server{
		Runner:           runner,
		Port:             defaultPort,
		MessageDelimeter: []byte(defaultMessageDelimiter),
	}
}

// Run starts the server listening for events from dredd.
func (server *Server) Run() error {
	fmt.Println("Starting")
	ln, err := net.Listen("tcp", ":"+server.Port)
	if err != nil {
		return err
	}
	conn, err := ln.Accept()
	if err != nil {
		return err
	}

	defer conn.Close()
	server.conn = conn

	for {
		body, err := bufio.
			NewReader(conn).
			ReadString(byte(server.MessageDelimeter[0]))
		if err != nil {
			return err
		}

		body = body[:len(body)-1]
		m := &message{}
		err = json.Unmarshal([]byte(body), m)
		if err != nil {
			return err
		}
		err = server.ProcessMessage(m)
		if err != nil {
			return err
		}
	}
}

// ProcessMessage handles a single event message.
func (server *Server) ProcessMessage(m *message) error {
	switch m.Event {
	case "beforeAll":
		fallthrough
	case "afterAll":
		m.transactions = []*Transaction{}
		err := json.Unmarshal(m.Data, &m.transactions)
		if err != nil {
			return err
		}
	default:
		m.transaction = &Transaction{}
		err := json.Unmarshal(m.Data, m.transaction)
		if err != nil {
			return err
		}
	}

	switch m.Event {
	case "beforeAll":
		server.Runner.RunBeforeAll(m.transactions)
		break
	case "beforeEach":
		// before is run after beforeEach, as no separate event is fired.
		server.Runner.RunBeforeEach(m.transaction)
		server.Runner.RunBefore(m.transaction)
		break
	case "beforeEachValidation":
		// beforeValidation is run after beforeEachValidation, as no separate event
		// is fired.
		server.Runner.RunBeforeEachValidation(m.transaction)
		server.Runner.RunBeforeValidation(m.transaction)
		break
	case "afterEach":
		// after is run before afterEach as no separate event is fired.
		server.Runner.RunAfter(m.transaction)
		server.Runner.RunAfterEach(m.transaction)
		break
	case "afterAll":
		server.Runner.RunAfterAll(m.transactions)
		break
	default:
		return fmt.Errorf("Unknown event '%s'", m.Event)
	}

	switch m.Event {
	case "beforeAll":
		fallthrough
	case "afterAll":
		return server.sendResponse(m, m.transactions)
	default:
		return server.sendResponse(m, m.transaction)
	}
}

// sendResponse submits the transaction(s) back to dredd.
func (server *Server) sendResponse(m *message, dataObj interface{}) error {
	data, err := json.Marshal(dataObj)
	if err != nil {
		return err
	}

	m.Data = json.RawMessage(data)
	response, err := json.Marshal(m)
	if err != nil {
		return err
	}
	server.conn.Write(response)
	server.conn.Write(server.MessageDelimeter)
	return nil
}

// message represents a single event received over the connection.
type message struct {
	UUID  string          `json:"uuid"`
	Event string          `json:"event"`
	Data  json.RawMessage `json:"data"`

	transaction  *Transaction
	transactions []*Transaction
}
<commit_msg>Handle EOF gracefully<commit_after>package goodman

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"net"
)

const (
	defaultPort             = "61321"
	defaultMessageDelimiter = "\n"
)

// Server is responsible for starting a server and running lifecycle callbacks.
type Server struct {
	Runner           *Runner
	Port             string
	MessageDelimeter []byte
	conn             net.Conn
}

// NewServer returns a new server instance with the supplied runner. If no
// runner is supplied, a new one will be created.
func NewServer(runner *Runner) *Server {
	if runner == nil {
		runner = NewRunner()
	}
	return &Server{
		Runner:           runner,
		Port:             defaultPort,
		MessageDelimeter: []byte(defaultMessageDelimiter),
	}
}

// Run starts the server listening for events from dredd.
func (server *Server) Run() error {
	fmt.Println("Starting")
	ln, err := net.Listen("tcp", ":"+server.Port)
	if err != nil {
		return err
	}
	conn, err := ln.Accept()
	if err != nil {
		return err
	}

	defer conn.Close()
	server.conn = conn

	for {
		body, err := bufio.
			NewReader(conn).
			ReadString(byte(server.MessageDelimeter[0]))
		if err == io.EOF {
			return nil
		}
		if err != nil {
			return err
		}

		body = body[:len(body)-1]
		m := &message{}
		err = json.Unmarshal([]byte(body), m)
		if err != nil {
			return err
		}
		err = server.ProcessMessage(m)
		if err != nil {
			return err
		}
	}
}

// ProcessMessage handles a single event message.
func (server *Server) ProcessMessage(m *message) error {
	switch m.Event {
	case "beforeAll":
		fallthrough
	case "afterAll":
		m.transactions = []*Transaction{}
		err := json.Unmarshal(m.Data, &m.transactions)
		if err != nil {
			return err
		}
	default:
		m.transaction = &Transaction{}
		err := json.Unmarshal(m.Data, m.transaction)
		if err != nil {
			return err
		}
	}

	switch m.Event {
	case "beforeAll":
		server.Runner.RunBeforeAll(m.transactions)
		break
	case "beforeEach":
		// before is run after beforeEach, as no separate event is fired.
		server.Runner.RunBeforeEach(m.transaction)
		server.Runner.RunBefore(m.transaction)
		break
	case "beforeEachValidation":
		// beforeValidation is run after beforeEachValidation, as no separate event
		// is fired.
		server.Runner.RunBeforeEachValidation(m.transaction)
		server.Runner.RunBeforeValidation(m.transaction)
		break
	case "afterEach":
		// after is run before afterEach as no separate event is fired.
		server.Runner.RunAfter(m.transaction)
		server.Runner.RunAfterEach(m.transaction)
		break
	case "afterAll":
		server.Runner.RunAfterAll(m.transactions)
		break
	default:
		return fmt.Errorf("Unknown event '%s'", m.Event)
	}

	switch m.Event {
	case "beforeAll":
		fallthrough
	case "afterAll":
		return server.sendResponse(m, m.transactions)
	default:
		return server.sendResponse(m, m.transaction)
	}
}

// sendResponse submits the transaction(s) back to dredd.
func (server *Server) sendResponse(m *message, dataObj interface{}) error {
	data, err := json.Marshal(dataObj)
	if err != nil {
		return err
	}

	m.Data = json.RawMessage(data)
	response, err := json.Marshal(m)
	if err != nil {
		return err
	}
	server.conn.Write(response)
	server.conn.Write(server.MessageDelimeter)
	return nil
}

// message represents a single event received over the connection.
type message struct {
	UUID  string          `json:"uuid"`
	Event string          `json:"event"`
	Data  json.RawMessage `json:"data"`

	transaction  *Transaction
	transactions []*Transaction
}
<|endoftext|>


<commit_before>package delayd2

import (
	"errors"
	"sync"

	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/nabeken/aws-go-sqs/queue"
)

var ErrTooManyPayloads = errors.New("relay: too many payloads. Up to 10 payloads can be sent at once")

type Relay struct {
	sqsSvc *sqs.SQS

	// maps queue name to queue url
	mu       sync.RWMutex
	queueMap map[string]*string
}

func NewRelay(sqsSvc *sqs.SQS) *Relay {
	return &Relay{
		sqsSvc: sqsSvc,

		queueMap: make(map[string]*string),
	}
}

func (r *Relay) existURL(relayTo string) (*string, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	u, found := r.queueMap[relayTo]
	return u, found
}

func (r *Relay) retrieveURL(relayTo string) (*string, error) {
	if u, found := r.existURL(relayTo); found {
		return u, nil
	}

	r.mu.Lock()
	defer r.mu.Unlock()

	u, err := queue.GetQueueURL(r.sqsSvc, relayTo)
	if err != nil {
		return nil, err
	}
	r.queueMap[relayTo] = u
	return u, nil
}

// Relay relays payloads to relayTo queue.
func (r *Relay) Relay(payloads []string, relayTo string) error {
	if len(payloads) > 10 {
		return ErrTooManyPayloads
	}

	url, err := r.retrieveURL(relayTo)
	if err != nil {
		return err
	}

	batch := make([]queue.BatchMessage, 0, len(payloads))
	for _, body := range payloads {
		batch = append(batch, queue.BatchMessage{
			Body: body,
		})
	}

	entries, id2index := queue.BuildBatchRequestEntry(batch...)
	req := &sqs.SendMessageBatchInput{
		Entries:  entries,
		QueueUrl: url,
	}

	return SendMessageBatch(r.sqsSvc, req, id2index)
}

func SendMessageBatch(s *sqs.SQS, req *sqs.SendMessageBatchInput, id2index map[string]int) error {
	resp, err := s.SendMessageBatch(req)
	if err != nil {
		return err
	}
	return queue.NewBatchError(id2index, resp.Failed)
}
<commit_msg>relay: Fix the order of Relay<commit_after>package delayd2

import (
	"errors"
	"sync"

	"github.com/aws/aws-sdk-go/service/sqs"
	"github.com/nabeken/aws-go-sqs/queue"
)

var ErrTooManyPayloads = errors.New("relay: too many payloads. Up to 10 payloads can be sent at once")

type Relay struct {
	sqsSvc *sqs.SQS

	// maps queue name to queue url
	mu       sync.RWMutex
	queueMap map[string]*string
}

func NewRelay(sqsSvc *sqs.SQS) *Relay {
	return &Relay{
		sqsSvc: sqsSvc,

		queueMap: make(map[string]*string),
	}
}

func (r *Relay) existURL(relayTo string) (*string, bool) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	u, found := r.queueMap[relayTo]
	return u, found
}

func (r *Relay) retrieveURL(relayTo string) (*string, error) {
	if u, found := r.existURL(relayTo); found {
		return u, nil
	}

	r.mu.Lock()
	defer r.mu.Unlock()

	u, err := queue.GetQueueURL(r.sqsSvc, relayTo)
	if err != nil {
		return nil, err
	}
	r.queueMap[relayTo] = u
	return u, nil
}

// Relay relays payloads to relayTo queue.
func (r *Relay) Relay(relayTo string, payloads []string) error {
	if len(payloads) > 10 {
		return ErrTooManyPayloads
	}

	url, err := r.retrieveURL(relayTo)
	if err != nil {
		return err
	}

	batch := make([]queue.BatchMessage, 0, len(payloads))
	for _, body := range payloads {
		batch = append(batch, queue.BatchMessage{
			Body: body,
		})
	}

	entries, id2index := queue.BuildBatchRequestEntry(batch...)
	req := &sqs.SendMessageBatchInput{
		Entries:  entries,
		QueueUrl: url,
	}

	return SendMessageBatch(r.sqsSvc, req, id2index)
}

func SendMessageBatch(s *sqs.SQS, req *sqs.SendMessageBatchInput, id2index map[string]int) error {
	resp, err := s.SendMessageBatch(req)
	if err != nil {
		return err
	}
	return queue.NewBatchError(id2index, resp.Failed)
}
<|endoftext|>


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

import (
	"fmt"

	"github.com/coffeehc/logger"
)

/*
格式:
map[city:map[geoname_id:5037649 names:map[de:Minneapolis en:Minneapolis es:Mineápolis fr:Minneapolis ja:ミネアポリス pt-BR:Minneapolis ru:Миннеаполис zh-CN:明尼阿波利斯]] continent:map[code:NA geoname_id:6255149 names:map[de:Nordamerika en:North America es:Norteamérica fr:Amérique du Nord ja:北アメリカ pt-BR:América do Norte ru:Северная Америка zh-CN:北美洲]] country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] location:map[latitude:44.9759 longitude:-93.2166 metro_code:613 time_zone:America/Chicago] postal:map[code:55414] registered_country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] subdivisions:[map[geoname_id:5037779 iso_code:MN names:map[en:Minnesota es:Minnesota ja:ミネソタ州 ru:Миннесота]]]]
*/
type GeoIp_City struct {
	Id           int     `json:"id"`
	Ip           string  `json:"ip"`
	City         string  `json:"city"`
	Continent    string  `json:"continent"`
	Country      string  `json:"country"`
	Postal       string  `json:"postal"`
	IsoCode      string  `json:"isoCode"`
	Latitude     float64 `json:"latitude"`
	Longitude    float64 `json:"longitude"`
	TimeZone     string  `json:"timeZone"`
	Subdivisions string  `json:"subdivisions"`
	Area         string  `json:"area"`
}

func (this *IpDataBase) GetCityByIp(ip string, isoCode string) (*GeoIp_City, error) {
	entry, err := this.get(ip)
	if err != nil {
		return nil, err
	}
	if entry == nil {
		return nil, fmt.Errorf("未知地区,Ip:%s", ip)
	}
	if isoCode != "" {
		var support bool = false
		for _, language := range this.metadata.languages {
			if language == isoCode {
				support = true
				break
			}
		}
		if !support {
			return nil, fmt.Errorf("不支持%s的语言编码", isoCode)
		}
	} else {
		isoCode = "zh-CN"
	}
	city := new(GeoIp_City)
	city.IsoCode = isoCode
	city.Ip = ip
	logger.Debug("%#v", entry)
	var value map[interface{}]interface{}
	node := entry.node.(map[interface{}]interface{})
	if node["city"] != nil {
		value = node["city"].(map[interface{}]interface{})
		if value["geoname_id"] != nil {
			city.Id = int(value["geoname_id"].(uint32))
		}
		value = value["names"].(map[interface{}]interface{})
		city.City = getName(value, isoCode)
	}
	if node["continent"] != nil {
		value = node["continent"].(map[interface{}]interface{})
		value = value["names"].(map[interface{}]interface{})
		city.Continent = getName(value, isoCode)
	}
	if node["country"] != nil { //国家是有可能为空的
		value = node["country"].(map[interface{}]interface{})
		if value["names"] != nil {
			value = value["names"].(map[interface{}]interface{})
			city.Country = getName(value, isoCode)
		}
	}
	if node["postal"] != nil {
		value = node["postal"].(map[interface{}]interface{})
		city.Postal = value["code"].(string)
	}
	if node["location"] != nil {
		value = node["location"].(map[interface{}]interface{})
		city.Latitude = value["latitude"].(float64)
		city.Longitude = value["longitude"].(float64)
		if value["time_zone"] != nil {
			city.TimeZone = value["time_zone"].(string)
		}
	}
	if node["subdivisions"] != nil {
		values := node["subdivisions"].([]interface{})
		if len(values) > 0 {
			value = values[0].(map[interface{}]interface{})
			if value["iso_code"] != nil {
				city.Subdivisions = value["iso_code"].(string)
			}
			if value["names"] != nil {
				value = value["names"].(map[interface{}]interface{})
				city.Area = getName(value, isoCode)
			}
		}
	}
	return city, nil
}

func getName(value map[interface{}]interface{}, isoCode string) string {
	if value[isoCode] != nil {
		return value[isoCode].(string)
	} else {
		if value["en"] != nil {
			return value["en"].(string)
		} else {
			return "未知"
		}
	}
}
<commit_msg>no message<commit_after>// geoip project geoip.go
package geoip

import "fmt"

/*
格式:
map[city:map[geoname_id:5037649 names:map[de:Minneapolis en:Minneapolis es:Mineápolis fr:Minneapolis ja:ミネアポリス pt-BR:Minneapolis ru:Миннеаполис zh-CN:明尼阿波利斯]] continent:map[code:NA geoname_id:6255149 names:map[de:Nordamerika en:North America es:Norteamérica fr:Amérique du Nord ja:北アメリカ pt-BR:América do Norte ru:Северная Америка zh-CN:北美洲]] country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] location:map[latitude:44.9759 longitude:-93.2166 metro_code:613 time_zone:America/Chicago] postal:map[code:55414] registered_country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] subdivisions:[map[geoname_id:5037779 iso_code:MN names:map[en:Minnesota es:Minnesota ja:ミネソタ州 ru:Миннесота]]]]
*/
type GeoIp_City struct {
	Id           int     `json:"id"`
	Ip           string  `json:"ip"`
	City         string  `json:"city"`
	Continent    string  `json:"continent"`
	Country      string  `json:"country"`
	Postal       string  `json:"postal"`
	IsoCode      string  `json:"isoCode"`
	Latitude     float64 `json:"latitude"`
	Longitude    float64 `json:"longitude"`
	TimeZone     string  `json:"timeZone"`
	Subdivisions string  `json:"subdivisions"`
	Area         string  `json:"area"`
}

func (this *IpDataBase) GetCityByIp(ip string, isoCode string) (*GeoIp_City, error) {
	entry, err := this.get(ip)
	if err != nil {
		return nil, err
	}
	if entry == nil {
		return nil, fmt.Errorf("未知地区,Ip:%s", ip)
	}
	if isoCode != "" {
		var support bool = false
		for _, language := range this.metadata.languages {
			if language == isoCode {
				support = true
				break
			}
		}
		if !support {
			return nil, fmt.Errorf("不支持%s的语言编码", isoCode)
		}
	} else {
		isoCode = "zh-CN"
	}
	city := new(GeoIp_City)
	city.IsoCode = isoCode
	city.Ip = ip
	var value map[interface{}]interface{}
	node := entry.node.(map[interface{}]interface{})
	if node["city"] != nil {
		value = node["city"].(map[interface{}]interface{})
		if value["geoname_id"] != nil {
			city.Id = int(value["geoname_id"].(uint32))
		}
		value = value["names"].(map[interface{}]interface{})
		city.City = getName(value, isoCode)
	}
	if node["continent"] != nil {
		value = node["continent"].(map[interface{}]interface{})
		value = value["names"].(map[interface{}]interface{})
		city.Continent = getName(value, isoCode)
	}
	if node["country"] != nil { //国家是有可能为空的
		value = node["country"].(map[interface{}]interface{})
		if value["names"] != nil {
			value = value["names"].(map[interface{}]interface{})
			city.Country = getName(value, isoCode)
		}
	}
	if node["postal"] != nil {
		value = node["postal"].(map[interface{}]interface{})
		city.Postal = value["code"].(string)
	}
	if node["location"] != nil {
		value = node["location"].(map[interface{}]interface{})
		city.Latitude = value["latitude"].(float64)
		city.Longitude = value["longitude"].(float64)
		if value["time_zone"] != nil {
			city.TimeZone = value["time_zone"].(string)
		}
	}
	if node["subdivisions"] != nil {
		values := node["subdivisions"].([]interface{})
		if len(values) > 0 {
			value = values[0].(map[interface{}]interface{})
			if value["iso_code"] != nil {
				city.Subdivisions = value["iso_code"].(string)
			}
			if value["names"] != nil {
				value = value["names"].(map[interface{}]interface{})
				city.Area = getName(value, isoCode)
			}
		}
	}
	return city, nil
}

func getName(value map[interface{}]interface{}, isoCode string) string {
	if value[isoCode] != nil {
		return value[isoCode].(string)
	} else {
		if value["en"] != nil {
			return value["en"].(string)
		} else {
			return "未知"
		}
	}
}
<|endoftext|>


<commit_before>/*
fperf allows you to build your performace tools easily

Three steps to create your own testcase

1. Create the "NewClient" function

	package demo

	import (
		"fmt"
		"github.com/shafreeck/fperf/client"
		"time"
	)

	type DemoClient struct{}

	func NewDemoClient(flag *client.FlagSet) client.Client {
		return &DemoClient{}
	}

2. Implement the UnaryClient or StreamClient

	func (c *DemoClient) Dial(addr string) error {
		fmt.Println("Dial to", addr)
		return nil
	}

	func (c *DemoClient) Request() error {
		time.Sleep(100 * time.Millisecond)
		return nil
	}

3. Register to fperf

	func init() {
		client.Register("demo", NewDemoClient, "This is a demo client discription")
	}

Run the buildin testcase

http_testing is a simple builtin testcase to benchmark http servers

	fperf -cpu 8 -connection 10 http_testing -url http://example.com
*/
package main

import (
	"flag"
	"fmt"
	db "github.com/influxdata/influxdb/client/v2"
	"github.com/shafreeck/fperf/client"
	hist "github.com/shafreeck/fperf/stats"
	"golang.org/x/net/context"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"
)

type setting struct {
	Connection int
	Stream     int
	Goroutine  int
	CPU        int
	Burst      int
	N          int //number of requests
	Tick       time.Duration
	Address    string
	Send       bool
	Recv       bool
	Delay      time.Duration
	Async      bool
	Target     string
	CallType   string
	InfluxDB   string
}

type statistics struct {
	latencies []time.Duration
	histogram *hist.Histogram
}

type roundtrip struct {
	start time.Time
	end   time.Time
	ack   bool
}

func createClients(n int, addr string) []client.Client {
	clients := make([]client.Client, n)
	for i := 0; i < n; i++ {
		cli := client.NewClient(s.Target)
		if cli == nil {
			log.Fatalf("Can not find client %q for benchmark\n", s.Target)
		}

		cli.Dial(addr)
		clients[i] = cli
	}
	return clients
}
func createStreams(n int, clients []client.Client) []client.Stream {
	streams := make([]client.Stream, n*len(clients))
	for cur, cli := range clients {
		for i := 0; i < n; i++ {
			if cli, ok := cli.(client.StreamClient); ok {
				stream, err := cli.CreateStream(context.Background())
				if err != nil {
					log.Fatalf("StreamCall faile to create new stream, %v", err)
				}
				streams[cur*n+i] = stream
			} else {
				log.Fatalln(s.Target, " do not implement the client.StreamClient")
			}
		}
	}
	return streams
}

func benchmarkStream(n int, streams []client.Stream) {
	var wg sync.WaitGroup
	for _, stream := range streams {
		for i := 0; i < n; i++ {
			//Notice here. we must pass stream as a parameter because the varibale stream
			//would be changed after the goroutine created
			if s.Async {
				wg.Add(2)
				go func(stream client.Stream) { send(nil, stream); wg.Done() }(stream)
				go func(stream client.Stream) { recv(nil, stream); wg.Done() }(stream)
			} else {
				wg.Add(1)
				go func(stream client.Stream) { run(nil, stream); wg.Done() }(stream)
			}
		}
	}
	go statPrint()
	wg.Wait()
}
func benchmarkUnary(n int, clients []client.Client) {
	var wg sync.WaitGroup
	for _, cli := range clients {
		for i := 0; i < n; i++ {
			wg.Add(1)
			if cli, ok := cli.(client.UnaryClient); ok {
				go func(cli client.UnaryClient) { runUnary(nil, cli); wg.Done() }(cli)
			} else {
				log.Fatalln(s.Target, " does not implement the client.UnaryClient")
			}
		}
	}
	go statPrint()
	wg.Wait()
}

func runUnary(done <-chan int, cli client.UnaryClient) {
	for i := 0; s.N == 0 || i < s.N; i++ {
		//select {
		//case <-done:
		//	log.Println("run goroutine exit done")
		//	return
		//default:
		start := time.Now()
		if err := cli.Request(); err != nil {
			log.Println(err)
		}
		eplase := time.Since(start)
		stats.latencies = append(stats.latencies, eplase)
		stats.histogram.Add(int64(eplase))
		if s.Delay > 0 {
			time.Sleep(s.Delay)
		}
		//	}
	}
}
func run(done <-chan int, stream client.Stream) {
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("run goroutine exit done")
			return
		default:
			start := time.Now()
			if s.Send {
				stream.DoSend()
			}
			if s.Recv {
				stream.DoRecv()
			}
			eplase := time.Since(start)
			stats.latencies = append(stats.latencies, eplase)
			stats.histogram.Add(int64(eplase))
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}

func send(done <-chan int, stream client.Stream) {
	timer := time.NewTimer(time.Second)
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("send goroutine exit, done")
			return
		default:
			select {
			case rtts <- &roundtrip{start: time.Now(), ack: false}:
				timer.Reset(time.Second)
			case <-timer.C:
				log.Println("blocked on send rtts")
			}

			if burst != nil {
				select {
				case burst <- 0:
					timer.Reset(time.Second)
				case <-timer.C:
					log.Println("blocked on send burst chan")
				}
			}

			stream.DoSend()
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}
func recv(done <-chan int, stream client.Stream) {
	timer := time.NewTimer(time.Second)
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("recv goroutine exit, done")
			return
		default:
			if burst != nil {
				select {
				case <-burst:
					timer.Reset(time.Second)
				case <-timer.C:
					log.Println("blocked on recv burst chan")
				}
			}
			err := stream.DoRecv()
			if err != nil {
				log.Println("recv goroutine exit", err)
				return
			}
			select {
			case rtt := <-rtts:
				timer.Reset(time.Second)
				rtt.ack = true
				eplase := time.Since(rtt.start)
				stats.latencies = append(stats.latencies, eplase)
				stats.histogram.Add(int64(eplase))
			case <-timer.C:
				log.Println("blocked on recv rtts")
			}
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}

func statPrint() {
	tickc := time.Tick(s.Tick)
	var latencies []time.Duration
	total := int64(0)
	for {
		select {
		case <-tickc:
			latencies = stats.latencies
			stats.latencies = stats.latencies[:0]

			sum := time.Duration(0)
			for _, eplase := range latencies {
				total++
				sum += eplase
			}
			count := len(latencies)
			if count != 0 {
				log.Printf("latency %v qps %d total %v\n", sum/time.Duration(count), int64(float64(count)/float64(s.Tick)*float64(time.Second)), total)
				if influxdb != nil {
					bp, _ := db.NewBatchPoints(db.BatchPointsConfig{
						Database:  "fperf",
						Precision: "s",
					})
					tags := map[string]string{"latency": "latency", "qps": "qps"}
					fields := map[string]interface{}{
						"latency": float64(sum) / float64(count) / 1000.0,
						"qps":     int64(float64(count) / float64(s.Tick) * float64(time.Second)),
					}
					pt, err := db.NewPoint("benchmark", tags, fields, time.Now())
					if err != nil {
						log.Println("Error: ", err.Error())
					}
					bp.AddPoint(pt)

					// Write the batch
					err = influxdb.Write(bp)
					if err != nil {
						log.Println("Error: ", err.Error())
					}
				}
			} else {
				log.Printf("blocking...")
			}
		}
	}
}

var s setting
var stats statistics
var rtts = make(chan *roundtrip, 10*1024*1024)
var mutex sync.RWMutex
var burst chan int
var influxdb db.Client

func usage() {
	fmt.Printf("Usage: %v [options] <client>\noptions:\n", os.Args[0])
	flag.PrintDefaults()
	fmt.Println("clients:")
	for name, desc := range client.AllClients() {
		fmt.Printf(" %s", name)
		if len(desc) > 0 {
			fmt.Printf("\t: %s", desc)
		}
		fmt.Println()
	}
}

func main() {
	flag.IntVar(&s.Connection, "connection", 1, "number of connection")
	flag.IntVar(&s.Stream, "stream", 1, "number of streams per connection")
	flag.IntVar(&s.Goroutine, "goroutine", 1, "number of goroutines per stream")
	flag.IntVar(&s.CPU, "cpu", 0, "set the GOMAXPROCS, use go default if 0")
	flag.IntVar(&s.Burst, "burst", 0, "burst a number of request, use with -async=true")
	flag.IntVar(&s.N, "N", 0, "number of request per goroutine")
	flag.BoolVar(&s.Send, "send", true, "perform send action")
	flag.BoolVar(&s.Recv, "recv", true, "perform recv action")
	flag.DurationVar(&s.Delay, "delay", 0, "wait delay time before send the next request")
	flag.DurationVar(&s.Tick, "tick", 2*time.Second, "interval between statistics")
	flag.StringVar(&s.Address, "server", "127.0.0.1:8804", "address of the target server")
	flag.BoolVar(&s.Async, "async", false, "send and recv in seperate goroutines")
	flag.StringVar(&s.CallType, "type", "auto", "set the call type:unary, stream or auto. default is auto")
	flag.StringVar(&s.InfluxDB, "influxdb", "", "writing stats to influxdb, specify the address in this option")
	flag.Usage = usage
	flag.Parse()

	s.Target = flag.Arg(0)
	if len(s.Target) == 0 {
		flag.Usage()
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		_ = <-c
		stats.histogram.Value().Print(os.Stdout)
		os.Exit(0)
	}()

	runtime.GOMAXPROCS(s.CPU)
	go func() {
		runtime.SetBlockProfileRate(1)
		log.Println(http.ListenAndServe(":6060", nil))
	}()

	if s.Burst > 0 {
		burst = make(chan int, s.Burst)
	}

	if len(s.InfluxDB) > 0 {
		c, err := db.NewHTTPClient(db.HTTPConfig{
			Addr: s.InfluxDB,
		})
		if err != nil {
			log.Fatalf("Error creating InfluxDB Client: %v", err.Error())
		}
		defer c.Close()
		q := db.NewQuery("CREATE DATABASE fperf", "", "")
		if response, err := c.Query(q); err == nil && response.Error() == nil {
			log.Println(response.Results)
		}
		influxdb = c
	}

	stats.latencies = make([]time.Duration, 0, 500000)
	histopt := hist.HistogramOptions{
		NumBuckets:         16,
		GrowthFactor:       1.8,
		SmallestBucketSize: 1000,
		MinValue:           10000,
	}
	stats.histogram = hist.NewHistogram(histopt)
	clients := createClients(s.Connection, s.Address)
	cli := clients[0]
	switch s.CallType {
	case "auto":
		switch cli.(type) {
		case client.StreamClient:
			streams := createStreams(s.Stream, clients)
			benchmarkStream(s.Goroutine, streams)
		case client.UnaryClient:
			benchmarkUnary(s.Goroutine, clients)
		}
	case "stream":
		streams := createStreams(s.Stream, clients)
		benchmarkStream(s.Goroutine, streams)
	case "unary":
		benchmarkUnary(s.Goroutine, clients)
	}
}
<commit_msg>Handle error of Dial<commit_after>/*
fperf allows you to build your performace tools easily

Three steps to create your own testcase

1. Create the "NewClient" function

	package demo

	import (
		"fmt"
		"github.com/shafreeck/fperf/client"
		"time"
	)

	type DemoClient struct{}

	func NewDemoClient(flag *client.FlagSet) client.Client {
		return &DemoClient{}
	}

2. Implement the UnaryClient or StreamClient

	func (c *DemoClient) Dial(addr string) error {
		fmt.Println("Dial to", addr)
		return nil
	}

	func (c *DemoClient) Request() error {
		time.Sleep(100 * time.Millisecond)
		return nil
	}

3. Register to fperf

	func init() {
		client.Register("demo", NewDemoClient, "This is a demo client discription")
	}

Run the buildin testcase

http_testing is a simple builtin testcase to benchmark http servers

	fperf -cpu 8 -connection 10 http_testing -url http://example.com
*/
package main

import (
	"flag"
	"fmt"
	db "github.com/influxdata/influxdb/client/v2"
	"github.com/shafreeck/fperf/client"
	hist "github.com/shafreeck/fperf/stats"
	"golang.org/x/net/context"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"sync"
	"syscall"
	"time"
)

type setting struct {
	Connection int
	Stream     int
	Goroutine  int
	CPU        int
	Burst      int
	N          int //number of requests
	Tick       time.Duration
	Address    string
	Send       bool
	Recv       bool
	Delay      time.Duration
	Async      bool
	Target     string
	CallType   string
	InfluxDB   string
}

type statistics struct {
	latencies []time.Duration
	histogram *hist.Histogram
}

type roundtrip struct {
	start time.Time
	end   time.Time
	ack   bool
}

func createClients(n int, addr string) []client.Client {
	clients := make([]client.Client, n)
	for i := 0; i < n; i++ {
		cli := client.NewClient(s.Target)
		if cli == nil {
			log.Fatalf("Can not find client %q for benchmark\n", s.Target)
		}

		if err := cli.Dial(addr); err != nil {
			log.Fatalln(err)
		}
		clients[i] = cli
	}
	return clients
}
func createStreams(n int, clients []client.Client) []client.Stream {
	streams := make([]client.Stream, n*len(clients))
	for cur, cli := range clients {
		for i := 0; i < n; i++ {
			if cli, ok := cli.(client.StreamClient); ok {
				stream, err := cli.CreateStream(context.Background())
				if err != nil {
					log.Fatalf("StreamCall faile to create new stream, %v", err)
				}
				streams[cur*n+i] = stream
			} else {
				log.Fatalln(s.Target, " do not implement the client.StreamClient")
			}
		}
	}
	return streams
}

func benchmarkStream(n int, streams []client.Stream) {
	var wg sync.WaitGroup
	for _, stream := range streams {
		for i := 0; i < n; i++ {
			//Notice here. we must pass stream as a parameter because the varibale stream
			//would be changed after the goroutine created
			if s.Async {
				wg.Add(2)
				go func(stream client.Stream) { send(nil, stream); wg.Done() }(stream)
				go func(stream client.Stream) { recv(nil, stream); wg.Done() }(stream)
			} else {
				wg.Add(1)
				go func(stream client.Stream) { run(nil, stream); wg.Done() }(stream)
			}
		}
	}
	go statPrint()
	wg.Wait()
}
func benchmarkUnary(n int, clients []client.Client) {
	var wg sync.WaitGroup
	for _, cli := range clients {
		for i := 0; i < n; i++ {
			wg.Add(1)
			if cli, ok := cli.(client.UnaryClient); ok {
				go func(cli client.UnaryClient) { runUnary(nil, cli); wg.Done() }(cli)
			} else {
				log.Fatalln(s.Target, " does not implement the client.UnaryClient")
			}
		}
	}
	go statPrint()
	wg.Wait()
}

func runUnary(done <-chan int, cli client.UnaryClient) {
	for i := 0; s.N == 0 || i < s.N; i++ {
		//select {
		//case <-done:
		//	log.Println("run goroutine exit done")
		//	return
		//default:
		start := time.Now()
		if err := cli.Request(); err != nil {
			log.Println(err)
		}
		eplase := time.Since(start)
		stats.latencies = append(stats.latencies, eplase)
		stats.histogram.Add(int64(eplase))
		if s.Delay > 0 {
			time.Sleep(s.Delay)
		}
		//	}
	}
}
func run(done <-chan int, stream client.Stream) {
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("run goroutine exit done")
			return
		default:
			start := time.Now()
			if s.Send {
				stream.DoSend()
			}
			if s.Recv {
				stream.DoRecv()
			}
			eplase := time.Since(start)
			stats.latencies = append(stats.latencies, eplase)
			stats.histogram.Add(int64(eplase))
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}

func send(done <-chan int, stream client.Stream) {
	timer := time.NewTimer(time.Second)
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("send goroutine exit, done")
			return
		default:
			select {
			case rtts <- &roundtrip{start: time.Now(), ack: false}:
				timer.Reset(time.Second)
			case <-timer.C:
				log.Println("blocked on send rtts")
			}

			if burst != nil {
				select {
				case burst <- 0:
					timer.Reset(time.Second)
				case <-timer.C:
					log.Println("blocked on send burst chan")
				}
			}

			stream.DoSend()
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}
func recv(done <-chan int, stream client.Stream) {
	timer := time.NewTimer(time.Second)
	for i := 0; s.N == 0 || i < s.N; i++ {
		select {
		case <-done:
			log.Println("recv goroutine exit, done")
			return
		default:
			if burst != nil {
				select {
				case <-burst:
					timer.Reset(time.Second)
				case <-timer.C:
					log.Println("blocked on recv burst chan")
				}
			}
			err := stream.DoRecv()
			if err != nil {
				log.Println("recv goroutine exit", err)
				return
			}
			select {
			case rtt := <-rtts:
				timer.Reset(time.Second)
				rtt.ack = true
				eplase := time.Since(rtt.start)
				stats.latencies = append(stats.latencies, eplase)
				stats.histogram.Add(int64(eplase))
			case <-timer.C:
				log.Println("blocked on recv rtts")
			}
			if s.Delay > 0 {
				time.Sleep(s.Delay)
			}
		}
	}
}

func statPrint() {
	tickc := time.Tick(s.Tick)
	var latencies []time.Duration
	total := int64(0)
	for {
		select {
		case <-tickc:
			latencies = stats.latencies
			stats.latencies = stats.latencies[:0]

			sum := time.Duration(0)
			for _, eplase := range latencies {
				total++
				sum += eplase
			}
			count := len(latencies)
			if count != 0 {
				log.Printf("latency %v qps %d total %v\n", sum/time.Duration(count), int64(float64(count)/float64(s.Tick)*float64(time.Second)), total)
				if influxdb != nil {
					bp, _ := db.NewBatchPoints(db.BatchPointsConfig{
						Database:  "fperf",
						Precision: "s",
					})
					tags := map[string]string{"latency": "latency", "qps": "qps"}
					fields := map[string]interface{}{
						"latency": float64(sum) / float64(count) / 1000.0,
						"qps":     int64(float64(count) / float64(s.Tick) * float64(time.Second)),
					}
					pt, err := db.NewPoint("benchmark", tags, fields, time.Now())
					if err != nil {
						log.Println("Error: ", err.Error())
					}
					bp.AddPoint(pt)

					// Write the batch
					err = influxdb.Write(bp)
					if err != nil {
						log.Println("Error: ", err.Error())
					}
				}
			} else {
				log.Printf("blocking...")
			}
		}
	}
}

var s setting
var stats statistics
var rtts = make(chan *roundtrip, 10*1024*1024)
var mutex sync.RWMutex
var burst chan int
var influxdb db.Client

func usage() {
	fmt.Printf("Usage: %v [options] <client>\noptions:\n", os.Args[0])
	flag.PrintDefaults()
	fmt.Println("clients:")
	for name, desc := range client.AllClients() {
		fmt.Printf(" %s", name)
		if len(desc) > 0 {
			fmt.Printf("\t: %s", desc)
		}
		fmt.Println()
	}
}

func main() {
	flag.IntVar(&s.Connection, "connection", 1, "number of connection")
	flag.IntVar(&s.Stream, "stream", 1, "number of streams per connection")
	flag.IntVar(&s.Goroutine, "goroutine", 1, "number of goroutines per stream")
	flag.IntVar(&s.CPU, "cpu", 0, "set the GOMAXPROCS, use go default if 0")
	flag.IntVar(&s.Burst, "burst", 0, "burst a number of request, use with -async=true")
	flag.IntVar(&s.N, "N", 0, "number of request per goroutine")
	flag.BoolVar(&s.Send, "send", true, "perform send action")
	flag.BoolVar(&s.Recv, "recv", true, "perform recv action")
	flag.DurationVar(&s.Delay, "delay", 0, "wait delay time before send the next request")
	flag.DurationVar(&s.Tick, "tick", 2*time.Second, "interval between statistics")
	flag.StringVar(&s.Address, "server", "127.0.0.1:8804", "address of the target server")
	flag.BoolVar(&s.Async, "async", false, "send and recv in seperate goroutines")
	flag.StringVar(&s.CallType, "type", "auto", "set the call type:unary, stream or auto. default is auto")
	flag.StringVar(&s.InfluxDB, "influxdb", "", "writing stats to influxdb, specify the address in this option")
	flag.Usage = usage
	flag.Parse()

	s.Target = flag.Arg(0)
	if len(s.Target) == 0 {
		flag.Usage()
		return
	}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		_ = <-c
		stats.histogram.Value().Print(os.Stdout)
		os.Exit(0)
	}()

	runtime.GOMAXPROCS(s.CPU)
	go func() {
		runtime.SetBlockProfileRate(1)
		log.Println(http.ListenAndServe(":6060", nil))
	}()

	if s.Burst > 0 {
		burst = make(chan int, s.Burst)
	}

	if len(s.InfluxDB) > 0 {
		c, err := db.NewHTTPClient(db.HTTPConfig{
			Addr: s.InfluxDB,
		})
		if err != nil {
			log.Fatalf("Error creating InfluxDB Client: %v", err.Error())
		}
		defer c.Close()
		q := db.NewQuery("CREATE DATABASE fperf", "", "")
		if response, err := c.Query(q); err == nil && response.Error() == nil {
			log.Println(response.Results)
		}
		influxdb = c
	}

	stats.latencies = make([]time.Duration, 0, 500000)
	histopt := hist.HistogramOptions{
		NumBuckets:         16,
		GrowthFactor:       1.8,
		SmallestBucketSize: 1000,
		MinValue:           10000,
	}
	stats.histogram = hist.NewHistogram(histopt)
	clients := createClients(s.Connection, s.Address)
	cli := clients[0]
	switch s.CallType {
	case "auto":
		switch cli.(type) {
		case client.StreamClient:
			streams := createStreams(s.Stream, clients)
			benchmarkStream(s.Goroutine, streams)
		case client.UnaryClient:
			benchmarkUnary(s.Goroutine, clients)
		}
	case "stream":
		streams := createStreams(s.Stream, clients)
		benchmarkStream(s.Goroutine, streams)
	case "unary":
		benchmarkUnary(s.Goroutine, clients)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Snowflake Computing Inc. All right reserved.

package gosnowflake

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"io"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"

	"context"

	"sync"
)

var random *rand.Rand

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}

const requestGUIDKey string = "request_guid"

// Format of "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
const uuidLen int = 36

// This class takes in an url during construction and replace the
// value of request_guid every time the replace() is called
// When the url does not contain request_guid, just return the original
// url
type requestGUIDReplacerI interface {
	// replace the url with new ID
	replace() string
}

// Make requestGUIDReplacer given a url string
func makeRequestGUIDReplacer(url string) requestGUIDReplacerI {
	startIndex := strings.Index(url, requestGUIDKey)
	if startIndex == -1 {
		return &transientReplacer{url}
	}
	replacer := &requestGUIDReplacer{}
	startIndex += len(requestGUIDKey) + 1
	replacer.prefix = url[:startIndex]

	startIndex += uuidLen
	replacer.suffix = url[startIndex:]
	return replacer
}

// this replacer does nothing but replace the url
type transientReplacer struct {
	url string
}

func (replacer *transientReplacer) replace() string {
	return replacer.url
}

/*
requestGUIDReplacer is a one-shot object that is created out of the retry loop and
called with replace to change the retry_guid's value upon every retry
*/
type requestGUIDReplacer struct {
	// cached prefix and suffix to avoid parsing same url again
	prefix string
	suffix string
}

/**
This function would replace they value of the requestGUIDKey in a url with a newly
generated uuid
*/
func (replacer *requestGUIDReplacer) replace() string {
	return replacer.prefix + uuid.New().String() + replacer.suffix
}

type waitAlgo struct {
	mutex *sync.Mutex   // required for random.Int63n
	base  time.Duration // base wait time
	cap   time.Duration // maximum wait time
}

func randSecondDuration(n time.Duration) time.Duration {
	return time.Duration(random.Int63n(int64(n/time.Second))) * time.Second
}

// decorrelated jitter backoff
func (w *waitAlgo) decorr(attempt int, sleep time.Duration) time.Duration {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	t := 3*sleep - w.base
	switch {
	case t > 0:
		return durationMin(w.cap, randSecondDuration(t)+w.base)
	case t < 0:
		return durationMin(w.cap, randSecondDuration(-t)+3*sleep)
	}
	return w.base
}

var defaultWaitAlgo = &waitAlgo{
	mutex: &sync.Mutex{},
	base:  5 * time.Second,
	cap:   160 * time.Second,
}

type requestFunc func(method, urlStr string, body io.Reader) (*http.Request, error)

type clientInterface interface {
	Do(req *http.Request) (*http.Response, error)
}

func retryHTTP(
	ctx context.Context,
	client clientInterface,
	req requestFunc,
	method string,
	fullURL string,
	headers map[string]string,
	body []byte,
	timeout time.Duration,
	raise4XX bool) (res *http.Response, err error) {

	totalTimeout := timeout
	glog.V(2).Infof("retryHTTP.totalTimeout: %v", totalTimeout)
	retryCounter := 0
	sleepTime := time.Duration(0)

	var rIDReplacer requestGUIDReplacerI

	for {
		req, err := req(method, fullURL, bytes.NewReader(body))
		if err != nil {
			return nil, err
		}
		if req != nil {
			// req can be nil in tests
			req = req.WithContext(ctx)
		}
		for k, v := range headers {
			req.Header.Set(k, v)
		}
		res, err = client.Do(req)
		if err == nil && res.StatusCode == http.StatusOK {
			// exit if success
			break
		}
		if raise4XX && res != nil && res.StatusCode >= 400 && res.StatusCode < 500 {
			// abort connection if raise4XX flag is enabled and the range of HTTP status code are 4XX.
			// This is currently used for Snowflake login. The caller must generate an error object based on HTTP status.
			break
		}

		// context cancel or timeout
		if err != nil {
			urlError, isURLError := err.(*url.Error)
			if isURLError &&
				(urlError.Err == context.DeadlineExceeded || urlError.Err == context.Canceled) {
				return res, urlError.Err
			}
		}

		// cannot just return 4xx and 5xx status as the error can be sporadic. retry often helps.
		if err != nil {
			glog.V(2).Infof(
				"failed http connection. no response is returned. err: %v. retrying...\n", err)
		} else {
			glog.V(2).Infof(
				"failed http connection. HTTP Status: %v. retrying...\n", res.StatusCode)
		}
		// uses decorrelated jitter backoff
		sleepTime = defaultWaitAlgo.decorr(retryCounter, sleepTime)

		if totalTimeout > 0 {
			glog.V(2).Infof("to timeout: %v", totalTimeout)
			// if any timeout is set
			totalTimeout -= sleepTime
			if totalTimeout <= 0 {
				if err != nil {
					return nil, fmt.Errorf("timeout. err: %v. Hanging?", err)
				}
				if res != nil {
					return nil, fmt.Errorf("timeout. HTTP Status: %v. Hanging?", res.StatusCode)
				}
				return nil, errors.New("timeout. Hanging?")
			}
		}
		retryCounter++
		if rIDReplacer == nil {
			rIDReplacer = makeRequestGUIDReplacer(fullURL)
		}
		fullURL = rIDReplacer.replace()
		glog.V(2).Infof("sleeping %v. to timeout: %v. retrying", sleepTime, totalTimeout)
		time.Sleep(sleepTime)
	}
	return res, err
}
<commit_msg>do not sleep through a context timeout<commit_after>// Copyright (c) 2017-2018 Snowflake Computing Inc. All right reserved.

package gosnowflake

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"io"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"

	"context"

	"sync"
)

var random *rand.Rand

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}

const requestGUIDKey string = "request_guid"

// Format of "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
const uuidLen int = 36

// This class takes in an url during construction and replace the
// value of request_guid every time the replace() is called
// When the url does not contain request_guid, just return the original
// url
type requestGUIDReplacerI interface {
	// replace the url with new ID
	replace() string
}

// Make requestGUIDReplacer given a url string
func makeRequestGUIDReplacer(url string) requestGUIDReplacerI {
	startIndex := strings.Index(url, requestGUIDKey)
	if startIndex == -1 {
		return &transientReplacer{url}
	}
	replacer := &requestGUIDReplacer{}
	startIndex += len(requestGUIDKey) + 1
	replacer.prefix = url[:startIndex]

	startIndex += uuidLen
	replacer.suffix = url[startIndex:]
	return replacer
}

// this replacer does nothing but replace the url
type transientReplacer struct {
	url string
}

func (replacer *transientReplacer) replace() string {
	return replacer.url
}

/*
requestGUIDReplacer is a one-shot object that is created out of the retry loop and
called with replace to change the retry_guid's value upon every retry
*/
type requestGUIDReplacer struct {
	// cached prefix and suffix to avoid parsing same url again
	prefix string
	suffix string
}

/**
This function would replace they value of the requestGUIDKey in a url with a newly
generated uuid
*/
func (replacer *requestGUIDReplacer) replace() string {
	return replacer.prefix + uuid.New().String() + replacer.suffix
}

type waitAlgo struct {
	mutex *sync.Mutex   // required for random.Int63n
	base  time.Duration // base wait time
	cap   time.Duration // maximum wait time
}

func randSecondDuration(n time.Duration) time.Duration {
	return time.Duration(random.Int63n(int64(n/time.Second))) * time.Second
}

// decorrelated jitter backoff
func (w *waitAlgo) decorr(attempt int, sleep time.Duration) time.Duration {
	w.mutex.Lock()
	defer w.mutex.Unlock()
	t := 3*sleep - w.base
	switch {
	case t > 0:
		return durationMin(w.cap, randSecondDuration(t)+w.base)
	case t < 0:
		return durationMin(w.cap, randSecondDuration(-t)+3*sleep)
	}
	return w.base
}

var defaultWaitAlgo = &waitAlgo{
	mutex: &sync.Mutex{},
	base:  5 * time.Second,
	cap:   160 * time.Second,
}

type requestFunc func(method, urlStr string, body io.Reader) (*http.Request, error)

type clientInterface interface {
	Do(req *http.Request) (*http.Response, error)
}

func retryHTTP(
	ctx context.Context,
	client clientInterface,
	req requestFunc,
	method string,
	fullURL string,
	headers map[string]string,
	body []byte,
	timeout time.Duration,
	raise4XX bool) (res *http.Response, err error) {

	totalTimeout := timeout
	glog.V(2).Infof("retryHTTP.totalTimeout: %v", totalTimeout)
	retryCounter := 0
	sleepTime := time.Duration(0)

	var rIDReplacer requestGUIDReplacerI

	for {
		req, err := req(method, fullURL, bytes.NewReader(body))
		if err != nil {
			return nil, err
		}
		if req != nil {
			// req can be nil in tests
			req = req.WithContext(ctx)
		}
		for k, v := range headers {
			req.Header.Set(k, v)
		}
		res, err = client.Do(req)
		if err == nil && res.StatusCode == http.StatusOK {
			// exit if success
			break
		}
		if raise4XX && res != nil && res.StatusCode >= 400 && res.StatusCode < 500 {
			// abort connection if raise4XX flag is enabled and the range of HTTP status code are 4XX.
			// This is currently used for Snowflake login. The caller must generate an error object based on HTTP status.
			break
		}

		// context cancel or timeout
		if err != nil {
			urlError, isURLError := err.(*url.Error)
			if isURLError &&
				(urlError.Err == context.DeadlineExceeded || urlError.Err == context.Canceled) {
				return res, urlError.Err
			}
		}

		// cannot just return 4xx and 5xx status as the error can be sporadic. retry often helps.
		if err != nil {
			glog.V(2).Infof(
				"failed http connection. no response is returned. err: %v. retrying...\n", err)
		} else {
			glog.V(2).Infof(
				"failed http connection. HTTP Status: %v. retrying...\n", res.StatusCode)
		}
		// uses decorrelated jitter backoff
		sleepTime = defaultWaitAlgo.decorr(retryCounter, sleepTime)

		if totalTimeout > 0 {
			glog.V(2).Infof("to timeout: %v", totalTimeout)
			// if any timeout is set
			totalTimeout -= sleepTime
			if totalTimeout <= 0 {
				if err != nil {
					return nil, fmt.Errorf("timeout. err: %v. Hanging?", err)
				}
				if res != nil {
					return nil, fmt.Errorf("timeout. HTTP Status: %v. Hanging?", res.StatusCode)
				}
				return nil, errors.New("timeout. Hanging?")
			}
		}
		retryCounter++
		if rIDReplacer == nil {
			rIDReplacer = makeRequestGUIDReplacer(fullURL)
		}
		fullURL = rIDReplacer.replace()
		glog.V(2).Infof("sleeping %v. to timeout: %v. retrying", sleepTime, totalTimeout)

		await := time.NewTimer(sleepTime)
		select {
		case <-await.C:
			// retry the request
		case <-ctx.Done():
			await.Stop()
			return res, ctx.Err()
		}
	}
	return res, err
}
<|endoftext|>