<commit_before>package main

import (
	"reflect"
	"regexp"
	"strings"
	"testing"
)

var genMatcherTests = []struct {
	src string
	dst *regexp.Regexp
}{
	// one branch
	{`abc`, regexp.MustCompile(`(abc)`)},
	{`abcdef`, regexp.MustCompile(`(abcdef)`)},

	// multiple branches
	{`a,b`, regexp.MustCompile(`(a|b)`)},
	{`a,,b,c`, regexp.MustCompile(`(a||b|c)`)},
	{`a,bc,def`, regexp.MustCompile(`(a|bc|def)`)},
	{`,a`, regexp.MustCompile(`(|a)`)},
	{`a,`, regexp.MustCompile(`(a|)`)},
	{`,a,`, regexp.MustCompile(`(|a|)`)},

	// use escape
	{`a\,b`, regexp.MustCompile(`(a,b)`)},
	{`a\,bc\,def`, regexp.MustCompile(`(a,bc,def)`)},

	// multiple branches with escape
	{`a\,b,c`, regexp.MustCompile(`(a,b|c)`)},
	{`a,bc\,def`, regexp.MustCompile(`(a|bc,def)`)},

	// regexp quote
	{`a+b`, regexp.MustCompile(`(a\+b)`)},
	{`(a|bc)*def`, regexp.MustCompile(`(\(a\|bc\)\*def)`)},

	// unquote special values
	{`a\\bc`, regexp.MustCompile("(a\\\\bc)")},
	{`a\tb\,c`, regexp.MustCompile("(a\tb,c)")},
	{`a\tbc\n\ndef`, regexp.MustCompile("(a\tbc\n\ndef)")},

	// multiple groups
	{`a/b`, regexp.MustCompile("(a)(b)")},
	{`a//b/c`, regexp.MustCompile(`(a)()(b)(c)`)},
	{`a/bc/def`, regexp.MustCompile("(a)(bc)(def)")},
	{`a,b/c`, regexp.MustCompile("(a|b)(c)")},
	{`/a`, regexp.MustCompile(`()(a)`)},
	{`a/`, regexp.MustCompile(`(a)()`)},
	{`/a/`, regexp.MustCompile(`()(a)()`)},

	// multiple groups with escape
	{`a/b\/c`, regexp.MustCompile("(a)(b/c)")},
	{`a/\/bc\//def`, regexp.MustCompile("(a)(/bc/)(def)")},
	{`a\,b,c/d,e\/f`, regexp.MustCompile("(a,b|c)(d|e/f)")},
}

func TestGenMatcher(t *testing.T) {
	for _, test := range genMatcherTests {
		expect := test.dst
		actual, err := newMatcher(test.src, false)
		if err != nil {
			t.Errorf("newMatcher(%q) returns %q, want nil",
				test.src, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}

var genMatcherWithBoundaryTests = []struct {
	src string
	dst *regexp.Regexp
}{
	{`abc`, regexp.MustCompile(`\b(abc)\b`)},
	{`a,b`, regexp.MustCompile(`\b(a|b)\b`)},
	{`a\,b,c`, regexp.MustCompile(`\b(a,b|c)\b`)},
	{`a/b`, regexp.MustCompile(`\b(a)(b)\b`)},
	{`a/bc/def`, regexp.MustCompile(`\b(a)(bc)(def)\b`)},
	{`a,b/c`, regexp.MustCompile(`\b(a|b)(c)\b`)},
	{`a\,b,c/d,e\/f`, regexp.MustCompile(`\b(a,b|c)(d|e/f)\b`)},
}

func TestGenMatcherWithBoundary(t *testing.T) {
	for _, test := range genMatcherWithBoundaryTests {
		expect := test.dst
		actual, err := newMatcher(test.src, true)
		if err != nil {
			t.Errorf("newMatcher(%q) returns %q, want nil",
				test.src, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}

var genReplacementTests = []struct {
	from        string
	to          string
	replacement []map[string]string
}{
	// one branch
	{
		from: "abc",
		to:   "def",
		replacement: []map[string]string{
			map[string]string{
				"abc": "def",
			},
		},
	},
	{
		from: "abcdef",
		to:   "ghijkl",
		replacement: []map[string]string{
			map[string]string{
				"abcdef": "ghijkl",
			},
		},
	},

	// multiple branches
	{
		from: "a,b",
		to:   "b,a",
		replacement: []map[string]string{
			map[string]string{
				"a": "b",
				"b": "a",
			},
		},
	},
	{
		from: "a,,b,c",
		to:   "d,e,f,g",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
				"":  "e",
				"b": "f",
				"c": "g",
			},
		},
	},
	{
		from: ",a",
		to:   "a,",
		replacement: []map[string]string{
			map[string]string{"": "a", "a": ""},
		},
	},
	{
		from: "a,b,c",
		to:   ",d,",
		replacement: []map[string]string{
			map[string]string{
				"a": "",
				"b": "d",
				"c": "",
			},
		},
	},

	// multiple groups
	{
		from: "a/b",
		to:   "c/d",
		replacement: []map[string]string{
			map[string]string{
				"a": "c",
			},
			map[string]string{
				"b": "d",
			},
		},
	},
	{
		from: "a//b/c",
		to:   "d/e/f/g",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
			},
			map[string]string{
				"": "e",
			},
			map[string]string{
				"b": "f",
			},
			map[string]string{
				"c": "g",
			},
		},
	},
	{
		from: "a,b/c",
		to:   "d,e/f",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
				"b": "e",
			},
			map[string]string{
				"c": "f",
			},
		},
	},
	{
		from: "/a",
		to:   "a/",
		replacement: []map[string]string{
			map[string]string{
				"": "a",
			},
			map[string]string{
				"a": "",
			},
		},
	},
	{
		from: "/a/",
		to:   "b/c/d",
		replacement: []map[string]string{
			map[string]string{
				"": "b",
			},
			map[string]string{
				"a": "c",
			},
			map[string]string{
				"": "d",
			},
		},
	},

	// special chars
	{
		from: "( , )",
		to:   "(,)",
		replacement: []map[string]string{
			map[string]string{
				"( ": "(",
				" )": ")",
			},
		},
	},
	{
		from: "^*/|$",
		to:   "[+/?]",
		replacement: []map[string]string{
			map[string]string{
				"^*": "[+",
			},
			map[string]string{
				"|$": "?]",
			},
		},
	},
}

func TestGenReplacement(t *testing.T) {
	for _, test := range genReplacementTests {
		expect := test.replacement
		actual, err := newReplacement(test.from, test.to)
		if err != nil {
			t.Errorf("newReplacement(%q, %q) returns %q, want nil",
				test.from, test.to, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q, %q: got %q, want %q",
				test.from, test.to, actual, expect)
		}
	}
}

var replaceTests = []struct {
	from string
	to   string
	src  string
	dst  string
}{
	// one branch
	{
		from: "abc",
		to:   "def",
		src:  "foo bar",
		dst:  "foo bar",
	},
	{
		from: "abc",
		to:   "def",
		src:  "abc def",
		dst:  "def def",
	},
	{
		from: "a",
		to:   "b",
		src:  "a b c a b c",
		dst:  "b b c b b c",
	},

	// multiple branches
	{
		from: "abc,def",
		to:   "def,abc",
		src:  "abc def",
		dst:  "def abc",
	},
	{
		from: "a,b,c,d",
		to:   "e,f,g,h",
		src:  "d c b a",
		dst:  "h g f e",
	},
	{
		from: "a, ",
		to:   " ,a",
		src:  "a a a",
		dst:  " a a ",
	},

	// multiple groups
	{
		from: "a/b",
		to:   "c/d",
		src:  "aa ab ac ad",
		dst:  "aa cd ac ad",
	},
	{
		from: "a//b/c",
		to:   "d/e/f/g",
		src:  "abc bca cab",
		dst:  "defg bca cab",
	},
	{
		from: "dog,cat/s",
		to:   "cat,dog/s",
		src:  "cats cats dogs dogs cats",
		dst:  "dogs dogs cats cats dogs",
	},
}

func TestReplace(t *testing.T) {
	for _, test := range replaceTests {
		r, err := NewReplacer(test.from, test.to, false)
		if err != nil {
			t.Errorf("NewReplacer(%q, %q) returns %q, want nil",
				test.from, test.to, err)
			continue
		}

		expect := test.dst
		actual := r.ReplaceAll(test.src)
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("Replacer{%q, %q}: %q: got %q, want %q",
				test.from, test.to, test.src, actual, expect)
		}
	}
}

func BenchmarkReplacerReplace(b *testing.B) {
	src := strings.Repeat("aaa bbb\n", 1000)
	from, to := "aaa,bbb", "bbb,aaa"
	r, err := NewReplacer(from, to, false)
	if err != nil {
		b.Fatalf("NewReplacer(%q, %q, false) returns %q, want nil",
			from, to, err)
	}
	for i := 0; i < b.N; i++ {
		r.ReplaceAll(src)
	}
}
<commit_msg>Add benchmark for strings.Replacer to compare with Replacer<commit_after>package main

import (
	"reflect"
	"regexp"
	"strings"
	"testing"
)

var genMatcherTests = []struct {
	src string
	dst *regexp.Regexp
}{
	// one branch
	{`abc`, regexp.MustCompile(`(abc)`)},
	{`abcdef`, regexp.MustCompile(`(abcdef)`)},

	// multiple branches
	{`a,b`, regexp.MustCompile(`(a|b)`)},
	{`a,,b,c`, regexp.MustCompile(`(a||b|c)`)},
	{`a,bc,def`, regexp.MustCompile(`(a|bc|def)`)},
	{`,a`, regexp.MustCompile(`(|a)`)},
	{`a,`, regexp.MustCompile(`(a|)`)},
	{`,a,`, regexp.MustCompile(`(|a|)`)},

	// use escape
	{`a\,b`, regexp.MustCompile(`(a,b)`)},
	{`a\,bc\,def`, regexp.MustCompile(`(a,bc,def)`)},

	// multiple branches with escape
	{`a\,b,c`, regexp.MustCompile(`(a,b|c)`)},
	{`a,bc\,def`, regexp.MustCompile(`(a|bc,def)`)},

	// regexp quote
	{`a+b`, regexp.MustCompile(`(a\+b)`)},
	{`(a|bc)*def`, regexp.MustCompile(`(\(a\|bc\)\*def)`)},

	// unquote special values
	{`a\\bc`, regexp.MustCompile("(a\\\\bc)")},
	{`a\tb\,c`, regexp.MustCompile("(a\tb,c)")},
	{`a\tbc\n\ndef`, regexp.MustCompile("(a\tbc\n\ndef)")},

	// multiple groups
	{`a/b`, regexp.MustCompile("(a)(b)")},
	{`a//b/c`, regexp.MustCompile(`(a)()(b)(c)`)},
	{`a/bc/def`, regexp.MustCompile("(a)(bc)(def)")},
	{`a,b/c`, regexp.MustCompile("(a|b)(c)")},
	{`/a`, regexp.MustCompile(`()(a)`)},
	{`a/`, regexp.MustCompile(`(a)()`)},
	{`/a/`, regexp.MustCompile(`()(a)()`)},

	// multiple groups with escape
	{`a/b\/c`, regexp.MustCompile("(a)(b/c)")},
	{`a/\/bc\//def`, regexp.MustCompile("(a)(/bc/)(def)")},
	{`a\,b,c/d,e\/f`, regexp.MustCompile("(a,b|c)(d|e/f)")},
}

func TestGenMatcher(t *testing.T) {
	for _, test := range genMatcherTests {
		expect := test.dst
		actual, err := newMatcher(test.src, false)
		if err != nil {
			t.Errorf("newMatcher(%q) returns %q, want nil",
				test.src, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}

var genMatcherWithBoundaryTests = []struct {
	src string
	dst *regexp.Regexp
}{
	{`abc`, regexp.MustCompile(`\b(abc)\b`)},
	{`a,b`, regexp.MustCompile(`\b(a|b)\b`)},
	{`a\,b,c`, regexp.MustCompile(`\b(a,b|c)\b`)},
	{`a/b`, regexp.MustCompile(`\b(a)(b)\b`)},
	{`a/bc/def`, regexp.MustCompile(`\b(a)(bc)(def)\b`)},
	{`a,b/c`, regexp.MustCompile(`\b(a|b)(c)\b`)},
	{`a\,b,c/d,e\/f`, regexp.MustCompile(`\b(a,b|c)(d|e/f)\b`)},
}

func TestGenMatcherWithBoundary(t *testing.T) {
	for _, test := range genMatcherWithBoundaryTests {
		expect := test.dst
		actual, err := newMatcher(test.src, true)
		if err != nil {
			t.Errorf("newMatcher(%q) returns %q, want nil",
				test.src, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q: got %q, want %q",
				test.src, actual, expect)
		}
	}
}

var genReplacementTests = []struct {
	from        string
	to          string
	replacement []map[string]string
}{
	// one branch
	{
		from: "abc",
		to:   "def",
		replacement: []map[string]string{
			map[string]string{
				"abc": "def",
			},
		},
	},
	{
		from: "abcdef",
		to:   "ghijkl",
		replacement: []map[string]string{
			map[string]string{
				"abcdef": "ghijkl",
			},
		},
	},

	// multiple branches
	{
		from: "a,b",
		to:   "b,a",
		replacement: []map[string]string{
			map[string]string{
				"a": "b",
				"b": "a",
			},
		},
	},
	{
		from: "a,,b,c",
		to:   "d,e,f,g",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
				"":  "e",
				"b": "f",
				"c": "g",
			},
		},
	},
	{
		from: ",a",
		to:   "a,",
		replacement: []map[string]string{
			map[string]string{"": "a", "a": ""},
		},
	},
	{
		from: "a,b,c",
		to:   ",d,",
		replacement: []map[string]string{
			map[string]string{
				"a": "",
				"b": "d",
				"c": "",
			},
		},
	},

	// multiple groups
	{
		from: "a/b",
		to:   "c/d",
		replacement: []map[string]string{
			map[string]string{
				"a": "c",
			},
			map[string]string{
				"b": "d",
			},
		},
	},
	{
		from: "a//b/c",
		to:   "d/e/f/g",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
			},
			map[string]string{
				"": "e",
			},
			map[string]string{
				"b": "f",
			},
			map[string]string{
				"c": "g",
			},
		},
	},
	{
		from: "a,b/c",
		to:   "d,e/f",
		replacement: []map[string]string{
			map[string]string{
				"a": "d",
				"b": "e",
			},
			map[string]string{
				"c": "f",
			},
		},
	},
	{
		from: "/a",
		to:   "a/",
		replacement: []map[string]string{
			map[string]string{
				"": "a",
			},
			map[string]string{
				"a": "",
			},
		},
	},
	{
		from: "/a/",
		to:   "b/c/d",
		replacement: []map[string]string{
			map[string]string{
				"": "b",
			},
			map[string]string{
				"a": "c",
			},
			map[string]string{
				"": "d",
			},
		},
	},

	// special chars
	{
		from: "( , )",
		to:   "(,)",
		replacement: []map[string]string{
			map[string]string{
				"( ": "(",
				" )": ")",
			},
		},
	},
	{
		from: "^*/|$",
		to:   "[+/?]",
		replacement: []map[string]string{
			map[string]string{
				"^*": "[+",
			},
			map[string]string{
				"|$": "?]",
			},
		},
	},
}

func TestGenReplacement(t *testing.T) {
	for _, test := range genReplacementTests {
		expect := test.replacement
		actual, err := newReplacement(test.from, test.to)
		if err != nil {
			t.Errorf("newReplacement(%q, %q) returns %q, want nil",
				test.from, test.to, err)
			continue
		}
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("%q, %q: got %q, want %q",
				test.from, test.to, actual, expect)
		}
	}
}

var replaceTests = []struct {
	from string
	to   string
	src  string
	dst  string
}{
	// one branch
	{
		from: "abc",
		to:   "def",
		src:  "foo bar",
		dst:  "foo bar",
	},
	{
		from: "abc",
		to:   "def",
		src:  "abc def",
		dst:  "def def",
	},
	{
		from: "a",
		to:   "b",
		src:  "a b c a b c",
		dst:  "b b c b b c",
	},

	// multiple branches
	{
		from: "abc,def",
		to:   "def,abc",
		src:  "abc def",
		dst:  "def abc",
	},
	{
		from: "a,b,c,d",
		to:   "e,f,g,h",
		src:  "d c b a",
		dst:  "h g f e",
	},
	{
		from: "a, ",
		to:   " ,a",
		src:  "a a a",
		dst:  " a a ",
	},

	// multiple groups
	{
		from: "a/b",
		to:   "c/d",
		src:  "aa ab ac ad",
		dst:  "aa cd ac ad",
	},
	{
		from: "a//b/c",
		to:   "d/e/f/g",
		src:  "abc bca cab",
		dst:  "defg bca cab",
	},
	{
		from: "dog,cat/s",
		to:   "cat,dog/s",
		src:  "cats cats dogs dogs cats",
		dst:  "dogs dogs cats cats dogs",
	},
}

func TestReplace(t *testing.T) {
	for _, test := range replaceTests {
		r, err := NewReplacer(test.from, test.to, false)
		if err != nil {
			t.Errorf("NewReplacer(%q, %q) returns %q, want nil",
				test.from, test.to, err)
			continue
		}

		expect := test.dst
		actual := r.ReplaceAll(test.src)
		if !reflect.DeepEqual(actual, expect) {
			t.Errorf("Replacer{%q, %q}: %q: got %q, want %q",
				test.from, test.to, test.src, actual, expect)
		}
	}
}

func BenchmarkStringsReplace(b *testing.B) {
	src := strings.Repeat("aaa bbb\n", 1000)
	rep := strings.NewReplacer("aaa", "bbb", "bbb", "aaa")
	for i := 0; i < b.N; i++ {
		rep.Replace(src)
	}
}

func BenchmarkReplacerReplace(b *testing.B) {
	src := strings.Repeat("aaa bbb\n", 1000)
	from, to := "aaa,bbb", "bbb,aaa"
	r, err := NewReplacer(from, to, false)
	if err != nil {
		b.Fatalf("NewReplacer(%q, %q, false) returns %q, want nil",
			from, to, err)
	}
	for i := 0; i < b.N; i++ {
		r.ReplaceAll(src)
	}
}
<|endoftext|>


<commit_before>package nagios

import (
//	"os"
	"testing"
	"bytes"
	"fmt"
)

func TestNRPERequest(t *testing.T) {
	var p NrpePacket
	buf := new(bytes.Buffer)
	p.SetMessage("hellfdfffffffffffffffffffffffffddddddddddddddddddddddddddddddddddddddddddo")
	p.PrepareRequest()
	err := p.Generate(buf)
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	fmt.Printf("% x", buf.Bytes())

}
<commit_msg>test packet correctness<commit_after>package nagios

import (
	//	"os"
	. "github.com/smartystreets/goconvey/convey"
	"testing"
	"bytes"
	"fmt"
)

func TestNRPERequest(t *testing.T) {
	var p NrpePacket
	buf := new(bytes.Buffer)
	testStr := "=hellfdfffffddddddddddddz"
	p.SetMessage(testStr)
	p.PrepareRequest()
	err := p.Generate(buf)
	if err != nil {
		fmt.Println("binary.Write failed:", err)
	}
	str := fmt.Sprintf("%s", buf.Bytes())
	Convey (`create packet`,t, func() {
		Convey("contains msg",func() {
			So(str,ShouldContainSubstring,testStr)
		})
		Convey("string is nul-terminated",func() {
			So(str,ShouldContainSubstring,testStr +"\000")
		})
	})

}
<|endoftext|>


<commit_before>package main

import (
	"../nsq"
	"github.com/bmizerany/assert"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"testing"
)

func TestGetTopic(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)

	nsqd = NewNSQd(1, nil, nil, nil, 10, os.TempDir(), 1024)

	topic1 := nsqd.GetTopic("test")
	assert.NotEqual(t, nil, topic1)
	assert.Equal(t, "test", topic1.name)

	topic2 := nsqd.GetTopic("test")
	assert.Equal(t, topic1, topic2)

	topic3 := nsqd.GetTopic("test2")
	assert.Equal(t, "test2", topic3.name)
	assert.NotEqual(t, topic2, topic3)
}

func TestGetChannel(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)

	topic := NewTopic("test", 10, os.TempDir(), 1024)
	channel1 := topic.GetChannel("ch1")
	assert.NotEqual(t, nil, channel1)
	assert.Equal(t, "ch1", channel1.name)

	channel2 := topic.GetChannel("ch2")

	assert.Equal(t, channel1, topic.channelMap["ch1"])
	assert.Equal(t, channel2, topic.channelMap["ch2"])
}

func BenchmarkTopicPut(b *testing.B) {
	b.StopTimer()
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)
	topicName := "testbench" + strconv.Itoa(b.N)
	nsqd = NewNSQd(1, nil, nil, nil, int64(b.N), os.TempDir(), 1024)
	b.StartTimer()

	for i := 0; i < b.N; i++ {
		topic := nsqd.GetTopic(topicName)
		msg := nsq.NewMessage(<-nsqd.idChan, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaa"))
		topic.PutMessage(msg)
	}
}
<commit_msg>add benchmark for topic and channel put<commit_after>package main

import (
	"../nsq"
	"github.com/bmizerany/assert"
	"io/ioutil"
	"log"
	"os"
	"runtime"
	"strconv"
	"testing"
)

func TestGetTopic(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)

	nsqd = NewNSQd(1, nil, nil, nil, 10, os.TempDir(), 1024)

	topic1 := nsqd.GetTopic("test")
	assert.NotEqual(t, nil, topic1)
	assert.Equal(t, "test", topic1.name)

	topic2 := nsqd.GetTopic("test")
	assert.Equal(t, topic1, topic2)

	topic3 := nsqd.GetTopic("test2")
	assert.Equal(t, "test2", topic3.name)
	assert.NotEqual(t, topic2, topic3)
}

func TestGetChannel(t *testing.T) {
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)

	topic := NewTopic("test", 10, os.TempDir(), 1024)
	channel1 := topic.GetChannel("ch1")
	assert.NotEqual(t, nil, channel1)
	assert.Equal(t, "ch1", channel1.name)

	channel2 := topic.GetChannel("ch2")

	assert.Equal(t, channel1, topic.channelMap["ch1"])
	assert.Equal(t, channel2, topic.channelMap["ch2"])
}

func BenchmarkTopicPut(b *testing.B) {
	b.StopTimer()
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)
	topicName := "bench_topic_put" + strconv.Itoa(b.N)
	nsqd = NewNSQd(1, nil, nil, nil, int64(b.N), os.TempDir(), 1024)
	b.StartTimer()

	for i := 0; i <= b.N; i++ {
		topic := nsqd.GetTopic(topicName)
		msg := nsq.NewMessage(<-nsqd.idChan, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaa"))
		topic.PutMessage(msg)
	}
}

func BenchmarkTopicToChannelPut(b *testing.B) {
	b.StopTimer()
	log.SetOutput(ioutil.Discard)
	defer log.SetOutput(os.Stdout)
	topicName := "bench_topic_to_channel_put" + strconv.Itoa(b.N)
	channelName := "bench"
	nsqd = NewNSQd(1, nil, nil, nil, int64(b.N), os.TempDir(), 1024)
	channel := nsqd.GetTopic(topicName).GetChannel(channelName)
	b.StartTimer()

	for i := 0; i <= b.N; i++ {
		topic := nsqd.GetTopic(topicName)
		msg := nsq.NewMessage(<-nsqd.idChan, []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaa"))
		topic.PutMessage(msg)
	}

	for {
		if len(channel.memoryMsgChan) == b.N {
			break
		}
		runtime.Gosched()
	}
}
<|endoftext|>


<commit_before>package ocrworker

import (
	"fmt"
	"net/url"
	"regexp"
)

type OcrRequest struct {
	ImgUrl            string                 `json:"img_url"`
	Name              string                 `json:"name"`
	EngineType        OcrEngineType          `json:"engine"`
	ImgBytes          []byte                 `json:"img_bytes"`
	ImgFiles          [][]byte               `json:"img_files"`
	PreprocessorChain []string               `json:"preprocessors"`
	PreprocessorArgs  map[string]interface{} `json:"preprocessor-args"`
	EngineArgs        map[string]interface{} `json:"engine_args"`

	// decode ocr in http handler rather than putting in queue
	InplaceDecode bool `json:"inplace_decode"`
}

// figure out the next pre-processor routing key to use (if any).
// if we have finished with the pre-processors, then use the processorRoutingKey
func (ocrRequest *OcrRequest) nextPreprocessor(processorRoutingKey string) string {
	if len(ocrRequest.PreprocessorChain) == 0 {
		return processorRoutingKey
	} else {
		var x string
		s := ocrRequest.PreprocessorChain
		x, s = s[len(s)-1], s[:len(s)-1]
		ocrRequest.PreprocessorChain = s
		return x
	}

}

func (ocrRequest *OcrRequest) downloadImgUrl() error {

	bytes, err := url2bytes(ocrRequest.ImgUrl)
	if err != nil {
		return err
	}
	ocrRequest.ImgBytes = bytes
	u, _ := url.Parse(ocrRequest.ImgUrl)
	path := u.Path
	reg := regexp.MustCompile("(^/.*?_|\\..{3})")
	ocrRequest.Name = reg.ReplaceAllString(path, "")
	ocrRequest.ImgUrl = ""
	return nil
}

func (o OcrRequest) String() string {
	return fmt.Sprintf("ImgUrl: %s, EngineType: %s, Preprocessors: %s", o.ImgUrl, o.EngineType, o.PreprocessorChain)
}
<commit_msg>keep docId in file name<commit_after>package ocrworker

import (
	"fmt"
	"net/url"
	"regexp"
)

type OcrRequest struct {
	ImgUrl            string                 `json:"img_url"`
	Name              string                 `json:"name"`
	EngineType        OcrEngineType          `json:"engine"`
	ImgBytes          []byte                 `json:"img_bytes"`
	ImgFiles          [][]byte               `json:"img_files"`
	PreprocessorChain []string               `json:"preprocessors"`
	PreprocessorArgs  map[string]interface{} `json:"preprocessor-args"`
	EngineArgs        map[string]interface{} `json:"engine_args"`

	// decode ocr in http handler rather than putting in queue
	InplaceDecode bool `json:"inplace_decode"`
}

// figure out the next pre-processor routing key to use (if any).
// if we have finished with the pre-processors, then use the processorRoutingKey
func (ocrRequest *OcrRequest) nextPreprocessor(processorRoutingKey string) string {
	if len(ocrRequest.PreprocessorChain) == 0 {
		return processorRoutingKey
	} else {
		var x string
		s := ocrRequest.PreprocessorChain
		x, s = s[len(s)-1], s[:len(s)-1]
		ocrRequest.PreprocessorChain = s
		return x
	}

}

func (ocrRequest *OcrRequest) downloadImgUrl() error {

	bytes, err := url2bytes(ocrRequest.ImgUrl)
	if err != nil {
		return err
	}
	ocrRequest.ImgBytes = bytes
	u, _ := url.Parse(ocrRequest.ImgUrl)
	path := u.Path
	reg := regexp.MustCompile("(^/|\\..{3})")
	ocrRequest.Name = reg.ReplaceAllString(path, "")
	ocrRequest.ImgUrl = ""
	return nil
}

func (o OcrRequest) String() string {
	return fmt.Sprintf("ImgUrl: %s, EngineType: %s, Preprocessors: %s", o.ImgUrl, o.EngineType, o.PreprocessorChain)
}
<|endoftext|>


<commit_before>/*
Package commands implements the IPFS command interface

Using github.com/ipfs/go-ipfs/commands to define the command line and
HTTP APIs.  This is the interface available to folks consuming IPFS
from outside of the Go language.
*/
package commands

import (
	"bytes"
	"io"
	"sort"

	cmds "github.com/ipfs/go-ipfs/commands"
)

type Command struct {
	Name        string
	Subcommands []Command
	Options     []cmds.Option
}

// CommandsCmd takes in a root command,
// and returns a command that lists the subcommands in that root
func CommandsCmd(root *cmds.Command) *cmds.Command {
	return &cmds.Command{
		Helptext: cmds.HelpText{
			Tagline:          "List all available commands.",
			ShortDescription: `Lists all available commands (and subcommands) and exits.`,
		},

		Run: func(req cmds.Request, res cmds.Response) {
			root := cmd2outputCmd("ipfs", root)
			res.SetOutput(&root)
		},
		Marshalers: cmds.MarshalerMap{
			cmds.Text: func(res cmds.Response) (io.Reader, error) {
				v := res.Output().(*Command)
				buf := new(bytes.Buffer)
				for _, s := range cmdPathStrings(v) {
					buf.Write([]byte(s + "\n"))
				}
				return buf, nil
			},
		},
		Type: Command{},
	}
}

func cmd2outputCmd(name string, cmd *cmds.Command) Command {
	output := Command{
		Name:        name,
		Subcommands: make([]Command, len(cmd.Subcommands)),
		Options:     cmd.Options,
	}

	i := 0
	for name, sub := range cmd.Subcommands {
		output.Subcommands[i] = cmd2outputCmd(name, sub)
		i++
	}

	return output
}

func cmdPathStrings(cmd *Command) []string {
	var cmds []string

	var recurse func(prefix string, cmd *Command)
	recurse = func(prefix string, cmd *Command) {
		newPrefix := prefix + cmd.Name
		cmds = append(cmds, newPrefix)
		if prefix != "" {
			for _, option := range cmd.Options {
				optName := option.Names()[0]
				if len(optName) == 1 {
					optName = "-" + optName
				} else {
					optName = "--" + optName
				}
				cmds = append(cmds, newPrefix+" "+optName)
			}
		}
		for _, sub := range cmd.Subcommands {
			recurse(newPrefix+" ", &sub)
		}
	}

	recurse("", cmd)
	sort.Sort(sort.StringSlice(cmds))
	return cmds
}
<commit_msg>commands: add --flags to show all flags<commit_after>/*
Package commands implements the IPFS command interface

Using github.com/ipfs/go-ipfs/commands to define the command line and
HTTP APIs.  This is the interface available to folks consuming IPFS
from outside of the Go language.
*/
package commands

import (
	"bytes"
	"io"
	"sort"

	cmds "github.com/ipfs/go-ipfs/commands"
)

type Command struct {
	Name        string
	Subcommands []Command
	Options     []cmds.Option
	ShowOptions bool
}

const (
	flagsOptionName    = "flags"
)

// CommandsCmd takes in a root command,
// and returns a command that lists the subcommands in that root
func CommandsCmd(root *cmds.Command) *cmds.Command {
	return &cmds.Command{
		Helptext: cmds.HelpText{
			Tagline:          "List all available commands.",
			ShortDescription: `Lists all available commands (and subcommands) and exits.`,
		},
		Options: []cmds.Option{
			cmds.BoolOption(flagsOptionName, "f", "Show command flags"),
		},
		Run: func(req cmds.Request, res cmds.Response) {
			showOptions, _, _ := req.Option(flagsOptionName).Bool();
			rootCmd := cmd2outputCmd("ipfs", root, showOptions)
			res.SetOutput(&rootCmd)
		},
		Marshalers: cmds.MarshalerMap{
			cmds.Text: func(res cmds.Response) (io.Reader, error) {
				v := res.Output().(*Command)
				buf := new(bytes.Buffer)
				for _, s := range cmdPathStrings(v) {
					buf.Write([]byte(s + "\n"))
				}
				return buf, nil
			},
		},
		Type: Command{},
	}
}

func cmd2outputCmd(name string, cmd *cmds.Command, showOptions bool) Command {
	output := Command{
		Name:        name,
		Subcommands: make([]Command, len(cmd.Subcommands)),
		Options:     cmd.Options,
		ShowOptions: showOptions,
	}

	i := 0
	for name, sub := range cmd.Subcommands {
		output.Subcommands[i] = cmd2outputCmd(name, sub, showOptions)
		i++
	}

	return output
}

func cmdPathStrings(cmd *Command) []string {
	var cmds []string

	var recurse func(prefix string, cmd *Command)
	recurse = func(prefix string, cmd *Command) {
		newPrefix := prefix + cmd.Name
		cmds = append(cmds, newPrefix)
		if prefix != "" && cmd.ShowOptions {
			for _, option := range cmd.Options {
				optName := option.Names()[0]
				if len(optName) == 1 {
					optName = "-" + optName
				} else {
					optName = "--" + optName
				}
				cmds = append(cmds, newPrefix+" "+optName)
			}
		}
		for _, sub := range cmd.Subcommands {
			recurse(newPrefix+" ", &sub)
		}
	}

	recurse("", cmd)
	sort.Sort(sort.StringSlice(cmds))
	return cmds
}
<|endoftext|>


<commit_before>package openapi

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

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

// Create implements `POST /channel.create`
func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelArchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Archive implements `POST /channel.archive`
func (c *ChannelService) Archive(ctx context.Context, opt *ChannelArchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.archive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelUnarchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Unarchive implements `POST /channel.unarchive`
func (c *ChannelService) Unarchive(ctx context.Context, opt *ChannelUnarchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.unarchive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelLeaveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Leave implements `POST /channel.leave`
func (c *ChannelService) Leave(ctx context.Context, opt *ChannelLeaveOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.leave", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelJoinOptions struct {
	ChannelID string `json:"channel_id"`
}

// Leave implements `POST /channel.join`
func (c *ChannelService) Join(ctx context.Context, opt *ChannelJoinOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.join", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}
<commit_msg>feat(openapi): implement `channel.invite`<commit_after>package openapi

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

type Channel struct {
	ID            *string       `json:"id,omitempty"`
	TeamID        *string       `json:"team_id,omitempty"`
	VChannelID    *string       `json:"vchannel_id,omitempty"`
	UserID        *string       `json:"uid,omitempty"`
	Name          *string       `json:"name,omitempty"`
	Type          *VChannelType `json:"type,omitempty"`
	Private       *bool         `json:"private,omitempty"`
	General       *bool         `json:"general,omitempty"`
	Topic         *string       `json:"topic,omitempty"`
	IsMember      *bool         `json:"is_member,omitempty"`
	IsActive      *bool         `json:"is_active,omitempty"`
	MemberUserIDs []string      `json:"member_uids,omitempty"`
	LatestTS      *VChannelTS   `json:"latest_ts,omitempty"`
}

type ChannelService service

type ChannelInfoOptions struct {
	ChannelID string
}

// Info implements `GET /channel.info`
func (c *ChannelService) Info(ctx context.Context, opt *ChannelInfoOptions) (*Channel, *http.Response, error) {
	endpoint := fmt.Sprintf("channel.info?channel_id=%s", opt.ChannelID)
	req, err := c.client.newRequest("GET", endpoint, nil)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

// List implements `GET /channel.list`
func (c *ChannelService) List(ctx context.Context) ([]*Channel, *http.Response, error) {
	req, err := c.client.newRequest("GET", "channel.list", nil)
	if err != nil {
		return nil, nil, err
	}

	var channels []*Channel
	resp, err := c.client.do(ctx, req, &channels)
	if err != nil {
		return nil, resp, err
	}
	return channels, resp, nil
}

type ChannelCreateOptions struct {
	Name    string  `json:"name"`
	Topic   *string `json:"topic,omitempty"`
	Private *bool   `json:"private,omitempty"`
}

// Create implements `POST /channel.create`
func (c *ChannelService) Create(ctx context.Context, opt *ChannelCreateOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.create", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelArchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Archive implements `POST /channel.archive`
func (c *ChannelService) Archive(ctx context.Context, opt *ChannelArchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.archive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelUnarchiveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Unarchive implements `POST /channel.unarchive`
func (c *ChannelService) Unarchive(ctx context.Context, opt *ChannelUnarchiveOptions) (*Channel, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.unarchive", opt)
	if err != nil {
		return nil, nil, err
	}

	var channel Channel
	resp, err := c.client.do(ctx, req, &channel)
	if err != nil {
		return nil, resp, err
	}
	return &channel, resp, nil
}

type ChannelLeaveOptions struct {
	ChannelID string `json:"channel_id"`
}

// Leave implements `POST /channel.leave`
func (c *ChannelService) Leave(ctx context.Context, opt *ChannelLeaveOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.leave", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelJoinOptions struct {
	ChannelID string `json:"channel_id"`
}

// Join implements `POST /channel.join`
func (c *ChannelService) Join(ctx context.Context, opt *ChannelJoinOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.join", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}

type ChannelInviteOptions struct {
	ChannelID    string `json:"channel_id"`
	InviteUserID string `json:"invite_uid"`
}

// Invite implements `POST /channel.invite`
func (c *ChannelService) Invite(ctx context.Context, opt *ChannelInviteOptions) (*ResponseNoContent, *http.Response, error) {
	req, err := c.client.newRequest("POST", "channel.invite", opt)
	if err != nil {
		return nil, nil, err
	}

	resp, err := c.client.do(ctx, req, nil)
	if err != nil {
		return nil, resp, err
	}
	return &ResponseNoContent{}, resp, nil
}
<|endoftext|>


<commit_before>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
)

var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")

type JsonPatchOperation struct {
	Operation string      `json:"op"`
	Path      string      `json:"path"`
	Value     interface{} `json:"value,omitempty"`
}

func (j *JsonPatchOperation) Json() string {
	b, _ := json.Marshal(j)
	return string(b)
}

func (j *JsonPatchOperation) MarshalJSON() ([]byte, error) {
	var b bytes.Buffer
	b.WriteString("{")
	b.WriteString(fmt.Sprintf(`"op":"%s"`, j.Operation))
	b.WriteString(fmt.Sprintf(`,"path":"%s"`, j.Path))
	// Consider omitting Value for non-nullable operations.
	if j.Value != nil || j.Operation == "replace" || j.Operation == "add" {
		v, err := json.Marshal(j.Value)
		if err != nil {
			return nil, err
		}
		b.WriteString(`,"value":`)
		b.Write(v)
	}
	b.WriteString("}")
	return b.Bytes(), nil
}

type ByPath []JsonPatchOperation

func (a ByPath) Len() int           { return len(a) }
func (a ByPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }

func NewPatch(operation, path string, value interface{}) JsonPatchOperation {
	return JsonPatchOperation{Operation: operation, Path: path, Value: value}
}

// CreatePatch creates a patch as specified in http://jsonpatch.com/
//
// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content.
// The function will return an array of JsonPatchOperations
//
// An error will be returned if any of the two documents are invalid.
func CreatePatch(a, b []byte) ([]JsonPatchOperation, error) {
	aI := map[string]interface{}{}
	bI := map[string]interface{}{}
	err := json.Unmarshal(a, &aI)
	if err != nil {
		return nil, errBadJSONDoc
	}
	err = json.Unmarshal(b, &bI)
	if err != nil {
		return nil, errBadJSONDoc
	}
	return diff(aI, bI, "", []JsonPatchOperation{})
}

// Returns true if the values matches (must be json types)
// The types of the values must match, otherwise it will always return false
// If two map[string]interface{} are given, all elements must match.
func matchesValue(av, bv interface{}) bool {
	if reflect.TypeOf(av) != reflect.TypeOf(bv) {
		return false
	}
	switch at := av.(type) {
	case string:
		bt := bv.(string)
		if bt == at {
			return true
		}
	case float64:
		bt := bv.(float64)
		if bt == at {
			return true
		}
	case bool:
		bt := bv.(bool)
		if bt == at {
			return true
		}
	case map[string]interface{}:
		bt := bv.(map[string]interface{})
		for key := range at {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		for key := range bt {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		return true
	case []interface{}:
		bt := bv.([]interface{})
		if len(bt) != len(at) {
			return false
		}
		for key := range at {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		for key := range bt {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		return true
	}
	return false
}

func makePath(path string, newPart interface{}) string {
	if path == "" {
		return fmt.Sprintf("/%v", newPart)
	} else {
		if strings.HasSuffix(path, "/") {
			path = path + fmt.Sprintf("%v", newPart)
		} else {
			path = path + fmt.Sprintf("/%v", newPart)
		}
	}
	return path
}

// diff returns the (recursive) difference between a and b as an array of JsonPatchOperations.
func diff(a, b map[string]interface{}, path string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
	for key, bv := range b {
		p := makePath(path, key)
		av, ok := a[key]
		// value was added
		if !ok {
			patch = append(patch, NewPatch("add", p, bv))
			continue
		}
		// If types have changed, replace completely
		if reflect.TypeOf(av) != reflect.TypeOf(bv) {
			patch = append(patch, NewPatch("replace", p, bv))
			continue
		}
		// Types are the same, compare values
		var err error
		patch, err = handleValues(av, bv, p, patch)
		if err != nil {
			return nil, err
		}
	}
	// Now add all deleted values as nil
	for key := range a {
		_, found := b[key]
		if !found {
			p := makePath(path, key)

			patch = append(patch, NewPatch("remove", p, nil))
		}
	}
	return patch, nil
}

func handleValues(av, bv interface{}, p string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
	var err error
	switch at := av.(type) {
	case map[string]interface{}:
		bt := bv.(map[string]interface{})
		patch, err = diff(at, bt, p, patch)
		if err != nil {
			return nil, err
		}
	case string, float64, bool:
		if !matchesValue(av, bv) {
			patch = append(patch, NewPatch("replace", p, bv))
		}
	case []interface{}:
		bt, ok := bv.([]interface{})
		if !ok {
			// array replaced by non-array
			patch = append(patch, NewPatch("replace", p, bv))
		} else if len(at) != len(bt) {
			// arrays are not the same length
			patch = append(patch, compareArray(at, bt, p)...)

		} else {
			for i := range bt {
				patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
				if err != nil {
					return nil, err
				}
			}
		}
	case nil:
		switch bv.(type) {
		case nil:
			// Both nil, fine.
		default:
			patch = append(patch, NewPatch("add", p, bv))
		}
	default:
		panic(fmt.Sprintf("Unknown type:%T ", av))
	}
	return patch, nil
}

func compareArray(av, bv []interface{}, p string) []JsonPatchOperation {
	retval := []JsonPatchOperation{}
	//	var err error
	for i, v := range av {
		found := false
		for _, v2 := range bv {
			if reflect.DeepEqual(v, v2) {
				found = true
				break
			}
		}
		if !found {
			retval = append(retval, NewPatch("remove", makePath(p, i), nil))
		}
	}

	for i, v := range bv {
		found := false
		for _, v2 := range av {
			if reflect.DeepEqual(v, v2) {
				found = true
				break
			}
		}
		if !found {
			retval = append(retval, NewPatch("add", makePath(p, i), v))
		}
	}

	return retval
}
<commit_msg>encode keys (support rfc6901#section-4)<commit_after>package jsonpatch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
)

var errBadJSONDoc = fmt.Errorf("Invalid JSON Document")

type JsonPatchOperation struct {
	Operation string      `json:"op"`
	Path      string      `json:"path"`
	Value     interface{} `json:"value,omitempty"`
}

func (j *JsonPatchOperation) Json() string {
	b, _ := json.Marshal(j)
	return string(b)
}

func (j *JsonPatchOperation) MarshalJSON() ([]byte, error) {
	var b bytes.Buffer
	b.WriteString("{")
	b.WriteString(fmt.Sprintf(`"op":"%s"`, j.Operation))
	b.WriteString(fmt.Sprintf(`,"path":"%s"`, j.Path))
	// Consider omitting Value for non-nullable operations.
	if j.Value != nil || j.Operation == "replace" || j.Operation == "add" {
		v, err := json.Marshal(j.Value)
		if err != nil {
			return nil, err
		}
		b.WriteString(`,"value":`)
		b.Write(v)
	}
	b.WriteString("}")
	return b.Bytes(), nil
}

type ByPath []JsonPatchOperation

func (a ByPath) Len() int           { return len(a) }
func (a ByPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }

func NewPatch(operation, path string, value interface{}) JsonPatchOperation {
	return JsonPatchOperation{Operation: operation, Path: path, Value: value}
}

// CreatePatch creates a patch as specified in http://jsonpatch.com/
//
// 'a' is original, 'b' is the modified document. Both are to be given as json encoded content.
// The function will return an array of JsonPatchOperations
//
// An error will be returned if any of the two documents are invalid.
func CreatePatch(a, b []byte) ([]JsonPatchOperation, error) {
	aI := map[string]interface{}{}
	bI := map[string]interface{}{}
	err := json.Unmarshal(a, &aI)
	if err != nil {
		return nil, errBadJSONDoc
	}
	err = json.Unmarshal(b, &bI)
	if err != nil {
		return nil, errBadJSONDoc
	}
	return diff(aI, bI, "", []JsonPatchOperation{})
}

// Returns true if the values matches (must be json types)
// The types of the values must match, otherwise it will always return false
// If two map[string]interface{} are given, all elements must match.
func matchesValue(av, bv interface{}) bool {
	if reflect.TypeOf(av) != reflect.TypeOf(bv) {
		return false
	}
	switch at := av.(type) {
	case string:
		bt := bv.(string)
		if bt == at {
			return true
		}
	case float64:
		bt := bv.(float64)
		if bt == at {
			return true
		}
	case bool:
		bt := bv.(bool)
		if bt == at {
			return true
		}
	case map[string]interface{}:
		bt := bv.(map[string]interface{})
		for key := range at {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		for key := range bt {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		return true
	case []interface{}:
		bt := bv.([]interface{})
		if len(bt) != len(at) {
			return false
		}
		for key := range at {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		for key := range bt {
			if !matchesValue(at[key], bt[key]) {
				return false
			}
		}
		return true
	}
	return false
}

// From http://tools.ietf.org/html/rfc6901#section-4 :
//
// Evaluation of each reference token begins by decoding any escaped
// character sequence.  This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
// occurrence of the sequence '~0' to '~'.
//   TODO decode support:
//   var rfc6901Decoder = strings.NewReplacer("~1", "/", "~0", "~")

var rfc6901Encoder = strings.NewReplacer("~", "~0", "/", "~1")

func makePath(path string, newPart interface{}) string {
	key := rfc6901Encoder.Replace(fmt.Sprintf("%v", newPart))
	if path == "" {
		return "/" + key
	}
	if strings.HasSuffix(path, "/") {
		return path + key
	}
	return path + "/" + key
}

// diff returns the (recursive) difference between a and b as an array of JsonPatchOperations.
func diff(a, b map[string]interface{}, path string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
	for key, bv := range b {
		p := makePath(path, key)
		av, ok := a[key]
		// value was added
		if !ok {
			patch = append(patch, NewPatch("add", p, bv))
			continue
		}
		// If types have changed, replace completely
		if reflect.TypeOf(av) != reflect.TypeOf(bv) {
			patch = append(patch, NewPatch("replace", p, bv))
			continue
		}
		// Types are the same, compare values
		var err error
		patch, err = handleValues(av, bv, p, patch)
		if err != nil {
			return nil, err
		}
	}
	// Now add all deleted values as nil
	for key := range a {
		_, found := b[key]
		if !found {
			p := makePath(path, key)

			patch = append(patch, NewPatch("remove", p, nil))
		}
	}
	return patch, nil
}

func handleValues(av, bv interface{}, p string, patch []JsonPatchOperation) ([]JsonPatchOperation, error) {
	var err error
	switch at := av.(type) {
	case map[string]interface{}:
		bt := bv.(map[string]interface{})
		patch, err = diff(at, bt, p, patch)
		if err != nil {
			return nil, err
		}
	case string, float64, bool:
		if !matchesValue(av, bv) {
			patch = append(patch, NewPatch("replace", p, bv))
		}
	case []interface{}:
		bt, ok := bv.([]interface{})
		if !ok {
			// array replaced by non-array
			patch = append(patch, NewPatch("replace", p, bv))
		} else if len(at) != len(bt) {
			// arrays are not the same length
			patch = append(patch, compareArray(at, bt, p)...)

		} else {
			for i := range bt {
				patch, err = handleValues(at[i], bt[i], makePath(p, i), patch)
				if err != nil {
					return nil, err
				}
			}
		}
	case nil:
		switch bv.(type) {
		case nil:
			// Both nil, fine.
		default:
			patch = append(patch, NewPatch("add", p, bv))
		}
	default:
		panic(fmt.Sprintf("Unknown type:%T ", av))
	}
	return patch, nil
}

func compareArray(av, bv []interface{}, p string) []JsonPatchOperation {
	retval := []JsonPatchOperation{}
	//	var err error
	for i, v := range av {
		found := false
		for _, v2 := range bv {
			if reflect.DeepEqual(v, v2) {
				found = true
				break
			}
		}
		if !found {
			retval = append(retval, NewPatch("remove", makePath(p, i), nil))
		}
	}

	for i, v := range bv {
		found := false
		for _, v2 := range av {
			if reflect.DeepEqual(v, v2) {
				found = true
				break
			}
		}
		if !found {
			retval = append(retval, NewPatch("add", makePath(p, i), v))
		}
	}

	return retval
}
<|endoftext|>


<commit_before>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package jsre provides execution environment for JavaScript.
package jsre

import (
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/robertkrimen/otto"
)

/*
JSRE is a generic JS runtime environment embedding the otto JS interpreter.
It provides some helper functions to
- load code from files
- run code snippets
- require libraries
- bind native go objects
*/
type JSRE struct {
	assetPath     string
	evalQueue     chan *evalReq
	stopEventLoop chan bool
	loopWg        sync.WaitGroup
}

// jsTimer is a single timer instance with a callback function
type jsTimer struct {
	timer    *time.Timer
	duration time.Duration
	interval bool
	call     otto.FunctionCall
}

// evalReq is a serialized vm execution request processed by runEventLoop.
type evalReq struct {
	fn   func(vm *otto.Otto)
	done chan bool
}

// runtime must be stopped with Stop() after use and cannot be used after stopping
func New(assetPath string) *JSRE {
	re := &JSRE{
		assetPath:     assetPath,
		evalQueue:     make(chan *evalReq),
		stopEventLoop: make(chan bool),
	}
	re.loopWg.Add(1)
	go re.runEventLoop()
	re.Set("loadScript", re.loadScript)
	re.Set("inspect", prettyPrintJS)
	return re
}

// This function runs the main event loop from a goroutine that is started
// when JSRE is created. Use Stop() before exiting to properly stop it.
// The event loop processes vm access requests from the evalQueue in a
// serialized way and calls timer callback functions at the appropriate time.

// Exported functions always access the vm through the event queue. You can
// call the functions of the otto vm directly to circumvent the queue. These
// functions should be used if and only if running a routine that was already
// called from JS through an RPC call.
func (self *JSRE) runEventLoop() {
	vm := otto.New()
	registry := map[*jsTimer]*jsTimer{}
	ready := make(chan *jsTimer)

	newTimer := func(call otto.FunctionCall, interval bool) (*jsTimer, otto.Value) {

		delay, _ := call.Argument(1).ToInteger()
		if 0 >= delay {
			delay = 1
		}
		timer := &jsTimer{
			duration: time.Duration(delay) * time.Millisecond,
			call:     call,
			interval: interval,
		}
		registry[timer] = timer

		timer.timer = time.AfterFunc(timer.duration, func() {
			ready <- timer
		})

		value, err := call.Otto.ToValue(timer)
		if err != nil {
			panic(err)
		}

		return timer, value
	}

	setTimeout := func(call otto.FunctionCall) otto.Value {
		_, value := newTimer(call, false)
		return value
	}

	setInterval := func(call otto.FunctionCall) otto.Value {
		_, value := newTimer(call, true)
		return value
	}

	clearTimeout := func(call otto.FunctionCall) otto.Value {
		timer, _ := call.Argument(0).Export()
		if timer, ok := timer.(*jsTimer); ok {
			timer.timer.Stop()
			delete(registry, timer)
		}
		return otto.UndefinedValue()
	}
	vm.Set("setTimeout", setTimeout)
	vm.Set("setInterval", setInterval)
	vm.Set("clearTimeout", clearTimeout)
	vm.Set("clearInterval", clearTimeout)

	var waitForCallbacks bool

loop:
	for {
		select {
		case timer := <-ready:
			// execute callback, remove/reschedule the timer
			var arguments []interface{}
			if len(timer.call.ArgumentList) > 2 {
				tmp := timer.call.ArgumentList[2:]
				arguments = make([]interface{}, 2+len(tmp))
				for i, value := range tmp {
					arguments[i+2] = value
				}
			} else {
				arguments = make([]interface{}, 1)
			}
			arguments[0] = timer.call.ArgumentList[0]
			_, err := vm.Call(`Function.call.call`, nil, arguments...)
			if err != nil {
				fmt.Println("js error:", err, arguments)
			}
			if timer.interval {
				timer.timer.Reset(timer.duration)
			} else {
				delete(registry, timer)
				if waitForCallbacks && (len(registry) == 0) {
					break loop
				}
			}
		case req := <-self.evalQueue:
			// run the code, send the result back
			req.fn(vm)
			close(req.done)
			if waitForCallbacks && (len(registry) == 0) {
				break loop
			}
		case waitForCallbacks = <-self.stopEventLoop:
			if !waitForCallbacks || (len(registry) == 0) {
				break loop
			}
		}
	}

	for _, timer := range registry {
		timer.timer.Stop()
		delete(registry, timer)
	}

	self.loopWg.Done()
}

// do schedules the given function on the event loop.
func (self *JSRE) do(fn func(*otto.Otto)) {
	done := make(chan bool)
	req := &evalReq{fn, done}
	self.evalQueue <- req
	<-done
}

// stops the event loop before exit, optionally waits for all timers to expire
func (self *JSRE) Stop(waitForCallbacks bool) {
	self.stopEventLoop <- waitForCallbacks
	self.loopWg.Wait()
}

// Exec(file) loads and runs the contents of a file
// if a relative path is given, the jsre's assetPath is used
func (self *JSRE) Exec(file string) error {
	code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file))
	if err != nil {
		return err
	}
	self.do(func(vm *otto.Otto) { _, err = vm.Run(code) })
	return err
}

// Bind assigns value v to a variable in the JS environment
// This method is deprecated, use Set.
func (self *JSRE) Bind(name string, v interface{}) error {
	return self.Set(name, v)
}

// Run runs a piece of JS code.
func (self *JSRE) Run(code string) (v otto.Value, err error) {
	self.do(func(vm *otto.Otto) { v, err = vm.Run(code) })
	return v, err
}

// Get returns the value of a variable in the JS environment.
func (self *JSRE) Get(ns string) (v otto.Value, err error) {
	self.do(func(vm *otto.Otto) { v, err = vm.Get(ns) })
	return v, err
}

// Set assigns value v to a variable in the JS environment.
func (self *JSRE) Set(ns string, v interface{}) (err error) {
	self.do(func(vm *otto.Otto) { err = vm.Set(ns, v) })
	return err
}

// loadScript executes a JS script from inside the currently executing JS code.
func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
	file, err := call.Argument(0).ToString()
	if err != nil {
		// TODO: throw exception
		return otto.FalseValue()
	}
	file = common.AbsolutePath(self.assetPath, file)
	source, err := ioutil.ReadFile(file)
	if err != nil {
		// TODO: throw exception
		return otto.FalseValue()
	}
	if _, err := compileAndRun(call.Otto, file, source); err != nil {
		// TODO: throw exception
		fmt.Println("err:", err)
		return otto.FalseValue()
	}
	// TODO: return evaluation result
	return otto.TrueValue()
}

// EvalAndPrettyPrint evaluates code and pretty prints the result to
// standard output.
func (self *JSRE) EvalAndPrettyPrint(code string) (err error) {
	self.do(func(vm *otto.Otto) {
		var val otto.Value
		val, err = vm.Run(code)
		if err != nil {
			return
		}
		prettyPrint(vm, val)
		fmt.Println()
	})
	return err
}

// Compile compiles and then runs a piece of JS code.
func (self *JSRE) Compile(filename string, src interface{}) (err error) {
	self.do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) })
	return err
}

func compileAndRun(vm *otto.Otto, filename string, src interface{}) (otto.Value, error) {
	script, err := vm.Compile(filename, src)
	if err != nil {
		return otto.Value{}, err
	}
	return vm.Run(script)
}
<commit_msg>jsre: timer bugfix when clearInterval was called from within the callback<commit_after>// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package jsre provides execution environment for JavaScript.
package jsre

import (
	"fmt"
	"io/ioutil"
	"sync"
	"time"

	"github.com/ethereum/go-ethereum/common"
	"github.com/robertkrimen/otto"
)

/*
JSRE is a generic JS runtime environment embedding the otto JS interpreter.
It provides some helper functions to
- load code from files
- run code snippets
- require libraries
- bind native go objects
*/
type JSRE struct {
	assetPath     string
	evalQueue     chan *evalReq
	stopEventLoop chan bool
	loopWg        sync.WaitGroup
}

// jsTimer is a single timer instance with a callback function
type jsTimer struct {
	timer    *time.Timer
	duration time.Duration
	interval bool
	call     otto.FunctionCall
}

// evalReq is a serialized vm execution request processed by runEventLoop.
type evalReq struct {
	fn   func(vm *otto.Otto)
	done chan bool
}

// runtime must be stopped with Stop() after use and cannot be used after stopping
func New(assetPath string) *JSRE {
	re := &JSRE{
		assetPath:     assetPath,
		evalQueue:     make(chan *evalReq),
		stopEventLoop: make(chan bool),
	}
	re.loopWg.Add(1)
	go re.runEventLoop()
	re.Set("loadScript", re.loadScript)
	re.Set("inspect", prettyPrintJS)
	return re
}

// This function runs the main event loop from a goroutine that is started
// when JSRE is created. Use Stop() before exiting to properly stop it.
// The event loop processes vm access requests from the evalQueue in a
// serialized way and calls timer callback functions at the appropriate time.

// Exported functions always access the vm through the event queue. You can
// call the functions of the otto vm directly to circumvent the queue. These
// functions should be used if and only if running a routine that was already
// called from JS through an RPC call.
func (self *JSRE) runEventLoop() {
	vm := otto.New()
	registry := map[*jsTimer]*jsTimer{}
	ready := make(chan *jsTimer)

	newTimer := func(call otto.FunctionCall, interval bool) (*jsTimer, otto.Value) {

		delay, _ := call.Argument(1).ToInteger()
		if 0 >= delay {
			delay = 1
		}
		timer := &jsTimer{
			duration: time.Duration(delay) * time.Millisecond,
			call:     call,
			interval: interval,
		}
		registry[timer] = timer

		timer.timer = time.AfterFunc(timer.duration, func() {
			ready <- timer
		})

		value, err := call.Otto.ToValue(timer)
		if err != nil {
			panic(err)
		}

		return timer, value
	}

	setTimeout := func(call otto.FunctionCall) otto.Value {
		_, value := newTimer(call, false)
		return value
	}

	setInterval := func(call otto.FunctionCall) otto.Value {
		_, value := newTimer(call, true)
		return value
	}

	clearTimeout := func(call otto.FunctionCall) otto.Value {
		timer, _ := call.Argument(0).Export()
		if timer, ok := timer.(*jsTimer); ok {
			timer.timer.Stop()
			delete(registry, timer)
		}
		return otto.UndefinedValue()
	}
	vm.Set("setTimeout", setTimeout)
	vm.Set("setInterval", setInterval)
	vm.Set("clearTimeout", clearTimeout)
	vm.Set("clearInterval", clearTimeout)

	var waitForCallbacks bool

loop:
	for {
		select {
		case timer := <-ready:
			// execute callback, remove/reschedule the timer
			var arguments []interface{}
			if len(timer.call.ArgumentList) > 2 {
				tmp := timer.call.ArgumentList[2:]
				arguments = make([]interface{}, 2+len(tmp))
				for i, value := range tmp {
					arguments[i+2] = value
				}
			} else {
				arguments = make([]interface{}, 1)
			}
			arguments[0] = timer.call.ArgumentList[0]
			_, err := vm.Call(`Function.call.call`, nil, arguments...)
			if err != nil {
				fmt.Println("js error:", err, arguments)
			}

			_, inreg := registry[timer] // when clearInterval is called from within the callback don't reset it
			if timer.interval && inreg {
				timer.timer.Reset(timer.duration)
			} else {
				delete(registry, timer)
				if waitForCallbacks && (len(registry) == 0) {
					break loop
				}
			}
		case req := <-self.evalQueue:
			// run the code, send the result back
			req.fn(vm)
			close(req.done)
			if waitForCallbacks && (len(registry) == 0) {
				break loop
			}
		case waitForCallbacks = <-self.stopEventLoop:
			if !waitForCallbacks || (len(registry) == 0) {
				break loop
			}
		}
	}

	for _, timer := range registry {
		timer.timer.Stop()
		delete(registry, timer)
	}

	self.loopWg.Done()
}

// do schedules the given function on the event loop.
func (self *JSRE) do(fn func(*otto.Otto)) {
	done := make(chan bool)
	req := &evalReq{fn, done}
	self.evalQueue <- req
	<-done
}

// stops the event loop before exit, optionally waits for all timers to expire
func (self *JSRE) Stop(waitForCallbacks bool) {
	self.stopEventLoop <- waitForCallbacks
	self.loopWg.Wait()
}

// Exec(file) loads and runs the contents of a file
// if a relative path is given, the jsre's assetPath is used
func (self *JSRE) Exec(file string) error {
	code, err := ioutil.ReadFile(common.AbsolutePath(self.assetPath, file))
	if err != nil {
		return err
	}
	self.do(func(vm *otto.Otto) { _, err = vm.Run(code) })
	return err
}

// Bind assigns value v to a variable in the JS environment
// This method is deprecated, use Set.
func (self *JSRE) Bind(name string, v interface{}) error {
	return self.Set(name, v)
}

// Run runs a piece of JS code.
func (self *JSRE) Run(code string) (v otto.Value, err error) {
	self.do(func(vm *otto.Otto) { v, err = vm.Run(code) })
	return v, err
}

// Get returns the value of a variable in the JS environment.
func (self *JSRE) Get(ns string) (v otto.Value, err error) {
	self.do(func(vm *otto.Otto) { v, err = vm.Get(ns) })
	return v, err
}

// Set assigns value v to a variable in the JS environment.
func (self *JSRE) Set(ns string, v interface{}) (err error) {
	self.do(func(vm *otto.Otto) { err = vm.Set(ns, v) })
	return err
}

// loadScript executes a JS script from inside the currently executing JS code.
func (self *JSRE) loadScript(call otto.FunctionCall) otto.Value {
	file, err := call.Argument(0).ToString()
	if err != nil {
		// TODO: throw exception
		return otto.FalseValue()
	}
	file = common.AbsolutePath(self.assetPath, file)
	source, err := ioutil.ReadFile(file)
	if err != nil {
		// TODO: throw exception
		return otto.FalseValue()
	}
	if _, err := compileAndRun(call.Otto, file, source); err != nil {
		// TODO: throw exception
		fmt.Println("err:", err)
		return otto.FalseValue()
	}
	// TODO: return evaluation result
	return otto.TrueValue()
}

// EvalAndPrettyPrint evaluates code and pretty prints the result to
// standard output.
func (self *JSRE) EvalAndPrettyPrint(code string) (err error) {
	self.do(func(vm *otto.Otto) {
		var val otto.Value
		val, err = vm.Run(code)
		if err != nil {
			return
		}
		prettyPrint(vm, val)
		fmt.Println()
	})
	return err
}

// Compile compiles and then runs a piece of JS code.
func (self *JSRE) Compile(filename string, src interface{}) (err error) {
	self.do(func(vm *otto.Otto) { _, err = compileAndRun(vm, filename, src) })
	return err
}

func compileAndRun(vm *otto.Otto, filename string, src interface{}) (otto.Value, error) {
	script, err := vm.Compile(filename, src)
	if err != nil {
		return otto.Value{}, err
	}
	return vm.Run(script)
}
<|endoftext|>


<commit_before>// Copyright (C) 2016  Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package openconfig

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

func joinPath(path *Path) string {
	return strings.Join(path.Element, "/")
}

func convertUpdate(update *Update) (interface{}, error) {
	switch update.Value.Type {
	case Type_JSON:
		var value interface{}
		err := json.Unmarshal(update.Value.Value, &value)
		if err != nil {
			return nil, fmt.Errorf("Malformed JSON update %q in %s",
				update.Value.Value, update)
		}
		return value, nil
	case Type_BYTES:
		return strconv.Quote(string(update.Value.Value)), nil
	default:
		return nil,
			fmt.Errorf("Unhandled type of value %v in %s", update.Value.Type, update)
	}
}

// SubscribeResponseToJSON converts a SubscribeResponse into a JSON string
func SubscribeResponseToJSON(resp *SubscribeResponse) (string, error) {
	m := make(map[string]interface{}, 1)
	var err error
	switch resp := resp.Response.(type) {
	case *SubscribeResponse_Update:
		notif := resp.Update
		m["timestamp"] = notif.Timestamp
		m["path"] = "/" + joinPath(notif.Prefix)
		if len(notif.Update) != 0 {
			updates := make(map[string]interface{}, len(notif.Update))
			for _, update := range notif.Update {
				updates[joinPath(update.Path)], err = convertUpdate(update)
				if err != nil {
					return "", err
				}
			}
			m["updates"] = updates
		}
		if len(notif.Delete) != 0 {
			deletes := make([]string, len(notif.Delete))
			for i, del := range notif.Delete {
				deletes[i] = joinPath(del)
			}
			m["deletes"] = deletes
		}
		m = map[string]interface{}{"notification": m}
	case *SubscribeResponse_Heartbeat:
		m["heartbeat"] = resp.Heartbeat.Interval
	case *SubscribeResponse_SyncResponse:
		m["syncResponse"] = resp.SyncResponse
	default:
		return "", fmt.Errorf("Unknown type of response: %T: %s", resp, resp)
	}
	js, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		return "", err
	}
	return string(js), nil
}

// EscapeFunc is the escaping method for attribute names
type EscapeFunc func(k string) string

// NotificationToMap maps a Notification into a nested map of entities
func NotificationToMap(notification *Notification,
	escape EscapeFunc) (map[string]interface{}, error) {
	if escape == nil {
		escape = func(name string) string {
			return name
		}
	}
	prefix := notification.GetPrefix()
	root := map[string]interface{}{
		"_timestamp": notification.Timestamp,
	}
	prefixLeaf := root
	if prefix != nil {
		parent := root
		for _, element := range prefix.Element {
			node := map[string]interface{}{}
			parent[escape(element)] = node
			parent = node
		}
		prefixLeaf = parent
	}
	for _, update := range notification.GetUpdate() {
		parent := prefixLeaf
		path := update.GetPath()
		elementLen := len(path.Element)
		if elementLen > 1 {
			for _, element := range path.Element[:elementLen-2] {
				escapedElement := escape(element)
				node, found := parent[escapedElement]
				if !found {
					node = map[string]interface{}{}
					parent[escapedElement] = node
				}
				var ok bool
				parent, ok = node.(map[string]interface{})
				if !ok {
					return nil, fmt.Errorf(
						"Node %s is of type %T (expected map[string]interface traversing %q)",
						element, node, path.Element)
				}
			}
		}
		value := update.GetValue()
		if value.Type != Type_JSON {
			return nil, fmt.Errorf("Unexpected value type %s for path %v",
				value.Type, path)
		}
		var unmarshaledValue interface{}
		if err := json.Unmarshal(value.Value, &unmarshaledValue); err != nil {
			return nil, err
		}
		parent[escape(path.Element[elementLen-1])] = unmarshaledValue
	}
	return root, nil
}

// NotificationToJSONDocument maps a Notification into a single JSON document
func NotificationToJSONDocument(notification *Notification,
	escape EscapeFunc) ([]byte, error) {
	m, err := NotificationToMap(notification, escape)
	if err != nil {
		return nil, err
	}
	return json.Marshal(m)
}
<commit_msg>openconfig: escape keys in JSON values<commit_after>// Copyright (C) 2016  Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package openconfig

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
)

func joinPath(path *Path) string {
	return strings.Join(path.Element, "/")
}

func convertUpdate(update *Update) (interface{}, error) {
	switch update.Value.Type {
	case Type_JSON:
		var value interface{}
		err := json.Unmarshal(update.Value.Value, &value)
		if err != nil {
			return nil, fmt.Errorf("Malformed JSON update %q in %s",
				update.Value.Value, update)
		}
		return value, nil
	case Type_BYTES:
		return strconv.Quote(string(update.Value.Value)), nil
	default:
		return nil,
			fmt.Errorf("Unhandled type of value %v in %s", update.Value.Type, update)
	}
}

// SubscribeResponseToJSON converts a SubscribeResponse into a JSON string
func SubscribeResponseToJSON(resp *SubscribeResponse) (string, error) {
	m := make(map[string]interface{}, 1)
	var err error
	switch resp := resp.Response.(type) {
	case *SubscribeResponse_Update:
		notif := resp.Update
		m["timestamp"] = notif.Timestamp
		m["path"] = "/" + joinPath(notif.Prefix)
		if len(notif.Update) != 0 {
			updates := make(map[string]interface{}, len(notif.Update))
			for _, update := range notif.Update {
				updates[joinPath(update.Path)], err = convertUpdate(update)
				if err != nil {
					return "", err
				}
			}
			m["updates"] = updates
		}
		if len(notif.Delete) != 0 {
			deletes := make([]string, len(notif.Delete))
			for i, del := range notif.Delete {
				deletes[i] = joinPath(del)
			}
			m["deletes"] = deletes
		}
		m = map[string]interface{}{"notification": m}
	case *SubscribeResponse_Heartbeat:
		m["heartbeat"] = resp.Heartbeat.Interval
	case *SubscribeResponse_SyncResponse:
		m["syncResponse"] = resp.SyncResponse
	default:
		return "", fmt.Errorf("Unknown type of response: %T: %s", resp, resp)
	}
	js, err := json.MarshalIndent(m, "", "  ")
	if err != nil {
		return "", err
	}
	return string(js), nil
}

// EscapeFunc is the escaping method for attribute names
type EscapeFunc func(k string) string

// escapeValue looks for maps in an interface and escapes their keys
func escapeValue(value interface{}, escape EscapeFunc) interface{} {
	valueMap, ok := value.(map[string]interface{})
	if !ok {
		return value
	}
	escapedMap := make(map[string]interface{}, len(valueMap))
	for k, v := range valueMap {
		escapedKey := escape(k)
		escapedMap[escapedKey] = escapeValue(v, escape)
	}
	return escapedMap
}

// NotificationToMap maps a Notification into a nested map of entities
func NotificationToMap(notification *Notification,
	escape EscapeFunc) (map[string]interface{}, error) {
	if escape == nil {
		escape = func(name string) string {
			return name
		}
	}
	prefix := notification.GetPrefix()
	root := map[string]interface{}{
		"_timestamp": notification.Timestamp,
	}
	prefixLeaf := root
	if prefix != nil {
		parent := root
		for _, element := range prefix.Element {
			node := map[string]interface{}{}
			parent[escape(element)] = node
			parent = node
		}
		prefixLeaf = parent
	}
	for _, update := range notification.GetUpdate() {
		parent := prefixLeaf
		path := update.GetPath()
		elementLen := len(path.Element)
		if elementLen > 1 {
			for _, element := range path.Element[:elementLen-2] {
				escapedElement := escape(element)
				node, found := parent[escapedElement]
				if !found {
					node = map[string]interface{}{}
					parent[escapedElement] = node
				}
				var ok bool
				parent, ok = node.(map[string]interface{})
				if !ok {
					return nil, fmt.Errorf(
						"Node %s is of type %T (expected map[string]interface traversing %q)",
						element, node, path.Element)
				}
			}
		}
		value := update.GetValue()
		if value.Type != Type_JSON {
			return nil, fmt.Errorf("Unexpected value type %s for path %v",
				value.Type, path)
		}
		var unmarshaledValue interface{}
		if err := json.Unmarshal(value.Value, &unmarshaledValue); err != nil {
			return nil, err
		}
		parent[escape(path.Element[elementLen-1])] = escapeValue(unmarshaledValue,
			escape)
	}
	return root, nil
}

// NotificationToJSONDocument maps a Notification into a single JSON document
func NotificationToJSONDocument(notification *Notification,
	escape EscapeFunc) ([]byte, error) {
	m, err := NotificationToMap(notification, escape)
	if err != nil {
		return nil, err
	}
	return json.Marshal(m)
}
<|endoftext|>


<commit_before>// Tideland Go REST Server Library - JSON Web Token - Cache
//
// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package jwt

//--------------------
// IMPORTS
//--------------------

import (
	"sync"
	"time"
)

//--------------------
// CACHE
//--------------------

// Cache provides a caching for tokens so that these
// don't have to be decoded or verified multiple times.
type Cache interface {
	// Get tries to retrieve a token from the cache.
	Get(token string) (JWT, bool)

	// Put adds a token to the cache.
	Put(jwt JWT)
}

// cacheEntry manages a token and its access time.
type cacheEntry struct {
	jwt      JWT
	accessed time.Time
}

// cache implements Cache.
type cache struct {
	mutex   sync.Mutex
	cleanup time.Duration
	leeway  time.Duration
	entries map[string]*cacheEntry
}

// NewCache creates a new JWT caching. It takes two
// durations. The first one is the time a token hasn't
// been used anymore before it is cleaned up. The second
// one is the leeway taken for token time validations.
func NewCache(cleanup, leeway time.Duration) Cache {
	c := &cache{
		cleanup: cleanup,
		leeway:  leeway,
		entries: map[string]*cacheEntry{},
	}
	// TODO Start cleanup goroutine.
	return c
}

// Get implements the Cache interface.
func (c *cache) Get(token string) (JWT, bool) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	entry, ok := c.entries[token]
	if !ok {
		return nil, false
	}
	if entry.jwt.IsValid(c.leeway) {
		entry.accessed = time.Now()
		return entry.jwt, true
	}
	// Remove invalid token.
	delete(c.entries, token)
	return nil, false
}

// Put implements the Cache interface.
func (c *cache) Put(jwt JWT) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if jwt.IsValid(c.leeway) {
		c.entries[jwt.String()] = &cacheEntry{jwt, time.Now()}
	}
}

// EOF
<commit_msg>Added cleanup to cache<commit_after>// Tideland Go REST Server Library - JSON Web Token - Cache
//
// Copyright (C) 2016 Frank Mueller / Tideland / Oldenburg / Germany
//
// All rights reserved. Use of this source code is governed
// by the new BSD license.

package jwt

//--------------------
// IMPORTS
//--------------------

import (
	"sync"
	"time"

	"github.com/tideland/golib/loop"
)

//--------------------
// CACHE
//--------------------

// Cache provides a caching for tokens so that these
// don't have to be decoded or verified multiple times.
type Cache interface {
	// Get tries to retrieve a token from the cache.
	Get(token string) (JWT, bool)

	// Put adds a token to the cache.
	Put(jwt JWT)

	// Stop tells the cache to end working.
	Stop() error
}

// cacheEntry manages a token and its access time.
type cacheEntry struct {
	jwt      JWT
	accessed time.Time
}

// cache implements Cache.
type cache struct {
	mutex   sync.Mutex
	ttl     time.Duration
	leeway  time.Duration
	entries map[string]*cacheEntry
	loop    loop.Loop
}

// NewCache creates a new JWT caching. It takes two
// durations. The first one is the time a token hasn't
// been used anymore before it is cleaned up. The second
// one is the leeway taken for token time validations.
func NewCache(ttl, leeway time.Duration) Cache {
	c := &cache{
		ttl:     ttl,
		leeway:  leeway,
		entries: map[string]*cacheEntry{},
	}
	c.loop = loop.Go(c.backendLoop, "jwt", "cache")
	return c
}

// Get implements the Cache interface.
func (c *cache) Get(token string) (JWT, bool) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	entry, ok := c.entries[token]
	if !ok {
		return nil, false
	}
	if entry.jwt.IsValid(c.leeway) {
		entry.accessed = time.Now()
		return entry.jwt, true
	}
	// Remove invalid token.
	delete(c.entries, token)
	return nil, false
}

// Put implements the Cache interface.
func (c *cache) Put(jwt JWT) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	if jwt.IsValid(c.leeway) {
		c.entries[jwt.String()] = &cacheEntry{jwt, time.Now()}
	}
}

// Stop implements the Cache interface.
func (c *cache) Stop() error {
	return c.loop.Stop()
}

// backendLoop runs a cleaning session every five minutes.
func (c *cache) backendLoop(l loop.Loop) error {
	defer func() {
		// Some cleanup after stop or error.
		c.ttl = 0
		c.leeway = 0
		c.entries = nil
	}()
	ticker := time.NewTicker(5 * time.Minute)
	for {
		select {
		case <-l.ShallStop():
			return nil
		case <-ticker.C:
			c.cleanup()
		}
	}
}

// cleanup checks for invalid or unused tokens.
func (c *cache) cleanup() {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	valids := map[string]*cacheEntry{}
	now := time.Now()
	for token, entry := range c.entries {
		if entry.jwt.IsValid(c.leeway) {
			if entry.accessed.Add(c.ttl).Before(now) {
				// Everything fine.
				valids[token] = entry
			}
		}
	}
	c.entries = valids
}

// EOF
<|endoftext|>