<commit_before>package debugstream

import (
	"bytes"
	"context"
	"strings"
	"testing"
	"time"
)

func TestScopedCommands(t *testing.T) {
	sc := NewScopedCommands()
	if len(sc.commands) != 1 {
		t.Fatalf("scoped commands failed to create with one scope: had %v", len(sc.commands))
	}
	if len(sc.commands[0]) != 3 {
		t.Fatalf("scoped commands failed to create with three commands: had %v", len(sc.commands[0]))
	}
}

func TestScopedCommands_AssumeScope(t *testing.T) {
	sc := NewScopedCommands()

	in := bytes.NewBufferString("scope\nscope zero\nscope 2\nscope 0\n0 scope 0\n2 scope 0\n0")
	out := new(bytes.Buffer)

	sc.AttachToStream(context.Background(), in, out)

	time.Sleep(50 * time.Millisecond)

	expected := `assume scope requires a scopeID
Active Scopes: [0]
assume scope <scopeID> expects a valid int32 scope
you provided "zero" which errored with strconv.ParseInt: parsing "zero": invalid syntax
inactive scope 2
assumed scope 0
assumed scope 0
unknown scopeID 2
only provided scopeID 0 without command
`

	got := out.String()
	if got != expected {
		t.Fatal("got:\n" + got + "\nexpected:\n" + expected)
	}
}

func TestScopedCommands_Help(t *testing.T) {
	sc := NewScopedCommands()

	in := bytes.NewBufferString("help\nhelp 0\n help scope\nhelp 1\nhelp badcommand")
	out := new(bytes.Buffer)

	sc.AttachToStream(context.Background(), in, out)

	time.Sleep(50 * time.Millisecond)

	expected := `help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
General Commands:
  fade: fade the specified renderable by the given int if given. Renderable must be registered in debug
  help
  scope: provide a scopeID to use commands without a scopeID prepended

help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
General Commands:
  fade: fade the specified renderable by the given int if given. Renderable must be registered in debug
  help
  scope: provide a scopeID to use commands without a scopeID prepended

help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
Registered Instances of scope
  scope0 scope: provide a scopeID to use commands without a scopeID prepended
inactive scope 1 see correct usage by using help without the scope
help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
Registered Instances of badcommand
  Warning scope '0' did not have the specified command "badcommand"
`

	got := out.String()
	if got != expected {
		t.Fatal("got:\n" + got + "\nexpected:\n" + expected)
	}
}

func TestScopedCommands_AttachToStream(t *testing.T) {
	in := bytes.NewBufferString("simple")
	out := new(bytes.Buffer)

	sc := NewScopedCommands()
	sc.AttachToStream(context.Background(), in, out)

	// lazy interim approach for the async to complete

	time.Sleep(50 * time.Millisecond)
	output := out.String()
	if !strings.Contains(output, "Unknown command") {
		t.Fatalf("attached Stream doesnt work %s\n", output)
	}
}

func TestScopedCommands_DetachFromStream(t *testing.T) {
	in := new(bytes.Buffer)
	out := new(bytes.Buffer)

	ctx, cancel := context.WithCancel(context.Background())

	sc := NewScopedCommands()
	sc.AttachToStream(ctx, in, out)
	cancel()
	time.Sleep(50 * time.Millisecond)
	output := out.String()
	if !strings.Contains(output, "stopping debugstream") {
		t.Fatalf("unattaching Stream doesnt work %s\n", output)
	}

}
<commit_msg>debugstream: update tests for removed fade command<commit_after>package debugstream

import (
	"bytes"
	"context"
	"strings"
	"testing"
	"time"
)

func TestScopedCommands(t *testing.T) {
	sc := NewScopedCommands()
	if len(sc.commands) != 1 {
		t.Fatalf("scoped commands failed to create with one scope: had %v", len(sc.commands))
	}
	if len(sc.commands[0]) != 2 {
		t.Fatalf("scoped commands failed to create with two commands: had %v", len(sc.commands[0]))
	}
}

func TestScopedCommands_AssumeScope(t *testing.T) {
	sc := NewScopedCommands()

	in := bytes.NewBufferString("scope\nscope zero\nscope 2\nscope 0\n0 scope 0\n2 scope 0\n0")
	out := new(bytes.Buffer)

	sc.AttachToStream(context.Background(), in, out)

	time.Sleep(50 * time.Millisecond)

	expected := `assume scope requires a scopeID
Active Scopes: [0]
assume scope <scopeID> expects a valid int32 scope
you provided "zero" which errored with strconv.ParseInt: parsing "zero": invalid syntax
inactive scope 2
assumed scope 0
assumed scope 0
unknown scopeID 2
only provided scopeID 0 without command
`

	got := out.String()
	if got != expected {
		t.Fatal("got:\n" + got + "\nexpected:\n" + expected)
	}
}

func TestScopedCommands_Help(t *testing.T) {
	sc := NewScopedCommands()

	in := bytes.NewBufferString("help\nhelp 0\n help scope\nhelp 1\nhelp badcommand")
	out := new(bytes.Buffer)

	sc.AttachToStream(context.Background(), in, out)

	time.Sleep(50 * time.Millisecond)

	expected := `help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
General Commands:
  help
  scope: provide a scopeID to use commands without a scopeID prepended

help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
General Commands:
  help
  scope: provide a scopeID to use commands without a scopeID prepended

help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
Registered Instances of scope
  scope0 scope: provide a scopeID to use commands without a scopeID prepended
inactive scope 1 see correct usage by using help without the scope
help <scopeID> to see commands linked to a given window
Active Scopes: [0]
Current Assumed Scope: 0
Registered Instances of badcommand
  Warning scope '0' did not have the specified command "badcommand"
`

	got := out.String()
	if got != expected {
		t.Fatal("got:\n" + got + "\nexpected:\n" + expected)
	}
}

func TestScopedCommands_AttachToStream(t *testing.T) {
	in := bytes.NewBufferString("simple")
	out := new(bytes.Buffer)

	sc := NewScopedCommands()
	sc.AttachToStream(context.Background(), in, out)

	// lazy interim approach for the async to complete

	time.Sleep(50 * time.Millisecond)
	output := out.String()
	if !strings.Contains(output, "Unknown command") {
		t.Fatalf("attached Stream doesnt work %s\n", output)
	}
}

func TestScopedCommands_DetachFromStream(t *testing.T) {
	in := new(bytes.Buffer)
	out := new(bytes.Buffer)

	ctx, cancel := context.WithCancel(context.Background())

	sc := NewScopedCommands()
	sc.AttachToStream(ctx, in, out)
	cancel()
	time.Sleep(50 * time.Millisecond)
	output := out.String()
	if !strings.Contains(output, "stopping debugstream") {
		t.Fatalf("unattaching Stream doesnt work %s\n", output)
	}

}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package tools

import (
	"errors"
	"fmt"
	"strings"

	"github.com/juju/utils/set"

	"github.com/juju/juju/version"
)

// List holds tools available in an environment. The order of tools within
// a List is not significant.
type List []*Tools

var ErrNoMatches = errors.New("no matching tools available")

// String returns the versions of the tools in src, separated by semicolons.
func (src List) String() string {
	names := make([]string, len(src))
	for i, tools := range src {
		names[i] = tools.Version.String()
	}
	return strings.Join(names, ";")
}

// AllSeries returns all series for which some tools in src were built.
func (src List) AllSeries() []string {
	return src.collect(func(tools *Tools) string {
		return tools.Version.Series
	})
}

// OneSeries returns the single series for which all tools in src were built.
func (src List) OneSeries() string {
	series := src.AllSeries()
	if len(series) != 1 {
		panic(fmt.Errorf("should have gotten tools for one series, got %v", series))
	}
	return series[0]
}

// Arches returns all architectures for which some tools in src were built.
func (src List) Arches() []string {
	return src.collect(func(tools *Tools) string {
		return tools.Version.Arch
	})
}

// collect calls f on all values in src and returns an alphabetically
// ordered list of the returned results without duplicates.
func (src List) collect(f func(*Tools) string) []string {
	seen := make(set.Strings)
	for _, tools := range src {
		seen.Add(f(tools))
	}
	return seen.SortedValues()
}

// URLs returns download URLs for the tools in src, keyed by binary version.
func (src List) URLs() map[version.Binary]string {
	result := map[version.Binary]string{}
	for _, tools := range src {
		result[tools.Version] = tools.URL
	}
	return result
}

// Newest returns the greatest version in src, and the tools with that version.
func (src List) Newest() (version.Number, List) {
	var result List
	var best version.Number
	for _, tools := range src {
		if best.Compare(tools.Version.Number) < 0 {
			// Found new best number; reset result list.
			best = tools.Version.Number
			result = append(result[:0], tools)
		} else if tools.Version.Number == best {
			result = append(result, tools)
		}
	}
	return best, result
}

// NewestCompatible returns the most recent version compatible with
// base, i.e. with the same major and minor numbers and greater or
// equal patch and build numbers.
func (src List) NewestCompatible(base version.Number) (newest version.Number, found bool) {
	newest = base
	found = false
	for _, tool := range src {
		toolVersion := tool.Version.Number
		if newest == toolVersion {
			found = true
		} else if newest.Compare(toolVersion) < 0 &&
			toolVersion.Major == newest.Major &&
			toolVersion.Minor == newest.Minor {
			newest = toolVersion
			found = true
		}
	}
	return newest, found
}

// Exclude returns the tools in src that are not in excluded.
func (src List) Exclude(excluded List) List {
	ignore := make(map[version.Binary]bool, len(excluded))
	for _, tool := range excluded {
		ignore[tool.Version] = true
	}
	var result List
	for _, tool := range src {
		if !ignore[tool.Version] {
			result = append(result, tool)
		}
	}
	return result
}

// Match returns a List, derived from src, containing only those tools that
// match the supplied Filter. If no tools match, it returns ErrNoMatches.
func (src List) Match(f Filter) (List, error) {
	var result List
	for _, tools := range src {
		if f.match(tools) {
			result = append(result, tools)
		}
	}
	if len(result) == 0 {
		return nil, ErrNoMatches
	}
	return result, nil
}

func (l List) Len() int           { return len(l) }
func (l List) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
func (l List) Less(i, j int) bool { return l[i].Version.String() < l[j].Version.String() }

// Filter holds criteria for choosing tools.
type Filter struct {
	// Number, if non-zero, causes the filter to match only tools with
	// that exact version number.
	Number version.Number

	// Series, if not empty, causes the filter to match only tools with
	// that series.
	Series string

	// Arch, if not empty, causes the filter to match only tools with
	// that architecture.
	Arch string
}

// match returns true if the supplied tools match f.
func (f Filter) match(tools *Tools) bool {
	if f.Number != version.Zero && tools.Version.Number != f.Number {
		return false
	}
	if f.Series != "" && tools.Version.Series != f.Series {
		return false
	}
	if f.Arch != "" && tools.Version.Arch != f.Arch {
		return false
	}
	return true
}
<commit_msg>Improved version checking<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package tools

import (
	"fmt"
	"strings"

	"github.com/juju/errors"
	"github.com/juju/utils/set"

	"github.com/juju/juju/version"
)

// List holds tools available in an environment. The order of tools within
// a List is not significant.
type List []*Tools

// ErrNoMatches represents a failure to find tools for the given query.
var ErrNoMatches = errors.New("no matching tools available")

// IsNoMatches return true if the passed error is ErrNoMatches.
func IsNoMatches(err error) bool {
	return ErrNoMatches.Error() == err.Error()
}

// String returns the versions of the tools in src, separated by semicolons.
func (src List) String() string {
	names := make([]string, len(src))
	for i, tools := range src {
		names[i] = tools.Version.String()
	}
	return strings.Join(names, ";")
}

// AllSeries returns all series for which some tools in src were built.
func (src List) AllSeries() []string {
	return src.collect(func(tools *Tools) string {
		return tools.Version.Series
	})
}

// OneSeries returns the single series for which all tools in src were built.
func (src List) OneSeries() string {
	series := src.AllSeries()
	if len(series) != 1 {
		panic(fmt.Errorf("should have gotten tools for one series, got %v", series))
	}
	return series[0]
}

// Arches returns all architectures for which some tools in src were built.
func (src List) Arches() []string {
	return src.collect(func(tools *Tools) string {
		return tools.Version.Arch
	})
}

// collect calls f on all values in src and returns an alphabetically
// ordered list of the returned results without duplicates.
func (src List) collect(f func(*Tools) string) []string {
	seen := make(set.Strings)
	for _, tools := range src {
		seen.Add(f(tools))
	}
	return seen.SortedValues()
}

// URLs returns download URLs for the tools in src, keyed by binary version.
func (src List) URLs() map[version.Binary]string {
	result := map[version.Binary]string{}
	for _, tools := range src {
		result[tools.Version] = tools.URL
	}
	return result
}

// Newest returns the greatest version in src, and the tools with that version.
func (src List) Newest() (version.Number, List) {
	var result List
	var best version.Number
	for _, tools := range src {
		if best.Compare(tools.Version.Number) < 0 {
			// Found new best number; reset result list.
			best = tools.Version.Number
			result = append(result[:0], tools)
		} else if tools.Version.Number == best {
			result = append(result, tools)
		}
	}
	return best, result
}

// NewestCompatible returns the most recent version compatible with
// base, i.e. with the same major and minor numbers and greater or
// equal patch and build numbers.
func (src List) NewestCompatible(base version.Number) (newest version.Number, found bool) {
	newest = base
	found = false
	for _, tool := range src {
		toolVersion := tool.Version.Number
		if newest == toolVersion {
			found = true
		} else if newest.Compare(toolVersion) < 0 &&
			toolVersion.Major == newest.Major &&
			toolVersion.Minor == newest.Minor {
			newest = toolVersion
			found = true
		}
	}
	return newest, found
}

// Exclude returns the tools in src that are not in excluded.
func (src List) Exclude(excluded List) List {
	ignore := make(map[version.Binary]bool, len(excluded))
	for _, tool := range excluded {
		ignore[tool.Version] = true
	}
	var result List
	for _, tool := range src {
		if !ignore[tool.Version] {
			result = append(result, tool)
		}
	}
	return result
}

// Match returns a List, derived from src, containing only those tools that
// match the supplied Filter. If no tools match, it returns ErrNoMatches.
func (src List) Match(f Filter) (List, error) {
	var result List
	for _, tools := range src {
		if f.match(tools) {
			result = append(result, tools)
		}
	}
	if len(result) == 0 {
		return nil, ErrNoMatches
	}
	return result, nil
}

func (l List) Len() int           { return len(l) }
func (l List) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
func (l List) Less(i, j int) bool { return l[i].Version.String() < l[j].Version.String() }

// Filter holds criteria for choosing tools.
type Filter struct {
	// Number, if non-zero, causes the filter to match only tools with
	// that exact version number.
	Number version.Number

	// Series, if not empty, causes the filter to match only tools with
	// that series.
	Series string

	// Arch, if not empty, causes the filter to match only tools with
	// that architecture.
	Arch string
}

// match returns true if the supplied tools match f.
func (f Filter) match(tools *Tools) bool {
	if f.Number != version.Zero && tools.Version.Number != f.Number {
		return false
	}
	if f.Series != "" && tools.Version.Series != f.Series {
		return false
	}
	if f.Arch != "" && tools.Version.Arch != f.Arch {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package watchmanager

import (
	"fmt"
	"runtime"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber-go/tally"
	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/integration"
	"golang.org/x/net/context"

	"github.com/m3db/m3/src/x/clock"
)

func TestWatchChan(t *testing.T) {
	wh, ecluster, _, _, _, closer := testCluster(t) //nolint:dogsled
	defer closer()

	ec := ecluster.RandClient()
	integration.WaitClientV3(t, ec)

	wc, _, err := wh.watchChanWithTimeout("foo", 0)
	require.NoError(t, err)
	require.Equal(t, 0, len(wc))

	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	select {
	case <-wc:
	case <-time.After(time.Second):
		require.Fail(t, "could not get notification")
	}

	ecluster.Members[0].Stop(t)

	before := time.Now()
	_, _, err = wh.watchChanWithTimeout("foo", 0)
	require.WithinDuration(t, time.Now(), before, 150*time.Millisecond)
	require.Error(t, err)
	require.NoError(t, ecluster.Members[0].Restart(t))
}

func TestWatchSimple(t *testing.T) {
	wh, ec, updateCalled, shouldStop, doneCh, closer := testSetup(t)
	defer closer()
	integration.WaitClientV3(t, ec)
	require.Equal(t, int32(0), atomic.LoadInt32(updateCalled))

	go wh.Watch("foo")

	time.Sleep(3 * wh.opts.WatchChanInitTimeout())

	lastRead := atomic.LoadInt32(updateCalled)
	_, err := ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for {
		if atomic.LoadInt32(updateCalled) >= lastRead+1 {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	lastRead = atomic.LoadInt32(updateCalled)
	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for {
		if atomic.LoadInt32(updateCalled) >= lastRead+1 {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	// trigger CheckAndStop
	atomic.AddInt32(shouldStop, 1)
	<-doneCh

	lastRead = atomic.LoadInt32(updateCalled)
	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)
	// put no longer triggers anything
	require.Equal(t, lastRead, atomic.LoadInt32(updateCalled))

	// sleep enough time and make sure nothing happens
	time.Sleep(3 * wh.opts.WatchChanCheckInterval())

	require.Equal(t, lastRead, atomic.LoadInt32(updateCalled))
}

func TestWatchRecreate(t *testing.T) {
	wh, ecluster, updateCalled, shouldStop, doneCh, closer := testCluster(t)
	defer closer()

	ec := ecluster.RandClient()
	integration.WaitClientV3(t, ec)

	failTotal := 1
	wh.opts = wh.opts.
		SetClient(ec).
		SetWatchChanInitTimeout(50 * time.Millisecond).
		SetWatchChanResetInterval(50 * time.Millisecond)

	go func() {
		ecluster.Members[0].DropConnections()
		ecluster.Members[0].Blackhole()
		wh.Watch("foo")
	}()

	time.Sleep(4 * wh.opts.WatchChanInitTimeout())

	// watch will error out but updateFn will be tried
	for i := 0; i < 100; i++ {
		if atomic.LoadInt32(updateCalled) >= int32(failTotal) {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	ecluster.Members[0].Unblackhole()
	// now we have retried failTotal times, give enough time for reset to happen
	time.Sleep(3 * (wh.opts.WatchChanResetInterval()))

	updatesBefore := atomic.LoadInt32(updateCalled)
	// there should be a valid watch now, trigger a notification
	_, err := ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for i := 0; i < 100; i++ {
		if atomic.LoadInt32(updateCalled) > updatesBefore {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	// clean up the background go routine
	atomic.AddInt32(shouldStop, 1)
	<-doneCh
}

func TestWatchNoLeader(t *testing.T) {
	const (
		watchInitAndRetryDelay = 200 * time.Millisecond
		watchCheckInterval     = 50 * time.Millisecond
	)

	ecluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer ecluster.Terminate(t)

	var (
		ec              = ecluster.Client(0)
		tickDuration    = 10 * time.Millisecond
		electionTimeout = time.Duration(3*ecluster.Members[0].ElectionTicks) * tickDuration
		doneCh          = make(chan struct{}, 1)
		eventLog        = []*clientv3.Event{}
		updateCalled    int32
		shouldStop      int32
	)

	opts := NewOptions().
		SetClient(ec).
		SetUpdateFn(
			func(_ string, e []*clientv3.Event) error {
				atomic.AddInt32(&updateCalled, 1)
				if len(e) > 0 {
					eventLog = append(eventLog, e...)
				}
				return nil
			},
		).
		SetTickAndStopFn(
			func(string) bool {
				if atomic.LoadInt32(&shouldStop) == 0 {
					return false
				}

				close(doneCh)

				return true
			},
		).
		SetWatchChanInitTimeout(watchInitAndRetryDelay).
		SetWatchChanResetInterval(watchInitAndRetryDelay).
		SetWatchChanCheckInterval(watchCheckInterval)

	integration.WaitClientV3(t, ec)

	wh, err := NewWatchManager(opts)
	require.NoError(t, err)

	go wh.Watch("foo")

	runtime.Gosched()
	time.Sleep(10 * time.Millisecond)

	// there should be a valid watch now, trigger a notification
	_, err = ec.Put(context.Background(), "foo", "bar")
	require.NoError(t, err)

	leaderIdx := ecluster.WaitLeader(t)
	require.True(t, leaderIdx >= 0 && leaderIdx < len(ecluster.Members), "got invalid leader")

	// simulate quorum loss
	ecluster.Members[1].Stop(t)
	ecluster.Members[2].Stop(t)

	// wait for election timeout, then member[0] will not have a leader.
	time.Sleep(electionTimeout)

	require.NoError(t, ecluster.Members[1].Restart(t))
	require.NoError(t, ecluster.Members[2].Restart(t))

	// wait for leader + election delay just in case
	time.Sleep(time.Duration(3*ecluster.Members[0].ElectionTicks) * tickDuration)

	leaderIdx = ecluster.WaitLeader(t)
	require.True(t, leaderIdx >= 0 && leaderIdx < len(ecluster.Members), "got invalid leader")
	integration.WaitClientV3(t, ec) // wait for client to be ready again

	_, err = ec.Put(context.Background(), "foo", "baz")
	require.NoError(t, err)

	// give some time for watch to be updated
	require.True(t, clock.WaitUntil(func() bool {
		return atomic.LoadInt32(&updateCalled) >= 2
	}, 10*time.Second))

	updates := atomic.LoadInt32(&updateCalled)
	if updates < 2 {
		require.Fail(t,
			"insufficient update calls",
			"expected at least 2 update attempts, got %d during a partition",
			updates)
	}

	atomic.AddInt32(&shouldStop, 1)
	<-doneCh

	require.Len(t, eventLog, 2)
	require.NotNil(t, eventLog[0])
	require.Equal(t, eventLog[0].Kv.Key, []byte("foo"))
	require.Equal(t, eventLog[0].Kv.Value, []byte("bar"))
	require.NotNil(t, eventLog[1])
	require.Equal(t, eventLog[1].Kv.Key, []byte("foo"))
	require.Equal(t, eventLog[1].Kv.Value, []byte("baz"))
}

func TestWatchCompactedRevision(t *testing.T) {
	wh, ec, updateCalled, shouldStop, doneCh, closer := testSetup(t)
	defer closer()

	integration.WaitClientV3(t, ec)

	ts := tally.NewTestScope("", nil)
	errC := ts.Counter("errors")
	wh.m.etcdWatchError = errC

	var compactRev int64
	for i := 1; i <= 10; i++ {
		resp, err := ec.Put(context.Background(), "foo", fmt.Sprintf("bar-%d", i))
		require.NoError(t, err)
		compactRev = resp.Header.Revision
	}

	_, err := ec.Compact(context.Background(), compactRev)
	require.NoError(t, err)

	wh.opts = wh.opts.SetWatchOptions([]clientv3.OpOption{
		clientv3.WithCreatedNotify(),
		clientv3.WithRev(1),
	})

	go wh.Watch("foo")

	require.True(t, clock.WaitUntil(func() bool {
		return atomic.LoadInt32(updateCalled) == 3
	}, 30*time.Second))

	lastRead := atomic.LoadInt32(updateCalled)
	ec.Put(context.Background(), "foo", "bar-11")

	for atomic.LoadInt32(updateCalled) <= lastRead {
		time.Sleep(10 * time.Millisecond)
	}

	errN := ts.Snapshot().Counters()["errors+"].Value()
	assert.Equal(t, int64(1), errN, "expected to encounter watch error")

	atomic.AddInt32(shouldStop, 1)
	<-doneCh
}

func testCluster(t *testing.T) (
	*manager,
	*integration.ClusterV3,
	*int32,
	*int32,
	chan struct{},
	func(),
) {
	ecluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})

	closer := func() {
		ecluster.Terminate(t)
	}

	var (
		updateCalled int32
		shouldStop   int32
	)
	doneCh := make(chan struct{}, 1)
	opts := NewOptions().
		SetClient(ecluster.RandClient()).
		SetUpdateFn(func(string, []*clientv3.Event) error {
			atomic.AddInt32(&updateCalled, 1)
			return nil
		}).
		SetTickAndStopFn(func(string) bool {
			if atomic.LoadInt32(&shouldStop) == 0 {
				return false
			}

			close(doneCh)

			return true
		}).
		SetWatchChanCheckInterval(100 * time.Millisecond).
		SetWatchChanInitTimeout(100 * time.Millisecond).
		SetWatchChanResetInterval(100 * time.Millisecond)

	wh, err := NewWatchManager(opts)
	require.NoError(t, err)

	return wh.(*manager), ecluster, &updateCalled, &shouldStop, doneCh, closer
}

func testSetup(t *testing.T) (*manager, *clientv3.Client, *int32, *int32, chan struct{}, func()) {
	wh, ecluster, updateCalled, shouldStop, donech, closer := testCluster(t)
	return wh, ecluster.RandClient(), updateCalled, shouldStop, donech, closer
}
<commit_msg>[tests] Skip flaky TestWatchNoLeader (#3106)<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package watchmanager

import (
	"fmt"
	"runtime"
	"sync/atomic"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/uber-go/tally"
	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/integration"
	"golang.org/x/net/context"

	"github.com/m3db/m3/src/x/clock"
)

func TestWatchChan(t *testing.T) {
	wh, ecluster, _, _, _, closer := testCluster(t) //nolint:dogsled
	defer closer()

	ec := ecluster.RandClient()
	integration.WaitClientV3(t, ec)

	wc, _, err := wh.watchChanWithTimeout("foo", 0)
	require.NoError(t, err)
	require.Equal(t, 0, len(wc))

	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	select {
	case <-wc:
	case <-time.After(time.Second):
		require.Fail(t, "could not get notification")
	}

	ecluster.Members[0].Stop(t)

	before := time.Now()
	_, _, err = wh.watchChanWithTimeout("foo", 0)
	require.WithinDuration(t, time.Now(), before, 150*time.Millisecond)
	require.Error(t, err)
	require.NoError(t, ecluster.Members[0].Restart(t))
}

func TestWatchSimple(t *testing.T) {
	wh, ec, updateCalled, shouldStop, doneCh, closer := testSetup(t)
	defer closer()
	integration.WaitClientV3(t, ec)
	require.Equal(t, int32(0), atomic.LoadInt32(updateCalled))

	go wh.Watch("foo")

	time.Sleep(3 * wh.opts.WatchChanInitTimeout())

	lastRead := atomic.LoadInt32(updateCalled)
	_, err := ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for {
		if atomic.LoadInt32(updateCalled) >= lastRead+1 {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	lastRead = atomic.LoadInt32(updateCalled)
	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for {
		if atomic.LoadInt32(updateCalled) >= lastRead+1 {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	// trigger CheckAndStop
	atomic.AddInt32(shouldStop, 1)
	<-doneCh

	lastRead = atomic.LoadInt32(updateCalled)
	_, err = ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)
	// put no longer triggers anything
	require.Equal(t, lastRead, atomic.LoadInt32(updateCalled))

	// sleep enough time and make sure nothing happens
	time.Sleep(3 * wh.opts.WatchChanCheckInterval())

	require.Equal(t, lastRead, atomic.LoadInt32(updateCalled))
}

func TestWatchRecreate(t *testing.T) {
	wh, ecluster, updateCalled, shouldStop, doneCh, closer := testCluster(t)
	defer closer()

	ec := ecluster.RandClient()
	integration.WaitClientV3(t, ec)

	failTotal := 1
	wh.opts = wh.opts.
		SetClient(ec).
		SetWatchChanInitTimeout(50 * time.Millisecond).
		SetWatchChanResetInterval(50 * time.Millisecond)

	go func() {
		ecluster.Members[0].DropConnections()
		ecluster.Members[0].Blackhole()
		wh.Watch("foo")
	}()

	time.Sleep(4 * wh.opts.WatchChanInitTimeout())

	// watch will error out but updateFn will be tried
	for i := 0; i < 100; i++ {
		if atomic.LoadInt32(updateCalled) >= int32(failTotal) {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	ecluster.Members[0].Unblackhole()
	// now we have retried failTotal times, give enough time for reset to happen
	time.Sleep(3 * (wh.opts.WatchChanResetInterval()))

	updatesBefore := atomic.LoadInt32(updateCalled)
	// there should be a valid watch now, trigger a notification
	_, err := ec.Put(context.Background(), "foo", "v")
	require.NoError(t, err)

	for i := 0; i < 100; i++ {
		if atomic.LoadInt32(updateCalled) > updatesBefore {
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	// clean up the background go routine
	atomic.AddInt32(shouldStop, 1)
	<-doneCh
}

func TestWatchNoLeader(t *testing.T) {
	t.Skip("flaky, started to fail very consistently on CI")
	const (
		watchInitAndRetryDelay = 200 * time.Millisecond
		watchCheckInterval     = 50 * time.Millisecond
	)

	ecluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 3})
	defer ecluster.Terminate(t)

	var (
		ec              = ecluster.Client(0)
		tickDuration    = 10 * time.Millisecond
		electionTimeout = time.Duration(3*ecluster.Members[0].ElectionTicks) * tickDuration
		doneCh          = make(chan struct{}, 1)
		eventLog        = []*clientv3.Event{}
		updateCalled    int32
		shouldStop      int32
	)

	opts := NewOptions().
		SetClient(ec).
		SetUpdateFn(
			func(_ string, e []*clientv3.Event) error {
				atomic.AddInt32(&updateCalled, 1)
				if len(e) > 0 {
					eventLog = append(eventLog, e...)
				}
				return nil
			},
		).
		SetTickAndStopFn(
			func(string) bool {
				if atomic.LoadInt32(&shouldStop) == 0 {
					return false
				}

				close(doneCh)

				return true
			},
		).
		SetWatchChanInitTimeout(watchInitAndRetryDelay).
		SetWatchChanResetInterval(watchInitAndRetryDelay).
		SetWatchChanCheckInterval(watchCheckInterval)

	integration.WaitClientV3(t, ec)

	wh, err := NewWatchManager(opts)
	require.NoError(t, err)

	go wh.Watch("foo")

	runtime.Gosched()
	time.Sleep(10 * time.Millisecond)

	// there should be a valid watch now, trigger a notification
	_, err = ec.Put(context.Background(), "foo", "bar")
	require.NoError(t, err)

	leaderIdx := ecluster.WaitLeader(t)
	require.True(t, leaderIdx >= 0 && leaderIdx < len(ecluster.Members), "got invalid leader")

	// simulate quorum loss
	ecluster.Members[1].Stop(t)
	ecluster.Members[2].Stop(t)

	// wait for election timeout, then member[0] will not have a leader.
	time.Sleep(electionTimeout)

	require.NoError(t, ecluster.Members[1].Restart(t))
	require.NoError(t, ecluster.Members[2].Restart(t))

	// wait for leader + election delay just in case
	time.Sleep(time.Duration(3*ecluster.Members[0].ElectionTicks) * tickDuration)

	leaderIdx = ecluster.WaitLeader(t)
	require.True(t, leaderIdx >= 0 && leaderIdx < len(ecluster.Members), "got invalid leader")
	integration.WaitClientV3(t, ec) // wait for client to be ready again

	_, err = ec.Put(context.Background(), "foo", "baz")
	require.NoError(t, err)

	// give some time for watch to be updated
	require.True(t, clock.WaitUntil(func() bool {
		return atomic.LoadInt32(&updateCalled) >= 2
	}, 10*time.Second))

	updates := atomic.LoadInt32(&updateCalled)
	if updates < 2 {
		require.Fail(t,
			"insufficient update calls",
			"expected at least 2 update attempts, got %d during a partition",
			updates)
	}

	atomic.AddInt32(&shouldStop, 1)
	<-doneCh

	require.Len(t, eventLog, 2)
	require.NotNil(t, eventLog[0])
	require.Equal(t, eventLog[0].Kv.Key, []byte("foo"))
	require.Equal(t, eventLog[0].Kv.Value, []byte("bar"))
	require.NotNil(t, eventLog[1])
	require.Equal(t, eventLog[1].Kv.Key, []byte("foo"))
	require.Equal(t, eventLog[1].Kv.Value, []byte("baz"))
}

func TestWatchCompactedRevision(t *testing.T) {
	wh, ec, updateCalled, shouldStop, doneCh, closer := testSetup(t)
	defer closer()

	integration.WaitClientV3(t, ec)

	ts := tally.NewTestScope("", nil)
	errC := ts.Counter("errors")
	wh.m.etcdWatchError = errC

	var compactRev int64
	for i := 1; i <= 10; i++ {
		resp, err := ec.Put(context.Background(), "foo", fmt.Sprintf("bar-%d", i))
		require.NoError(t, err)
		compactRev = resp.Header.Revision
	}

	_, err := ec.Compact(context.Background(), compactRev)
	require.NoError(t, err)

	wh.opts = wh.opts.SetWatchOptions([]clientv3.OpOption{
		clientv3.WithCreatedNotify(),
		clientv3.WithRev(1),
	})

	go wh.Watch("foo")

	require.True(t, clock.WaitUntil(func() bool {
		return atomic.LoadInt32(updateCalled) == 3
	}, 30*time.Second))

	lastRead := atomic.LoadInt32(updateCalled)
	ec.Put(context.Background(), "foo", "bar-11")

	for atomic.LoadInt32(updateCalled) <= lastRead {
		time.Sleep(10 * time.Millisecond)
	}

	errN := ts.Snapshot().Counters()["errors+"].Value()
	assert.Equal(t, int64(1), errN, "expected to encounter watch error")

	atomic.AddInt32(shouldStop, 1)
	<-doneCh
}

func testCluster(t *testing.T) (
	*manager,
	*integration.ClusterV3,
	*int32,
	*int32,
	chan struct{},
	func(),
) {
	ecluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})

	closer := func() {
		ecluster.Terminate(t)
	}

	var (
		updateCalled int32
		shouldStop   int32
	)
	doneCh := make(chan struct{}, 1)
	opts := NewOptions().
		SetClient(ecluster.RandClient()).
		SetUpdateFn(func(string, []*clientv3.Event) error {
			atomic.AddInt32(&updateCalled, 1)
			return nil
		}).
		SetTickAndStopFn(func(string) bool {
			if atomic.LoadInt32(&shouldStop) == 0 {
				return false
			}

			close(doneCh)

			return true
		}).
		SetWatchChanCheckInterval(100 * time.Millisecond).
		SetWatchChanInitTimeout(100 * time.Millisecond).
		SetWatchChanResetInterval(100 * time.Millisecond)

	wh, err := NewWatchManager(opts)
	require.NoError(t, err)

	return wh.(*manager), ecluster, &updateCalled, &shouldStop, doneCh, closer
}

func testSetup(t *testing.T) (*manager, *clientv3.Client, *int32, *int32, chan struct{}, func()) {
	wh, ecluster, updateCalled, shouldStop, donech, closer := testCluster(t)
	return wh, ecluster.RandClient(), updateCalled, shouldStop, donech, closer
}
<|endoftext|>


<commit_before>package i18n

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cloudfoundry/cli/cf/resources"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/nicksnyder/go-i18n/i18n/language"
)

const (
	defaultLocale  = "en-us"
	lang           = "LANG"
	lcAll          = "LC_ALL"
	resourceSuffix = ".all.json"
	zhTW           = "zh-tw"
	zhHK           = "zh-hk"
	zhHant         = "zh-hant"
	hyphen         = "-"
	underscore     = "_"
)

var T go_i18n.TranslateFunc

type LocalReader interface {
	Locale() string
}

func Init(config LocalReader) go_i18n.TranslateFunc {
	loadAsset("cf/i18n/resources/" + defaultLocale + resourceSuffix)
	defaultTfunc := go_i18n.MustTfunc(defaultLocale)

	assetNames := resources.AssetNames()

	sources := []string{
		config.Locale(),
		os.Getenv(lcAll),
		os.Getenv(lang),
	}

	for _, source := range sources {
		if source == "" {
			continue
		}

		for _, l := range language.Parse(source) {
			if l.Tag == zhTW || l.Tag == zhHK {
				l.Tag = zhHant
			}

			for _, assetName := range assetNames {
				assetLocale := strings.ToLower(strings.Replace(path.Base(assetName), underscore, hyphen, -1))
				if strings.HasPrefix(assetLocale, l.Tag) {
					loadAsset(assetName)

					t := go_i18n.MustTfunc(source)

					return func(translationID string, args ...interface{}) string {
						if translated := t(translationID, args...); translated != translationID {
							return translated
						}

						return defaultTfunc(translationID, args...)
					}
				}
			}
		}
	}

	return defaultTfunc
}

func loadAsset(assetName string) {
	assetBytes, err := resources.Asset(assetName)
	if err != nil {
		panic(fmt.Sprintf("Could not load asset '%s': %s", assetName, err.Error()))
	}

	err = go_i18n.ParseTranslationFileBytes(assetName, assetBytes)
	if err != nil {
		panic(fmt.Sprintf("Could not load translations '%s': %s", assetName, err.Error()))
	}
}
<commit_msg>Handle language codes zh-TW and zh-HK<commit_after>package i18n

import (
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/cloudfoundry/cli/cf/resources"
	go_i18n "github.com/nicksnyder/go-i18n/i18n"
	"github.com/nicksnyder/go-i18n/i18n/language"
)

const (
	defaultLocale  = "en-us"
	lang           = "LANG"
	lcAll          = "LC_ALL"
	resourceSuffix = ".all.json"
	zhTW           = "zh-tw"
	zhHK           = "zh-hk"
	zhHant         = "zh-hant"
	hyphen         = "-"
	underscore     = "_"
)

var T go_i18n.TranslateFunc

type LocalReader interface {
	Locale() string
}

func Init(config LocalReader) go_i18n.TranslateFunc {
	loadAsset("cf/i18n/resources/" + defaultLocale + resourceSuffix)
	defaultTfunc := go_i18n.MustTfunc(defaultLocale)

	assetNames := resources.AssetNames()

	sources := []string{
		config.Locale(),
		os.Getenv(lcAll),
		os.Getenv(lang),
	}

	for _, source := range sources {
		if source == "" {
			continue
		}

		for _, l := range language.Parse(source) {
			if l.Tag == zhTW || l.Tag == zhHK {
				l.Tag = zhHant
			}

			for _, assetName := range assetNames {
				assetLocale := strings.ToLower(strings.Replace(path.Base(assetName), underscore, hyphen, -1))
				if strings.HasPrefix(assetLocale, l.Tag) {
					loadAsset(assetName)

					t := go_i18n.MustTfunc(l.Tag)

					return func(translationID string, args ...interface{}) string {
						if translated := t(translationID, args...); translated != translationID {
							return translated
						}

						return defaultTfunc(translationID, args...)
					}
				}
			}
		}
	}

	return defaultTfunc
}

func loadAsset(assetName string) {
	assetBytes, err := resources.Asset(assetName)
	if err != nil {
		panic(fmt.Sprintf("Could not load asset '%s': %s", assetName, err.Error()))
	}

	err = go_i18n.ParseTranslationFileBytes(assetName, assetBytes)
	if err != nil {
		panic(fmt.Sprintf("Could not load translations '%s': %s", assetName, err.Error()))
	}
}
<|endoftext|>


<commit_before>package main

import "strings"
import "strconv"
import "fmt"
import "errors"
import "net"
import "net/http"
import "net/url"
import "time"
import "html"
import "log"
import "io"
import "bufio"
import "bytes"
import "flag"
import "encoding/xml"
import "golang.org/x/tools/blog/atom"

// Maximum size a request for a bug-xml is read in byte.
var maxBugRequestRead int64

// Maximum number of requests per second. Set to something negative to disable
var maxRequestsPerSecond int

// Channel to block on during too many requests in a second
var tooManyRequestsBlocker chan bool = make(chan bool)

const versionMajor = 0
const versionMinor = 1
const versionBugfix = 0
const versionGit = true

const bugzillaDateFormat = "2006-01-02 15:04:05 -0700"
const userAgentName = "bugzillatoatom"

// returns the minimum of the given values
func min(a int, b int) int {
    if a <= b {
        return a
    } else {
        return b
    }
}

func getVersion() string {
    if versionGit {
        return strconv.Itoa(versionMajor) + "." + strconv.Itoa(versionMinor) + "." + strconv.Itoa(versionBugfix) + "-git"
    } else {
        return strconv.Itoa(versionMajor) + "." + strconv.Itoa(versionMinor) + "." + strconv.Itoa(versionBugfix)
    }
}

// Read from r until given string is found. Appends toAppend afterwards if string
// is found and in any case returns the result
func readUntilString(r io.Reader, until string, toAppend string) (string, error) {
    var buffer bytes.Buffer
    eofReached := false
    rs := bufio.NewReader(io.LimitReader(r, maxBugRequestRead))

    for !eofReached {
        str, err := rs.ReadString('\n')

        if err == io.EOF {
            eofReached = true
        } else if err != nil {
            log.Printf("Error during reading from url: %s\n", err)
            return "", err
        }

        index := strings.Index(str, until)

        if index == -1 {
            buffer.WriteString(str)
        } else {
            buffer.WriteString(str[:index])
            buffer.WriteString(toAppend)
            break
        }
    }

    return buffer.String(), nil
}

// Requests the bug from given url
func doRequest(target *url.URL) (string, error) {
    request := http.Request{
        Method: http.MethodGet,
        URL: target,
        Header: http.Header{
            "User-Agent": { userAgentName + "/" + getVersion() },
        },
    }

    resp, err := http.DefaultClient.Do(&request)

    if err != nil {
        log.Printf("Error during GET to url \"%s\": %s\n", target, err)
        return "", err
    }

    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        errStr := fmt.Sprintf("Request returned status code %d (%s).", resp.StatusCode, http.StatusText(resp.StatusCode))
        return "", errors.New(errStr)
    }

    // TODO: maybe we should search for something more clever to abort. <attachment could be given by a user in a report
    return readUntilString(resp.Body, "<attachment", "</bug></bugzilla>")
}

// converts the given xml string into an atom feed
func convertXmlToAtom(inXml string) (string, error) {
    type Who struct {
        Name string `xml:",chardata"`
        RealName string `xml:"name,attr"`
    }

    getFormatedName := func(w Who) string {
        if w.RealName == "" {
            return w.Name
        } else {
            return w.RealName + " (" + w.Name + ")"
        }
    }

    type Comment struct {
        CommentId int `xml:"commentid"`
        CommentCount int `xml:"comment_count"`
        AttachmentID int `xml:"attachid"`
        Who Who `xml:"who"`
        When string `xml:"bug_when"`
        Text string `xml:"thetext"`
    }

    type InResult struct {
        Urlbase string `xml:"urlbase,attr"`
        BugId int `xml:"bug>bug_id"`
        Description string `xml:"bug>short_desc"`
        Comments []Comment `xml:"bug>long_desc"`
    }

    inResult := InResult{}
    err := xml.Unmarshal([]byte(inXml), &inResult)
    if err != nil {
        log.Printf("Error during unmarshalling the xml: %s\n", err)
        return "", err
    } else if len(inResult.Comments) == 0 {
        // One comment, the initial one, should always be available
        err := errors.New("Zero comments in bug. There should be at least the initial one.")
        log.Printf("Error after unmarshalling the xml: %s\n", err)
        return "", err
    }

    updateTime, err := time.Parse(bugzillaDateFormat, inResult.Comments[len(inResult.Comments)-1].When)
    if err != nil {
        log.Printf("Couldn't parse updateTime in initial comment: %s\n", err)
        return "", err
    }

    inUrl := fmt.Sprintf("%s/show_bug.cgi?id=%d", inResult.Urlbase, inResult.BugId)
    attachmentUrl := fmt.Sprintf("%s/attachment.cgi?id=", inResult.Urlbase)

    feed := &atom.Feed{
        Title: inResult.Description,
        ID: inUrl,
        Link: []atom.Link{atom.Link{Href: inUrl, Rel: "alternate"}},
        Updated: atom.Time(updateTime),
        Author: &atom.Person{Name: getFormatedName(inResult.Comments[0].Who)},
        Entry: make([]*atom.Entry, 0, len(inResult.Comments)),
    }

    for i, comment := range inResult.Comments {
        creationTime, err := time.Parse(bugzillaDateFormat, comment.When)
        if err != nil {
            log.Printf("Couldn't parse updateTime in comment %d: %s\n", i, err)
            return "", err
        }

        links := []atom.Link{atom.Link{Href: inUrl + "#c" + strconv.Itoa(comment.CommentCount), Rel: "alternate"}}
        if comment.AttachmentID != 0 {
            links = append(links, atom.Link{Href: attachmentUrl + strconv.Itoa(comment.AttachmentID), Rel: "enclosure"})
        }

        entry := &atom.Entry{
            Title: getFormatedName(comment.Who) + ": " + comment.Text[:min(100, len(comment.Text))],
            ID: inUrl + "#c" + strconv.Itoa(comment.CommentCount),
            Link: links,
            Published: atom.Time(creationTime),
            Author: &atom.Person{Name: getFormatedName(comment.Who)},
            Content: &atom.Text{Type: "html", Body: strings.Replace(html.EscapeString(comment.Text), "\n", "
", -1)},
        }

        feed.Entry = append(feed.Entry, entry)
    }

    atom, err := xml.MarshalIndent(feed, "", "\t")
    if err != nil {
        log.Printf("Error during creating the atom feed: %s\n", err)
        return "", err
    }

    return xml.Header + string(atom), nil
}

// Filters not allowed targets, defined by the given networks
// TODO: Technically an attack is possible. First return a harmless IP
//       for the check and another one later for the actual request.
func checkTargetAllowed(target string, forbiddenNetworks []*net.IPNet) (bool, error) {
    if forbiddenNetworks == nil {
        return true, nil
    }

    ips, err := net.LookupIP(target)

    if err != nil {
        return false, err
    }

    for _, ip := range ips {
        for _, ipnet := range forbiddenNetworks {
            if ipnet.Contains(ip) {
                return false, nil
            }
        }
    }

    return true, nil
}

func handleConvert(w http.ResponseWriter, r *http.Request, forbiddenNetworks []*net.IPNet) {
    // Block during too many requests in the last second
    if maxRequestsPerSecond >= 0 {
        <-tooManyRequestsBlocker
    }

    // Check for a possible recursive call
    if r.Header != nil {
        for _, agent := range r.Header["User-Agent"] {
            if strings.Contains(agent, userAgentName) {
                errStr := fmt.Sprintf("User-Agent \"%s\" blocked.", r.Header["User-Agent"])
                http.Error(w, errStr, http.StatusForbidden)
                return
            }
        }
    }

    formValueUrl := r.FormValue("url")

    // if the user didn't give a protocol simply assume http
    if !(strings.HasPrefix(formValueUrl, "http://") || strings.HasPrefix(formValueUrl, "https://")) {
        formValueUrl = "http://" + formValueUrl
    }

    target, err := url.Parse(formValueUrl)

    if err != nil {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": %s\nAre you sure the url is correct?", r.FormValue("url"), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    parsedQuery := target.Query()
    parsedQuery.Set("ctype", "xml")
    target.RawQuery = parsedQuery.Encode()
    target.Fragment = ""

    portPosition := strings.Index(target.Host, ":")
    var hostWithoutPort string
    if portPosition >= 0 {
        hostWithoutPort = target.Host[:portPosition]
    } else {
        hostWithoutPort = target.Host
    }

    if hostWithoutPort == "" {
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": No host recognized.\nAre you sure the url is correct?", formValueUrl)
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    allowed, err := checkTargetAllowed(hostWithoutPort, forbiddenNetworks)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during checking whether the host \"%s\" is blocked: %s.\nAre you sure the url is correct?", hostWithoutPort, err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    if !allowed {
        errStr := fmt.Sprintf("Host \"%s\" of url \"%s\" is blocked.", hostWithoutPort, formValueUrl)
        http.Error(w, errStr, http.StatusForbidden)
        return
    }

    inXml, err := doRequest(target)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during fetching the url \"%s\": %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    atom, err := convertXmlToAtom(inXml)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during conversion of the url \"%s\" to atom: %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "%s", atom)
}

func handleMain(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", `

<title>bugzillatoatom</title>

<form action=convert>
    Convert a Bugzilla bug entry into an Atom feed. Enter an url:
    <input type="text" name="url">

`)
}

// Parses a given IP or CIDR into a CIDR. IPs are treated as CIDRs with full bitmask
func parseIPOrCIDR(str string) (*net.IPNet, error) {

    if !strings.Contains(str, "/") {
        if strings.Contains(str, ":") {
            str = str + "/128"
        } else {
            str = str + "/32"
        }
    }

    _, ipnet, err := net.ParseCIDR(str)
    return ipnet, err
}

// To allow forbiddenNetworks to be parsed as argument
type CIDRList []*net.IPNet

func (forbiddenNetworks *CIDRList) String() string {
    strs := []string{}

    for _, ipnet := range *forbiddenNetworks {
        strs = append(strs, ipnet.String())
    }

    return strings.Join(strs, ", ")
}

func (forbiddenNetworks *CIDRList) Set(value string) error {
    ipnet, err := parseIPOrCIDR(value)

    if err == nil {
        *forbiddenNetworks = append(*forbiddenNetworks, ipnet)
    }

    return err
}

func main() {
    version := flag.Bool("version", false, "Print the current version and exit")
    port := flag.Uint64("p", 9080, "Port to bind to")
    maxBugRequestReadFlag := flag.Uint64("requestsize", 1 * 1024 * 1024, "Maximum number of bytes to read during a request to another server.") // 1MiB per default
    flag.IntVar(&maxRequestsPerSecond, "persecond", 5, "Maximum number of requests to another server per second. Set to -1 to disable.")
    forbiddenNetworks := CIDRList{}
    flag.Var(&forbiddenNetworks, "b", "IP or Network in CIDR format to block. If a host is available under any blocked IP it will be blocked. Can be given multiple times.\n\tYou probably want to exclude localhost or local networks both on IPv4 and IPv6.")
    flag.Parse()

    if *version {
        log.Fatalln(getVersion())
    }

    if *maxBugRequestReadFlag & (1 << 63) != 0 {
        log.Fatalln("Too large requestsize")
    } else {
        maxBugRequestRead = int64(*maxBugRequestReadFlag)
    }

    // Add a timeout for the default http.Get() in case something goes wrong
    // on the oher side.
    http.DefaultClient = &http.Client{Timeout: time.Second * 30}

    for i := 0; i < maxRequestsPerSecond; i++ {
        go func() {
            for {
                tooManyRequestsBlocker <- true
                time.Sleep(time.Second)
            }
        }()
    }

    http.HandleFunc("/convert", func(w http.ResponseWriter, r *http.Request) { handleConvert(w, r, forbiddenNetworks) })
    http.HandleFunc("/", handleMain)

    log.Fatal(http.ListenAndServe(":" + strconv.FormatUint(*port, 10), nil))
}<commit_msg>Added more logging<commit_after>package main

import "strings"
import "strconv"
import "fmt"
import "errors"
import "net"
import "net/http"
import "net/url"
import "time"
import "html"
import "log"
import "io"
import "bufio"
import "bytes"
import "flag"
import "encoding/xml"
import "golang.org/x/tools/blog/atom"

// Maximum size a request for a bug-xml is read in byte.
var maxBugRequestRead int64

// Maximum number of requests per second. Set to something negative to disable
var maxRequestsPerSecond int

// Channel to block on during too many requests in a second
var tooManyRequestsBlocker chan bool = make(chan bool)

const versionMajor = 0
const versionMinor = 1
const versionBugfix = 0
const versionGit = true

const bugzillaDateFormat = "2006-01-02 15:04:05 -0700"
const userAgentName = "bugzillatoatom"

// returns the minimum of the given values
func min(a int, b int) int {
    if a <= b {
        return a
    } else {
        return b
    }
}

func getVersion() string {
    if versionGit {
        return strconv.Itoa(versionMajor) + "." + strconv.Itoa(versionMinor) + "." + strconv.Itoa(versionBugfix) + "-git"
    } else {
        return strconv.Itoa(versionMajor) + "." + strconv.Itoa(versionMinor) + "." + strconv.Itoa(versionBugfix)
    }
}

// Read from r until given string is found. Appends toAppend afterwards if string
// is found and in any case returns the result
func readUntilString(r io.Reader, until string, toAppend string) (string, error) {
    var buffer bytes.Buffer
    eofReached := false
    rs := bufio.NewReader(io.LimitReader(r, maxBugRequestRead))

    for !eofReached {
        str, err := rs.ReadString('\n')

        if err == io.EOF {
            eofReached = true
        } else if err != nil {
            log.Printf("Error during reading from url: %s\n", err)
            return "", err
        }

        index := strings.Index(str, until)

        if index == -1 {
            buffer.WriteString(str)
        } else {
            buffer.WriteString(str[:index])
            buffer.WriteString(toAppend)
            break
        }
    }

    return buffer.String(), nil
}

// Requests the bug from given url
func doRequest(target *url.URL) (string, error) {
    request := http.Request{
        Method: http.MethodGet,
        URL: target,
        Header: http.Header{
            "User-Agent": { userAgentName + "/" + getVersion() },
        },
    }

    resp, err := http.DefaultClient.Do(&request)

    if err != nil {
        log.Printf("Error during GET to url \"%s\": %s\n", target, err)
        return "", err
    }

    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        log.Printf("Request to \"%s\" returned status code %d (%s).\n", target, resp.StatusCode, http.StatusText(resp.StatusCode))
        errStr := fmt.Sprintf("Request returned status code %d (%s).", resp.StatusCode, http.StatusText(resp.StatusCode))
        return "", errors.New(errStr)
    }

    // TODO: maybe we should search for something more clever to abort. <attachment could be given by a user in a report
    return readUntilString(resp.Body, "<attachment", "</bug></bugzilla>")
}

// converts the given xml string into an atom feed
func convertXmlToAtom(inXml string) (string, error) {
    type Who struct {
        Name string `xml:",chardata"`
        RealName string `xml:"name,attr"`
    }

    getFormatedName := func(w Who) string {
        if w.RealName == "" {
            return w.Name
        } else {
            return w.RealName + " (" + w.Name + ")"
        }
    }

    type Comment struct {
        CommentId int `xml:"commentid"`
        CommentCount int `xml:"comment_count"`
        AttachmentID int `xml:"attachid"`
        Who Who `xml:"who"`
        When string `xml:"bug_when"`
        Text string `xml:"thetext"`
    }

    type InResult struct {
        Urlbase string `xml:"urlbase,attr"`
        BugId int `xml:"bug>bug_id"`
        Description string `xml:"bug>short_desc"`
        Comments []Comment `xml:"bug>long_desc"`
    }

    inResult := InResult{}
    err := xml.Unmarshal([]byte(inXml), &inResult)
    if err != nil {
        log.Printf("Error during unmarshalling the xml: %s\n", err)
        return "", err
    } else if len(inResult.Comments) == 0 {
        // One comment, the initial one, should always be available
        err := errors.New("Zero comments in bug. There should be at least the initial one.")
        log.Println("Zero comments in bug. There should be at least the initial one.")
        return "", err
    }

    updateTime, err := time.Parse(bugzillaDateFormat, inResult.Comments[len(inResult.Comments)-1].When)
    if err != nil {
        log.Printf("Couldn't parse updateTime in initial comment: %s\n", err)
        return "", err
    }

    inUrl := fmt.Sprintf("%s/show_bug.cgi?id=%d", inResult.Urlbase, inResult.BugId)
    attachmentUrl := fmt.Sprintf("%s/attachment.cgi?id=", inResult.Urlbase)

    feed := &atom.Feed{
        Title: inResult.Description,
        ID: inUrl,
        Link: []atom.Link{atom.Link{Href: inUrl, Rel: "alternate"}},
        Updated: atom.Time(updateTime),
        Author: &atom.Person{Name: getFormatedName(inResult.Comments[0].Who)},
        Entry: make([]*atom.Entry, 0, len(inResult.Comments)),
    }

    for i, comment := range inResult.Comments {
        creationTime, err := time.Parse(bugzillaDateFormat, comment.When)
        if err != nil {
            log.Printf("Couldn't parse updateTime in comment %d: %s\n", i, err)
            return "", err
        }

        links := []atom.Link{atom.Link{Href: inUrl + "#c" + strconv.Itoa(comment.CommentCount), Rel: "alternate"}}
        if comment.AttachmentID != 0 {
            links = append(links, atom.Link{Href: attachmentUrl + strconv.Itoa(comment.AttachmentID), Rel: "enclosure"})
        }

        entry := &atom.Entry{
            Title: getFormatedName(comment.Who) + ": " + comment.Text[:min(100, len(comment.Text))],
            ID: inUrl + "#c" + strconv.Itoa(comment.CommentCount),
            Link: links,
            Published: atom.Time(creationTime),
            Author: &atom.Person{Name: getFormatedName(comment.Who)},
            Content: &atom.Text{Type: "html", Body: strings.Replace(html.EscapeString(comment.Text), "\n", "
", -1)},
        }

        feed.Entry = append(feed.Entry, entry)
    }

    atom, err := xml.MarshalIndent(feed, "", "\t")
    if err != nil {
        log.Printf("Error during creating the atom feed: %s\n", err)
        return "", err
    }

    return xml.Header + string(atom), nil
}

// Filters not allowed targets, defined by the given networks
// TODO: Technically an attack is possible. First return a harmless IP
//       for the check and another one later for the actual request.
func checkTargetAllowed(target string, forbiddenNetworks []*net.IPNet) (bool, error) {
    if forbiddenNetworks == nil {
        return true, nil
    }

    ips, err := net.LookupIP(target)

    if err != nil {
        return false, err
    }

    for _, ip := range ips {
        for _, ipnet := range forbiddenNetworks {
            if ipnet.Contains(ip) {
                log.Printf("Blocked target \"%s\" since it's IP %s is contained in blocked network %s.\n", target, ip, ipnet)
                return false, nil
            }
        }
    }

    return true, nil
}

func handleConvert(w http.ResponseWriter, r *http.Request, forbiddenNetworks []*net.IPNet) {
    // Block during too many requests in the last second
    if maxRequestsPerSecond >= 0 {
        <-tooManyRequestsBlocker
    }

    // Check for a possible recursive call
    if r.Header != nil {
        for _, agent := range r.Header["User-Agent"] {
            if strings.Contains(agent, userAgentName) {
                log.Printf("Blocked request by %s due tue User-Agent \"%s\".\n", r.RemoteAddr, agent)
                errStr := fmt.Sprintf("User-Agent \"%s\" blocked.", r.Header["User-Agent"])
                http.Error(w, errStr, http.StatusForbidden)
                return
            }
        }
    }

    formValueUrl := r.FormValue("url")

    // if the user didn't give a protocol simply assume http
    if !(strings.HasPrefix(formValueUrl, "http://") || strings.HasPrefix(formValueUrl, "https://")) {
        formValueUrl = "http://" + formValueUrl
    }

    target, err := url.Parse(formValueUrl)

    if err != nil {
        log.Printf("Error occurred during parsing the url \"%s\": %s.\n", r.FormValue("url"), err.Error())
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": %s\nAre you sure the url is correct?", r.FormValue("url"), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    parsedQuery := target.Query()
    parsedQuery.Set("ctype", "xml")
    target.RawQuery = parsedQuery.Encode()
    target.Fragment = ""

    portPosition := strings.Index(target.Host, ":")
    var hostWithoutPort string
    if portPosition >= 0 {
        hostWithoutPort = target.Host[:portPosition]
    } else {
        hostWithoutPort = target.Host
    }

    if hostWithoutPort == "" {
        log.Printf("Error occurred during parsing the url \"%s\": No host recognized.\n", formValueUrl)
        errStr := fmt.Sprintf("Error occurred during parsing the url \"%s\": No host recognized.\nAre you sure the url is correct?", formValueUrl)
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    allowed, err := checkTargetAllowed(hostWithoutPort, forbiddenNetworks)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during checking whether the host \"%s\" is blocked: %s.\nAre you sure the url is correct?", hostWithoutPort, err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    if !allowed {
        errStr := fmt.Sprintf("Host \"%s\" of url \"%s\" is blocked.", hostWithoutPort, formValueUrl)
        http.Error(w, errStr, http.StatusForbidden)
        return
    }

    inXml, err := doRequest(target)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during fetching the url \"%s\": %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    atom, err := convertXmlToAtom(inXml)
    if err != nil {
        errStr := fmt.Sprintf("Error occurred during conversion of the url \"%s\" to atom: %s\nAre you sure the url is correct?", target.String(), err.Error())
        http.Error(w, errStr, http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "%s", atom)
}

func handleMain(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "%s", `

<title>bugzillatoatom</title>

<form action=convert>
    Convert a Bugzilla bug entry into an Atom feed. Enter an url:
    <input type="text" name="url">

`)
}

// Parses a given IP or CIDR into a CIDR. IPs are treated as CIDRs with full bitmask
func parseIPOrCIDR(str string) (*net.IPNet, error) {

    if !strings.Contains(str, "/") {
        if strings.Contains(str, ":") {
            str = str + "/128"
        } else {
            str = str + "/32"
        }
    }

    _, ipnet, err := net.ParseCIDR(str)
    return ipnet, err
}

// To allow forbiddenNetworks to be parsed as argument
type CIDRList []*net.IPNet

func (forbiddenNetworks *CIDRList) String() string {
    strs := []string{}

    for _, ipnet := range *forbiddenNetworks {
        strs = append(strs, ipnet.String())
    }

    return strings.Join(strs, ", ")
}

func (forbiddenNetworks *CIDRList) Set(value string) error {
    ipnet, err := parseIPOrCIDR(value)

    if err == nil {
        *forbiddenNetworks = append(*forbiddenNetworks, ipnet)
    }

    return err
}

func main() {
    version := flag.Bool("version", false, "Print the current version and exit")
    port := flag.Uint64("p", 9080, "Port to bind to")
    maxBugRequestReadFlag := flag.Uint64("requestsize", 1 * 1024 * 1024, "Maximum number of bytes to read during a request to another server.") // 1MiB per default
    flag.IntVar(&maxRequestsPerSecond, "persecond", 5, "Maximum number of requests to another server per second. Set to -1 to disable.")
    forbiddenNetworks := CIDRList{}
    flag.Var(&forbiddenNetworks, "b", "IP or Network in CIDR format to block. If a host is available under any blocked IP it will be blocked. Can be given multiple times.\n\tYou probably want to exclude localhost or local networks both on IPv4 and IPv6.")
    flag.Parse()

    if *version {
        log.Fatalln(getVersion())
    }

    if *maxBugRequestReadFlag & (1 << 63) != 0 {
        log.Fatalln("Too large requestsize")
    } else {
        maxBugRequestRead = int64(*maxBugRequestReadFlag)
    }

    // Add a timeout for the default http.Get() in case something goes wrong
    // on the oher side.
    http.DefaultClient = &http.Client{Timeout: time.Second * 30}

    for i := 0; i < maxRequestsPerSecond; i++ {
        go func() {
            for {
                tooManyRequestsBlocker <- true
                time.Sleep(time.Second)
            }
        }()
    }

    http.HandleFunc("/convert", func(w http.ResponseWriter, r *http.Request) { handleConvert(w, r, forbiddenNetworks) })
    http.HandleFunc("/", handleMain)

    log.Fatal(http.ListenAndServe(":" + strconv.FormatUint(*port, 10), nil))
}<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

package main

import (
	"errors"
	"fmt"
	"strconv"

	"openblockchain/ccs"
	"openblockchain/cci/project"
	"openblockchain/cci/com/obc/chaincode/example02"

	"github.com/golang/protobuf/proto"
	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

type ChaincodeExample struct {
}

// Called to initialize the chaincode
func (t *ChaincodeExample) Init(stub *shim.ChaincodeStub, param *project.Init) error {

	var err error

	fmt.Printf("Aval = %d, Bval = %d\n", param.PartyA.Value, param.PartyB.Value)

	// Write the state to the ledger
	err = t.PutState(stub, param.PartyA)
	if err != nil {
		return err
	}

	err = t.PutState(stub, param.PartyB)
	if err != nil {
		return err
	}

	return nil
}

// Transaction makes payment of X units from A to B
func (t *ChaincodeExample) MakePayment(stub *shim.ChaincodeStub, param *example02.PaymentParams) error {

	var err error

	// Get the state from the ledger
	src, err := t.GetState(stub, param.PartySrc)
	if err != nil {
		return err
	}

	dst, err := t.GetState(stub, param.PartyDst)
	if err != nil {
		return err
	}

	// Perform the execution
	X := int(param.Amount)
	src = src - X
	dst = dst + X
	fmt.Printf("Aval = %d, Bval = %d\n", src, dst)

	// Write the state back to the ledger
	err = stub.PutState(param.PartySrc, []byte(strconv.Itoa(src)))
	if err != nil {
		return err
	}

	err = stub.PutState(param.PartyDst, []byte(strconv.Itoa(dst)))
	if err != nil {
		return err
	}

	return nil
}

// Deletes an entity from state
func (t *ChaincodeExample) DeleteAccount(stub *shim.ChaincodeStub, param *example02.Entity) error {

	// Delete the key from the state in ledger
	err := stub.DelState(param.Id)
	if err != nil {
		return errors.New("Failed to delete state")
	}

	return nil
}

// Query callback representing the query of a chaincode
func (t *ChaincodeExample) CheckBalance(stub *shim.ChaincodeStub, param *example02.Entity) (*example02.BalanceResult, error) {
	var err error

	// Get the state from the ledger
	val, err := t.GetState(stub, param.Id)
	if err != nil {
		return nil, err
	}

	fmt.Printf("Query Response: %d\n", val)
	return &example02.BalanceResult{Balance: proto.Int32(int32(val))}, nil
}

func main() {
	self := &ChaincodeExample{}
	handler := ccs.ShimHandler{Project: self, Example02: self}
	err := ccs.Start(handler) // Our one instance implements both Transactions and Queries interfaces
	if err != nil {
		fmt.Printf("Error starting example chaincode: %s", err)
	}
}

//-------------------------------------------------
// Helpers
//-------------------------------------------------
func (t *ChaincodeExample) PutState(stub *shim.ChaincodeStub, party *project.Party) error {
	return stub.PutState(party.Entity, []byte(strconv.Itoa(int(party.Value))))
}

func (t *ChaincodeExample) GetState(stub *shim.ChaincodeStub, entity string) (int, error) {
	bytes, err := stub.GetState(entity)
	if err != nil {
		return 0, errors.New("Failed to get state")
	}
	if bytes == nil {
		return 0, errors.New("Entity not found")
	}

	val, _ := strconv.Atoi(string(bytes))
	return val, nil
}
<commit_msg>Fix compile errors in example02 chaincode:     CheckBalance - need int(32) not a pointer     main - ccs.Start needs a pointer to the ShimHandler<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

package main

import (
	"errors"
	"fmt"
	"strconv"

	"openblockchain/ccs"
	"openblockchain/cci/project"
	"openblockchain/cci/com/obc/chaincode/example02"

	"github.com/golang/protobuf/proto"
	"github.com/openblockchain/obc-peer/openchain/chaincode/shim"
)

type ChaincodeExample struct {
}

// Called to initialize the chaincode
func (t *ChaincodeExample) Init(stub *shim.ChaincodeStub, param *project.Init) error {

	var err error

	fmt.Printf("Aval = %d, Bval = %d\n", param.PartyA.Value, param.PartyB.Value)

	// Write the state to the ledger
	err = t.PutState(stub, param.PartyA)
	if err != nil {
		return err
	}

	err = t.PutState(stub, param.PartyB)
	if err != nil {
		return err
	}

	return nil
}

// Transaction makes payment of X units from A to B
func (t *ChaincodeExample) MakePayment(stub *shim.ChaincodeStub, param *example02.PaymentParams) error {

	var err error

	// Get the state from the ledger
	src, err := t.GetState(stub, param.PartySrc)
	if err != nil {
		return err
	}

	dst, err := t.GetState(stub, param.PartyDst)
	if err != nil {
		return err
	}

	// Perform the execution
	X := int(param.Amount)
	src = src - X
	dst = dst + X
	fmt.Printf("Aval = %d, Bval = %d\n", src, dst)

	// Write the state back to the ledger
	err = stub.PutState(param.PartySrc, []byte(strconv.Itoa(src)))
	if err != nil {
		return err
	}

	err = stub.PutState(param.PartyDst, []byte(strconv.Itoa(dst)))
	if err != nil {
		return err
	}

	return nil
}

// Deletes an entity from state
func (t *ChaincodeExample) DeleteAccount(stub *shim.ChaincodeStub, param *example02.Entity) error {

	// Delete the key from the state in ledger
	err := stub.DelState(param.Id)
	if err != nil {
		return errors.New("Failed to delete state")
	}

	return nil
}

// Query callback representing the query of a chaincode
func (t *ChaincodeExample) CheckBalance(stub *shim.ChaincodeStub, param *example02.Entity) (*example02.BalanceResult, error) {
	var err error

	// Get the state from the ledger
	val, err := t.GetState(stub, param.Id)
	if err != nil {
		return nil, err
	}

	fmt.Printf("Query Response: %d\n", val)
	return &example02.BalanceResult{Balance: *proto.Int32(int32(val))}, nil
}

func main() {
	self := &ChaincodeExample{}
	handler := ccs.ShimHandler{Project: self, Example02: self}
	err := ccs.Start(&handler) // Our one instance implements both Transactions and Queries interfaces
	if err != nil {
		fmt.Printf("Error starting example chaincode: %s", err)
	}
}

//-------------------------------------------------
// Helpers
//-------------------------------------------------
func (t *ChaincodeExample) PutState(stub *shim.ChaincodeStub, party *project.Party) error {
	return stub.PutState(party.Entity, []byte(strconv.Itoa(int(party.Value))))
}

func (t *ChaincodeExample) GetState(stub *shim.ChaincodeStub, entity string) (int, error) {
	bytes, err := stub.GetState(entity)
	if err != nil {
		return 0, errors.New("Failed to get state")
	}
	if bytes == nil {
		return 0, errors.New("Entity not found")
	}

	val, _ := strconv.Atoi(string(bytes))
	return val, nil
}
<|endoftext|>


<commit_before>package main

import (
    "bytes"
    "crypto/md5"
    "fmt"
    "github.com/hoisie/web.go"
)

func Md5(b []byte) string {
    hash := md5.New()
    hash.Write(b)
    return fmt.Sprintf("%x", hash.Sum())

}

var page = `

<title>Multipart Test</title>

<form action="/multipart" enctype="multipart/form-data" method="POST">

 Please select a File
<input id="file" type="file" name="file"/>

 Please write some text
<input id="input1" type="text" name="input1"/>

 Please write some more text
<input id="input2" type="text" name="input2"/>

<input type="submit" name="Submit" value="Submit"/>

`

func index() string { return page }

func multipart(ctx *web.Context) string {
    var output bytes.Buffer
    output.WriteString("
input1: " + ctx.Params["input1"] + "
")
    output.WriteString("
input2: " + ctx.Params["input2"] + "
")
    output.WriteString("
file: " + ctx.Files["file"].Filename + " " + Md5(ctx.Files["file"].Data) + "
")
    return output.String()
}

func main() {
    web.Get("/", index)
    web.Post("/multipart", multipart)
    web.Run("0.0.0.0:9999")
}
<commit_msg>Fix multipart.go example<commit_after>package main

import (
    "bytes"
    "crypto/md5"
    "fmt"
    "github.com/hoisie/web"
    "io"
)

func Md5(r io.Reader) string {
    hash := md5.New()
    io.Copy(hash, r)
    return fmt.Sprintf("%x", hash.Sum(nil))
}

var page = `

<title>Multipart Test</title>

<form action="/multipart" enctype="multipart/form-data" method="POST">

 Please select a File
<input id="file" type="file" name="file"/>

 Please write some text
<input id="input1" type="text" name="input1"/>

 Please write some more text
<input id="input2" type="text" name="input2"/>

<input type="submit" name="Submit" value="Submit"/>
</form>

`

func index() string { return page }

func multipart(ctx *web.Context) string {
    ctx.Request.ParseMultipartForm(10 * 1024 * 1024)
    form := ctx.Request.MultipartForm
    var output bytes.Buffer
    output.WriteString("
input1: " + form.Value["input1"][0] + "
")
    output.WriteString("
input2: " + form.Value["input2"][0] + "
")

    fileHeader := form.File["file"][0]
    filename := fileHeader.Filename
    file, err := fileHeader.Open()
    if err != nil {
        return err.Error()
    }

    output.WriteString("
file: " + filename + " " + Md5(file) + "
")
    return output.String()
}

func main() {
    web.Get("/", index)
    web.Post("/multipart", multipart)
    web.Run("0.0.0.0:9999")
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"text/template"
	"time"

	"github.com/gorilla/mux"
	"github.com/weaveworks/mesh"

	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

var allConnectionStates = []string{"established", "pending", "retrying", "failed", "connecting"}

var rootTemplate = template.New("root").Funcs(map[string]interface{}{
	"countDNSEntries": countDNSEntries,
	"printList": func(list []string) string {
		if len(list) == 0 {
			return "none"
		}
		return strings.Join(list, ", ")
	},
	"printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string {
		var buffer bytes.Buffer

		type stats struct {
			ips       uint32
			nickname  string
			reachable bool
		}

		peerStats := make(map[string]*stats)

		for _, entry := range status.Entries {
			s, found := peerStats[entry.Peer]
			if !found {
				s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
				peerStats[entry.Peer] = s
			}
			s.ips += entry.Size
		}

		printOwned := func(name string, nickName string, info string, ips uint32) {
			percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs)

			displayName := name + "(" + nickName + ")"
			fmt.Fprintf(&buffer, "%-37v %8d IPs (%04.1f%% of total) %s\n",
				displayName, ips, percentageRanges, info)
		}

		// print the local info first
		if ourStats := peerStats[router.Name]; ourStats != nil {
			activeStr := fmt.Sprintf("(%d active)", status.ActiveIPs)
			printOwned(router.Name, ourStats.nickname, activeStr, ourStats.ips)
		}

		// and then the rest
		for peer, stats := range peerStats {
			if peer != router.Name {
				reachableStr := ""
				if !stats.reachable {
					reachableStr = "- unreachable!"
				}
				printOwned(peer, stats.nickname, reachableStr, stats.ips)
			}
		}

		return buffer.String()
	},
	"allIPAMOwnersUnreachable": func(status ipam.Status) bool {
		for _, entry := range status.Entries {
			if entry.Size > 0 && entry.IsKnownPeer {
				return false
			}
		}
		return true
	},
	"printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string {
		counts := make(map[string]int)
		for _, conn := range conns {
			counts[conn.State]++
		}
		return printCounts(counts, allConnectionStates)
	},
	"printPeerConnectionCounts": func(peers []mesh.PeerStatus) string {
		counts := make(map[string]int)
		for _, peer := range peers {
			for _, conn := range peer.Connections {
				if conn.Established {
					counts["established"]++
				} else {
					counts["pending"]++
				}
			}
		}
		return printCounts(counts, []string{"established", "pending"})
	},
	"printState": func(enabled bool) string {
		if enabled {
			return "enabled"
		}
		return "disabled"
	},
	"trimSuffix": strings.TrimSuffix,
})

func countDNSEntries(entries []nameserver.EntryStatus) int {
	count := 0
	for _, entry := range entries {
		if entry.Tombstone == 0 {
			count++
		}
	}
	return count
}

func countDNSEntriesForPeer(peername string, entries []nameserver.EntryStatus) int {
	count := 0
	for _, entry := range entries {
		if entry.Tombstone == 0 && entry.Origin == peername {
			count++
		}
	}
	return count
}

// Print counts in a specified order
func printCounts(counts map[string]int, keys []string) string {
	var stringCounts []string
	for _, key := range keys {
		if count, ok := counts[key]; ok {
			stringCounts = append(stringCounts, fmt.Sprintf("%d %s", count, key))
		}
	}
	return strings.Join(stringCounts, ", ")
}

// Strip escaped newlines from template
func escape(template string) string {
	return strings.Replace(template, "\\\n", "", -1)
}

// Define a named template panicking on error
func defTemplate(name string, text string) *template.Template {
	return template.Must(rootTemplate.New(name).Parse(escape(text)))
}

var statusTemplate = defTemplate("status", `\
        Version: {{.Version}} ({{.VersionCheck}})

        Service: router
       Protocol: {{.Router.Protocol}} \
{{if eq .Router.ProtocolMinVersion .Router.ProtocolMaxVersion}}\
{{.Router.ProtocolMaxVersion}}\
{{else}}\
{{.Router.ProtocolMinVersion}}..{{.Router.ProtocolMaxVersion}}\
{{end}}
           Name: {{.Router.Name}}({{.Router.NickName}})
     Encryption: {{printState .Router.Encryption}}
  PeerDiscovery: {{printState .Router.PeerDiscovery}}
        Targets: {{len .Router.Targets}}
    Connections: {{len .Router.Connections}}{{with printConnectionCounts .Router.Connections}} ({{.}}){{end}}
          Peers: {{len .Router.Peers}}{{with printPeerConnectionCounts .Router.Peers}} (with {{.}} connections){{end}}
 TrustedSubnets: {{printList .Router.TrustedSubnets}}
{{if .IPAM}}\

        Service: ipam
{{if .IPAM.Entries}}\
{{if allIPAMOwnersUnreachable .IPAM}}\
         Status: all IP ranges owned by unreachable peers - use 'rmpeer' if they are dead
{{else if len .IPAM.PendingAllocates}}\
         Status: waiting for IP range grant from peers
{{else}}\
         Status: ready
{{end}}\
{{else if .IPAM.Paxos}}\
{{if .IPAM.Paxos.Elector}}\
         Status: awaiting consensus (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}})
{{else}}\
         Status: priming
{{end}}\
{{else}}\
         Status: idle
{{end}}\
          Range: {{.IPAM.Range}}
  DefaultSubnet: {{.IPAM.DefaultSubnet}}
{{end}}\
{{if .DNS}}\

        Service: dns
         Domain: {{.DNS.Domain}}
       Upstream: {{printList .DNS.Upstream}}
            TTL: {{.DNS.TTL}}
        Entries: {{countDNSEntries .DNS.Entries}}
{{end}}\
`)

var targetsTemplate = defTemplate("targetsTemplate", `\
{{range .Router.Targets}}{{.}}
{{end}}\
`)

var connectionsTemplate = defTemplate("connectionsTemplate", `\
{{range .Router.Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}} {{range $key,$element := .Attrs}}{{if ne $key "name"}}{{$key}}={{$element}}{{end}}{{end}}
{{end}}\
`)

var peersTemplate = defTemplate("peers", `\
{{range .Router.Peers}}\
{{.Name}}({{.NickName}})
{{range .Connections}}\
   {{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \
{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-37v" $nameNickName}} \
{{if .Established}}established{{else}}pending{{end}}
{{end}}\
{{end}}\
`)

var dnsEntriesTemplate = defTemplate("dnsEntries", `\
{{$domain := printf ".%v" .DNS.Domain}}\
{{range .DNS.Entries}}\
{{if eq .Tombstone 0}}\
{{$hostname := trimSuffix .Hostname $domain}}\
{{printf "%-12v" $hostname}} {{printf "%-15v" .Address}} {{printf "%12.12v" .ContainerID}} {{.Origin}}
{{end}}\
{{end}}\
`)

var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`)

type VersionCheck struct {
	Enabled     bool
	Success     bool
	NewVersion  string
	NextCheckAt time.Time
}

func versionCheck() *VersionCheck {
	v := &VersionCheck{}
	if checkpoint.IsCheckDisabled() {
		return v
	}

	v.Enabled = true
	v.Success = success.Load().(bool)
	v.NewVersion = newVersion.Load().(string)
	v.NextCheckAt = checker.NextCheckAt()

	return v
}

func (v *VersionCheck) String() string {
	switch {
	case !v.Enabled:
		return "version check update disabled"
	case !v.Success:
		return fmt.Sprintf("failed to check latest version - see logs; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
	case v.NewVersion != "":
		return fmt.Sprintf("version %s available - please upgrade!", v.NewVersion)
	default:
		return fmt.Sprintf("up to date; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
	}
}

type WeaveStatus struct {
	Version      string
	VersionCheck *VersionCheck              `json:"VersionCheck,omitempty"`
	Router       *weave.NetworkRouterStatus `json:"Router,omitempty"`
	IPAM         *ipam.Status               `json:"IPAM,omitempty"`
	DNS          *nameserver.Status         `json:"DNS,omitempty"`
}

// Read-only functions, suitable for exposing on an unprotected socket
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
	status := func() WeaveStatus {
		return WeaveStatus{
			version,
			versionCheck(),
			weave.NewNetworkRouterStatus(router),
			ipam.NewStatus(allocator, defaultSubnet),
			nameserver.NewStatus(ns, dnsserver)}
	}
	muxRouter.Methods("GET").Path("/report").Headers("Accept", "application/json").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			json, err := json.MarshalIndent(status(), "", "    ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				Log.Error("Error during report marshalling: ", err)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(json)
		})

	muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			funcs := template.FuncMap{
				"json": func(v interface{}) string {
					a, _ := json.Marshal(v)
					return string(a)
				},
			}
			formatTemplate, err := template.New("format").Funcs(funcs).Parse(mux.Vars(r)["format"])
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if err := formatTemplate.Execute(w, status()); err != nil {
				http.Error(w, "error during template execution", http.StatusInternalServerError)
				Log.Error(err)
			}
		})

	defHandler := func(path string, template *template.Template) {
		muxRouter.Methods("GET").Path(path).HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				if err := template.Execute(w, status()); err != nil {
					http.Error(w, "error during template execution", http.StatusInternalServerError)
					Log.Error(err)
				}
			})
	}

	defHandler("/status", statusTemplate)
	defHandler("/status/targets", targetsTemplate)
	defHandler("/status/connections", connectionsTemplate)
	defHandler("/status/peers", peersTemplate)
	defHandler("/status/dns", dnsEntriesTemplate)
	defHandler("/status/ipam", ipamTemplate)
}
<commit_msg>Fix message when IPAM has pending allocations<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"text/template"
	"time"

	"github.com/gorilla/mux"
	"github.com/weaveworks/mesh"

	"github.com/weaveworks/go-checkpoint"
	"github.com/weaveworks/weave/ipam"
	"github.com/weaveworks/weave/nameserver"
	"github.com/weaveworks/weave/net/address"
	weave "github.com/weaveworks/weave/router"
)

var allConnectionStates = []string{"established", "pending", "retrying", "failed", "connecting"}

var rootTemplate = template.New("root").Funcs(map[string]interface{}{
	"countDNSEntries": countDNSEntries,
	"printList": func(list []string) string {
		if len(list) == 0 {
			return "none"
		}
		return strings.Join(list, ", ")
	},
	"printIPAMRanges": func(router weave.NetworkRouterStatus, status ipam.Status) string {
		var buffer bytes.Buffer

		type stats struct {
			ips       uint32
			nickname  string
			reachable bool
		}

		peerStats := make(map[string]*stats)

		for _, entry := range status.Entries {
			s, found := peerStats[entry.Peer]
			if !found {
				s = &stats{nickname: entry.Nickname, reachable: entry.IsKnownPeer}
				peerStats[entry.Peer] = s
			}
			s.ips += entry.Size
		}

		printOwned := func(name string, nickName string, info string, ips uint32) {
			percentageRanges := float32(ips) * 100.0 / float32(status.RangeNumIPs)

			displayName := name + "(" + nickName + ")"
			fmt.Fprintf(&buffer, "%-37v %8d IPs (%04.1f%% of total) %s\n",
				displayName, ips, percentageRanges, info)
		}

		// print the local info first
		if ourStats := peerStats[router.Name]; ourStats != nil {
			activeStr := fmt.Sprintf("(%d active)", status.ActiveIPs)
			printOwned(router.Name, ourStats.nickname, activeStr, ourStats.ips)
		}

		// and then the rest
		for peer, stats := range peerStats {
			if peer != router.Name {
				reachableStr := ""
				if !stats.reachable {
					reachableStr = "- unreachable!"
				}
				printOwned(peer, stats.nickname, reachableStr, stats.ips)
			}
		}

		return buffer.String()
	},
	"allIPAMOwnersUnreachable": func(status ipam.Status) bool {
		for _, entry := range status.Entries {
			if entry.Size > 0 && entry.IsKnownPeer {
				return false
			}
		}
		return true
	},
	"printConnectionCounts": func(conns []mesh.LocalConnectionStatus) string {
		counts := make(map[string]int)
		for _, conn := range conns {
			counts[conn.State]++
		}
		return printCounts(counts, allConnectionStates)
	},
	"printPeerConnectionCounts": func(peers []mesh.PeerStatus) string {
		counts := make(map[string]int)
		for _, peer := range peers {
			for _, conn := range peer.Connections {
				if conn.Established {
					counts["established"]++
				} else {
					counts["pending"]++
				}
			}
		}
		return printCounts(counts, []string{"established", "pending"})
	},
	"printState": func(enabled bool) string {
		if enabled {
			return "enabled"
		}
		return "disabled"
	},
	"trimSuffix": strings.TrimSuffix,
})

func countDNSEntries(entries []nameserver.EntryStatus) int {
	count := 0
	for _, entry := range entries {
		if entry.Tombstone == 0 {
			count++
		}
	}
	return count
}

func countDNSEntriesForPeer(peername string, entries []nameserver.EntryStatus) int {
	count := 0
	for _, entry := range entries {
		if entry.Tombstone == 0 && entry.Origin == peername {
			count++
		}
	}
	return count
}

// Print counts in a specified order
func printCounts(counts map[string]int, keys []string) string {
	var stringCounts []string
	for _, key := range keys {
		if count, ok := counts[key]; ok {
			stringCounts = append(stringCounts, fmt.Sprintf("%d %s", count, key))
		}
	}
	return strings.Join(stringCounts, ", ")
}

// Strip escaped newlines from template
func escape(template string) string {
	return strings.Replace(template, "\\\n", "", -1)
}

// Define a named template panicking on error
func defTemplate(name string, text string) *template.Template {
	return template.Must(rootTemplate.New(name).Parse(escape(text)))
}

var statusTemplate = defTemplate("status", `\
        Version: {{.Version}} ({{.VersionCheck}})

        Service: router
       Protocol: {{.Router.Protocol}} \
{{if eq .Router.ProtocolMinVersion .Router.ProtocolMaxVersion}}\
{{.Router.ProtocolMaxVersion}}\
{{else}}\
{{.Router.ProtocolMinVersion}}..{{.Router.ProtocolMaxVersion}}\
{{end}}
           Name: {{.Router.Name}}({{.Router.NickName}})
     Encryption: {{printState .Router.Encryption}}
  PeerDiscovery: {{printState .Router.PeerDiscovery}}
        Targets: {{len .Router.Targets}}
    Connections: {{len .Router.Connections}}{{with printConnectionCounts .Router.Connections}} ({{.}}){{end}}
          Peers: {{len .Router.Peers}}{{with printPeerConnectionCounts .Router.Peers}} (with {{.}} connections){{end}}
 TrustedSubnets: {{printList .Router.TrustedSubnets}}
{{if .IPAM}}\

        Service: ipam
{{if .IPAM.Entries}}\
{{if allIPAMOwnersUnreachable .IPAM}}\
         Status: all IP ranges owned by unreachable peers - use 'rmpeer' if they are dead
{{else if len .IPAM.PendingAllocates}}\
         Status: waiting for IP(s) to become available
{{else}}\
         Status: ready
{{end}}\
{{else if .IPAM.Paxos}}\
{{if .IPAM.Paxos.Elector}}\
         Status: awaiting consensus (quorum: {{.IPAM.Paxos.Quorum}}, known: {{.IPAM.Paxos.KnownNodes}})
{{else}}\
         Status: priming
{{end}}\
{{else}}\
         Status: idle
{{end}}\
          Range: {{.IPAM.Range}}
  DefaultSubnet: {{.IPAM.DefaultSubnet}}
{{end}}\
{{if .DNS}}\

        Service: dns
         Domain: {{.DNS.Domain}}
       Upstream: {{printList .DNS.Upstream}}
            TTL: {{.DNS.TTL}}
        Entries: {{countDNSEntries .DNS.Entries}}
{{end}}\
`)

var targetsTemplate = defTemplate("targetsTemplate", `\
{{range .Router.Targets}}{{.}}
{{end}}\
`)

var connectionsTemplate = defTemplate("connectionsTemplate", `\
{{range .Router.Connections}}\
{{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} {{printf "%-11v" .State}} {{.Info}} {{range $key,$element := .Attrs}}{{if ne $key "name"}}{{$key}}={{$element}}{{end}}{{end}}
{{end}}\
`)

var peersTemplate = defTemplate("peers", `\
{{range .Router.Peers}}\
{{.Name}}({{.NickName}})
{{range .Connections}}\
   {{if .Outbound}}->{{else}}<-{{end}} {{printf "%-21v" .Address}} \
{{$nameNickName := printf "%v(%v)" .Name .NickName}}{{printf "%-37v" $nameNickName}} \
{{if .Established}}established{{else}}pending{{end}}
{{end}}\
{{end}}\
`)

var dnsEntriesTemplate = defTemplate("dnsEntries", `\
{{$domain := printf ".%v" .DNS.Domain}}\
{{range .DNS.Entries}}\
{{if eq .Tombstone 0}}\
{{$hostname := trimSuffix .Hostname $domain}}\
{{printf "%-12v" $hostname}} {{printf "%-15v" .Address}} {{printf "%12.12v" .ContainerID}} {{.Origin}}
{{end}}\
{{end}}\
`)

var ipamTemplate = defTemplate("ipamTemplate", `{{printIPAMRanges .Router .IPAM}}`)

type VersionCheck struct {
	Enabled     bool
	Success     bool
	NewVersion  string
	NextCheckAt time.Time
}

func versionCheck() *VersionCheck {
	v := &VersionCheck{}
	if checkpoint.IsCheckDisabled() {
		return v
	}

	v.Enabled = true
	v.Success = success.Load().(bool)
	v.NewVersion = newVersion.Load().(string)
	v.NextCheckAt = checker.NextCheckAt()

	return v
}

func (v *VersionCheck) String() string {
	switch {
	case !v.Enabled:
		return "version check update disabled"
	case !v.Success:
		return fmt.Sprintf("failed to check latest version - see logs; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
	case v.NewVersion != "":
		return fmt.Sprintf("version %s available - please upgrade!", v.NewVersion)
	default:
		return fmt.Sprintf("up to date; next check at %s", v.NextCheckAt.Format("2006/01/02 15:04:05"))
	}
}

type WeaveStatus struct {
	Version      string
	VersionCheck *VersionCheck              `json:"VersionCheck,omitempty"`
	Router       *weave.NetworkRouterStatus `json:"Router,omitempty"`
	IPAM         *ipam.Status               `json:"IPAM,omitempty"`
	DNS          *nameserver.Status         `json:"DNS,omitempty"`
}

// Read-only functions, suitable for exposing on an unprotected socket
func HandleHTTP(muxRouter *mux.Router, version string, router *weave.NetworkRouter, allocator *ipam.Allocator, defaultSubnet address.CIDR, ns *nameserver.Nameserver, dnsserver *nameserver.DNSServer) {
	status := func() WeaveStatus {
		return WeaveStatus{
			version,
			versionCheck(),
			weave.NewNetworkRouterStatus(router),
			ipam.NewStatus(allocator, defaultSubnet),
			nameserver.NewStatus(ns, dnsserver)}
	}
	muxRouter.Methods("GET").Path("/report").Headers("Accept", "application/json").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			json, err := json.MarshalIndent(status(), "", "    ")
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				Log.Error("Error during report marshalling: ", err)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(json)
		})

	muxRouter.Methods("GET").Path("/report").Queries("format", "{format}").HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			funcs := template.FuncMap{
				"json": func(v interface{}) string {
					a, _ := json.Marshal(v)
					return string(a)
				},
			}
			formatTemplate, err := template.New("format").Funcs(funcs).Parse(mux.Vars(r)["format"])
			if err != nil {
				http.Error(w, err.Error(), http.StatusBadRequest)
				return
			}
			if err := formatTemplate.Execute(w, status()); err != nil {
				http.Error(w, "error during template execution", http.StatusInternalServerError)
				Log.Error(err)
			}
		})

	defHandler := func(path string, template *template.Template) {
		muxRouter.Methods("GET").Path(path).HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				if err := template.Execute(w, status()); err != nil {
					http.Error(w, "error during template execution", http.StatusInternalServerError)
					Log.Error(err)
				}
			})
	}

	defHandler("/status", statusTemplate)
	defHandler("/status/targets", targetsTemplate)
	defHandler("/status/connections", connectionsTemplate)
	defHandler("/status/peers", peersTemplate)
	defHandler("/status/dns", dnsEntriesTemplate)
	defHandler("/status/ipam", ipamTemplate)
}
<|endoftext|>


<commit_before>package main

/*
 * A libjit wrapper for Golang
 *
 * Copyright (c) 2013-2014 Chanwit Kaewkasi
 * Suranaree University of Technology
 *
 */
import "fmt"
import . "github.com/chanwit/jit"

/*
extern int NativeMult(int a,int b);
*/
import "C"

//export NativeMult
func NativeMult(a, b C.int) C.int {
	fmt.Println(">>>>Test")
	return a * b
}

func main() {

	// Create a context to hold the JIT's primary state
	// defer to Destroy the context at the end of func main()
	ctx := NewContext()
	defer ctx.Destroy()

	// Lock the context while we build and compile the function
	ctx.BuildStart()

	// Create the function object
	// void foo(int x, int y, int* result) {
	//   *result = NativeMult(x, y);
	// }
	f := ctx.NewFunction(Void(), []Type{Int(), Int(), VoidPtr()})

	// Construct the function body
	x, y, result := f.Param3()

    // This is native call
	sig := NewSignature(Int(), []Type{Int(), Int()})
	res := f.CallNative("NativeMult", C.NativeMult, sig, x, y)
	f.Store(x, res)
	f.StoreRelative(result, 0, x)

	// Compile the function
	f.Compile()

	// Dump the result to standard output
	f.Dump("foo")

	// Unlock the context
	ctx.BuildEnd()

	// Execute the function
	var r int = 0
	f.Run(3, 5, &r)
	fmt.Println(r)
}
<commit_msg>gofmt<commit_after>package main

/*
 * A libjit wrapper for Golang
 *
 * Copyright (c) 2013-2014 Chanwit Kaewkasi
 * Suranaree University of Technology
 *
 */
import "fmt"
import . "github.com/chanwit/jit"

/*
extern int NativeMult(int a,int b);
*/
import "C"

//export NativeMult
func NativeMult(a, b C.int) C.int {
	fmt.Println(">>>>Test")
	return a * b
}

func main() {

	// Create a context to hold the JIT's primary state
	// defer to Destroy the context at the end of func main()
	ctx := NewContext()
	defer ctx.Destroy()

	// Lock the context while we build and compile the function
	ctx.BuildStart()

	// Create the function object
	// void foo(int x, int y, int* result) {
	//   *result = NativeMult(x, y);
	// }
	f := ctx.NewFunction(Void(), []Type{Int(), Int(), VoidPtr()})

	// Construct the function body
	x, y, result := f.Param3()

	// This is native call
	sig := NewSignature(Int(), []Type{Int(), Int()})
	res := f.CallNative("NativeMult", C.NativeMult, sig, x, y)
	f.Store(x, res)
	f.StoreRelative(result, 0, x)

	// Compile the function
	f.Compile()

	// Dump the result to standard output
	f.Dump("foo")

	// Unlock the context
	ctx.BuildEnd()

	// Execute the function
	var r int = 0
	f.Run(3, 5, &r)
	fmt.Println(r)
}
<|endoftext|>