<commit_before>package gopx

import (
	"errors"
	"fmt"
)

// SplitAfterKM split a track into parts of n KM
func (gpx *Gpx) SplitAfterKM(km float64) ([]*Gpx, error) {
	if km <= 0 {
		return nil, errors.New("km is less than or zero")
	}

	points := gpx.GetPoints()
	if len(points) == 0 {
		return nil, errors.New("No points found. Unable to split track")
	}

	var newGpxs []*Gpx

	var gpxPoints Points
	prev := points[0]
	gpxDist := 0.0
	gpxPoints = append(gpxPoints, prev)
	for i, point := range points[1:] {
		gpxPoints = append(gpxPoints, point)
		gpxDist = gpxDist + prev.Distance(point)
		prev = point

		if gpxDist >= km {
			name := fmt.Sprintf("%s-%d", gpx.GetName(), i)
			newGpxs = append(newGpxs, gpxPoints.createGpx(name))

			gpxPoints = nil
			gpxDist = 0.0
		}
	}

	// Remaining points
	newGpxs = append(newGpxs, gpxPoints.createGpx(""))

	return newGpxs, nil
}

// Split a Gpx track into even parts
func (gpx *Gpx) Split(parts int) ([]*Gpx, error) {
	if parts <= 0 {
		return nil, errors.New("Parts is less than or zero")
	}

	points := gpx.GetPoints()
	if len(points) == 0 {
		return nil, errors.New("No points found. Unable to split track")
	}

	splittedPoints := points.split(parts)

	var newGpxs []*Gpx
	for i := 0; i < parts; i++ {
		name := fmt.Sprintf("%s-%d", gpx.GetName(), i)
		newGpxs = append(newGpxs, splittedPoints[i].createGpx(name))
	}

	return newGpxs, nil
}

// Split a slice of Points into even parts
func (points Points) split(parts int) []Points {
	var splittedPoints []Points
	partSize := (len(points) / parts)

	for i := 0; i < parts; i++ {
		begin := i * partSize
		end := (i + 1) * partSize

		// Last part should only contain the remaining points
		if i == partSize {
			end = len(points)
		}

		splittedPoints = append(splittedPoints, points[begin:end])
	}

	return splittedPoints
}
<commit_msg>Give splitted gpx files a better name<commit_after>package gopx

import (
	"errors"
	"fmt"
)

// SplitAfterKM split a track into parts of n KM
func (gpx *Gpx) SplitAfterKM(km float64) ([]*Gpx, error) {
	if km <= 0 {
		return nil, errors.New("km is less than or zero")
	}

	points := gpx.GetPoints()
	if len(points) == 0 {
		return nil, errors.New("No points found. Unable to split track")
	}

	var newGpxs []*Gpx

	var gpxPoints Points
	prev := points[0]
	gpxDist := 0.0
	gpxPoints = append(gpxPoints, prev)
	for _, point := range points[1:] {
		gpxPoints = append(gpxPoints, point)
		gpxDist = gpxDist + prev.Distance(point)
		prev = point

		if gpxDist >= km {
			name := fmt.Sprintf("%s-%d", gpx.GetName(), len(newGpxs)+1)
			newGpxs = append(newGpxs, gpxPoints.createGpx(name))

			gpxPoints = nil
			gpxDist = 0.0
		}
	}

	// Remaining points
	newGpxs = append(newGpxs, gpxPoints.createGpx(fmt.Sprintf("%s-%d", gpx.GetName(), len(newGpxs)+1)))

	return newGpxs, nil
}

// Split a Gpx track into even parts
func (gpx *Gpx) Split(parts int) ([]*Gpx, error) {
	if parts <= 0 {
		return nil, errors.New("Parts is less than or zero")
	}

	points := gpx.GetPoints()
	if len(points) == 0 {
		return nil, errors.New("No points found. Unable to split track")
	}

	splittedPoints := points.split(parts)

	var newGpxs []*Gpx
	for i := 0; i < parts; i++ {
		name := fmt.Sprintf("%s-%d", gpx.GetName(), i)
		newGpxs = append(newGpxs, splittedPoints[i].createGpx(name))
	}

	return newGpxs, nil
}

// Split a slice of Points into even parts
func (points Points) split(parts int) []Points {
	var splittedPoints []Points
	partSize := (len(points) / parts)

	for i := 0; i < parts; i++ {
		begin := i * partSize
		end := (i + 1) * partSize

		// Last part should only contain the remaining points
		if i == partSize {
			end = len(points)
		}

		splittedPoints = append(splittedPoints, points[begin:end])
	}

	return splittedPoints
}
<|endoftext|>


<commit_before>
package main

import (
	"github.com/keybase/go-libkb"
	"github.com/keybase/protocol/go"
)

type IdentifyResOrError struct {
	body *keybase_1.IdentifyStartResBody
	err error
}

type RemoteTrackUI struct {
	them *libkb.User
	body keybase_1.IdentifyStartResBody
	ch chan IdentifyResOrError
}

func NewRemoteTrackUI(u *libkb.User) *RemoteTrackUI {
	return &RemoteTrackUI{
		them : u,
		ch : make(chan IdentifyResOrError),
	}
}

func (u *RemoteTrackUI) FinishWebProofCheck(*libkb.WebProofChainLink, libkb.LinkCheckResult) {
	return
}
func (u *RemoteTrackUI) FinishSocialProofCheck(*libkb.SocialProofChainLink, libkb.LinkCheckResult) {
	return
}
func (u *RemoteTrackUI) FinishAndPrompt(*libkb.IdentifyRes) (ti libkb.TrackInstructions, err error) {
	return
}
func (u *RemoteTrackUI) DisplayCryptocurrency(*libkb.CryptocurrencyChainLink) {
	return
}
func (u *RemoteTrackUI) DisplayKey(k *libkb.PgpFingerprint, diff libkb.TrackDiff) {
	if k != nil {
		u.body.Key.PgpFingerprint = (*k)[:]
	}
	if diff != nil {
		d := libkb.ExportTrackDiff(diff)
		u.body.Key.TrackDiff = &d
	}
	return
}
func (u *RemoteTrackUI) ReportLastTrack(l *libkb.TrackLookup) {
	if l != nil {
		u.body.WhenLastTracked = int(l.GetCTime().Unix())
	}
	return
}
func (u *RemoteTrackUI) Start() {
	return
}

func (u *RemoteTrackUI) LaunchNetworkChecks(res *libkb.IdentifyRes) {
	u.ch <- IdentifyResOrError{ body : &u.body }
}
<commit_msg>work on exporting tracking<commit_after>
package main

import (
	"github.com/keybase/go-libkb"
	"github.com/keybase/protocol/go"
)

type IdentifyResOrError struct {
	body *keybase_1.IdentifyStartResBody
	err error
}

type RemoteTrackUI struct {
	them *libkb.User
	body keybase_1.IdentifyStartResBody
	ch chan IdentifyResOrError
}

func NewRemoteTrackUI(u *libkb.User) *RemoteTrackUI {
	return &RemoteTrackUI{
		them : u,
		ch : make(chan IdentifyResOrError),
	}
}

func (u *RemoteTrackUI) FinishWebProofCheck(*libkb.WebProofChainLink, libkb.LinkCheckResult) {
	return
}
func (u *RemoteTrackUI) FinishSocialProofCheck(*libkb.SocialProofChainLink, libkb.LinkCheckResult) {
	return
}
func (u *RemoteTrackUI) FinishAndPrompt(*libkb.IdentifyRes) (ti libkb.TrackInstructions, err error) {
	return
}
func (u *RemoteTrackUI) DisplayCryptocurrency(*libkb.CryptocurrencyChainLink) {
	return
}
func (u *RemoteTrackUI) DisplayKey(k *libkb.PgpFingerprint, diff libkb.TrackDiff) {
	if k != nil {
		u.body.Key.PgpFingerprint = (*k)[:]
	}
	u.body.Key.TrackDiff = libkb.ExportTrackDiff(diff)
	return
}
func (u *RemoteTrackUI) ReportLastTrack(l *libkb.TrackLookup) {
	if l != nil {
		u.body.WhenLastTracked = int(l.GetCTime().Unix())
	}
	return
}
func (u *RemoteTrackUI) Start() {
	return
}

func (u *RemoteTrackUI) LaunchNetworkChecks(res *libkb.IdentifyRes) {
	for i, r := range res.ProofChecks {
		u.body.Proofs = append(u.body.Proofs, r.ExportToIdentifyRow(i))
	}
	u.ch <- IdentifyResOrError{ body : &u.body }
}
<|endoftext|>


<commit_before>package gamehack

import (
	"fmt"
	"html/template"
	"net/http"

	"appengine"
	"appengine/datastore"
	"appengine/user"
)

func root(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "index", nil)
}

func phone(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		http.Redirect(w, r, "/", http.StatusUnauthorized)
		return
	}
	user := User{
		Name: u.String(),
	}

	userKey := datastore.NewKey(c, "User", u.ID, 0, nil)

	err := datastore.Get(c, userKey, &user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	_, err = datastore.NewQuery("PhoneEntry").Ancestor(userKey).GetAll(c, &user.PhoneEntries)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	renderTemplate(w, "phone", user)
}

func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) {
	t, err := template.ParseFiles(fmt.Sprintf("static/%s.html", tmpl))
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	err = t.Execute(w, c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<commit_msg>Cache parsed templates per App Engine instance.<commit_after>package gamehack

import (
	"html/template"
	"net/http"

	"appengine"
	"appengine/datastore"
	"appengine/user"
)

// Base directory where templates are stored.
const tD = "static/"

var templates = template.Must(template.ParseFiles(
	tD+"index.html",
	tD+"phone.html",
))

func root(w http.ResponseWriter, r *http.Request) {
	renderTemplate(w, "index", nil)
}

func phone(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	u := user.Current(c)
	if u == nil {
		http.Redirect(w, r, "/", http.StatusUnauthorized)
		return
	}
	user := User{
		Name: u.String(),
	}

	userKey := datastore.NewKey(c, "User", u.ID, 0, nil)

	err := datastore.Get(c, userKey, &user)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	_, err = datastore.NewQuery("PhoneEntry").Ancestor(userKey).GetAll(c, &user.PhoneEntries)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	renderTemplate(w, "phone", user)
}

func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) {
	err := templates.ExecuteTemplate(w, tmpl+".html", c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>package smtp

import (
	"net"
	"testing"

	"github.com/gansoi/gansoi/plugins"
)

type (
	tcpBannerServer struct {
		banner string
	}
)

const (
	banner = "220 test-server ESMTP"
)

func newBannerServer() net.Listener {
	listener, _ := net.Listen("tcp", "0.0.0.0:0")

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				return
			}

			conn.Write([]byte(banner + "\r\n"))
		}
	}()

	return listener
}

func TestDefaultPort(t *testing.T) {
	cases := map[string]string{
		"hello":     "hello:25",
		"hello:25":  "hello:25",
		"hello::25": "hello::25",
	}

	for input, expected := range cases {
		output := defaultPort(input)
		if output != expected {
			t.Fatalf("defaultPort() did not return what we expected, got %s, expected %s", output, expected)
		}
	}
}

func TestAgent(t *testing.T) {
	a := plugins.GetAgent("smtp")
	_ = a.(*SMTP)
}

func TestCheckFail(t *testing.T) {
	a := SMTP{
		Address: "127.0.0.1:0",
	}

	result := plugins.NewAgentResult()
	err := a.Check(result)
	if err == nil {
		t.Fatalf("Failed to detect error")
	}
}

func TestCheck(t *testing.T) {
	serve := newBannerServer()
	defer serve.Close()

	a := SMTP{
		Address: serve.Addr().String(),
	}

	result := plugins.NewAgentResult()
	err := a.Check(result)
	if err != nil {
		t.Fatalf("Check failed: %s", err.Error())
	}
	if result["banner"] != "test-server ESMTP" {
		t.Fatalf("banner mismatch, got '%s', expected '%s'", result["banner"], banner)
	}
}

var _ plugins.Agent = (*SMTP)(nil)
<commit_msg>Use localhost for loopback test.<commit_after>package smtp

import (
	"net"
	"testing"

	"github.com/gansoi/gansoi/plugins"
)

type (
	tcpBannerServer struct {
		banner string
	}
)

const (
	banner = "220 test-server ESMTP"
)

func newBannerServer() net.Listener {
	listener, _ := net.Listen("tcp", "127.0.0.1:0")

	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				return
			}

			conn.Write([]byte(banner + "\r\n"))
		}
	}()

	return listener
}

func TestDefaultPort(t *testing.T) {
	cases := map[string]string{
		"hello":     "hello:25",
		"hello:25":  "hello:25",
		"hello::25": "hello::25",
	}

	for input, expected := range cases {
		output := defaultPort(input)
		if output != expected {
			t.Fatalf("defaultPort() did not return what we expected, got %s, expected %s", output, expected)
		}
	}
}

func TestAgent(t *testing.T) {
	a := plugins.GetAgent("smtp")
	_ = a.(*SMTP)
}

func TestCheckFail(t *testing.T) {
	a := SMTP{
		Address: "127.0.0.1:0",
	}

	result := plugins.NewAgentResult()
	err := a.Check(result)
	if err == nil {
		t.Fatalf("Failed to detect error")
	}
}

func TestCheck(t *testing.T) {
	serve := newBannerServer()
	defer serve.Close()

	a := SMTP{
		Address: serve.Addr().String(),
	}

	result := plugins.NewAgentResult()
	err := a.Check(result)
	if err != nil {
		t.Fatalf("Check failed: %s", err.Error())
	}
	if result["banner"] != "test-server ESMTP" {
		t.Fatalf("banner mismatch, got '%s', expected '%s'", result["banner"], banner)
	}
}

var _ plugins.Agent = (*SMTP)(nil)
<|endoftext|>


<commit_before>// Package ipam_test is responsible for testing of IP addresses management
package ipam_test

import (
	"github.com/ligato/cn-infra/logging/logroot"
	. "github.com/onsi/gomega"
	"testing"

	"github.com/contiv/vpp/plugins/contiv/ipam"
	"net"
	"strconv"
)

/*
TODO extended tests for pod ip allocating and releasing:
	-exhaust(no check) -> release all(no error check) -> exhaust again(no ip address allocated twice check) (checking proper releasing of all ip addresses)
	-exhaust(no check) -> release half of ip address(no error check) -> exhaust again (check collision with 1-phase allocated ip addresses) (checking proper releasing of only those addresses that we want to release)
	-check <8-bit,=8-bit,>8-bit pool allocation
TODO test bad config values
TODO test host ip part to be < 8-bits (check if host id trimming is working)
TODO check multiple hosts IPAMs for no interconnection between them and that hostID is not hardwired into them somehow
*/

const (
	b10000000 = 1 << 7
	b11000000 = 1<<7 + 1<<6
	b11000010 = 1<<7 + 1<<6 + 1<<1
	b10100001 = 1<<7 + 1<<5 + 1
	b10100101 = 1<<7 + 1<<5 + 1<<2 + 1
	b11100101 = 1<<7 + 1<<6 + 1<<5 + 1<<2 + 1

	incorrectHostIDForIPAllocation = ""
)

var (
	hostID1 uint8 = b10100001
	hostID2 uint8 = b10100101

	podID = "podID"

	config = ipam.Config{
		PodSubnetCIDR:           "1.2." + str(b10000000) + ".2/17",
		PodNetworkPrefixLen:     29, // 3 bits left -> 6 free IP addresses (gateway IP + zero ending IP is reserved)
		VSwitchSubnetCIDR:       "2.3." + str(b11000000) + ".2/18",
		VSwitchNetworkPrefixLen: 30, // 2 bit left -> 3 free IP addresses (zero ending IP is reserved)
		HostNodeSubnetCidr:      "3.4.5." + str(b11000010) + "/26",
	}
)

// TestStaticGetters tests exposed IPAM API that provides data that doesn't change in time (and are not dynamically
// recomputed based on new input in form of API function parameters)
func TestStaticGetters(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())
	Expect(i.HostID()).To(BeEquivalentTo(hostID1))

	// pods addresses IPAM API
	Expect(*i.PodSubnet()).To(BeEquivalentTo(network("1.2." + str(b10000000) + ".0/17")))
	expectedPodNetwork := network("1.2." + str(b10000000+int(hostID1>>5)) + "." + str(int(hostID1<<3)) + "/29")
	Expect(*i.PodNetwork()).To(BeEquivalentTo(expectedPodNetwork))
	Expect(expectedPodNetwork.Contains(i.PodGatewayIP())).To(BeTrue(), "Pod Gateway IP is not in range of network for pods for given host.")

	// vSwitch addresses IPAM API
	expectedVSwitchNetwork := network("2.3." + str(b11000000+int(hostID1>>6)) + "." + str(int(hostID1<<2)) + "/30")
	Expect(*i.VSwitchNetwork()).To(BeEquivalentTo(expectedVSwitchNetwork))
	Expect(expectedVSwitchNetwork.Contains(i.VEthHostEndIP())).To(BeTrue(), "VEthHostEndIP is not in range of vSwitch network for given host.")
	Expect(expectedVSwitchNetwork.Contains(i.VEthVPPEndIP())).To(BeTrue(), "VEthVPPEndIP is not in range of vSwitch network for given host.")
}

// TestDynamicGetters tests proper working IMAP API that provides data based on new input (func parameters)
func TestDynamicGetters(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())

	ip, err := i.HostIPAddress(hostID2)
	Expect(err).To(BeNil())
	Expect(ip).To(BeEquivalentTo(net.IPv4(3, 4, 5, b11100101).To4()))

	ipNet, err := i.HostIPNetwork(hostID2)
	Expect(err).To(BeNil())
	Expect(*ipNet).To(BeEquivalentTo(ipWithNetworkMask("3.4.5." + str(b11100101) + "/26")))
}

// TestBasicAllocateReleasePodAddress test simple happy path scenario for getting 1 pod address and releasing it
func TestBasicAllocateReleasePodAddress(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())

	ip, err := i.NextPodIP(podID)
	Expect(err).To(BeNil())
	Expect(ip).NotTo(BeNil())
	Expect(i.PodNetwork().Contains(ip)).To(BeTrue(), "Pod IP address is not from pod network")

	err = i.ReleasePodIP(podID)
	Expect(err).To(BeNil())
}

// TestBadInputForIPAllocation tests expected failure of IP allocation caused by bad input
func TestBadInputForIPAllocation(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())

	_, err = i.NextPodIP(incorrectHostIDForIPAllocation)
	Expect(err).NotTo(BeNil())
}

// TestIgnoringOfBadInputForIPRelease tests special case of ignored bad input for pod IP release that happens by kubernetes restart
func TestIgnoringOfBadInputForIPRelease(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())

	err = i.ReleasePodIP(incorrectHostIDForIPAllocation)
	Expect(err).To(BeNil())
}

// TestDistinctAllocations test whether all pod IP addresses are distinct to each other until exhaustion of the whole IP address pool
func TestDistinctAllocations(t *testing.T) {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())

	allocated := make(map[string]bool)
	maxIPCount := 6
	for j := 1; j <= maxIPCount; j++ {
		ip, err := i.NextPodIP(strconv.Itoa(j)) //TODO check for IPv4 vs IPv6 addresses because net.IP.Equals() considers them equal
		Expect(err).To(BeNil(), "Can't successfully allocate %v. IP address out of %v possible IP addresses", j, maxIPCount)
		Expect(allocated[ip.String()]).To(BeFalse(), "IP address %v is allocated second time", ip)
		allocated[ip.String()] = true
	}
	_, err = i.NextPodIP(strconv.Itoa(maxIPCount + 1))
	Expect(err).NotTo(BeNil(), "Pool of free IP addresses should be empty, but IPAM allocation function didn't fail")
}

func network(networkCIDR string) net.IPNet {
	_, result, err := net.ParseCIDR(networkCIDR)
	Expect(err).To(BeNil())
	return *result
}

func ipWithNetworkMask(ipWithMaskCIDR string) net.IPNet {
	ip, result, err := net.ParseCIDR(ipWithMaskCIDR)
	Expect(err).To(BeNil())
	result.IP = ip.To4()
	return *result
}

func str(i int) string {
	return strconv.Itoa(i)
}
<commit_msg>test refactoring<commit_after>// Package ipam_test is responsible for testing of IP addresses management
package ipam_test

import (
	"github.com/ligato/cn-infra/logging/logroot"
	. "github.com/onsi/gomega"
	"testing"

	"github.com/contiv/vpp/plugins/contiv/ipam"
	"net"
	"strconv"
)

/*
TODO extended tests for pod ip allocating and releasing:
	-exhaust(no check) -> release all(no error check) -> exhaust again(no ip address allocated twice check) (checking proper releasing of all ip addresses)
	-exhaust(no check) -> release half of ip address(no error check) -> exhaust again (check collision with 1-phase allocated ip addresses) (checking proper releasing of only those addresses that we want to release)
	-check <8-bit,=8-bit,>8-bit pool allocation
TODO test bad config values
TODO test host ip part to be < 8-bits (check if host id trimming is working)
TODO check multiple hosts IPAMs for no interconnection between them and that hostID is not hardwired into them somehow
*/

const (
	b10000000 = 1 << 7
	b11000000 = 1<<7 + 1<<6
	b11000010 = 1<<7 + 1<<6 + 1<<1
	b10100001 = 1<<7 + 1<<5 + 1
	b10100101 = 1<<7 + 1<<5 + 1<<2 + 1
	b11100101 = 1<<7 + 1<<6 + 1<<5 + 1<<2 + 1

	incorrectHostIDForIPAllocation = ""
)

var (
	hostID1 uint8 = b10100001
	hostID2 uint8 = b10100101

	podID = "podID"

	config = ipam.Config{
		PodSubnetCIDR:           "1.2." + str(b10000000) + ".2/17",
		PodNetworkPrefixLen:     29, // 3 bits left -> 6 free IP addresses (gateway IP + zero ending IP is reserved)
		VSwitchSubnetCIDR:       "2.3." + str(b11000000) + ".2/18",
		VSwitchNetworkPrefixLen: 30, // 2 bit left -> 3 free IP addresses (zero ending IP is reserved)
		HostNodeSubnetCidr:      "3.4.5." + str(b11000010) + "/26",
	}
)

func setup(t *testing.T) *ipam.IPAM {
	RegisterTestingT(t)

	i, err := ipam.New(logroot.StandardLogger(), uint8(hostID1), &config)
	Expect(err).To(BeNil())
	return i
}

// TestStaticGetters tests exposed IPAM API that provides data that doesn't change in time (and are not dynamically
// recomputed based on new input in form of API function parameters)
func TestStaticGetters(t *testing.T) {
	i := setup(t)
	Expect(i.HostID()).To(BeEquivalentTo(hostID1))

	// pods addresses IPAM API
	Expect(*i.PodSubnet()).To(BeEquivalentTo(network("1.2." + str(b10000000) + ".0/17")))
	expectedPodNetwork := network("1.2." + str(b10000000+int(hostID1>>5)) + "." + str(int(hostID1<<3)) + "/29")
	Expect(*i.PodNetwork()).To(BeEquivalentTo(expectedPodNetwork))
	Expect(expectedPodNetwork.Contains(i.PodGatewayIP())).To(BeTrue(), "Pod Gateway IP is not in range of network for pods for given host.")

	// vSwitch addresses IPAM API
	expectedVSwitchNetwork := network("2.3." + str(b11000000+int(hostID1>>6)) + "." + str(int(hostID1<<2)) + "/30")
	Expect(*i.VSwitchNetwork()).To(BeEquivalentTo(expectedVSwitchNetwork))
	Expect(expectedVSwitchNetwork.Contains(i.VEthHostEndIP())).To(BeTrue(), "VEthHostEndIP is not in range of vSwitch network for given host.")
	Expect(expectedVSwitchNetwork.Contains(i.VEthVPPEndIP())).To(BeTrue(), "VEthVPPEndIP is not in range of vSwitch network for given host.")
}

// TestDynamicGetters tests proper working IMAP API that provides data based on new input (func parameters)
func TestDynamicGetters(t *testing.T) {
	i := setup(t)
	ip, err := i.HostIPAddress(hostID2)
	Expect(err).To(BeNil())
	Expect(ip).To(BeEquivalentTo(net.IPv4(3, 4, 5, b11100101).To4()))

	ipNet, err := i.HostIPNetwork(hostID2)
	Expect(err).To(BeNil())
	Expect(*ipNet).To(BeEquivalentTo(ipWithNetworkMask("3.4.5." + str(b11100101) + "/26")))
}

// TestBasicAllocateReleasePodAddress test simple happy path scenario for getting 1 pod address and releasing it
func TestBasicAllocateReleasePodAddress(t *testing.T) {
	i := setup(t)
	ip, err := i.NextPodIP(podID)
	Expect(err).To(BeNil())
	Expect(ip).NotTo(BeNil())
	Expect(i.PodNetwork().Contains(ip)).To(BeTrue(), "Pod IP address is not from pod network")

	err = i.ReleasePodIP(podID)
	Expect(err).To(BeNil())
}

// TestBadInputForIPAllocation tests expected failure of IP allocation caused by bad input
func TestBadInputForIPAllocation(t *testing.T) {
	i := setup(t)
	_, err := i.NextPodIP(incorrectHostIDForIPAllocation)
	Expect(err).NotTo(BeNil())
}

// TestIgnoringOfBadInputForIPRelease tests special case of ignored bad input for pod IP release that happens by kubernetes restart
func TestIgnoringOfBadInputForIPRelease(t *testing.T) {
	i := setup(t)
	err := i.ReleasePodIP(incorrectHostIDForIPAllocation)
	Expect(err).To(BeNil())
}

// TestDistinctAllocations test whether all pod IP addresses are distinct to each other until exhaustion of the whole IP address pool
func TestDistinctAllocations(t *testing.T) {
	i := setup(t)
	allocated := make(map[string]bool)
	maxIPCount := 6
	for j := 1; j <= maxIPCount; j++ {
		ip, err := i.NextPodIP(strconv.Itoa(j)) //TODO check for IPv4 vs IPv6 addresses because net.IP.Equals() considers them equal
		Expect(err).To(BeNil(), "Can't successfully allocate %v. IP address out of %v possible IP addresses", j, maxIPCount)
		Expect(allocated[ip.String()]).To(BeFalse(), "IP address %v is allocated second time", ip)
		allocated[ip.String()] = true
	}
	_, err := i.NextPodIP(strconv.Itoa(maxIPCount + 1))
	Expect(err).NotTo(BeNil(), "Pool of free IP addresses should be empty, but IPAM allocation function didn't fail")
}

func network(networkCIDR string) net.IPNet {
	_, result, err := net.ParseCIDR(networkCIDR)
	Expect(err).To(BeNil())
	return *result
}

func ipWithNetworkMask(ipWithMaskCIDR string) net.IPNet {
	ip, result, err := net.ParseCIDR(ipWithMaskCIDR)
	Expect(err).To(BeNil())
	result.IP = ip.To4()
	return *result
}

func str(i int) string {
	return strconv.Itoa(i)
}
<|endoftext|>


<commit_before>// 13 february 2014
package ui

import (
	"fmt"
	"sync"
)

// Orientation defines the orientation of controls in a Stack.
type Orientation int
const (
	Horizontal Orientation = iota
	Vertical
)

// A Stack stacks controls horizontally or vertically within the Stack's parent, alotting each the same size.
type Stack struct {
	lock			sync.Mutex
	created		bool
	orientation	Orientation
	controls		[]Control
}

// NewStack creates a new Stack with the specified orientation.
func NewStack(o Orientation, controls ...Control) *Stack {
	if o != Horizontal && o != Vertical {
		panic(fmt.Sprintf("invalid orientation %d given to NewStack()", o))
	}
	return &Stack{
		orientation:	o,
		controls:		controls,
	}
}

func (s *Stack) make(window *sysData) error {
	for i, c := range s.controls {
		err := c.make(window)
		if err != nil {
			return fmt.Errorf("error adding control %d: %v", i, err)
		}
	}
	s.created = true
	return nil
}

func (s *Stack) setRect(x int, y int, width int, height int) error {
	var dx, dy int

	if len(s.controls) == 0 {		// do nothing if there's nothing to do
		return nil
	}
	switch s.orientation {
	case Horizontal:
		dx = width / len(s.controls)
		width = dx
	case Vertical:
		dy = height / len(s.controls)
		height = dy
	default:
		panic(fmt.Sprintf("invalid orientation %d given to Stack.setRect()", s.orientation))
	}
	for i, c := range s.controls {
		err := c.setRect(x, y, width, height)
		if err != nil {
			return fmt.Errorf("error setting size of control %d: %v", i, err)
		}
		x += dx
		y += dy
	}
	return nil
}
<commit_msg>Started rewriting Stack to conform to the new layout plan.<commit_after>// 13 february 2014
package ui

import (
	"fmt"
	"sync"
)

// Orientation defines the orientation of controls in a Stack.
type Orientation int
const (
	Horizontal Orientation = iota
	Vertical
)

// A Stack stacks controls horizontally or vertically within the Stack's parent.
// A horizontal Stack gives all controls the same height and their preferred widths.
// A vertical Stack gives all controls the same width and their preferred heights.
// Some controls may be marked as "stretchy": when the Window they are in changes size, stretchy controls resize to take up the remaining space after non-stretchy controls are laid out. If multiple controls are marked stretchy, they are alloted equal distribution of the remaining space.
type Stack struct {
	lock			sync.Mutex
	created		bool
	orientation	Orientation
	controls		[]Control
	stretchy		[]bool
	xpos, ypos	[]int		// caches to avoid reallocating these each time
	width, height	[]int
}

// NewStack creates a new Stack with the specified orientation.
func NewStack(o Orientation, controls ...Control) *Stack {
	if o != Horizontal && o != Vertical {
		panic(fmt.Sprintf("invalid orientation %d given to NewStack()", o))
	}
	return &Stack{
		orientation:	o,
		controls:		controls,
		stretchy:		make([]bool, len(controls)),
		xpos:		make([]int, len(controls)),
		ypos:		make([]int, len(controls)),
		width:		make([]int, len(controls)),
		height:		make([]int, len(controls)),
	}
}

// SetStretchy marks a control in a Stack as stretchy.
func (s *Stack) SetStretchy(index int) {
	s.lock.Lock()
	defer s.lock.Unlock()

	s[index] = true			// TODO explicitly check for index out of bounds?
}

func (s *Stack) make(window *sysData) error {
	for i, c := range s.controls {
		err := c.make(window)
		if err != nil {
			return fmt.Errorf("error adding control %d to Stack: %v", i, err)
		}
	}
	s.created = true
	return nil
}

func (s *Stack) setRect(x int, y int, width int, height int) error {
	var dx, dy int

	if len(s.controls) == 0 {		// do nothing if there's nothing to do
		return nil
	}
	switch s.orientation {
	case Horizontal:
		dx = width / len(s.controls)
		width = dx
	case Vertical:
		dy = height / len(s.controls)
		height = dy
	default:
		panic(fmt.Sprintf("invalid orientation %d given to Stack.setRect()", s.orientation))
	}
	for i, c := range s.controls {
		err := c.setRect(x, y, width, height)
		if err != nil {
			return fmt.Errorf("error setting size of control %d: %v", i, err)
		}
		x += dx
		y += dy
	}
	return nil
}
<|endoftext|>


<commit_before>package quorum

import (
	"common"
	"common/crypto"
	"fmt"
)

type ParticipantIndex uint8

// The state is what provides persistence to the consensus algorithms.
// The state is updated every block, and every honest host is
// guaranteed to update their state in the same way.
type State struct {
	// Who is participating in the quorum
	Participants [common.QuorumSize]*Participant
	// Our own index in the quorum
	ParticipantIndex ParticipantIndex

	// The cryptographic keys belonging to this host specifically
	PublicKey crypto.PublicKey
	SecretKey crypto.SecretKey

	// The hash of this was used in stage 1 for the most recent heartbeat
	StoredEntropyStage2 common.Entropy

	// The stage 1 entropies from the last block
	// PreviousEntropy [common.QuorumSize]*crypto.TruncatedHash

	// Consensus Algorithm Status
	CurrentStep int
	Heartbeats  [common.QuorumSize]map[crypto.TruncatedHash]*Heartbeat

	// Wallet Data
	Wallets map[string]uint64
}

// Currently just an address, as the participant is accessed
// by knowing the public key. It's in its own struct because
// more fields might be added.
type Participant struct {
	PublicKey crypto.PublicKey
}

// Create and initialize a state object
func CreateState(participantIndex ParticipantIndex) (s State, err error) {
	// check that participantIndex is legal
	if int(participantIndex) >= common.QuorumSize {
		err = fmt.Errorf("Invalid participant index!")
		return
	}

	// initialize crypto keys
	pubKey, secKey, err := crypto.CreateKeyPair()
	if err != nil {
		return
	}
	s.PublicKey = pubKey
	s.SecretKey = secKey

	s.ParticipantIndex = participantIndex

	s.CurrentStep = 1
	s.Wallets = make(map[string]uint64)
	return
}

// Populates a state with this participant, initializing variables as needed
// return codes are arbitraily chosen and are only for the test suite
func (s *State) AddParticipant(pubKey crypto.PublicKey, i ParticipantIndex) (err error) {
	// Check that there is not already a participant for the index
	if s.Participants[i] != nil {
		err = fmt.Errorf("A participant already exists for the given index!")
		return
	}

	// initialize participant object
	var p Participant
	p.PublicKey = pubKey

	// initialize the heartbeat map for this participant
	s.Heartbeats[i] = make(map[crypto.TruncatedHash]*Heartbeat)

	// add to state
	s.Participants[i] = &p

	return
}

func HandleMessage(m common.Message) {
	// take the payload and squeeze out the type bytes
	// use a switch statement based on type
}
<commit_msg>add State.RandInt<commit_after>package quorum

import (
	"common"
	"common/crypto"
	"fmt"
)

type ParticipantIndex uint8

// The state is what provides persistence to the consensus algorithms.
// The state is updated every block, and every honest host is
// guaranteed to update their state in the same way.
type State struct {
	// Who is participating in the quorum
	Participants [common.QuorumSize]*Participant
	// Our own index in the quorum
	ParticipantIndex ParticipantIndex

	// The cryptographic keys belonging to this host specifically
	PublicKey crypto.PublicKey
	SecretKey crypto.SecretKey

	// The hash of this was used in stage 1 for the most recent heartbeat
	StoredEntropyStage2 common.Entropy

	// The stage 1 entropies from the last block
	// Entropy seed to be used while compiling next block
	CurrentEntropy common.Entropy

	// Consensus Algorithm Status
	CurrentStep int
	Heartbeats  [common.QuorumSize]map[crypto.TruncatedHash]*Heartbeat

	// Wallet Data
	Wallets map[string]uint64
}

// Currently just an address, as the participant is accessed
// by knowing the public key. It's in its own struct because
// more fields might be added.
type Participant struct {
	PublicKey crypto.PublicKey
}

// Create and initialize a state object
func CreateState(participantIndex ParticipantIndex) (s State, err error) {
	// check that participantIndex is legal
	if int(participantIndex) >= common.QuorumSize {
		err = fmt.Errorf("Invalid participant index!")
		return
	}

	// initialize crypto keys
	pubKey, secKey, err := crypto.CreateKeyPair()
	if err != nil {
		return
	}
	s.PublicKey = pubKey
	s.SecretKey = secKey

	s.ParticipantIndex = participantIndex

	s.CurrentStep = 1
	s.Wallets = make(map[string]uint64)
	return
}

// Populates a state with this participant, initializing variables as needed
// return codes are arbitraily chosen and are only for the test suite
func (s *State) AddParticipant(pubKey crypto.PublicKey, i ParticipantIndex) (err error) {
	// Check that there is not already a participant for the index
	if s.Participants[i] != nil {
		err = fmt.Errorf("A participant already exists for the given index!")
		return
	}

	// initialize participant object
	var p Participant
	p.PublicKey = pubKey

	// initialize the heartbeat map for this participant
	s.Heartbeats[i] = make(map[crypto.TruncatedHash]*Heartbeat)

	// add to state
	s.Participants[i] = &p

	return
}

// Use the entropy stored in the state to generate a random
// integer [low, high)
func (s *State) RandInt(low int, high int) (randInt int, err error) {
	// Convert CurrentEntropy into an int
	rollingInt := 0
	for i := 0; i < 4; i++ {
		rollingInt = rollingInt << 4
		rollingInt += int(s.CurrentEntropy[0])
	}

	randInt = (rollingInt % (high - low)) + low

	// Convert random number seed to next value
	truncatedHash, err := crypto.CalculateTruncatedHash(s.CurrentEntropy[:])
	s.CurrentEntropy = common.Entropy(truncatedHash)
	return
}

func HandleMessage(m common.Message) {
	// take the payload and squeeze out the type bytes
	// use a switch statement based on type
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

var opt Options

var countDirs int
var countFiles int

func update(f os.FileInfo) {
	if f.IsDir() {
		countDirs++
	} else {
		countFiles++
	}
}

// checkFile checks if we have to add this file.
// Returns true if we have to recurse or false if we don't
func checkFile(path string, f os.FileInfo) bool {
	if opt.excludeEmptyFiles && !f.IsDir() && f.Size() == 0 {
		return true
	}

	if opt.excludeHiddenFiles && strings.HasPrefix(f.Name(), ".") {
		// hidden file or directory
		return false
	}
	if opt.ignoreSymLinks && f.Mode()&os.ModeSymlink != 0 {
		return nil
	}
	update(f)

	// only make hash for files, skip dirs
	if !f.IsDir() {

	}
	fmt.Printf("[+] Analyzed: %v directories and %v files\r",
		countDirs, countFiles)

	return true
}

func readDir(s string) error {
	files, err := ioutil.ReadDir(s)
	if err != nil {
		return err
	}

	if opt.excludeEmptyDir && len(files) == 0 {
		return nil
	}

	for _, file := range files {
		path := s + "/" + file.Name()
		recurse := checkFile(path, file)

		if recurse && file.IsDir() {
			readDir(path)
		}
	}
	return nil
}

// Start the program with the current options. Options param is read only
func Start(options Options) {
	opt = options
	fmt.Println("[+] Starting in directory:", opt.currentDir)

	err := readDir(opt.currentDir)
	if err != nil {
		fmt.Println("[-]", err)
	}

	fmt.Println()
}
<commit_msg>not search in empty dirs<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

var opt Options

var countDirs int
var countFiles int

func update(f os.FileInfo) {
	if f.IsDir() {
		countDirs++
	} else {
		countFiles++
	}
}

// checkFile checks if we have to add this file.
// Returns true if we have to recurse or false if we don't
func checkFile(path string, f os.FileInfo) bool {
	if opt.excludeEmptyFiles && !f.IsDir() && f.Size() == 0 {
		return false
	}

	if opt.excludeHiddenFiles && strings.HasPrefix(f.Name(), ".") {
		// hidden file or directory
		return false
	}
	if opt.ignoreSymLinks && f.Mode()&os.ModeSymlink != 0 {
		return false
	}
	update(f)

	// only make hash for files, skip dirs
	if !f.IsDir() {

	}
	fmt.Printf("[+] Analyzed: %v directories and %v files\r",
		countDirs, countFiles)

	return true
}

func readDir(s string) error {
	files, err := ioutil.ReadDir(s)
	if err != nil {
		return err
	}

	if opt.excludeEmptyDir && len(files) == 0 {
		return nil
	}

	for _, file := range files {
		path := s + "/" + file.Name()
		recurse := checkFile(path, file)

		if recurse && file.IsDir() {
			readDir(path)
		}
	}
	return nil
}

// Start the program with the current options. Options param is read only
func Start(options Options) {
	opt = options
	fmt.Println("[+] Starting in directory:", opt.currentDir)

	err := readDir(opt.currentDir)
	if err != nil {
		fmt.Println("[-]", err)
	}

	fmt.Println()
}
<|endoftext|>


<commit_before>package iosupport

import (
	"os"
	"strings"
)

// Provide tool like GNU wc command
// Usage:
//
//  file, _ := os.Open("my_file.txt")
//  wc := iosupport.NewWordCount(file)
//  wc.Perform()
//  println(wc.Bytes)
//  println(wc.Chars)
//  println(wc.Words)
//  println(wc.Lines)
//
//  - With options
//
//  wc := iosupport.NewWordCount(file)
//  opts := iosupport.NewWordCountOptions()
//  opts.CountByte = true
//  opts.CountChar = true
//  opts.CountWord = true
//  opts.CountLine = true
//  wc.Opts = opts
//  wc.Perform()

type WordCount struct {
	s     *Scanner          // The scanner provided by the client.
	Opts  *WordCountOptions // Defines what is counted
	Bytes int               // Bytes counter
	Chars int               // Chars counter
	Words int               // Words counter
	Lines int               // Lines counter
	err   error             // Sticky error.
}

type WordCountOptions struct {
	CountByte bool
	CountChar bool
	CountWord bool
	CountLine bool
}

func NewWordCount(f *os.File) *WordCount {
	return &WordCount{
		s:     NewScanner(f),
		Opts:  defaultWordCounterOptions(),
		Bytes: 0,
		Chars: 0,
		Words: 0,
		Lines: 0,
	}
}

func NewWordCountOptions() *WordCountOptions {
	return new(WordCountOptions)
}

func defaultWordCounterOptions() *WordCountOptions {
	return &WordCountOptions{
		CountByte: false,
		CountChar: true,
		CountWord: true,
		CountLine: true,
	}
}

func (wc *WordCount) Perform() error {
	for wc.s.ScanLine() {
		if wc.s.Err() != nil {
			return wc.s.Err()
		}

		if wc.Opts.CountByte {
			// +1 for EOL character
			wc.Bytes += len(wc.s.Bytes()) + 1
		}
		if wc.Opts.CountChar {
			// +1 for EOL character
			wc.Chars += len(wc.s.Text()) + 1
		}
		if wc.Opts.CountWord {
			wc.Words += CountWords(wc.s.Text())
		}
		if wc.Opts.CountLine {
			wc.Lines++
		}
	}
	return nil
}

func CountWords(str string) int {
	if len(str) == 0 {
		return 0
	}
	words := len(strings.Split(str, " "))
	words += len(strings.Split(str, string('\t'))) - 1 // -1 because string itself is aready counted
	return words
}
<commit_msg>Remove used struc field<commit_after>package iosupport

import (
	"os"
	"strings"
)

// Provide tool like GNU wc command
// Usage:
//
//  file, _ := os.Open("my_file.txt")
//  wc := iosupport.NewWordCount(file)
//  wc.Perform()
//  println(wc.Bytes)
//  println(wc.Chars)
//  println(wc.Words)
//  println(wc.Lines)
//
//  - With options
//
//  wc := iosupport.NewWordCount(file)
//  opts := iosupport.NewWordCountOptions()
//  opts.CountByte = true
//  opts.CountChar = true
//  opts.CountWord = true
//  opts.CountLine = true
//  wc.Opts = opts
//  wc.Perform()

type WordCount struct {
	s     *Scanner          // The scanner provided by the client.
	Opts  *WordCountOptions // Defines what is counted
	Bytes int               // Bytes counter
	Chars int               // Chars counter
	Words int               // Words counter
	Lines int               // Lines counter
}

type WordCountOptions struct {
	CountByte bool
	CountChar bool
	CountWord bool
	CountLine bool
}

func NewWordCount(f *os.File) *WordCount {
	return &WordCount{
		s:     NewScanner(f),
		Opts:  defaultWordCounterOptions(),
		Bytes: 0,
		Chars: 0,
		Words: 0,
		Lines: 0,
	}
}

func NewWordCountOptions() *WordCountOptions {
	return new(WordCountOptions)
}

func defaultWordCounterOptions() *WordCountOptions {
	return &WordCountOptions{
		CountByte: false,
		CountChar: true,
		CountWord: true,
		CountLine: true,
	}
}

func (wc *WordCount) Perform() error {
	for wc.s.ScanLine() {
		if wc.s.Err() != nil {
			return wc.s.Err()
		}

		if wc.Opts.CountByte {
			// +1 for EOL character
			wc.Bytes += len(wc.s.Bytes()) + 1
		}
		if wc.Opts.CountChar {
			// +1 for EOL character
			wc.Chars += len(wc.s.Text()) + 1
		}
		if wc.Opts.CountWord {
			wc.Words += CountWords(wc.s.Text())
		}
		if wc.Opts.CountLine {
			wc.Lines++
		}
	}
	return nil
}

func CountWords(str string) int {
	if len(str) == 0 {
		return 0
	}
	words := len(strings.Split(str, " "))
	words += len(strings.Split(str, string('\t'))) - 1 // -1 because string itself is aready counted
	return words
}
<|endoftext|>


<commit_before>//
// Package ws provides the core library used by cmds/ws/ws.go, cmds/wsinit/wsinit.go and
// cmds/wsindexer/wsindexer.go
//
// Copyright (c) 2014 - 2016, R. S. Doiel
// All rights not granted herein are expressly reserved by R. S. Doiel.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package ws

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"log"
	"math/big"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	// Version is used as a release number number for ws, wsinit, wsindexer
	Version = "0.0.8"
)

// Configuration provides the basic settings used by _ws_ and _wsint_ commands.
type Configuration struct {
	URL     *url.URL
	DocRoot string
	SSLKey  string
	SSLCert string
}

var configFileTemplate = `#!/bin/bash
# generated %d-%02d-%02d by ws version %s
export WS_URL=%q
export WS_DOCROOT=%q
export WS_SSL_KEY=%q
export WS_SSL_CERT=%q
`

// SetDefaults sets the structure to common default values
// + DocRoot = "."
// + URL = http://localhost:8000
func (config *Configuration) SetDefaults() {
	u, _ := url.Parse("http://localhost:8000")
	config.URL = u
	config.DocRoot = "."
}

// Getenv scans the environment variables and updates the fields in
// the configuration. If there is a problem parsing WS_URL then an
// error is returned.
func (config *Configuration) Getenv() error {
	if s := os.Getenv("WS_DOCROOT"); s != "" {
		config.DocRoot = s
	}
	if s := os.Getenv("WS_SSL_KEY"); s != "" {
		config.SSLKey = s
	}
	if s := os.Getenv("WS_SSL_CERT"); s != "" {
		config.SSLCert = s
	}
	if s := os.Getenv("WS_URL"); s != "" {
		u, err := url.Parse(s)
		config.URL = u
		return err
	}
	return nil
}

// String returns a multiline block of text suitable to save in a text file.
func (config *Configuration) String() string {
	var u string
	now := time.Now()
	yr, mn, dy := now.Date()
	if config.URL != nil {
		u = config.URL.String()
	}
	return fmt.Sprintf(configFileTemplate, yr, mn, dy, Version, u, config.DocRoot, config.SSLKey, config.SSLCert)
}

// Validate performs a sanity check of the values in the configuration
// Returns nil if OK otherwise returns error
func (config *Configuration) Validate() error {
	scheme := config.URL.Scheme
	docRoot := config.DocRoot
	sslkey := config.SSLKey
	sslcert := config.SSLCert
	if scheme == "https" {
		if sslkey == "" || sslcert == "" {
			return fmt.Errorf("Cannot use https without specifying SSL Cert and Key")
		}
		if _, err := os.Stat(sslkey); os.IsNotExist(err) {
			return fmt.Errorf("Cannot find %s, %s", sslkey, err)
		}
		if _, err := os.Stat(sslcert); os.IsNotExist(err) {
			return fmt.Errorf("Cannot find %s, %s", sslcert, err)
		}
	}
	if _, err := os.Stat(docRoot); os.IsNotExist(err) {
		return fmt.Errorf("Can't find document root %s, %s", docRoot, err)
	}
	return nil
}

// GenerateKeyAndCert will generate a new SSL Key/Cert pair if none exist.
// It will return a error if they already exist.
func (config *Configuration) GenerateKeyAndCert() error {
	// Double check to see if we need a self-signed cert...
	if config.URL.Scheme != "https" {
		log.Printf("Skipping key/cert creation, not needed for %s", config.URL.String())
		return nil
	}
	// Check to see if config.SSLKey and config.SSLCert already exist, if not create them.
	if config.SSLKey == "" || config.SSLCert == "" {
		log.Println("Skipping key/cert creation, not defined by config")
		return nil
	}
	if _, err := os.Stat(config.SSLCert); os.IsExist(err) == true {
		log.Printf("%s already exists, skipping key creation", config.SSLCert)
		return nil
	}
	if _, err := os.Stat(config.SSLKey); os.IsExist(err) == true {
		log.Printf("%s already exists, skipping key creation", config.SSLKey)
		return nil
	}

	hostname := config.URL.Host
	// Trim our hostname before the port number if needed
	if pos := strings.Index(hostname, ":"); pos > 0 {
		hostname = hostname[0:pos]
	}
	if hostname == "" {
		hostname = "localhost"
	}

	rsaBits := 2048
	log.Printf("Generating %d bit key", rsaBits)
	priv, err := rsa.GenerateKey(rand.Reader, rsaBits)
	if err != nil {
		return err
	}
	notBefore := time.Now()
	yr, _, _ := notBefore.Date()
	yr++
	notAfter := time.Date(yr, 12, 31, 2, 59, 59, 0, time.UTC)

	log.Println("Setting up cerificates")
	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(0),
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
		},
		NotBefore:             notBefore,
		NotAfter:              notAfter,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}

	log.Println("Checking IP address")
	if ip := net.ParseIP(hostname); ip != nil {
		template.IPAddresses = append(template.IPAddresses, ip)
	} else {
		template.DNSNames = append(template.DNSNames, hostname)
	}

	template.IsCA = false
	log.Println("Generating x509 certs from template")
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return err
	}

	log.Printf("Creating %s\n", config.SSLCert)
	// make the directory if needed.
	dname, _ := filepath.Split(config.SSLCert)
	if _, err := os.Stat(dname); os.IsNotExist(err) {
		err := os.MkdirAll(dname, 0770)
		if err != nil {
			return fmt.Errorf("Can't create directory %s, %s", dname, err)
		}
	}

	certOut, err := os.Create(config.SSLCert)
	if err != nil {
		return err
	}
	log.Printf("Encode %s as pem", config.SSLCert)
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	log.Printf("Wrote %s\n", config.SSLCert)

	// make the directory if needed.
	dname, _ = filepath.Split(config.SSLKey)
	if _, err := os.Stat(dname); os.IsNotExist(err) {
		err := os.MkdirAll(dname, 0770)
		if err != nil {
			return fmt.Errorf("Can't create directory %s, %s", dname, err)
		}
	}
	log.Printf("Creating %s\n", config.SSLKey)
	keyOut, err := os.OpenFile(config.SSLKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	log.Printf("Encode %s as pem", config.SSLKey)
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()
	log.Printf("Wrote %s\n", config.SSLKey)
	// We got this far so no errors
	return nil
}

// InitializeProject scans the current working path and identifies what
// directories need to be created, creates them, adds SSL keys/certs if
// needed and returns a suggested configuration file.
func (config *Configuration) InitializeProject() (string, error) {
	// Only append SSL dir and files if config.URL.Scheme is https
	directories := []string{
		config.DocRoot,
	}
	if config.URL.Scheme == "https" {
		sslKeyDir, _ := filepath.Split(config.SSLKey)
		sslCertDir, _ := filepath.Split(config.SSLCert)
		directories = append(directories, sslKeyDir)
		directories = append(directories, sslCertDir)
	}

	// Check if directory exists, if not created it
	for _, directory := range directories {
		if directory != "" {
			_, err := os.Stat(directory)
			if os.IsNotExist(err) == true {
				if os.MkdirAll(directory, 0775) != nil {
					return "", fmt.Errorf("Can't create %s, %s", directory, err)
				}
			}
		}
	}
	if config.URL.Scheme == "https" {
		if err := config.GenerateKeyAndCert(); err != nil {
			return config.String(), err
		}
	}
	// return a suggested config file or error
	return config.String(), nil
}
<commit_msg>snapshot<commit_after>//
// Package ws provides the core library used by cmds/ws/ws.go, cmds/wsinit/wsinit.go and
// cmds/wsindexer/wsindexer.go
//
// Copyright (c) 2014 - 2016, R. S. Doiel
// All rights not granted herein are expressly reserved by R. S. Doiel.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
package ws

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"log"
	"math/big"
	"net"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	// Version is used as a release number number for ws, wsinit, wsindexer
	Version = "v0.0.9"
)

// Configuration provides the basic settings used by _ws_ and _wsint_ commands.
type Configuration struct {
	URL     *url.URL
	DocRoot string
	SSLKey  string
	SSLCert string
}

var configFileTemplate = `#!/bin/bash
# generated %d-%02d-%02d by ws version %s
export WS_URL=%q
export WS_DOCROOT=%q
export WS_SSL_KEY=%q
export WS_SSL_CERT=%q
`

// SetDefaults sets the structure to common default values
// + DocRoot = "."
// + URL = http://localhost:8000
func (config *Configuration) SetDefaults() {
	u, _ := url.Parse("http://localhost:8000")
	config.URL = u
	config.DocRoot = "."
}

// Getenv scans the environment variables and updates the fields in
// the configuration. If there is a problem parsing WS_URL then an
// error is returned.
func (config *Configuration) Getenv() error {
	if s := os.Getenv("WS_DOCROOT"); s != "" {
		config.DocRoot = s
	}
	if s := os.Getenv("WS_SSL_KEY"); s != "" {
		config.SSLKey = s
	}
	if s := os.Getenv("WS_SSL_CERT"); s != "" {
		config.SSLCert = s
	}
	if s := os.Getenv("WS_URL"); s != "" {
		u, err := url.Parse(s)
		config.URL = u
		return err
	}
	return nil
}

// String returns a multiline block of text suitable to save in a text file.
func (config *Configuration) String() string {
	var u string
	now := time.Now()
	yr, mn, dy := now.Date()
	if config.URL != nil {
		u = config.URL.String()
	}
	return fmt.Sprintf(configFileTemplate, yr, mn, dy, Version, u, config.DocRoot, config.SSLKey, config.SSLCert)
}

// Validate performs a sanity check of the values in the configuration
// Returns nil if OK otherwise returns error
func (config *Configuration) Validate() error {
	scheme := config.URL.Scheme
	docRoot := config.DocRoot
	sslkey := config.SSLKey
	sslcert := config.SSLCert
	if scheme == "https" {
		if sslkey == "" || sslcert == "" {
			return fmt.Errorf("Cannot use https without specifying SSL Cert and Key")
		}
		if _, err := os.Stat(sslkey); os.IsNotExist(err) {
			return fmt.Errorf("Cannot find %s, %s", sslkey, err)
		}
		if _, err := os.Stat(sslcert); os.IsNotExist(err) {
			return fmt.Errorf("Cannot find %s, %s", sslcert, err)
		}
	}
	if _, err := os.Stat(docRoot); os.IsNotExist(err) {
		return fmt.Errorf("Can't find document root %s, %s", docRoot, err)
	}
	return nil
}

// GenerateKeyAndCert will generate a new SSL Key/Cert pair if none exist.
// It will return a error if they already exist.
func (config *Configuration) GenerateKeyAndCert() error {
	// Double check to see if we need a self-signed cert...
	if config.URL.Scheme != "https" {
		log.Printf("Skipping key/cert creation, not needed for %s", config.URL.String())
		return nil
	}
	// Check to see if config.SSLKey and config.SSLCert already exist, if not create them.
	if config.SSLKey == "" || config.SSLCert == "" {
		log.Println("Skipping key/cert creation, not defined by config")
		return nil
	}
	if _, err := os.Stat(config.SSLCert); os.IsExist(err) == true {
		log.Printf("%s already exists, skipping key creation", config.SSLCert)
		return nil
	}
	if _, err := os.Stat(config.SSLKey); os.IsExist(err) == true {
		log.Printf("%s already exists, skipping key creation", config.SSLKey)
		return nil
	}

	hostname := config.URL.Host
	// Trim our hostname before the port number if needed
	if pos := strings.Index(hostname, ":"); pos > 0 {
		hostname = hostname[0:pos]
	}
	if hostname == "" {
		hostname = "localhost"
	}

	rsaBits := 2048
	log.Printf("Generating %d bit key", rsaBits)
	priv, err := rsa.GenerateKey(rand.Reader, rsaBits)
	if err != nil {
		return err
	}
	notBefore := time.Now()
	yr, _, _ := notBefore.Date()
	yr++
	notAfter := time.Date(yr, 12, 31, 2, 59, 59, 0, time.UTC)

	log.Println("Setting up cerificates")
	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(0),
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
		},
		NotBefore:             notBefore,
		NotAfter:              notAfter,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}

	log.Println("Checking IP address")
	if ip := net.ParseIP(hostname); ip != nil {
		template.IPAddresses = append(template.IPAddresses, ip)
	} else {
		template.DNSNames = append(template.DNSNames, hostname)
	}

	template.IsCA = false
	log.Println("Generating x509 certs from template")
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return err
	}

	log.Printf("Creating %s\n", config.SSLCert)
	// make the directory if needed.
	dname, _ := filepath.Split(config.SSLCert)
	if _, err := os.Stat(dname); os.IsNotExist(err) {
		err := os.MkdirAll(dname, 0770)
		if err != nil {
			return fmt.Errorf("Can't create directory %s, %s", dname, err)
		}
	}

	certOut, err := os.Create(config.SSLCert)
	if err != nil {
		return err
	}
	log.Printf("Encode %s as pem", config.SSLCert)
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	log.Printf("Wrote %s\n", config.SSLCert)

	// make the directory if needed.
	dname, _ = filepath.Split(config.SSLKey)
	if _, err := os.Stat(dname); os.IsNotExist(err) {
		err := os.MkdirAll(dname, 0770)
		if err != nil {
			return fmt.Errorf("Can't create directory %s, %s", dname, err)
		}
	}
	log.Printf("Creating %s\n", config.SSLKey)
	keyOut, err := os.OpenFile(config.SSLKey, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}
	log.Printf("Encode %s as pem", config.SSLKey)
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
	keyOut.Close()
	log.Printf("Wrote %s\n", config.SSLKey)
	// We got this far so no errors
	return nil
}

// InitializeProject scans the current working path and identifies what
// directories need to be created, creates them, adds SSL keys/certs if
// needed and returns a suggested configuration file.
func (config *Configuration) InitializeProject() (string, error) {
	// Only append SSL dir and files if config.URL.Scheme is https
	directories := []string{
		config.DocRoot,
	}
	if config.URL.Scheme == "https" {
		sslKeyDir, _ := filepath.Split(config.SSLKey)
		sslCertDir, _ := filepath.Split(config.SSLCert)
		directories = append(directories, sslKeyDir)
		directories = append(directories, sslCertDir)
	}

	// Check if directory exists, if not created it
	for _, directory := range directories {
		if directory != "" {
			_, err := os.Stat(directory)
			if os.IsNotExist(err) == true {
				if os.MkdirAll(directory, 0775) != nil {
					return "", fmt.Errorf("Can't create %s, %s", directory, err)
				}
			}
		}
	}
	if config.URL.Scheme == "https" {
		if err := config.GenerateKeyAndCert(); err != nil {
			return config.String(), err
		}
	}
	// return a suggested config file or error
	return config.String(), nil
}
<|endoftext|>


<commit_before>package agency

import (
	"encoding/json"
	"time"
)

type durationCounter struct {
	lived time.Duration
	value float64
}

func (dc *durationCounter) push(n float64, d time.Duration) float64 {
	dc.value = (dc.value*float64(dc.lived) + n*float64(time.Second)) / float64(d)
	dc.lived = d
	return dc.value
}

func (dc *durationCounter) MarshalJSON() ([]byte, error) {
	return json.Marshal(dc.value)
}

type State struct {
	Start                 time.Time
	InsertedPerSecond     *durationCounter
	AcquiredPerSecond     *durationCounter
	AcknowledgedPerSecond *durationCounter
	DroppedPerSecond      *durationCounter
}

func NewState() *State {
	return &State{
		Start:                 time.Now(),
		InsertedPerSecond:     &durationCounter{},
		AcquiredPerSecond:     &durationCounter{},
		AcknowledgedPerSecond: &durationCounter{},
		DroppedPerSecond:      &durationCounter{},
	}
}

func (s *State) Lived() time.Duration {
	return time.Now().Sub(s.Start)
}

func (s *State) insert() {
	s.InsertedPerSecond.push(1, s.Lived())
}

func (s *State) acq() {
	s.AcquiredPerSecond.push(1, s.Lived())
}

func (s *State) ack() {
	s.AcknowledgedPerSecond.push(1, s.Lived())
}

func (s *State) dropped() {
	s.DroppedPerSecond.push(1, s.Lived())
}

func (s *State) MarshalJSON() ([]byte, error) {
	o := &struct {
		Start                 time.Time
		InsertedPerSecond     *durationCounter
		AcquiredPerSecond     *durationCounter
		AcknowledgedPerSecond *durationCounter
		DroppedPerSecond      *durationCounter
		Lived                 time.Duration
	}{
		Start:                 s.Start,
		InsertedPerSecond:     s.InsertedPerSecond,
		AcquiredPerSecond:     s.AcquiredPerSecond,
		AcknowledgedPerSecond: s.AcknowledgedPerSecond,
		DroppedPerSecond:      s.DroppedPerSecond,
		Lived:                 s.Lived(),
	}
	return json.Marshal(o)
}
<commit_msg>update state<commit_after>package agency

import (
	"encoding/json"
	"time"
)

type durationCounter struct {
	lived time.Duration
	value float64
}

func (dc *durationCounter) push(n float64, d time.Duration) float64 {
	dc.value = (dc.value*float64(dc.lived) + n*float64(time.Second)) / float64(d)
	dc.lived = d
	return dc.value
}

func (dc *durationCounter) MarshalJSON() ([]byte, error) {
	return json.Marshal(dc.value)
}

type State struct {
	Start                 time.Time
	Insert                int64
	InsertedPerSecond     *durationCounter
	Acquired              int64
	AcquiredPerSecond     *durationCounter
	Acknowledged          int64
	AcknowledgedPerSecond *durationCounter
	Dropped               int64
	DroppedPerSecond      *durationCounter
}

func NewState() *State {
	return &State{
		Start:                 time.Now(),
		InsertedPerSecond:     &durationCounter{},
		AcquiredPerSecond:     &durationCounter{},
		AcknowledgedPerSecond: &durationCounter{},
		DroppedPerSecond:      &durationCounter{},
	}
}

func (s *State) Lived() time.Duration {
	return time.Now().Sub(s.Start)
}

func (s *State) insert() {
	s.Insert += 1
	s.InsertedPerSecond.push(1, s.Lived())
}

func (s *State) acq() {
	s.Acquired += 1
	s.AcquiredPerSecond.push(1, s.Lived())
}

func (s *State) ack() {
	s.Acknowledged += 1
	s.AcknowledgedPerSecond.push(1, s.Lived())
}

func (s *State) dropped() {
	s.Dropped += 1
	s.DroppedPerSecond.push(1, s.Lived())
}

func (s *State) MarshalJSON() ([]byte, error) {
	o := &struct {
		Start                 time.Time
		Insert                int64
		InsertedPerSecond     *durationCounter
		Acquired              int64
		AcquiredPerSecond     *durationCounter
		Acknowledged          int64
		AcknowledgedPerSecond *durationCounter
		Dropped               int64
		DroppedPerSecond      *durationCounter
		Lived                 time.Duration
	}{
		Start:                 s.Start,
		InsertedPerSecond:     s.InsertedPerSecond,
		AcquiredPerSecond:     s.AcquiredPerSecond,
		AcknowledgedPerSecond: s.AcknowledgedPerSecond,
		DroppedPerSecond:      s.DroppedPerSecond,
		Insert:                s.Insert,
		Acquired:              s.Acquired,
		Acknowledged:          s.Acknowledged,
		Dropped:               s.Dropped,
		Lived:                 s.Lived(),
	}
	return json.Marshal(o)
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	as "github.com/aerospike/aerospike-client-go"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	// StatsMetrics lists the keys we report from aero's info:statistics
	// command.
	// See `asinfo -l -v statistics` for the full list.
	StatsMetrics = []metric{
		gauge("cluster_size", "cluster size"),
		gauge("system_free_mem_pct", "system free mem pct"),
		gauge("objects", "objects"),
		gauge("sub_objects", "sub objects"),
		gauge("info_queue", "info queue"),
		gauge("delete_queue", "delete queue"),
		gauge("client_connections", "client connections"),
		gauge("heartbeat_connections", "heartbeat connections"),
		gauge("fabric_connections", "fabric connections"),
		gauge("batch_index_initiate", "batch index initiate"),
		gauge("batch_index_complete", "batch index complete"),
		gauge("batch_index_error", "batch index error"),
		gauge("batch_index_timeout", "batch index timeout"),
		gauge("batch_initiate", "batch initiate"),
		gauge("batch_queue", "batch queue"),
		gauge("batch_error", "batch error"),
		gauge("batch_timeout", "batch timeout"),
		gauge("scans_active", "scans active"),
		gauge("query_short_running", "query short running"),
		gauge("query_long_running", "query long running"),
		gauge("sindex_ucgarbage_found", "sindex ucgarbage found"),
		gauge("sindex_gc_locktimedout", "sindex gc locktimedout"),
		gauge("sindex_gc_inactivity_dur", "sindex gc inactivity dur"),
		gauge("sindex_gc_activity_dur", "sindex gc activity dur"),
		gauge("sindex_gc_list_creation_time", "sindex gc list creation time"),
		gauge("sindex_gc_list_deletion_time", "sindex gc list deletion time"),
		gauge("sindex_gc_objects_validated", "sindex gc objects validated"),
		gauge("sindex_gc_garbage_found", "sindex gc garbage found"),
		gauge("sindex_gc_garbage_cleaned", "sindex gc garbage cleaned"),
		counter("fabric_msgs_sent", "fabric msgs sent"),
		counter("fabric_msgs_rcvd", "fabric msgs rcvd"),
		counter("xdr_ship_success", "xdr ship success"),
		counter("xdr_ship_delete_success", "xdr ship delete success"),
		counter("xdr_ship_source_error", "xdr ship source error"),
		counter("xdr_ship_destination_error", "xdr ship destination error"),
		gauge("xdr_ship_bytes", "xdr ship bytes"),
		gauge("xdr_ship_latency_avg", "xdr ship latency avg"),
		gauge("xdr_ship_compression_avg_pct", "xdr ship compression avg pct"),
		gauge("xdr_ship_inflight_objects", "xdr ship inflight objects"),
		gauge("xdr_ship_outstanding_objects", "xdr ship outstanding objects"),
		counter("xdr_read_success", "xdr read success"),
		counter("xdr_read_error", "xdr read error"),
		gauge("xdr_read_notfound", "xdr read notfound"),
		gauge("xdr_read_latency_avg", "xdr read latency avg"),
		gauge("xdr_read_active_avg_pct", "xdr read active avg pct"),
		gauge("xdr_read_idle_avg_pct", "xdr read idle avg pct"),
		gauge("xdr_read_reqq_used", "xdr read reqq used"),
		gauge("xdr_read_reqq_used_pct", "xdr read reqq used pct"),
		gauge("xdr_read_respq_used", "xdr read respq used"),
		gauge("xdr_read_txnq_used", "xdr read txnq used"),
		gauge("xdr_read_txnq_used_pct", "xdr read txnq used pct"),
		gauge("xdr_queue_overflow_error", "xdr queue overflow error"),
		gauge("xdr_hotkey_fetch", "xdr hotkey fetch"),
		gauge("xdr_hotkey_skip", "xdr hotkey skip"),
		counter("xdr_unknown_namespace_error", "xdr unknown namespace error"),
		counter("xdr_uninitialized_destination_error", "xdr uninitialized destination error"),
		gauge("xdr_timelag", "xdr timelag"),
		gauge("xdr_throughput", "xdr throughput"),
	}
)

type statsCollector cmetrics

func newStatsCollector() statsCollector {
	smetrics := map[string]cmetric{}
	for _, m := range StatsMetrics {
		smetrics[m.aeroName] = cmetric{
			desc: prometheus.NewDesc(
				promkey(systemNode, m.aeroName),
				m.desc,
				nil,
				nil,
			),
			typ: m.typ,
		}
	}
	return smetrics
}

func (sc statsCollector) describe(ch chan<- *prometheus.Desc) {
	for _, s := range sc {
		ch <- s.desc
	}
}

func (sc statsCollector) collect(conn *as.Connection, ch chan<- prometheus.Metric) {
	res, err := as.RequestInfo(conn, "statistics")
	if err != nil {
		log.Print(err)
		return
	}
	infoCollect(ch, cmetrics(sc), res["statistics"])
}
<commit_msg>update counters for 3.15<commit_after>package main

import (
	"log"

	as "github.com/aerospike/aerospike-client-go"
	"github.com/prometheus/client_golang/prometheus"
)

var (
	// StatsMetrics lists the keys we report from aero's info:statistics
	// command.
	// See `asinfo -l -v statistics` for the full list.
	StatsMetrics = []metric{
		gauge("cluster_size", "cluster size"),
		// cluster_key=C0758EC6A81F
		// cluster_integrity=true
		// cluster_is_member=true
		counter("uptime", "uptime"),
		gauge("system_free_mem_pct", "system free mem pct"),
		// system_swapping=false
		gauge("heap_allocated_kbytes", "heap allocated kbytes"),
		gauge("heap_active_kbytes", "heap active kbytes"),
		gauge("heap_mapped_kbytes", "heap mapped kbytes"),
		gauge("heap_efficiency_pct", "heap efficiency pct"),
		gauge("heap_site_count", "heap site count"),
		gauge("objects", "objects"),
		gauge("tombstones", "tombstones"),
		gauge("tsvc_queue", "tsvc queue"),
		gauge("info_queue", "info queue"),
		gauge("delete_queue", "delete queue"),
		// rw_in_progress=0
		// proxy_in_progress=0
		// tree_gc_queue=0
		gauge("client_connections", "client connections"),
		gauge("heartbeat_connections", "heartbeat connections"),
		gauge("fabric_connections", "fabric connections"),
		counter("heartbeat_received_self", "heartbeat received self"),
		counter("heartbeat_received_foreign", "heartbeat received foreign"),
		counter("reaped_fds", "reaped fds"),
		counter("info_complete", "info complete"),
		counter("demarshal_error", "demarshal error"),
		counter("early_tsvc_client_error", "early tsvc client error"),
		counter("early_tsvc_batch_sub_error", "early tsvc batch sub error"),
		counter("early_tsvc_udf_sub_error", "early tsvc udf sub error"),
		gauge("batch_index_initiate", "batch index initiate"),
		// batch_index_queue=0:0,0:0,0:0,0:0
		gauge("batch_index_complete", "batch index complete"),
		gauge("batch_index_error", "batch index error"),
		gauge("batch_index_timeout", "batch index timeout"),
		gauge("batch_index_unused_buffers", "batch index unused buffers"),
		gauge("batch_index_huge_buffers", "batch index huge buffers"),
		counter("batch_index_created_buffers", "batch index created buffers"),
		counter("batch_index_destroyed_buffers", "batch index destroyed buffers"),
		gauge("batch_initiate", "batch initiate"),
		gauge("batch_queue", "batch queue"),
		gauge("batch_error", "batch error"),
		gauge("batch_timeout", "batch timeout"),
		gauge("scans_active", "scans active"),
		gauge("query_short_running", "query short running"),
		gauge("query_long_running", "query long running"),
		gauge("sindex_ucgarbage_found", "sindex ucgarbage found"),
		gauge("sindex_gc_locktimedout", "sindex gc locktimedout"),
		gauge("sindex_gc_list_creation_time", "sindex gc list creation time"),
		gauge("sindex_gc_list_deletion_time", "sindex gc list deletion time"),
		gauge("sindex_gc_objects_validated", "sindex gc objects validated"),
		gauge("sindex_gc_garbage_found", "sindex gc garbage found"),
		gauge("sindex_gc_garbage_cleaned", "sindex gc garbage cleaned"),
		// paxos_principal=BB9508FED001500
		// migrate_allowed=true
		gauge("migrate_partitions_remaining", "migrate partitions remaining"),
		gauge("fabric_bulk_send_rate", "fabric bulk send rate"),
		gauge("fabric_bulk_recv_rate", "fabric bulk recv rate"),
		gauge("fabric_ctrl_send_rate", "fabric ctrl send rate"),
		gauge("fabric_ctrl_recv_rate", "fabric ctrl recv rate"),
		gauge("fabric_meta_send_rate", "fabric meta send rate"),
		gauge("fabric_meta_recv_rate", "fabric meta recv rate"),
		gauge("fabric_rw_send_rate", "fabric rw send rate"),
		gauge("fabric_rw_recv_rate", "fabric rw recv rate"),
		counter("xdr_ship_success", "xdr ship success"),
		counter("xdr_ship_delete_success", "xdr ship delete success"),
		counter("xdr_ship_source_error", "xdr ship source error"),
		counter("xdr_ship_destination_error", "xdr ship destination error"),
		gauge("xdr_ship_bytes", "xdr ship bytes"),
		gauge("xdr_ship_latency_avg", "xdr ship latency avg"),
		gauge("xdr_ship_compression_avg_pct", "xdr ship compression avg pct"),
		gauge("xdr_ship_inflight_objects", "xdr ship inflight objects"),
		gauge("xdr_ship_outstanding_objects", "xdr ship outstanding objects"),
		counter("xdr_read_success", "xdr read success"),
		counter("xdr_read_error", "xdr read error"),
		gauge("xdr_read_notfound", "xdr read notfound"),
		gauge("xdr_read_latency_avg", "xdr read latency avg"),
		gauge("xdr_read_active_avg_pct", "xdr read active avg pct"),
		gauge("xdr_read_idle_avg_pct", "xdr read idle avg pct"),
		gauge("xdr_read_reqq_used", "xdr read reqq used"),
		gauge("xdr_read_reqq_used_pct", "xdr read reqq used pct"),
		gauge("xdr_read_respq_used", "xdr read respq used"),
		gauge("xdr_read_txnq_used", "xdr read txnq used"),
		gauge("xdr_read_txnq_used_pct", "xdr read txnq used pct"),
		gauge("xdr_queue_overflow_error", "xdr queue overflow error"),
		gauge("xdr_hotkey_fetch", "xdr hotkey fetch"),
		gauge("xdr_hotkey_skip", "xdr hotkey skip"),
		counter("xdr_unknown_namespace_error", "xdr unknown namespace error"),
		counter("xdr_uninitialized_destination_error", "xdr uninitialized destination error"),
		gauge("xdr_timelag", "xdr timelag"),
		gauge("xdr_throughput", "xdr throughput"),
	}
)

type statsCollector cmetrics

func newStatsCollector() statsCollector {
	smetrics := map[string]cmetric{}
	for _, m := range StatsMetrics {
		smetrics[m.aeroName] = cmetric{
			desc: prometheus.NewDesc(
				promkey(systemNode, m.aeroName),
				m.desc,
				nil,
				nil,
			),
			typ: m.typ,
		}
	}
	return smetrics
}

func (sc statsCollector) describe(ch chan<- *prometheus.Desc) {
	for _, s := range sc {
		ch <- s.desc
	}
}

func (sc statsCollector) collect(conn *as.Connection, ch chan<- prometheus.Metric) {
	res, err := as.RequestInfo(conn, "statistics")
	if err != nil {
		log.Print(err)
		return
	}
	infoCollect(ch, cmetrics(sc), res["statistics"])
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/melvinmt/firebase"
)

type Domain struct {
	Time time.Time
	Name string
}

type DomainStore struct {
	history *firebase.Reference
	domain  *firebase.Reference
}

func NewDomainStore(fbUrl, auth string) DomainStore {
	historyUrl := fmt.Sprintf("%s/history", fbUrl)
	domainUrl := fmt.Sprintf("%s/domain", fbUrl)
	return DomainStore{
		history: firebase.NewReference(historyUrl).Auth(auth),
		domain:  firebase.NewReference(domainUrl).Auth(auth),
	}
}

func (d DomainStore) Domain() (domain string, err error) {
	err = d.domain.Value(&domain)
	return domain, err
}

func (d DomainStore) History() (domains []Domain, err error) {
	var m map[string]Domain
	err = d.history.Value(&m)
	for _, val := range m {
		domains = append(domains, val)
	}
	return domains, err
}

func (d DomainStore) Set(domainName string) error {
	domain := Domain{
		Time: time.Now(),
		Name: domainName,
	}

	err := d.domain.Write(domain.Name)
	if err != nil {
		return fmt.Errorf("Failed to set current domain: %v", err)
	}

	err = d.history.Push(domain)
	if err != nil {
		return fmt.Errorf("Failed to add domain to history: %v", err)
	}
	return nil
}
<commit_msg>Added sorting of history<commit_after>package main

import (
	"fmt"
	"sort"
	"time"

	"github.com/melvinmt/firebase"
)

type Domain struct {
	Time time.Time
	Name string
}

type DomainStore struct {
	history *firebase.Reference
	domain  *firebase.Reference
}

func NewDomainStore(fbUrl, auth string) DomainStore {
	historyUrl := fmt.Sprintf("%s/history", fbUrl)
	domainUrl := fmt.Sprintf("%s/domain", fbUrl)
	return DomainStore{
		history: firebase.NewReference(historyUrl).Auth(auth),
		domain:  firebase.NewReference(domainUrl).Auth(auth),
	}
}

func (d DomainStore) Domain() (domain string, err error) {
	err = d.domain.Value(&domain)
	return domain, err
}

func (d DomainStore) History() (domains []Domain, err error) {
	var m map[string]Domain
	err = d.history.Value(&m)

	var keys []string
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for _, k := range keys {
		domains = append(domains, m[k])
	}
	return domains, err
}

func (d DomainStore) Set(domainName string) error {
	domain := Domain{
		Time: time.Now(),
		Name: domainName,
	}

	err := d.domain.Write(domain.Name)
	if err != nil {
		return fmt.Errorf("Failed to set current domain: %v", err)
	}

	err = d.history.Push(domain)
	if err != nil {
		return fmt.Errorf("Failed to add domain to history: %v", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package rkv

import (
	"bytes"
	"fmt"
	"math/rand"
	"time"

	"golang.org/x/net/context"

	"github.com/relab/raft"
	commonpb "github.com/relab/raft/raftpb"
	cmdpb "github.com/relab/rkv/cmdpb"
)

// TODO Context timeout should depend on heartbeat setting.

// Store is a key-value store backed by a map.
type Store struct {
	store map[string]string

	nextID  uint64
	clients map[string]uint64

	waiting map[string]chan interface{}
	read    chan *readRequest

	raft raft.Raft
}

type readRequest struct {
	key   string
	value chan<- string
}

// NewStore returns a newly initialized store.
func NewStore(raft raft.Raft) *Store {
	s := &Store{
		store:   make(map[string]string),
		clients: make(map[string]uint64),
		waiting: make(map[string]chan interface{}),
		read:    make(chan *readRequest),
		raft:    raft,
	}

	go s.run()

	return s
}

func (s *Store) run() {
	for {
		select {
		case req := <-s.read:
			req.value <- s.store[req.key]

		case entries := <-s.raft.Committed():
			for _, entry := range entries {
				switch entry.EntryType {
				case commonpb.EntryNormal:
					if bytes.Equal(raft.NOOP, entry.Data) {
						continue
					}

					var cmd cmdpb.Cmd
					err := cmd.Unmarshal(entry.Data)

					if err != nil {
						// TODO Ignore malformed requests. Log?
						continue
					}

					var res interface{}

					switch cmd.CmdType {
					case cmdpb.Register:
						id := fmt.Sprintf("%d", entry.Index)
						res = id
						if _, ok := s.clients[id]; ok {
							// Don't reset sequence
							// number if we receive
							// a duplicate.
							break
						}
						s.clients[id] = 0
					case cmdpb.Insert:
						// TODO We need to return
						// ErrSessionExpired, when the
						// session is expired. TODO If
						// we see seq > oldseq + 1, we
						// need to deal with that, i.e,
						// we might have stale data?
						if oldseq := s.clients[cmd.ClientID]; oldseq >= cmd.Seq {
							// Already applied.
							break
						}

						s.clients[cmd.ClientID] = cmd.Seq
						s.store[cmd.Key] = cmd.Value
					}

					cmdID := cmdUID(&cmd)
					if ch, ok := s.waiting[cmdID]; ok {
						ch <- res
						delete(s.waiting, cmdID)
					}
				}
			}
		}
	}
}

// randSeq is used to uniquely identify register command. There is a chance of a
// collision, but I'll take those odds any day.
func randSeq() uint64 {
	return uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
}

func cmdUID(cmd *cmdpb.Cmd) string {
	if cmd.CmdType == cmdpb.Insert {
		return fmt.Sprintf("INSERT:%s%d", cmd.ClientID, cmd.Seq)
	}

	return fmt.Sprintf("REGISTER:%d", cmd.Seq)
}

func (s *Store) Register() (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	cmd := cmdpb.Cmd{CmdType: cmdpb.Register, Seq: randSeq()}
	b, err := cmd.Marshal()

	if err != nil {
		return "", err
	}

	done := make(chan interface{}, 1)
	// TODO Store cmds under clientID, so they can be expired.
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return "", err
	}

	select {
	case res := <-done:
		return res.(string), nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Lookup gets a value from the map given a key. If an error is returned, the
// client should retry the same request. Note that if the key doesn't exist, the empty string is
// returned.
func (s *Store) Lookup(key string, allowStale bool) (string, error) {
	// TODO Buffer reads to amortize cost.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	value := make(chan string, 1)

	if !allowStale {
		err := s.raft.Read(ctx)

		if err != nil {
			return "", err
		}
	}

	r := readRequest{
		key:   key,
		value: value,
	}

	s.read <- &r

	select {
	case v := <-value:
		return v, nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Insert inserts value in map given a key. If an error is returned, the client
// should retry the same request.
func (s *Store) Insert(id string, seq uint64, key, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	// TODO Check if session is valid. Make it a function.

	cmd := cmdpb.Cmd{
		CmdType:  cmdpb.Insert,
		ClientID: id,
		Seq:      seq,
		Key:      key,
		Value:    value,
	}
	b, err := cmd.Marshal()

	if err != nil {
		return err
	}

	done := make(chan interface{}, 1)
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return err
	}

	select {
	case <-done:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<commit_msg>store.go: Refactor<commit_after>package rkv

import (
	"bytes"
	"fmt"
	"math/rand"
	"time"

	"golang.org/x/net/context"

	"github.com/relab/raft"
	commonpb "github.com/relab/raft/raftpb"
	cmdpb "github.com/relab/rkv/cmdpb"
)

// TODO Context timeout should depend on heartbeat setting.

// Store is a key-value store backed by a map.
type Store struct {
	store map[string]string

	nextID  uint64
	clients map[string]uint64

	waiting map[string]chan interface{}
	read    chan *readRequest

	raft raft.Raft
}

type readRequest struct {
	key   string
	value chan<- string
}

// NewStore returns a newly initialized store.
func NewStore(raft raft.Raft) *Store {
	s := &Store{
		store:   make(map[string]string),
		clients: make(map[string]uint64),
		waiting: make(map[string]chan interface{}),
		read:    make(chan *readRequest),
		raft:    raft,
	}

	go s.run()

	return s
}

func (s *Store) run() {
	for {
		select {
		case req := <-s.read:
			req.value <- s.store[req.key]

		case entries := <-s.raft.Committed():
			for _, entry := range entries {
				s.handleEntry(&entry)
			}
		}
	}
}

func (s *Store) handleEntry(entry *commonpb.Entry) {
	switch entry.EntryType {
	case commonpb.EntryNormal:
		if bytes.Equal(raft.NOOP, entry.Data) {
			return
		}

		var cmd cmdpb.Cmd
		err := cmd.Unmarshal(entry.Data)

		if err != nil {
			// TODO Ignore malformed requests. Log?
			return
		}

		var res interface{}

		switch cmd.CmdType {
		case cmdpb.Register:
			id := fmt.Sprintf("%d", entry.Index)
			res = id
			if _, ok := s.clients[id]; ok {
				// Don't reset sequence number if we receive a
				// duplicate.
				break
			}
			s.clients[id] = 0
		case cmdpb.Insert:
			// TODO We need to return ErrSessionExpired, when the
			// session is expired. TODO If we see seq > oldseq + 1,
			// we need to deal with that, i.e, we might have stale
			// data?
			if oldseq := s.clients[cmd.ClientID]; oldseq >= cmd.Seq {
				// Already applied.
				break
			}

			s.clients[cmd.ClientID] = cmd.Seq
			s.store[cmd.Key] = cmd.Value
		}

		cmdID := cmdUID(&cmd)
		if ch, ok := s.waiting[cmdID]; ok {
			ch <- res
			delete(s.waiting, cmdID)
		}
	}
}

// randSeq is used to uniquely identify register command. There is a chance of a
// collision, but I'll take those odds any day.
func randSeq() uint64 {
	return uint64(rand.Uint32())<<32 + uint64(rand.Uint32())
}

func cmdUID(cmd *cmdpb.Cmd) string {
	if cmd.CmdType == cmdpb.Insert {
		return fmt.Sprintf("INSERT:%s%d", cmd.ClientID, cmd.Seq)
	}

	return fmt.Sprintf("REGISTER:%d", cmd.Seq)
}

func (s *Store) Register() (string, error) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	cmd := cmdpb.Cmd{CmdType: cmdpb.Register, Seq: randSeq()}
	b, err := cmd.Marshal()

	if err != nil {
		return "", err
	}

	done := make(chan interface{}, 1)
	// TODO Store cmds under clientID, so they can be expired.
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return "", err
	}

	select {
	case res := <-done:
		return res.(string), nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Lookup gets a value from the map given a key. If an error is returned, the
// client should retry the same request. Note that if the key doesn't exist, the
// empty string is returned.
func (s *Store) Lookup(key string, allowStale bool) (string, error) {
	// TODO Buffer reads to amortize cost.
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	value := make(chan string, 1)

	if !allowStale {
		err := s.raft.Read(ctx)

		if err != nil {
			return "", err
		}
	}

	r := readRequest{
		key:   key,
		value: value,
	}

	s.read <- &r

	select {
	case v := <-value:
		return v, nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

// Insert inserts value in map given a key. If an error is returned, the client
// should retry the same request.
func (s *Store) Insert(id string, seq uint64, key, value string) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	// TODO Check if session is valid. Make it a function.

	cmd := cmdpb.Cmd{
		CmdType:  cmdpb.Insert,
		ClientID: id,
		Seq:      seq,
		Key:      key,
		Value:    value,
	}
	b, err := cmd.Marshal()

	if err != nil {
		return err
	}

	done := make(chan interface{}, 1)
	s.waiting[cmdUID(&cmd)] = done

	if err := s.raft.ProposeCmd(ctx, b); err != nil {
		return err
	}

	select {
	case <-done:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<|endoftext|>


<commit_before>package etcd_store

import (
	"errors"
	"io"
)

var (
	ErrHorizonOutOfDate  = errors.New("store: Current horizon is beyond requested horizon")
	ErrRevisionOutOfDate = errors.New("store: Current revision is beyond requested revision")
)

// Horizon/Revision 0 == most recent
type KV struct {
	Key      []byte
	Value    []byte
	Horizon  uint64
	Revision uint64
}

type Store interface {
	Version() int
	Horzon() uint64
	Get(kv KV) (KV, error)
	Set(kv KV) error
	Delete(kv KV) error
	ListKeysWithPrefix(key []byte, horizon uint64) ([][]byte, error)

	Watch(prefix []byte, recursive, stream bool, start, end uint64) (Watcher, error)

	SnapshotTo(w io.Writer) error
	Compact(horizon uint64) error
}

// modified from etcd/store/watcher.go. It seems reasonable enough.
type Watcher interface {
	KVChan() chan *KV
	StartHorizon() uint64 // The horizon at which the Watcher was created
	Close()
}
<commit_msg>Fix prefix and range<commit_after>package etcd_store

import (
	"errors"
	"io"
)

var (
	ErrHorizonOutOfDate  = errors.New("store: Current horizon is beyond requested horizon")
	ErrRevisionOutOfDate = errors.New("store: Current revision is beyond requested revision")
)

// Horizon/Revision 0 == most recent
type KV struct {
	Key      []byte
	Value    []byte
	Horizon  uint64
	Revision uint64
}

type Store interface {
	Version() int
	Horzon() uint64
	Get(kv KV) (KV, error)
	Set(kv KV) error
	Delete(kv KV) error
	// ListKeysWithPrefix lists the keys with the given prefix.
	// The returned keys are sorted in (level, bytes) order. Each "/" after prefix increments the level of a returned key (to simulate directory depth).
	// level is the max level of the listed keys. Zero is unlimited.
	ListKeysWithPrefix(prefix []byte, horizon uint64, level int) ([][]byte, error)

	// ListKeysInRange lists the keys between [start, end).
	// The returned keys are sorted in (level, bytes) order. Each "/" after prefix increments the level of a returned key (to simulate directory depth).
	// level is the max level of the listed keys. Zero is unlimited.
	ListKeysInRange(start, end []byte, horizon uint64, level int) ([][]byte, error)

	Watch(prefix []byte, recursive, stream bool, start, end uint64) (Watcher, error)

	SnapshotTo(w io.Writer) error
	Compact(horizon uint64) error
}

// modified from etcd/store/watcher.go. It seems reasonable enough.
type Watcher interface {
	KVChan() chan *KV
	StartHorizon() uint64 // The horizon at which the Watcher was created
	Close()
}
<|endoftext|>