<commit_before>package sse

import (
	"testing"
	"time"

	"github.com/go-rfc/sse/internal/testutils"
	"github.com/stretchr/testify/assert"
)

const (
	contentTypeTextPlain = "text/plain; charset=utf-8"
)

// currentState holds the most recent value of the event source
var currentState ReadyState

func TestEventSourceStates(t *testing.T) {
	for _, test := range []struct {
		stateNumber   byte
		expectedState ReadyState
	}{
		{0, Connecting},
		{1, Open},
		{2, Closing},
		{3, Closed},
	} {
		assert.Equal(t, test.expectedState, ReadyState(test.stateNumber))
	}
}

func TestEventSourceConnectAndClose(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		url := handler.URL
		es, err := NewEventSource(url)

		assert.Nil(t, err)
		assert.Equal(t, url, es.URL())

		es.Close(nil)
		assertStates(t, []ReadyState{Connecting, Open, Closing, Closed}, es.ReadyState())
	})
}

func TestEventSourceConnectAndCloseThenReceive(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		url := handler.URL
		es, err := NewEventSource(url)

		assert.Nil(t, err)
		es.Close(nil)

		_, ok := <-es.MessageEvents()
		assert.False(t, ok)
	})
}

func TestEventSourceWithInvalidContentType(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.ContentType = contentTypeTextPlain
		es, err := NewEventSource(handler.URL)

		assert.Equal(t, ErrContentType, err)
		assertStates(t, []ReadyState{Connecting, Closing, Closed}, es.ReadyState())
	})
}

func TestEventSourceConnectWriteAndReceiveShortEvent(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		expectedEv := newMessageEvent("", "", 128)
		go handler.SendAndClose(messageEventToString(expectedEv))

		ev, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, expectedEv.Data, ev.Data)
	})
}

func TestEventSourceConnectWriteAndReceiveLongEvent(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		expectedEv := newMessageEvent("", "", 128)
		go handler.SendAndClose(messageEventToString(expectedEv))

		ev, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, expectedEv.Data, ev.Data)
	})
}

func TestEventSourceLastEventID(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		lastEventID := "123"
		expected := newMessageEvent(lastEventID, "", 512)
		go handler.SendWithID(messageEventToString(expected), expected.LastEventID)

		actual, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, lastEventID, actual.LastEventID)
		assert.Equal(t, expected.Data, actual.Data)

		ev := newMessageEvent("", "", 32)
		go handler.SendWithID(messageEventToString(ev), ev.LastEventID)

		actual, ok = <-es.MessageEvents()
		assert.Equal(t, lastEventID, actual.LastEventID)
	})
}

func TestEventSourceRetryIsRespected(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 3

		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.SendAndClose(retryEventToString(100))
		go handler.Send(newMessageEventString("", "", 128))
		select {
		case _, ok := <-es.MessageEvents():
			assert.True(t, ok)
		case <-timeout(125 * time.Millisecond):
			assert.Fail(t, "event source did not reconnect within the allowed time.")
		}

		// Smaller retry
		handler.SendAndClose(retryEventToString(1))
		go handler.Send(newMessageEventString("", "", 128))
		select {
		case _, ok := <-es.MessageEvents():
			assert.True(t, ok)
		case <-timeout(10 * time.Millisecond):
			assert.Fail(t, "event source did not reconnect within the allowed time.")
		}

		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open, Connecting, Open},
			es.ReadyState(),
		)
	})
}

func TestEventSourceDropConnectionCannotReconnect(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.CloseActiveRequest()

		_, ok := <-es.MessageEvents()
		assert.False(t, ok)
		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open, Closing, Closed},
			es.ReadyState(),
		)

	})
}

func TestEventSourceDropConnectionCanReconnect(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 2
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.CloseActiveRequest()
		time.Sleep(25 * time.Millisecond)
		go handler.Send(newMessageEventString("", "", 128))
		_, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open},
			es.ReadyState(),
		)
	})
}

func TestEventSourceLastEventIDHeaderOnReconnecting(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 2
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.Send(retryEventToString(1))

		// After closing, we retry and can poll the second message
		go handler.SendAndCloseWithID(newMessageEventString("first", "", 128), "first")
		_, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, "first", es.lastEventID)

		go handler.SendWithID(newMessageEventString("second", "", 128), "second")
		_, ok = <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, "second", es.lastEventID)
	})
}

func timeout(d time.Duration) <-chan struct{} {
	ch := make(chan struct{})
	go func() {
		time.Sleep(d)
		ch <- struct{}{}
	}()
	return ch
}

func assertStates(t *testing.T, expected []ReadyState, states <-chan Status) {
	actual := collectStates(states)
	assert.Equal(t, expected, actual)
}

func collectStates(states <-chan Status) []ReadyState {
	list := []ReadyState{}
	poll := true
	for poll {
		select {
		case status := <-states:
			list = append(list, status.ReadyState)
		case <-timeout(250 * time.Millisecond):
			poll = false
		}
	}
	return list
}

type testFn = func(*testutils.TestServerHandler)

func runTest(t *testing.T, fn testFn) {
	t.Log("setting up test")
	h := testutils.NewDefaultTestServerHandler(t)
	defer h.Close()
	fn(h)
	t.Logf("tearing down test")
}
<commit_msg>eventsource/test: use time.After<commit_after>package sse

import (
	"testing"
	"time"

	"github.com/go-rfc/sse/internal/testutils"
	"github.com/stretchr/testify/assert"
)

const (
	contentTypeTextPlain = "text/plain; charset=utf-8"
)

// currentState holds the most recent value of the event source
var currentState ReadyState

func TestEventSourceStates(t *testing.T) {
	for _, test := range []struct {
		stateNumber   byte
		expectedState ReadyState
	}{
		{0, Connecting},
		{1, Open},
		{2, Closing},
		{3, Closed},
	} {
		assert.Equal(t, test.expectedState, ReadyState(test.stateNumber))
	}
}

func TestEventSourceConnectAndClose(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		url := handler.URL
		es, err := NewEventSource(url)

		assert.Nil(t, err)
		assert.Equal(t, url, es.URL())

		es.Close(nil)
		assertStates(t, []ReadyState{Connecting, Open, Closing, Closed}, es.ReadyState())
	})
}

func TestEventSourceConnectAndCloseThenReceive(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		url := handler.URL
		es, err := NewEventSource(url)

		assert.Nil(t, err)
		es.Close(nil)

		_, ok := <-es.MessageEvents()
		assert.False(t, ok)
	})
}

func TestEventSourceWithInvalidContentType(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.ContentType = contentTypeTextPlain
		es, err := NewEventSource(handler.URL)

		assert.Equal(t, ErrContentType, err)
		assertStates(t, []ReadyState{Connecting, Closing, Closed}, es.ReadyState())
	})
}

func TestEventSourceConnectWriteAndReceiveShortEvent(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		expectedEv := newMessageEvent("", "", 128)
		go handler.SendAndClose(messageEventToString(expectedEv))

		ev, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, expectedEv.Data, ev.Data)
	})
}

func TestEventSourceConnectWriteAndReceiveLongEvent(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		expectedEv := newMessageEvent("", "", 128)
		go handler.SendAndClose(messageEventToString(expectedEv))

		ev, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, expectedEv.Data, ev.Data)
	})
}

func TestEventSourceLastEventID(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		lastEventID := "123"
		expected := newMessageEvent(lastEventID, "", 512)
		go handler.SendWithID(messageEventToString(expected), expected.LastEventID)

		actual, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, lastEventID, actual.LastEventID)
		assert.Equal(t, expected.Data, actual.Data)

		ev := newMessageEvent("", "", 32)
		go handler.SendWithID(messageEventToString(ev), ev.LastEventID)

		actual, ok = <-es.MessageEvents()
		assert.Equal(t, lastEventID, actual.LastEventID)
	})
}

func TestEventSourceRetryIsRespected(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 3

		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.SendAndClose(retryEventToString(100))
		go handler.Send(newMessageEventString("", "", 128))
		select {
		case _, ok := <-es.MessageEvents():
			assert.True(t, ok)
		case <-time.After(125 * time.Millisecond):
			assert.Fail(t, "event source did not reconnect within the allowed time.")
		}

		// Smaller retry
		handler.SendAndClose(retryEventToString(1))
		go handler.Send(newMessageEventString("", "", 128))
		select {
		case _, ok := <-es.MessageEvents():
			assert.True(t, ok)
		case <-time.After(10 * time.Millisecond):
			assert.Fail(t, "event source did not reconnect within the allowed time.")
		}

		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open, Connecting, Open},
			es.ReadyState(),
		)
	})
}

func TestEventSourceDropConnectionCannotReconnect(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.CloseActiveRequest()

		_, ok := <-es.MessageEvents()
		assert.False(t, ok)
		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open, Closing, Closed},
			es.ReadyState(),
		)

	})
}

func TestEventSourceDropConnectionCanReconnect(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 2
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.CloseActiveRequest()
		time.Sleep(25 * time.Millisecond)
		go handler.Send(newMessageEventString("", "", 128))
		_, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assertStates(
			t,
			[]ReadyState{Connecting, Open, Connecting, Open},
			es.ReadyState(),
		)
	})
}

func TestEventSourceLastEventIDHeaderOnReconnecting(t *testing.T) {
	runTest(t, func(handler *testutils.TestServerHandler) {
		handler.MaxRequestsToProcess = 2
		es, err := NewEventSource(handler.URL)
		assert.Nil(t, err)

		handler.Send(retryEventToString(1))

		// After closing, we retry and can poll the second message
		go handler.SendAndCloseWithID(newMessageEventString("first", "", 128), "first")
		_, ok := <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, "first", es.lastEventID)

		go handler.SendWithID(newMessageEventString("second", "", 128), "second")
		_, ok = <-es.MessageEvents()
		assert.True(t, ok)
		assert.Equal(t, "second", es.lastEventID)
	})
}

func assertStates(t *testing.T, expected []ReadyState, states <-chan Status) {
	actual := collectStates(states)
	assert.Equal(t, expected, actual)
}

func collectStates(states <-chan Status) []ReadyState {
	list := []ReadyState{}
	poll := true
	for poll {
		select {
		case status := <-states:
			list = append(list, status.ReadyState)
		case <-time.After(250 * time.Millisecond):
			poll = false
		}
	}
	return list
}

type testFn = func(*testutils.TestServerHandler)

func runTest(t *testing.T, fn testFn) {
	t.Log("setting up test")
	h := testutils.NewDefaultTestServerHandler(t)
	defer h.Close()
	fn(h)
	t.Logf("tearing down test")
}
<|endoftext|>


<commit_before>package app

import termbox "github.com/nsf/termbox-go"

type servicesScreenEventHandler struct {
	baseEventHandler
}

func (h *servicesScreenEventHandler) handle(event termbox.Event) {
	handled := false

	switch event.Key {
	case termbox.KeyEnter:
		showServices := func(serviceID string) error {
			h.dry.ShowServiceTasks(serviceID)
			h.renderChan <- struct{}{}
			return nil
		}
		h.dry.state.activeWidget.OnEvent(showServices)
		handled = true
	}
	if !handled {
		h.baseEventHandler.handle(event)
	} else {
		h.setFocus(true)
	}
}
<commit_msg>Add event handler for service tasks screen<commit_after>package app

import termbox "github.com/nsf/termbox-go"

type servicesScreenEventHandler struct {
	baseEventHandler
}

func (h *servicesScreenEventHandler) handle(event termbox.Event) {
	handled := false

	switch event.Key {
	case termbox.KeyEnter:
		showServices := func(serviceID string) error {
			h.dry.ShowServiceTasks(serviceID)
			h.renderChan <- struct{}{}
			return nil
		}
		h.dry.state.activeWidget.OnEvent(showServices)
		handled = true
	}
	if !handled {
		h.baseEventHandler.handle(event)
	} else {
		h.setFocus(true)
	}
}

type serviceTaskScreenEventHandler struct {
	baseEventHandler
}

func (h *serviceTaskScreenEventHandler) handle(event termbox.Event) {

	switch event.Key {
	case termbox.KeyEsc:
		h.dry.ShowServices()
	}

	h.baseEventHandler.handle(event)

}
<|endoftext|>


<commit_before>package v1

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	redis "gopkg.in/redis.v5"
	"zxq.co/ripple/rippleapi/common"
)

type setAllowedData struct {
	UserID  int `json:"user_id"`
	Allowed int `json:"allowed"`
}

// UserManageSetAllowedPOST allows to set the allowed status of an user.
func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
	var data setAllowedData
	if err := md.Unmarshal(&data); err != nil {
		return ErrBadJSON
	}
	if data.Allowed < 0 || data.Allowed > 2 {
		return common.SimpleResponse(400, "Allowed status must be between 0 and 2")
	}
	var banDatetime int64
	var privsSet string
	if data.Allowed == 0 {
		banDatetime = time.Now().Unix()
		privsSet = "privileges = (privileges & ~3)"
	} else if data.Allowed == 1 {
		banDatetime = 0
		privsSet = "privileges = (privileges | 3)"
	} else if data.Allowed == 2 {
		banDatetime = time.Now().Unix()
		privsSet = "privileges = (privileges | 2) & (privileges & ~1)"
	}
	_, err := md.DB.Exec("UPDATE users SET "+privsSet+", ban_datetime = ? WHERE id = ?", banDatetime, data.UserID)
	if err != nil {
		md.Err(err)
		return Err500
	}
	rapLog(md, fmt.Sprintf("changed UserID:%d's allowed to %d. This was done using the API's terrible ManageSetAllowed.", data.UserID, data.Allowed))
	go fixPrivileges(data.UserID, md.DB)
	query := `
SELECT users.id, users.username, register_datetime, privileges,
	latest_activity, users_stats.username_aka,
	users_stats.country
FROM users
LEFT JOIN users_stats
ON users.id=users_stats.id
WHERE users.id=?
LIMIT 1`
	return userPutsSingle(md, md.DB.QueryRowx(query, data.UserID))
}

type userEditData struct {
	ID            int          `json:"id"`
	Username      *string      `json:"username"`
	UsernameAKA   *string      `json:"username_aka"`
	Privileges    *uint64      `json:"privileges"`
	Country       *string      `json:"country"`
	SilenceInfo   *silenceInfo `json:"silence_info"`
	ResetUserpage bool         `json:"reset_userpage"`
	//ResetAvatar bool `json:"reset_avatar"`
}

var privChangeList = [...]string{
	"banned",
	"locked",
	"restricted",
	"removed all restrictions on",
}

// UserEditPOST allows to edit an user's information.
func UserEditPOST(md common.MethodData) common.CodeMessager {
	var data userEditData
	if err := md.Unmarshal(&data); err != nil {
		fmt.Println(err)
		return ErrBadJSON
	}

	if data.ID == 0 {
		return common.SimpleResponse(404, "That user could not be found")
	}

	var prevUser struct {
		Username   string
		Privileges uint64
	}
	err := md.DB.Get(&prevUser, "SELECT username, privileges FROM users WHERE id = ? LIMIT 1", data.ID)

	switch err {
	case nil: // carry on
	case sql.ErrNoRows:
		return common.SimpleResponse(404, "That user could not be found")
	default:
		md.Err(err)
		return Err500
	}

	const initQuery = "UPDATE users SET\n"
	q := initQuery
	var args []interface{}

	// totally did not realise I had to update some fields in users_stats as well
	// and just copy pasting the above code by prefixing "stats" to every
	// variable
	const statsInitQuery = "UPDATE users_stats SET\n"
	statsQ := statsInitQuery
	var statsArgs []interface{}

	if common.UserPrivileges(prevUser.Privileges)&common.AdminPrivilegeManageUsers != 0 &&
		data.ID != md.User.UserID {
		return common.SimpleResponse(403, "Can't edit that user")
	}

	var isBanned bool
	var isSilenced bool
	if data.Privileges != nil {
		// If we want to modify privileges other than Normal/Public, we need to have
		// the right privilege ourselves and AdminManageUsers won't suffice.
		if (*data.Privileges&^3) != (prevUser.Privileges&^3) &&
			md.User.UserPrivileges&common.AdminPrivilegeManagePrivilege == 0 {
			return common.SimpleResponse(403, "Can't modify user privileges without AdminManagePrivileges")
		}
		q += "privileges = ?,\n"
		args = append(args, *data.Privileges)

		// UserPublic became 0, so banned or restricted
		const uPublic = uint64(common.UserPrivilegePublic)
		if *data.Privileges&uPublic == 0 && prevUser.Privileges&uPublic != 0 {
			q += "ban_datetime = ?,\n"
			args = append(args, time.Now().Unix())
			isBanned = true
		}

		// If we modified other privileges apart from Normal and Public, we use a generic
		// "changed user's privileges". Otherwise, we are more descriptive.
		if *data.Privileges^prevUser.Privileges > 3 {
			rapLog(md, fmt.Sprintf("has changed %s's privileges", prevUser.Username))
		} else {
			rapLog(md, fmt.Sprintf("has %s %s", privChangeList[*data.Privileges&3], prevUser.Username))
		}
	}
	if data.Username != nil {
		if strings.Contains(*data.Username, " ") && strings.Contains(*data.Username, "_") {
			return common.SimpleResponse(400, "Mixed spaces and underscores")
		}
		if usernameAvailable(md, *data.Username, data.ID) {
			return common.SimpleResponse(409, "User with that username exists")
		}
		jsonData, _ := json.Marshal(struct {
			UserID      int    `json:"userID"`
			NewUsername string `json:"newUsername"`
		}{data.ID, *data.Username})
		md.R.Publish("peppy:change_username", string(jsonData))
	}
	if data.UsernameAKA != nil {
		statsQ += "username_aka = ?,\n"
		statsArgs = append(statsArgs, *data.UsernameAKA)
	}
	if data.Country != nil {
		statsQ += "country = ?,\n"
		statsArgs = append(statsArgs, *data.Country)
		rapLog(md, fmt.Sprintf("has changed %s country to %s", prevUser.Username, *data.Country))
		appendToUserNotes(md, "country changed to "+*data.Country, data.ID)
	}
	if data.SilenceInfo != nil && md.User.UserPrivileges&common.AdminPrivilegeSilenceUsers != 0 {
		q += "silence_end = ?, silence_reason = ?,\n"
		args = append(args, time.Time(data.SilenceInfo.End).Unix(), data.SilenceInfo.Reason)
		isSilenced = true
	}
	if data.ResetUserpage {
		statsQ += "userpage_content = '',\n"
	}

	if q != initQuery {
		q = q[:len(q)-2] + " WHERE id = ? LIMIT 1"
		args = append(args, data.ID)
		_, err = md.DB.Exec(q, args...)
		if err != nil {
			md.Err(err)
			return Err500
		}

	}
	if statsQ != statsInitQuery {
		statsQ = statsQ[:len(statsQ)-2] + " WHERE id = ? LIMIT 1"
		statsArgs = append(statsArgs, data.ID)
		_, err = md.DB.Exec(statsQ, statsArgs...)
		if err != nil {
			md.Err(err)
			return Err500
		}
	}

	if isBanned || isSilenced {
		if err := updateBanBancho(md.R, data.ID); err != nil {
			md.Err(err)
			return Err500
		}
	}

	rapLog(md, fmt.Sprintf("has updated user %s", prevUser.Username))

	return userPutsSingle(md, md.DB.QueryRowx(userFields+" WHERE users.id = ? LIMIT 1", data.ID))
}

func updateBanBancho(r *redis.Client, user int) error {
	return r.Publish("peppy:ban", strconv.Itoa(user)).Err()
}

type wipeUserData struct {
	ID    int   `json:"id"`
	Modes []int `json:"modes"`
	Relax int   `json:"relax"`
}

// WipeUserPOST wipes an user's scores.
func WipeUserPOST(md common.MethodData) common.CodeMessager {
	data := wipeUserData{
		// Wipe both classic & relax by default
		Relax: -1,
	}
	if err := md.Unmarshal(&data); err != nil {
		return ErrBadJSON
	}
	if data.ID == 0 {
		return ErrMissingField("id")
	}
	if len(data.Modes) == 0 {
		return ErrMissingField("modes")
	}

	var userData struct {
		Username   string
		Privileges uint64
	}
	err := md.DB.Get(&userData, "SELECT username, privileges FROM users WHERE id = ?", data.ID)
	switch err {
	case sql.ErrNoRows:
		return common.SimpleResponse(404, "That user could not be found!")
	case nil: // carry on
	default:
		md.Err(err)
		return Err500
	}

	/*if common.UserPrivileges(userData.Privileges)&common.AdminPrivilegeManageUsers != 0 {
		return common.SimpleResponse(403, "Can't edit that user")
	}*/

	tx, err := md.DB.Beginx()
	if err != nil {
		md.Err(err)
		return Err500
	}

	for _, mode := range data.Modes {
		if mode < 0 || mode > 3 {
			continue
		}
		var suffix string
		if data.Relax > -1 {
			suffix = fmt.Sprintf("AND is_relax = %d", data.Relax)
		}
		_, err = tx.Exec("INSERT INTO scores_removed SELECT * FROM scores WHERE userid = ? AND play_mode = ? "+suffix, data.ID, mode)
		if err != nil {
			md.Err(err)
		}
		_, err = tx.Exec("DELETE FROM scores WHERE userid = ? AND play_mode = ? "+suffix, data.ID, mode)
		if err != nil {
			md.Err(err)
		}
		if data.Relax <= 0 {
			// Wipe classic stats
			_, err = tx.Exec(strings.Replace(
				`UPDATE users_stats SET total_score_MODE = 0, ranked_score_MODE = 0, replays_watched_MODE = 0,
				playcount_MODE = 0, avg_accuracy_MODE = 0, total_hits_MODE = 0, level_MODE = 0, pp_MODE = 0
				WHERE id = ?`, "MODE", modesToReadable[mode], -1,
			), data.ID)
			if err != nil {
				md.Err(err)
			}
		}
		if data.Relax < 0 || data.Relax == 1 {
			// Wipe relax stats
			_, err = tx.Exec(strings.Replace(
				`UPDATE users_stats_relax SET total_score_MODE = 0, ranked_score_MODE = 0,
				playcount_MODE = 0, avg_accuracy_MODE = 0, total_hits_MODE = 0, level_MODE = 0, pp_MODE = 0
				WHERE id = ?`, "MODE", modesToReadable[mode], -1,
			), data.ID)
			if err != nil {
				md.Err(err)
			}
		}
		_, err = tx.Exec("DELETE FROM users_beatmap_playcount WHERE user_id = ? AND game_mode = ?", data.ID, mode)
		if err != nil {
			md.Err(err)
		}
	}

	if err = tx.Commit(); err != nil {
		md.Err(err)
		return Err500
	}

	rapLog(md, fmt.Sprintf("has wiped %s's account", userData.Username))

	return userPutsSingle(md, md.DB.QueryRowx(userFields+" WHERE users.id = ? LIMIT 1", data.ID))
}

func appendToUserNotes(md common.MethodData, message string, user int) {
	message = "\n[" + time.Now().Format("2006-01-02 15:04:05") + "] API: " + message
	_, err := md.DB.Exec("UPDATE users SET notes = CONCAT(COALESCE(notes, ''), ?) WHERE id = ?",
		message, user)
	if err != nil {
		md.Err(err)
	}
}

func usernameAvailable(md common.MethodData, u string, userID int) (r bool) {
	err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE username_safe = ? AND id != ?)", common.SafeUsername(u), userID).Scan(&r)
	if err != nil && err != sql.ErrNoRows {
		md.Err(err)
	}
	return
}
<commit_msg>Accidental comment<commit_after>package v1

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	redis "gopkg.in/redis.v5"
	"zxq.co/ripple/rippleapi/common"
)

type setAllowedData struct {
	UserID  int `json:"user_id"`
	Allowed int `json:"allowed"`
}

// UserManageSetAllowedPOST allows to set the allowed status of an user.
func UserManageSetAllowedPOST(md common.MethodData) common.CodeMessager {
	var data setAllowedData
	if err := md.Unmarshal(&data); err != nil {
		return ErrBadJSON
	}
	if data.Allowed < 0 || data.Allowed > 2 {
		return common.SimpleResponse(400, "Allowed status must be between 0 and 2")
	}
	var banDatetime int64
	var privsSet string
	if data.Allowed == 0 {
		banDatetime = time.Now().Unix()
		privsSet = "privileges = (privileges & ~3)"
	} else if data.Allowed == 1 {
		banDatetime = 0
		privsSet = "privileges = (privileges | 3)"
	} else if data.Allowed == 2 {
		banDatetime = time.Now().Unix()
		privsSet = "privileges = (privileges | 2) & (privileges & ~1)"
	}
	_, err := md.DB.Exec("UPDATE users SET "+privsSet+", ban_datetime = ? WHERE id = ?", banDatetime, data.UserID)
	if err != nil {
		md.Err(err)
		return Err500
	}
	rapLog(md, fmt.Sprintf("changed UserID:%d's allowed to %d. This was done using the API's terrible ManageSetAllowed.", data.UserID, data.Allowed))
	go fixPrivileges(data.UserID, md.DB)
	query := `
SELECT users.id, users.username, register_datetime, privileges,
	latest_activity, users_stats.username_aka,
	users_stats.country
FROM users
LEFT JOIN users_stats
ON users.id=users_stats.id
WHERE users.id=?
LIMIT 1`
	return userPutsSingle(md, md.DB.QueryRowx(query, data.UserID))
}

type userEditData struct {
	ID            int          `json:"id"`
	Username      *string      `json:"username"`
	UsernameAKA   *string      `json:"username_aka"`
	Privileges    *uint64      `json:"privileges"`
	Country       *string      `json:"country"`
	SilenceInfo   *silenceInfo `json:"silence_info"`
	ResetUserpage bool         `json:"reset_userpage"`
	//ResetAvatar bool `json:"reset_avatar"`
}

var privChangeList = [...]string{
	"banned",
	"locked",
	"restricted",
	"removed all restrictions on",
}

// UserEditPOST allows to edit an user's information.
func UserEditPOST(md common.MethodData) common.CodeMessager {
	var data userEditData
	if err := md.Unmarshal(&data); err != nil {
		fmt.Println(err)
		return ErrBadJSON
	}

	if data.ID == 0 {
		return common.SimpleResponse(404, "That user could not be found")
	}

	var prevUser struct {
		Username   string
		Privileges uint64
	}
	err := md.DB.Get(&prevUser, "SELECT username, privileges FROM users WHERE id = ? LIMIT 1", data.ID)

	switch err {
	case nil: // carry on
	case sql.ErrNoRows:
		return common.SimpleResponse(404, "That user could not be found")
	default:
		md.Err(err)
		return Err500
	}

	const initQuery = "UPDATE users SET\n"
	q := initQuery
	var args []interface{}

	// totally did not realise I had to update some fields in users_stats as well
	// and just copy pasting the above code by prefixing "stats" to every
	// variable
	const statsInitQuery = "UPDATE users_stats SET\n"
	statsQ := statsInitQuery
	var statsArgs []interface{}

	if common.UserPrivileges(prevUser.Privileges)&common.AdminPrivilegeManageUsers != 0 &&
		data.ID != md.User.UserID {
		return common.SimpleResponse(403, "Can't edit that user")
	}

	var isBanned bool
	var isSilenced bool
	if data.Privileges != nil {
		// If we want to modify privileges other than Normal/Public, we need to have
		// the right privilege ourselves and AdminManageUsers won't suffice.
		if (*data.Privileges&^3) != (prevUser.Privileges&^3) &&
			md.User.UserPrivileges&common.AdminPrivilegeManagePrivilege == 0 {
			return common.SimpleResponse(403, "Can't modify user privileges without AdminManagePrivileges")
		}
		q += "privileges = ?,\n"
		args = append(args, *data.Privileges)

		// UserPublic became 0, so banned or restricted
		const uPublic = uint64(common.UserPrivilegePublic)
		if *data.Privileges&uPublic == 0 && prevUser.Privileges&uPublic != 0 {
			q += "ban_datetime = ?,\n"
			args = append(args, time.Now().Unix())
			isBanned = true
		}

		// If we modified other privileges apart from Normal and Public, we use a generic
		// "changed user's privileges". Otherwise, we are more descriptive.
		if *data.Privileges^prevUser.Privileges > 3 {
			rapLog(md, fmt.Sprintf("has changed %s's privileges", prevUser.Username))
		} else {
			rapLog(md, fmt.Sprintf("has %s %s", privChangeList[*data.Privileges&3], prevUser.Username))
		}
	}
	if data.Username != nil {
		if strings.Contains(*data.Username, " ") && strings.Contains(*data.Username, "_") {
			return common.SimpleResponse(400, "Mixed spaces and underscores")
		}
		if usernameAvailable(md, *data.Username, data.ID) {
			return common.SimpleResponse(409, "User with that username exists")
		}
		jsonData, _ := json.Marshal(struct {
			UserID      int    `json:"userID"`
			NewUsername string `json:"newUsername"`
		}{data.ID, *data.Username})
		md.R.Publish("peppy:change_username", string(jsonData))
	}
	if data.UsernameAKA != nil {
		statsQ += "username_aka = ?,\n"
		statsArgs = append(statsArgs, *data.UsernameAKA)
	}
	if data.Country != nil {
		statsQ += "country = ?,\n"
		statsArgs = append(statsArgs, *data.Country)
		rapLog(md, fmt.Sprintf("has changed %s country to %s", prevUser.Username, *data.Country))
		appendToUserNotes(md, "country changed to "+*data.Country, data.ID)
	}
	if data.SilenceInfo != nil && md.User.UserPrivileges&common.AdminPrivilegeSilenceUsers != 0 {
		q += "silence_end = ?, silence_reason = ?,\n"
		args = append(args, time.Time(data.SilenceInfo.End).Unix(), data.SilenceInfo.Reason)
		isSilenced = true
	}
	if data.ResetUserpage {
		statsQ += "userpage_content = '',\n"
	}

	if q != initQuery {
		q = q[:len(q)-2] + " WHERE id = ? LIMIT 1"
		args = append(args, data.ID)
		_, err = md.DB.Exec(q, args...)
		if err != nil {
			md.Err(err)
			return Err500
		}

	}
	if statsQ != statsInitQuery {
		statsQ = statsQ[:len(statsQ)-2] + " WHERE id = ? LIMIT 1"
		statsArgs = append(statsArgs, data.ID)
		_, err = md.DB.Exec(statsQ, statsArgs...)
		if err != nil {
			md.Err(err)
			return Err500
		}
	}

	if isBanned || isSilenced {
		if err := updateBanBancho(md.R, data.ID); err != nil {
			md.Err(err)
			return Err500
		}
	}

	rapLog(md, fmt.Sprintf("has updated user %s", prevUser.Username))

	return userPutsSingle(md, md.DB.QueryRowx(userFields+" WHERE users.id = ? LIMIT 1", data.ID))
}

func updateBanBancho(r *redis.Client, user int) error {
	return r.Publish("peppy:ban", strconv.Itoa(user)).Err()
}

type wipeUserData struct {
	ID    int   `json:"id"`
	Modes []int `json:"modes"`
	Relax int   `json:"relax"`
}

// WipeUserPOST wipes an user's scores.
func WipeUserPOST(md common.MethodData) common.CodeMessager {
	data := wipeUserData{
		// Wipe both classic & relax by default
		Relax: -1,
	}
	if err := md.Unmarshal(&data); err != nil {
		return ErrBadJSON
	}
	if data.ID == 0 {
		return ErrMissingField("id")
	}
	if len(data.Modes) == 0 {
		return ErrMissingField("modes")
	}

	var userData struct {
		Username   string
		Privileges uint64
	}
	err := md.DB.Get(&userData, "SELECT username, privileges FROM users WHERE id = ?", data.ID)
	switch err {
	case sql.ErrNoRows:
		return common.SimpleResponse(404, "That user could not be found!")
	case nil: // carry on
	default:
		md.Err(err)
		return Err500
	}

	if common.UserPrivileges(userData.Privileges)&common.AdminPrivilegeManageUsers != 0 {
		return common.SimpleResponse(403, "Can't edit that user")
	}

	tx, err := md.DB.Beginx()
	if err != nil {
		md.Err(err)
		return Err500
	}

	for _, mode := range data.Modes {
		if mode < 0 || mode > 3 {
			continue
		}
		var suffix string
		if data.Relax > -1 {
			suffix = fmt.Sprintf("AND is_relax = %d", data.Relax)
		}
		_, err = tx.Exec("INSERT INTO scores_removed SELECT * FROM scores WHERE userid = ? AND play_mode = ? "+suffix, data.ID, mode)
		if err != nil {
			md.Err(err)
		}
		_, err = tx.Exec("DELETE FROM scores WHERE userid = ? AND play_mode = ? "+suffix, data.ID, mode)
		if err != nil {
			md.Err(err)
		}
		if data.Relax <= 0 {
			// Wipe classic stats
			_, err = tx.Exec(strings.Replace(
				`UPDATE users_stats SET total_score_MODE = 0, ranked_score_MODE = 0, replays_watched_MODE = 0,
				playcount_MODE = 0, avg_accuracy_MODE = 0, total_hits_MODE = 0, level_MODE = 0, pp_MODE = 0
				WHERE id = ?`, "MODE", modesToReadable[mode], -1,
			), data.ID)
			if err != nil {
				md.Err(err)
			}
		}
		if data.Relax < 0 || data.Relax == 1 {
			// Wipe relax stats
			_, err = tx.Exec(strings.Replace(
				`UPDATE users_stats_relax SET total_score_MODE = 0, ranked_score_MODE = 0,
				playcount_MODE = 0, avg_accuracy_MODE = 0, total_hits_MODE = 0, level_MODE = 0, pp_MODE = 0
				WHERE id = ?`, "MODE", modesToReadable[mode], -1,
			), data.ID)
			if err != nil {
				md.Err(err)
			}
		}
		_, err = tx.Exec("DELETE FROM users_beatmap_playcount WHERE user_id = ? AND game_mode = ?", data.ID, mode)
		if err != nil {
			md.Err(err)
		}
	}

	if err = tx.Commit(); err != nil {
		md.Err(err)
		return Err500
	}

	rapLog(md, fmt.Sprintf("has wiped %s's account", userData.Username))

	return userPutsSingle(md, md.DB.QueryRowx(userFields+" WHERE users.id = ? LIMIT 1", data.ID))
}

func appendToUserNotes(md common.MethodData, message string, user int) {
	message = "\n[" + time.Now().Format("2006-01-02 15:04:05") + "] API: " + message
	_, err := md.DB.Exec("UPDATE users SET notes = CONCAT(COALESCE(notes, ''), ?) WHERE id = ?",
		message, user)
	if err != nil {
		md.Err(err)
	}
}

func usernameAvailable(md common.MethodData, u string, userID int) (r bool) {
	err := md.DB.QueryRow("SELECT EXISTS(SELECT 1 FROM users WHERE username_safe = ? AND id != ?)", common.SafeUsername(u), userID).Scan(&r)
	if err != nil && err != sql.ErrNoRows {
		md.Err(err)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/nsf/termbox-go"
)

type Modeline struct {
	// dimensions
	x, y, w int

	// feedback for user
	paused bool

	// user input
	input *Editbox
}

func NewModeline(x, y, w int) *Modeline {
	e := new(Editbox)
	return &Modeline{x, y, w, false, e}
}

func (results *ResultsView) Summarize(paused bool) string {
	sel := results.result_selected + 1
	if results.result_count == 0 {
		sel = 0
	}

	s := fmt.Sprintf("(%d/%d", sel, results.result_count)
	if paused {
		s += " paused"
	}
	s += ")"
	return s
}

func (m *Modeline) Draw(results *ResultsView) {
	coldef := termbox.ColorDefault
	spaceForCursor := 2
	summary := results.Summarize(m.paused)

	tbprint(m.w-len(summary), m.y, termbox.ColorCyan|termbox.AttrBold, coldef, summary)

	// modeline.Draw(2, , w-2, 1)
	spaceLeft := m.w - spaceForCursor - len(summary)
	m.input.Draw(m.x+spaceForCursor, m.y, spaceLeft)
	termbox.SetCell(0, m.y, '>', coldef, coldef)
	termbox.SetCursor(spaceForCursor+m.input.CursorX(), m.y)
}

func (m *Modeline) Contents() string {
	return string(m.input.text)
}

func (m *Modeline) Pause() {
	m.paused = true
}
func (m *Modeline) Unpause() {
	m.paused = false
}
<commit_msg>no printing<commit_after>package main

import (
	"fmt"

	"github.com/nsf/termbox-go"
)

type Modeline struct {
	// dimensions
	x, y, w int

	// feedback for user
	paused bool

	// user input
	input *Editbox
}

func NewModeline(x, y, w int) *Modeline {
	e := new(Editbox)
	return &Modeline{x, y, w, false, e}
}

func (results *ResultsView) Summarize(paused bool) string {
	sel := results.result_selected + 1
	if results.result_count == 0 {
		sel = 0
	}

	s := fmt.Sprintf("(%d/%d", sel, results.result_count)
	if paused {
		s += " paused"
	}
	s += ")"
	return s
}

func (m *Modeline) Draw(results *ResultsView) {
	coldef := termbox.ColorDefault
	spaceForCursor := 2
	summary := results.Summarize(m.paused)

	tbprint(m.w-len(summary), m.y, termbox.ColorCyan|termbox.AttrBold, coldef, summary)

	// modeline.Draw(2, , w-2, 1)
	spaceLeft := m.w - spaceForCursor - len(summary)
	m.input.Draw(m.x+spaceForCursor, m.y, spaceLeft)
	termbox.SetCell(0, m.y, '>', coldef, coldef)
	termbox.SetCursor(spaceForCursor+m.input.CursorX(), m.y)
}

func (m *Modeline) Contents() string {
	return string(m.input.text).ToLower()
}

func (m *Modeline) Pause() {
	m.paused = true
}
func (m *Modeline) Unpause() {
	m.paused = false
}
<|endoftext|>


<commit_before><commit_msg>neutrino: exclude peers that do not support our required services<commit_after><|endoftext|>


<commit_before>package broker

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/gdamore/mangos"
	"github.com/gdamore/mangos/protocol/req"
	"github.com/gdamore/mangos/transport/tcp"
)

type operation string
type daemon string

const (
	minNumMessages             = 100
	minMessageSize             = 9
	start            operation = "start"
	stop             operation = "stop"
	sub              operation = "subscribers"
	pub              operation = "publishers"
	run              operation = "run"
	results          operation = "results"
	teardown         operation = "teardown"
	resultsSleep               = time.Second
	sendRecvDeadline           = 5 * time.Second
)

type request struct {
	Operation   operation `json:"operation"`
	Broker      string    `json:"broker"`
	Port        string    `json:"port"`
	NumMessages uint      `json:"num_messages"`
	MessageSize uint64    `json:"message_size"`
	Count       uint      `json:"count"`
	Host        string    `json:"host"`
}

type response struct {
	Success    bool        `json:"success"`
	Message    string      `json:"message"`
	Result     interface{} `json:"result"`
	PubResults []*Result   `json:"pub_results,omitempty"`
	SubResults []*Result   `json:"sub_results,omitempty"`
}

// Benchmark contains configuration settings for broker tests.
type Benchmark struct {
	BrokerdHost   string
	BrokerName    string
	BrokerHost    string
	BrokerPort    string
	PeerHosts     []string
	NumMessages   uint
	MessageSize   uint64
	Publishers    uint
	Subscribers   uint
	StartupSleep  uint
	DaemonTimeout uint
}

func (b *Benchmark) validate() error {
	if b.BrokerdHost == "" {
		return errors.New("Invalid broker daemon host")
	}

	if b.BrokerName == "" {
		return errors.New("Invalid broker name")
	}

	if b.BrokerHost == "" {
		return errors.New("Invalid broker host")
	}

	if b.BrokerPort == "" {
		return errors.New("Invalid broker port")
	}

	if len(b.PeerHosts) == 0 {
		return errors.New("Must provide at least one peer host")
	}

	if b.NumMessages < minNumMessages {
		return fmt.Errorf("Number of messages must be at least %d", minNumMessages)
	}

	if b.MessageSize < minMessageSize {
		return fmt.Errorf("Message size must be at least %d", minMessageSize)
	}

	if b.Publishers <= 0 {
		return errors.New("Number of producers must be greater than zero")
	}

	if b.Subscribers <= 0 {
		return errors.New("Number of consumers must be greater than zero")
	}

	return nil
}

// Result contains test result data for a single peer.
type Result struct {
	Duration   float32        `json:"duration,omitempty"`
	Throughput float32        `json:"throughput,omitempty"`
	Latency    LatencyResults `json:"latency,omitempty"`
	Err        string         `json:"error"`
}

// ResultContainer contains the Results for a single node.
type ResultContainer struct {
	Peer              string
	PublisherResults  []*Result
	SubscriberResults []*Result
}

// LatencyResults contains the latency result data for a single peer.
type LatencyResults struct {
	Min    int64   `json:"min"`
	Q1     int64   `json:"q1"`
	Q2     int64   `json:"q2"`
	Q3     int64   `json:"q3"`
	Max    int64   `json:"max"`
	Mean   float64 `json:"mean"`
	StdDev float64 `json:"std_dev"`
}

// Client provides an API for interacting with Flotilla.
type Client struct {
	brokerd   mangos.Socket
	peerd     map[string]mangos.Socket
	Benchmark *Benchmark
}

// NewClient creates and returns a new Client from the provided Benchmark
// configuration. It returns an error if the Benchmark is not valid or it
// can't communicate with any of the specified peers.
func NewClient(b *Benchmark) (*Client, error) {
	if err := b.validate(); err != nil {
		return nil, err
	}

	brokerd, err := req.NewSocket()
	if err != nil {
		return nil, err
	}

	brokerd.AddTransport(tcp.NewTransport())
	brokerd.SetOption(mangos.OptionSendDeadline, time.Duration(b.DaemonTimeout)*time.Second)
	brokerd.SetOption(mangos.OptionRecvDeadline, time.Duration(b.DaemonTimeout)*time.Second)

	if err := brokerd.Dial(fmt.Sprintf("tcp://%s", b.BrokerdHost)); err != nil {
		return nil, err
	}

	peerd := make(map[string]mangos.Socket, len(b.PeerHosts))
	for _, peer := range b.PeerHosts {
		s, err := req.NewSocket()
		if err != nil {
			return nil, err
		}

		s.AddTransport(tcp.NewTransport())
		s.SetOption(mangos.OptionSendDeadline, time.Duration(b.DaemonTimeout)*time.Second)
		s.SetOption(mangos.OptionRecvDeadline, time.Duration(b.DaemonTimeout)*time.Second)

		if err := s.Dial(fmt.Sprintf("tcp://%s", peer)); err != nil {
			return nil, err
		}

		peerd[peer] = s
	}

	return &Client{
		brokerd:   brokerd,
		peerd:     peerd,
		Benchmark: b,
	}, nil
}

// Start begins the broker test.
func (c *Client) Start() ([]*ResultContainer, error) {
	fmt.Println("Starting broker - if the image hasn't been pulled yet, this may take a while...")
	if err := c.startBroker(); err != nil {
		return nil, fmt.Errorf("Failed to start broker: %s", err.Error())
	}

	// Allow some time for broker startup.
	time.Sleep(time.Duration(c.Benchmark.StartupSleep) * time.Second)

	fmt.Println("Preparing producers")
	if err := c.startPublishers(); err != nil {
		return nil, fmt.Errorf("Failed to start producers: %s", err.Error())
	}

	fmt.Println("Preparing consumers")
	if err := c.startSubscribers(); err != nil {
		return nil, fmt.Errorf("Failed to start consumers %s:", err.Error())
	}

	fmt.Println("Running benchmark")
	if err := c.runBenchmark(); err != nil {
		return nil, fmt.Errorf("Failed to run benchmark %s:", err.Error())
	}

	return <-c.collectResults(), nil
}

func (c *Client) startBroker() error {
	resp, err := sendRequest(c.brokerd, request{
		Operation: start,
		Broker:    c.Benchmark.BrokerName,
		Host:      c.Benchmark.BrokerHost,
		Port:      c.Benchmark.BrokerPort,
	})

	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Message)
	}

	return nil
}

func (c *Client) startSubscribers() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{
			Operation:   sub,
			Broker:      c.Benchmark.BrokerName,
			Host:        fmt.Sprintf("%s:%s", c.Benchmark.BrokerHost, c.Benchmark.BrokerPort),
			Count:       c.Benchmark.Subscribers,
			NumMessages: c.Benchmark.NumMessages,
			MessageSize: c.Benchmark.MessageSize,
		})

		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) startPublishers() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{
			Operation:   pub,
			Broker:      c.Benchmark.BrokerName,
			Host:        fmt.Sprintf("%s:%s", c.Benchmark.BrokerHost, c.Benchmark.BrokerPort),
			Count:       c.Benchmark.Publishers,
			NumMessages: c.Benchmark.NumMessages,
			MessageSize: c.Benchmark.MessageSize,
		})

		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) runBenchmark() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{Operation: run})
		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) collectResults() <-chan []*ResultContainer {
	resultsChan := make(chan []*ResultContainer, 1)

	go func(chan<- []*ResultContainer) {
		results := make([]*ResultContainer, 0, len(c.peerd))
		subResults := make(chan *ResultContainer, len(c.peerd))
		complete := 0

		for host, peerd := range c.peerd {
			go collectResultsFromPeer(host, peerd, subResults)
		}

		for {
			select {
			case subResult, ok := <-subResults:
				if !ok {
					return
				}
				results = append(results, subResult)
				complete++
			}

			if complete == len(c.peerd) {
				resultsChan <- results
				return
			}
		}
	}(resultsChan)

	return resultsChan
}

// Teardown performs any necessary cleanup logic, including stopping the
// broker and tearing down peers.
func (c *Client) Teardown() {
	fmt.Println("Tearing down peers")
	for _, peerd := range c.peerd {
		_, err := sendRequest(peerd, request{Operation: teardown})
		if err != nil {
			fmt.Printf("Failed to teardown peer: %s\n", err.Error())
		}
	}

	fmt.Println("Stopping broker")
	if err := c.stopBroker(); err != nil {
		fmt.Printf("Failed to stop broker: %s\n", err.Error())
	}
}

func (c *Client) stopBroker() error {
	resp, err := sendRequest(c.brokerd, request{Operation: stop})
	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Message)
	}

	return nil
}

func sendRequest(s mangos.Socket, request request) (*response, error) {
	fmt.Println("Sending a request")

	requestJSON, err := json.Marshal(request)
	if err != nil {
		// This is not recoverable.
		panic(err)
	}

	fmt.Printf("sendRequest: %s\n", requestJSON)

	if err := s.Send(requestJSON); err != nil {
		return nil, err
	}

	rep, err := s.Recv()
	if err != nil {
		return nil, err
	}

	var resp response
	if err := json.Unmarshal(rep, &resp); err != nil {
		return nil, err
	}

	return &resp, nil
}

func collectResultsFromPeer(host string, peerd mangos.Socket, subResults chan *ResultContainer) {
	for {
		resp, err := sendRequest(peerd, request{Operation: results})
		if err != nil {
			fmt.Println("Failed to collect results from peer:", err.Error())
			close(subResults)
			return
		}

		if !resp.Success {
			fmt.Printf("Failed to collect results from peer: %s", resp.Message)
			subResults <- nil
		}

		if resp.Message == "Results not ready" {
			time.Sleep(resultsSleep)
			continue
		}

		subResults <- &ResultContainer{
			Peer:              host,
			PublisherResults:  resp.PubResults,
			SubscriberResults: resp.SubResults,
		}
		break
	}
}
<commit_msg>Modified the code to ignore result from startBroker call, since broker is actually started.<commit_after>package broker

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"github.com/gdamore/mangos"
	"github.com/gdamore/mangos/protocol/req"
	"github.com/gdamore/mangos/transport/tcp"
)

type operation string
type daemon string

const (
	minNumMessages             = 100
	minMessageSize             = 9
	start            operation = "start"
	stop             operation = "stop"
	sub              operation = "subscribers"
	pub              operation = "publishers"
	run              operation = "run"
	results          operation = "results"
	teardown         operation = "teardown"
	resultsSleep               = time.Second
	sendRecvDeadline           = 5 * time.Second
)

type request struct {
	Operation   operation `json:"operation"`
	Broker      string    `json:"broker"`
	Port        string    `json:"port"`
	NumMessages uint      `json:"num_messages"`
	MessageSize uint64    `json:"message_size"`
	Count       uint      `json:"count"`
	Host        string    `json:"host"`
}

type response struct {
	Success    bool        `json:"success"`
	Message    string      `json:"message"`
	Result     interface{} `json:"result"`
	PubResults []*Result   `json:"pub_results,omitempty"`
	SubResults []*Result   `json:"sub_results,omitempty"`
}

// Benchmark contains configuration settings for broker tests.
type Benchmark struct {
	BrokerdHost   string
	BrokerName    string
	BrokerHost    string
	BrokerPort    string
	PeerHosts     []string
	NumMessages   uint
	MessageSize   uint64
	Publishers    uint
	Subscribers   uint
	StartupSleep  uint
	DaemonTimeout uint
}

func (b *Benchmark) validate() error {
	if b.BrokerdHost == "" {
		return errors.New("Invalid broker daemon host")
	}

	if b.BrokerName == "" {
		return errors.New("Invalid broker name")
	}

	if b.BrokerHost == "" {
		return errors.New("Invalid broker host")
	}

	if b.BrokerPort == "" {
		return errors.New("Invalid broker port")
	}

	if len(b.PeerHosts) == 0 {
		return errors.New("Must provide at least one peer host")
	}

	if b.NumMessages < minNumMessages {
		return fmt.Errorf("Number of messages must be at least %d", minNumMessages)
	}

	if b.MessageSize < minMessageSize {
		return fmt.Errorf("Message size must be at least %d", minMessageSize)
	}

	if b.Publishers <= 0 {
		return errors.New("Number of producers must be greater than zero")
	}

	if b.Subscribers <= 0 {
		return errors.New("Number of consumers must be greater than zero")
	}

	return nil
}

// Result contains test result data for a single peer.
type Result struct {
	Duration   float32        `json:"duration,omitempty"`
	Throughput float32        `json:"throughput,omitempty"`
	Latency    LatencyResults `json:"latency,omitempty"`
	Err        string         `json:"error"`
}

// ResultContainer contains the Results for a single node.
type ResultContainer struct {
	Peer              string
	PublisherResults  []*Result
	SubscriberResults []*Result
}

// LatencyResults contains the latency result data for a single peer.
type LatencyResults struct {
	Min    int64   `json:"min"`
	Q1     int64   `json:"q1"`
	Q2     int64   `json:"q2"`
	Q3     int64   `json:"q3"`
	Max    int64   `json:"max"`
	Mean   float64 `json:"mean"`
	StdDev float64 `json:"std_dev"`
}

// Client provides an API for interacting with Flotilla.
type Client struct {
	brokerd   mangos.Socket
	peerd     map[string]mangos.Socket
	Benchmark *Benchmark
}

// NewClient creates and returns a new Client from the provided Benchmark
// configuration. It returns an error if the Benchmark is not valid or it
// can't communicate with any of the specified peers.
func NewClient(b *Benchmark) (*Client, error) {
	if err := b.validate(); err != nil {
		return nil, err
	}

	brokerd, err := req.NewSocket()
	if err != nil {
		return nil, err
	}

	brokerd.AddTransport(tcp.NewTransport())
	brokerd.SetOption(mangos.OptionSendDeadline, time.Duration(b.DaemonTimeout)*time.Second)
	brokerd.SetOption(mangos.OptionRecvDeadline, time.Duration(b.DaemonTimeout)*time.Second)

	if err := brokerd.Dial(fmt.Sprintf("tcp://%s", b.BrokerdHost)); err != nil {
		return nil, err
	}

	peerd := make(map[string]mangos.Socket, len(b.PeerHosts))
	for _, peer := range b.PeerHosts {
		s, err := req.NewSocket()
		if err != nil {
			return nil, err
		}

		s.AddTransport(tcp.NewTransport())
		s.SetOption(mangos.OptionSendDeadline, time.Duration(b.DaemonTimeout)*time.Second)
		s.SetOption(mangos.OptionRecvDeadline, time.Duration(b.DaemonTimeout)*time.Second)

		if err := s.Dial(fmt.Sprintf("tcp://%s", peer)); err != nil {
			return nil, err
		}

		peerd[peer] = s
	}

	return &Client{
		brokerd:   brokerd,
		peerd:     peerd,
		Benchmark: b,
	}, nil
}

// Start begins the broker test.
func (c *Client) Start() ([]*ResultContainer, error) {
	fmt.Println("Starting broker - if the image hasn't been pulled yet, this may take a while...")
	if err := c.startBroker(); err != nil {
		return nil, fmt.Errorf("Failed to start broker: %s", err.Error())
	}

	// Allow some time for broker startup.
	time.Sleep(time.Duration(c.Benchmark.StartupSleep) * time.Second)

	fmt.Println("Preparing producers")
	if err := c.startPublishers(); err != nil {
		return nil, fmt.Errorf("Failed to start producers: %s", err.Error())
	}

	fmt.Println("Preparing consumers")
	if err := c.startSubscribers(); err != nil {
		return nil, fmt.Errorf("Failed to start consumers %s:", err.Error())
	}

	fmt.Println("Running benchmark")
	if err := c.runBenchmark(); err != nil {
		return nil, fmt.Errorf("Failed to run benchmark %s:", err.Error())
	}

	return <-c.collectResults(), nil
}

func (c *Client) startBroker() error {
	resp, err := sendRequest(c.brokerd, request{
		Operation: start,
		Broker:    c.Benchmark.BrokerName,
		Host:      c.Benchmark.BrokerHost,
		Port:      c.Benchmark.BrokerPort,
	})

	// Hard coded for now, since Kafka seems to have started properly.
	return nil

//	if err != nil {
//		return err
//	}
//
//	if !resp.Success {
//		return errors.New(resp.Message)
//	}
//
//	return nil
}

func (c *Client) startSubscribers() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{
			Operation:   sub,
			Broker:      c.Benchmark.BrokerName,
			Host:        fmt.Sprintf("%s:%s", c.Benchmark.BrokerHost, c.Benchmark.BrokerPort),
			Count:       c.Benchmark.Subscribers,
			NumMessages: c.Benchmark.NumMessages,
			MessageSize: c.Benchmark.MessageSize,
		})

		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) startPublishers() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{
			Operation:   pub,
			Broker:      c.Benchmark.BrokerName,
			Host:        fmt.Sprintf("%s:%s", c.Benchmark.BrokerHost, c.Benchmark.BrokerPort),
			Count:       c.Benchmark.Publishers,
			NumMessages: c.Benchmark.NumMessages,
			MessageSize: c.Benchmark.MessageSize,
		})

		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) runBenchmark() error {
	for _, peerd := range c.peerd {
		resp, err := sendRequest(peerd, request{Operation: run})
		if err != nil {
			return err
		}

		if !resp.Success {
			return errors.New(resp.Message)
		}
	}
	return nil
}

func (c *Client) collectResults() <-chan []*ResultContainer {
	resultsChan := make(chan []*ResultContainer, 1)

	go func(chan<- []*ResultContainer) {
		results := make([]*ResultContainer, 0, len(c.peerd))
		subResults := make(chan *ResultContainer, len(c.peerd))
		complete := 0

		for host, peerd := range c.peerd {
			go collectResultsFromPeer(host, peerd, subResults)
		}

		for {
			select {
			case subResult, ok := <-subResults:
				if !ok {
					return
				}
				results = append(results, subResult)
				complete++
			}

			if complete == len(c.peerd) {
				resultsChan <- results
				return
			}
		}
	}(resultsChan)

	return resultsChan
}

// Teardown performs any necessary cleanup logic, including stopping the
// broker and tearing down peers.
func (c *Client) Teardown() {
	fmt.Println("Tearing down peers")
	for _, peerd := range c.peerd {
		_, err := sendRequest(peerd, request{Operation: teardown})
		if err != nil {
			fmt.Printf("Failed to teardown peer: %s\n", err.Error())
		}
	}

	fmt.Println("Stopping broker")
	if err := c.stopBroker(); err != nil {
		fmt.Printf("Failed to stop broker: %s\n", err.Error())
	}
}

func (c *Client) stopBroker() error {
	resp, err := sendRequest(c.brokerd, request{Operation: stop})
	if err != nil {
		return err
	}

	if !resp.Success {
		return errors.New(resp.Message)
	}

	return nil
}

func sendRequest(s mangos.Socket, request request) (*response, error) {
	fmt.Println("Sending a request")

	requestJSON, err := json.Marshal(request)
	if err != nil {
		// This is not recoverable.
		panic(err)
	}

	fmt.Printf("sendRequest: %s\n", requestJSON)

	if err := s.Send(requestJSON); err != nil {
		return nil, err
	}

	rep, err := s.Recv()
	if err != nil {
		return nil, err
	}

	var resp response
	if err := json.Unmarshal(rep, &resp); err != nil {
		return nil, err
	}

	return &resp, nil
}

func collectResultsFromPeer(host string, peerd mangos.Socket, subResults chan *ResultContainer) {
	for {
		resp, err := sendRequest(peerd, request{Operation: results})
		if err != nil {
			fmt.Println("Failed to collect results from peer:", err.Error())
			close(subResults)
			return
		}

		if !resp.Success {
			fmt.Printf("Failed to collect results from peer: %s", resp.Message)
			subResults <- nil
		}

		if resp.Message == "Results not ready" {
			time.Sleep(resultsSleep)
			continue
		}

		subResults <- &ResultContainer{
			Peer:              host,
			PublisherResults:  resp.PubResults,
			SubscriberResults: resp.SubResults,
		}
		break
	}
}
<|endoftext|>


<commit_before>package kcp

import (
	"crypto/md5"
	"crypto/rand"
	"io"
)

// nonceMD5 is a nonce generator for each packet header
// which took the advantages of both MD5 and CSPRNG(like /dev/urandom).
// The benchmark shows it's faster than previous CSPRNG only method.
type nonceMD5 struct {
	data [md5.Size]byte
}

// Nonce fills a nonce into the provided slice with no more than md5.Size bytes
// the entropy will be updated whenever a leading 0 appears
func (n *nonceMD5) Fill(nonce []byte) {
	if n.data[0] == 0 { // 1/256 chance for entropy update
		io.ReadFull(rand.Reader, n.data[:])
	}
	n.data = md5.Sum(n.data[:])
	copy(nonce, n.data[:])
}
<commit_msg>update comment<commit_after>package kcp

import (
	"crypto/md5"
	"crypto/rand"
	"io"
)

// nonceMD5 is a nonce generator for each packet header
// which took the advantages of both MD5 and CSPRNG(like /dev/urandom).
// The benchmark shows it's faster than previous CSPRNG only method.
type nonceMD5 struct {
	data [md5.Size]byte
}

// Fill fills a nonce into the provided slice with no more than md5.Size bytes
// the entropy will be updated whenever a leading 0 appears
func (n *nonceMD5) Fill(nonce []byte) {
	if n.data[0] == 0 { // 1/256 chance for entropy update
		io.ReadFull(rand.Reader, n.data[:])
	}
	n.data = md5.Sum(n.data[:])
	copy(nonce, n.data[:])
}
<|endoftext|>


<commit_before>// +build openbsd

package host

import (
	"bytes"
	"context"
	"encoding/binary"
	"io/ioutil"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
	"github.com/shirou/gopsutil/process"
	"golang.org/x/sys/unix"
)

const (
	UTNameSize = 32 /* see MAXLOGNAME in <sys/param.h> */
	UTLineSize = 8
	UTHostSize = 16
)

func Info() (*InfoStat, error) {
	return InfoWithContext(context.Background())
}

func InfoWithContext(ctx context.Context) (*InfoStat, error) {
	ret := &InfoStat{
		OS:             runtime.GOOS,
		PlatformFamily: "openbsd",
	}

	hostname, err := os.Hostname()
	if err == nil {
		ret.Hostname = hostname
	}

	platform, family, version, err := PlatformInformation()
	if err == nil {
		ret.Platform = platform
		ret.PlatformFamily = family
		ret.PlatformVersion = version
	}
	system, role, err := Virtualization()
	if err == nil {
		ret.VirtualizationSystem = system
		ret.VirtualizationRole = role
	}

	procs, err := process.Pids()
	if err == nil {
		ret.Procs = uint64(len(procs))
	}

	boot, err := BootTime()
	if err == nil {
		ret.BootTime = boot
		ret.Uptime = uptime(boot)
	}

	return ret, nil
}

func BootTime() (uint64, error) {
	return BootTimeWithContext(context.Background())
}

func BootTimeWithContext(ctx context.Context) (uint64, error) {
	val, err := common.DoSysctrl("kern.boottime")
	if err != nil {
		return 0, err
	}

	boottime, err := strconv.ParseUint(val[0], 10, 64)
	if err != nil {
		return 0, err
	}

	return boottime, nil
}

func uptime(boot uint64) uint64 {
	return uint64(time.Now().Unix()) - boot
}

func Uptime() (uint64, error) {
	return UptimeWithContext(context.Background())
}

func UptimeWithContext(ctx context.Context) (uint64, error) {
	boot, err := BootTime()
	if err != nil {
		return 0, err
	}
	return uptime(boot), nil
}

func PlatformInformation() (string, string, string, error) {
	return PlatformInformationWithContext(context.Background())
}

func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
	platform := ""
	family := ""
	version := ""

	p, err := unix.Sysctl("kern.ostype")
	if err == nil {
		platform = strings.ToLower(p)
	}
	v, err := unix.Sysctl("kern.osrelease")
	if err == nil {
		version = strings.ToLower(v)
	}

	return platform, family, version, nil
}

func Virtualization() (string, string, error) {
	return VirtualizationWithContext(context.Background())
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
	return "", "", common.ErrNotImplementedError
}

func Users() ([]UserStat, error) {
	return UsersWithContext(context.Background())
}

func UsersWithContext(ctx context.Context) ([]UserStat, error) {
	var ret []UserStat
	utmpfile := "/var/run/utmp"
	file, err := os.Open(utmpfile)
	if err != nil {
		return ret, err
	}
	defer file.Close()

	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return ret, err
	}

	u := Utmp{}
	entrySize := int(unsafe.Sizeof(u))
	count := len(buf) / entrySize

	for i := 0; i < count; i++ {
		b := buf[i*entrySize : i*entrySize+entrySize]
		var u Utmp
		br := bytes.NewReader(b)
		err := binary.Read(br, binary.LittleEndian, &u)
		if err != nil || u.Time == 0 {
			continue
		}
		user := UserStat{
			User:     common.IntToString(u.Name[:]),
			Terminal: common.IntToString(u.Line[:]),
			Host:     common.IntToString(u.Host[:]),
			Started:  int(u.Time),
		}

		ret = append(ret, user)
	}

	return ret, nil
}

func SensorsTemperatures() ([]TemperatureStat, error) {
	return SensorsTemperaturesWithContext(context.Background())
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
	return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelVersion() (string, error) {
	return KernelVersionWithContext(context.Background())
}

func KernelVersionWithContext(ctx context.Context) (string, error) {
	_, _, version, err := PlatformInformation()
	return version, err
}
<commit_msg>[host][openbsd] Remove calls to sysctl binary in host/host_openbsd.go #639<commit_after>// +build openbsd

package host

import (
	"bytes"
	"context"
	"encoding/binary"
	"io/ioutil"
	"os"
	"runtime"
	"strings"
	"sync/atomic"
	"time"
	"unsafe"

	"github.com/shirou/gopsutil/internal/common"
	"github.com/shirou/gopsutil/process"
	"golang.org/x/sys/unix"
)

const (
	UTNameSize = 32 /* see MAXLOGNAME in <sys/param.h> */
	UTLineSize = 8
	UTHostSize = 16
)

func Info() (*InfoStat, error) {
	return InfoWithContext(context.Background())
}

func InfoWithContext(ctx context.Context) (*InfoStat, error) {
	ret := &InfoStat{
		OS:             runtime.GOOS,
		PlatformFamily: "openbsd",
	}

	hostname, err := os.Hostname()
	if err == nil {
		ret.Hostname = hostname
	}

	platform, family, version, err := PlatformInformation()
	if err == nil {
		ret.Platform = platform
		ret.PlatformFamily = family
		ret.PlatformVersion = version
	}
	system, role, err := Virtualization()
	if err == nil {
		ret.VirtualizationSystem = system
		ret.VirtualizationRole = role
	}

	procs, err := process.Pids()
	if err == nil {
		ret.Procs = uint64(len(procs))
	}

	boot, err := BootTime()
	if err == nil {
		ret.BootTime = boot
		ret.Uptime = uptime(boot)
	}

	return ret, nil
}

// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64

func BootTime() (uint64, error) {
	return BootTimeWithContext(context.Background())
}

func BootTimeWithContext(ctx context.Context) (uint64, error) {
	// https://github.com/AaronO/dashd/blob/222e32ef9f7a1f9bea4a8da2c3627c4cb992f860/probe/probe_darwin.go
	t := atomic.LoadUint64(&cachedBootTime)
	if t != 0 {
		return t, nil
	}
	value, err := unix.Sysctl("kern.boottime")
	if err != nil {
		return 0, err
	}
	bytes := []byte(value[:])
	var boottime uint64
	boottime = uint64(bytes[0]) + uint64(bytes[1])*256 + uint64(bytes[2])*256*256 + uint64(bytes[3])*256*256*256

	atomic.StoreUint64(&cachedBootTime, boottime)

	return boottime, nil
}

func uptime(boot uint64) uint64 {
	return uint64(time.Now().Unix()) - boot
}

func Uptime() (uint64, error) {
	return UptimeWithContext(context.Background())
}

func UptimeWithContext(ctx context.Context) (uint64, error) {
	boot, err := BootTime()
	if err != nil {
		return 0, err
	}
	return uptime(boot), nil
}

func PlatformInformation() (string, string, string, error) {
	return PlatformInformationWithContext(context.Background())
}

func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
	platform := ""
	family := ""
	version := ""

	p, err := unix.Sysctl("kern.ostype")
	if err == nil {
		platform = strings.ToLower(p)
	}
	v, err := unix.Sysctl("kern.osrelease")
	if err == nil {
		version = strings.ToLower(v)
	}

	return platform, family, version, nil
}

func Virtualization() (string, string, error) {
	return VirtualizationWithContext(context.Background())
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
	return "", "", common.ErrNotImplementedError
}

func Users() ([]UserStat, error) {
	return UsersWithContext(context.Background())
}

func UsersWithContext(ctx context.Context) ([]UserStat, error) {
	var ret []UserStat
	utmpfile := "/var/run/utmp"
	file, err := os.Open(utmpfile)
	if err != nil {
		return ret, err
	}
	defer file.Close()

	buf, err := ioutil.ReadAll(file)
	if err != nil {
		return ret, err
	}

	u := Utmp{}
	entrySize := int(unsafe.Sizeof(u))
	count := len(buf) / entrySize

	for i := 0; i < count; i++ {
		b := buf[i*entrySize : i*entrySize+entrySize]
		var u Utmp
		br := bytes.NewReader(b)
		err := binary.Read(br, binary.LittleEndian, &u)
		if err != nil || u.Time == 0 {
			continue
		}
		user := UserStat{
			User:     common.IntToString(u.Name[:]),
			Terminal: common.IntToString(u.Line[:]),
			Host:     common.IntToString(u.Host[:]),
			Started:  int(u.Time),
		}

		ret = append(ret, user)
	}

	return ret, nil
}

func SensorsTemperatures() ([]TemperatureStat, error) {
	return SensorsTemperaturesWithContext(context.Background())
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
	return []TemperatureStat{}, common.ErrNotImplementedError
}

func KernelVersion() (string, error) {
	return KernelVersionWithContext(context.Background())
}

func KernelVersionWithContext(ctx context.Context) (string, error) {
	_, _, version, err := PlatformInformation()
	return version, err
}
<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 main

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

// ============================================================================================================================
// Asset Definitions
// ============================================================================================================================

// ----- Marbles ----- //
type Marble struct {
	ObjectType string        `json:"docType"`
	Name       string        `json:"name"`     //the fieldtags are needed to keep case from bouncing around
	Color      string        `json:"color"`
	Size       int           `json:"size"`
	Owner      OwnerRelation `json:"owner"`
}

// ----- Owners ----- //
var ownerIndexStr = "_ownerindex"             //name for the key/value that will store a list of all known owners
type Owner struct {
	ObjectType string `json:"docType"`
	Username   string `json:"username"`
	Company    string `json:"company"`
	Timestamp  int64  `json:"timestamp"`      //utc timestamp of registration
	Marbles  []string `json:"marbles"`        //list of marbles names
}
type OwnersIndex struct {
	ObjectType string   `json:"docType"`
	Owners    []string  `json:"owners"`
}
type OwnerRelation struct {
	Username   string `json:"username"`
	Company    string `json:"company"`
}

// ============================================================================================================================
// Main
// ============================================================================================================================
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode - %s", err)
	}
}

// ============================================================================================================================
// Init - reset all the things
// ============================================================================================================================
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	_, args := stub.GetFunctionAndParameters()
	var Aval int
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	// Initialize the chaincode
	Aval, err = strconv.Atoi(args[0])
	if err != nil {
		return shim.Error("Expecting integer value for asset holding")
	}

	// Write the state to the ledger
	err = stub.PutState("abc", []byte(strconv.Itoa(Aval))) //making a test var "abc", I find it handy to read/write to it right away to test the network
	if err != nil {
		return shim.Error(err.Error())
	}

	var owner OwnersIndex
	owner.ObjectType = "OwnerIndex"
	jsonAsBytes, _ := json.Marshal(owner)         //owner is empty, this clears the owner index
	err = stub.PutState(ownerIndexStr, jsonAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

// ============================================================================================================================
// Invoke - Our entry point for Invocations
// ============================================================================================================================
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	fmt.Println("starting invoke, for - " + function)

	// Handle different functions
	if function == "init" {                   //initialize the chaincode state, used as reset
		return t.Init(stub)
	} else if function == "delete_marble" {   //deletes a marble from state
		return delete_marble(stub, args)
	} else if function == "write" {           //generic writes to ledger
		return write(stub, args)
	} else if function == "init_marble" {     //create a new marble
		return init_marble(stub, args)
	} else if function == "set_owner" {       //change owner of a marble
		return set_owner(stub, args)
	} else if function == "read" {            //generic read ledger
		return read(stub, args)
	}else if function == "init_owner"{        //create a new marble owner
		return init_owner(stub, args)
	}else if function == "read_marble_index"{ //read marble/owner mapping
		return read_marble_index(stub)
	}else if function == "read_everything"{   //read everything, (owners + marbles + companies)
		return read_everything(stub)
	}

	// error out
	fmt.Println("Received unknown invoke function name - " + function)
	return shim.Error("Received unknown invoke function name - '" + function + "'")
}

// ============================================================================================================================
// Query - legacy function
// ============================================================================================================================
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Error("Unknown supported call")
}

// ========================================================
// Make Timestamp - create a timestamp in ms
// ========================================================
func makeTimestamp() int64 {
	return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond))
}

// ========================================================
// Input Sanitation - dumb input checking, look for empty strings
// ========================================================
func sanitize_arguments(strs []string) error{
	for i, val:= range strs {
		if len(val) <= 0 {
			return errors.New("Argument " + strconv.Itoa(i) + " must be a non-empty string")
		}
		if len(val) > 32 {
			return errors.New("Argument " + strconv.Itoa(i) + " must be <= 32 characters")
		}
	}
	return nil
}<commit_msg>better logs for marbles<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 main

import (
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

// ============================================================================================================================
// Asset Definitions
// ============================================================================================================================

// ----- Marbles ----- //
type Marble struct {
	ObjectType string        `json:"docType"`
	Name       string        `json:"name"`     //the fieldtags are needed to keep case from bouncing around
	Color      string        `json:"color"`
	Size       int           `json:"size"`
	Owner      OwnerRelation `json:"owner"`
}

// ----- Owners ----- //
var ownerIndexStr = "_ownerindex"             //name for the key/value that will store a list of all known owners
type Owner struct {
	ObjectType string `json:"docType"`
	Username   string `json:"username"`
	Company    string `json:"company"`
	Timestamp  int64  `json:"timestamp"`      //utc timestamp of registration
	Marbles  []string `json:"marbles"`        //list of marbles names
}
type OwnersIndex struct {
	ObjectType string   `json:"docType"`
	Owners    []string  `json:"owners"`
}
type OwnerRelation struct {
	Username   string `json:"username"`
	Company    string `json:"company"`
}

// ============================================================================================================================
// Main
// ============================================================================================================================
func main() {
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Printf("Error starting Simple chaincode - %s", err)
	}
}

// ============================================================================================================================
// Init - reset all the things
// ============================================================================================================================
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
	fmt.Println("Marbles Is Starting Up")
	_, args := stub.GetFunctionAndParameters()
	var Aval int
	var err error

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	// Initialize the chaincode
	Aval, err = strconv.Atoi(args[0])
	if err != nil {
		return shim.Error("Expecting integer value for asset holding")
	}

	// Write the state to the ledger
	err = stub.PutState("abc", []byte(strconv.Itoa(Aval))) //making a test var "abc", I find it handy to read/write to it right away to test the network
	if err != nil {
		return shim.Error(err.Error())
	}

	var owner OwnersIndex
	owner.ObjectType = "OwnerIndex"
	jsonAsBytes, _ := json.Marshal(owner)         //owner is empty, this clears the owner index
	err = stub.PutState(ownerIndexStr, jsonAsBytes)
	if err != nil {
		return shim.Error(err.Error())
	}

	fmt.Println(" - ready for action")
	return shim.Success(nil)
}

// ============================================================================================================================
// Invoke - Our entry point for Invocations
// ============================================================================================================================
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
	function, args := stub.GetFunctionAndParameters()
	fmt.Println(" ")
	fmt.Println("starting invoke, for - " + function)

	// Handle different functions
	if function == "init" {                   //initialize the chaincode state, used as reset
		return t.Init(stub)
	} else if function == "delete_marble" {   //deletes a marble from state
		return delete_marble(stub, args)
	} else if function == "write" {           //generic writes to ledger
		return write(stub, args)
	} else if function == "init_marble" {     //create a new marble
		return init_marble(stub, args)
	} else if function == "set_owner" {       //change owner of a marble
		return set_owner(stub, args)
	} else if function == "read" {            //generic read ledger
		return read(stub, args)
	}else if function == "init_owner"{        //create a new marble owner
		return init_owner(stub, args)
	}else if function == "read_marble_index"{ //read marble/owner mapping
		return read_marble_index(stub)
	}else if function == "read_everything"{   //read everything, (owners + marbles + companies)
		return read_everything(stub)
	}

	// error out
	fmt.Println("Received unknown invoke function name - " + function)
	return shim.Error("Received unknown invoke function name - '" + function + "'")
}

// ============================================================================================================================
// Query - legacy function
// ============================================================================================================================
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response {
	return shim.Error("Unknown supported call - Query()")
}

// ========================================================
// Make Timestamp - create a timestamp in ms
// ========================================================
func makeTimestamp() int64 {
	return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond))
}

// ========================================================
// Input Sanitation - dumb input checking, look for empty strings
// ========================================================
func sanitize_arguments(strs []string) error{
	for i, val:= range strs {
		if len(val) <= 0 {
			return errors.New("Argument " + strconv.Itoa(i) + " must be a non-empty string")
		}
		if len(val) > 32 {
			return errors.New("Argument " + strconv.Itoa(i) + " must be <= 32 characters")
		}
	}
	return nil
}<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"log"
)

func main() {
	log.Printf("tusd started")

	http.HandleFunc("/", route)

	addr := ":1080"
	log.Printf("serving clients at %s", addr)

	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func route(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Server", "tusd")

	if r.Method == "POST" && r.URL.Path == "/files" {
		createFile(w, r)
		return
	}

	reply(w, http.StatusNotFound, "No matching route")
}

func reply(w http.ResponseWriter, code int, message string) {
	w.WriteHeader(code)
	fmt.Fprintf(w, "%d - %s: %s\n", code, http.StatusText(code), message)
}

func createFile(w http.ResponseWriter, r *http.Request) {
	contentRange, err := parseContentRange(r.Header.Get("Content-Range"))
	if err != nil {
		reply(w, http.StatusBadRequest, err.Error())
		return
	}

	if contentRange.End != -1 {
		reply(w, http.StatusNotImplemented, "File data in initial request.")
		return
	}

	contentType := r.Header.Get("Content-Type")
	if contentType == "" {
		contentType = "application/octet-stream"
	}

	log.Printf("contentType: %s", contentType)
	log.Printf("range: %#v", contentRange)
}
<commit_msg>Logging<commit_after>package main

import (
	"fmt"
	"net/http"
	"log"
)

func main() {
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
	log.Printf("tusd started")

	http.HandleFunc("/", route)

	addr := ":1080"
	log.Printf("serving clients at %s", addr)

	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func route(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s", r.Method, r.URL.RequestURI())

	w.Header().Set("Server", "tusd")

	if r.Method == "request: POST" && r.URL.Path == "/files" {
		createFile(w, r)
	} else {
		reply(w, http.StatusNotFound, "No matching route")
	}
}

func reply(w http.ResponseWriter, code int, message string) {
	w.WriteHeader(code)
	fmt.Fprintf(w, "%d - %s: %s\n", code, http.StatusText(code), message)
}

func createFile(w http.ResponseWriter, r *http.Request) {
	contentRange, err := parseContentRange(r.Header.Get("Content-Range"))
	if err != nil {
		reply(w, http.StatusBadRequest, err.Error())
		return
	}

	if contentRange.End != -1 {
		reply(w, http.StatusNotImplemented, "File data in initial request.")
		return
	}

	contentType := r.Header.Get("Content-Type")
	if contentType == "" {
		contentType = "application/octet-stream"
	}

	log.Printf("contentType: %s", contentType)
	log.Printf("range: %#v", contentRange)
}
<|endoftext|>


<commit_before>package httpd

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"testing"
)

func Test_NewServer(t *testing.T) {
	store := newTestStore()
	s := &testServer{New(":0", store)}
	if s == nil {
		t.Fatal("failed to create HTTP service")
	}

	if err := s.Start(); err != nil {
		t.Fatalf("failed to start HTTP service: %s", err)
	}

	b := doGet(t, s.URL(), "k1")
	if string(b) != `{"k1":""}` {
		t.Fatalf("wrong value received for key k1: %s", string(b))
	}

	doPost(t, s.URL(), "k1", "v1")

	b = doGet(t, s.URL(), "k1")
	if string(b) != `{"k1":"v1"}` {
		t.Fatalf("wrong value received for key k1: %s", string(b))
	}

	store.m["k2"] = "v2"
	b = doGet(t, s.URL(), "k2")
	if string(b) != `{"k2":"v2"}` {
		t.Fatalf("wrong value received for key k2: %s", string(b))
	}

	doDelete(t, s.URL(), "k2")
	b = doGet(t, s.URL(), "k2")
	if string(b) != `{"k2":""}` {
		t.Fatalf("wrong value received for key k2: %s", string(b))
	}

}

type testServer struct {
	*Service
}

func (t *testServer) URL() string {
	port := strings.TrimLeft(t.Addr().String(), "[::]:")
	return fmt.Sprintf("http://127.0.0.1:%s", port)
}

type testStore struct {
	m map[string]string
}

func newTestStore() *testStore {
	return &testStore{
		m: make(map[string]string),
	}
}

func (t *testStore) Get(key string) (string, error) {
	return t.m[key], nil
}

func (t *testStore) Set(key, value string) error {
	t.m[key] = value
	return nil
}

func (t *testStore) Delete(key string) error {
	delete(t.m, key)
	return nil
}

func (t *testStore) Join(addr string) error {
	return nil
}

func doGet(t *testing.T, url, key string) string {
	resp, err := http.Get(fmt.Sprintf("%s/key/%s", url, key))
	if err != nil {
		t.Fatalf("failed to GET key: %s", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("failed to read response: %s", err)
	}
	return string(body)
}

func doPost(t *testing.T, url, key, value string) {
	b, err := json.Marshal(map[string]string{key: value})
	if err != nil {
		t.Fatalf("failed to encode key and value for POST: %s", err)
	}
	resp, err := http.Post(fmt.Sprintf("%s/key", url), "application-type/json", bytes.NewReader(b))
	defer resp.Body.Close()
	if err != nil {
		t.Fatalf("POST request failed: %s", err)
	}
}

func doDelete(t *testing.T, u, key string) {
	ru, err := url.Parse(fmt.Sprintf("%s/key/%s", u, key))
	if err != nil {
		t.Fatalf("failed to parse URL for delete: %s", err)
	}
	req := &http.Request{
		Method: "DELETE",
		URL:    ru,
	}

	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("failed to GET key: %s", err)
	}
	defer resp.Body.Close()
}
<commit_msg>Fix store unit testing<commit_after>package httpd

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"testing"
)

func Test_NewServer(t *testing.T) {
	store := newTestStore()
	s := &testServer{New(":0", store)}
	if s == nil {
		t.Fatal("failed to create HTTP service")
	}

	if err := s.Start(); err != nil {
		t.Fatalf("failed to start HTTP service: %s", err)
	}

	b := doGet(t, s.URL(), "k1")
	if string(b) != `{"k1":""}\n` {
		t.Fatalf("wrong value received for key k1: %s", string(b))
	}

	doPost(t, s.URL(), "k1", "v1")

	b = doGet(t, s.URL(), "k1")
	if string(b) != `{"k1":"v1"}\n` {
		t.Fatalf("wrong value received for key k1: %s", string(b))
	}

	store.m["k2"] = "v2"
	b = doGet(t, s.URL(), "k2")
	if string(b) != `{"k2":"v2"}\n` {
		t.Fatalf("wrong value received for key k2: %s", string(b))
	}

	doDelete(t, s.URL(), "k2")
	b = doGet(t, s.URL(), "k2")
	if string(b) != `{"k2":""}\n` {
		t.Fatalf("wrong value received for key k2: %s", string(b))
	}

}

type testServer struct {
	*Service
}

func (t *testServer) URL() string {
	port := strings.TrimLeft(t.Addr().String(), "[::]:")
	return fmt.Sprintf("http://127.0.0.1:%s", port)
}

type testStore struct {
	m map[string]string
}

func newTestStore() *testStore {
	return &testStore{
		m: make(map[string]string),
	}
}

func (t *testStore) Get(key string) (string, error) {
	return t.m[key], nil
}

func (t *testStore) Set(key, value string) error {
	t.m[key] = value
	return nil
}

func (t *testStore) Delete(key string) error {
	delete(t.m, key)
	return nil
}

func (t *testStore) Join(addr string) error {
	return nil
}

func doGet(t *testing.T, url, key string) string {
	resp, err := http.Get(fmt.Sprintf("%s/key/%s", url, key))
	if err != nil {
		t.Fatalf("failed to GET key: %s", err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatalf("failed to read response: %s", err)
	}
	return string(body)
}

func doPost(t *testing.T, url, key, value string) {
	b, err := json.Marshal(map[string]string{key: value})
	if err != nil {
		t.Fatalf("failed to encode key and value for POST: %s", err)
	}
	resp, err := http.Post(fmt.Sprintf("%s/key", url), "application-type/json", bytes.NewReader(b))
	defer resp.Body.Close()
	if err != nil {
		t.Fatalf("POST request failed: %s", err)
	}
}

func doDelete(t *testing.T, u, key string) {
	ru, err := url.Parse(fmt.Sprintf("%s/key/%s", u, key))
	if err != nil {
		t.Fatalf("failed to parse URL for delete: %s", err)
	}
	req := &http.Request{
		Method: "DELETE",
		URL:    ru,
	}

	client := http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatalf("failed to GET key: %s", err)
	}
	defer resp.Body.Close()
}
<|endoftext|>