<commit_before>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.1.60"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<commit_msg>functions: 0.1.61 release [skip ci]<commit_after>package server

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

// Version of IronFunctions
var Version = "0.1.61"

func handleVersion(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{"version": Version})
}
<|endoftext|>


<commit_before>package flow

import (
	"fmt"

	"go/types"

	"github.com/dustin/go-humanize"
)

func cardinalityMismatchError(source, dest ComponentID, sourceSig, destSig *types.Tuple) error {
	return fmt.Errorf(`
As I infer the types of values flowing through your program, I see a mismatch in this connection.

	%[1]s -> %[2]s

There are %[3]d results coming from %[1]s:

	%[4]s

But %[2]s is expecting %[5]d argument[s]:

	%[6]s

HINT: These should have identical length and types.
`, source, dest, sourceSig.Len(), sourceSig, destSig.Len(), destSig)
}

func typeMismatchError(source, dest ComponentID, argIndex int, sourceType, endType types.Type) error {
	return fmt.Errorf(`
As I infer the types of values flowing through your program, I see a mismatch in this connection.

	%[1]s -> %[2]s

The %[3]s result of %[1]s has type:

	%[4]s

But the %[3]s argument of %[2]s has type:

	%[5]s

HINT: These should have identical types.
`, source, dest, humanize.Ordinal(argIndex), sourceType, endType)
}
<commit_msg>Improve error message for type mismatch.<commit_after>package flow

import (
	"fmt"

	"go/types"

	"github.com/dustin/go-humanize"
)

func cardinalityMismatchError(source, dest ComponentID, sourceSig, destSig *types.Tuple) error {
	return fmt.Errorf(`
As I infer the types of values flowing through your program, I see a mismatch in this connection.

	%[1]s -> %[2]s

There are %[3]d results coming from %[1]s:

	%[4]s

But %[2]s is expecting %[5]d argument[s]:

	%[6]s

HINT: These should have identical length and types.
`, source, dest, sourceSig.Len(), sourceSig, destSig.Len(), destSig)
}

func typeMismatchError(source, dest ComponentID, argIndex int, sourceType, endType types.Type) error {
	return fmt.Errorf(`
As I infer the types of values flowing through your program, I see a mismatch in this connection.

	%[1]s -> %[2]s

The %[3]s result of %[1]s has type:

	%[4]s

But the %[3]s argument of %[2]s has type:

	%[5]s

HINT: These should have identical types.
`, source, dest, humanize.Ordinal(argIndex+1), sourceType, endType)
}
<|endoftext|>


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

package suite

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"strings"
	"testing"

	"github.com/vdobler/ht/scope"
)

func logger() *log.Logger {
	if testing.Verbose() {
		return log.New(os.Stdout, "", 0)
	}

	return log.New(ioutil.Discard, "", 0)
}

// Variables in outer scopes dominate those in inner scopes.
func TestVariableDominance(t *testing.T) {
	txt := `
# dominace.suite
{
    Name: Testsuite to check variable dominance
    Variables: {
        C:  suite
        D:  suite
    }
    Main: [
        { File: "dominance.ht"
          Variables: {
              B: call
              C: call
              D: call
          }
        }
    ]
}

# dominance.ht
{
    Name: Test of variable dominance
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        A: local
        B: local
        C: local
        D: local
    }
}`

	globals := map[string]string{"D": "global"}

	rs, err := parseRawSuite("dominace.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	if s.Tests[0].Variables["A"] != "local" ||
		s.Tests[0].Variables["B"] != "call" ||
		s.Tests[0].Variables["C"] != "suite" ||
		s.Tests[0].Variables["D"] != "global" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable dominance. Got %v", s.Tests[0].Variables)
	}
}

// Variables are handed down from scope to scope. Replacement works.
func TestVariableHanddown(t *testing.T) {
	txt := `
# handdown.suite
{
    Name: Testsuite to check variable handdown
    Variables: {
        C:  "test-c",
        D:  "{{E}}"
    }
    Main: [
        { File: "handdown.ht"
          Variables: {
              A: "call-a"
              B: "{{C}}",
          }
        }
    ]
}

# handdown.ht
{
    Name: Test of variable handdown
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        Va: "{{A}}"
        Vb: "{{B}}"
    }
}`

	globals := map[string]string{"E": "global-e"}

	rs, err := parseRawSuite("handdown.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	if s.Tests[0].Variables["A"] != "call-a" ||
		s.Tests[0].Variables["B"] != "test-c" ||
		s.Tests[0].Variables["C"] != "test-c" ||
		s.Tests[0].Variables["D"] != "global-e" ||
		s.Tests[0].Variables["E"] != "global-e" ||
		s.Tests[0].Variables["Va"] != "call-a" ||
		s.Tests[0].Variables["Vb"] != "test-c" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable handdown. Got %v", s.Tests[0].Variables)
	}
}

// The automatic variables COUNTER and RANDOM are injected into global
// and call scope so that call- and test-scope have just one value of COUNTER
// and RANDOM.
func TestAutomaticVariables(t *testing.T) {
	scope.Random.Seed(1234)
	lastCnt := <-scope.GetCounter // next value from GetCounter is lastCnt+1
	scope.ResetCounter <- 1
	lastCnt = 0

	txt := `
# automatic.suite
{
    Name: Testsuite for automatic variables
    Variables: {
        SuiteCount:  "{{COUNTER}}",
        SuiteRand:  "{{RANDOM}}"
    }
    Main: [
        { File: "test.ht"
          Variables: {
              CallCount: "{{COUNTER}}"
              CallRand: "{{RANDOM}}",
          }
        },
        { File: "test.ht"
          Variables: {
              CallCount: "{{COUNTER}}"
              CallRand: "{{RANDOM}}",
          }
        }
    ]
}

# test.ht
{
    Name: Test of automatic varibles
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        TestCount: "{{COUNTER}}"
        TestRand: "{{RANDOM}}"
    }
}`

	globals := map[string]string{"E": "global-e"}

	rs, err := parseRawSuite("automatic.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	want1 := fmt.Sprintf("SuiteCount=%d SuiteRand=131682 ", lastCnt+1)
	want1 += fmt.Sprintf("CallCount=%d CallRand=858315 ", lastCnt+2)
	want1 += fmt.Sprintf("TestCount=%d TestRand=858315 ", lastCnt+2) // Same as Call{Count,Rand}
	want1 += fmt.Sprintf("COUNTER=%d RANDOM=858315", lastCnt+2)      // Same as Call{Count,Rand}
	if wrong := matchVars(s.Tests[0].Variables, want1); wrong != "" {
		s.PrintReport(os.Stdout)
		t.Errorf("First invocation. Got %s", wrong)
	}

	want2 := fmt.Sprintf("SuiteCount=%d SuiteRand=131682 ", lastCnt+1) // Same as in first invocation
	want2 += fmt.Sprintf("CallCount=%d CallRand=817389 ", lastCnt+3)
	want2 += fmt.Sprintf("TestCount=%d TestRand=817389 ", lastCnt+3) // Same as Call{Count,Rand}
	want2 += fmt.Sprintf("COUNTER=%d RANDOM=817389", lastCnt+3)      // Same as Call{Count,Rand}
	if wrong := matchVars(s.Tests[1].Variables, want2); wrong != "" {
		s.PrintReport(os.Stdout)
		t.Errorf("Second invocation. Got %s", wrong)
	}
}

// Variable extraction works upwards: From test-scope into suite-scope.
// RANDOM (and counter are not special).
func TestVariableExtraction(t *testing.T) {
	rand.Seed(1234)

	txt := `
# extraction.suite
{
    Name: Testsuite for variable extraction
    Variables: {
        A:  "initial-A",
        B:  "B",
    }
    Main: [
        { File: "test.ht"
          Variables: {
              C: "{{A}}"
          }
        },
        { File: "test.ht"
          Variables: {
              C: "{{B}}"
          }
        }
    ]
}

# test.ht
{
    Name: Test of variable extraction
    Request: { URL: "file:///etc/passwd" }
    VarEx: {
        A: {Extractor: "SetVariable", To: "fixed-A" }
        B: {Extractor: "SetVariable", To: "{{B}} {{B}}" }
        D: {Extractor: "SetVariable", To: "D={{C}}" }
        RANDOM: {Extractor: "SetVariable", To: "abcdef" }
    }
}`

	rs, err := parseRawSuite("extraction.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(nil, nil, logger())

	if s.FinalVariables["A"] != "fixed-A" ||
		s.FinalVariables["B"] != "B B B B" ||
		s.FinalVariables["D"] != "D=B B" ||
		s.FinalVariables["RANDOM"] != "abcdef" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable extraction. Got %v", s.FinalVariables)
	}
}

func matchVars(got map[string]string, want string) string {
	for _, elem := range strings.Split(want, " ") {
		p := strings.Split(elem, "=")
		name, val := p[0], p[1]
		if g := got[name]; g != val {
			return fmt.Sprintf("%s=%s, want %s", name, g, elem)
		}
	}

	return ""
}
<commit_msg>suite: get rid of old code<commit_after>// Copyright 2016 Volker Dobler.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package suite

import (
	"fmt"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"strings"
	"testing"

	"github.com/vdobler/ht/scope"
)

func logger() *log.Logger {
	if testing.Verbose() {
		return log.New(os.Stdout, "", 0)
	}

	return log.New(ioutil.Discard, "", 0)
}

// Variables in outer scopes dominate those in inner scopes.
func TestVariableDominance(t *testing.T) {
	txt := `
# dominace.suite
{
    Name: Testsuite to check variable dominance
    Variables: {
        C:  suite
        D:  suite
    }
    Main: [
        { File: "dominance.ht"
          Variables: {
              B: call
              C: call
              D: call
          }
        }
    ]
}

# dominance.ht
{
    Name: Test of variable dominance
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        A: local
        B: local
        C: local
        D: local
    }
}`

	globals := map[string]string{"D": "global"}

	rs, err := parseRawSuite("dominace.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	if s.Tests[0].Variables["A"] != "local" ||
		s.Tests[0].Variables["B"] != "call" ||
		s.Tests[0].Variables["C"] != "suite" ||
		s.Tests[0].Variables["D"] != "global" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable dominance. Got %v", s.Tests[0].Variables)
	}
}

// Variables are handed down from scope to scope. Replacement works.
func TestVariableHanddown(t *testing.T) {
	txt := `
# handdown.suite
{
    Name: Testsuite to check variable handdown
    Variables: {
        C:  "test-c",
        D:  "{{E}}"
    }
    Main: [
        { File: "handdown.ht"
          Variables: {
              A: "call-a"
              B: "{{C}}",
          }
        }
    ]
}

# handdown.ht
{
    Name: Test of variable handdown
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        Va: "{{A}}"
        Vb: "{{B}}"
    }
}`

	globals := map[string]string{"E": "global-e"}

	rs, err := parseRawSuite("handdown.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	if s.Tests[0].Variables["A"] != "call-a" ||
		s.Tests[0].Variables["B"] != "test-c" ||
		s.Tests[0].Variables["C"] != "test-c" ||
		s.Tests[0].Variables["D"] != "global-e" ||
		s.Tests[0].Variables["E"] != "global-e" ||
		s.Tests[0].Variables["Va"] != "call-a" ||
		s.Tests[0].Variables["Vb"] != "test-c" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable handdown. Got %v", s.Tests[0].Variables)
	}
}

// The automatic variables COUNTER and RANDOM are injected into global
// and call scope so that call- and test-scope have just one value of COUNTER
// and RANDOM.
func TestAutomaticVariables(t *testing.T) {
	scope.Random.Seed(1234)
	scope.ResetCounter <- 1

	txt := `
# automatic.suite
{
    Name: Testsuite for automatic variables
    Variables: {
        SuiteCount:  "{{COUNTER}}",
        SuiteRand:  "{{RANDOM}}"
    }
    Main: [
        { File: "test.ht"
          Variables: {
              CallCount: "{{COUNTER}}"
              CallRand: "{{RANDOM}}",
          }
        },
        { File: "test.ht"
          Variables: {
              CallCount: "{{COUNTER}}"
              CallRand: "{{RANDOM}}",
          }
        }
    ]
}

# test.ht
{
    Name: Test of automatic varibles
    Request: { URL: "file:///etc/passwd" }
    Variables: {
        TestCount: "{{COUNTER}}"
        TestRand: "{{RANDOM}}"
    }
}`

	globals := map[string]string{"E": "global-e"}

	rs, err := parseRawSuite("automatic.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(globals, nil, logger())

	want1 := fmt.Sprintf("SuiteCount=%d SuiteRand=131682 ", 1)
	want1 += fmt.Sprintf("CallCount=%d CallRand=858315 ", 2)
	want1 += fmt.Sprintf("TestCount=%d TestRand=858315 ", 2) // Same as Call{Count,Rand}
	want1 += fmt.Sprintf("COUNTER=%d RANDOM=858315", 2)      // Same as Call{Count,Rand}
	if wrong := matchVars(s.Tests[0].Variables, want1); wrong != "" {
		s.PrintReport(os.Stdout)
		t.Errorf("First invocation. Got %s", wrong)
	}

	want2 := fmt.Sprintf("SuiteCount=%d SuiteRand=131682 ", 1) // Same as in first invocation
	want2 += fmt.Sprintf("CallCount=%d CallRand=817389 ", 3)
	want2 += fmt.Sprintf("TestCount=%d TestRand=817389 ", 3) // Same as Call{Count,Rand}
	want2 += fmt.Sprintf("COUNTER=%d RANDOM=817389", 3)      // Same as Call{Count,Rand}
	if wrong := matchVars(s.Tests[1].Variables, want2); wrong != "" {
		s.PrintReport(os.Stdout)
		t.Errorf("Second invocation. Got %s", wrong)
	}
}

// Variable extraction works upwards: From test-scope into suite-scope.
// RANDOM (and counter are not special).
func TestVariableExtraction(t *testing.T) {
	rand.Seed(1234)

	txt := `
# extraction.suite
{
    Name: Testsuite for variable extraction
    Variables: {
        A:  "initial-A",
        B:  "B",
    }
    Main: [
        { File: "test.ht"
          Variables: {
              C: "{{A}}"
          }
        },
        { File: "test.ht"
          Variables: {
              C: "{{B}}"
          }
        }
    ]
}

# test.ht
{
    Name: Test of variable extraction
    Request: { URL: "file:///etc/passwd" }
    VarEx: {
        A: {Extractor: "SetVariable", To: "fixed-A" }
        B: {Extractor: "SetVariable", To: "{{B}} {{B}}" }
        D: {Extractor: "SetVariable", To: "D={{C}}" }
        RANDOM: {Extractor: "SetVariable", To: "abcdef" }
    }
}`

	rs, err := parseRawSuite("extraction.suite", txt)
	if err != nil {
		t.Fatalf("Unexpected error: %s", err)
	}
	s := rs.Execute(nil, nil, logger())

	if s.FinalVariables["A"] != "fixed-A" ||
		s.FinalVariables["B"] != "B B B B" ||
		s.FinalVariables["D"] != "D=B B" ||
		s.FinalVariables["RANDOM"] != "abcdef" {
		s.PrintReport(os.Stdout)
		t.Errorf("Bad variable extraction. Got %v", s.FinalVariables)
	}
}

func matchVars(got map[string]string, want string) string {
	for _, elem := range strings.Split(want, " ") {
		p := strings.Split(elem, "=")
		name, val := p[0], p[1]
		if g := got[name]; g != val {
			return fmt.Sprintf("%s=%s, want %s", name, g, elem)
		}
	}

	return ""
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/eferro/go-snmpqueries/pkg/snmpquery"
)

const (
	CONTENTION = 4
)

func main() {
	var input = make(chan snmpquery.QueryWithOutputChannel)
	go snmpquery.ProcessAndDispatchQueries(input, CONTENTION)

	for id := 0; id < 10; id++ {
		q, _ := snmpquery.FromJson(`{"command":"walk", "destination":"localhost", "community":"kaleidos", "oid":"1.3.6.1.2.1.2.2"}`)
		q.Id = id
		fmt.Println("Result:", snmpquery.ExecuteQuery(input, *q))
	}
}
<commit_msg>Changed default example<commit_after>package main

import (
	"fmt"

	"github.com/eferro/go-snmpqueries/pkg/snmpquery"
)

const (
	CONTENTION = 4
)

func main() {
	var input = make(chan snmpquery.QueryWithOutputChannel)
	go snmpquery.ProcessAndDispatchQueries(input, CONTENTION)

	for id := 0; id < 10; id++ {
		q, _ := snmpquery.FromJson(`{"command":"walk", "destination":"localhost", "community":"public", "oid":"1.3.6.1"}`)
		q.Id = id

		fmt.Println("Result:", snmpquery.ExecuteQuery(input, *q))
	}
}
<|endoftext|>


<commit_before>package terraform

import (
	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

// DestroyApplyGraphBuilder implements GraphBuilder and is responsible for
// applying a pure-destroy plan.
//
// This graph builder is very similar to the ApplyGraphBuilder but
// is slightly simpler.
type DestroyApplyGraphBuilder struct {
	// Module is the root module for the graph to build.
	Module *module.Tree

	// Diff is the diff to apply.
	Diff *Diff

	// State is the current state
	State *State

	// Providers is the list of providers supported.
	Providers []string

	// DisableReduce, if true, will not reduce the graph. Great for testing.
	DisableReduce bool
}

// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Build(path []string) (*Graph, error) {
	return (&BasicGraphBuilder{
		Steps:    b.Steps(),
		Validate: true,
	}).Build(path)
}

// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Steps() []GraphTransformer {
	// Custom factory for creating providers.
	providerFactory := func(name string, path []string) GraphNodeProvider {
		return &NodeApplyableProvider{
			NameValue: name,
			PathValue: path,
		}
	}

	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
		return &NodeApplyableResource{
			NodeAbstractResource: a,
		}
	}

	steps := []GraphTransformer{
		// Creates all the nodes represented in the diff.
		&DiffTransformer{
			Concrete: concreteResource,

			Diff:   b.Diff,
			Module: b.Module,
			State:  b.State,
		},

		// Create orphan output nodes
		&OrphanOutputTransformer{Module: b.Module, State: b.State},

		// Attach the configuration to any resources
		&AttachResourceConfigTransformer{Module: b.Module},

		// Attach the state
		&AttachStateTransformer{State: b.State},

		// Destruction ordering. NOTE: For destroys, we don't need to
		// do any CBD stuff, so that is explicitly not here.
		&DestroyEdgeTransformer{Module: b.Module, State: b.State},

		// Create all the providers
		&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
		&ProviderTransformer{},
		&ParentProviderTransformer{},
		&AttachProviderConfigTransformer{Module: b.Module},

		// Add root variables
		&RootVariableTransformer{Module: b.Module},

		// Add module variables
		&ModuleVariableTransformer{Module: b.Module},

		// Add the outputs
		&OutputTransformer{Module: b.Module},

		// Connect references so ordering is correct
		&ReferenceTransformer{},

		// Add the node to fix the state count boundaries
		&CountBoundaryTransformer{},

		// Single root
		&RootTransformer{},
	}

	if !b.DisableReduce {
		// Perform the transitive reduction to make our graph a bit
		// more sane if possible (it usually is possible).
		steps = append(steps, &TransitiveReductionTransformer{})
	}

	return steps
}
<commit_msg>terraform: destroy apply graph builder should disable providers<commit_after>package terraform

import (
	"github.com/hashicorp/terraform/config/module"
	"github.com/hashicorp/terraform/dag"
)

// DestroyApplyGraphBuilder implements GraphBuilder and is responsible for
// applying a pure-destroy plan.
//
// This graph builder is very similar to the ApplyGraphBuilder but
// is slightly simpler.
type DestroyApplyGraphBuilder struct {
	// Module is the root module for the graph to build.
	Module *module.Tree

	// Diff is the diff to apply.
	Diff *Diff

	// State is the current state
	State *State

	// Providers is the list of providers supported.
	Providers []string

	// DisableReduce, if true, will not reduce the graph. Great for testing.
	DisableReduce bool
}

// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Build(path []string) (*Graph, error) {
	return (&BasicGraphBuilder{
		Steps:    b.Steps(),
		Validate: true,
	}).Build(path)
}

// See GraphBuilder
func (b *DestroyApplyGraphBuilder) Steps() []GraphTransformer {
	// Custom factory for creating providers.
	providerFactory := func(name string, path []string) GraphNodeProvider {
		return &NodeApplyableProvider{
			NameValue: name,
			PathValue: path,
		}
	}

	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
		return &NodeApplyableResource{
			NodeAbstractResource: a,
		}
	}

	steps := []GraphTransformer{
		// Creates all the nodes represented in the diff.
		&DiffTransformer{
			Concrete: concreteResource,

			Diff:   b.Diff,
			Module: b.Module,
			State:  b.State,
		},

		// Create orphan output nodes
		&OrphanOutputTransformer{Module: b.Module, State: b.State},

		// Attach the configuration to any resources
		&AttachResourceConfigTransformer{Module: b.Module},

		// Attach the state
		&AttachStateTransformer{State: b.State},

		// Destruction ordering. NOTE: For destroys, we don't need to
		// do any CBD stuff, so that is explicitly not here.
		&DestroyEdgeTransformer{Module: b.Module, State: b.State},

		// Create all the providers
		&MissingProviderTransformer{Providers: b.Providers, Factory: providerFactory},
		&ProviderTransformer{},
		&DisableProviderTransformer{},
		&ParentProviderTransformer{},
		&AttachProviderConfigTransformer{Module: b.Module},

		// Add root variables
		&RootVariableTransformer{Module: b.Module},

		// Add module variables
		&ModuleVariableTransformer{Module: b.Module},

		// Add the outputs
		&OutputTransformer{Module: b.Module},

		// Connect references so ordering is correct
		&ReferenceTransformer{},

		// Add the node to fix the state count boundaries
		&CountBoundaryTransformer{},

		// Single root
		&RootTransformer{},
	}

	if !b.DisableReduce {
		// Perform the transitive reduction to make our graph a bit
		// more sane if possible (it usually is possible).
		steps = append(steps, &TransitiveReductionTransformer{})
	}

	return steps
}
<|endoftext|>


<commit_before>package expr

import (
	"fmt"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/schema"
)

type FuncMinMax struct {
	in GraphiteFunc
}

func NewMinMax() GraphiteFunc {
	return &FuncMinMax{}
}

func (s *FuncMinMax) Signature() ([]Arg, []Arg) {
	return []Arg{
		ArgSeriesList{val: &s.in}}, []Arg{ArgSeriesList{}}
}

func (s *FuncMinMax) Context(context Context) Context {
	return context
}

func (s *FuncMinMax) Exec(dataMap DataMap) ([]models.Series, error) {
	series, err := s.in.Exec(dataMap)
	if err != nil {
		return nil, err
	}

	outputs := make([]models.Series, len(series))

	for i, serie := range series {
		out := pointSlicePool.Get().([]schema.Point)

		for _, p := range serie.Datapoints {
			out = append(out, schema.Point{Val: p.Val, Ts: p.Ts})
		}

		s := models.Series{
			Target:       fmt.Sprintf("minMax(%s)", serie.Target),
			QueryPatt:    fmt.Sprintf("minMax(%s)", serie.Target),
			Tags:         serie.CopyTagsWith("minMax", "1"),
			Datapoints:   out,
			Interval:     serie.Interval,
			Meta:         serie.Meta,
			QueryMDP:     serie.QueryMDP,
			QueryPNGroup: serie.QueryPNGroup,
		}
		outputs[i] = s
	}
	dataMap.Add(Req{}, outputs...)
	return outputs, nil
}
<commit_msg>Implement min_max<commit_after>package expr

import (
	"fmt"
	"math"

	"github.com/grafana/metrictank/api/models"
	"github.com/grafana/metrictank/batch"
	"github.com/grafana/metrictank/schema"
)

type FuncMinMax struct {
	in GraphiteFunc
}

func NewMinMax() GraphiteFunc {
	return &FuncMinMax{}
}

func (s *FuncMinMax) Signature() ([]Arg, []Arg) {
	return []Arg{
		ArgSeriesList{val: &s.in}}, []Arg{ArgSeriesList{}}
}

func (s *FuncMinMax) Context(context Context) Context {
	return context
}

func (s *FuncMinMax) Exec(dataMap DataMap) ([]models.Series, error) {
	series, err := s.in.Exec(dataMap)
	if err != nil {
		return nil, err
	}

	outputs := make([]models.Series, len(series))

	valOrDefault := func(val float64, def float64) float64 {
		if math.IsNaN(val) {
			return def
		}
		return val
	}

	minMax := func(val float64, min float64, max float64) float64 {
		if math.IsNaN(val) {
			return val
		}
		if max-min == 0 {
			return 0
		}
		return (val - min) / (max - min)
	}

	for i, serie := range series {
		out := pointSlicePool.Get().([]schema.Point)

		minVal := valOrDefault(batch.Min(serie.Datapoints), 0)
		maxVal := valOrDefault(batch.Max(serie.Datapoints), 0)

		for _, p := range serie.Datapoints {
			out = append(out, schema.Point{Val: minMax(p.Val, minVal, maxVal), Ts: p.Ts})
		}

		s := models.Series{
			Target:       fmt.Sprintf("minMax(%s)", serie.Target),
			QueryPatt:    fmt.Sprintf("minMax(%s)", serie.QueryPatt),
			Tags:         serie.CopyTagsWith("minMax", "1"),
			Datapoints:   out,
			Interval:     serie.Interval,
			Meta:         serie.Meta,
			QueryMDP:     serie.QueryMDP,
			QueryPNGroup: serie.QueryPNGroup,
		}
		outputs[i] = s
	}
	dataMap.Add(Req{}, outputs...)
	return outputs, nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func getVendorSubmodules() (map[string]string, error) {
	output, err := execute(
		exec.Command("git", "submodule", "status"),
	)
	if err != nil {
		return nil, err
	}

	vendors := map[string]string{}

	lines := strings.Split(output, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}

		parts := strings.Split(strings.TrimLeft(line, " -"), " ")
		if len(parts) >= 2 {
			path := parts[1]
			commit := parts[0]
			if strings.HasPrefix(path, "vendor/") {
				path = strings.TrimPrefix(path, "vendor/")
				vendors[path] = commit
			}
		}
	}

	return vendors, nil
}

func addVendorSubmodule(importpath string) error {
	var (
		target   = "vendor/" + importpath
		prefixes = []string{"git://", "git+ssh://", "ssh://", "https://"}

		errs []string
	)

	for _, prefix := range prefixes {
		url := prefix + importpath

		_, err := execute(
			exec.Command("git", "submodule", "add", "-f", url, target),
		)
		if err == nil {
			return nil
		}

		errs = append(errs, err.Error())
	}

	return errors.New(strings.Join(errs, "\n"))
}

func removeVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(exec.Command("git", "submodule", "deinit", "-f", path))
	if err != nil {
		return err
	}

	_, err = execute(exec.Command("git", "rm", "-r", "-f", path))
	if err != nil {
		return err
	}

	return nil
}

func updateVendorSubmodule(importpath string) error {
	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	cmd := exec.Command("git", "pull", "origin", "master")
	cmd.Dir = filepath.Join(cwd, "vendor", importpath)

	_, err = execute(cmd)

	return err
}
<commit_msg>submodule: change prefix sequence<commit_after>package main

import (
	"errors"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

func getVendorSubmodules() (map[string]string, error) {
	output, err := execute(
		exec.Command("git", "submodule", "status"),
	)
	if err != nil {
		return nil, err
	}

	vendors := map[string]string{}

	lines := strings.Split(output, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}

		parts := strings.Split(strings.TrimLeft(line, " -"), " ")
		if len(parts) >= 2 {
			path := parts[1]
			commit := parts[0]
			if strings.HasPrefix(path, "vendor/") {
				path = strings.TrimPrefix(path, "vendor/")
				vendors[path] = commit
			}
		}
	}

	return vendors, nil
}

func addVendorSubmodule(importpath string) error {
	var (
		target   = "vendor/" + importpath
		prefixes = []string{"https://", "git://", "git+ssh://"}

		errs []string
	)

	for _, prefix := range prefixes {
		url := prefix + importpath

		_, err := execute(
			exec.Command("git", "submodule", "add", "-f", url, target),
		)
		if err == nil {
			return nil
		}

		errs = append(errs, err.Error())
	}

	return errors.New(strings.Join(errs, "\n"))
}

func removeVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(exec.Command("git", "submodule", "deinit", "-f", path))
	if err != nil {
		return err
	}

	_, err = execute(exec.Command("git", "rm", "-r", "-f", path))
	if err != nil {
		return err
	}

	return nil
}

func updateVendorSubmodule(importpath string) error {
	cwd, err := os.Getwd()
	if err != nil {
		return err
	}

	cmd := exec.Command("git", "pull", "origin", "master")
	cmd.Dir = filepath.Join(cwd, "vendor", importpath)

	_, err = execute(cmd)

	return err
}
<|endoftext|>


<commit_before>package server

type indexTemplateData struct {
	InlineScript string
	Stylesheet   string
	Scripts      []string
}

const indexTemplate = `
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="theme-color" content="#222">

  <title>Dispatch</title>
  <meta name="description" content="Web-based IRC client.">

  <link rel="preload" href="/init" as="fetch" crossorigin>

  {{if .InlineScript}}

  {{end}}

  {{range .Scripts}}

  {{end}}

  <link rel="preload" href="/font/RobotoMono-Regular.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/Montserrat-Regular.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/Montserrat-Bold.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/RobotoMono-Bold.woff2" as="font" type="font/woff2" crossorigin>

  {{if .Stylesheet}}
  <link href="{{.Stylesheet}}" rel="stylesheet">
  {{end}}

  <link rel="manifest" href="/manifest.json">

  This page needs JavaScript enabled to function.

`
<commit_msg>Add apple-touch-icon<commit_after>package server

type indexTemplateData struct {
	InlineScript string
	Stylesheet   string
	Scripts      []string
}

const indexTemplate = `
<!DOCTYPE html>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="theme-color" content="#222">

  <title>Dispatch</title>
  <meta name="description" content="Web-based IRC client.">

  <link rel="preload" href="/init" as="fetch" crossorigin>

  {{if .InlineScript}}

  {{end}}

  {{range .Scripts}}

  {{end}}

  <link rel="preload" href="/font/RobotoMono-Regular.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/Montserrat-Regular.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/Montserrat-Bold.woff2" as="font" type="font/woff2" crossorigin>
  <link rel="preload" href="/font/RobotoMono-Bold.woff2" as="font" type="font/woff2" crossorigin>

  {{if .Stylesheet}}
  <link href="{{.Stylesheet}}" rel="stylesheet">
  {{end}}

  <link rel="manifest" href="/manifest.json">
  <link rel="apple-touch-icon" href="/icon_192.png">

  This page needs JavaScript enabled to function.

`
<|endoftext|>


<commit_before>// Package mse (Message Stream Encryption) provides a transparent wrapper for bidirectional
// data streams (e.g. TCP transports) that prevents passive eavesdroping
// and thus protocol or content identification.
//
// It is also designed to provide limited protection against active MITM attacks
// and portscanning by requiring a weak shared secret to complete the handshake.
// You should note that the major design goal was payload and protocol obfuscation,
// not peer authentication and data integrity verification. Thus it does not offer
// protection against adversaries which already know the necessary data to establish
// connections (that is IP/Port/Shared Secret/Payload protocol).
//
// To minimize the load on systems that employ this protocol fast cryptographic
// methods have been chosen over maximum-security algorithms.
//
// See http://wiki.vuze.com/w/Message_Stream_Encryption for details.
package mse

import (
	"bytes"
	"crypto/cipher"
	crand "crypto/rand"
	"crypto/rc4"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
)

// TODO seed rands

const (
	// p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563
	p            = 0xDEADBEEFDEADBEEF // TODO change this
	pSize        = 8                  // bytes TODO should be 96
	g            = 2
	sKey  uint64 = 1234 // TODO make it variable
)

var vc = make([]byte, 8)

type CryptoMethod uint32

// Crypto methods
const (
	PlainText CryptoMethod = 1 << iota
	RC4
)

type Stream struct {
	raw io.ReadWriter
	// TODO remove x and y from struct
	x uint64 // private key // TODO must be 160 bits
	y uint64 // public key
	r io.Reader
	w io.Writer
}

func NewStream(rw io.ReadWriter) *Stream {
	s := Stream{
		raw: rw,
		x:   uint64(rand.Int63()),
	}
	s.y = (g ^ s.x) % p
	return &s
}

func (s *Stream) Read(p []byte) (n int, err error)  { return s.r.Read(p) }
func (s *Stream) Write(p []byte) (n int, err error) { return s.w.Write(p) }

func (s *Stream) HandshakeOutgoing(cryptoProvide CryptoMethod) (selected CryptoMethod, err error) {
	writeBuf := bytes.NewBuffer(make([]byte, 0, 96+512))

	// Step 1 | A->B: Diffie Hellman Ya, PadA
	err = binary.Write(writeBuf, binary.BigEndian, &s.y)
	if err != nil {
		return
	}
	padA := pad()
	_, err = writeBuf.Write(padA)
	if err != nil {
		return
	}
	fmt.Println("--- out: writing Step 1")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")

	// Step 2 | B->A: Diffie Hellman Yb, PadB
	b := make([]byte, pSize+512)
	fmt.Println("--- out: reading PubkeyB")
	_, err = io.ReadAtLeast(s.raw, b, pSize)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")
	yRemote := binary.BigEndian.Uint64(b)
	b = nil
	S := (yRemote ^ s.x) % p
	fmt.Printf("--- S out: %#v\n", S)
	cipherEnc, err := rc4.NewCipher(rc4Key("keyA", S, sKey))
	if err != nil {
		return
	}
	cipherDec, err := rc4.NewCipher(rc4Key("keyB", S, sKey))
	if err != nil {
		return
	}
	discard := make([]byte, 1024)
	cipherEnc.XORKeyStream(discard, discard)
	cipherDec.XORKeyStream(discard, discard)
	s.w = &cipher.StreamWriter{S: cipherEnc, W: s.raw}
	s.r = &cipher.StreamReader{S: cipherDec, R: s.raw}

	// Step 3 | A->B: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
	req1 := hash("req1", S)
	req2 := hash("req2", sKey)
	req3 := hash("req3", S)
	for i := 0; i < sha1.Size; i++ {
		req3[i] ^= req2[i]
	}
	padC := pad()
	_, err = writeBuf.Write(req1)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(req3)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(vc)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, cryptoProvide)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, uint16(len(padC))) // len(PadC)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(padC)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, uint16(0)) // len(IA) TODO take it as argument
	if err != nil {
		return
	}
	encBytes := writeBuf.Bytes()[40:]
	cipherEnc.XORKeyStream(encBytes, encBytes)
	fmt.Println("--- out: writing Step 3")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")

	// Step 4 | B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
	vcRead := make([]byte, 8)
	fmt.Println("--- out: read sync")
	_, err = io.ReadFull(s.r, vcRead)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")
	if !bytes.Equal(vcRead, vc) {
		err = errors.New("invalid VC")
		return
	}
	err = binary.Read(s.r, binary.BigEndian, &selected)
	if err != nil {
		return
	}
	fmt.Printf("--- selected: %#v\n", selected)
	if !isPowerOfTwo(uint32(selected)) {
		err = fmt.Errorf("invalid crypto selected: %d", selected)
		return
	}
	if (selected & cryptoProvide) == 0 {
		err = fmt.Errorf("selected crypto is not provided: %d", selected)
		return
	}
	var lenPadD uint16
	err = binary.Read(s.r, binary.BigEndian, &lenPadD)
	if err != nil {
		return
	}
	fmt.Printf("--- lenPadD: %#v\n", lenPadD)
	if lenPadD > 0 {
		_, err = io.CopyN(ioutil.Discard, s.r, int64(lenPadD))
		if err != nil {
			return
		}
	}

	return selected, nil

	// Step 5 | A->B: ENCRYPT2(Payload Stream)
}

func isPowerOfTwo(x uint32) bool { return (x != 0) && ((x & (x - 1)) == 0) }

func hash(prefix string, key uint64) []byte {
	h := sha1.New()
	h.Write([]byte(prefix))
	binary.Write(h, binary.BigEndian, &key)
	return h.Sum(nil)
}

func rc4Key(prefix string, s uint64, sKey uint64) []byte {
	h := sha1.New()
	h.Write([]byte(prefix))
	binary.Write(h, binary.BigEndian, &s)
	binary.Write(h, binary.BigEndian, &sKey)
	return h.Sum(nil)
}

func pad() []byte {
	b := make([]byte, rand.Intn(512))
	crand.Read(b)
	return b
}

func (s *Stream) HandshakeIncoming(cryptoSelect func(cryptoProvide CryptoMethod) (CryptoMethod, error)) error {
	writeBuf := bytes.NewBuffer(make([]byte, 0, 96+512))

	// Step 1 | A->B: Diffie Hellman Ya, PadA
	buf := make([]byte, pSize+512)
	fmt.Println("--- in: read PubkeyA")
	_, err := io.ReadAtLeast(s.raw, buf, pSize)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")
	yRemote := binary.BigEndian.Uint64(buf)
	buf = nil
	S := (yRemote ^ s.x) % p
	fmt.Printf("--- S in:  %#v\n", S)
	cipherEnc, err := rc4.NewCipher(rc4Key("keyB", S, sKey))
	if err != nil {
		return err
	}
	cipherDec, err := rc4.NewCipher(rc4Key("keyA", S, sKey))
	if err != nil {
		return err
	}
	discard := make([]byte, 1024)
	cipherEnc.XORKeyStream(discard, discard)
	cipherDec.XORKeyStream(discard, discard)
	s.w = &cipher.StreamWriter{S: cipherEnc, W: s.raw}
	s.r = &cipher.StreamReader{S: cipherDec, R: s.raw}

	// Step 2 | B->A: Diffie Hellman Yb, PadB
	err = binary.Write(writeBuf, binary.BigEndian, &s.y)
	if err != nil {
		return err
	}
	padB := pad()
	_, err = writeBuf.Write(padB)
	if err != nil {
		return err
	}
	fmt.Println("--- in: writing Step 2")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")

	// Step 3 | A->B: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
	hash1Calc := hash("req1", S)
	hash2Calc := hash("req2", sKey)
	hash3Calc := hash("req3", S)
	for i := 0; i < sha1.Size; i++ {
		hash3Calc[i] ^= hash2Calc[i]
	}
	hashRead := make([]byte, 20)
	_, err = io.ReadFull(s.raw, hashRead)
	if err != nil {
		return err
	}
	if !bytes.Equal(hashRead, hash1Calc) {
		err = errors.New("invalid S hash")
		return err
	}
	_, err = io.ReadFull(s.raw, hashRead)
	if err != nil {
		return err
	}
	if !bytes.Equal(hashRead, hash3Calc) {
		err = errors.New("invalid SKEY hash")
		return err
	}
	vcRead := make([]byte, 8)
	fmt.Println("--- in: read vc")
	_, err = io.ReadFull(s.r, vcRead)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")
	if !bytes.Equal(vcRead, vc) {
		return fmt.Errorf("invalid VC: %s", hex.EncodeToString(vcRead))
	}
	var cryptoProvide CryptoMethod
	err = binary.Read(s.r, binary.BigEndian, &cryptoProvide)
	if err != nil {
		return err
	}
	selected, err := cryptoSelect(cryptoProvide)
	if err != nil {
		return err
	}
	var lenPadC uint16
	err = binary.Read(s.r, binary.BigEndian, &lenPadC)
	if err != nil {
		return err
	}
	_, err = io.CopyN(ioutil.Discard, s.r, int64(lenPadC))
	if err != nil {
		return err
	}
	var lenIA uint16
	err = binary.Read(s.r, binary.BigEndian, &lenIA)
	if err != nil {
		return err
	}

	// Step 4 | B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
	fmt.Println("--- in: begin step 4")
	_, err = writeBuf.Write(vc)
	if err != nil {
		return err
	}
	err = binary.Write(writeBuf, binary.BigEndian, selected)
	if err != nil {
		return err
	}
	padD := pad()
	err = binary.Write(writeBuf, binary.BigEndian, uint16(len(padD)))
	if err != nil {
		return err
	}
	_, err = writeBuf.Write(padD)
	if err != nil {
		return err
	}
	fmt.Println("--- in: writing step 4")
	_, err = writeBuf.WriteTo(s.w)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")

	// Step 5 | A->B: ENCRYPT2(Payload Stream)
	return nil
}
<commit_msg>use big numbers<commit_after>// Package mse (Message Stream Encryption) provides a transparent wrapper for bidirectional
// data streams (e.g. TCP transports) that prevents passive eavesdroping
// and thus protocol or content identification.
//
// It is also designed to provide limited protection against active MITM attacks
// and portscanning by requiring a weak shared secret to complete the handshake.
// You should note that the major design goal was payload and protocol obfuscation,
// not peer authentication and data integrity verification. Thus it does not offer
// protection against adversaries which already know the necessary data to establish
// connections (that is IP/Port/Shared Secret/Payload protocol).
//
// To minimize the load on systems that employ this protocol fast cryptographic
// methods have been chosen over maximum-security algorithms.
//
// See http://wiki.vuze.com/w/Message_Stream_Encryption for details.
package mse

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/rc4"
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/big"
)

const (
	pString = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563"
)

var (
	p    = new(big.Int) // TODO precalculate bytes
	g    = big.NewInt(2)
	vc   = make([]byte, 8)
	sKey = make([]byte, 20) // TODO take it as argument
)

func init() {
	b, err := hex.DecodeString(pString)
	if err != nil {
		panic(err)
	}
	p.SetBytes(b)
}

type CryptoMethod uint32

// Crypto methods
const (
	PlainText CryptoMethod = 1 << iota
	RC4
)

type Stream struct {
	raw io.ReadWriter
	r   io.Reader
	w   io.Writer
}

func NewStream(rw io.ReadWriter) *Stream { return &Stream{raw: rw} }

func (s *Stream) Read(p []byte) (n int, err error)  { return s.r.Read(p) }
func (s *Stream) Write(p []byte) (n int, err error) { return s.w.Write(p) }

func privateKey() (*big.Int, error) {
	b := make([]byte, 20)
	_, err := rand.Read(b)
	if err != nil {
		return nil, err
	}
	var n big.Int
	return n.SetBytes(b), nil
}

func publicKey(private *big.Int) *big.Int {
	var n big.Int
	return n.Exp(g, private, p)
}

func keyPair() (private, public *big.Int, err error) {
	private, err = privateKey()
	if err != nil {
		return
	}
	public = publicKey(private)
	return
}

func writePubKey(buf *bytes.Buffer, key *big.Int) error {
	b := key.Bytes() // big-endian
	pad := 96 - len(b)
	fmt.Printf("--- pad: %d\n", pad)
	_, err := buf.Write(make([]byte, pad))
	if err != nil {
		return err
	}
	_, err = buf.Write(b)
	return err
}

func keyBytesWithPad(key *big.Int) []byte {
	b := key.Bytes()
	pad := 96 - len(b)
	if pad > 0 {
		b = make([]byte, 96)
		copy(b[pad:], key.Bytes())
	}
	return b
}

func (s *Stream) HandshakeOutgoing(cryptoProvide CryptoMethod) (selected CryptoMethod, err error) {
	writeBuf := bytes.NewBuffer(make([]byte, 0, 96+512))

	Xa, Ya, err := keyPair()
	if err != nil {
		return
	}

	// Step 1 | A->B: Diffie Hellman Ya, PadA
	err = writePubKey(writeBuf, Ya)
	if err != nil {
		return
	}
	padA, err := pad()
	if err != nil {
		return
	}
	_, err = writeBuf.Write(padA)
	if err != nil {
		return
	}
	fmt.Println("--- out: writing Step 1")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")

	// Step 2 | B->A: Diffie Hellman Yb, PadB
	b := make([]byte, 96+512)
	fmt.Println("--- out: reading PubkeyB")
	_, err = io.ReadAtLeast(s.raw, b, 96)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")
	Yb := new(big.Int)
	Yb.SetBytes(b[:96])
	b = nil
	S := Yb.Exp(Yb, Xa, p)
	cipherEnc, err := rc4.NewCipher(rc4Key("keyA", S, sKey))
	if err != nil {
		return
	}
	cipherDec, err := rc4.NewCipher(rc4Key("keyB", S, sKey))
	if err != nil {
		return
	}
	discard := make([]byte, 1024)
	cipherEnc.XORKeyStream(discard, discard)
	cipherDec.XORKeyStream(discard, discard)
	s.w = &cipher.StreamWriter{S: cipherEnc, W: s.raw}
	s.r = &cipher.StreamReader{S: cipherDec, R: s.raw}

	// Step 3 | A->B: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
	req1 := hashKey("req1", S)
	req2 := hashBytes("req2", sKey)
	req3 := hashKey("req3", S)
	for i := 0; i < sha1.Size; i++ {
		req3[i] ^= req2[i]
	}
	padC, err := pad()
	if err != nil {
		return
	}
	_, err = writeBuf.Write(req1)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(req3)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(vc)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, cryptoProvide)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, uint16(len(padC))) // len(PadC)
	if err != nil {
		return
	}
	_, err = writeBuf.Write(padC)
	if err != nil {
		return
	}
	err = binary.Write(writeBuf, binary.BigEndian, uint16(0)) // len(IA) TODO take it as argument
	if err != nil {
		return
	}
	encBytes := writeBuf.Bytes()[40:]
	cipherEnc.XORKeyStream(encBytes, encBytes)
	fmt.Println("--- out: writing Step 3")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")

	// Step 4 | B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
	vcRead := make([]byte, 8)
	fmt.Println("--- out: read sync")
	_, err = io.ReadFull(s.r, vcRead)
	if err != nil {
		return
	}
	fmt.Println("--- out: done")
	if !bytes.Equal(vcRead, vc) {
		err = errors.New("invalid VC")
		return
	}
	err = binary.Read(s.r, binary.BigEndian, &selected)
	if err != nil {
		return
	}
	fmt.Printf("--- selected: %#v\n", selected)
	if !isPowerOfTwo(uint32(selected)) {
		err = fmt.Errorf("invalid crypto selected: %d", selected)
		return
	}
	if (selected & cryptoProvide) == 0 {
		err = fmt.Errorf("selected crypto is not provided: %d", selected)
		return
	}
	var lenPadD uint16
	err = binary.Read(s.r, binary.BigEndian, &lenPadD)
	if err != nil {
		return
	}
	fmt.Printf("--- lenPadD: %#v\n", lenPadD)
	if lenPadD > 0 {
		_, err = io.CopyN(ioutil.Discard, s.r, int64(lenPadD))
		if err != nil {
			return
		}
	}

	return selected, nil

	// Step 5 | A->B: ENCRYPT2(Payload Stream)
}

func isPowerOfTwo(x uint32) bool { return (x != 0) && ((x & (x - 1)) == 0) }

func hashKey(prefix string, key *big.Int) []byte {
	h := sha1.New()
	h.Write([]byte(prefix))
	h.Write(keyBytesWithPad(key))
	return h.Sum(nil)
}

func hashBytes(prefix string, key []byte) []byte {
	h := sha1.New()
	h.Write([]byte(prefix))
	h.Write(key)
	return h.Sum(nil)
}

func rc4Key(prefix string, S *big.Int, sKey []byte) []byte {
	h := sha1.New()
	h.Write([]byte(prefix))
	h.Write(keyBytesWithPad(S))
	h.Write(sKey)
	return h.Sum(nil)
}

func pad() ([]byte, error) {
	padLen, err := rand.Int(rand.Reader, big.NewInt(512))
	if err != nil {
		return nil, err
	}
	b := make([]byte, int(padLen.Int64()))
	_, err = rand.Read(b)
	if err != nil {
		return nil, err
	}
	return b, nil
}

func (s *Stream) HandshakeIncoming(cryptoSelect func(cryptoProvide CryptoMethod) (CryptoMethod, error)) error {
	writeBuf := bytes.NewBuffer(make([]byte, 0, 96+512))

	Xb, Yb, err := keyPair()
	if err != nil {
		return err
	}

	// Step 1 | A->B: Diffie Hellman Ya, PadA
	b := make([]byte, 96+512)
	fmt.Println("--- in: read PubkeyA")
	_, err = io.ReadAtLeast(s.raw, b, 96)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")
	Ya := new(big.Int)
	Ya.SetBytes(b[:96])
	b = nil
	S := Ya.Exp(Ya, Xb, p)
	cipherEnc, err := rc4.NewCipher(rc4Key("keyB", S, sKey))
	if err != nil {
		return err
	}
	cipherDec, err := rc4.NewCipher(rc4Key("keyA", S, sKey))
	if err != nil {
		return err
	}
	discard := make([]byte, 1024)
	cipherEnc.XORKeyStream(discard, discard)
	cipherDec.XORKeyStream(discard, discard)
	s.w = &cipher.StreamWriter{S: cipherEnc, W: s.raw}
	s.r = &cipher.StreamReader{S: cipherDec, R: s.raw}

	// Step 2 | B->A: Diffie Hellman Yb, PadB
	err = writePubKey(writeBuf, Yb)
	if err != nil {
		return err
	}
	padB, err := pad()
	if err != nil {
		return err
	}
	_, err = writeBuf.Write(padB)
	if err != nil {
		return err
	}
	fmt.Println("--- in: writing Step 2")
	_, err = writeBuf.WriteTo(s.raw)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")

	// Step 3 | A->B: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA)
	hash1Calc := hashKey("req1", S)
	hash2Calc := hashBytes("req2", sKey)
	hash3Calc := hashKey("req3", S)
	for i := 0; i < sha1.Size; i++ {
		hash3Calc[i] ^= hash2Calc[i]
	}
	hashRead := make([]byte, 20)
	_, err = io.ReadFull(s.raw, hashRead)
	if err != nil {
		return err
	}
	if !bytes.Equal(hashRead, hash1Calc) {
		err = errors.New("invalid S hash")
		return err
	}
	_, err = io.ReadFull(s.raw, hashRead)
	if err != nil {
		return err
	}
	if !bytes.Equal(hashRead, hash3Calc) {
		err = errors.New("invalid SKEY hash")
		return err
	}
	vcRead := make([]byte, 8)
	fmt.Println("--- in: read vc")
	_, err = io.ReadFull(s.r, vcRead)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")
	if !bytes.Equal(vcRead, vc) {
		return fmt.Errorf("invalid VC: %s", hex.EncodeToString(vcRead))
	}
	var cryptoProvide CryptoMethod
	err = binary.Read(s.r, binary.BigEndian, &cryptoProvide)
	if err != nil {
		return err
	}
	selected, err := cryptoSelect(cryptoProvide)
	if err != nil {
		return err
	}
	var lenPadC uint16
	err = binary.Read(s.r, binary.BigEndian, &lenPadC)
	if err != nil {
		return err
	}
	_, err = io.CopyN(ioutil.Discard, s.r, int64(lenPadC))
	if err != nil {
		return err
	}
	var lenIA uint16
	err = binary.Read(s.r, binary.BigEndian, &lenIA)
	if err != nil {
		return err
	}

	// Step 4 | B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
	fmt.Println("--- in: begin step 4")
	_, err = writeBuf.Write(vc)
	if err != nil {
		return err
	}
	err = binary.Write(writeBuf, binary.BigEndian, selected)
	if err != nil {
		return err
	}
	padD, err := pad()
	if err != nil {
		return err
	}
	err = binary.Write(writeBuf, binary.BigEndian, uint16(len(padD)))
	if err != nil {
		return err
	}
	_, err = writeBuf.Write(padD)
	if err != nil {
		return err
	}
	fmt.Println("--- in: writing step 4")
	_, err = writeBuf.WriteTo(s.w)
	if err != nil {
		return err
	}
	fmt.Println("--- in: done")

	// Step 5 | A->B: ENCRYPT2(Payload Stream)
	return nil
}
<|endoftext|>


<commit_before>package template

import (
	"io"
	"path/filepath"

	"github.com/kataras/go-errors"
	"github.com/valyala/bytebufferpool"
)

type (
	// Entries the template Engines with their loader
	Entries []*Entry

	// Entry contains a template Engine and its Loader
	Entry struct {
		Loader *Loader
		Engine Engine
	}

	// Mux is an optional feature, used when you want to use multiple template engines
	// It stores the loaders with each of the template engine,
	// the identifier of each template engine is the (loader's) Extension
	// the registry finds the correct template engine and executes the template
	// so you can use and render a template file by it's file extension
	Mux struct {
		// Reload reloads the template engine on each execute, used when the project is under development status
		// if true the template will reflect the runtime template files changes
		// defaults to false
		Reload bool

		// Entries the template Engines with their loader
		Entries Entries
		// SharedFuncs funcs that will be shared all over the supported template engines
		SharedFuncs map[string]interface{}

		buffer *bytebufferpool.Pool
	}
)

// LoadEngine loads the Engine using its registered loader
// Internal Note:
// Loader can be used without a mux because of this we have this type of function here which just pass itself's field into other itself's field
// which, normally, is not a smart choice.
func (entry *Entry) LoadEngine() error {
	return entry.Loader.LoadEngine(entry.Engine)
}

// LoadAll loads all template engines entries, returns the first error
func (entries Entries) LoadAll() error {
	for i, n := 0, len(entries); i < n; i++ {
		if err := entries[i].LoadEngine(); err != nil {
			return err
		}
	}
	return nil
}

// Find receives a filename, gets its extension and returns the template engine responsible for that file extension
func (entries Entries) Find(filename string) *Entry {
	extension := filepath.Ext(filename)
	// Read-Only no locks needed, at serve/runtime-time the library is not supposed to add new template engines
	for i, n := 0, len(entries); i < n; i++ {
		e := entries[i]
		if e.Loader.Extension == extension {
			return e
		}
	}
	return nil
}

// DefaultMux is the default template mux
// use that to share template engines across multiple sources in the same app.
var DefaultMux = NewMux()

// NewMux returns a new Mux
// Mux is an optional feature, used when you want to use multiple template engines
// It stores the loaders with each of the template engine,
// the identifier of each template engine is the (loader's) Extension
// the registry finds the correct template engine and executes the template
// so you can use and render a template file by it's file extension
func NewMux(sharedFuncs ...map[string]interface{}) *Mux {
	var funcs map[string]interface{}
	if len(sharedFuncs) > 0 {
		funcs = sharedFuncs[0]
	} else {
		funcs = make(map[string]interface{}, 0)
	}

	m := &Mux{
		Entries:     Entries{},
		SharedFuncs: funcs,
		Reload:      false,
		buffer:      &bytebufferpool.Pool{},
	}
	return m
}

// UseFuncMap adds shared template funcs to the Mux
// these funcs are applied to all template engines.
//
// Should be called not called after Load.
func UseFuncMap(funcMap map[string]interface{}) *Mux {
	return DefaultMux.UseFuncMap(funcMap)
}

// UseFuncMap adds shared template funcs to the Mux
// these funcs are applied to all template engines
//
// Should be called not called after Load.
func (m *Mux) UseFuncMap(funcMap map[string]interface{}) *Mux {
	if funcMap == nil {
		return m
	}

	for k, v := range m.SharedFuncs {
		m.SharedFuncs[k] = v
	}

	// if template engine is already added (but not loaded)
	// then it's valid to add these funcs there.
	for i, n := 0, len(m.Entries); i < n; i++ {
		entry := m.Entries[i]
		// add the shared  funcs if template engine supports funcs.
		m.setSharedFuncs(entry)
	}

	return m
}

func (m *Mux) setSharedFuncs(e *Entry) {
	// add the shared  funcs if template engine supports funcs.
	if funcer, ok := e.Engine.(EngineFuncs); ok {
		if funcer.Funcs() != nil && m.SharedFuncs != nil {
			for k, v := range m.SharedFuncs {
				funcer.Funcs()[k] = v
			}
		}
	}
}

// AddEngine adds but not loads a template engine, returns the entry's Loader
func AddEngine(e Engine) *Loader {
	return DefaultMux.AddEngine(e)
}

// AddEngine adds but not loads a template engine, returns the entry's Loader
func (m *Mux) AddEngine(e Engine) *Loader {

	entry := &Entry{Engine: e, Loader: NewLoader()}
	// add the shared  funcs
	m.setSharedFuncs(entry)
	m.Entries = append(m.Entries, entry)
	// returns the entry's Loader(pointer)
	return entry.Loader
}

// Load loads all template engines entries, returns the first error
// it just calls and returns the Entries.LoadALl
func Load() error {
	return DefaultMux.Load()
}

// Load loads all template engines entries, returns the first error
// it just calls and returns the Entries.LoadALl
func (m *Mux) Load() error {
	return m.Entries.LoadAll()
}

var (
	errNoTemplateEngineForExt = errors.New("No template engine found for '%s'")
	errTemplateNotFound       = errors.New("Template %s was not found")
)

// ExecuteWriter calls the correct template Engine's ExecuteWriter func
func ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (err error) {
	return DefaultMux.ExecuteWriter(out, name, binding, options...)
}

// ExecuteWriter calls the correct template Engine's ExecuteWriter func
func (m *Mux) ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (err error) {
	if m == nil {
		//file extension, but no template engine registered
		return errNoTemplateEngineForExt.Format(filepath.Ext(name))
	}

	entry := m.Entries.Find(name)
	if entry == nil {
		return errTemplateNotFound.Format(name)
	}

	if m.Reload {
		if err = entry.LoadEngine(); err != nil {
			return
		}
	}

	return entry.Engine.ExecuteWriter(out, name, binding, options...)
}

// ExecuteString executes a template from a specific template engine and returns its contents result as string, it doesn't renders
func ExecuteString(name string, binding interface{}, options ...map[string]interface{}) (result string, err error) {
	return DefaultMux.ExecuteString(name, binding, options...)
}

// ExecuteString executes a template from a specific template engine and returns its contents result as string, it doesn't renders
func (m *Mux) ExecuteString(name string, binding interface{}, options ...map[string]interface{}) (result string, err error) {
	out := m.buffer.Get()
	defer m.buffer.Put(out)
	err = m.ExecuteWriter(out, name, binding, options...)
	if err == nil {
		result = out.String()
	}
	return
}

var errNoTemplateEngineSupportsRawParsing = errors.New("Not found a valid template engine found which supports raw parser")

// ExecuteRaw read moreon template.go:EngineRawParser
// parse with the first valid EngineRawParser
func ExecuteRaw(src string, wr io.Writer, binding interface{}) error {
	return DefaultMux.ExecuteRaw(src, wr, binding)
}

// ExecuteRaw read moreon template.go:EngineRawParser
// parse with the first valid EngineRawParser
func (m *Mux) ExecuteRaw(src string, wr io.Writer, binding interface{}) error {
	if m == nil {
		//file extension, but no template engine registered
		return errNoTemplateEngineForExt.Format(src)
	}

	for _, e := range m.Entries {
		if p, is := e.Engine.(EngineRawExecutor); is {
			return p.ExecuteRaw(src, wr, binding)
		}
	}
	return errNoTemplateEngineSupportsRawParsing
}

// ExecuteRawString receives raw template source contents and returns it's result as string
func ExecuteRawString(src string, binding interface{}) (result string, err error) {
	return DefaultMux.ExecuteRawString(src, binding)
}

// ExecuteRawString receives raw template source contents and returns it's result as string
func (m *Mux) ExecuteRawString(src string, binding interface{}) (result string, err error) {
	out := m.buffer.Get()
	defer m.buffer.Put(out)
	err = m.ExecuteRaw(src, out, binding)
	if err == nil {
		result = out.String()
	}
	return
}
<commit_msg>Add a specific to engine funcmap setter side-by-side with the generic UseFuncMap<commit_after>package template

import (
	"io"
	"path/filepath"

	"github.com/kataras/go-errors"
	"github.com/valyala/bytebufferpool"
)

type (
	// Entries the template Engines with their loader
	Entries []*Entry

	// Entry contains a template Engine and its Loader
	Entry struct {
		Loader *Loader
		Engine Engine
	}

	// Mux is an optional feature, used when you want to use multiple template engines
	// It stores the loaders with each of the template engine,
	// the identifier of each template engine is the (loader's) Extension
	// the registry finds the correct template engine and executes the template
	// so you can use and render a template file by it's file extension
	Mux struct {
		// Reload reloads the template engine on each execute, used when the project is under development status
		// if true the template will reflect the runtime template files changes
		// defaults to false
		Reload bool

		// Entries the template Engines with their loader
		Entries Entries
		// SharedFuncs funcs that will be shared all over the supported template engines
		SharedFuncs map[string]interface{}

		buffer *bytebufferpool.Pool
	}
)

// LoadEngine loads the Engine using its registered loader
// Internal Note:
// Loader can be used without a mux because of this we have this type of function here which just pass itself's field into other itself's field
// which, normally, is not a smart choice.
func (entry *Entry) LoadEngine() error {
	return entry.Loader.LoadEngine(entry.Engine)
}

// LoadAll loads all template engines entries, returns the first error
func (entries Entries) LoadAll() error {
	for i, n := 0, len(entries); i < n; i++ {
		if err := entries[i].LoadEngine(); err != nil {
			return err
		}
	}
	return nil
}

// Find receives a filename, gets its extension and returns the template engine responsible for that file extension
func (entries Entries) Find(filename string) *Entry {
	extension := filepath.Ext(filename)
	// Read-Only no locks needed, at serve/runtime-time the library is not supposed to add new template engines
	for i, n := 0, len(entries); i < n; i++ {
		e := entries[i]
		if e.Loader.Extension == extension {
			return e
		}
	}
	return nil
}

// DefaultMux is the default template mux
// use that to share template engines across multiple sources in the same app.
var DefaultMux = NewMux()

// NewMux returns a new Mux
// Mux is an optional feature, used when you want to use multiple template engines
// It stores the loaders with each of the template engine,
// the identifier of each template engine is the (loader's) Extension
// the registry finds the correct template engine and executes the template
// so you can use and render a template file by it's file extension
func NewMux(sharedFuncs ...map[string]interface{}) *Mux {
	var funcs map[string]interface{}
	if len(sharedFuncs) > 0 {
		funcs = sharedFuncs[0]
	} else {
		funcs = make(map[string]interface{}, 0)
	}

	m := &Mux{
		Entries:     Entries{},
		SharedFuncs: funcs,
		Reload:      false,
		buffer:      &bytebufferpool.Pool{},
	}
	return m
}

// UseFuncMap adds shared template funcs to the Mux
// these funcs are applied to all template engines.
//
// Should be called not called after Load.
func UseFuncMap(funcMap map[string]interface{}) *Mux {
	return DefaultMux.UseFuncMap(funcMap)
}

// UseFuncMap adds shared template funcs to the Mux
// these funcs are applied to all template engines
//
// Should be called not called after Load.
func (m *Mux) UseFuncMap(funcMap map[string]interface{}) *Mux {
	if len(funcMap) == 0 {
		return m
	}

	for k, v := range m.SharedFuncs {
		m.SharedFuncs[k] = v
	}

	// if template engine is already added (but not loaded)
	// then it's valid to add these funcs there.
	for i, n := 0, len(m.Entries); i < n; i++ {
		// add the shared  funcs if template engine supports funcs.
		m.SetFuncMapToEngine(funcMap, m.Entries[i].Engine)
	}

	return m
}

// SetFuncMapToEngine sets or overrides a specific func map to a specific template engine
// SharedFuncs stays untouched here.
//
// Call UseFuncMap if you want to set SharedFuncs and be applied
// to all registered and future template engines registrations.
func SetFuncMapToEngine(funcMap map[string]interface{}, e Engine) *Mux {
	return DefaultMux.SetFuncMapToEngine(funcMap, e)
}

// SetFuncMapToEngine sets or overrides a specific func map to a specific template engine
// SharedFuncs stays untouched here.
//
// Call UseFuncMap if you want to set SharedFuncs and be applied
// to all registered and future template engines registrations.
func (m *Mux) SetFuncMapToEngine(funcMap map[string]interface{}, e Engine) *Mux {
	if len(funcMap) == 0 {
		return m
	}
	// add the shared  funcs if template engine supports funcs.
	if funcer, ok := e.(EngineFuncs); ok {
		if funcer.Funcs() != nil {
			for k, v := range funcMap {
				funcer.Funcs()[k] = v
			}
		}
	}
	return m
}

// AddEngine adds but not loads a template engine, returns the entry's Loader
func AddEngine(e Engine) *Loader {
	return DefaultMux.AddEngine(e)
}

// AddEngine adds but not loads a template engine, returns the entry's Loader
func (m *Mux) AddEngine(e Engine) *Loader {
	// add the shared  funcs
	m.SetFuncMapToEngine(m.SharedFuncs, e)

	entry := &Entry{Engine: e, Loader: NewLoader()}

	m.Entries = append(m.Entries, entry)
	// returns the entry's Loader(pointer)
	return entry.Loader
}

// Load loads all template engines entries, returns the first error
// it just calls and returns the Entries.LoadALl
func Load() error {
	return DefaultMux.Load()
}

// Load loads all template engines entries, returns the first error
// it just calls and returns the Entries.LoadALl
func (m *Mux) Load() error {
	return m.Entries.LoadAll()
}

var (
	errNoTemplateEngineForExt = errors.New("No template engine found for '%s'")
	errTemplateNotFound       = errors.New("Template %s was not found")
)

// ExecuteWriter calls the correct template Engine's ExecuteWriter func
func ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (err error) {
	return DefaultMux.ExecuteWriter(out, name, binding, options...)
}

// ExecuteWriter calls the correct template Engine's ExecuteWriter func
func (m *Mux) ExecuteWriter(out io.Writer, name string, binding interface{}, options ...map[string]interface{}) (err error) {
	if m == nil {
		//file extension, but no template engine registered
		return errNoTemplateEngineForExt.Format(filepath.Ext(name))
	}

	entry := m.Entries.Find(name)
	if entry == nil {
		return errTemplateNotFound.Format(name)
	}

	if m.Reload {
		if err = entry.LoadEngine(); err != nil {
			return
		}
	}

	return entry.Engine.ExecuteWriter(out, name, binding, options...)
}

// ExecuteString executes a template from a specific template engine and returns its contents result as string, it doesn't renders
func ExecuteString(name string, binding interface{}, options ...map[string]interface{}) (result string, err error) {
	return DefaultMux.ExecuteString(name, binding, options...)
}

// ExecuteString executes a template from a specific template engine and returns its contents result as string, it doesn't renders
func (m *Mux) ExecuteString(name string, binding interface{}, options ...map[string]interface{}) (result string, err error) {
	out := m.buffer.Get()
	defer m.buffer.Put(out)
	err = m.ExecuteWriter(out, name, binding, options...)
	if err == nil {
		result = out.String()
	}
	return
}

var errNoTemplateEngineSupportsRawParsing = errors.New("Not found a valid template engine found which supports raw parser")

// ExecuteRaw read moreon template.go:EngineRawParser
// parse with the first valid EngineRawParser
func ExecuteRaw(src string, wr io.Writer, binding interface{}) error {
	return DefaultMux.ExecuteRaw(src, wr, binding)
}

// ExecuteRaw read moreon template.go:EngineRawParser
// parse with the first valid EngineRawParser
func (m *Mux) ExecuteRaw(src string, wr io.Writer, binding interface{}) error {
	if m == nil {
		//file extension, but no template engine registered
		return errNoTemplateEngineForExt.Format(src)
	}

	for _, e := range m.Entries {
		if p, is := e.Engine.(EngineRawExecutor); is {
			return p.ExecuteRaw(src, wr, binding)
		}
	}
	return errNoTemplateEngineSupportsRawParsing
}

// ExecuteRawString receives raw template source contents and returns it's result as string
func ExecuteRawString(src string, binding interface{}) (result string, err error) {
	return DefaultMux.ExecuteRawString(src, binding)
}

// ExecuteRawString receives raw template source contents and returns it's result as string
func (m *Mux) ExecuteRawString(src string, binding interface{}) (result string, err error) {
	out := m.buffer.Get()
	defer m.buffer.Put(out)
	err = m.ExecuteRaw(src, out, binding)
	if err == nil {
		result = out.String()
	}
	return
}
<|endoftext|>


<commit_before>package memberlist

import (
	"fmt"
	"github.com/ugorji/go/codec"
	"net"
	"time"
)

// messageType is an integer ID of a type of message that can be received
// on network channels from other members.
type messageType uint8

// The list of available message types.
const (
	pingMsg messageType = iota
	indirectPingMsg
	ackRespMsg
	suspectMsg
	aliveMsg
	deadMsg
	pushPullMsg
	compoundMsg
	userMsg // User mesg, not handled by us
)

const (
	compoundHeaderOverhead = 2   // Assumed header overhead
	compoundOverhead       = 2   // Assumed overhead per entry in compoundHeader
	metaMaxSize            = 128 // Maximum size for nod emeta data
	udpBufSize             = 65536
	udpRecvBuf             = 2 * 1024 * 1024
	udpSendBuf             = 1400
	userMsgOverhead        = 1
)

// ping request sent directly to node
type ping struct {
	SeqNo uint32
}

// indirect ping sent to an indirect ndoe
type indirectPingReq struct {
	SeqNo  uint32
	Target []byte
}

// ack response is sent for a ping
type ackResp struct {
	SeqNo uint32
}

// suspect is broadcast when we suspect a node is dead
type suspect struct {
	Incarnation uint32
	Node        string
}

// alive is broadcast when we know a node is alive.
// Overloaded for nodes joining
type alive struct {
	Incarnation uint32
	Node        string
	Addr        []byte
	Meta        []byte
}

// dead is broadcast when we confirm a node is dead
// Overloaded for nodes leaving
type dead struct {
	Incarnation uint32
	Node        string
}

// pushPullHeader is used to inform the
// otherside how many states we are transfering
type pushPullHeader struct {
	Nodes        int
	UserStateLen int // Encodes the byte lengh of user state
}

// pushNodeState is used for pushPullReq when we are
// transfering out node states
type pushNodeState struct {
	Name        string
	Addr        []byte
	Meta        []byte
	Incarnation uint32
	State       nodeStateType
}

// setUDPRecvBuf is used to resize the UDP receive window. The function
// attempts to set the read buffer to `udpRecvBuf` but backs off until
// the read buffer can be set.
func setUDPRecvBuf(c *net.UDPConn) {
	size := udpRecvBuf
	for {
		if err := c.SetReadBuffer(size); err == nil {
			break
		}
		size = size / 2
	}
}

// tcpListen listens for and handles incoming connections
func (m *Memberlist) tcpListen() {
	for {
		conn, err := m.tcpListener.AcceptTCP()
		if err != nil {
			if m.shutdown {
				break
			}
			m.logger.Printf("[ERR] Error accepting TCP connection: %s", err)
			continue
		}
		go m.handleConn(conn)
	}
}

// handleConn handles a single incoming TCP connection
func (m *Memberlist) handleConn(conn *net.TCPConn) {
	m.logger.Printf("[INFO] Doing push/pull sync with: %s", conn.RemoteAddr())
	defer conn.Close()

	remoteNodes, userState, err := readRemoteState(conn)
	if err != nil {
		m.logger.Printf("[ERR] Failed to receive remote state: %s", err)
		return
	}

	if err := m.sendLocalState(conn); err != nil {
		m.logger.Printf("[ERR] Failed to push local state: %s", err)
	}

	// Merge the membership state
	m.mergeState(remoteNodes)

	// Invoke the delegate for user state
	if m.config.Delegate != nil {
		m.config.Delegate.MergeRemoteState(userState)
	}
}

// udpListen listens for and handles incoming UDP packets
func (m *Memberlist) udpListen() {
	mainBuf := make([]byte, udpBufSize)
	var n int
	var addr net.Addr
	var err error
	var lastPacket time.Time
	for {
		// Do a check for potentially blocking operations
		if !lastPacket.IsZero() && time.Now().Sub(lastPacket) > time.Millisecond {
			diff := time.Now().Sub(lastPacket)
			m.logger.Printf(
				"[WARN] Potential blocking operation. Last command took %v",
				diff)
		}

		// Reset buffer
		buf := mainBuf[0:udpBufSize]

		// Read a packet
		n, addr, err = m.udpListener.ReadFrom(buf)
		if err != nil {
			if m.shutdown {
				break
			}
			m.logger.Printf("[ERR] Error reading UDP packet: %s", err)
			continue
		}

		// Check the length
		if n < 1 {
			m.logger.Printf("[ERR] UDP packet too short (%d bytes). From: %s",
				len(buf), addr)
			continue
		}

		// Capture the current time
		lastPacket = time.Now()

		// Handle the command
		m.handleCommand(buf[:n], addr)
	}
}

func (m *Memberlist) handleCommand(buf []byte, from net.Addr) {
	// Decode the message type
	msgType := messageType(buf[0])
	buf = buf[1:]

	// Switch on the msgType
	switch msgType {
	case compoundMsg:
		m.handleCompound(buf, from)
	case pingMsg:
		m.handlePing(buf, from)
	case indirectPingMsg:
		m.handleIndirectPing(buf, from)
	case ackRespMsg:
		m.handleAck(buf, from)
	case suspectMsg:
		m.handleSuspect(buf, from)
	case aliveMsg:
		m.handleAlive(buf, from)
	case deadMsg:
		m.handleDead(buf, from)
	case userMsg:
		m.handleUser(buf, from)
	default:
		m.logger.Printf("[ERR] UDP msg type (%d) not supported. From: %s", msgType, from)
	}
}

func (m *Memberlist) handleCompound(buf []byte, from net.Addr) {
	// Decode the parts
	trunc, parts, err := decodeCompoundMessage(buf)
	if err != nil {
		m.logger.Printf("[ERR] Failed to decode compound request: %s", err)
		return
	}

	// Log any truncation
	if trunc > 0 {
		m.logger.Printf("[WARN] Compound request had %d truncated messages", trunc)
	}

	// Handle each message
	for _, part := range parts {
		m.handleCommand(part, from)
	}
}

func (m *Memberlist) handlePing(buf []byte, from net.Addr) {
	var p ping
	if err := decode(buf, &p); err != nil {
		m.logger.Printf("[ERR] Failed to decode ping request: %s", err)
		return
	}
	ack := ackResp{p.SeqNo}
	if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
		m.logger.Printf("[ERR] Failed to send ack: %s", err)
	}
}

func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) {
	var ind indirectPingReq
	if err := decode(buf, &ind); err != nil {
		m.logger.Printf("[ERR] Failed to decode indirect ping request: %s", err)
		return
	}

	// Send a ping to the correct host
	localSeqNo := m.nextSeqNo()
	ping := ping{SeqNo: localSeqNo}
	destAddr := &net.UDPAddr{IP: ind.Target, Port: m.config.UDPPort}

	// Setup a response handler to relay the ack
	respHandler := func() {
		ack := ackResp{ind.SeqNo}
		if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
			m.logger.Printf("[ERR] Failed to forward ack: %s", err)
		}
	}
	m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout)

	// Send the ping
	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
		m.logger.Printf("[ERR] Failed to send ping: %s", err)
	}
}

func (m *Memberlist) handleAck(buf []byte, from net.Addr) {
	var ack ackResp
	if err := decode(buf, &ack); err != nil {
		m.logger.Printf("[ERR] Failed to decode ack response: %s", err)
		return
	}
	m.invokeAckHandler(ack.SeqNo)
}

func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) {
	var sus suspect
	if err := decode(buf, &sus); err != nil {
		m.logger.Printf("[ERR] Failed to decode suspect message: %s", err)
		return
	}
	m.suspectNode(&sus)
}

func (m *Memberlist) handleAlive(buf []byte, from net.Addr) {
	var live alive
	if err := decode(buf, &live); err != nil {
		m.logger.Printf("[ERR] Failed to decode alive message: %s", err)
		return
	}
	m.aliveNode(&live)
}

func (m *Memberlist) handleDead(buf []byte, from net.Addr) {
	var d dead
	if err := decode(buf, &d); err != nil {
		m.logger.Printf("[ERR] Failed to decode dead message: %s", err)
		return
	}
	m.deadNode(&d)
}

// handleUser is used to notify channels of incoming user data
func (m *Memberlist) handleUser(buf []byte, from net.Addr) {
	d := m.config.Delegate
	if d != nil {
		d.NotifyMsg(buf)
	}
}

// encodeAndSendMsg is used to combine the encoding and sending steps
func (m *Memberlist) encodeAndSendMsg(to net.Addr, msgType messageType, msg interface{}) error {
	out, err := encode(msgType, msg)
	if err != nil {
		return err
	}
	if err := m.sendMsg(to, out.Bytes()); err != nil {
		return err
	}
	return nil
}

// sendMsg is used to send a UDP message to another host. It will opportunistically
// create a compoundMsg and piggy back other broadcasts
func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
	// Check if we can piggy back any messages
	bytesAvail := udpSendBuf - len(msg) - compoundHeaderOverhead
	extra := m.getBroadcasts(compoundOverhead, bytesAvail)

	// Fast path if nothing to piggypack
	if len(extra) == 0 {
		return m.rawSendMsg(to, msg)
	}

	// Join all the messages
	msgs := make([][]byte, 0, 1+len(extra))
	msgs = append(msgs, msg)
	msgs = append(msgs, extra...)

	// Create a compound message
	compound := makeCompoundMessage(msgs)

	// Send the message
	return m.rawSendMsg(to, compound.Bytes())
}

// rawSendMsg is used to send a UDP message to another host without modification
func (m *Memberlist) rawSendMsg(to net.Addr, msg []byte) error {
	_, err := m.udpListener.WriteTo(msg, to)
	return err
}

// sendState is used to initiate a push/pull over TCP with a remote node
func (m *Memberlist) sendAndReceiveState(addr []byte) ([]pushNodeState, []byte, error) {
	// Attempt to connect
	dialer := net.Dialer{Timeout: m.config.TCPTimeout}
	dest := net.TCPAddr{IP: addr, Port: m.config.TCPPort}
	conn, err := dialer.Dial("tcp", dest.String())
	if err != nil {
		return nil, nil, err
	}
	defer conn.Close()

	// Send our state
	if err := m.sendLocalState(conn); err != nil {
		return nil, nil, err
	}

	// Read remote state
	remote, userState, err := readRemoteState(conn)
	if err != nil {
		return nil, nil, err
	}

	// Return the remote state
	return remote, userState, nil
}

// sendLocalState is invoked to send our local state over a tcp connection
func (m *Memberlist) sendLocalState(conn net.Conn) error {
	// Prepare the local node state
	m.nodeLock.RLock()
	localNodes := make([]pushNodeState, len(m.nodes))
	for idx, n := range m.nodes {
		localNodes[idx].Name = n.Name
		localNodes[idx].Addr = n.Addr
		localNodes[idx].Incarnation = n.Incarnation
		localNodes[idx].State = n.State
		localNodes[idx].Meta = n.Meta
	}
	m.nodeLock.RUnlock()

	// Get the delegate state
	var userData []byte
	if m.config.Delegate != nil {
		userData = m.config.Delegate.LocalState()
	}

	// Send our node state
	header := pushPullHeader{Nodes: len(localNodes), UserStateLen: len(userData)}
	hd := codec.MsgpackHandle{}
	enc := codec.NewEncoder(conn, &hd)

	// Begin state push
	conn.Write([]byte{byte(pushPullMsg)})

	if err := enc.Encode(&header); err != nil {
		return err
	}
	for i := 0; i < header.Nodes; i++ {
		if err := enc.Encode(&localNodes[i]); err != nil {
			return err
		}
	}

	// Write the user state as well
	if userData != nil {
		conn.Write(userData)
	}
	return nil
}

// recvRemoteState is used to read the remote state from a connection
func readRemoteState(conn net.Conn) ([]pushNodeState, []byte, error) {
	// Read the message type
	buf := [1]byte{0}
	if _, err := conn.Read(buf[:]); err != nil {
		return nil, nil, err
	}
	msgType := messageType(buf[0])

	// Quit if not push/pull
	if msgType != pushPullMsg {
		err := fmt.Errorf("received invalid msgType (%d)", msgType)
		return nil, nil, err
	}

	// Read the push/pull header
	var header pushPullHeader
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(conn, &hd)
	if err := dec.Decode(&header); err != nil {
		return nil, nil, err
	}

	// Allocate space for the transfer
	remoteNodes := make([]pushNodeState, header.Nodes)

	// Try to decode all the states
	for i := 0; i < header.Nodes; i++ {
		if err := dec.Decode(&remoteNodes[i]); err != nil {
			return remoteNodes, nil, err
		}
	}

	// Read the remote user state into a buffer
	var userBuf []byte
	if header.UserStateLen > 0 {
		userBuf = make([]byte, header.UserStateLen)
		bytes, err := conn.Read(userBuf)
		if err == nil && bytes != header.UserStateLen {
			err = fmt.Errorf(
				"Failed to read full user state (%d / %d)",
				bytes, header.UserStateLen)
		}
		if err != nil {
			return remoteNodes, nil, err
		}
	}

	return remoteNodes, userBuf, nil
}
<commit_msg>clearer logging for push/pull<commit_after>package memberlist

import (
	"fmt"
	"github.com/ugorji/go/codec"
	"net"
	"time"
)

// messageType is an integer ID of a type of message that can be received
// on network channels from other members.
type messageType uint8

// The list of available message types.
const (
	pingMsg messageType = iota
	indirectPingMsg
	ackRespMsg
	suspectMsg
	aliveMsg
	deadMsg
	pushPullMsg
	compoundMsg
	userMsg // User mesg, not handled by us
)

const (
	compoundHeaderOverhead = 2   // Assumed header overhead
	compoundOverhead       = 2   // Assumed overhead per entry in compoundHeader
	metaMaxSize            = 128 // Maximum size for nod emeta data
	udpBufSize             = 65536
	udpRecvBuf             = 2 * 1024 * 1024
	udpSendBuf             = 1400
	userMsgOverhead        = 1
)

// ping request sent directly to node
type ping struct {
	SeqNo uint32
}

// indirect ping sent to an indirect ndoe
type indirectPingReq struct {
	SeqNo  uint32
	Target []byte
}

// ack response is sent for a ping
type ackResp struct {
	SeqNo uint32
}

// suspect is broadcast when we suspect a node is dead
type suspect struct {
	Incarnation uint32
	Node        string
}

// alive is broadcast when we know a node is alive.
// Overloaded for nodes joining
type alive struct {
	Incarnation uint32
	Node        string
	Addr        []byte
	Meta        []byte
}

// dead is broadcast when we confirm a node is dead
// Overloaded for nodes leaving
type dead struct {
	Incarnation uint32
	Node        string
}

// pushPullHeader is used to inform the
// otherside how many states we are transfering
type pushPullHeader struct {
	Nodes        int
	UserStateLen int // Encodes the byte lengh of user state
}

// pushNodeState is used for pushPullReq when we are
// transfering out node states
type pushNodeState struct {
	Name        string
	Addr        []byte
	Meta        []byte
	Incarnation uint32
	State       nodeStateType
}

// setUDPRecvBuf is used to resize the UDP receive window. The function
// attempts to set the read buffer to `udpRecvBuf` but backs off until
// the read buffer can be set.
func setUDPRecvBuf(c *net.UDPConn) {
	size := udpRecvBuf
	for {
		if err := c.SetReadBuffer(size); err == nil {
			break
		}
		size = size / 2
	}
}

// tcpListen listens for and handles incoming connections
func (m *Memberlist) tcpListen() {
	for {
		conn, err := m.tcpListener.AcceptTCP()
		if err != nil {
			if m.shutdown {
				break
			}
			m.logger.Printf("[ERR] Error accepting TCP connection: %s", err)
			continue
		}
		go m.handleConn(conn)
	}
}

// handleConn handles a single incoming TCP connection
func (m *Memberlist) handleConn(conn *net.TCPConn) {
	m.logger.Printf("[INFO] Responding to push/pull sync with: %s", conn.RemoteAddr())
	defer conn.Close()

	remoteNodes, userState, err := readRemoteState(conn)
	if err != nil {
		m.logger.Printf("[ERR] Failed to receive remote state: %s", err)
		return
	}

	if err := m.sendLocalState(conn); err != nil {
		m.logger.Printf("[ERR] Failed to push local state: %s", err)
	}

	// Merge the membership state
	m.mergeState(remoteNodes)

	// Invoke the delegate for user state
	if m.config.Delegate != nil {
		m.config.Delegate.MergeRemoteState(userState)
	}
}

// udpListen listens for and handles incoming UDP packets
func (m *Memberlist) udpListen() {
	mainBuf := make([]byte, udpBufSize)
	var n int
	var addr net.Addr
	var err error
	var lastPacket time.Time
	for {
		// Do a check for potentially blocking operations
		if !lastPacket.IsZero() && time.Now().Sub(lastPacket) > time.Millisecond {
			diff := time.Now().Sub(lastPacket)
			m.logger.Printf(
				"[WARN] Potential blocking operation. Last command took %v",
				diff)
		}

		// Reset buffer
		buf := mainBuf[0:udpBufSize]

		// Read a packet
		n, addr, err = m.udpListener.ReadFrom(buf)
		if err != nil {
			if m.shutdown {
				break
			}
			m.logger.Printf("[ERR] Error reading UDP packet: %s", err)
			continue
		}

		// Check the length
		if n < 1 {
			m.logger.Printf("[ERR] UDP packet too short (%d bytes). From: %s",
				len(buf), addr)
			continue
		}

		// Capture the current time
		lastPacket = time.Now()

		// Handle the command
		m.handleCommand(buf[:n], addr)
	}
}

func (m *Memberlist) handleCommand(buf []byte, from net.Addr) {
	// Decode the message type
	msgType := messageType(buf[0])
	buf = buf[1:]

	// Switch on the msgType
	switch msgType {
	case compoundMsg:
		m.handleCompound(buf, from)
	case pingMsg:
		m.handlePing(buf, from)
	case indirectPingMsg:
		m.handleIndirectPing(buf, from)
	case ackRespMsg:
		m.handleAck(buf, from)
	case suspectMsg:
		m.handleSuspect(buf, from)
	case aliveMsg:
		m.handleAlive(buf, from)
	case deadMsg:
		m.handleDead(buf, from)
	case userMsg:
		m.handleUser(buf, from)
	default:
		m.logger.Printf("[ERR] UDP msg type (%d) not supported. From: %s", msgType, from)
	}
}

func (m *Memberlist) handleCompound(buf []byte, from net.Addr) {
	// Decode the parts
	trunc, parts, err := decodeCompoundMessage(buf)
	if err != nil {
		m.logger.Printf("[ERR] Failed to decode compound request: %s", err)
		return
	}

	// Log any truncation
	if trunc > 0 {
		m.logger.Printf("[WARN] Compound request had %d truncated messages", trunc)
	}

	// Handle each message
	for _, part := range parts {
		m.handleCommand(part, from)
	}
}

func (m *Memberlist) handlePing(buf []byte, from net.Addr) {
	var p ping
	if err := decode(buf, &p); err != nil {
		m.logger.Printf("[ERR] Failed to decode ping request: %s", err)
		return
	}
	ack := ackResp{p.SeqNo}
	if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
		m.logger.Printf("[ERR] Failed to send ack: %s", err)
	}
}

func (m *Memberlist) handleIndirectPing(buf []byte, from net.Addr) {
	var ind indirectPingReq
	if err := decode(buf, &ind); err != nil {
		m.logger.Printf("[ERR] Failed to decode indirect ping request: %s", err)
		return
	}

	// Send a ping to the correct host
	localSeqNo := m.nextSeqNo()
	ping := ping{SeqNo: localSeqNo}
	destAddr := &net.UDPAddr{IP: ind.Target, Port: m.config.UDPPort}

	// Setup a response handler to relay the ack
	respHandler := func() {
		ack := ackResp{ind.SeqNo}
		if err := m.encodeAndSendMsg(from, ackRespMsg, &ack); err != nil {
			m.logger.Printf("[ERR] Failed to forward ack: %s", err)
		}
	}
	m.setAckHandler(localSeqNo, respHandler, m.config.ProbeTimeout)

	// Send the ping
	if err := m.encodeAndSendMsg(destAddr, pingMsg, &ping); err != nil {
		m.logger.Printf("[ERR] Failed to send ping: %s", err)
	}
}

func (m *Memberlist) handleAck(buf []byte, from net.Addr) {
	var ack ackResp
	if err := decode(buf, &ack); err != nil {
		m.logger.Printf("[ERR] Failed to decode ack response: %s", err)
		return
	}
	m.invokeAckHandler(ack.SeqNo)
}

func (m *Memberlist) handleSuspect(buf []byte, from net.Addr) {
	var sus suspect
	if err := decode(buf, &sus); err != nil {
		m.logger.Printf("[ERR] Failed to decode suspect message: %s", err)
		return
	}
	m.suspectNode(&sus)
}

func (m *Memberlist) handleAlive(buf []byte, from net.Addr) {
	var live alive
	if err := decode(buf, &live); err != nil {
		m.logger.Printf("[ERR] Failed to decode alive message: %s", err)
		return
	}
	m.aliveNode(&live)
}

func (m *Memberlist) handleDead(buf []byte, from net.Addr) {
	var d dead
	if err := decode(buf, &d); err != nil {
		m.logger.Printf("[ERR] Failed to decode dead message: %s", err)
		return
	}
	m.deadNode(&d)
}

// handleUser is used to notify channels of incoming user data
func (m *Memberlist) handleUser(buf []byte, from net.Addr) {
	d := m.config.Delegate
	if d != nil {
		d.NotifyMsg(buf)
	}
}

// encodeAndSendMsg is used to combine the encoding and sending steps
func (m *Memberlist) encodeAndSendMsg(to net.Addr, msgType messageType, msg interface{}) error {
	out, err := encode(msgType, msg)
	if err != nil {
		return err
	}
	if err := m.sendMsg(to, out.Bytes()); err != nil {
		return err
	}
	return nil
}

// sendMsg is used to send a UDP message to another host. It will opportunistically
// create a compoundMsg and piggy back other broadcasts
func (m *Memberlist) sendMsg(to net.Addr, msg []byte) error {
	// Check if we can piggy back any messages
	bytesAvail := udpSendBuf - len(msg) - compoundHeaderOverhead
	extra := m.getBroadcasts(compoundOverhead, bytesAvail)

	// Fast path if nothing to piggypack
	if len(extra) == 0 {
		return m.rawSendMsg(to, msg)
	}

	// Join all the messages
	msgs := make([][]byte, 0, 1+len(extra))
	msgs = append(msgs, msg)
	msgs = append(msgs, extra...)

	// Create a compound message
	compound := makeCompoundMessage(msgs)

	// Send the message
	return m.rawSendMsg(to, compound.Bytes())
}

// rawSendMsg is used to send a UDP message to another host without modification
func (m *Memberlist) rawSendMsg(to net.Addr, msg []byte) error {
	_, err := m.udpListener.WriteTo(msg, to)
	return err
}

// sendState is used to initiate a push/pull over TCP with a remote node
func (m *Memberlist) sendAndReceiveState(addr []byte) ([]pushNodeState, []byte, error) {
	// Attempt to connect
	dialer := net.Dialer{Timeout: m.config.TCPTimeout}
	dest := net.TCPAddr{IP: addr, Port: m.config.TCPPort}
	conn, err := dialer.Dial("tcp", dest.String())
	if err != nil {
		return nil, nil, err
	}
	defer conn.Close()
	m.logger.Printf("[INFO] Initiating push/pull sync with: %s", conn.RemoteAddr())

	// Send our state
	if err := m.sendLocalState(conn); err != nil {
		return nil, nil, err
	}

	// Read remote state
	remote, userState, err := readRemoteState(conn)
	if err != nil {
		return nil, nil, err
	}

	// Return the remote state
	return remote, userState, nil
}

// sendLocalState is invoked to send our local state over a tcp connection
func (m *Memberlist) sendLocalState(conn net.Conn) error {
	// Prepare the local node state
	m.nodeLock.RLock()
	localNodes := make([]pushNodeState, len(m.nodes))
	for idx, n := range m.nodes {
		localNodes[idx].Name = n.Name
		localNodes[idx].Addr = n.Addr
		localNodes[idx].Incarnation = n.Incarnation
		localNodes[idx].State = n.State
		localNodes[idx].Meta = n.Meta
	}
	m.nodeLock.RUnlock()

	// Get the delegate state
	var userData []byte
	if m.config.Delegate != nil {
		userData = m.config.Delegate.LocalState()
	}

	// Send our node state
	header := pushPullHeader{Nodes: len(localNodes), UserStateLen: len(userData)}
	hd := codec.MsgpackHandle{}
	enc := codec.NewEncoder(conn, &hd)

	// Begin state push
	conn.Write([]byte{byte(pushPullMsg)})

	if err := enc.Encode(&header); err != nil {
		return err
	}
	for i := 0; i < header.Nodes; i++ {
		if err := enc.Encode(&localNodes[i]); err != nil {
			return err
		}
	}

	// Write the user state as well
	if userData != nil {
		conn.Write(userData)
	}
	return nil
}

// recvRemoteState is used to read the remote state from a connection
func readRemoteState(conn net.Conn) ([]pushNodeState, []byte, error) {
	// Read the message type
	buf := [1]byte{0}
	if _, err := conn.Read(buf[:]); err != nil {
		return nil, nil, err
	}
	msgType := messageType(buf[0])

	// Quit if not push/pull
	if msgType != pushPullMsg {
		err := fmt.Errorf("received invalid msgType (%d)", msgType)
		return nil, nil, err
	}

	// Read the push/pull header
	var header pushPullHeader
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(conn, &hd)
	if err := dec.Decode(&header); err != nil {
		return nil, nil, err
	}

	// Allocate space for the transfer
	remoteNodes := make([]pushNodeState, header.Nodes)

	// Try to decode all the states
	for i := 0; i < header.Nodes; i++ {
		if err := dec.Decode(&remoteNodes[i]); err != nil {
			return remoteNodes, nil, err
		}
	}

	// Read the remote user state into a buffer
	var userBuf []byte
	if header.UserStateLen > 0 {
		userBuf = make([]byte, header.UserStateLen)
		bytes, err := conn.Read(userBuf)
		if err == nil && bytes != header.UserStateLen {
			err = fmt.Errorf(
				"Failed to read full user state (%d / %d)",
				bytes, header.UserStateLen)
		}
		if err != nil {
			return remoteNodes, nil, err
		}
	}

	return remoteNodes, userBuf, nil
}
<|endoftext|>