<commit_before>package inlet_http

import (
	"io/ioutil"
	"net/http"
	"time"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

const (
	REQUEST_TIMEOUT = 30 * time.Second
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPRequestPayloadHook func(*http.Request, []byte, *spirit.Payload)
type InletHTTPResponseHandler func(spirit.Payload, http.ResponseWriter, *http.Request)
type InletHTTPErrorResponseHandler func(error, http.ResponseWriter, *http.Request)
type InletHTTPRequestDecoder func([]byte) (map[string]interface{}, error)

type option func(*InletHTTP)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
	requestDecoder InletHTTPRequestDecoder
	payloadHook    InletHTTPRequestPayloadHook
	timeout        time.Duration
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequestPayloadHook(hook InletHTTPRequestPayloadHook) option {
	return func(f *InletHTTP) {
		f.payloadHook = hook
	}
}

func SetRequestDecoder(decoder InletHTTPRequestDecoder) option {
	return func(f *InletHTTP) {
		f.requestDecoder = decoder
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func SetTimeout(millisecond int64) option {
	return func(f *InletHTTP) {
		f.timeout = time.Duration(millisecond)
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func (p *InletHTTP) Run(handlers ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	if p.requestDecoder == nil {
		panic("request encoder is nil")
	}

	if p.config.Timeout > 0 {
		p.timeout = time.Millisecond * time.Duration(p.config.Timeout)
		p.requester.SetTimeout(p.timeout)
	} else {
		p.timeout = REQUEST_TIMEOUT
	}

	m := martini.Classic()

	if handlers != nil {
		for _, handler := range handlers {
			m.Use(handler)
		}
	}

	m.Use(p.handler)

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{}

	if mapContent, err = p.requestDecoder(binBody); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	payload := spirit.Payload{}

	payload.SetContent(mapContent)

	responseChan := make(chan spirit.Payload)
	errChan := make(chan error)
	defer close(responseChan)
	defer close(errChan)

	var graph spirit.MessageGraph
	if graph, err = p.graphProvider.GetGraph(r); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	if p.payloadHook != nil {
		p.payloadHook(r, binBody, &payload)
	}

	msgId := ""

	msgId, err = p.requester.Request(graph, payload, responseChan, errChan)
	if err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	defer p.requester.OnMessageProcessed(msgId)

	var respPayload spirit.Payload

	select {
	case respPayload = <-responseChan:
		{
			p.writeCookiesAndHeaders(respPayload, w, r)
			p.respHandler(respPayload, w, r)
		}
	case err = <-errChan:
		{
			p.writeCookiesAndHeaders(respPayload, w, r)
			p.errRespHandler(err, w, r)
		}
	case <-time.After(time.Duration(p.timeout)):
		{
			err = ERR_REQUEST_TIMEOUT.New(errors.Params{"msgId": msgId})
			p.errRespHandler(err, w, r)
		}
	}

	return
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) Error(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload *spirit.Payload) {
	p.requester.OnMessageReceived(*payload)
}
<commit_msg>add cookies forworad to next component support<commit_after>package inlet_http

import (
	"io/ioutil"
	"net/http"
	"time"

	"github.com/go-martini/martini"
	"github.com/gogap/errors"
	"github.com/gogap/logs"
	"github.com/gogap/spirit"
)

const (
	REQUEST_TIMEOUT = 30 * time.Second
)

const (
	CTX_HTTP_COOKIES = "CTX_HTTP_COOKIES"
	CTX_HTTP_HEADERS = "CTX_HTTP_HEADERS"

	CMD_HTTP_HEADERS_SET = "CMD_HTTP_HEADERS_SET"
	CMD_HTTP_COOKIES_SET = "CMD_HTTP_COOKIES_SET"
)

type NameValue struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type InletHTTPRequestPayloadHook func(*http.Request, []byte, *spirit.Payload)
type InletHTTPResponseHandler func(spirit.Payload, http.ResponseWriter, *http.Request)
type InletHTTPErrorResponseHandler func(error, http.ResponseWriter, *http.Request)
type InletHTTPRequestDecoder func([]byte) (map[string]interface{}, error)

type option func(*InletHTTP)

type InletHTTP struct {
	config         Config
	requester      Requester
	graphProvider  GraphProvider
	respHandler    InletHTTPResponseHandler
	errRespHandler InletHTTPErrorResponseHandler
	requestDecoder InletHTTPRequestDecoder
	payloadHook    InletHTTPRequestPayloadHook
	timeout        time.Duration
}

func (p *InletHTTP) Option(opts ...option) {
	for _, opt := range opts {
		opt(p)
	}
}

func SetRequestPayloadHook(hook InletHTTPRequestPayloadHook) option {
	return func(f *InletHTTP) {
		f.payloadHook = hook
	}
}

func SetRequestDecoder(decoder InletHTTPRequestDecoder) option {
	return func(f *InletHTTP) {
		f.requestDecoder = decoder
	}
}

func SetRequester(requester Requester) option {
	return func(f *InletHTTP) {
		f.requester = requester
	}
}

func SetHTTPConfig(httpConfig Config) option {
	return func(f *InletHTTP) {
		f.config = httpConfig
	}
}

func SetGraphProvider(graphProvider GraphProvider) option {
	return func(f *InletHTTP) {
		f.graphProvider = graphProvider
	}
}

func SetResponseHandler(handler InletHTTPResponseHandler) option {
	return func(f *InletHTTP) {
		f.respHandler = handler
	}
}

func SetErrorResponseHandler(handler InletHTTPErrorResponseHandler) option {
	return func(f *InletHTTP) {
		f.errRespHandler = handler
	}
}

func SetTimeout(millisecond int64) option {
	return func(f *InletHTTP) {
		f.timeout = time.Duration(millisecond)
	}
}

func NewInletHTTP(opts ...option) *InletHTTP {
	inletHTTP := new(InletHTTP)
	inletHTTP.Option(opts...)

	if inletHTTP.requester == nil {
		inletHTTP.requester = NewClassicRequester()
	}

	return inletHTTP
}

func (p *InletHTTP) Requester() Requester {
	return p.requester
}

func (p *InletHTTP) Run(handlers ...martini.Handler) {
	if p.graphProvider == nil {
		panic("graph provider is nil")
	}

	if p.requester == nil {
		panic("requester is nil")
	}

	if p.respHandler == nil {
		panic("response handler is nil")
	}

	if p.errRespHandler == nil {
		panic("error response handler is nil")
	}

	if p.requestDecoder == nil {
		panic("request encoder is nil")
	}

	if p.config.Timeout > 0 {
		p.timeout = time.Millisecond * time.Duration(p.config.Timeout)
		p.requester.SetTimeout(p.timeout)
	} else {
		p.timeout = REQUEST_TIMEOUT
	}

	m := martini.Classic()

	if handlers != nil {
		for _, handler := range handlers {
			m.Use(handler)
		}
	}

	m.Use(p.handler)

	if p.config.Address != "" {
		m.RunOnAddr(p.config.Address)
	} else {
		m.Run()
	}
}

func (p *InletHTTP) handler(w http.ResponseWriter, r *http.Request) {
	var err error
	var binBody []byte
	if binBody, err = ioutil.ReadAll(r.Body); err != nil {
		err = ERR_READ_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	var mapContent map[string]interface{}

	if mapContent, err = p.requestDecoder(binBody); err != nil {
		err = ERR_UNMARSHAL_HTTP_BODY_FAILED.New(errors.Params{"err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	payload := spirit.Payload{}

	payload.SetContent(mapContent)

	responseChan := make(chan spirit.Payload)
	errChan := make(chan error)
	defer close(responseChan)
	defer close(errChan)

	var graph spirit.MessageGraph
	if graph, err = p.graphProvider.GetGraph(r); err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	cookies := map[string]string{}
	reqCookies := r.Cookies()
	if reqCookies != nil && len(reqCookies) > 0 {
		for _, cookie := range reqCookies {
			cookies[cookie.Name] = cookie.Value
		}
	}

	payload.SetContext(CTX_HTTP_COOKIES, cookies)

	if p.payloadHook != nil {
		p.payloadHook(r, binBody, &payload)
	}

	msgId := ""

	msgId, err = p.requester.Request(graph, payload, responseChan, errChan)
	if err != nil {
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	defer p.requester.OnMessageProcessed(msgId)

	var respPayload spirit.Payload

	select {
	case respPayload = <-responseChan:
		{
			p.writeCookiesAndHeaders(respPayload, w, r)
			p.respHandler(respPayload, w, r)
		}
	case err = <-errChan:
		{
			p.writeCookiesAndHeaders(respPayload, w, r)
			p.errRespHandler(err, w, r)
		}
	case <-time.After(time.Duration(p.timeout)):
		{
			err = ERR_REQUEST_TIMEOUT.New(errors.Params{"msgId": msgId})
			p.errRespHandler(err, w, r)
		}
	}

	return
}

func (p *InletHTTP) writeCookiesAndHeaders(payload spirit.Payload, w http.ResponseWriter, r *http.Request) {
	var err error
	// Cookies
	cmdCookiesSize := payload.GetCommandValueSize(CMD_HTTP_COOKIES_SET)
	cmdCookies := make([]interface{}, cmdCookiesSize)
	for i := 0; i < cmdCookiesSize; i++ {
		cookie := new(http.Cookie)
		cmdCookies[i] = cookie
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_COOKIES_SET, cmdCookies); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": err})
		p.errRespHandler(err, w, r)
		return
	}

	for _, cookie := range cmdCookies {
		if c, ok := cookie.(*http.Cookie); ok {
			c.Domain = p.config.Domain
			c.Path = "/"
			http.SetCookie(w, c)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_COOKIES_SET, "err": "object could not parser to cookies"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}

	cmdHeadersSize := payload.GetCommandValueSize(CMD_HTTP_HEADERS_SET)
	cmdHeaders := make([]interface{}, cmdHeadersSize)
	for i := 0; i < cmdHeadersSize; i++ {
		header := new(NameValue)
		cmdHeaders[i] = header
	}

	if err = payload.GetCommandObjectArray(CMD_HTTP_HEADERS_SET, cmdHeaders); err != nil {
		err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": err})
		logs.Error(err)
		p.errRespHandler(err, w, r)
		return
	}

	for _, header := range cmdHeaders {
		if nv, ok := header.(*NameValue); ok {
			w.Header().Add(nv.Name, nv.Value)
		} else {
			err = ERR_PARSE_COMMAND_TO_OBJECT_FAILED.New(errors.Params{"cmd": CMD_HTTP_HEADERS_SET, "err": "object could not parser to headers"})
			logs.Error(err)
			p.errRespHandler(err, w, r)
			return
		}
	}
}

func (p *InletHTTP) CallBack(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) Error(payload *spirit.Payload) (result interface{}, err error) {
	p.OnMessageResponse(payload)
	return nil, nil
}

func (p *InletHTTP) OnMessageResponse(payload *spirit.Payload) {
	p.requester.OnMessageReceived(*payload)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/remogatto/prettytest"
	"net/http"
	"net/http/httptest"
	"runtime"
	"strconv"
	"testing"
	"time"
)

type testSuite struct {
	prettytest.Suite
}

func TestRunner(t *testing.T) {
	prettytest.RunWithFormatter(
		t,
		new(prettytest.TDDFormatter),
		new(testSuite),
	)
}

func startRace() chan bool {
	useWiimote = false
	ready := make(chan bool)
	go raceFunc(ready)
	<-ready                 // ready to process
	racerChan <- time.Now() // start the race
	return ready
}

func stopRace(ready chan bool) {
	statusChan <- Finished
	<-ready
	for {
		select {
		// need to empty all unprocessed actions left over from test to properly clean up
		case <-racerChan:
		case <-statusChan:
		default:
			return
		}
	}
}

func (t *testSuite) TestLoadRacers() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("test_runners.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 8)
	t.Equal(len(unbibbedEntries), 0)
	mutex.Unlock()

	req, err = uploadFile("test_runners2.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 4)
	t.Equal(len(unbibbedEntries), 4)
	mutex.Unlock()
	req, err = uploadFile("test_runners3.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 0)
	t.Equal(len(unbibbedEntries), 8)
	mutex.Unlock()
}

func (t *testSuite) TestRemoveRacer() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("prizes.json")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadPrizes(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(prizes), 26)
	mutex.Unlock()
	req, err = uploadFile("test_runners_prizes.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	now := time.Now()
	mutex.Lock()
	for x := 0; x < len(bibbedEntries); x++ {
		now = now.Add(time.Second)
		racerChan <- now // have everyone cross the line with different times
	}
	mutex.Unlock()
	for {
		mutex.Lock()
		if len(results) >= len(bibbedEntries) {
			mutex.Unlock()
			break
		}
		mutex.Unlock()
		runtime.Gosched()
	}
	// 8 racers, test the beginning, middle, and end
	mutex.Lock()
	tableTests := []struct {
		place  int
		code   int
		length int
		victim *Result
	}{
		{0, 409, 8, nil},
		{1, 301, 7, results[0]},
		{3, 301, 6, results[3]},
		{6, 301, 5, results[7]},
	}
	mutex.Unlock()
	for _, x := range tableTests {
		req, err := http.NewRequest("post", "", nil)
		req.ParseForm()
		req.Form.Set("place", strconv.Itoa(x.place))
		t.Nil(err)
		w := httptest.NewRecorder()
		mutex.Lock()
		if x.place != 0 {
			t.Equal(results[x.place-1], x.victim)
		}
		mutex.Unlock()
		removeRacer(w, req)
		t.Equal(w.Code, x.code)
		mutex.Lock()
		t.Equal(len(results), x.length)
		mutex.Unlock()
	}
}

func (t *testSuite) TestPrizes() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("prizes.json")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadPrizes(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(prizes), 26)
	mutex.Unlock()

	req, err = uploadFile("test_runners_prizes.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	now := time.Now()
	mutex.Lock()
	for x := 0; x < len(bibbedEntries); x++ {
		now = now.Add(time.Second)
		racerChan <- now // have everyone cross the line with different times
	}
	mutex.Unlock()
	bibslength := 0
	for {
		mutex.Lock()
		if len(results) >= len(bibbedEntries) {
			bibslength = len(bibbedEntries)
			mutex.Unlock()
			break
		}
		mutex.Unlock()
		runtime.Gosched()
	}
	for x := 1; x <= bibslength; x++ {
		req, err = http.NewRequest("post", "", nil)
		req.ParseForm()
		req.Form.Set("next", strconv.Itoa(x))
		req.Form.Set("bib", strconv.Itoa(x))
		t.Nil(err)
		w = httptest.NewRecorder()
		linkBib(w, req)
		t.Equal(w.Code, 301)
	}
	mutex.Lock()
	t.Equal(len(prizes[0].Winners), 1) // men's overall
	t.Equal(prizes[0].Winners[0], results[0])
	t.Equal(len(prizes[2].Winners), 1) // men's u10
	t.Equal(prizes[2].Winners[0], results[6])
	t.Equal(len(prizes[4].Winners), 0)  // men's 11-15
	t.Equal(len(prizes[6].Winners), 0)  // men's 16-20
	t.Equal(len(prizes[8].Winners), 0)  // men's 21-25
	t.Equal(len(prizes[10].Winners), 0) // men's 26-30
	t.Equal(len(prizes[12].Winners), 0) // men's 31-35
	t.Equal(len(prizes[14].Winners), 1) // men's 36-40
	t.Equal(prizes[14].Winners[0], results[1])
	t.Equal(len(prizes[16].Winners), 0) // men's 41-45
	t.Equal(len(prizes[18].Winners), 0) // men's 46-50
	t.Equal(len(prizes[20].Winners), 2) // men's 51-55
	t.Equal(prizes[20].Winners[0], results[3])
	t.Equal(prizes[20].Winners[1], results[4])
	//t.Equal(prizes[20].Winners[1], results[5]) // he didn't place
	t.Equal(len(prizes[22].Winners), 0) // men's 56-60
	t.Equal(len(prizes[24].Winners), 0) // men's 61+

	t.Equal(len(prizes[1].Winners), 1) // women's overall
	t.Equal(prizes[1].Winners[0], results[2])
	t.Equal(len(prizes[3].Winners), 1) // women's u10
	t.Equal(prizes[3].Winners[0], results[7])
	t.Equal(len(prizes[5].Winners), 0)  // women's 11-15
	t.Equal(len(prizes[7].Winners), 0)  // women's 16-20
	t.Equal(len(prizes[9].Winners), 0)  // women's 21-25
	t.Equal(len(prizes[11].Winners), 0) // women's 26-30
	t.Equal(len(prizes[13].Winners), 0) // women's 31-35
	t.Equal(len(prizes[15].Winners), 0) // women's 36-40
	t.Equal(len(prizes[17].Winners), 0) // women's 41-45
	t.Equal(len(prizes[19].Winners), 0) // women's 46-50
	t.Equal(len(prizes[21].Winners), 0) // women's 51-55
	t.Equal(len(prizes[23].Winners), 0) // women's 56-60
	t.Equal(len(prizes[25].Winners), 0) // women's 61+
	mutex.Unlock()
}

func (t *testSuite) TestHumanDuration() {
	duration := HumanDuration(time.Second * 120)
	t.Equal(duration.String(), "00:02:00.00")
	t.Equal(duration.Clock(), "00:02:00")
	duration = HumanDuration(time.Second * 0)
	t.Equal(duration.String(), "00:00:00.00")
	t.Equal(duration.Clock(), "00:00:00")
	duration = HumanDuration(time.Hour)
	t.Equal(duration.String(), "01:00:00.00")
	t.Equal(duration.Clock(), "01:00:00")
	duration = HumanDuration(time.Second * 5)
	t.Equal(duration.String(), "00:00:05.00")
	t.Equal(duration.Clock(), "00:00:05")
	duration = HumanDuration(time.Second * 50)
	t.Equal(duration.String(), "00:00:50.00")
	t.Equal(duration.Clock(), "00:00:50")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5)
	t.Equal(duration.String(), "01:45:05.00")
	t.Equal(duration.Clock(), "01:45:05")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5 + time.Millisecond*104)
	t.Equal(duration.String(), "01:45:05.10")
	t.Equal(duration.Clock(), "01:45:05")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5 + time.Millisecond*907)
	t.Equal(duration.String(), "01:45:05.91")
	t.Equal(duration.Clock(), "01:45:05")
}
<commit_msg>modified the test to use the "old" results<commit_after>package main

import (
	"github.com/remogatto/prettytest"
	"net/http"
	"net/http/httptest"
	"runtime"
	"strconv"
	"testing"
	"time"
)

type testSuite struct {
	prettytest.Suite
}

func TestRunner(t *testing.T) {
	prettytest.RunWithFormatter(
		t,
		new(prettytest.TDDFormatter),
		new(testSuite),
	)
}

func startRace() chan bool {
	useWiimote = false
	ready := make(chan bool)
	go raceFunc(ready)
	<-ready                 // ready to process
	racerChan <- time.Now() // start the race
	return ready
}

func stopRace(ready chan bool) {
	statusChan <- Finished
	<-ready
	for {
		select {
		// need to empty all unprocessed actions left over from test to properly clean up
		case <-racerChan:
		case <-statusChan:
		default:
			return
		}
	}
}

func (t *testSuite) TestLoadRacers() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("test_runners.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 8)
	t.Equal(len(unbibbedEntries), 0)
	mutex.Unlock()

	req, err = uploadFile("test_runners2.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 4)
	t.Equal(len(unbibbedEntries), 4)
	mutex.Unlock()
	req, err = uploadFile("test_runners3.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(bibbedEntries), 0)
	t.Equal(len(unbibbedEntries), 8)
	mutex.Unlock()
}

func (t *testSuite) TestRemoveRacer() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("prizes.json")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadPrizes(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(prizes), 26)
	mutex.Unlock()
	req, err = uploadFile("test_runners_prizes.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	now := time.Now()
	mutex.Lock()
	for x := 0; x < len(bibbedEntries); x++ {
		now = now.Add(time.Second)
		racerChan <- now // have everyone cross the line with different times
	}
	mutex.Unlock()
	for {
		mutex.Lock()
		if len(results) >= len(bibbedEntries) {
			mutex.Unlock()
			break
		}
		mutex.Unlock()
		runtime.Gosched()
	}
	// 8 racers, test the beginning, middle, and end
	mutex.Lock()
	tableTests := []struct {
		place  int
		code   int
		length int
		victim *Result
	}{
		{0, 409, 8, nil},
		{1, 301, 7, results[0]},
		{3, 301, 6, results[3]},
		{6, 301, 5, results[7]},
	}
	mutex.Unlock()
	for _, x := range tableTests {
		req, err := http.NewRequest("post", "", nil)
		req.ParseForm()
		req.Form.Set("place", strconv.Itoa(x.place))
		t.Nil(err)
		w := httptest.NewRecorder()
		mutex.Lock()
		if x.place != 0 {
			t.Equal(results[x.place-1], x.victim)
		}
		mutex.Unlock()
		removeRacer(w, req)
		t.Equal(w.Code, x.code)
		mutex.Lock()
		t.Equal(len(results), x.length)
		mutex.Unlock()
	}
}

func (t *testSuite) TestPrizes() {
	defer stopRace(startRace())
	// race is started, load the racers
	req, err := uploadFile("test_prizes.json")
	t.Nil(err)
	t.Not(t.Nil(req))
	w := httptest.NewRecorder()
	uploadPrizes(w, req)
	t.Equal(w.Code, 301)
	mutex.Lock()
	t.Equal(len(prizes), 26)
	mutex.Unlock()

	req, err = uploadFile("test_runners_prizes.csv")
	t.Nil(err)
	t.Not(t.Nil(req))
	w = httptest.NewRecorder()
	uploadRacers(w, req)
	t.Equal(w.Code, 301)
	now := time.Now()
	mutex.Lock()
	for x := 0; x < len(bibbedEntries); x++ {
		now = now.Add(time.Second)
		racerChan <- now // have everyone cross the line with different times
	}
	mutex.Unlock()
	bibslength := 0
	for {
		mutex.Lock()
		if len(results) >= len(bibbedEntries) {
			bibslength = len(bibbedEntries)
			mutex.Unlock()
			break
		}
		mutex.Unlock()
		runtime.Gosched()
	}
	for x := 1; x <= bibslength; x++ {
		req, err = http.NewRequest("post", "", nil)
		req.ParseForm()
		req.Form.Set("next", strconv.Itoa(x))
		req.Form.Set("bib", strconv.Itoa(x))
		t.Nil(err)
		w = httptest.NewRecorder()
		linkBib(w, req)
		t.Equal(w.Code, 301)
	}
	mutex.Lock()
	t.Equal(len(prizes[0].Winners), 1) // men's overall
	t.Equal(prizes[0].Winners[0], results[0])
	t.Equal(len(prizes[2].Winners), 1) // men's u10
	t.Equal(prizes[2].Winners[0], results[6])
	t.Equal(len(prizes[4].Winners), 0)  // men's 11-15
	t.Equal(len(prizes[6].Winners), 0)  // men's 16-20
	t.Equal(len(prizes[8].Winners), 0)  // men's 21-25
	t.Equal(len(prizes[10].Winners), 0) // men's 26-30
	t.Equal(len(prizes[12].Winners), 0) // men's 31-35
	t.Equal(len(prizes[14].Winners), 1) // men's 36-40
	t.Equal(prizes[14].Winners[0], results[1])
	t.Equal(len(prizes[16].Winners), 0) // men's 41-45
	t.Equal(len(prizes[18].Winners), 0) // men's 46-50
	t.Equal(len(prizes[20].Winners), 2) // men's 51-55
	t.Equal(prizes[20].Winners[0], results[3])
	t.Equal(prizes[20].Winners[1], results[4])
	//t.Equal(prizes[20].Winners[1], results[5]) // he didn't place
	t.Equal(len(prizes[22].Winners), 0) // men's 56-60
	t.Equal(len(prizes[24].Winners), 0) // men's 61+

	t.Equal(len(prizes[1].Winners), 1) // women's overall
	t.Equal(prizes[1].Winners[0], results[2])
	t.Equal(len(prizes[3].Winners), 1) // women's u10
	t.Equal(prizes[3].Winners[0], results[7])
	t.Equal(len(prizes[5].Winners), 0)  // women's 11-15
	t.Equal(len(prizes[7].Winners), 0)  // women's 16-20
	t.Equal(len(prizes[9].Winners), 0)  // women's 21-25
	t.Equal(len(prizes[11].Winners), 0) // women's 26-30
	t.Equal(len(prizes[13].Winners), 0) // women's 31-35
	t.Equal(len(prizes[15].Winners), 0) // women's 36-40
	t.Equal(len(prizes[17].Winners), 0) // women's 41-45
	t.Equal(len(prizes[19].Winners), 0) // women's 46-50
	t.Equal(len(prizes[21].Winners), 0) // women's 51-55
	t.Equal(len(prizes[23].Winners), 0) // women's 56-60
	t.Equal(len(prizes[25].Winners), 0) // women's 61+
	mutex.Unlock()
}

func (t *testSuite) TestHumanDuration() {
	duration := HumanDuration(time.Second * 120)
	t.Equal(duration.String(), "00:02:00.00")
	t.Equal(duration.Clock(), "00:02:00")
	duration = HumanDuration(time.Second * 0)
	t.Equal(duration.String(), "00:00:00.00")
	t.Equal(duration.Clock(), "00:00:00")
	duration = HumanDuration(time.Hour)
	t.Equal(duration.String(), "01:00:00.00")
	t.Equal(duration.Clock(), "01:00:00")
	duration = HumanDuration(time.Second * 5)
	t.Equal(duration.String(), "00:00:05.00")
	t.Equal(duration.Clock(), "00:00:05")
	duration = HumanDuration(time.Second * 50)
	t.Equal(duration.String(), "00:00:50.00")
	t.Equal(duration.Clock(), "00:00:50")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5)
	t.Equal(duration.String(), "01:45:05.00")
	t.Equal(duration.Clock(), "01:45:05")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5 + time.Millisecond*104)
	t.Equal(duration.String(), "01:45:05.10")
	t.Equal(duration.Clock(), "01:45:05")
	duration = HumanDuration(time.Hour + time.Minute*45 + time.Second*5 + time.Millisecond*907)
	t.Equal(duration.String(), "01:45:05.91")
	t.Equal(duration.Clock(), "01:45:05")
}
<|endoftext|>


<commit_before>package raftgorums

import (
	"fmt"
	"log"
	"net"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	gorums "github.com/relab/raft/raftgorums/gorumspb"
	pb "github.com/relab/raft/raftgorums/raftpb"
)

// Node ties an instance of Raft to the network.
type Node struct {
	Raft *Raft

	server *grpc.Server

	lis   net.Listener
	peers []string

	conf *gorums.Configuration
}

// NewNode returns a Node with an instance of Raft given the configuration.
func NewNode(lis net.Listener, cfg *Config) *Node {
	peers := make([]string, len(cfg.Nodes))
	// We don't want to mutate cfg.Nodes.
	copy(peers, cfg.Nodes)

	id := cfg.ID
	// Exclude self.
	peers = append(peers[:id-1], peers[id:]...)

	n := &Node{
		Raft:   NewRaft(cfg),
		server: grpc.NewServer(),
		lis:    lis,
		peers:  peers,
	}

	gorums.RegisterRaftServer(n.server, n)

	return n
}

// Run start listening for incoming messages, and delivers outgoing messages.
func (n *Node) Run() (ferr error) {
	go func() {
		ferr = n.server.Serve(n.lis)
	}()

	opts := []gorums.ManagerOption{
		gorums.WithGrpcDialOptions(
			grpc.WithBlock(),
			grpc.WithInsecure(),
			grpc.WithTimeout(TCPConnect*time.Millisecond)),
		// TODO WithLogger?
	}

	mgr, err := gorums.NewManager(n.peers, opts...)

	if err != nil {
		return err
	}

	n.conf, err = mgr.NewConfiguration(mgr.NodeIDs(), NewQuorumSpec(len(n.peers)+1))

	if err != nil {
		return err
	}

	go n.Raft.Run()

	for {
		rvreqout := n.Raft.RequestVoteRequestChan()
		aereqout := n.Raft.AppendEntriesRequestChan()

		select {
		case req := <-rvreqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.RequestVote(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("RequestVote failed = %v", err))

			}

			if res.RequestVoteResponse == nil {
				continue
			}

			n.Raft.HandleRequestVoteResponse(res.RequestVoteResponse)
		case req := <-aereqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.AppendEntries(ctx, req)

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("AppendEntries failed = %v", err))

				if res.AppendEntriesResponse == nil {
					continue
				}
			}

			// Cancel on abort.
			if !res.AppendEntriesResponse.Success {
				cancel()
			}

			n.Raft.HandleAppendEntriesResponse(res.AppendEntriesResponse)
		}
	}
}

// RequestVote implements gorums.RaftServer.
func (n *Node) RequestVote(ctx context.Context, req *pb.RequestVoteRequest) (*pb.RequestVoteResponse, error) {
	return n.Raft.HandleRequestVoteRequest(req), nil
}

// AppendEntries implements gorums.RaftServer.
func (n *Node) AppendEntries(ctx context.Context, req *pb.AppendEntriesRequest) (*pb.AppendEntriesResponse, error) {
	return n.Raft.HandleAppendEntriesRequest(req), nil
}
<commit_msg>raftgorums/node.go: Take grpc.Server as argument<commit_after>package raftgorums

import (
	"fmt"
	"log"
	"net"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/grpc"

	gorums "github.com/relab/raft/raftgorums/gorumspb"
	pb "github.com/relab/raft/raftgorums/raftpb"
)

// Node ties an instance of Raft to the network.
type Node struct {
	Raft *Raft

	server *grpc.Server
	lis    net.Listener

	peers []string

	conf *gorums.Configuration
}

// NewNode returns a Node with an instance of Raft given the configuration.
func NewNode(server *grpc.Server, lis net.Listener, cfg *Config) *Node {
	peers := make([]string, len(cfg.Nodes))
	// We don't want to mutate cfg.Nodes.
	copy(peers, cfg.Nodes)

	id := cfg.ID
	// Exclude self.
	peers = append(peers[:id-1], peers[id:]...)

	n := &Node{
		Raft:   NewRaft(cfg),
		server: server,
		lis:    lis,
		peers:  peers,
	}

	gorums.RegisterRaftServer(n.server, n)

	return n
}

// Run start listening for incoming messages, and delivers outgoing messages.
func (n *Node) Run() (ferr error) {
	go func() {
		ferr = n.server.Serve(n.lis)
	}()

	opts := []gorums.ManagerOption{
		gorums.WithGrpcDialOptions(
			grpc.WithBlock(),
			grpc.WithInsecure(),
			grpc.WithTimeout(TCPConnect*time.Millisecond)),
		// TODO WithLogger?
	}

	mgr, err := gorums.NewManager(n.peers, opts...)

	if err != nil {
		return err
	}

	n.conf, err = mgr.NewConfiguration(mgr.NodeIDs(), NewQuorumSpec(len(n.peers)+1))

	if err != nil {
		return err
	}

	go n.Raft.Run()

	for {
		rvreqout := n.Raft.RequestVoteRequestChan()
		aereqout := n.Raft.AppendEntriesRequestChan()

		select {
		case req := <-rvreqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.RequestVote(ctx, req)
			cancel()

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("RequestVote failed = %v", err))

			}

			if res.RequestVoteResponse == nil {
				continue
			}

			n.Raft.HandleRequestVoteResponse(res.RequestVoteResponse)
		case req := <-aereqout:
			ctx, cancel := context.WithTimeout(context.Background(), TCPHeartbeat*time.Millisecond)
			res, err := n.conf.AppendEntries(ctx, req)

			if err != nil {
				// TODO Better error message.
				log.Println(fmt.Sprintf("AppendEntries failed = %v", err))

				if res.AppendEntriesResponse == nil {
					continue
				}
			}

			// Cancel on abort.
			if !res.AppendEntriesResponse.Success {
				cancel()
			}

			n.Raft.HandleAppendEntriesResponse(res.AppendEntriesResponse)
		}
	}
}

// RequestVote implements gorums.RaftServer.
func (n *Node) RequestVote(ctx context.Context, req *pb.RequestVoteRequest) (*pb.RequestVoteResponse, error) {
	return n.Raft.HandleRequestVoteRequest(req), nil
}

// AppendEntries implements gorums.RaftServer.
func (n *Node) AppendEntries(ctx context.Context, req *pb.AppendEntriesRequest) (*pb.AppendEntriesResponse, error) {
	return n.Raft.HandleAppendEntriesRequest(req), nil
}
<|endoftext|>


<commit_before>package DUP

import (
	"github.com/stretchr/testify/assert"
	"log"
	"testing"
	"time"
)

// Get clients for the test
func GetClients(t *testing.T, num int, headName string) []client {
	factory := ClientFactory{}

	// Create clients
	clients := make([]client, num)
	clientNames := make([]string, num)
	for i := 0; i < num; i++ {
		clients[i] = factory.NewClient()

		tcpAddr := clients[i].node.GetTCPAddr()
		clientNames[i] = tcpAddr.String()
		log.Println("[DEBUG] Created client", tcpAddr.String())
	}

	// Create channel messengers
	resolverMap := make(map[string]chan Message)
	messengers := GetChannelMessengers(clientNames, resolverMap)

	// Attach chennel messengers to clients
	for i := 0; i < num; i++ {
		clients[i].messenger = messengers[i]
	}

	return clients

}

func TestInteg_ChannelMessenger(t *testing.T) {
	assert := assert.New(t)

	timeout := time.AfterFunc(2000*time.Millisecond, func() {
		panic("TestInteg_ChannelMessenger timed out!")
	})
	defer timeout.Stop()

	headName := "0.0.0.0:7946"
	clients := GetClients(t, 3, headName)

	for i := range clients {
		clients[i].Start()
	}

	clients[1].Join(headName)
	clients[2].Join(headName)
	num_clients := clients[0].NumMembers()
	assert.Equal(num_clients, 3, "Incorrect num of initial clients")

	// Test tracking of active nodes
	assert.Equal(1, clients[0].NumActiveMembers(), "bad initial active members")
	assert.Equal(0, clients[1].NumActiveMembers(), "Not purging active after join")

	// Test tracking of pending nodes
	assert.Equal(2, len(clients[0].pendingMembers), "Not tracking pending members")

	num_active := clients[0].UpdateActiveMembers()
	assert.Equal(3, num_active, "invlaid new number of active members.")

	clients[1].WaitActive()
	clients[2].WaitActive()
	assert.Equal(3, clients[1].NumActiveMembers(), "invlaid new number of active members.")
	assert.Equal(3, clients[2].NumActiveMembers(), "invlaid new number of active members.")

	assert.True(clients[1].IsActive())
	assert.True(clients[2].IsActive())

	clients[1].Close()
	time.Sleep(time.Millisecond * 50)
	assert.Equal(2, clients[0].NumActiveMembers(), "Didn't handle client leaving")
	assert.Equal(2, clients[2].NumActiveMembers(), "Didn't handle client leaving")

	t.Error("Not implemented.")

}
<commit_msg>Removed not implemented error from integration test.<commit_after>package DUP

import (
	"github.com/stretchr/testify/assert"
	"log"
	"testing"
	"time"
)

// Get clients for the test
func GetClients(t *testing.T, num int, headName string) []client {
	factory := ClientFactory{}

	// Create clients
	clients := make([]client, num)
	clientNames := make([]string, num)
	for i := 0; i < num; i++ {
		clients[i] = factory.NewClient()

		tcpAddr := clients[i].node.GetTCPAddr()
		clientNames[i] = tcpAddr.String()
		log.Println("[DEBUG] Created client", tcpAddr.String())
	}

	// Create channel messengers
	resolverMap := make(map[string]chan Message)
	messengers := GetChannelMessengers(clientNames, resolverMap)

	// Attach chennel messengers to clients
	for i := 0; i < num; i++ {
		clients[i].messenger = messengers[i]
	}

	return clients

}

func TestInteg_ChannelMessenger(t *testing.T) {
	assert := assert.New(t)

	timeout := time.AfterFunc(2000*time.Millisecond, func() {
		panic("TestInteg_ChannelMessenger timed out!")
	})
	defer timeout.Stop()

	headName := "0.0.0.0:7946"
	clients := GetClients(t, 3, headName)

	for i := range clients {
		clients[i].Start()
	}

	clients[1].Join(headName)
	clients[2].Join(headName)
	num_clients := clients[0].NumMembers()
	assert.Equal(num_clients, 3, "Incorrect num of initial clients")

	// Test tracking of active nodes
	assert.Equal(1, clients[0].NumActiveMembers(), "bad initial active members")
	assert.Equal(0, clients[1].NumActiveMembers(), "Not purging active after join")

	// Test tracking of pending nodes
	assert.Equal(2, len(clients[0].pendingMembers), "Not tracking pending members")

	num_active := clients[0].UpdateActiveMembers()
	assert.Equal(3, num_active, "invlaid new number of active members.")

	clients[1].WaitActive()
	clients[2].WaitActive()
	assert.Equal(3, clients[1].NumActiveMembers(), "invlaid new number of active members.")
	assert.Equal(3, clients[2].NumActiveMembers(), "invlaid new number of active members.")

	assert.True(clients[1].IsActive())
	assert.True(clients[2].IsActive())

	clients[1].Close()
	time.Sleep(time.Millisecond * 50)
	assert.Equal(2, clients[0].NumActiveMembers(), "Didn't handle client leaving")
	assert.Equal(2, clients[2].NumActiveMembers(), "Didn't handle client leaving")

}
<|endoftext|>


<commit_before>package irMagician

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"time"

	"github.com/tarm/goserial"
)

type Serial struct {
	SerialObject io.ReadWriteCloser
}

type IrData struct {
	Data       []int  `json:"data"`
	Format     string `json:"format"`
	Freq       int    `json:"freq"`
	Postscaler int    `json:"postscaler"`
}

const (
	sleepTime = 10
)

func New(name string) (*Serial, error) {
	c := &serial.Config{
		Name: name,
		Baud: 9600}
	s, err := serial.OpenPort(c)
	if err != nil {
		return &Serial{}, err
	}
	return &Serial{SerialObject: s}, nil
}

func (ser *Serial) writeSerial(data string) error {
	_, err := ser.SerialObject.Write([]byte(data))
	if err != nil {
		return err
	}
	return nil
}

func (ser *Serial) readSerial() (string, error) {
	buf := make([]byte, 128)
	n, err := ser.SerialObject.Read(buf)
	if err != nil {
		return "", err
	}
	return string(buf[:n]), nil
}

func (ser *Serial) bankSet(bank int) {
	var irCommand string
	irCommand = fmt.Sprintf("b,%d\r\n", bank)
	ser.writeSerial(irCommand)
	time.Sleep(sleepTime * time.Millisecond)
}

// Capture the IR Signal
func (ser *Serial) CaptureSignal() error {
	irCommand := "c\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(3000 * time.Millisecond)
	_, err := ser.readSerial()
	if err != nil {
		return err
	}

	return nil
}

// Play the IR Signal
func (ser *Serial) Play() {
	irCommand := "p\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(sleepTime * time.Millisecond)
	ser.readSerial()
}

// Get the Temperature
func (ser *Serial) GetTemperature() (string, error) {
	irCommand := "t\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(100 * time.Millisecond)
	res, err := ser.readSerial()
	if err != nil {
		return "Cannot read data", err
	}

	temp := strings.Split(res, "\r\n")[0]
	tf64, err := strconv.ParseFloat(temp, 64)
	if err != nil {
		return "", errors.New("Cannot get temperature")
	}
	degree := ((5.0 / 1024.0 * tf64) - 0.4) / (19.53 / 1000.0)

	return fmt.Sprintf("%.1f", degree), nil
}

// Send the IR Signal from Local Data
func (ser *Serial) SendIrData(filepath string) error {
	var irData IrData
	var irCommand string

	jsonString, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}
	err = json.Unmarshal(jsonString, &irData)
	if err != nil {
		return err
	}

	recNumber := len(irData.Data)
	postScaler := irData.Postscaler

	// Data length setting
	irCommand = fmt.Sprintf("n,%d\r\n", recNumber)
	ser.writeSerial(irCommand)
	ser.readSerial()
	time.Sleep(sleepTime * time.Millisecond)

	// Post scale setting
	irCommand = fmt.Sprintf("k,%d\r\n", postScaler)
	ser.writeSerial(irCommand)
	ser.readSerial()
	time.Sleep(sleepTime * time.Millisecond)

	// Bank & Data setting
	for n := 0; n < recNumber; n++ {
		// Bank set
		bank := n / 64
		pos := n % 64
		if pos == 0 {
			ser.bankSet(bank)
		}
		// Data set
		irCommand = fmt.Sprintf("w,%d,%d\r\n", pos, irData.Data[n])
		ser.writeSerial(irCommand)
		time.Sleep(sleepTime * time.Millisecond)
	}

	ser.Play()

	return nil
}

// Save the IR Signal in Local
func (ser *Serial) SaveIrData(filepath string) error {
	var irCommand string

	// Get Capture Data Size
	ser.writeSerial("i,1\r\n")
	time.Sleep(sleepTime * time.Millisecond)
	sSize, err := ser.readSerial()
	if err != nil {
		return err
	}
	sSize = strings.Split(sSize, "\r\n")[0]
	dSize, err := strconv.ParseInt(sSize, 16, 0)
	if err != nil {
		return err
	}
	data := make([]int, int(dSize))

	// Get Postscaler value
	ser.writeSerial("i,6\r\n")
	time.Sleep(sleepTime * time.Millisecond)
	sPostScaler, err := ser.readSerial()
	if err != nil {
		return err
	}
	sPostScaler = strings.Split(sPostScaler, "\r\n")[0]
	postScaler, err := strconv.Atoi(sPostScaler)
	if err != nil {
		return err
	}

	// Bank & Data setting
	for n := 0; n < int(dSize); n++ {
		// Bank set
		bank := n / 64
		pos := n % 64
		if pos == 0 {
			ser.bankSet(bank)
		}

		// Dump Memory
		irCommand = fmt.Sprintf("d,%d\r\n", pos)
		ser.writeSerial(irCommand)
		time.Sleep(sleepTime * time.Millisecond)
		sMem, err := ser.readSerial()
		if err != nil {
			return err
		}
		sMem = strings.Split(sMem, " ")[0]
		mem, err := strconv.ParseInt(sMem, 16, 0)
		if err != nil {
			return err
		}
		data[n] = int(mem)
	}

	jsonData, err := json.Marshal(&IrData{Data: data, Format: "raw", Freq: 38, Postscaler: postScaler})
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(filepath, jsonData, 0644); err != nil {
		return err
	}

	return nil
}
<commit_msg>fix CaptureSignal func<commit_after>package irMagician

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
	"time"

	"github.com/tarm/goserial"
)

type Serial struct {
	SerialObject io.ReadWriteCloser
}

type IrData struct {
	Data       []int  `json:"data"`
	Format     string `json:"format"`
	Freq       int    `json:"freq"`
	Postscaler int    `json:"postscaler"`
}

const (
	sleepTime = 10
)

func New(name string) (*Serial, error) {
	c := &serial.Config{
		Name: name,
		Baud: 9600}
	s, err := serial.OpenPort(c)
	if err != nil {
		return &Serial{}, err
	}
	return &Serial{SerialObject: s}, nil
}

func (ser *Serial) writeSerial(data string) error {
	_, err := ser.SerialObject.Write([]byte(data))
	if err != nil {
		return err
	}
	return nil
}

func (ser *Serial) readSerial() (string, error) {
	buf := make([]byte, 128)
	n, err := ser.SerialObject.Read(buf)
	if err != nil {
		return "", err
	}
	return string(buf[:n]), nil
}

func (ser *Serial) bankSet(bank int) {
	var irCommand string
	irCommand = fmt.Sprintf("b,%d\r\n", bank)
	ser.writeSerial(irCommand)
	time.Sleep(sleepTime * time.Millisecond)
}

// Capture the IR Signal
func (ser *Serial) CaptureSignal() error {
	irCommand := "c\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(3000 * time.Millisecond)
	res, err := ser.readSerial()
	if err != nil {
		return err
	}

	res = strings.Split(res, "\r\n")[0]
	res = strings.Replace(res, "... ", "", 1)
	if _, err := strconv.Atoi(res); err != nil {
		return errors.New(res)
	}

	return nil
}

// Play the IR Signal
func (ser *Serial) Play() {
	irCommand := "p\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(sleepTime * time.Millisecond)
	ser.readSerial()
}

// Get the Temperature
func (ser *Serial) GetTemperature() (string, error) {
	irCommand := "t\r\n"
	ser.writeSerial(irCommand)
	time.Sleep(100 * time.Millisecond)
	res, err := ser.readSerial()
	if err != nil {
		return "", err
	}

	res = strings.Split(res, "\r\n")[0]
	temp, err := strconv.ParseFloat(res, 64)
	if err != nil {
		return "", errors.New("Cannot get temperature")
	}
	degree := ((5.0 / 1024.0 * temp) - 0.4) / (19.53 / 1000.0)

	return fmt.Sprintf("%.1f", degree), nil
}

// Send the IR Signal from Local Data
func (ser *Serial) SendIrData(filepath string) error {
	var irData IrData
	var irCommand string

	jsonString, err := ioutil.ReadFile(filepath)
	if err != nil {
		return err
	}
	err = json.Unmarshal(jsonString, &irData)
	if err != nil {
		return err
	}

	recNumber := len(irData.Data)
	postScaler := irData.Postscaler

	// Data length setting
	irCommand = fmt.Sprintf("n,%d\r\n", recNumber)
	ser.writeSerial(irCommand)
	ser.readSerial()
	time.Sleep(sleepTime * time.Millisecond)

	// Post scale setting
	irCommand = fmt.Sprintf("k,%d\r\n", postScaler)
	ser.writeSerial(irCommand)
	ser.readSerial()
	time.Sleep(sleepTime * time.Millisecond)

	// Bank & Data setting
	for n := 0; n < recNumber; n++ {
		// Bank set
		bank := n / 64
		pos := n % 64
		if pos == 0 {
			ser.bankSet(bank)
		}
		// Data set
		irCommand = fmt.Sprintf("w,%d,%d\r\n", pos, irData.Data[n])
		ser.writeSerial(irCommand)
		time.Sleep(sleepTime * time.Millisecond)
	}

	ser.Play()

	return nil
}

// Save the IR Signal in Local
func (ser *Serial) SaveIrData(filepath string) error {
	var irCommand string

	// Get Capture Data Size
	ser.writeSerial("i,1\r\n")
	time.Sleep(sleepTime * time.Millisecond)
	sSize, err := ser.readSerial()
	if err != nil {
		return err
	}
	sSize = strings.Split(sSize, "\r\n")[0]
	dSize, err := strconv.ParseInt(sSize, 16, 0)
	if err != nil {
		return err
	}
	data := make([]int, int(dSize))

	// Get Postscaler value
	ser.writeSerial("i,6\r\n")
	time.Sleep(sleepTime * time.Millisecond)
	sPostScaler, err := ser.readSerial()
	if err != nil {
		return err
	}
	sPostScaler = strings.Split(sPostScaler, "\r\n")[0]
	postScaler, err := strconv.Atoi(sPostScaler)
	if err != nil {
		return err
	}

	// Bank & Data setting
	for n := 0; n < int(dSize); n++ {
		// Bank set
		bank := n / 64
		pos := n % 64
		if pos == 0 {
			ser.bankSet(bank)
		}

		// Dump Memory
		irCommand = fmt.Sprintf("d,%d\r\n", pos)
		ser.writeSerial(irCommand)
		time.Sleep(sleepTime * time.Millisecond)
		sMem, err := ser.readSerial()
		if err != nil {
			return err
		}
		sMem = strings.Split(sMem, " ")[0]
		mem, err := strconv.ParseInt(sMem, 16, 0)
		if err != nil {
			return err
		}
		data[n] = int(mem)
	}

	jsonData, err := json.Marshal(&IrData{Data: data, Format: "raw", Freq: 38, Postscaler: postScaler})
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(filepath, jsonData, 0644); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package rogue

import (
	"image/png"
	"math"
	"math/rand"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/martinlindhe/roguer/rollingparticle"
	"github.com/ojrac/opensimplex-go"
)

var island *Island // singelton

// NewIsland inits the singelton
func NewIsland() *Island {

	// XXX load existing world from disk
	seed := int64(666666)
	log.Infof("Generating island with seed %d ...", seed)
	island = generateIsland(seed, 220, 140)

	island.spawnGravel()
	island.spawnTrees()

	island.fillWithCritters()
	log.Info("Done generating island")

	// store island to disk as png
	islandColImage := island.ColoredHeightMapAsImage()
	//islandColImageName := fmt.Sprintf("public/img/islands/%d.png", seed)
	islandColImageName := "public/img/islands/current.png"
	islandColImgFile, err := os.Create(islandColImageName)
	if err != nil {
		panic(err)
	}
	png.Encode(islandColImgFile, islandColImage)
	/*
		islandImage := island.HeightMapAsImage()
		islandImgFile, _ := os.Create("island.png")
		png.Encode(islandImgFile, islandImage)
	*/
	return island
}

// create some small rocks spread out over surface
func (i *Island) spawnGravel() {
	for y := 0; y < i.Height; y++ {
		for x := 0; x < i.Width; x++ {
			pos := Point{X: float64(x), Y: float64(y)}
			if i.isAboveWater(pos) {
				// add 1-3 items
				cnt := 1 + rand.Intn(3)

				for i := 0; i < cnt; i++ {
					name := ""
					// XXX make it less likely to place a large rock
					switch rand.Intn(3) {
					case 0:
						name = "small rock"
					case 1:
						name = "medium rock"
					case 2:
						name = "large rock"
					default:
						panic("")
					}
					island.addNpcFromName(name, pos)
				}
			}
		}
	}
}

// create trees all over the island
func (i *Island) spawnTrees() {

	cnt := 0
	for y := 0; y < i.Height; y++ {
		for x := 0; x < i.Width; x++ {
			pos := Point{X: float64(x), Y: float64(y)}
			if i.isAboveWater(pos) {
				// add one tree in 3% of the time
				if rand.Intn(100) < 3 {
					name := ""
					// XXX make it less likely to place oak trees ?
					switch rand.Intn(3) {
					case 0:
						name = "oak tree"
					case 1:
						name = "apple tree"
					case 2:
						name = "birch tree"
					default:
						panic("")
					}
					island.addNpcFromName(name, pos)
					cnt++
				}
			}
		}
	}
	log.Printf("spawned %d trees", cnt)
}

// generate critters based on data file
func (i *Island) fillWithCritters() {

	dwarf := i.getNpcSpecFromRace("dwarf")
	for n := 0; n < 5; n++ {
		i.addNpcFromSpec(dwarf, i.RandomPointAboveWater())
	}

	rabbit := i.getNpcSpecFromRace("rabbit")
	for n := 0; n < 5; n++ {
		i.addNpcFromSpec(rabbit, i.RandomPointAboveWater())
	}
}

func generateIsland(seed int64, width int, height int) *Island {

	particleLength := 8
	innerBlur := 0.85
	outerBlur := 0.60
	roller := rollingparticle.New(seed, width, height, particleLength, innerBlur, outerBlur)

	/*
		rollerImage := slice2DAsImage(&roller, width, height)
		rollerImgFile, _ := os.Create("roller.png")
		png.Encode(rollerImgFile, rollerImage)
	*/

	m := make2DIntSlice(width, height)

	noise := opensimplex.NewWithSeed(seed)

	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {

			// combine some sizes of noise
			fBig := noise.Eval2(float64(x)*0.005, float64(y)*0.005)
			fMid := noise.Eval2(float64(x)*0.01, float64(y)*0.01)
			fSmall := noise.Eval2(float64(x)*0.02, float64(y)*0.02)
			fMini := noise.Eval2(float64(x)*0.04, float64(y)*0.04)

			f := (fBig + fMid + fSmall + fMini) / 4

			// scale from -1.0-1.0 to 0.0-1.0
			f = (f + 1.0) / 2.0

			// scale from 0.0-1.0 to 0-255
			b := int(0)
			if f == 1.0 {
				b = 255
			} else {
				b = int(math.Floor(f * 256.0))
			}

			// combine with rolling particle
			opacity := 0.5
			b = int((1-opacity)*float64(b) + opacity*float64(roller[y][x]))

			m[y][x] = b
		}
	}

	is := &Island{
		Width:     width,
		Height:    height,
		Seed:      seed,
		HeightMap: m}

	// load all possible world items, NPC:s and actions
	is.npcSpecs, _ = parseObjectsDefinition("data/objs.yml")
	is.actionSpecs, _ = parseActionsDefinition("data/actions.yml")

	return is
}
<commit_msg>worldgen: reduce amount of rocks<commit_after>package rogue

import (
	"image/png"
	"math"
	"math/rand"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/martinlindhe/roguer/rollingparticle"
	"github.com/ojrac/opensimplex-go"
)

var island *Island // singelton

// NewIsland inits the singelton
func NewIsland() *Island {

	// XXX load existing world from disk
	seed := int64(666666)
	log.Infof("Generating island with seed %d ...", seed)
	island = generateIsland(seed, 220, 140)

	island.spawnGravel()
	island.spawnTrees()

	island.fillWithCritters()
	log.Info("Done generating island")

	// store island to disk as png
	islandColImage := island.ColoredHeightMapAsImage()
	//islandColImageName := fmt.Sprintf("public/img/islands/%d.png", seed)
	islandColImageName := "public/img/islands/current.png"
	islandColImgFile, err := os.Create(islandColImageName)
	if err != nil {
		panic(err)
	}
	png.Encode(islandColImgFile, islandColImage)
	/*
		islandImage := island.HeightMapAsImage()
		islandImgFile, _ := os.Create("island.png")
		png.Encode(islandImgFile, islandImage)
	*/
	return island
}

// create some small rocks spread out over surface
func (i *Island) spawnGravel() {
	for y := 0; y < i.Height; y++ {
		for x := 0; x < i.Width; x++ {
			pos := Point{X: float64(x), Y: float64(y)}
			if i.isAboveWater(pos) {
				// 10% chance to add a rock
				if rand.Intn(100) < 10 {
					name := ""
					// XXX make it less likely to place a large rock
					switch rand.Intn(3) {
					case 0:
						name = "small rock"
					case 1:
						name = "medium rock"
					case 2:
						name = "large rock"
					default:
						panic("")
					}
					island.addNpcFromName(name, pos)
				}
			}
		}
	}
}

// create trees all over the island
func (i *Island) spawnTrees() {

	cnt := 0
	for y := 0; y < i.Height; y++ {
		for x := 0; x < i.Width; x++ {
			pos := Point{X: float64(x), Y: float64(y)}
			if i.isAboveWater(pos) {
				// add one tree in 3% of the time
				if rand.Intn(100) < 3 {
					name := ""
					// XXX make it less likely to place oak trees ?
					switch rand.Intn(3) {
					case 0:
						name = "oak tree"
					case 1:
						name = "apple tree"
					case 2:
						name = "birch tree"
					default:
						panic("")
					}
					island.addNpcFromName(name, pos)
					cnt++
				}
			}
		}
	}
	log.Printf("spawned %d trees", cnt)
}

// generate critters based on data file
func (i *Island) fillWithCritters() {

	dwarf := i.getNpcSpecFromRace("dwarf")
	for n := 0; n < 5; n++ {
		i.addNpcFromSpec(dwarf, i.RandomPointAboveWater())
	}

	rabbit := i.getNpcSpecFromRace("rabbit")
	for n := 0; n < 5; n++ {
		i.addNpcFromSpec(rabbit, i.RandomPointAboveWater())
	}
}

func generateIsland(seed int64, width int, height int) *Island {

	particleLength := 8
	innerBlur := 0.85
	outerBlur := 0.60
	roller := rollingparticle.New(seed, width, height, particleLength, innerBlur, outerBlur)

	/*
		rollerImage := slice2DAsImage(&roller, width, height)
		rollerImgFile, _ := os.Create("roller.png")
		png.Encode(rollerImgFile, rollerImage)
	*/

	m := make2DIntSlice(width, height)

	noise := opensimplex.NewWithSeed(seed)

	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {

			// combine some sizes of noise
			fBig := noise.Eval2(float64(x)*0.005, float64(y)*0.005)
			fMid := noise.Eval2(float64(x)*0.01, float64(y)*0.01)
			fSmall := noise.Eval2(float64(x)*0.02, float64(y)*0.02)
			fMini := noise.Eval2(float64(x)*0.04, float64(y)*0.04)

			f := (fBig + fMid + fSmall + fMini) / 4

			// scale from -1.0-1.0 to 0.0-1.0
			f = (f + 1.0) / 2.0

			// scale from 0.0-1.0 to 0-255
			b := int(0)
			if f == 1.0 {
				b = 255
			} else {
				b = int(math.Floor(f * 256.0))
			}

			// combine with rolling particle
			opacity := 0.5
			b = int((1-opacity)*float64(b) + opacity*float64(roller[y][x]))

			m[y][x] = b
		}
	}

	is := &Island{
		Width:     width,
		Height:    height,
		Seed:      seed,
		HeightMap: m}

	// load all possible world items, NPC:s and actions
	is.npcSpecs, _ = parseObjectsDefinition("data/objs.yml")
	is.actionSpecs, _ = parseActionsDefinition("data/actions.yml")

	return is
}
<|endoftext|>


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

package isvcs

import (
	"github.com/Sirupsen/logrus"
	"github.com/control-center/serviced/dfs/docker"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/logging"
	"github.com/control-center/serviced/utils"

	"errors"
	"fmt"
	"github.com/control-center/serviced/config"
	"os"
	"strings"
	"time"
)

var (
	Mgr *Manager
	log = logging.PackageLogger()
)

const (
	IMAGE_REPO         = "zenoss/serviced-isvcs"
	IMAGE_TAG          = "v72"
	ZK_IMAGE_REPO      = "zenoss/isvcs-zookeeper"
	ZK_IMAGE_TAG       = "v16"
	OTSDB_BT_REPO      = "zenoss/isvcs-metrics-bigtable"
	OTSDB_BT_TAG       = "v1"
	API_KEY_PROXY_REPO = "gcr.io/zing-registry-188222/api-key-proxy"
	API_KEY_PROXY_TAG  = "2018-08-01-1"
)

type IServiceHealthResult struct {
	ServiceName    string
	ContainerName  string
	ContainerID    string
	HealthStatuses []domain.HealthCheckStatus
}

//
func PreInit(bigtable bool) error {
	// Setup the initial Isvcs
	InitAllIsvcs(bigtable)

	// Set the environment map.
	if err := setIsvcsEnv(); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to set isvcs options: %s\n", err)
		return err
	}

	return nil
}

func Init(esStartupTimeoutInSeconds int, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker, startZK bool, bigtable bool) {
	if err := PreInit(bigtable); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "PreInit",
		}).WithError(err).Fatal("Unable to initialize ISVCS")
	}

	elasticsearch_serviced.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second
	elasticsearch_logstash.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)

	elasticsearch_serviced.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_serviced); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "elasticsearch-serviced",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	elasticsearch_logstash.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_logstash); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "elasticsearch-logstash",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	zookeeper.docker = dockerAPI
	if !startZK {
		// Don't start the ZK process but keep the container so that
		// healtchecks for the ZK cluster are reported.
		zookeeper.Command = func() string { return "sleep infinity" }
		zookeeper.PortBindings = []portBinding{}
	}
	if err := Mgr.Register(zookeeper); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "zookeeper",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	logstash.docker = dockerAPI
	if err := Mgr.Register(logstash); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "logstash",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	opentsdb.docker = dockerAPI
	if err := Mgr.Register(opentsdb); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "opentsdb",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	dockerRegistry.docker = dockerAPI
	if err := Mgr.Register(dockerRegistry); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "docker-registry",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	kibana.docker = dockerAPI
	if err := Mgr.Register(kibana); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "kibana",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	if config.GetOptions().StartAPIKeyProxy {
		apiKeyProxy.docker = dockerAPI
		if err := Mgr.Register(apiKeyProxy); err != nil {
			log.WithFields(logrus.Fields{
				"isvc": "api-key-proxy",
			}).WithError(err).Fatal("Unable to register internal service")
		}
	} else {
		log.WithFields(logrus.Fields{"isvc": "api-key-proxy"}).Debug("NOT starting service per config.")
	}
}

func InitServices(isvcNames []string, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	if err := PreInit(false); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "PreInit",
		}).WithError(err).Fatal("Unable to initialize ISVCS")
	}

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)
	for _, isvcName := range isvcNames {
		switch isvcName {
		case "zookeeper":
			zookeeper.docker = dockerAPI
			if err := Mgr.Register(zookeeper); err != nil {
				log.WithFields(logrus.Fields{
					"isvc": "zookeeper",
				}).WithError(err).Fatal("Unable to register internal service")
			}
		}
	}
}

// This function sets up key pieces of information for ISVCS in the environment map.
// (Adapted from the cmd.go cli function of the same name)
func setIsvcsEnv() error {
	options := config.GetOptions()

	if zkid := options.IsvcsZKID; zkid > 0 {
		if err := AddEnv(fmt.Sprintf("zookeeper:ZKID=%d", zkid)); err != nil {
			return err
		}
	}
	if zkquorum := strings.Join(options.IsvcsZKQuorum, ","); zkquorum != "" {
		if err := AddEnv("zookeeper:ZK_QUORUM=" + zkquorum); err != nil {
			return err
		}
	}
	if zkusername := options.IsvcsZKUsername; zkusername != "" {
		if err := AddEnv("zookeeper:ZK_USERNAME=" + zkusername); err != nil {
			return err
		}
	}
	if zkpasswd := options.IsvcsZKPasswd; zkpasswd != "" {
		if err := AddEnv("zookeeper:ZK_PASSWD=" + zkpasswd); err != nil {
			return err
		}
	}

	if opentsdbusername := options.IsvcsOpenTsdbUsername; opentsdbusername != "" {
		if err := AddEnv("opentsdb:OPENTSDB_USERNAME=" + opentsdbusername); err != nil {
			return err
		}
	}
	if opentsdbpasswd := options.IsvcsOpenTsdbPasswd; opentsdbpasswd != "" {
		if err := AddEnv("opentsdb:OPENTSDB_PASSWD=" + opentsdbpasswd); err != nil {
			return err
		}
	}
	// Configure api key proxy isvc only if indicated in configuration.
	if options.StartAPIKeyProxy {
		// Add variables for api proxy
		apiIp := getDockerIP()
		if apiIp == "" {
			return ErrNoDockerIP
		}
		proxyToAddr := fmt.Sprintf("https://%s:%s", apiIp, strings.TrimLeft(options.UIPort, ":"))
		if options.KeyProxyJsonServer == "" {
			return errors.New("Configuration error: SERVICED_KEYPROXY_JSON_SERVER must be set if SERVICED_START_API_KEY_PROXY is true.")
		}
		apiProxyVars := []string{
			"api-key-proxy:KEYPROXY_PROXY_LISTENER_PORT=" + options.KeyProxyListenPort,
			"api-key-proxy:KEYPROXY_PROXY_LOCATION_USES_TLS=true",
			"api-key-proxy:KEYPROXY_SERVE_TLS=true",
			fmt.Sprintf("api-key-proxy:KEYPROXY_ZPROXY_LOCATION=%s", proxyToAddr),
			fmt.Sprintf("api-key-proxy:KEYPROXY_JSON_SERVER=%s", options.KeyProxyJsonServer),
		}
		for _, val := range apiProxyVars {
			if err := AddEnv(val); err != nil {
				return err
			}
		}
	}
	// Add variables specified in options
	for _, val := range options.IsvcsENV {
		if err := AddEnv(val); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>CC-4464: fix metrics query and consumer<commit_after>// Copyright 2014 The Serviced Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package isvcs

import (
	"github.com/Sirupsen/logrus"
	"github.com/control-center/serviced/dfs/docker"
	"github.com/control-center/serviced/domain"
	"github.com/control-center/serviced/logging"
	"github.com/control-center/serviced/utils"

	"errors"
	"fmt"
	"github.com/control-center/serviced/config"
	"os"
	"strings"
	"time"
)

var (
	Mgr *Manager
	log = logging.PackageLogger()
)

const (
	IMAGE_REPO         = "zenoss/serviced-isvcs"
	IMAGE_TAG          = "v73"
	ZK_IMAGE_REPO      = "zenoss/isvcs-zookeeper"
	ZK_IMAGE_TAG       = "v16"
	OTSDB_BT_REPO      = "zenoss/isvcs-metrics-bigtable"
	OTSDB_BT_TAG       = "v1"
	API_KEY_PROXY_REPO = "gcr.io/zing-registry-188222/api-key-proxy"
	API_KEY_PROXY_TAG  = "2018-08-01-1"
)

type IServiceHealthResult struct {
	ServiceName    string
	ContainerName  string
	ContainerID    string
	HealthStatuses []domain.HealthCheckStatus
}

//
func PreInit(bigtable bool) error {
	// Setup the initial Isvcs
	InitAllIsvcs(bigtable)

	// Set the environment map.
	if err := setIsvcsEnv(); err != nil {
		fmt.Fprintf(os.Stderr, "Unable to set isvcs options: %s\n", err)
		return err
	}

	return nil
}

func Init(esStartupTimeoutInSeconds int, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker, startZK bool, bigtable bool) {
	if err := PreInit(bigtable); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "PreInit",
		}).WithError(err).Fatal("Unable to initialize ISVCS")
	}

	elasticsearch_serviced.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second
	elasticsearch_logstash.StartupTimeout = time.Duration(esStartupTimeoutInSeconds) * time.Second

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)

	elasticsearch_serviced.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_serviced); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "elasticsearch-serviced",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	elasticsearch_logstash.docker = dockerAPI
	if err := Mgr.Register(elasticsearch_logstash); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "elasticsearch-logstash",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	zookeeper.docker = dockerAPI
	if !startZK {
		// Don't start the ZK process but keep the container so that
		// healtchecks for the ZK cluster are reported.
		zookeeper.Command = func() string { return "sleep infinity" }
		zookeeper.PortBindings = []portBinding{}
	}
	if err := Mgr.Register(zookeeper); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "zookeeper",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	logstash.docker = dockerAPI
	if err := Mgr.Register(logstash); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "logstash",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	opentsdb.docker = dockerAPI
	if err := Mgr.Register(opentsdb); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "opentsdb",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	dockerRegistry.docker = dockerAPI
	if err := Mgr.Register(dockerRegistry); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "docker-registry",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	kibana.docker = dockerAPI
	if err := Mgr.Register(kibana); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "kibana",
		}).WithError(err).Fatal("Unable to register internal service")
	}
	if config.GetOptions().StartAPIKeyProxy {
		apiKeyProxy.docker = dockerAPI
		if err := Mgr.Register(apiKeyProxy); err != nil {
			log.WithFields(logrus.Fields{
				"isvc": "api-key-proxy",
			}).WithError(err).Fatal("Unable to register internal service")
		}
	} else {
		log.WithFields(logrus.Fields{"isvc": "api-key-proxy"}).Debug("NOT starting service per config.")
	}
}

func InitServices(isvcNames []string, dockerLogDriver string, dockerLogConfig map[string]string, dockerAPI docker.Docker) {
	if err := PreInit(false); err != nil {
		log.WithFields(logrus.Fields{
			"isvc": "PreInit",
		}).WithError(err).Fatal("Unable to initialize ISVCS")
	}

	Mgr = NewManager(utils.LocalDir("images"), utils.TempDir("var/isvcs"), dockerLogDriver, dockerLogConfig)
	for _, isvcName := range isvcNames {
		switch isvcName {
		case "zookeeper":
			zookeeper.docker = dockerAPI
			if err := Mgr.Register(zookeeper); err != nil {
				log.WithFields(logrus.Fields{
					"isvc": "zookeeper",
				}).WithError(err).Fatal("Unable to register internal service")
			}
		}
	}
}

// This function sets up key pieces of information for ISVCS in the environment map.
// (Adapted from the cmd.go cli function of the same name)
func setIsvcsEnv() error {
	options := config.GetOptions()

	if zkid := options.IsvcsZKID; zkid > 0 {
		if err := AddEnv(fmt.Sprintf("zookeeper:ZKID=%d", zkid)); err != nil {
			return err
		}
	}
	if zkquorum := strings.Join(options.IsvcsZKQuorum, ","); zkquorum != "" {
		if err := AddEnv("zookeeper:ZK_QUORUM=" + zkquorum); err != nil {
			return err
		}
	}
	if zkusername := options.IsvcsZKUsername; zkusername != "" {
		if err := AddEnv("zookeeper:ZK_USERNAME=" + zkusername); err != nil {
			return err
		}
	}
	if zkpasswd := options.IsvcsZKPasswd; zkpasswd != "" {
		if err := AddEnv("zookeeper:ZK_PASSWD=" + zkpasswd); err != nil {
			return err
		}
	}

	if opentsdbusername := options.IsvcsOpenTsdbUsername; opentsdbusername != "" {
		if err := AddEnv("opentsdb:OPENTSDB_USERNAME=" + opentsdbusername); err != nil {
			return err
		}
	}
	if opentsdbpasswd := options.IsvcsOpenTsdbPasswd; opentsdbpasswd != "" {
		if err := AddEnv("opentsdb:OPENTSDB_PASSWD=" + opentsdbpasswd); err != nil {
			return err
		}
	}
	// Configure api key proxy isvc only if indicated in configuration.
	if options.StartAPIKeyProxy {
		// Add variables for api proxy
		apiIp := getDockerIP()
		if apiIp == "" {
			return ErrNoDockerIP
		}
		proxyToAddr := fmt.Sprintf("https://%s:%s", apiIp, strings.TrimLeft(options.UIPort, ":"))
		if options.KeyProxyJsonServer == "" {
			return errors.New("Configuration error: SERVICED_KEYPROXY_JSON_SERVER must be set if SERVICED_START_API_KEY_PROXY is true.")
		}
		apiProxyVars := []string{
			"api-key-proxy:KEYPROXY_PROXY_LISTENER_PORT=" + options.KeyProxyListenPort,
			"api-key-proxy:KEYPROXY_PROXY_LOCATION_USES_TLS=true",
			"api-key-proxy:KEYPROXY_SERVE_TLS=true",
			fmt.Sprintf("api-key-proxy:KEYPROXY_ZPROXY_LOCATION=%s", proxyToAddr),
			fmt.Sprintf("api-key-proxy:KEYPROXY_JSON_SERVER=%s", options.KeyProxyJsonServer),
		}
		for _, val := range apiProxyVars {
			if err := AddEnv(val); err != nil {
				return err
			}
		}
	}
	// Add variables specified in options
	for _, val := range options.IsvcsENV {
		if err := AddEnv(val); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package jkl

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

var j, _ = cookiejar.New(nil)

var httpClient *JiraClient

type JiraClient struct {
	*http.Client
	jiraRoot string
}

func NewJiraClient(jiraRoot string) *JiraClient {
	j := &JiraClient{
		&http.Client{
			Jar: j,
		},
		jiraRoot,
	}
	if j.jiraRoot == "" {
		j.jiraRoot = os.Getenv("JIRA_ROOT")
	}
	if *Verbose {
		fmt.Println("Jira root:", j.jiraRoot)
	}
	return j
}

func (j *JiraClient) Do(req *http.Request) (*http.Response, error) {
	var err error
	req.SetBasicAuth(os.Getenv("JIRA_USER"), os.Getenv("JIRA_PASSWORD"))
	if *Verbose {
		fmt.Println("Jira User: ", os.Getenv("JIRA_USER"))
		fmt.Println("Jira Password: ", os.Getenv("JIRA_PASSWORD"))
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json, text/plain, text/html")
	req.URL, err = url.Parse(j.jiraRoot + "rest/" + req.URL.RequestURI())
	if err != nil {
		return nil, err
	}
	resp, err := j.Client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		fmt.Println("Status code:", resp.StatusCode)
		if *Verbose {
			fmt.Println("Headers:")
			fmt.Println(resp.Header)
		}
		fmt.Println("Response:")
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
		fmt.Println(string(b))
		return nil, errors.New("Some http error happened.")
	}
	return resp, nil
}

func (j *JiraClient) Put(path string, payload io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("PUT", path, payload)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}

func (j *JiraClient) Post(path string, payload io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", path, payload)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}

func (j *JiraClient) Get(path string) (*http.Response, error) {
	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}
<commit_msg>Prevent verbose-bombing<commit_after>package jkl

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

var j, _ = cookiejar.New(nil)

var httpClient *JiraClient

type JiraClient struct {
	*http.Client
	jiraRoot string
}

func init(){
	x := false
	Verbose = &x
}

func NewJiraClient(jiraRoot string) *JiraClient {
	j := &JiraClient{
		&http.Client{
			Jar: j,
		},
		jiraRoot,
	}
	if j.jiraRoot == "" {
		j.jiraRoot = os.Getenv("JIRA_ROOT")
	}
	if *Verbose {
		fmt.Println("Jira root:", j.jiraRoot)
	}
	return j
}

func (j *JiraClient) Do(req *http.Request) (*http.Response, error) {
	var err error
	req.SetBasicAuth(os.Getenv("JIRA_USER"), os.Getenv("JIRA_PASSWORD"))
	if *Verbose {
		fmt.Println("Jira User: ", os.Getenv("JIRA_USER"))
		fmt.Println("Jira Password: ", os.Getenv("JIRA_PASSWORD"))
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept", "application/json, text/plain, text/html")
	req.URL, err = url.Parse(j.jiraRoot + "rest/" + req.URL.RequestURI())
	if err != nil {
		return nil, err
	}
	resp, err := j.Client.Do(req)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode >= 400 {
		fmt.Println("Status code:", resp.StatusCode)
		if *Verbose {
			fmt.Println("Headers:")
			fmt.Println(resp.Header)
		}
		fmt.Println("Response:")
		b, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
		fmt.Println(string(b))
		return nil, errors.New("Some http error happened.")
	}
	return resp, nil
}

func (j *JiraClient) Put(path string, payload io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("PUT", path, payload)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}

func (j *JiraClient) Post(path string, payload io.Reader) (*http.Response, error) {
	req, err := http.NewRequest("POST", path, payload)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}

func (j *JiraClient) Get(path string) (*http.Response, error) {
	req, err := http.NewRequest("GET", path, nil)
	if err != nil {
		return nil, err
	}
	return j.Do(req)
}
<|endoftext|>


<commit_before>package jocko

import (
	"bufio"
	"context"
	"crypto/tls"
	"math"
	"net"
	"runtime"
	"sync"
	"time"

	"github.com/travisjeffery/jocko/protocol"
)

const (
	defaultRTT = 1 * time.Second
	maxTimeout = time.Duration(math.MaxInt32) * time.Millisecond
	minTimeout = time.Duration(math.MinInt32) * time.Millisecond
)

// Resolver provides service discovery of the hosts of a kafka cluster.
type Resolver interface {
	// LookupHost looks up the given host using the local resolver.
	LookupHost(ctx context.Context, host string) ([]string, error)
}

type Dialer struct {
	// Unique ID for client connections established by this Dialer.
	ClientID string
	// Timeout is the max duration a dial will wait for a connect to complete.
	Timeout time.Duration
	// Deadline is the absolute time after which the dial will fail. Zero is no deadline.
	Deadline time.Time
	// LocalAddr is the local address to dial.
	LocalAddr net.Addr
	// RemoteAddr is the remote address to dial.
	RemoteAddr net.Addr
	// KeepAlive is the keep-alive period for a network connection.
	KeepAlive time.Duration
	// FallbackDelay is the duration to wait before spawning a fallback connection. If 0, default duration is 300ms.
	FallbackDelay time.Duration
	// Resolver species an alternative resolver to use.
	Resolver Resolver
	// TLS enables the Dialer to secure connections. If nil, standard net.Conn is used.
	TLS *tls.Config
	// DualStack enables RFC 6555-compliant "happy eyeballs" dialing.
	DualStack bool
}

var (
	defaultDialer = &Dialer{
		Timeout:   10 * time.Second,
		DualStack: true,
		ClientID:  "jocko",
	}
)

func Dial(network, address string) (*Conn, error) {
	return defaultDialer.Dial(network, address)
}

func DialContext(ctx context.Context, network, address string) (*Conn, error) {
	return defaultDialer.DialContext(ctx, network, address)
}

func (d *Dialer) Dial(network, address string) (*Conn, error) {
	return d.DialContext(context.Background(), network, address)
}

func (d *Dialer) DialContext(ctx context.Context, network, address string) (*Conn, error) {
	if d.Timeout != 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, d.Timeout)
		defer cancel()
	}

	if !d.Deadline.IsZero() {
		var cancel context.CancelFunc
		ctx, cancel = context.WithDeadline(ctx, d.Deadline)
		defer cancel()
	}

	c, err := d.dialContext(ctx, network, address)
	if err != nil {
		return nil, err
	}
	return NewConn(c, d.ClientID)
}

func (d *Dialer) dialContext(ctx context.Context, network, address string) (net.Conn, error) {
	if r := d.Resolver; r != nil {
		host, port := splitHostPort(address)
		addrs, err := r.LookupHost(ctx, host)
		if err != nil {
			return nil, err
		}
		if len(addrs) != 0 {
			address = addrs[0]
		}
		if len(port) != 0 {
			address, _ = splitHostPort(address)
			address = net.JoinHostPort(address, port)
		}
	}
	return (&net.Dialer{
		LocalAddr:     d.LocalAddr,
		FallbackDelay: d.FallbackDelay,
		KeepAlive:     d.KeepAlive,
	}).DialContext(ctx, network, address)
}

func splitHostPort(s string) (string, string) {
	host, port, _ := net.SplitHostPort(s)
	if len(host) == 0 && len(port) == 0 {
		host = s
	}
	return host, port
}

type Conn struct {
	conn          net.Conn
	mutex         sync.Mutex
	rlock         sync.Mutex
	rbuf          bufio.Reader
	wlock         sync.Mutex
	wbuf          bufio.Writer
	wdeadline     connDeadline
	rdeadline     connDeadline
	clientID      string
	correlationID int32
}

func NewConn(conn net.Conn, clientID string) (*Conn, error) {
	return &Conn{
		conn:     conn,
		clientID: clientID,
		rbuf:     *bufio.NewReader(conn),
		wbuf:     *bufio.NewWriter(conn),
	}, nil
}

func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() }

func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() }

func (c *Conn) SetDeadline(t time.Time) error {
	c.rdeadline.setDeadline(t)
	c.wdeadline.setDeadline(t)
	return nil
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	c.rdeadline.setDeadline(t)
	return nil
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	c.wdeadline.setDeadline(t)
	return nil
}

// Read satisfies net.Conn interface. Don't use it.
func (c *Conn) Read(b []byte) (int, error) {
	return 0, nil
}

func (c *Conn) Write(b []byte) (int, error) {
	return 0, nil
}

func (c *Conn) Close() error { return c.conn.Close() }

func (c *Conn) LeaderAndISR(req *protocol.LeaderAndISRRequest) (*protocol.LeaderAndISRResponse, error) {
	var resp protocol.LeaderAndISRResponse
	err := c.writeOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) CreateTopics(req *protocol.CreateTopicRequests) (*protocol.CreateTopicsResponse, error) {
	var resp protocol.CreateTopicsResponse
	err := c.writeOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) Fetch(req *protocol.FetchRequest) (*protocol.FetchResponses, error) {
	var resp protocol.FetchResponses
	err := c.readOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) readResponse(resp protocol.Decoder, size int) error {
	b := make([]byte, size)
	_, err := c.rbuf.Read(b)
	if err != nil {
		return err
	}
	return protocol.Decode(b, resp)
}

func (c *Conn) writeRequest(body protocol.Body) error {
	req := &protocol.Request{
		CorrelationID: c.correlationID,
		ClientID:      c.clientID,
		Body:          body,
	}
	b, err := protocol.Encode(req)
	if err != nil {
		return err
	}
	_, err = c.wbuf.Write(b)
	if err != nil {
		return err
	}
	return c.wbuf.Flush()
}

type wop func(deadline time.Time, id int32) error
type rop func(deadline time.Time, size int) error

func (c *Conn) readOperation(write wop, read rop) error {
	return c.do(&c.rdeadline, write, read)
}

func (c *Conn) writeOperation(write wop, read rop) error {
	return c.do(&c.wdeadline, write, read)
}

func (c *Conn) do(d *connDeadline, write wop, read rop) error {
	id, err := c.doRequest(d, write)
	if err != nil {
		return err
	}
	deadline, size, lock, err := c.waitResponse(d, id)
	if err != nil {
		return err
	}

	if err = read(deadline, size); err != nil {
		switch err.(type) {
		case protocol.Error:
		default:
			c.conn.Close()
		}
	}

	d.unsetConnReadDeadline()
	lock.Unlock()
	return err
}

func (c *Conn) doRequest(d *connDeadline, write wop) (int32, error) {
	c.wlock.Lock()
	c.correlationID++
	id := c.correlationID
	err := write(d.setConnWriteDeadline(c.conn), id)
	d.unsetConnWriteDeadline()
	if err != nil {
		c.conn.Close()
	}
	c.wlock.Unlock()
	return c.correlationID, nil
}

func (c *Conn) waitResponse(d *connDeadline, id int32) (deadline time.Time, size int, lock *sync.Mutex, err error) {
	for {
		var rsz int32
		var rid int32

		c.rlock.Lock()
		deadline = d.setConnReadDeadline(c.conn)

		if rsz, rid, err = c.peekResponseSizeAndID(); err != nil {
			d.unsetConnReadDeadline()
			c.conn.Close()
			c.rlock.Unlock()
			return
		}

		if id == rid {
			c.skipResponseSizeAndID()
			size, lock = int(rsz-4), &c.rlock
			return
		}

		c.rlock.Unlock()
		runtime.Gosched()
	}
}

func (c *Conn) readDeadline() time.Time {
	return c.rdeadline.deadline()
}

func (c *Conn) writeDeadline() time.Time {
	return c.wdeadline.deadline()
}

func (c *Conn) peekResponseSizeAndID() (int32, int32, error) {
	b, err := c.rbuf.Peek(8)
	if err != nil {
		return 0, 0, nil
	}
	size, id := protocol.MakeInt32(b[:4]), protocol.MakeInt32(b[4:])
	return size, id, nil
}

func (c *Conn) skipResponseSizeAndID() {
	c.rbuf.Discard(8)
}

type connDeadline struct {
	mutex sync.Mutex
	value time.Time
	rconn net.Conn
	wconn net.Conn
}

func (d *connDeadline) deadline() time.Time {
	d.mutex.Lock()
	t := d.value
	d.mutex.Unlock()
	return t
}

func (d *connDeadline) setDeadline(t time.Time) {
	d.mutex.Lock()
	d.value = t

	if d.rconn != nil {
		d.rconn.SetReadDeadline(t)
	}

	if d.wconn != nil {
		d.wconn.SetWriteDeadline(t)
	}

	d.mutex.Unlock()
}

func (d *connDeadline) setConnReadDeadline(conn net.Conn) time.Time {
	d.mutex.Lock()
	deadline := d.value
	d.rconn = conn
	d.rconn.SetReadDeadline(deadline)
	d.mutex.Unlock()
	return deadline
}

func (d *connDeadline) setConnWriteDeadline(conn net.Conn) time.Time {
	d.mutex.Lock()
	deadline := d.value
	d.wconn = conn
	d.wconn.SetWriteDeadline(deadline)
	d.mutex.Unlock()
	return deadline
}

func (d *connDeadline) unsetConnReadDeadline() {
	d.mutex.Lock()
	d.rconn = nil
	d.mutex.Unlock()
}

func (d *connDeadline) unsetConnWriteDeadline() {
	d.mutex.Lock()
	d.wconn = nil
	d.mutex.Unlock()
}
<commit_msg>conn: discard peeked response bytes<commit_after>package jocko

import (
	"bufio"
	"context"
	"crypto/tls"
	"math"
	"net"
	"runtime"
	"sync"
	"time"

	"github.com/travisjeffery/jocko/protocol"
)

const (
	defaultRTT = 1 * time.Second
	maxTimeout = time.Duration(math.MaxInt32) * time.Millisecond
	minTimeout = time.Duration(math.MinInt32) * time.Millisecond
)

// Resolver provides service discovery of the hosts of a kafka cluster.
type Resolver interface {
	// LookupHost looks up the given host using the local resolver.
	LookupHost(ctx context.Context, host string) ([]string, error)
}

type Dialer struct {
	// Unique ID for client connections established by this Dialer.
	ClientID string
	// Timeout is the max duration a dial will wait for a connect to complete.
	Timeout time.Duration
	// Deadline is the absolute time after which the dial will fail. Zero is no deadline.
	Deadline time.Time
	// LocalAddr is the local address to dial.
	LocalAddr net.Addr
	// RemoteAddr is the remote address to dial.
	RemoteAddr net.Addr
	// KeepAlive is the keep-alive period for a network connection.
	KeepAlive time.Duration
	// FallbackDelay is the duration to wait before spawning a fallback connection. If 0, default duration is 300ms.
	FallbackDelay time.Duration
	// Resolver species an alternative resolver to use.
	Resolver Resolver
	// TLS enables the Dialer to secure connections. If nil, standard net.Conn is used.
	TLS *tls.Config
	// DualStack enables RFC 6555-compliant "happy eyeballs" dialing.
	DualStack bool
}

var (
	defaultDialer = &Dialer{
		Timeout:   10 * time.Second,
		DualStack: true,
		ClientID:  "jocko",
	}
)

func Dial(network, address string) (*Conn, error) {
	return defaultDialer.Dial(network, address)
}

func DialContext(ctx context.Context, network, address string) (*Conn, error) {
	return defaultDialer.DialContext(ctx, network, address)
}

func (d *Dialer) Dial(network, address string) (*Conn, error) {
	return d.DialContext(context.Background(), network, address)
}

func (d *Dialer) DialContext(ctx context.Context, network, address string) (*Conn, error) {
	if d.Timeout != 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, d.Timeout)
		defer cancel()
	}

	if !d.Deadline.IsZero() {
		var cancel context.CancelFunc
		ctx, cancel = context.WithDeadline(ctx, d.Deadline)
		defer cancel()
	}

	c, err := d.dialContext(ctx, network, address)
	if err != nil {
		return nil, err
	}
	return NewConn(c, d.ClientID)
}

func (d *Dialer) dialContext(ctx context.Context, network, address string) (net.Conn, error) {
	if r := d.Resolver; r != nil {
		host, port := splitHostPort(address)
		addrs, err := r.LookupHost(ctx, host)
		if err != nil {
			return nil, err
		}
		if len(addrs) != 0 {
			address = addrs[0]
		}
		if len(port) != 0 {
			address, _ = splitHostPort(address)
			address = net.JoinHostPort(address, port)
		}
	}
	return (&net.Dialer{
		LocalAddr:     d.LocalAddr,
		FallbackDelay: d.FallbackDelay,
		KeepAlive:     d.KeepAlive,
	}).DialContext(ctx, network, address)
}

func splitHostPort(s string) (string, string) {
	host, port, _ := net.SplitHostPort(s)
	if len(host) == 0 && len(port) == 0 {
		host = s
	}
	return host, port
}

type Conn struct {
	conn          net.Conn
	mutex         sync.Mutex
	rlock         sync.Mutex
	rbuf          bufio.Reader
	wlock         sync.Mutex
	wbuf          bufio.Writer
	wdeadline     connDeadline
	rdeadline     connDeadline
	clientID      string
	correlationID int32
}

func NewConn(conn net.Conn, clientID string) (*Conn, error) {
	return &Conn{
		conn:     conn,
		clientID: clientID,
		rbuf:     *bufio.NewReader(conn),
		wbuf:     *bufio.NewWriter(conn),
	}, nil
}

func (c *Conn) LocalAddr() net.Addr { return c.conn.LocalAddr() }

func (c *Conn) RemoteAddr() net.Addr { return c.conn.RemoteAddr() }

func (c *Conn) SetDeadline(t time.Time) error {
	c.rdeadline.setDeadline(t)
	c.wdeadline.setDeadline(t)
	return nil
}

func (c *Conn) SetReadDeadline(t time.Time) error {
	c.rdeadline.setDeadline(t)
	return nil
}

func (c *Conn) SetWriteDeadline(t time.Time) error {
	c.wdeadline.setDeadline(t)
	return nil
}

// Read satisfies net.Conn interface. Don't use it.
func (c *Conn) Read(b []byte) (int, error) {
	return 0, nil
}

func (c *Conn) Write(b []byte) (int, error) {
	return 0, nil
}

func (c *Conn) Close() error { return c.conn.Close() }

func (c *Conn) LeaderAndISR(req *protocol.LeaderAndISRRequest) (*protocol.LeaderAndISRResponse, error) {
	var resp protocol.LeaderAndISRResponse
	err := c.writeOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) CreateTopics(req *protocol.CreateTopicRequests) (*protocol.CreateTopicsResponse, error) {
	var resp protocol.CreateTopicsResponse
	err := c.writeOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) Fetch(req *protocol.FetchRequest) (*protocol.FetchResponses, error) {
	var resp protocol.FetchResponses
	err := c.readOperation(func(deadline time.Time, id int32) error {
		return c.writeRequest(req)
	}, func(deadline time.Time, size int) error {
		return c.readResponse(&resp, size)
	})
	if err != nil {
		return nil, err
	}
	return &resp, nil
}

func (c *Conn) readResponse(resp protocol.Decoder, size int) error {
	b, err := c.rbuf.Peek(size)
	if err != nil {
		return err
	}
	err = protocol.Decode(b, resp)
	c.rbuf.Discard(size)
	return err
}

func (c *Conn) writeRequest(body protocol.Body) error {
	req := &protocol.Request{
		CorrelationID: c.correlationID,
		ClientID:      c.clientID,
		Body:          body,
	}
	b, err := protocol.Encode(req)
	if err != nil {
		return err
	}
	_, err = c.wbuf.Write(b)
	if err != nil {
		return err
	}
	return c.wbuf.Flush()
}

type wop func(deadline time.Time, id int32) error
type rop func(deadline time.Time, size int) error

func (c *Conn) readOperation(write wop, read rop) error {
	return c.do(&c.rdeadline, write, read)
}

func (c *Conn) writeOperation(write wop, read rop) error {
	return c.do(&c.wdeadline, write, read)
}

func (c *Conn) do(d *connDeadline, write wop, read rop) error {
	id, err := c.doRequest(d, write)
	if err != nil {
		return err
	}
	deadline, size, lock, err := c.waitResponse(d, id)
	if err != nil {
		return err
	}

	if err = read(deadline, size); err != nil {
		switch err.(type) {
		case protocol.Error:
		default:
			c.conn.Close()
		}
	}

	d.unsetConnReadDeadline()
	lock.Unlock()
	return err
}

func (c *Conn) doRequest(d *connDeadline, write wop) (int32, error) {
	c.wlock.Lock()
	c.correlationID++
	id := c.correlationID
	err := write(d.setConnWriteDeadline(c.conn), id)
	d.unsetConnWriteDeadline()
	if err != nil {
		c.conn.Close()
	}
	c.wlock.Unlock()
	return c.correlationID, nil
}

func (c *Conn) waitResponse(d *connDeadline, id int32) (deadline time.Time, size int, lock *sync.Mutex, err error) {
	for {
		var rsz int32
		var rid int32

		c.rlock.Lock()
		deadline = d.setConnReadDeadline(c.conn)

		if rsz, rid, err = c.peekResponseSizeAndID(); err != nil {
			d.unsetConnReadDeadline()
			c.conn.Close()
			c.rlock.Unlock()
			return
		}

		if id == rid {
			c.skipResponseSizeAndID()
			size, lock = int(rsz-4), &c.rlock
			return
		}

		c.rlock.Unlock()
		runtime.Gosched()
	}
}

func (c *Conn) readDeadline() time.Time {
	return c.rdeadline.deadline()
}

func (c *Conn) writeDeadline() time.Time {
	return c.wdeadline.deadline()
}

func (c *Conn) peekResponseSizeAndID() (int32, int32, error) {
	b, err := c.rbuf.Peek(8)
	if err != nil {
		return 0, 0, nil
	}
	size, id := protocol.MakeInt32(b[:4]), protocol.MakeInt32(b[4:])
	return size, id, nil
}

func (c *Conn) skipResponseSizeAndID() {
	c.rbuf.Discard(8)
}

type connDeadline struct {
	mutex sync.Mutex
	value time.Time
	rconn net.Conn
	wconn net.Conn
}

func (d *connDeadline) deadline() time.Time {
	d.mutex.Lock()
	t := d.value
	d.mutex.Unlock()
	return t
}

func (d *connDeadline) setDeadline(t time.Time) {
	d.mutex.Lock()
	d.value = t

	if d.rconn != nil {
		d.rconn.SetReadDeadline(t)
	}

	if d.wconn != nil {
		d.wconn.SetWriteDeadline(t)
	}

	d.mutex.Unlock()
}

func (d *connDeadline) setConnReadDeadline(conn net.Conn) time.Time {
	d.mutex.Lock()
	deadline := d.value
	d.rconn = conn
	d.rconn.SetReadDeadline(deadline)
	d.mutex.Unlock()
	return deadline
}

func (d *connDeadline) setConnWriteDeadline(conn net.Conn) time.Time {
	d.mutex.Lock()
	deadline := d.value
	d.wconn = conn
	d.wconn.SetWriteDeadline(deadline)
	d.mutex.Unlock()
	return deadline
}

func (d *connDeadline) unsetConnReadDeadline() {
	d.mutex.Lock()
	d.rconn = nil
	d.mutex.Unlock()
}

func (d *connDeadline) unsetConnWriteDeadline() {
	d.mutex.Lock()
	d.wconn = nil
	d.mutex.Unlock()
}
<|endoftext|>