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

package util

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"v.io/jiri/project"
	"v.io/jiri/tool"
	"v.io/x/lib/envvar"
)

const (
	jiriProfileEnv = "JIRI_PROFILE"
	javaEnv        = "JAVA_HOME"
)

// TODO(nlacasse): Rename this.
// VanadiumEnvironment returns the environment variables setting for the
// project. The util package captures the original state of the relevant
// environment variables when the tool is initialized and every invocation of
// this function updates this original state according to the jiri tool
// configuration.
//
// By default, the Go and VDL workspaces are added to the GOPATH and VDLPATH
// environment variables respectively. In addition, the JIRI_PROFILE
// environment variable can be used to activate an environment variable setting
// for various development profiles of the project (e.g. arm, android, java, or
// nacl).  Unlike the default setting, the setting enabled by the JIRI_PROFILE
// environment variable can override existing environment.
func VanadiumEnvironment(ctx *tool.Context) (*envvar.Vars, error) {
	env := envvar.VarsFromOS()
	root, err := project.JiriRoot()
	if err != nil {
		return nil, err
	}
	config, err := LoadConfig(ctx)
	if err != nil {
		return nil, err
	}
	env.Set("CGO_ENABLED", "1")
	if err := setGoPath(ctx, env, root, config); err != nil {
		return nil, err
	}
	if err := setVdlPath(ctx, env, root, config); err != nil {
		return nil, err
	}
	if profile := os.Getenv(jiriProfileEnv); profile != "" {
		fmt.Fprintf(ctx.Stdout(), `NOTE: Enabling environment variable setting for %q.
This can override values of existing environment variables.
`, profile)
		switch profile {
		case "android":
			// Cross-compilation for android on linux.
			if err := setAndroidEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "arm":
			// Cross-compilation for arm on linux.
			if err := setArmEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "java":
			// Building of a Go shared library for Java.
			if err := setJavaEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "nacl":
			// Cross-compilation for nacl.
			if err := setNaclEnv(ctx, env, root); err != nil {
				return nil, err
			}
		default:
			fmt.Fprintf(ctx.Stderr(), "Unknown environment profile %q", profile)
		}
	}
	if err := setSyncbaseEnv(ctx, env, root); err != nil {
		return nil, err
	}
	return env, nil
}

// setJavaEnv sets the environment variables used for building a Go
// shared library that is invoked from Java code. If Java is not
// installed on the host, this function is a no-op.
func setJavaEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	jdkHome := os.Getenv(javaEnv)
	if jdkHome == "" {
		return nil
	}

	// Compile using Java Go 1.5 (installed via 'jiri profile install java').
	javaGoDir := filepath.Join(root, "third_party", "java", "go")

	// Set Go-specific environment variables.
	cflags := env.GetTokens("CGO_CFLAGS", " ")
	cflags = append(cflags, filepath.Join("-I"+jdkHome, "include"), filepath.Join("-I"+jdkHome, "include", runtime.GOOS))
	env.SetTokens("CGO_CFLAGS", cflags, " ")
	env.Set("GOROOT", javaGoDir)

	// Update PATH.
	if _, err := ctx.Run().Stat(javaGoDir); err != nil {
		return fmt.Errorf("Couldn't find java go installation directory %s: did you run \"jiri profile install java\"?", javaGoDir)
	}
	path := env.GetTokens("PATH", ":")
	path = append([]string{filepath.Join(javaGoDir, "bin")}, path...)
	env.SetTokens("PATH", path, ":")
	return nil
}

// setAndroidEnv sets the environment variables used for android
// cross-compilation.
func setAndroidEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	// Compile using Android Go 1.5 (installed via
	// 'jiri profile install android').
	androidGoDir := filepath.Join(root, "third_party", "android", "go")

	// Set Go-specific environment variables.
	env.Set("GOARCH", "arm")
	env.Set("GOARM", "7")
	env.Set("GOOS", "android")
	env.Set("GOROOT", androidGoDir)

	// Update PATH.
	if _, err := ctx.Run().Stat(androidGoDir); err != nil {
		return fmt.Errorf("Couldn't find android Go installation directory %s: did you run \"jiri profile install android\"?", androidGoDir)
	}
	path := env.GetTokens("PATH", ":")
	path = append([]string{filepath.Join(androidGoDir, "bin")}, path...)
	env.SetTokens("PATH", path, ":")
	return nil
}

// setArmEnv sets the environment variables used for arm cross-compilation.
func setArmEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	// Set Go specific environment variables.
	env.Set("GOARCH", "arm")
	env.Set("GOARM", "6")
	env.Set("GOOS", "linux")

	// Add the paths to arm cross-compilation tools to the PATH.
	path := env.GetTokens("PATH", ":")
	path = append([]string{
		filepath.Join(root, "third_party", "cout", "xgcc", "cross_arm"),
		filepath.Join(root, "third_party", "repos", "go_arm", "bin"),
	}, path...)
	env.SetTokens("PATH", path, ":")

	return nil
}

// setGoPath adds the paths of Go workspaces to the GOPATH variable.
func setGoPath(ctx *tool.Context, env *envvar.Vars, root string, config *Config) error {
	return setPathHelper(ctx, env, "GOPATH", root, config.GoWorkspaces(), "")
}

// setVdlPath adds the paths of VDL workspaces to the VDLPATH variable.
func setVdlPath(ctx *tool.Context, env *envvar.Vars, root string, config *Config) error {
	return setPathHelper(ctx, env, "VDLPATH", root, config.VDLWorkspaces(), "src")
}

// setPathHelper is a utility function for setting path environment
// variables for different types of workspaces.
func setPathHelper(ctx *tool.Context, env *envvar.Vars, name, root string, workspaces []string, suffix string) error {
	path := env.GetTokens(name, ":")
	projects, _, err := project.ReadManifest(ctx)
	if err != nil {
		return err
	}
	for _, workspace := range workspaces {
		absWorkspace := filepath.Join(root, workspace, suffix)
		// Only append an entry to the path if the workspace is rooted
		// under a jiri project that exists locally or vice versa.
		for _, project := range projects {
			// We check if <project.Path> is a prefix of <absWorkspace> to
			// account for Go workspaces nested under a single jiri project,
			// such as: $JIRI_ROOT/release/projects/chat/go.
			//
			// We check if <absWorkspace> is a prefix of <project.Path> to
			// account for Go workspaces that span multiple jiri projects,
			// such as: $JIRI_ROOT/release/go.
			if strings.HasPrefix(absWorkspace, project.Path) || strings.HasPrefix(project.Path, absWorkspace) {
				if _, err := ctx.Run().Stat(filepath.Join(absWorkspace)); err == nil {
					path = append(path, absWorkspace)
					break
				}
			}
		}
	}
	env.SetTokens(name, path, ":")
	return nil
}

// TODO(nlacasse): Move setNaclEnv and setSyncbaseEnv out of jiri since they
// are not general-purpose.

// setNaclEnv sets the environment variables used for nacl
// cross-compilation.
func setNaclEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	env.Set("GOARCH", "amd64p32")
	env.Set("GOOS", "nacl")

	// Add the path to nacl cross-compiler to the PATH.
	path := env.GetTokens("PATH", ":")
	path = append([]string{
		filepath.Join(root, "third_party", "repos", "go_ppapi", "bin"),
	}, path...)
	env.SetTokens("PATH", path, ":")

	return nil
}

// setSyncbaseEnv adds the LevelDB third-party C++ libraries Vanadium
// Go code depends on to the CGO_CFLAGS and CGO_LDFLAGS variables.
func setSyncbaseEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	libs := []string{
		"leveldb",
		"snappy",
	}
	// TODO(rogulenko): get these vars from a config file.
	goos, goarch := env.Get("GOOS"), env.Get("GOARCH")
	if goos == "" {
		goos = runtime.GOOS
	}
	if goarch == "" {
		goarch = runtime.GOARCH
	}
	for _, lib := range libs {
		cflags := env.GetTokens("CGO_CFLAGS", " ")
		cxxflags := env.GetTokens("CGO_CXXFLAGS", " ")
		ldflags := env.GetTokens("CGO_LDFLAGS", " ")
		dir, err := ThirdPartyCCodePath(goos, goarch)
		if err != nil {
			return err
		}
		dir = filepath.Join(dir, lib)
		if _, err := ctx.Run().Stat(dir); err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			continue
		}
		cflags = append(cflags, filepath.Join("-I"+dir, "include"))
		cxxflags = append(cxxflags, filepath.Join("-I"+dir, "include"))
		ldflags = append(ldflags, filepath.Join("-L"+dir, "lib"))
		if runtime.GOARCH == "linux" {
			ldflags = append(ldflags, "-Wl,-rpath", filepath.Join(dir, "lib"))
		}
		env.SetTokens("CGO_CFLAGS", cflags, " ")
		env.SetTokens("CGO_CXXFLAGS", cxxflags, " ")
		env.SetTokens("CGO_LDFLAGS", ldflags, " ")
	}
	return nil
}
<commit_msg>Rename VanadiumEnvironment to JiriEnvironment.<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package util

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"

	"v.io/jiri/project"
	"v.io/jiri/tool"
	"v.io/x/lib/envvar"
)

const (
	jiriProfileEnv = "JIRI_PROFILE"
	javaEnv        = "JAVA_HOME"
)

// JiriEnvironment returns the environment variables setting for the project.
// The util package captures the original state of the relevant environment
// variables when the tool is initialized and every invocation of this function
// updates this original state according to the jiri tool configuration.
//
// By default, the Go and VDL workspaces are added to the GOPATH and VDLPATH
// environment variables respectively. In addition, the JIRI_PROFILE
// environment variable can be used to activate an environment variable setting
// for various development profiles of the project (e.g. arm, android, java, or
// nacl).  Unlike the default setting, the setting enabled by the JIRI_PROFILE
// environment variable can override existing environment.
func JiriEnvironment(ctx *tool.Context) (*envvar.Vars, error) {
	env := envvar.VarsFromOS()
	root, err := project.JiriRoot()
	if err != nil {
		return nil, err
	}
	config, err := LoadConfig(ctx)
	if err != nil {
		return nil, err
	}
	env.Set("CGO_ENABLED", "1")
	if err := setGoPath(ctx, env, root, config); err != nil {
		return nil, err
	}
	if err := setVdlPath(ctx, env, root, config); err != nil {
		return nil, err
	}
	if profile := os.Getenv(jiriProfileEnv); profile != "" {
		fmt.Fprintf(ctx.Stdout(), `NOTE: Enabling environment variable setting for %q.
This can override values of existing environment variables.
`, profile)
		switch profile {
		case "android":
			// Cross-compilation for android on linux.
			if err := setAndroidEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "arm":
			// Cross-compilation for arm on linux.
			if err := setArmEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "java":
			// Building of a Go shared library for Java.
			if err := setJavaEnv(ctx, env, root); err != nil {
				return nil, err
			}
		case "nacl":
			// Cross-compilation for nacl.
			if err := setNaclEnv(ctx, env, root); err != nil {
				return nil, err
			}
		default:
			fmt.Fprintf(ctx.Stderr(), "Unknown environment profile %q", profile)
		}
	}
	if err := setSyncbaseEnv(ctx, env, root); err != nil {
		return nil, err
	}
	return env, nil
}

// setJavaEnv sets the environment variables used for building a Go
// shared library that is invoked from Java code. If Java is not
// installed on the host, this function is a no-op.
func setJavaEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	jdkHome := os.Getenv(javaEnv)
	if jdkHome == "" {
		return nil
	}

	// Compile using Java Go 1.5 (installed via 'jiri profile install java').
	javaGoDir := filepath.Join(root, "third_party", "java", "go")

	// Set Go-specific environment variables.
	cflags := env.GetTokens("CGO_CFLAGS", " ")
	cflags = append(cflags, filepath.Join("-I"+jdkHome, "include"), filepath.Join("-I"+jdkHome, "include", runtime.GOOS))
	env.SetTokens("CGO_CFLAGS", cflags, " ")
	env.Set("GOROOT", javaGoDir)

	// Update PATH.
	if _, err := ctx.Run().Stat(javaGoDir); err != nil {
		return fmt.Errorf("Couldn't find java go installation directory %s: did you run \"jiri profile install java\"?", javaGoDir)
	}
	path := env.GetTokens("PATH", ":")
	path = append([]string{filepath.Join(javaGoDir, "bin")}, path...)
	env.SetTokens("PATH", path, ":")
	return nil
}

// setAndroidEnv sets the environment variables used for android
// cross-compilation.
func setAndroidEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	// Compile using Android Go 1.5 (installed via
	// 'jiri profile install android').
	androidGoDir := filepath.Join(root, "third_party", "android", "go")

	// Set Go-specific environment variables.
	env.Set("GOARCH", "arm")
	env.Set("GOARM", "7")
	env.Set("GOOS", "android")
	env.Set("GOROOT", androidGoDir)

	// Update PATH.
	if _, err := ctx.Run().Stat(androidGoDir); err != nil {
		return fmt.Errorf("Couldn't find android Go installation directory %s: did you run \"jiri profile install android\"?", androidGoDir)
	}
	path := env.GetTokens("PATH", ":")
	path = append([]string{filepath.Join(androidGoDir, "bin")}, path...)
	env.SetTokens("PATH", path, ":")
	return nil
}

// setArmEnv sets the environment variables used for arm cross-compilation.
func setArmEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	// Set Go specific environment variables.
	env.Set("GOARCH", "arm")
	env.Set("GOARM", "6")
	env.Set("GOOS", "linux")

	// Add the paths to arm cross-compilation tools to the PATH.
	path := env.GetTokens("PATH", ":")
	path = append([]string{
		filepath.Join(root, "third_party", "cout", "xgcc", "cross_arm"),
		filepath.Join(root, "third_party", "repos", "go_arm", "bin"),
	}, path...)
	env.SetTokens("PATH", path, ":")

	return nil
}

// setGoPath adds the paths of Go workspaces to the GOPATH variable.
func setGoPath(ctx *tool.Context, env *envvar.Vars, root string, config *Config) error {
	return setPathHelper(ctx, env, "GOPATH", root, config.GoWorkspaces(), "")
}

// setVdlPath adds the paths of VDL workspaces to the VDLPATH variable.
func setVdlPath(ctx *tool.Context, env *envvar.Vars, root string, config *Config) error {
	return setPathHelper(ctx, env, "VDLPATH", root, config.VDLWorkspaces(), "src")
}

// setPathHelper is a utility function for setting path environment
// variables for different types of workspaces.
func setPathHelper(ctx *tool.Context, env *envvar.Vars, name, root string, workspaces []string, suffix string) error {
	path := env.GetTokens(name, ":")
	projects, _, err := project.ReadManifest(ctx)
	if err != nil {
		return err
	}
	for _, workspace := range workspaces {
		absWorkspace := filepath.Join(root, workspace, suffix)
		// Only append an entry to the path if the workspace is rooted
		// under a jiri project that exists locally or vice versa.
		for _, project := range projects {
			// We check if <project.Path> is a prefix of <absWorkspace> to
			// account for Go workspaces nested under a single jiri project,
			// such as: $JIRI_ROOT/release/projects/chat/go.
			//
			// We check if <absWorkspace> is a prefix of <project.Path> to
			// account for Go workspaces that span multiple jiri projects,
			// such as: $JIRI_ROOT/release/go.
			if strings.HasPrefix(absWorkspace, project.Path) || strings.HasPrefix(project.Path, absWorkspace) {
				if _, err := ctx.Run().Stat(filepath.Join(absWorkspace)); err == nil {
					path = append(path, absWorkspace)
					break
				}
			}
		}
	}
	env.SetTokens(name, path, ":")
	return nil
}

// TODO(nlacasse): Move setNaclEnv and setSyncbaseEnv out of jiri since they
// are not general-purpose.

// setNaclEnv sets the environment variables used for nacl
// cross-compilation.
func setNaclEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	env.Set("GOARCH", "amd64p32")
	env.Set("GOOS", "nacl")

	// Add the path to nacl cross-compiler to the PATH.
	path := env.GetTokens("PATH", ":")
	path = append([]string{
		filepath.Join(root, "third_party", "repos", "go_ppapi", "bin"),
	}, path...)
	env.SetTokens("PATH", path, ":")

	return nil
}

// setSyncbaseEnv adds the LevelDB third-party C++ libraries Vanadium
// Go code depends on to the CGO_CFLAGS and CGO_LDFLAGS variables.
func setSyncbaseEnv(ctx *tool.Context, env *envvar.Vars, root string) error {
	libs := []string{
		"leveldb",
		"snappy",
	}
	// TODO(rogulenko): get these vars from a config file.
	goos, goarch := env.Get("GOOS"), env.Get("GOARCH")
	if goos == "" {
		goos = runtime.GOOS
	}
	if goarch == "" {
		goarch = runtime.GOARCH
	}
	for _, lib := range libs {
		cflags := env.GetTokens("CGO_CFLAGS", " ")
		cxxflags := env.GetTokens("CGO_CXXFLAGS", " ")
		ldflags := env.GetTokens("CGO_LDFLAGS", " ")
		dir, err := ThirdPartyCCodePath(goos, goarch)
		if err != nil {
			return err
		}
		dir = filepath.Join(dir, lib)
		if _, err := ctx.Run().Stat(dir); err != nil {
			if !os.IsNotExist(err) {
				return err
			}
			continue
		}
		cflags = append(cflags, filepath.Join("-I"+dir, "include"))
		cxxflags = append(cxxflags, filepath.Join("-I"+dir, "include"))
		ldflags = append(ldflags, filepath.Join("-L"+dir, "lib"))
		if runtime.GOARCH == "linux" {
			ldflags = append(ldflags, "-Wl,-rpath", filepath.Join(dir, "lib"))
		}
		env.SetTokens("CGO_CFLAGS", cflags, " ")
		env.SetTokens("CGO_CXXFLAGS", cxxflags, " ")
		env.SetTokens("CGO_LDFLAGS", ldflags, " ")
	}
	return nil
}
<|endoftext|>


<commit_before>package signalfx

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"golang.org/x/net/context"
)

func TestGoMetrics(t *testing.T) {
	const forceFail = false

	Convey("Testing GoMetrics", t, func() {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte(`"OK"`))
		}))
		defer ts.Close()

		config := NewConfig()
		So(config, ShouldNotBeNil)

		config.URL = ts.URL

		reporter := NewReporter(config, nil)
		So(reporter, ShouldNotBeNil)

		gometrics := NewGoMetrics(reporter)

		datapoints, err := reporter.Report(context.Background())
		So(err, ShouldBeNil)
		So(datapoints, ShouldNotBeNil)

		So(len(datapoints), ShouldBeGreaterThan, 0)

		testDataPoint := func(dp DataPoint, t MetricType) {
			So(dp.Type, ShouldEqual, t)
			So(dp.Timestamp.Before(time.Now()), ShouldBeTrue)
			So(len(dp.Dimensions), ShouldEqual, 2)

			for key, value := range dp.Dimensions {
				switch key {
				case "instance":
					So(value, ShouldEqual, "global_stats")
				case "stattype":
					So(value, ShouldEqual, "golang_sys")
				default:
					So(value, ShouldEqual, forceFail)
				}
			}

			So(dp.Value, ShouldBeGreaterThanOrEqualTo, 0)
		}

		for _, dp := range datapoints {
			switch dp.Metric {
			case "Alloc",
				"Sys",
				"HeapAlloc",
				"HeapSys",
				"HeapIdle",
				"HeapInuse",
				"HeapReleased",
				"HeapObjects",
				"StackInuse",
				"StackSys",
				"MSpanInuse",
				"MSpanSys",
				"MCacheInuse",
				"MCacheSys",
				"BuckHashSys",
				"GCSys",
				"OtherSys",
				"NextGC",
				"LastGC",
				"NumGC",
				"GOMAXPROCS",
				"process.uptime.ns",
				"num_cpu",
				"num_goroutine":
				testDataPoint(dp, GaugeType)
			case "TotalAlloc", "Lookups", "Mallocs", "Frees", "PauseTotalNs", "num_cgo_call":
				testDataPoint(dp, CumulativeCounterType)
			default:
				So(dp.Metric, ShouldEqual, forceFail)
			}
		}

		So(gometrics.Close(), ShouldBeNil)
	})
}
<commit_msg>Use greater than 28 instead of zero and provide explanation.<commit_after>package signalfx

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/goconvey/convey"
	"golang.org/x/net/context"
)

func TestGoMetrics(t *testing.T) {
	const forceFail = false

	Convey("Testing GoMetrics", t, func() {
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Write([]byte(`"OK"`))
		}))
		defer ts.Close()

		config := NewConfig()
		So(config, ShouldNotBeNil)

		config.URL = ts.URL

		reporter := NewReporter(config, nil)
		So(reporter, ShouldNotBeNil)

		gometrics := NewGoMetrics(reporter)
		datapoints, err := reporter.Report(context.Background())
		So(err, ShouldBeNil)
		So(datapoints, ShouldNotBeNil)
		// This can vary depending on if a GC cycle has run yet.
		So(len(datapoints), ShouldBeGreaterThan, 28)

		testDataPoint := func(dp DataPoint, t MetricType) {
			So(dp.Type, ShouldEqual, t)
			So(dp.Timestamp.Before(time.Now()), ShouldBeTrue)
			So(len(dp.Dimensions), ShouldEqual, 2)

			for key, value := range dp.Dimensions {
				switch key {
				case "instance":
					So(value, ShouldEqual, "global_stats")
				case "stattype":
					So(value, ShouldEqual, "golang_sys")
				default:
					So(value, ShouldEqual, forceFail)
				}
			}

			So(dp.Value, ShouldBeGreaterThanOrEqualTo, 0)
		}

		for _, dp := range datapoints {
			switch dp.Metric {
			case "Alloc",
				"Sys",
				"HeapAlloc",
				"HeapSys",
				"HeapIdle",
				"HeapInuse",
				"HeapReleased",
				"HeapObjects",
				"StackInuse",
				"StackSys",
				"MSpanInuse",
				"MSpanSys",
				"MCacheInuse",
				"MCacheSys",
				"BuckHashSys",
				"GCSys",
				"OtherSys",
				"NextGC",
				"LastGC",
				"NumGC",
				"GOMAXPROCS",
				"process.uptime.ns",
				"num_cpu",
				"num_goroutine":
				testDataPoint(dp, GaugeType)
			case "TotalAlloc", "Lookups", "Mallocs", "Frees", "PauseTotalNs", "num_cgo_call":
				testDataPoint(dp, CumulativeCounterType)
			default:
				So(dp.Metric, ShouldEqual, forceFail)
			}
		}

		So(gometrics.Close(), ShouldBeNil)
	})
}
<|endoftext|>


<commit_before>package bitfinex

import (
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/fundingoffer"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/order"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/position"
)

// Candle resolutions
const (
	OneMinute      CandleResolution = "1m"
	FiveMinutes    CandleResolution = "5m"
	FifteenMinutes CandleResolution = "15m"
	ThirtyMinutes  CandleResolution = "30m"
	OneHour        CandleResolution = "1h"
	ThreeHours     CandleResolution = "3h"
	SixHours       CandleResolution = "6h"
	TwelveHours    CandleResolution = "12h"
	OneDay         CandleResolution = "1D"
	OneWeek        CandleResolution = "7D"
	TwoWeeks       CandleResolution = "14D"
	OneMonth       CandleResolution = "1M"
)

type Mts int64
type SortOrder int

const (
	OldestFirst SortOrder = 1
	NewestFirst SortOrder = -1
)

type QueryLimit int

const QueryLimitMax QueryLimit = 1000

func CandleResolutionFromString(str string) (CandleResolution, error) {
	switch str {
	case string(OneMinute):
		return OneMinute, nil
	case string(FiveMinutes):
		return FiveMinutes, nil
	case string(FifteenMinutes):
		return FifteenMinutes, nil
	case string(ThirtyMinutes):
		return ThirtyMinutes, nil
	case string(OneHour):
		return OneHour, nil
	case string(ThreeHours):
		return ThreeHours, nil
	case string(SixHours):
		return SixHours, nil
	case string(TwelveHours):
		return TwelveHours, nil
	case string(OneDay):
		return OneDay, nil
	case string(OneWeek):
		return OneWeek, nil
	case string(TwoWeeks):
		return TwoWeeks, nil
	case string(OneMonth):
		return OneMonth, nil
	}
	return OneMinute, fmt.Errorf("could not convert string to resolution: %s", str)
}

type PermissionType string

const (
	PermissionRead  = "r"
	PermissionWrite = "w"
)

// CandleResolution provides a typed set of resolutions for candle subscriptions.
type CandleResolution string

// Order sides
const (
	Bid   common.OrderSide = 1
	Ask   common.OrderSide = 2
	Long  common.OrderSide = 1
	Short common.OrderSide = 2
)

// Settings flags

const (
	Dec_s     int = 9
	Time_s    int = 32
	Timestamp int = 32768
	Seq_all   int = 65536
	Checksum  int = 131072
)

// Book precision levels
const (
	// Aggregate precision levels
	Precision0 BookPrecision = "P0"
	Precision2 BookPrecision = "P2"
	Precision1 BookPrecision = "P1"
	Precision3 BookPrecision = "P3"
	// Raw precision
	PrecisionRawBook BookPrecision = "R0"
)

// private type
type bookPrecision string

// BookPrecision provides a typed book precision level.
type BookPrecision bookPrecision

const (
	// FrequencyRealtime book frequency gives updates as they occur in real-time.
	FrequencyRealtime BookFrequency = "F0"
	// FrequencyTwoPerSecond delivers two book updates per second.
	FrequencyTwoPerSecond BookFrequency = "F1"
	// PriceLevelDefault provides a constant default price level for book subscriptions.
	PriceLevelDefault int = 25
)

// BookFrequency provides a typed book frequency.
type BookFrequency string

type Notification struct {
	MTS        int64
	Type       string
	MessageID  int64
	NotifyInfo interface{}
	Code       int64
	Status     string
	Text       string
}

func NewNotificationFromRaw(raw []interface{}) (o *Notification, err error) {
	if len(raw) < 8 {
		return o, fmt.Errorf("data slice too short for notification: %#v", raw)
	}

	o = &Notification{
		MTS:       convert.I64ValOrZero(raw[0]),
		Type:      convert.SValOrEmpty(raw[1]),
		MessageID: convert.I64ValOrZero(raw[2]),
		//NotifyInfo: raw[4],
		Code:   convert.I64ValOrZero(raw[5]),
		Status: convert.SValOrEmpty(raw[6]),
		Text:   convert.SValOrEmpty(raw[7]),
	}

	// raw[4] = notify info
	var nraw []interface{}
	if raw[4] != nil {
		nraw = raw[4].([]interface{})
		switch o.Type {
		case "on-req":
			if len(nraw) <= 0 {
				o.NotifyInfo = nil
				break
			}
			// will be a set of orders if created via rest
			// this is to accommodate OCO orders
			if _, ok := nraw[0].([]interface{}); ok {
				o.NotifyInfo, err = order.SnapshotFromRaw(nraw)
				if err != nil {
					return nil, err
				}
			} else {
				on, err := order.FromRaw(nraw)
				if err != nil {
					return nil, err
				}
				oNew := order.New(*on)
				o.NotifyInfo = &oNew
			}
		case "ou-req":
			on, err := order.FromRaw(nraw)
			if err != nil {
				return nil, err
			}
			ou := order.Update(*on)
			o.NotifyInfo = &ou
		case "oc-req":
			// if list of list then parse to order snapshot
			on, err := order.FromRaw(nraw)
			if err != nil {
				return o, err
			}
			oc := order.Cancel(*on)
			o.NotifyInfo = &oc
		case "fon-req":
			fon, err := fundingoffer.FromRaw(nraw)
			if err != nil {
				return o, err
			}
			fundingOffer := fundingoffer.New(*fon)
			o.NotifyInfo = &fundingOffer
		case "foc-req":
			foc, err := fundingoffer.FromRaw(nraw)
			if err != nil {
				return o, err
			}
			fundingOffer := fundingoffer.Cancel(*foc)
			o.NotifyInfo = &fundingOffer
		case "uca":
			o.NotifyInfo = raw[4]
		case "acc_tf":
			o.NotifyInfo = raw[4]
		case "pm-req":
			p, err := position.FromRaw(nraw)
			if err != nil {
				return o, err
			}
			cp := position.Cancel(*p)
			o.NotifyInfo = &cp
		default:
			o.NotifyInfo = raw[4]
		}
	}

	return
}

type StatKey string

const (
	FundingSizeKey   StatKey = "funding.size"
	CreditSizeKey    StatKey = "credits.size"
	CreditSizeSymKey StatKey = "credits.size.sym"
	PositionSizeKey  StatKey = "pos.size"
)

type Stat struct {
	Period int64
	Volume float64
}

type StatusType string
<commit_msg>v2/types.go cleanup<commit_after>package bitfinex

import (
	"fmt"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
)

// Candle resolutions
const (
	OneMinute      CandleResolution = "1m"
	FiveMinutes    CandleResolution = "5m"
	FifteenMinutes CandleResolution = "15m"
	ThirtyMinutes  CandleResolution = "30m"
	OneHour        CandleResolution = "1h"
	ThreeHours     CandleResolution = "3h"
	SixHours       CandleResolution = "6h"
	TwelveHours    CandleResolution = "12h"
	OneDay         CandleResolution = "1D"
	OneWeek        CandleResolution = "7D"
	TwoWeeks       CandleResolution = "14D"
	OneMonth       CandleResolution = "1M"
)

type Mts int64
type SortOrder int

const (
	OldestFirst SortOrder = 1
	NewestFirst SortOrder = -1
)

type QueryLimit int

const QueryLimitMax QueryLimit = 1000

func CandleResolutionFromString(str string) (CandleResolution, error) {
	switch str {
	case string(OneMinute):
		return OneMinute, nil
	case string(FiveMinutes):
		return FiveMinutes, nil
	case string(FifteenMinutes):
		return FifteenMinutes, nil
	case string(ThirtyMinutes):
		return ThirtyMinutes, nil
	case string(OneHour):
		return OneHour, nil
	case string(ThreeHours):
		return ThreeHours, nil
	case string(SixHours):
		return SixHours, nil
	case string(TwelveHours):
		return TwelveHours, nil
	case string(OneDay):
		return OneDay, nil
	case string(OneWeek):
		return OneWeek, nil
	case string(TwoWeeks):
		return TwoWeeks, nil
	case string(OneMonth):
		return OneMonth, nil
	}
	return OneMinute, fmt.Errorf("could not convert string to resolution: %s", str)
}

type PermissionType string

const (
	PermissionRead  = "r"
	PermissionWrite = "w"
)

// CandleResolution provides a typed set of resolutions for candle subscriptions.
type CandleResolution string

// Order sides
const (
	Bid   common.OrderSide = 1
	Ask   common.OrderSide = 2
	Long  common.OrderSide = 1
	Short common.OrderSide = 2
)

// Settings flags

const (
	Dec_s     int = 9
	Time_s    int = 32
	Timestamp int = 32768
	Seq_all   int = 65536
	Checksum  int = 131072
)

// Book precision levels
const (
	// Aggregate precision levels
	Precision0 BookPrecision = "P0"
	Precision2 BookPrecision = "P2"
	Precision1 BookPrecision = "P1"
	Precision3 BookPrecision = "P3"
	// Raw precision
	PrecisionRawBook BookPrecision = "R0"
)

// private type
type bookPrecision string

// BookPrecision provides a typed book precision level.
type BookPrecision bookPrecision

const (
	// FrequencyRealtime book frequency gives updates as they occur in real-time.
	FrequencyRealtime BookFrequency = "F0"
	// FrequencyTwoPerSecond delivers two book updates per second.
	FrequencyTwoPerSecond BookFrequency = "F1"
	// PriceLevelDefault provides a constant default price level for book subscriptions.
	PriceLevelDefault int = 25
)

// BookFrequency provides a typed book frequency.
type BookFrequency string

type StatKey string

const (
	FundingSizeKey   StatKey = "funding.size"
	CreditSizeKey    StatKey = "credits.size"
	CreditSizeSymKey StatKey = "credits.size.sym"
	PositionSizeKey  StatKey = "pos.size"
)

type Stat struct {
	Period int64
	Volume float64
}

type StatusType string
<|endoftext|>


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

package state_test

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/state"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestMapReadingSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MapReadingSaverTest struct {
	scoreMap state.ScoreMap
	fileSystem      mock_fs.MockFileSystem
	wrapped      mock_backup.MockFileSaver
	saver        backup.FileSaver

	path string
	scores []blob.Score
}

func init() { RegisterTestSuite(&MapReadingSaverTest{}) }

func (t *MapReadingSaverTest) SetUp(i *TestInfo) {
	t.scoreMap = state.NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.saver = state.NewMapReadingFileSaver(t.scoreMap, t.fileSystem, t.wrapped)
}

func (t *MapReadingSaverTest) call()

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MapReadingSaverTest) DoesFoo() {
	ExpectEq("TODO", "")
}
<commit_msg>Fixed formatting.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package state_test

import (
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/state"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestMapReadingSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MapReadingSaverTest struct {
	scoreMap   state.ScoreMap
	fileSystem mock_fs.MockFileSystem
	wrapped    mock_backup.MockFileSaver
	saver      backup.FileSaver

	path   string
	scores []blob.Score
}

func init() { RegisterTestSuite(&MapReadingSaverTest{}) }

func (t *MapReadingSaverTest) SetUp(i *TestInfo) {
	t.scoreMap = state.NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.saver = state.NewMapReadingFileSaver(t.scoreMap, t.fileSystem, t.wrapped)
}

func (t *MapReadingSaverTest) call()

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MapReadingSaverTest) DoesFoo() {
	ExpectEq("TODO", "")
}
<|endoftext|>


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

package state_test

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/state"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
	"time"
)

func TestMapReadingSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MapReadingSaverTest struct {
	scoreMap   state.ScoreMap
	fileSystem mock_fs.MockFileSystem
	wrapped    mock_backup.MockFileSaver
	saver      backup.FileSaver

	path   string
	scores []blob.Score
	err    error
}

func init() { RegisterTestSuite(&MapReadingSaverTest{}) }

func (t *MapReadingSaverTest) SetUp(i *TestInfo) {
	t.scoreMap = state.NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.saver = state.NewMapReadingFileSaver(t.scoreMap, t.fileSystem, t.wrapped)
}

func (t *MapReadingSaverTest) call() {
	t.scores, t.err = t.saver.Save(t.path)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MapReadingSaverTest) CallsStat() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")("taco").
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("")))

	// Call
	t.call()
}

func (t *MapReadingSaverTest) StatReturnsError() {
	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("taco")))

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("Stat")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *MapReadingSaverTest) ScoreMapContainsEntry() {
	t.path = "taco"

	// Score map
	expectedKey := state.ScoreMapKey{
		Path: "taco",
		Permissions: 0644,
		Uid: 17,
		Gid: 19,
		MTime: time.Now(),
		Inode: 23,
		Size: 29,
	}

	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	t.scoreMap.Set(expectedKey, expectedScores)

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid: 17,
		Gid: 19,
		MTime: time.Now(),
		Inode: 23,
		Size: 29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, DeepEquals(expectedScores))
}

func (t *MapReadingSaverTest) CallsWrapped() {
	ExpectEq("TODO", "")
}

func (t *MapReadingSaverTest) WrappedReturnsError() {
	ExpectEq("TODO", "")
}

func (t *MapReadingSaverTest) WrappedSucceeds() {
	ExpectEq("TODO", "")
}
<commit_msg>MapReadingSaverTest.CallsWrapped<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package state_test

import (
	"errors"
	"github.com/jacobsa/comeback/backup"
	"github.com/jacobsa/comeback/backup/mock"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/fs"
	"github.com/jacobsa/comeback/fs/mock"
	"github.com/jacobsa/comeback/state"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
	"time"
)

func TestMapReadingSaver(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type MapReadingSaverTest struct {
	scoreMap   state.ScoreMap
	fileSystem mock_fs.MockFileSystem
	wrapped    mock_backup.MockFileSaver
	saver      backup.FileSaver

	path   string
	scores []blob.Score
	err    error
}

func init() { RegisterTestSuite(&MapReadingSaverTest{}) }

func (t *MapReadingSaverTest) SetUp(i *TestInfo) {
	t.scoreMap = state.NewScoreMap()
	t.fileSystem = mock_fs.NewMockFileSystem(i.MockController, "fileSystem")
	t.wrapped = mock_backup.NewMockFileSaver(i.MockController, "wrapped")
	t.saver = state.NewMapReadingFileSaver(t.scoreMap, t.fileSystem, t.wrapped)
}

func (t *MapReadingSaverTest) call() {
	t.scores, t.err = t.saver.Save(t.path)
}

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *MapReadingSaverTest) CallsStat() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")("taco").
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("")))

	// Call
	t.call()
}

func (t *MapReadingSaverTest) StatReturnsError() {
	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, errors.New("taco")))

	// Call
	t.call()

	ExpectThat(t.err, Error(HasSubstr("Stat")))
	ExpectThat(t.err, Error(HasSubstr("taco")))
}

func (t *MapReadingSaverTest) ScoreMapContainsEntry() {
	t.path = "taco"

	// Score map
	expectedKey := state.ScoreMapKey{
		Path: "taco",
		Permissions: 0644,
		Uid: 17,
		Gid: 19,
		MTime: time.Now(),
		Inode: 23,
		Size: 29,
	}

	expectedScores := []blob.Score{
		blob.ComputeScore([]byte("foo")),
		blob.ComputeScore([]byte("bar")),
	}

	t.scoreMap.Set(expectedKey, expectedScores)

	// File system
	entry := fs.DirectoryEntry{
		Permissions: 0644,
		Uid: 17,
		Gid: 19,
		MTime: time.Now(),
		Inode: 23,
		Size: 29,
	}

	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(entry, nil))

	// Call
	t.call()

	AssertEq(nil, t.err)
	ExpectThat(t.scores, DeepEquals(expectedScores))
}

func (t *MapReadingSaverTest) CallsWrapped() {
	t.path = "taco"

	// File system
	ExpectCall(t.fileSystem, "Stat")(Any()).
		WillOnce(oglemock.Return(fs.DirectoryEntry{}, nil))

	// Wrapped
	ExpectCall(t.wrapped, "Save")("taco").
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.call()
}
<|endoftext|>


<commit_before>package server

import (
	"flag"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"net/http"
)

var (
	defaults *config
	//decoder  = schema.NewDecoder()
)

func start(conf *config) {
	defaults = conf
	flag.Set("bind", conf.Address) // Uh, I guess that's a bit strange
	if conf.Proxy {
		goji.Insert(middleware.RealIP, middleware.Logger)
	}

	goji.Use(serveLapitar)

	register("/skin/:player", serveSkin)

	register("/head/:player", serveHeadNormal)
	register("/head/:size/:player", serveHeadWithSize)

	register("/face/:player", serveFaceNormal)
	register("/face/:size/:player", serveFaceWithSize)

	goji.Get("/*", http.FileServer(http.Dir("www"))) // TODO: How to find the correct dir?

	goji.Serve()
}

func register(pattern string, handler interface{}) {
	goji.Get(pattern+".png", handler)
	goji.Get(pattern, handler)
}

func serveLapitar(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", "Lapitar") // TODO: Version
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Rename /head to /avatar<commit_after>package server

import (
	"flag"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
	"net/http"
)

var (
	defaults *config
	//decoder  = schema.NewDecoder()
)

func start(conf *config) {
	defaults = conf
	flag.Set("bind", conf.Address) // Uh, I guess that's a bit strange
	if conf.Proxy {
		goji.Insert(middleware.RealIP, middleware.Logger)
	}

	goji.Use(serveLapitar)

	register("/skin/:player", serveSkin)

	register("/avatar/:player", serveHeadNormal)
	register("/avatar/:size/:player", serveHeadWithSize)

	register("/face/:player", serveFaceNormal)
	register("/face/:size/:player", serveFaceWithSize)

	goji.Get("/*", http.FileServer(http.Dir("www"))) // TODO: How to find the correct dir?

	goji.Serve()
}

func register(pattern string, handler interface{}) {
	goji.Get(pattern+".png", handler)
	goji.Get(pattern, handler)
}

func serveLapitar(c *web.C, h http.Handler) http.Handler {
	fn := func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Server", "Lapitar") // TODO: Version
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"gnat"
	"log"
	"net/http"
	"strings"

	b58 "github.com/jbenet/go-base58"
)

var addr = flag.String("localhost", ":8080", "http service address")
var dht *gnat.DHT
var hub *Hub

func main() {
	initializeDHT()
	setupServer()
}

func onForwardRequestReceived(forwardToIP string, msg []byte) {
	hub.sendMessageToAddr(forwardToIP, msg)
}

func onClientMessageReceived(addr string, message []byte) {

	headerLen := 0
	for i := 0; i < len(message); i++ {
		if string(message[i]) == "}" {
			headerLen = i + 1
			break
		}
	}

	u := map[string]string{}
	resp := map[string]string{}
	json.Unmarshal(message[:headerLen], &u)
	clientIP := strings.Split(addr, ":")[0]

	fmt.Println(u)
	sendTo := u["send_to"]
	if sendTo == "" {
		return
	}

	fmt.Println("Received forwarding request from " + addr)

	if !strings.Contains(sendTo, ":") {
		// invalid ip address format
		resp["error"] = "Bad request"
		respMsg, _ := json.Marshal(resp)
		hub.sendMessageToAddr(clientIP, respMsg)
	}

	sendToIP := strings.Split(sendTo, ":")[0]
	sendToPort := strings.Split(sendTo, ":")[1]

	resp["from"] = addr
	respHeader, _ := json.Marshal(resp)
	forwardMessage(sendToIP, sendToPort, append(respHeader, message[headerLen:]...))
}

func handConnectionRequest(w http.ResponseWriter, r *http.Request) {

	// generate digest hash of IP address
	ipDigest := sha256.Sum256([]byte(r.RemoteAddr))
	id := b58.Encode(ipDigest[:])

	// find the node connected to this client ip
	node, err := dht.FindNode(id)

	if err == nil {

		if string(node.ID) == string(dht.GetSelfID()) {
			fmt.Println("Client accepted by " + node.IP.String())
			log.Println(r.URL)

			if r.URL.Path != "/" {
				http.Error(w, "Not found", 404)
				return
			}

			if r.Method != "GET" {
				http.Error(w, "Method not allowed", 405)
				return
			}

			http.ServeFile(w, r, "./static/home.html")

		} else {
			fmt.Println("Redirecting to http:/" + node.IP.String())
			http.Redirect(w, r, "http:/"+node.IP.String(), 301)
		}

	} else {
		fmt.Println(err)
	}
}

func setupServer() {
	flag.Parse()
	hub = newHub()
	go hub.run(onClientMessageReceived)
	http.HandleFunc("/", handConnectionRequest)
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(hub, w, r)
	})
	err := http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func initializeDHT() {
	var ip = flag.String("ip", "0.0.0.0", "IP Address to use")
	var port = flag.String("port", "8080", "Port to use")
	var bIP = flag.String("bip", "", "IP Address to bootstrap against")
	var bPort = flag.String("bport", "", "Port to bootstrap against")
	var stun = flag.Bool("stun", true, "Use STUN")

	flag.Parse()

	var bootstrapNodes []*gnat.NetworkNode
	if *bIP != "" || *bPort != "" {
		bootstrapNode := gnat.NewNetworkNode(*bIP, *bPort)
		bootstrapNodes = append(bootstrapNodes, bootstrapNode)
	}

	var err error
	dht, err = gnat.NewDHT(&gnat.Options{
		BootstrapNodes:   bootstrapNodes,
		IP:               *ip,
		Port:             *port,
		UseStun:          *stun,
		OnForwardRequest: onForwardRequestReceived,
	})

	fmt.Println("Opening socket..")

	if *stun {
		fmt.Println("Discovering public address using STUN..")
	}

	err = dht.CreateSocket()
	if err != nil {
		panic(err)
	}
	fmt.Println("..done")

	go func() {
		fmt.Println("Now listening on " + dht.GetNetworkAddr())
		err := dht.Listen()
		panic(err)
	}()

	if len(bootstrapNodes) > 0 {
		fmt.Println("Bootstrapping..")
		dht.Bootstrap()
		fmt.Println("..done")
	}
}

func forwardMessage(ip string, port string, msg []byte) {
	ipDigest := sha256.Sum256([]byte(ip))
	id := b58.Encode(ipDigest[:])
	fmt.Println("Searching for forwarding node: [" + ip + ":" + port + "]")
	node, err := dht.FindNode(id)

	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("..forwarding node found:", node.IP.String())
		dht.ForwardData(node, gnat.NewNetworkNode(ip, port), msg)
	}
}
<commit_msg>removed need for port in api<commit_after>package main

import (
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"gnat"
	"log"
	"net/http"
	"strings"

	b58 "github.com/jbenet/go-base58"
)

var addr = flag.String("localhost", ":80", "http service address")
var dht *gnat.DHT
var hub *Hub

func main() {
	initializeDHT()
	setupServer()
}

func onForwardRequestReceived(forwardToIP string, msg []byte) {
	hub.sendMessageToAddr(forwardToIP, msg)
}

func onClientMessageReceived(addr string, message []byte) {

	headerLen := 0
	for i := 0; i < len(message); i++ {
		if string(message[i]) == "}" {
			headerLen = i + 1
			break
		}
	}

	u := map[string]string{}
	resp := map[string]string{}
	json.Unmarshal(message[:headerLen], &u)
	clientIP := strings.Split(addr, ":")[0]

	fmt.Println(u)
	sendTo := u["send_to"]
	if sendTo == "" {
		return
	}

	fmt.Println("Received forwarding request from " + addr)

	if !strings.Contains(sendTo, ":") {
		// invalid ip address format
		resp["error"] = "Bad request"
		respMsg, _ := json.Marshal(resp)
		hub.sendMessageToAddr(clientIP, respMsg)
	}

	sendToIP := sendTo
	sendToPort := "0"

	resp["from"] = strings.Split(addr, ":")[0]
	respHeader, _ := json.Marshal(resp)
	forwardMessage(sendToIP, sendToPort, append(respHeader, message[headerLen:]...))
}

func handConnectionRequest(w http.ResponseWriter, r *http.Request) {

	// generate digest hash of IP address
	ipDigest := sha256.Sum256([]byte(r.RemoteAddr))
	id := b58.Encode(ipDigest[:])

	// find the node connected to this client ip
	node, err := dht.FindNode(id)

	if err == nil {

		if string(node.ID) == string(dht.GetSelfID()) {
			fmt.Println("Client accepted by " + node.IP.String())
			log.Println(r.URL)

			if r.URL.Path != "/" {
				http.Error(w, "Not found", 404)
				return
			}

			if r.Method != "GET" {
				http.Error(w, "Method not allowed", 405)
				return
			}

			http.ServeFile(w, r, "./static/home.html")

		} else {
			fmt.Println("Redirecting to http:/" + node.IP.String())
			http.Redirect(w, r, "http:/"+node.IP.String(), 301)
		}

	} else {
		fmt.Println(err)
	}
}

func setupServer() {
	flag.Parse()
	hub = newHub()
	go hub.run(onClientMessageReceived)
	http.HandleFunc("/", handConnectionRequest)
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(hub, w, r)
	})
	err := http.ListenAndServe(*addr, nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func initializeDHT() {
	var ip = flag.String("ip", "0.0.0.0", "IP Address to use")
	var port = flag.String("port", "8080", "Port to use")
	var bIP = flag.String("bip", "", "IP Address to bootstrap against")
	var bPort = flag.String("bport", "", "Port to bootstrap against")
	var stun = flag.Bool("stun", true, "Use STUN")

	flag.Parse()

	var bootstrapNodes []*gnat.NetworkNode
	if *bIP != "" || *bPort != "" {
		bootstrapNode := gnat.NewNetworkNode(*bIP, *bPort)
		bootstrapNodes = append(bootstrapNodes, bootstrapNode)
	}

	var err error
	dht, err = gnat.NewDHT(&gnat.Options{
		BootstrapNodes:   bootstrapNodes,
		IP:               *ip,
		Port:             *port,
		UseStun:          *stun,
		OnForwardRequest: onForwardRequestReceived,
	})

	fmt.Println("Opening socket..")

	if *stun {
		fmt.Println("Discovering public address using STUN..")
	}

	err = dht.CreateSocket()
	if err != nil {
		panic(err)
	}
	fmt.Println("..done")

	go func() {
		fmt.Println("Now listening on " + dht.GetNetworkAddr())
		err := dht.Listen()
		panic(err)
	}()

	if len(bootstrapNodes) > 0 {
		fmt.Println("Bootstrapping..")
		dht.Bootstrap()
		fmt.Println("..done")
	}
}

func forwardMessage(ip string, port string, msg []byte) {
	ipDigest := sha256.Sum256([]byte(ip))
	id := b58.Encode(ipDigest[:])
	fmt.Println("Searching for forwarding node: [" + ip + ":" + port + "]")
	node, err := dht.FindNode(id)

	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("..forwarding node found:", node.IP.String())
		dht.ForwardData(node, gnat.NewNetworkNode(ip, port), msg)
	}
}
<|endoftext|>


<commit_before>package server

import (
	"fmt"
	"github.com/albertyw/devops-reactions-index/tumblr"
	"io/ioutil"
	"net/http"
	"os"
)

const dataURLPath = "/data.json"

var templateDir = os.Getenv("SERVER_TEMPLATES")
var indexPath = fmt.Sprintf("%s/index.htm", templateDir)
var uRLFilePaths = map[string]func() (string, error){}
var posts []tumblr.Post

func exactURL(
	targetFunc func(http.ResponseWriter, *http.Request),
	requestedPath string,
) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != requestedPath {
			http.NotFound(w, r)
			return
		}
		targetFunc(w, r)
		return
	}
}

func readFile(p string) func(http.ResponseWriter, *http.Request) {
	path := p
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return
		}
		html := string(data)
		fmt.Fprintf(w, html)
	}
}

func dataURLHandler(w http.ResponseWriter, r *http.Request) {
	html := tumblr.PostsToJSON(posts)
	fmt.Fprintf(w, html)
}

// Run starts up the HTTP server
func Run(p []tumblr.Post) {
	posts = p
	address := ":" + os.Getenv("PORT")
	fmt.Println("server listening on", address)
	http.HandleFunc("/", exactURL(readFile(indexPath), "/"))
	http.HandleFunc(dataURLPath, dataURLHandler)
	http.ListenAndServe(address, nil)
}
<commit_msg>Add comments<commit_after>package server

import (
	"fmt"
	"github.com/albertyw/devops-reactions-index/tumblr"
	"io/ioutil"
	"net/http"
	"os"
)

const dataURLPath = "/data.json"

var templateDir = os.Getenv("SERVER_TEMPLATES")
var indexPath = fmt.Sprintf("%s/index.htm", templateDir)
var uRLFilePaths = map[string]func() (string, error){}
var posts []tumblr.Post

// exactURL is a closure that checks that the http match is an exact url path
// match instead of allowing for net/http's loose match
func exactURL(
	targetFunc func(http.ResponseWriter, *http.Request),
	requestedPath string,
) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != requestedPath {
			http.NotFound(w, r)
			return
		}
		targetFunc(w, r)
		return
	}
}

// readFile returns a function that reads the file at a given path and makes a
// response from it
func readFile(p string) func(http.ResponseWriter, *http.Request) {
	path := p
	return func(w http.ResponseWriter, r *http.Request) {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return
		}
		html := string(data)
		fmt.Fprintf(w, html)
	}
}

// dataURLHandler is an http handler for the dataURLPath response
func dataURLHandler(w http.ResponseWriter, r *http.Request) {
	html := tumblr.PostsToJSON(posts)
	fmt.Fprintf(w, html)
}

// Run starts up the HTTP server
func Run(p []tumblr.Post) {
	posts = p
	address := ":" + os.Getenv("PORT")
	fmt.Println("server listening on", address)
	http.HandleFunc("/", exactURL(readFile(indexPath), "/"))
	http.HandleFunc(dataURLPath, dataURLHandler)
	http.ListenAndServe(address, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Queens-Hacks/Propagate/sim"
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	total := make(chan []byte)
	diff := make(chan []byte)

	s := sim.SimpleState(50, 50)
	data, err := sim.MarshalGameState(s)
	if err != nil {
		logrus.Fatal(err)
	}

	go func() {
		total <- data
	}()

	port := ":4444"

	logrus.Infof("Listening on port %s", port)
	New(ctx, total, diff, port)
}
<commit_msg>not working server<commit_after>package main

import (
	"github.com/Queens-Hacks/Propagate/sim"
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	total := make(chan []byte)
	diff := make(chan []byte)

	s := sim.SimpleState(100, 50)
	data, err := sim.MarshalGameState(s)
	if err != nil {
		logrus.Fatal(err)
	}

	go func() {
		total <- data
	}()

	port := ":4444"

	logrus.Infof("Listening on port %s", port)
	go New(ctx, total, diff, port)

	for {
		updateState(&s, sim.DirtTile)
		updateState(&s, sim.AirTile)
	}
}

func updateState(s *sim.State, t sim.TileType) {
	for x := 40; x < 60; x++ {
		for y := 20; y < 25; y++ {
			s.SetTile(sim.Location{x, y}, sim.Tile{T: t})
		}
	}
}
<|endoftext|>


<commit_before>package swarm

import (
	"common"
	"crypto/sha256"
	"log"
	"time"
)

/* SwarmInformed

   This State initializes the arbitrary swarm. It uses a simple consensus
   algorithm.

   The first stage is the learning phase. Each node sends a NodeAlive message.
   They then wait to see at least a majority of the swarms NodeAlive messages
   then they resend their NodeAlive message, to make sure that the majority of
   the swarm knows they are alive.

   Once the learning period has expired, rendezvous hashing is used to select
   the host which should compile the block. The selected host creates a block
   and announces it. The hosts who agree that the selected host is the block
   compiler release a heartbeat update.

   Once the selected host has compiled heartbeats from the majority of swarms,
   the block compiler makes another block which indicates that the swarm is
   transitioning out of this state.

   If this process fails, then the host should be marked as an invalid compiler
   and the next block compiler attempted, until this process fails or some other
   timeout expires.

   TODO: This implementation handles failure after the first block has appeared
   badly. Also the learning phase -> block compiler transition should probably
   have a pause in it and we should have a constant start time, not just 1 second
   after we started a given structure.

   TODO: We can actually do stage1 hashes in the nodealive message and stage1
   and 2 in the heartbeat message. This would initialize us faster
*/
type StateSwarmInformed struct {
	//Map of hosts seen to number of times they have failed to generate a block
	//Used for both host alive tracking & host block generation tracking
	hostsseen map[string]int

	// How many times we have broadcast that we are alive, we use a two stage
	// process where we broadcast, and then broadcast again when we have seen
	// enough nodes up to form a majority
	broadcastcount uint
	stage2         string

	// This state has two phases, the learning phase where it listens for new
	// hosts and then the commit stage where it listens for a block that
	// is correct according to its knowledge and then votes for it.
	learning bool
	alive    bool

	heartbeats []*Heartbeat

	chain *Blockchain

	// Internal channels
	blockgen      <-chan time.Time
	sendBroadcast chan struct{}
	update        chan uwrap
	sync          chan struct{}
	die           chan struct{}
}

type uwrap struct {
	update common.Update
	ret    chan State
}

func NewStateSwarmInformed(chain *Blockchain) (s *StateSwarmInformed) {
	s = new(StateSwarmInformed)
	s.chain = chain

	// When transitions / timeouts happen
	// Should be dynamically set
	s.blockgen = time.Tick(1 * time.Second)

	s.alive = true

	s.learning = true
	s.hostsseen = make(map[string]int)
	s.sendBroadcast = make(chan struct{})
	s.update = make(chan uwrap)
	s.sync = make(chan struct{})
	s.die = make(chan struct{})

	go s.broadcastLife()
	go s.mainloop()
	return
}

func (s *StateSwarmInformed) Sync() {
	<-s.sync
}

func (s *StateSwarmInformed) Die() {
	s.die <- struct{}{}
	<-s.die
	close(s.die)
}

func (s *StateSwarmInformed) sendUpdate(u common.Update) {
	s.chain.outgoingUpdates <- u
}

func (s *StateSwarmInformed) HandleUpdate(u common.Update) State {
	log.Print("STATE: Block queed to be handled")
	if !s.alive {
		return s
	}
	c := make(chan State)
	s.update <- uwrap{u, c}
	r := <-c
	return r
}

func (s *StateSwarmInformed) blockCompiler() (compiler string) {

	hosts := make([]string, 0, len(s.hostsseen))

	//Pull all hosts who we haven't seen skipping a block
	for host, skipped := range s.hostsseen {
		if skipped != 0 {
			continue
		}
		hosts = append(hosts, host)
	}

	//Check if we should be the block generator
	compiler = common.RendezvousHash(sha256.New(), hosts, s.chain.Host)
	return
}

func (s *StateSwarmInformed) mainloop() {

	var compiler string

	for {
		select {
		case _ = <-s.die:
			s.alive = false
			close(s.sendBroadcast)
			close(s.update)
			close(s.sync)
			s.die <- struct{}{}
			return
		case _ = <-s.sendBroadcast:
			log.Print("STATE: NodeAlive Update to be Queed")
			s.broadcastcount += 1
			go s.sendUpdate(NewNodeAlive(s.chain.Host, s.chain.Id))

		case s.sync <- struct{}{}:

		case t := <-s.update:
			log.Print("STATE: Update Recieved")
			b := s.handleUpdate(t.update)
			t.ret <- b

		case _ = <-s.blockgen:
			log.Print("STATE: Blockgen Recieved")

			if s.learning {
				s.learning = false
				log.Print("STATE: Disable Learning")
			} else if len(s.chain.BlockHistory) == 0 {
				if compiler != "" {
					s.hostsseen[compiler] += 1
					log.Print("STATE: Block Compiler not found")
				}
			}

			//Dont't try to generate a block if we don't have a majority of hosts
			if len(s.hostsseen) <= common.SWARMSIZE/2 {
				continue
				//Should actually switch to state swarmdied after a while
			}

			compiler = s.blockCompiler()

			log.Print("STATE: Block Compiler ", compiler, " Me ", s.chain.Host,
				" chain len ", len(s.chain.BlockHistory),
				" good ", compiler == s.chain.Host)

			if len(s.chain.BlockHistory) == 0 && compiler == s.chain.Host {

				log.Print("STATE: Generating Block type 1")

				id, err := common.RandomString(8)
				if err != nil {
					panic("checkBlockGenRandom" + err.Error())
				}
				b := &Block{id, s.chain.Id, s.chain.Host, nil, nil}
				b.StorageMapping = make(map[string]interface{})
				for host, _ := range s.hostsseen {
					b.StorageMapping[host] = nil
				}

				s.heartbeats = s.heartbeats[0:0]
				time.Sleep(100 * time.Millisecond)
				go s.sendUpdate(b)
			}

			if len(s.chain.BlockHistory) == 1 && len(s.heartbeats) > 2 {

				log.Print("STATE: Generating Block type 2")

				id, err := common.RandomString(8)
				if err != nil {
					panic(err)
				}

				b := &Block{id, s.chain.Id, s.chain.Host, nil, nil}
				b.StorageMapping = s.chain.BlockHistory[0].StorageMapping
				b.Heartbeats = make(map[string]*Heartbeat)
				for _, h := range s.heartbeats {
					b.Heartbeats[h.Host] = h
				}

				// Arbitrary hard coded constant to make the testcases pass
				time.Sleep(500 * time.Millisecond)
				go s.sendUpdate(b)
			}
		}
		log.Print("STATE: Signal Handling Finished")
	}
}

func (s *StateSwarmInformed) broadcastLife() {
	s.sendBroadcast <- struct{}{}
}

func (s *StateSwarmInformed) handleUpdate(t common.Update) State {
	switch n := t.(type) {
	case *NodeAlive:
		if !s.learning {
			return s
		}

		s.hostsseen[n.Node] = 0
		// Resend hostsseen count once you have seen a majority of hosts
		if len(s.hostsseen) > 2 && s.broadcastcount < 2 {
			go s.broadcastLife()
		}

		log.Print("STATE: Node added")

	case *Heartbeat:

		//If we're learning this is too early
		if s.learning {
			return s
		}

		// If we're not trying to compile we don't care
		if s.blockCompiler() != s.chain.Host {
			return s
		}

		if len(s.chain.BlockHistory) != 0 && n.ParentBlock == s.chain.BlockHistory[0].Id {
			s.heartbeats = append(s.heartbeats, n)
		}

	case *Block:
		return s.handleBlock(n)

	default:
	}
	return s
}

func (s *StateSwarmInformed) handleBlock(b *Block) State {

	// If the learning timeout hasn't expired, don't accept blocks
	if s.learning {
		log.Print("STATE: Block rejected b/c learning")
		return s
	}

	// All blocks in this state should be generated by the ideal host
	if b.Compiler != s.blockCompiler() {
		log.Print("STATE: Block rejected b/c wrong compiler")
		return s
	}

	// We are looking for a block to generate a heartbeat for
	if len(s.chain.BlockHistory) == 0 {
		log.Print("STATE: Block accepted type 1")
		s.chain.AddBlock(b)

		stage1, stage2 := common.HashedRandomData(sha256.New(), 8)
		s.stage2 = stage2

		if _, ok := b.StorageMapping[s.chain.Host]; ok {
			h := NewHeartbeat(s.chain.BlockHistory[0], s.chain.Host, stage1, "")
			go s.sendUpdate(h)
		}
		return s
	}

	// We're looking for the block with heartbeats to figure out if we're in
	// it
	if len(s.chain.BlockHistory) == 1 {
		log.Print("STATE: Block accepted type 2")

		s.chain.AddBlock(b)

		if _, ok := b.StorageMapping[s.chain.Host]; ok {
			//If we're in the block switch to signal mode
			log.Print("STATE: Switching to connected")
			go s.Die()
			return NewStateSteady()
		} else {
			//Join the swarm
			log.Print("STATE: Switching to Join")
		}
	}

	return s
}
<commit_msg>Remove redundant channels in stateinformed use lock<commit_after>package swarm

import (
	"common"
	"crypto/sha256"
	"log"
	"sync"
	"time"
)

/* SwarmInformed

   This State initializes the arbitrary swarm. It uses a simple consensus
   algorithm.

   The first stage is the learning phase. Each node sends a NodeAlive message.
   They then wait to see at least a majority of the swarms NodeAlive messages
   then they resend their NodeAlive message, to make sure that the majority of
   the swarm knows they are alive.

   Once the learning period has expired, rendezvous hashing is used to select
   the host which should compile the block. The selected host creates a block
   and announces it. The hosts who agree that the selected host is the block
   compiler release a heartbeat update.

   Once the selected host has compiled heartbeats from the majority of swarms,
   the block compiler makes another block which indicates that the swarm is
   transitioning out of this state.

   If this process fails, then the host should be marked as an invalid compiler
   and the next block compiler attempted, until this process fails or some other
   timeout expires.

   TODO: This implementation handles failure after the first block has appeared
   badly. Also the learning phase -> block compiler transition should probably
   have a pause in it and we should have a constant start time, not just 1 second
   after we started a given structure.

   TODO: We can actually do stage1 hashes in the nodealive message and stage1
   and 2 in the heartbeat message. This would initialize us faster
*/
type StateSwarmInformed struct {
	//Map of hosts seen to number of times they have failed to generate a block
	//Used for both host alive tracking & host block generation tracking
	hostsseen map[string]int

	// How many times we have broadcast that we are alive, we use a two stage
	// process where we broadcast, and then broadcast again when we have seen
	// enough nodes up to form a majority
	broadcastcount uint
	stage2         string

	// This state has two phases, the learning phase where it listens for new
	// hosts and then the commit stage where it listens for a block that
	// is correct according to its knowledge and then votes for it.
	learning bool

	heartbeats []*Heartbeat

	chain *Blockchain

	lock *sync.Mutex

	blockgen <-chan time.Time
	die      chan struct{}
}

type uwrap struct {
	update common.Update
	ret    chan State
}

func NewStateSwarmInformed(chain *Blockchain) (s *StateSwarmInformed) {
	s = new(StateSwarmInformed)
	s.chain = chain

	// When transitions / timeouts happen
	// Should be dynamically set
	s.blockgen = time.Tick(1 * time.Second)

	s.lock = &sync.Mutex{}

	s.learning = true
	s.hostsseen = make(map[string]int)
	s.die = make(chan struct{})

	go s.broadcastLife()
	go s.mainloop()
	return
}

func (s *StateSwarmInformed) Sync() {
	s.lock.Lock()
	defer s.lock.Unlock()
}

func (s *StateSwarmInformed) Die() {
	s.die <- struct{}{}
	<-s.die
	close(s.die)
}

func (s *StateSwarmInformed) sendUpdate(u common.Update) {
	s.chain.outgoingUpdates <- u
}

func (s *StateSwarmInformed) blockCompiler() (compiler string) {

	hosts := make([]string, 0, len(s.hostsseen))

	//Pull all hosts who we haven't seen skipping a block
	for host, skipped := range s.hostsseen {
		if skipped != 0 {
			continue
		}
		hosts = append(hosts, host)
	}

	//Check if we should be the block generator
	compiler = common.RendezvousHash(sha256.New(), hosts, s.chain.Host)
	return
}

func (s *StateSwarmInformed) mainloop() {

	var compiler string

	for {
		select {
		case _ = <-s.die:
			return

		case _ = <-s.blockgen:
			s.lock.Lock()
			log.Print("STATE: Blockgen Recieved")

			if s.learning {
				s.learning = false
				log.Print("STATE: Disable Learning")
			} else if len(s.chain.BlockHistory) == 0 {
				if compiler != "" {
					s.hostsseen[compiler] += 1
					log.Print("STATE: Block Compiler not found")
				}
			}

			//Dont't try to generate a block if we don't have a majority of hosts
			if len(s.hostsseen) <= common.SWARMSIZE/2 {
				continue
				//Should actually switch to state swarmdied after a while
			}

			compiler = s.blockCompiler()

			log.Print("STATE: Block Compiler ", compiler, " Me ", s.chain.Host,
				" chain len ", len(s.chain.BlockHistory),
				" good ", compiler == s.chain.Host)

			if len(s.chain.BlockHistory) == 0 && compiler == s.chain.Host {

				log.Print("STATE: Generating Block type 1")

				id, err := common.RandomString(8)
				if err != nil {
					panic("checkBlockGenRandom" + err.Error())
				}
				b := &Block{id, s.chain.Id, s.chain.Host, nil, nil}
				b.StorageMapping = make(map[string]interface{})
				for host, _ := range s.hostsseen {
					b.StorageMapping[host] = nil
				}

				s.heartbeats = s.heartbeats[0:0]
				time.Sleep(100 * time.Millisecond)
				go s.sendUpdate(b)
			}

			if len(s.chain.BlockHistory) == 1 && len(s.heartbeats) > 2 {

				log.Print("STATE: Generating Block type 2")

				id, err := common.RandomString(8)
				if err != nil {
					panic(err)
				}

				b := &Block{id, s.chain.Id, s.chain.Host, nil, nil}
				b.StorageMapping = s.chain.BlockHistory[0].StorageMapping
				b.Heartbeats = make(map[string]*Heartbeat)
				for _, h := range s.heartbeats {
					b.Heartbeats[h.Host] = h
				}

				// Arbitrary hard coded constant to make the testcases pass
				time.Sleep(500 * time.Millisecond)
				go s.sendUpdate(b)
			}
			s.lock.Unlock()
		}
		log.Print("STATE: Signal Handling Finished")
	}
}

func (s *StateSwarmInformed) broadcastLife() {
	log.Print("STATE: NodeAlive Update to be Queed")
	s.lock.Lock()
	defer s.lock.Unlock()
	s.broadcastcount += 1
	go s.sendUpdate(NewNodeAlive(s.chain.Host, s.chain.Id))

}

func (s *StateSwarmInformed) HandleUpdate(t common.Update) State {
	s.lock.Lock()
	defer s.lock.Unlock()
	switch n := t.(type) {
	case *NodeAlive:
		if !s.learning {
			return s
		}

		s.hostsseen[n.Node] = 0
		// Resend hostsseen count once you have seen a majority of hosts
		if len(s.hostsseen) > 2 && s.broadcastcount < 2 {
			go s.broadcastLife()
		}

		log.Print("STATE: Node added")

	case *Heartbeat:

		//If we're learning this is too early
		if s.learning {
			return s
		}

		// If we're not trying to compile we don't care
		if s.blockCompiler() != s.chain.Host {
			return s
		}

		if len(s.chain.BlockHistory) != 0 && n.ParentBlock == s.chain.BlockHistory[0].Id {
			s.heartbeats = append(s.heartbeats, n)
		}

	case *Block:
		return s.handleBlock(n)

	default:
	}
	return s
}

func (s *StateSwarmInformed) handleBlock(b *Block) State {

	// If the learning timeout hasn't expired, don't accept blocks
	if s.learning {
		log.Print("STATE: Block rejected b/c learning")
		return s
	}

	// All blocks in this state should be generated by the ideal host
	if b.Compiler != s.blockCompiler() {
		log.Print("STATE: Block rejected b/c wrong compiler")
		return s
	}

	// We are looking for a block to generate a heartbeat for
	if len(s.chain.BlockHistory) == 0 {
		log.Print("STATE: Block accepted type 1")
		s.chain.AddBlock(b)

		stage1, stage2 := common.HashedRandomData(sha256.New(), 8)
		s.stage2 = stage2

		if _, ok := b.StorageMapping[s.chain.Host]; ok {
			h := NewHeartbeat(s.chain.BlockHistory[0], s.chain.Host, stage1, "")
			go s.sendUpdate(h)
		}
		return s
	}

	// We're looking for the block with heartbeats to figure out if we're in
	// it
	if len(s.chain.BlockHistory) == 1 {
		log.Print("STATE: Block accepted type 2")

		s.chain.AddBlock(b)

		if _, ok := b.StorageMapping[s.chain.Host]; ok {
			//If we're in the block switch to signal mode
			log.Print("STATE: Switching to connected")
			go s.Die()
			return NewStateSteady()
		} else {
			//Join the swarm
			log.Print("STATE: Switching to Join")
		}
	}

	return s
}
<|endoftext|>


<commit_before>package lib

import (
	"strings"

	"github.com/peted27/go-ircevent"
)

func PrivmsgHandler(f func(e *irc.Event), hDirect, hIndirect, hPrivate bool) func(e *irc.Event) {

	return func(e *irc.Event) {
		var private, direct, indirect bool

		// deterimine the type of private message
		if strings.HasPrefix(e.Arguments[0], "#") {
			switch {
			case strings.HasPrefix(e.Arguments[1], "!"):
				indirect = true
			case strings.HasPrefix(e.Arguments[1], e.Connection.GetNick()+":"):
				direct = true
			case strings.HasPrefix(e.Arguments[1], e.Connection.GetNick()+","):
				direct = true
			}
		} else {
			private = true
		}

		// if handler is configured to handle the event, then pass it on untouched
		if (hDirect == direct) || (hIndirect == indirect) || (hPrivate == private) {
			f(e)
		}
	}
}
<commit_msg>updated logic in lib<commit_after>package lib

import (
	"strings"

	"github.com/peted27/go-ircevent"
)

func PrivmsgHandler(f func(e *irc.Event), hDirect, hIndirect, hPrivate bool) func(e *irc.Event) {

	return func(e *irc.Event) {
		var private, direct, indirect bool

		// deterimine the type of private message
		if strings.HasPrefix(e.Arguments[0], "#") {
			switch {
			case strings.HasPrefix(e.Arguments[1], "!"):
				indirect = true
			case strings.HasPrefix(e.Arguments[1], e.Connection.GetNick()+":"):
				direct = true
			case strings.HasPrefix(e.Arguments[1], e.Connection.GetNick()+","):
				direct = true
			}
		} else {
			private = true
		}

		// if handler is configured to handle the event, then pass it on untouched
		if (hDirect && direct) || (hIndirect && indirect) || (hPrivate && private) {
			f(e)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

type Type int

const (
	None Type = iota
	String
	Int
	Float
)
<commit_msg>Adds the Untyped type to indicate that a type has not yet been decided.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

type Type int

const (
	Untyped Type = iota // Untyped indicates no type has been determined
	None
	String
	Int
	Float
)
<|endoftext|>


<commit_before>package bql

import (
	"errors"
	"fmt"
	"io"
	"os"
	"pfi/sensorbee/sensorbee/core"
	"pfi/sensorbee/sensorbee/data"
	"sync"
	"time"
)

// TODO: create bql/builtin directory and move components in this file to there

func createSharedStateSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	// Get only name parameter from params
	name, ok := params["name"]
	if !ok {
		return nil, fmt.Errorf("cannot find 'name' parameter")
	}
	nameStr, err := data.AsString(name)
	if err != nil {
		return nil, err
	}

	// TODO: Support cascading delete. Because it isn't supported yet,
	// the sink will be running even after the target state is dropped.
	// Moreover, creating a state having the same name after dropping
	// the previous state might result in a confusing behavior.
	return core.NewSharedStateSink(ctx, nameStr)
}

func init() {
	MustRegisterGlobalSinkCreator("uds", SinkCreatorFunc(createSharedStateSink))
}

type writerSink struct {
	m           sync.Mutex
	w           io.Writer
	shouldClose bool
}

func (s *writerSink) Write(ctx *core.Context, t *core.Tuple) error {
	js := t.Data.String() // Format this outside the lock

	// This lock is required to avoid interleaving JSONs.
	s.m.Lock()
	defer s.m.Unlock()
	if s.w == nil {
		return errors.New("the sink is already closed")
	}
	_, err := fmt.Fprintln(s.w, js)
	return err
}

func (s *writerSink) Close(ctx *core.Context) error {
	s.m.Lock()
	defer s.m.Unlock()
	if s.w == nil {
		return nil
	}
	if s.shouldClose {
		if c, ok := s.w.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func createStdoutSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	return &writerSink{
		w: os.Stdout,
	}, nil
}

func createFileSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	// TODO: currently this sink isn't secure because it accepts any path.
	// TODO: support buffering

	var fpath string
	if v, ok := params["path"]; !ok {
		return nil, errors.New("path parameter is missing")
	} else if f, err := data.AsString(v); err != nil {
		return nil, errors.New("path parameter must be a string")
	} else {
		fpath = f
	}

	flags := os.O_WRONLY | os.O_APPEND | os.O_CREATE
	if v, ok := params["truncate"]; ok {
		t, err := data.AsBool(v)
		if err != nil {
			return nil, fmt.Errorf("'truncate' parameter must be bool: %v", err)
		}
		if t {
			flags |= os.O_TRUNC
		}
	}

	file, err := os.OpenFile(fpath, flags, 0644)
	if err != nil {
		return nil, err
	}
	return &writerSink{
		w:           file,
		shouldClose: true,
	}, nil
}

func init() {
	MustRegisterGlobalSinkCreator("stdout", SinkCreatorFunc(createStdoutSink))
	MustRegisterGlobalSinkCreator("file", SinkCreatorFunc(createFileSink))
}

func createDroppedTupleCollectorSource(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
	return core.NewDroppedTupleCollectorSource(), nil
}

func init() {
	MustRegisterGlobalSourceCreator("dropped_tuples", SourceCreatorFunc(createDroppedTupleCollectorSource))
}

type nodeStatusSource struct {
	topology core.Topology
	interval time.Duration
	stopCh   chan struct{}
}

func (s *nodeStatusSource) GenerateStream(ctx *core.Context, w core.Writer) error {
	next := time.Now().Add(s.interval)
	for {
		select {
		case <-s.stopCh:
			return nil
		case <-time.After(next.Sub(time.Now())):
		}
		now := time.Now()

		for name, n := range s.topology.Nodes() {
			t := &core.Tuple{
				Timestamp:     now,
				ProcTimestamp: now,
				Data:          n.Status(),
			}
			t.Data["node_name"] = data.String(name)
			t.Data["node_type"] = data.String(n.Type().String())
			w.Write(ctx, t)
		}

		next = next.Add(s.interval)
		if next.Before(now) {
			// delayed too much and should be rescheduled.
			next = now.Add(s.interval)
		}
	}
}

func (s *nodeStatusSource) Stop(ctx *core.Context) error {
	close(s.stopCh)
	return nil
}

// createNodeStatusSourceCreator creates a SourceCreator which creates
// nodeStatusSource. Because it requires core.Topology, it cannot be registered
// statically. It'll be registered in a function like NewTopologyBuilder.
func createNodeStatusSourceCreator(t core.Topology) SourceCreator {
	return SourceCreatorFunc(func(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
		interval := 1 * time.Second
		if v, ok := params["interval"]; !ok {
		} else if d, err := data.ToDuration(v); err != nil {
			return nil, err
		} else {
			interval = d
		}

		return &nodeStatusSource{
			topology: t,
			interval: interval,
			stopCh:   make(chan struct{}),
		}, nil
	})
}

type edgeStatusSource struct {
	topology core.Topology
	interval time.Duration
	stopCh   chan struct{}
}

func (s *edgeStatusSource) GenerateStream(ctx *core.Context, w core.Writer) error {
	next := time.Now().Add(s.interval)

	inputPath := data.MustCompilePath("input_stats.inputs")

	for {
		select {
		case <-s.stopCh:
			return nil
		case <-time.After(next.Sub(time.Now())):
		}
		now := time.Now()

		// collect all nodes that can receive data
		receivers := map[string]core.Node{}
		for name, b := range s.topology.Boxes() {
			receivers[name] = b
		}
		for name, s := range s.topology.Sinks() {
			receivers[name] = s
		}

		// loop over those receiver nodes and consider all of
		// their incoming edges
		for name, n := range receivers {
			nodeStatus := n.Status()
			// get the input status
			inputs, err := nodeStatus.Get(inputPath)
			if err != nil {
				ctx.ErrLog(err).WithField("node_status", nodeStatus).
					WithField("node_name", name).
					Error("No input_stats present in node status")
				continue
			}
			inputMap, err := data.AsMap(inputs)
			if err != nil {
				ctx.ErrLog(err).WithField("inputs", inputs).
					WithField("node_name", name).
					Error("input_stats.inputs is not a Map")
				continue
			}

			// loop over the input nodes to get an edge-centric view
			for inputName, inputStats := range inputMap {
				inputNode, err := s.topology.Node(inputName)
				if err != nil {
					ctx.ErrLog(err).WithField("sender", inputName).
						WithField("receiver", name).
						Error("Node listens to non-existing node")
					continue
				}
				edgeData := data.Map{
					"sender": data.Map{
						"node_name": data.String(inputName),
						"node_type": data.String(inputNode.Type().String()),
					},
					"receiver": data.Map{
						"node_name": data.String(name),
						"node_type": data.String(n.Type().String()),
					},
					// use the input statistics for that edge from the
					// receiver as edge statistics. the data is correct,
					// but the wording may be a bit weird, e.g. "num_received"
					// should maybe rather be "num_transferred"
					"stats": inputStats,
				}
				// write tuple
				t := &core.Tuple{
					Timestamp:     now,
					ProcTimestamp: now,
					Data:          edgeData,
				}
				w.Write(ctx, t)
			}

		}

		next = next.Add(s.interval)
		if next.Before(now) {
			// delayed too much and should be rescheduled.
			next = now.Add(s.interval)
		}
	}
}

func (s *edgeStatusSource) Stop(ctx *core.Context) error {
	close(s.stopCh)
	return nil
}

func createEdgeStatusSourceCreator(t core.Topology) SourceCreator {
	return SourceCreatorFunc(func(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
		interval := 1 * time.Second
		if v, ok := params["interval"]; !ok {
		} else if d, err := data.ToDuration(v); err != nil {
			return nil, err
		} else {
			interval = d
		}

		return &edgeStatusSource{
			topology: t,
			interval: interval,
			stopCh:   make(chan struct{}),
		}, nil
	})
}
<commit_msg>Add comments regarding format parameter support<commit_after>package bql

import (
	"errors"
	"fmt"
	"io"
	"os"
	"pfi/sensorbee/sensorbee/core"
	"pfi/sensorbee/sensorbee/data"
	"sync"
	"time"
)

// TODO: create bql/builtin directory and move components in this file to there

func createSharedStateSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	// Get only name parameter from params
	name, ok := params["name"]
	if !ok {
		return nil, fmt.Errorf("cannot find 'name' parameter")
	}
	nameStr, err := data.AsString(name)
	if err != nil {
		return nil, err
	}

	// TODO: Support cascading delete. Because it isn't supported yet,
	// the sink will be running even after the target state is dropped.
	// Moreover, creating a state having the same name after dropping
	// the previous state might result in a confusing behavior.
	return core.NewSharedStateSink(ctx, nameStr)
}

func init() {
	MustRegisterGlobalSinkCreator("uds", SinkCreatorFunc(createSharedStateSink))
}

type writerSink struct {
	m           sync.Mutex
	w           io.Writer
	shouldClose bool
}

func (s *writerSink) Write(ctx *core.Context, t *core.Tuple) error {
	// TODO: support custom formatting. There're several things that need to
	// be considered such as concurrent formatting, zero-copy write, and so on.
	// While encoding tuples outside the lock supports concurrent formatting,
	// it makes it difficult to support zero-copy write.

	js := t.Data.String() // Format this outside the lock

	// This lock is required to avoid interleaving JSONs.
	s.m.Lock()
	defer s.m.Unlock()
	if s.w == nil {
		return errors.New("the sink is already closed")
	}
	_, err := fmt.Fprintln(s.w, js)
	return err
}

func (s *writerSink) Close(ctx *core.Context) error {
	s.m.Lock()
	defer s.m.Unlock()
	if s.w == nil {
		return nil
	}
	if s.shouldClose {
		if c, ok := s.w.(io.Closer); ok {
			return c.Close()
		}
	}
	return nil
}

func createStdoutSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	return &writerSink{
		w: os.Stdout,
	}, nil
}

func createFileSink(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Sink, error) {
	// TODO: currently this sink isn't secure because it accepts any path.
	// TODO: support buffering
	// TODO: provide "format" parameter to support output formats other than "jsonl".
	//       "jsonl" should be the default value.
	// TODO: support "compression" parameter with values like "gz".

	var fpath string
	if v, ok := params["path"]; !ok {
		return nil, errors.New("path parameter is missing")
	} else if f, err := data.AsString(v); err != nil {
		return nil, errors.New("path parameter must be a string")
	} else {
		fpath = f
	}

	flags := os.O_WRONLY | os.O_APPEND | os.O_CREATE
	if v, ok := params["truncate"]; ok {
		t, err := data.AsBool(v)
		if err != nil {
			return nil, fmt.Errorf("'truncate' parameter must be bool: %v", err)
		}
		if t {
			flags |= os.O_TRUNC
		}
	}

	file, err := os.OpenFile(fpath, flags, 0644)
	if err != nil {
		return nil, err
	}
	return &writerSink{
		w:           file,
		shouldClose: true,
	}, nil
}

func init() {
	MustRegisterGlobalSinkCreator("stdout", SinkCreatorFunc(createStdoutSink))
	MustRegisterGlobalSinkCreator("file", SinkCreatorFunc(createFileSink))
}

func createDroppedTupleCollectorSource(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
	return core.NewDroppedTupleCollectorSource(), nil
}

func init() {
	MustRegisterGlobalSourceCreator("dropped_tuples", SourceCreatorFunc(createDroppedTupleCollectorSource))
}

type nodeStatusSource struct {
	topology core.Topology
	interval time.Duration
	stopCh   chan struct{}
}

func (s *nodeStatusSource) GenerateStream(ctx *core.Context, w core.Writer) error {
	next := time.Now().Add(s.interval)
	for {
		select {
		case <-s.stopCh:
			return nil
		case <-time.After(next.Sub(time.Now())):
		}
		now := time.Now()

		for name, n := range s.topology.Nodes() {
			t := &core.Tuple{
				Timestamp:     now,
				ProcTimestamp: now,
				Data:          n.Status(),
			}
			t.Data["node_name"] = data.String(name)
			t.Data["node_type"] = data.String(n.Type().String())
			w.Write(ctx, t)
		}

		next = next.Add(s.interval)
		if next.Before(now) {
			// delayed too much and should be rescheduled.
			next = now.Add(s.interval)
		}
	}
}

func (s *nodeStatusSource) Stop(ctx *core.Context) error {
	close(s.stopCh)
	return nil
}

// createNodeStatusSourceCreator creates a SourceCreator which creates
// nodeStatusSource. Because it requires core.Topology, it cannot be registered
// statically. It'll be registered in a function like NewTopologyBuilder.
func createNodeStatusSourceCreator(t core.Topology) SourceCreator {
	return SourceCreatorFunc(func(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
		interval := 1 * time.Second
		if v, ok := params["interval"]; !ok {
		} else if d, err := data.ToDuration(v); err != nil {
			return nil, err
		} else {
			interval = d
		}

		return &nodeStatusSource{
			topology: t,
			interval: interval,
			stopCh:   make(chan struct{}),
		}, nil
	})
}

type edgeStatusSource struct {
	topology core.Topology
	interval time.Duration
	stopCh   chan struct{}
}

func (s *edgeStatusSource) GenerateStream(ctx *core.Context, w core.Writer) error {
	next := time.Now().Add(s.interval)

	inputPath := data.MustCompilePath("input_stats.inputs")

	for {
		select {
		case <-s.stopCh:
			return nil
		case <-time.After(next.Sub(time.Now())):
		}
		now := time.Now()

		// collect all nodes that can receive data
		receivers := map[string]core.Node{}
		for name, b := range s.topology.Boxes() {
			receivers[name] = b
		}
		for name, s := range s.topology.Sinks() {
			receivers[name] = s
		}

		// loop over those receiver nodes and consider all of
		// their incoming edges
		for name, n := range receivers {
			nodeStatus := n.Status()
			// get the input status
			inputs, err := nodeStatus.Get(inputPath)
			if err != nil {
				ctx.ErrLog(err).WithField("node_status", nodeStatus).
					WithField("node_name", name).
					Error("No input_stats present in node status")
				continue
			}
			inputMap, err := data.AsMap(inputs)
			if err != nil {
				ctx.ErrLog(err).WithField("inputs", inputs).
					WithField("node_name", name).
					Error("input_stats.inputs is not a Map")
				continue
			}

			// loop over the input nodes to get an edge-centric view
			for inputName, inputStats := range inputMap {
				inputNode, err := s.topology.Node(inputName)
				if err != nil {
					ctx.ErrLog(err).WithField("sender", inputName).
						WithField("receiver", name).
						Error("Node listens to non-existing node")
					continue
				}
				edgeData := data.Map{
					"sender": data.Map{
						"node_name": data.String(inputName),
						"node_type": data.String(inputNode.Type().String()),
					},
					"receiver": data.Map{
						"node_name": data.String(name),
						"node_type": data.String(n.Type().String()),
					},
					// use the input statistics for that edge from the
					// receiver as edge statistics. the data is correct,
					// but the wording may be a bit weird, e.g. "num_received"
					// should maybe rather be "num_transferred"
					"stats": inputStats,
				}
				// write tuple
				t := &core.Tuple{
					Timestamp:     now,
					ProcTimestamp: now,
					Data:          edgeData,
				}
				w.Write(ctx, t)
			}

		}

		next = next.Add(s.interval)
		if next.Before(now) {
			// delayed too much and should be rescheduled.
			next = now.Add(s.interval)
		}
	}
}

func (s *edgeStatusSource) Stop(ctx *core.Context) error {
	close(s.stopCh)
	return nil
}

func createEdgeStatusSourceCreator(t core.Topology) SourceCreator {
	return SourceCreatorFunc(func(ctx *core.Context, ioParams *IOParams, params data.Map) (core.Source, error) {
		interval := 1 * time.Second
		if v, ok := params["interval"]; !ok {
		} else if d, err := data.ToDuration(v); err != nil {
			return nil, err
		} else {
			interval = d
		}

		return &edgeStatusSource{
			topology: t,
			interval: interval,
			stopCh:   make(chan struct{}),
		}, nil
	})
}
<|endoftext|>


<commit_before>package broker

import (
	zmq "github.com/pebbe/zmq4"
	"log"
	"runtime"
	"time"
)

func (b *Broker) Poll(messageHandler *MessageHandler) {
	b.connect()
	runtime.SetFinalizer(b, (*Broker).Close)

	poller := zmq.NewPoller()
	poller.Add(b.socket, zmq.POLLIN)

	for {
		polled, err := poller.Poll(HEARTBEAT_INTERVAL)

		if err != nil {
			log.Println("E: Interrupted")
			log.Printf("%q\n", err)
			break //  Interrupted
		}

		if len(polled) <= 0 {
			// TODO: heartbeat
			if time.Now().After(b.heartbeatAt) {
				log.Println("I: Heartbeat")
				//broker.Purge()
				//for _, worker := range b.waiting {
				//	worker.Send(WORKER_HEARTBEAT, []string{})
				//}
				b.heartbeatAt = time.Now().Add(HEARTBEAT_INTERVAL)
			}
			continue
		}

		msg, err := b.socket.RecvMessage(0)

		if err != nil {
			log.Println("E: Interrupted")
			log.Printf("%q\n", err)
			break //  Interrupted
		}

		message, err := NewMessage(msg)

		if err != nil {
			log.Println("!: Message malformed")
			continue
		}

		messageHandler.Respond(message, b.socket)
	}
}
<commit_msg>Heartbeat check happens on each poll<commit_after>package broker

import (
	zmq "github.com/pebbe/zmq4"
	"log"
	"runtime"
	"time"
)

func (b *Broker) Poll(messageHandler *MessageHandler) {
	b.connect()
	runtime.SetFinalizer(b, (*Broker).Close)

	poller := zmq.NewPoller()
	poller.Add(b.socket, zmq.POLLIN)

	for {
		polled, err := poller.Poll(HEARTBEAT_INTERVAL)

		if err != nil {
			log.Println("E: Interrupted")
			log.Printf("%q\n", err)
			break //  Interrupted
		}

		if len(polled) > 0 {
			msg, err := b.socket.RecvMessage(0)

			if err != nil {
				log.Println("E: Interrupted")
				log.Printf("%q\n", err)
				break //  Interrupted
			}

			message, err := NewMessage(msg)

			if err != nil {
				log.Println("!: Message malformed")
				continue
			}

			messageHandler.Respond(message, b.socket)
		}

		// TODO: heartbeat
		if time.Now().After(b.heartbeatAt) {
			log.Println("I: Heartbeat")
			//broker.Purge()
			//for _, worker := range b.waiting {
			//	worker.Send(WORKER_HEARTBEAT, []string{})
			//}
			b.heartbeatAt = time.Now().Add(HEARTBEAT_INTERVAL)
		}
	}
}
<|endoftext|>