<commit_before>package sortedmap

import (
	"testing"
	"time"
)

const (
	nilBoundValsErr  = "accepted nil bound values"
	generalBoundsErr = "between bounds error"
	nilValErr        = "nil value!"
	nonNilValErr     = "non-nil value"
	runawayIterErr   = "runaway iterator!"
)

var maxTime = time.Unix(1<<63-62135596801, 999999999)

func TestIterCh(t *testing.T) {
	if _, _, err := newSortedMapFromRandRecords(1000); err != nil {
		t.Fatal(err)
	}
}

func TestIterChTimeout(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	timeout := 1 * time.Microsecond
	sleepDur := 10 * time.Millisecond

	params := IterChParams{
		SendTimeout: timeout,
	}

	ch, err := sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}

	params.LowerBound = time.Time{}
	params.UpperBound = maxTime

	ch, err = sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}
}

func TestReversedIterChTimeout(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	timeout := 1 * time.Microsecond
	sleepDur := 10 * time.Millisecond

	params := IterChParams{
		Reversed:    true,
		SendTimeout: timeout,
	}

	ch, err := sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestReversedIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}

	params.LowerBound = time.Time{}
	params.UpperBound = maxTime

	ch, err = sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestReversedIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}
}

func TestBoundedIterCh(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	reversed := false
	earlierDate := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Date(5321, 1, 1, 0, 0, 0, 0, time.UTC)

	ch, err := sm.BoundedIterCh(reversed, nil, nil)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, time.Time{}, maxTime)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, earlierDate, time.Now())
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, time.Now(), laterDate)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	if _, err := sm.BoundedIterCh(reversed, laterDate, laterDate); err == nil {
		t.Fatalf("TestBoundedIterCh failed: %v", "equal bounds values were accepted error")
	}
}

func TestCustomIterCh(t *testing.T) {
	const (
		nilBoundValsErr  = "accepted two nil bound values"
		generalBoundsErr = "only one bound value"
	)
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	reversed := true
	buffSize := 64

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	params := IterChParams{
		Reversed: reversed,
		BufSize:  buffSize,
	}

	func() {
		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			t.Fatal(err)
		}
	}()

	params = IterChParams{
		Reversed:   reversed,
		BufSize:    buffSize,
		LowerBound: earlierDate,
		UpperBound: laterDate,
	}

	func() {
		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			t.Fatal(err)
		}
	}()

	params = IterChParams{
		Reversed:   reversed,
		BufSize:    buffSize,
		LowerBound: laterDate,
		UpperBound: earlierDate,
	}

	func() {
		_, err := sm.CustomIterCh(params)
		if err == nil {
			t.Fatal(err)
		}
	}()

	reversed = false
	params = IterChParams{
		Reversed:   reversed,
		BufSize:    0,
		LowerBound: laterDate,
		UpperBound: earlierDate,
	}

	func() {
		_, err := sm.CustomIterCh(params)
		if err == nil {
			t.Fatal(err)
		}
	}()
}

func TestCancelCustomIterCh(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	func() {
		params := IterChParams{
			LowerBound: earlierDate,
			UpperBound: laterDate,
		}

		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			if err.Error() != "Channel was nil." {
				t.Fatal(err)
			}
		} else {
			t.Fatal("Channel was not closed.")
		}
	}()
}

func TestIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	sm.IterFunc(false, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestIterFunc failed: %v", nilValErr)
		}
		return true
	})
	sm.IterFunc(true, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestIterFunc failed: %v", nilValErr)
		}
		return true
	})
	i := 0
	sm.IterFunc(false, func(rec Record) bool {
		if i > 0 {
			t.Fatalf("TestIterFunc failed: %v", runawayIterErr)
		}
		i++
		return false
	})
	i = 0
	sm.IterFunc(true, func(rec Record) bool {
		if i > 0 {
			t.Fatalf("TestIterFunc failed: %v", runawayIterErr)
		}
		i++
		return false
	})
}

func TestBoundedIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	if err := sm.BoundedIterFunc(false, nil, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, nil, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, laterDate, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, earlierDate, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}
}

func TestBoundedIterFuncWithNoBoundsReturned(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	if err := sm.BoundedIterFunc(false, time.Date(5783, 1, 1, 0, 0, 0, 0, time.UTC), time.Now(), func(rec Record) bool {
		if rec.Key == nil {
			t.Fatal(nilValErr)
		}
		return false
	}); err == nil {
		t.Fatal("Values fall between or are equal to the given bounds when it should not have returned bounds.")
	}
}

func TestReversedBoundedIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	if err := sm.BoundedIterFunc(true, nil, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestReversedBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, nil, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestReversedBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, laterDate, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, earlierDate, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}
}
<commit_msg>Change Iter cancel test to read before closing<commit_after>package sortedmap

import (
	"testing"
	"time"
)

const (
	nilBoundValsErr  = "accepted nil bound values"
	generalBoundsErr = "between bounds error"
	nilValErr        = "nil value!"
	nonNilValErr     = "non-nil value"
	runawayIterErr   = "runaway iterator!"
)

var maxTime = time.Unix(1<<63-62135596801, 999999999)

func TestIterCh(t *testing.T) {
	if _, _, err := newSortedMapFromRandRecords(1000); err != nil {
		t.Fatal(err)
	}
}

func TestIterChTimeout(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	timeout := 1 * time.Microsecond
	sleepDur := 10 * time.Millisecond

	params := IterChParams{
		SendTimeout: timeout,
	}

	ch, err := sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}

	params.LowerBound = time.Time{}
	params.UpperBound = maxTime

	ch, err = sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}
}

func TestReversedIterChTimeout(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	timeout := 1 * time.Microsecond
	sleepDur := 10 * time.Millisecond

	params := IterChParams{
		Reversed:    true,
		SendTimeout: timeout,
	}

	ch, err := sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestReversedIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}

	params.LowerBound = time.Time{}
	params.UpperBound = maxTime

	ch, err = sm.CustomIterCh(params)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			for i := 0; i < 5; i++ {
				time.Sleep(sleepDur)
				rec := <-ch.Records()
				if i > 1 && rec.Key != nil {
					t.Fatalf("TestReversedIterChTimeout failed: %v: %v", nonNilValErr, rec.Key)
				}
			}
		}()
	}
}

func TestBoundedIterCh(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	reversed := false
	earlierDate := time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Date(5321, 1, 1, 0, 0, 0, 0, time.UTC)

	ch, err := sm.BoundedIterCh(reversed, nil, nil)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, time.Time{}, maxTime)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, earlierDate, time.Now())
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	ch, err = sm.BoundedIterCh(reversed, time.Now(), laterDate)
	if err != nil {
		t.Fatal(err)
	} else {
		func() {
			defer ch.Close()

			if err := verifyRecords(ch.Records(), reversed); err != nil {
				t.Fatal(err)
			}
		}()
	}

	if _, err := sm.BoundedIterCh(reversed, laterDate, laterDate); err == nil {
		t.Fatalf("TestBoundedIterCh failed: %v", "equal bounds values were accepted error")
	}
}

func TestCustomIterCh(t *testing.T) {
	const (
		nilBoundValsErr  = "accepted two nil bound values"
		generalBoundsErr = "only one bound value"
	)
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	reversed := true
	buffSize := 64

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	params := IterChParams{
		Reversed: reversed,
		BufSize:  buffSize,
	}

	func() {
		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			t.Fatal(err)
		}
	}()

	params = IterChParams{
		Reversed:   reversed,
		BufSize:    buffSize,
		LowerBound: earlierDate,
		UpperBound: laterDate,
	}

	func() {
		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			t.Fatal(err)
		}
	}()

	params = IterChParams{
		Reversed:   reversed,
		BufSize:    buffSize,
		LowerBound: laterDate,
		UpperBound: earlierDate,
	}

	func() {
		_, err := sm.CustomIterCh(params)
		if err == nil {
			t.Fatal(err)
		}
	}()

	reversed = false
	params = IterChParams{
		Reversed:   reversed,
		BufSize:    0,
		LowerBound: laterDate,
		UpperBound: earlierDate,
	}

	func() {
		_, err := sm.CustomIterCh(params)
		if err == nil {
			t.Fatal(err)
		}
	}()
}

func TestCancelCustomIterCh(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	func() {
		params := IterChParams{
			LowerBound: earlierDate,
			UpperBound: laterDate,
		}

		ch, err := sm.CustomIterCh(params)
		if err != nil {
			t.Fatal(err)
		}
		defer ch.Close()

		<-ch.Records()
		ch.Close()

		if err := verifyRecords(ch.Records(), params.Reversed); err != nil {
			if err.Error() != "Channel was nil." {
				t.Fatal(err)
			}
		} else {
			t.Fatal("Channel was not closed.")
		}
	}()
}

func TestIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	sm.IterFunc(false, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestIterFunc failed: %v", nilValErr)
		}
		return true
	})
	sm.IterFunc(true, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestIterFunc failed: %v", nilValErr)
		}
		return true
	})
	i := 0
	sm.IterFunc(false, func(rec Record) bool {
		if i > 0 {
			t.Fatalf("TestIterFunc failed: %v", runawayIterErr)
		}
		i++
		return false
	})
	i = 0
	sm.IterFunc(true, func(rec Record) bool {
		if i > 0 {
			t.Fatalf("TestIterFunc failed: %v", runawayIterErr)
		}
		i++
		return false
	})
}

func TestBoundedIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	if err := sm.BoundedIterFunc(false, nil, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, nil, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, laterDate, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(false, earlierDate, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestBoundedIterFunc failed: %v", err)
	}
}

func TestBoundedIterFuncWithNoBoundsReturned(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}
	if err := sm.BoundedIterFunc(false, time.Date(5783, 1, 1, 0, 0, 0, 0, time.UTC), time.Now(), func(rec Record) bool {
		if rec.Key == nil {
			t.Fatal(nilValErr)
		}
		return false
	}); err == nil {
		t.Fatal("Values fall between or are equal to the given bounds when it should not have returned bounds.")
	}
}

func TestReversedBoundedIterFunc(t *testing.T) {
	sm, _, err := newSortedMapFromRandRecords(1000)
	if err != nil {
		t.Fatal(err)
	}

	earlierDate := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
	laterDate := time.Now()

	if err := sm.BoundedIterFunc(true, nil, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestReversedBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, nil, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestReversedBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, laterDate, nil, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}

	if err := sm.BoundedIterFunc(true, earlierDate, laterDate, func(rec Record) bool {
		if rec.Key == nil {
			t.Fatalf("TestBoundedIterFunc failed: %v", nilValErr)
		}
		return false
	}); err != nil {
		t.Fatalf("TestReversedBoundedIterFunc failed: %v", err)
	}
}
<|endoftext|>


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

package main

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/accumulator"
)

const (
	BlobVerOff     = int64(0)
	BlobVerSz      = 1
	BlobIdOff      = BlobVerOff + BlobVerSz
	BlobIdSz       = 1
	BlobMagic      = "asnmagic"
	BlobMagicOff   = BlobIdOff + BlobIdSz
	BlobMagicSz    = 8
	BlobRandomOff  = BlobMagicOff + BlobMagicSz
	BlobRandomSz   = 32
	BlobOwnerOff   = BlobRandomOff + BlobRandomSz
	BlobAuthorOff  = BlobOwnerOff + PubEncrSz
	BlobTimeOff    = BlobAuthorOff + PubEncrSz
	BlobTimeSz     = 8
	BlobNameLenOff = BlobTimeOff + BlobTimeSz
	BlobNameLenSz  = 1
	BlobNameOff    = BlobNameLenOff + BlobNameLenSz
)

var (
	blobs struct {
		debug.Debug
		c chan *Blob
	}
	ErrNotMagic = errors.New("Not Magic")
)

func init() {
	blobs.Set("blobs")
	blobs.c = make(chan *Blob, 16)
}

// BlobTime seeks and reads time from named or opened file.
func BlobTime(v interface{}) (t time.Time) {
	var (
		f   *os.File
		fn  string
		err error
		ok  bool
	)
	if fn, ok = v.(string); ok {
		if f, err = os.Open(fn); err != nil {
			return
		}
		defer f.Close()
	} else if f, ok = v.(*os.File); !ok {
		return
	}
	f.Seek(BlobTimeOff, os.SEEK_SET)
	(NBOReader{f}).ReadNBO(&t)
	return
}

// BlobSeek moves the ReadSeeker past the ASN blob headers
func BlobSeek(r io.ReadSeeker) (n int64, err error) {
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()
	n = blobSeek(r)
	return
}

// blobSeek will panic on error so the calling function must recover.
func blobSeek(r io.ReadSeeker) int64 {
	var b [1]byte
	_, err := r.Seek(BlobNameLenOff, os.SEEK_SET)
	if err != nil {
		panic(err)
	}
	_, err = r.Read(b[:])
	if err != nil {
		panic(err)
	}
	n, err := r.Seek(int64(b[0]), os.SEEK_CUR)
	if err != nil {
		panic(err)
	}
	return n
}

type Blob struct {
	Owner  PubEncr
	Author PubEncr
	Time   time.Time
	Name   string
	wo     int64
	l      int
}

func BlobPoolFlush() {
	for {
		select {
		case <-blobs.c:
		default:
			return
		}
	}
}

func NewBlob() (blob *Blob) {
	select {
	case blob = <-blobs.c:
	default:
		blob = &Blob{}
	}
	return
}

func NewBlobFrom(r io.Reader) (blob *Blob, err error) {
	blob = NewBlob()
	if _, err = blob.ReadFrom(r); err != nil {
		blob.Free()
		blob = nil
	}
	return
}

func NewBlobWith(owner, author *PubEncr, s string, t time.Time) (blob *Blob) {
	blob = NewBlob()
	blob.Owner = *owner
	blob.Author = *author
	blob.Name = s
	blob.Time = t
	return
}

// FN returns a formatted file name of its time and abbreviated sum.
func (blob *Blob) FN(sum string) string {
	return fmt.Sprintf("%016x_%s", blob.Time.UnixNano(), sum[:16])
}

// Free the Blob by pooling or release it to GC if pool is full.
func (blob *Blob) Free() {
	if blob != nil {
		blob.Owner.Reset()
		blob.Author.Reset()
		blob.Time = Time0
		blob.Name = ""
		blob.wo = 0
		select {
		case blobs.c <- blob:
		default:
		}
	}
}

// Blob{}.ReadFrom *after* Id{}.ReadFrom(r)
func (blob *Blob) ReadFrom(r io.Reader) (n int64, err error) {
	var (
		b [256]byte
		a accumulator.Int64
	)
	defer func() {
		if r := recover(); r != nil {
			err, _ = r.(error)
			blobs.Diag(debug.Depth(3), err)
		}
		n = int64(a)
	}()
	a.Accumulate(r.Read(b[:BlobMagicSz]))
	if string(b[:a]) != BlobMagic {
		err = ErrNotMagic
		return
	}
	a.Accumulate(r.Read(b[:BlobRandomSz]))
	a.Accumulate(r.Read(blob.Owner[:]))
	a.Accumulate(r.Read(blob.Author[:]))
	a.Accumulate((NBOReader{r}).ReadNBO(&blob.Time))
	a.Accumulate(r.Read(b[:1]))
	if l := int(b[0]); l > 0 {
		a.Accumulate(r.Read(b[:l]))
		blob.Name = string(b[:l])
	} else {
		blob.Name = ""
	}
	return
}

// RFC822Z returns formatted time.
func (blob *Blob) RFC822Z() string { return blob.Time.Format(time.RFC822Z) }

func (blob *Blob) String() string {
	b := &bytes.Buffer{}
	fmt.Fprintln(b, "name:", blob.Name)
	fmt.Fprintln(b, "owner:", blob.Owner)
	fmt.Fprintln(b, "author:", blob.Author)
	fmt.Fprint(b, "time: ", blob.RFC822Z())
	return b.String()
}

// Write to blob header is intended to be used from a io.MultiWriter to peel
// the blob header from a stream, the first and second bytes written are
// ignored as these are the version and id fields; also ignore everything after
// the name field.
func (blob *Blob) Write(b []byte) (n int, err error) {
	n = len(b)
	switch {
	case len(b) == 0:
		blobs.Diag(debug.Depth(2), "empty write")
	case blob.Name != "":
		// done, ignore the reset
		return
	case blob.wo < BlobMagicOff:
		blob.wo += 1
		b = b[1:]
	case blob.wo >= BlobMagicOff && blob.wo < BlobRandomOff:
		if string(b[:BlobMagicSz]) != BlobMagic {
			err = ErrNotMagic
		} else {
			blob.wo += BlobMagicSz
			b = b[BlobMagicSz:]
		}
	case blob.wo >= BlobRandomOff && blob.wo < BlobOwnerOff:
		blob.wo += PubEncrSz
		b = b[BlobRandomSz:]
	case blob.wo >= BlobOwnerOff && blob.wo < BlobAuthorOff:
		copy(blob.Owner[:], b[:PubEncrSz])
		blob.wo += PubEncrSz
		b = b[PubEncrSz:]
	case blob.wo >= BlobAuthorOff && blob.wo < BlobTimeOff:
		copy(blob.Author[:], b[:PubEncrSz])
		blob.wo += PubEncrSz
		b = b[PubEncrSz:]
	case blob.wo >= BlobTimeOff && blob.wo < BlobNameLenOff:
		nanoepoch := int64(binary.BigEndian.Uint64(b[:BlobTimeSz]))
		isec := int64(time.Second)
		blob.Time = time.Unix(nanoepoch/isec, nanoepoch%isec)
		blob.wo += 8
		b = b[8:]
	case blob.wo >= BlobNameLenOff && blob.wo < BlobNameOff:
		blob.l = int(b[0])
		blob.wo += 1
		b = b[1:]
	case blob.wo >= BlobNameOff:
		if blob.l > n {
			blobs.Diag(debug.Depth(2), "incomplete name:",
				n, "bytes vs.", blob.l)
			blob.l = n
		}
		blob.Name = string(b[:blob.l])
		return
	}
	if err == nil && len(b) > 0 {
		_, err = blob.Write(b)
	}
	return
}

func (blob *Blob) WriteTo(w io.Writer) (n int64, err error) {
	var (
		b [BlobRandomSz]byte
		a accumulator.Int64
	)
	defer func() {
		if r := recover(); r != nil {
			err, _ = r.(error)
		}
		n = int64(a)
	}()
	a.Accumulate(w.Write([]byte(BlobMagic)))
	rand.Reader.Read(b[:BlobRandomSz])
	a.Accumulate(w.Write(b[:BlobRandomSz]))
	a.Accumulate(w.Write(blob.Owner[:]))
	a.Accumulate(w.Write(blob.Author[:]))
	a.Accumulate((NBOWriter{w}).WriteNBO(blob.Time))
	b[0] = byte(len(blob.Name))
	a.Accumulate(w.Write(b[:1]))
	if len(blob.Name) > 0 {
		a.Accumulate(w.Write([]byte(blob.Name)))
	}
	return
}
<commit_msg>objdump: fix key formats<commit_after>// Copyright 2014-2015 Apptimist, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/apptimistco/asn/debug"
	"github.com/apptimistco/asn/debug/accumulator"
)

const (
	BlobVerOff     = int64(0)
	BlobVerSz      = 1
	BlobIdOff      = BlobVerOff + BlobVerSz
	BlobIdSz       = 1
	BlobMagic      = "asnmagic"
	BlobMagicOff   = BlobIdOff + BlobIdSz
	BlobMagicSz    = 8
	BlobRandomOff  = BlobMagicOff + BlobMagicSz
	BlobRandomSz   = 32
	BlobOwnerOff   = BlobRandomOff + BlobRandomSz
	BlobAuthorOff  = BlobOwnerOff + PubEncrSz
	BlobTimeOff    = BlobAuthorOff + PubEncrSz
	BlobTimeSz     = 8
	BlobNameLenOff = BlobTimeOff + BlobTimeSz
	BlobNameLenSz  = 1
	BlobNameOff    = BlobNameLenOff + BlobNameLenSz
)

var (
	blobs struct {
		debug.Debug
		c chan *Blob
	}
	ErrNotMagic = errors.New("Not Magic")
)

func init() {
	blobs.Set("blobs")
	blobs.c = make(chan *Blob, 16)
}

// BlobTime seeks and reads time from named or opened file.
func BlobTime(v interface{}) (t time.Time) {
	var (
		f   *os.File
		fn  string
		err error
		ok  bool
	)
	if fn, ok = v.(string); ok {
		if f, err = os.Open(fn); err != nil {
			return
		}
		defer f.Close()
	} else if f, ok = v.(*os.File); !ok {
		return
	}
	f.Seek(BlobTimeOff, os.SEEK_SET)
	(NBOReader{f}).ReadNBO(&t)
	return
}

// BlobSeek moves the ReadSeeker past the ASN blob headers
func BlobSeek(r io.ReadSeeker) (n int64, err error) {
	defer func() {
		if perr := recover(); perr != nil {
			err = perr.(error)
		}
	}()
	n = blobSeek(r)
	return
}

// blobSeek will panic on error so the calling function must recover.
func blobSeek(r io.ReadSeeker) int64 {
	var b [1]byte
	_, err := r.Seek(BlobNameLenOff, os.SEEK_SET)
	if err != nil {
		panic(err)
	}
	_, err = r.Read(b[:])
	if err != nil {
		panic(err)
	}
	n, err := r.Seek(int64(b[0]), os.SEEK_CUR)
	if err != nil {
		panic(err)
	}
	return n
}

type Blob struct {
	Owner  PubEncr
	Author PubEncr
	Time   time.Time
	Name   string
	wo     int64
	l      int
}

func BlobPoolFlush() {
	for {
		select {
		case <-blobs.c:
		default:
			return
		}
	}
}

func NewBlob() (blob *Blob) {
	select {
	case blob = <-blobs.c:
	default:
		blob = &Blob{}
	}
	return
}

func NewBlobFrom(r io.Reader) (blob *Blob, err error) {
	blob = NewBlob()
	if _, err = blob.ReadFrom(r); err != nil {
		blob.Free()
		blob = nil
	}
	return
}

func NewBlobWith(owner, author *PubEncr, s string, t time.Time) (blob *Blob) {
	blob = NewBlob()
	blob.Owner = *owner
	blob.Author = *author
	blob.Name = s
	blob.Time = t
	return
}

// FN returns a formatted file name of its time and abbreviated sum.
func (blob *Blob) FN(sum string) string {
	return fmt.Sprintf("%016x_%s", blob.Time.UnixNano(), sum[:16])
}

// Free the Blob by pooling or release it to GC if pool is full.
func (blob *Blob) Free() {
	if blob != nil {
		blob.Owner.Reset()
		blob.Author.Reset()
		blob.Time = Time0
		blob.Name = ""
		blob.wo = 0
		select {
		case blobs.c <- blob:
		default:
		}
	}
}

// Blob{}.ReadFrom *after* Id{}.ReadFrom(r)
func (blob *Blob) ReadFrom(r io.Reader) (n int64, err error) {
	var (
		b [256]byte
		a accumulator.Int64
	)
	defer func() {
		if r := recover(); r != nil {
			err, _ = r.(error)
			blobs.Diag(debug.Depth(3), err)
		}
		n = int64(a)
	}()
	a.Accumulate(r.Read(b[:BlobMagicSz]))
	if string(b[:a]) != BlobMagic {
		err = ErrNotMagic
		return
	}
	a.Accumulate(r.Read(b[:BlobRandomSz]))
	a.Accumulate(r.Read(blob.Owner[:]))
	a.Accumulate(r.Read(blob.Author[:]))
	a.Accumulate((NBOReader{r}).ReadNBO(&blob.Time))
	a.Accumulate(r.Read(b[:1]))
	if l := int(b[0]); l > 0 {
		a.Accumulate(r.Read(b[:l]))
		blob.Name = string(b[:l])
	} else {
		blob.Name = ""
	}
	return
}

// RFC822Z returns formatted time.
func (blob *Blob) RFC822Z() string { return blob.Time.Format(time.RFC822Z) }

func (blob *Blob) String() string {
	b := &bytes.Buffer{}
	fmt.Fprintln(b, "name:", blob.Name)
	fmt.Fprintln(b, "owner:", &blob.Owner)
	fmt.Fprintln(b, "author:", &blob.Author)
	fmt.Fprint(b, "time: ", blob.Time)
	return b.String()
}

// Write to blob header is intended to be used from a io.MultiWriter to peel
// the blob header from a stream, the first and second bytes written are
// ignored as these are the version and id fields; also ignore everything after
// the name field.
func (blob *Blob) Write(b []byte) (n int, err error) {
	n = len(b)
	switch {
	case len(b) == 0:
		blobs.Diag(debug.Depth(2), "empty write")
	case blob.Name != "":
		// done, ignore the reset
		return
	case blob.wo < BlobMagicOff:
		blob.wo += 1
		b = b[1:]
	case blob.wo >= BlobMagicOff && blob.wo < BlobRandomOff:
		if string(b[:BlobMagicSz]) != BlobMagic {
			err = ErrNotMagic
		} else {
			blob.wo += BlobMagicSz
			b = b[BlobMagicSz:]
		}
	case blob.wo >= BlobRandomOff && blob.wo < BlobOwnerOff:
		blob.wo += PubEncrSz
		b = b[BlobRandomSz:]
	case blob.wo >= BlobOwnerOff && blob.wo < BlobAuthorOff:
		copy(blob.Owner[:], b[:PubEncrSz])
		blob.wo += PubEncrSz
		b = b[PubEncrSz:]
	case blob.wo >= BlobAuthorOff && blob.wo < BlobTimeOff:
		copy(blob.Author[:], b[:PubEncrSz])
		blob.wo += PubEncrSz
		b = b[PubEncrSz:]
	case blob.wo >= BlobTimeOff && blob.wo < BlobNameLenOff:
		nanoepoch := int64(binary.BigEndian.Uint64(b[:BlobTimeSz]))
		isec := int64(time.Second)
		blob.Time = time.Unix(nanoepoch/isec, nanoepoch%isec)
		blob.wo += 8
		b = b[8:]
	case blob.wo >= BlobNameLenOff && blob.wo < BlobNameOff:
		blob.l = int(b[0])
		blob.wo += 1
		b = b[1:]
	case blob.wo >= BlobNameOff:
		if blob.l > n {
			blobs.Diag(debug.Depth(2), "incomplete name:",
				n, "bytes vs.", blob.l)
			blob.l = n
		}
		blob.Name = string(b[:blob.l])
		return
	}
	if err == nil && len(b) > 0 {
		_, err = blob.Write(b)
	}
	return
}

func (blob *Blob) WriteTo(w io.Writer) (n int64, err error) {
	var (
		b [BlobRandomSz]byte
		a accumulator.Int64
	)
	defer func() {
		if r := recover(); r != nil {
			err, _ = r.(error)
		}
		n = int64(a)
	}()
	a.Accumulate(w.Write([]byte(BlobMagic)))
	rand.Reader.Read(b[:BlobRandomSz])
	a.Accumulate(w.Write(b[:BlobRandomSz]))
	a.Accumulate(w.Write(blob.Owner[:]))
	a.Accumulate(w.Write(blob.Author[:]))
	a.Accumulate((NBOWriter{w}).WriteNBO(blob.Time))
	b[0] = byte(len(blob.Name))
	a.Accumulate(w.Write(b[:1]))
	if len(blob.Name) > 0 {
		a.Accumulate(w.Write([]byte(blob.Name)))
	}
	return
}
<|endoftext|>


<commit_before>package ams

import (
	"bytes"
	"context"
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"text/template"

	"github.com/pkg/errors"
)

func (c *Client) PutBlob(ctx context.Context, uploadURL *url.URL, file *os.File) ([]int, error) {
	fileInfo, err := file.Stat()
	if err != nil {
		return nil, errors.Wrap(err, "uploading file stat read failed")
	}
	params := url.Values{
		"comp":    {"block"},
		"blockid": {buildBlockID(1)},
	}
	req, err := c.newStorageRequest(ctx, http.MethodPut, *uploadURL,
		withQuery(params),
		withCustomHeader("x-ms-blob-type", "BlockBlob"),
		withContentType("application/octet-stream"),
		withBody(file),
	)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	req.ContentLength = fileInfo.Size()

	c.logger.Printf("[INFO] put blob ...")
	if err := c.do(req, http.StatusCreated, nil); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return []int{1}, nil
}

func (c *Client) PutBlockList(ctx context.Context, uploadURL *url.URL, blockList []int) error {
	params := url.Values{
		"comp": {"blocklist"},
	}
	blockListXML, err := BuildBlockListXML(blockList)
	if err != nil {
		return errors.Wrap(err, "block list XML build failed")
	}
	req, err := c.newStorageRequest(ctx, http.MethodPut, *uploadURL, withQuery(params), withBytes(blockListXML))
	if err != nil {
		return errors.Wrap(err, "request build failed")
	}
	req.ContentLength = int64(len(blockListXML))

	c.logger.Printf("[INFO] put block list ...")
	if err := c.do(req, http.StatusCreated, nil); err != nil {
		return errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")

	return nil
}

var blockListXML *template.Template = template.Must(
	template.New("blockListXML").
		Funcs(template.FuncMap{"buildBlockID": buildBlockID}).
		Parse(`<?xml version="1.0" encoding="utf-8"?><BlockList>{{ range . }}<Latest>{{ . | buildBlockID }}</Latest>{{ end }}</BlockList>`),
)

func buildBlockID(blockID int) string {
	s := fmt.Sprintf("BlockId%07d", blockID)
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func BuildBlockListXML(blockList []int) ([]byte, error) {
	var b bytes.Buffer
	if err := blockListXML.Execute(&b, blockList); err != nil {
		return nil, errors.Wrap(err, "template execute failed")
	}
	return b.Bytes(), nil
}
<commit_msg>refactor: change access level<commit_after>package ams

import (
	"bytes"
	"context"
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"text/template"

	"github.com/pkg/errors"
)

func (c *Client) PutBlob(ctx context.Context, uploadURL *url.URL, file *os.File) ([]int, error) {
	fileInfo, err := file.Stat()
	if err != nil {
		return nil, errors.Wrap(err, "uploading file stat read failed")
	}
	params := url.Values{
		"comp":    {"block"},
		"blockid": {buildBlockID(1)},
	}
	req, err := c.newStorageRequest(ctx, http.MethodPut, *uploadURL,
		withQuery(params),
		withCustomHeader("x-ms-blob-type", "BlockBlob"),
		withContentType("application/octet-stream"),
		withBody(file),
	)
	if err != nil {
		return nil, errors.Wrap(err, "request build failed")
	}
	req.ContentLength = fileInfo.Size()

	c.logger.Printf("[INFO] put blob ...")
	if err := c.do(req, http.StatusCreated, nil); err != nil {
		return nil, errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")
	return []int{1}, nil
}

func (c *Client) PutBlockList(ctx context.Context, uploadURL *url.URL, blockList []int) error {
	params := url.Values{
		"comp": {"blocklist"},
	}
	blockListXML, err := buildBlockListXML(blockList)
	if err != nil {
		return errors.Wrap(err, "block list XML build failed")
	}
	req, err := c.newStorageRequest(ctx, http.MethodPut, *uploadURL, withQuery(params), withBytes(blockListXML))
	if err != nil {
		return errors.Wrap(err, "request build failed")
	}
	req.ContentLength = int64(len(blockListXML))

	c.logger.Printf("[INFO] put block list ...")
	if err := c.do(req, http.StatusCreated, nil); err != nil {
		return errors.Wrap(err, "request failed")
	}
	c.logger.Printf("[INFO] completed")

	return nil
}

var blockListXML *template.Template = template.Must(
	template.New("blockListXML").
		Funcs(template.FuncMap{"buildBlockID": buildBlockID}).
		Parse(`<?xml version="1.0" encoding="utf-8"?><BlockList>{{ range . }}<Latest>{{ . | buildBlockID }}</Latest>{{ end }}</BlockList>`),
)

func buildBlockID(blockID int) string {
	s := fmt.Sprintf("BlockId%07d", blockID)
	return base64.StdEncoding.EncodeToString([]byte(s))
}

func buildBlockListXML(blockList []int) ([]byte, error) {
	var b bytes.Buffer
	if err := blockListXML.Execute(&b, blockList); err != nil {
		return nil, errors.Wrap(err, "template execute failed")
	}
	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package gotumlr

type blog struct {
	Title string
	Posts int64
	Name string
	Url string
	Updated int64
	Description string
	Ask bool
	Ask_anon bool
	Likes int64
}<commit_msg>Fix typo<commit_after>package gotumblr

type blog struct {
	Title string
	Posts int64
	Name string
	Url string
	Updated int64
	Description string
	Ask bool
	Ask_anon bool
	Likes int64
}<|endoftext|>


<commit_before>package votable

import (
	"encoding/xml"
	"fmt"
	"os"
	"testing"
)

func TestDecoding(t *testing.T) {
	for i, test := range []struct {
		fname string
	}{
		{
			fname: "testdata/test.vot",
		},
	} {
		f, err := os.Open(test.fname)
		if err != nil {
			t.Fatalf("test #%d: error opening [%s]: %v\n", i, test.fname, err)
		}
		defer f.Close()

		var vo xmlVO
		err = xml.NewDecoder(f).Decode(&vo)
		if err != nil {
			t.Fatalf("test #%d: error decoding [%s]: %v\n", i, test.fname, err)
		}

		fmt.Printf("test #%d: %#v\n", i, vo)

	}
}
<commit_msg>votable: improve TestDecoding<commit_after>package votable

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

func TestDecoding(t *testing.T) {
	for i, test := range []struct {
		fname string
	}{
		{
			fname: "testdata/test.vot",
		},
	} {
		f, err := os.Open(test.fname)
		if err != nil {
			t.Fatalf("test #%d: error opening [%s]: %v\n", i, test.fname, err)
		}
		defer f.Close()

		var vo xmlVO
		err = xml.NewDecoder(f).Decode(&vo)
		if err != nil {
			t.Fatalf("test #%d: error decoding [%s]: %v\n", i, test.fname, err)
		}

		// fmt.Printf("test #%d: %#v\n", i, vo)

		out := new(bytes.Buffer)
		enc := xml.NewEncoder(out)
		enc.Indent("", "  ")
		err = enc.Encode(vo)
		if err != nil {
			t.Fatalf("test #%d: error encoding [%s]: %v\n", i, test.fname, err)
		}

		fmt.Printf("test #%d:\n%s\n", i, string(out.Bytes()))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"time"
)

func writeChartByYear(fp *os.File, db *sql.DB) {
	fp.WriteString("## Top tracks by year\n\n")
	for year := 2016; year > 2012; year-- {
		yearlyEntries := findChartEntriesByYear(db, year)

		if len(yearlyEntries) > 0 {
			format := delimiterFormatString()

			fp.WriteString(fmt.Sprintf("#### Best of %d\n\n", year))
			fp.WriteString(outputTableHeader())
			for i, chartEntry := range yearlyEntries {
				title := chartEntry.Title
				artist := chartEntry.Artist

				output := fmt.Sprintf(format, i+1, artist, title, listenLink(chartEntry))
				fp.WriteString(output)
			}
			fp.WriteString("\n")
		}
	}
}

func writeChartByMonthAndYear(fp *os.File, db *sql.DB) {
	fp.WriteString("## Years by month\n\n")
	for year := 2016; year > 2012; year-- {
		for month := 12; month > 0; month-- {
			monthlyEntries := findChartEntriesByMonthAndYear(db, month, year)

			if len(monthlyEntries) > 0 {
				format := delimiterFormatString()

				fp.WriteString(fmt.Sprintf("#### %s ", time.Month(month)))
				fp.WriteString(strconv.Itoa(year) + " Charts" + "\n\n")
				fp.WriteString(outputTableHeader())
				for i, chartEntry := range monthlyEntries {
					title := chartEntry.Title
					artist := chartEntry.Artist

					output := fmt.Sprintf(format, i+1, artist, title, listenLink(chartEntry))
					fp.WriteString(output)
				}
				fp.WriteString("\n")
			}
		}
	}
}

func writeOutputFrom(db *sql.DB) {
	totalPlays := strconv.Itoa(countForTable(db, "plays"))
	totalTracks := strconv.Itoa(countForTable(db, "tracks"))

	markdownFile := os.ExpandEnv("${HOME}/.traktor-charts.md")
	fp, err := os.Create(markdownFile)
	if err != nil {
		fmt.Println("Unable to create", markdownFile)
	}
	defer fp.Close()

	fp.WriteString("# My Traktor DJ Charts\n\n")
	fp.WriteString(totalPlays + " songs played, " + totalTracks + " were unique.\n\n")

	fmt.Println(totalPlays, "songs played,", totalTracks, "were unique.")

	writeChartByYear(fp, db)
	writeChartByMonthAndYear(fp, db)

	fp.Sync()
}

func listenLink(ce ChartEntry) string {
	link := "https://www.youtube.com/results?search_query="
	return link + url.QueryEscape(ce.Artist+" "+ce.Title)
}

func delimiterFormatString() string {
	return "| %d | %s | %s | [YouTube](%s) |\n"
}

func outputTableHeader() string {
	return "| Number | Artist | Title | Check It |\n|---|---|---|---|\n"
}
<commit_msg>Fix "songs played" output spacing<commit_after>package main

import (
	"database/sql"
	"fmt"
	"net/url"
	"os"
	"strconv"
	"time"
)

func writeChartByYear(fp *os.File, db *sql.DB) {
	fp.WriteString("## Top tracks by year\n\n")
	for year := 2016; year > 2012; year-- {
		yearlyEntries := findChartEntriesByYear(db, year)

		if len(yearlyEntries) > 0 {
			format := delimiterFormatString()

			fp.WriteString(fmt.Sprintf("#### Best of %d\n\n", year))
			fp.WriteString(outputTableHeader())
			for i, chartEntry := range yearlyEntries {
				title := chartEntry.Title
				artist := chartEntry.Artist

				output := fmt.Sprintf(format, i+1, artist, title, listenLink(chartEntry))
				fp.WriteString(output)
			}
			fp.WriteString("\n")
		}
	}
}

func writeChartByMonthAndYear(fp *os.File, db *sql.DB) {
	fp.WriteString("## Years by month\n\n")
	for year := 2016; year > 2012; year-- {
		for month := 12; month > 0; month-- {
			monthlyEntries := findChartEntriesByMonthAndYear(db, month, year)

			if len(monthlyEntries) > 0 {
				format := delimiterFormatString()

				fp.WriteString(fmt.Sprintf("#### %s ", time.Month(month)))
				fp.WriteString(strconv.Itoa(year) + " Charts" + "\n\n")
				fp.WriteString(outputTableHeader())
				for i, chartEntry := range monthlyEntries {
					title := chartEntry.Title
					artist := chartEntry.Artist

					output := fmt.Sprintf(format, i+1, artist, title, listenLink(chartEntry))
					fp.WriteString(output)
				}
				fp.WriteString("\n")
			}
		}
	}
}

func writeOutputFrom(db *sql.DB) {
	totalPlays := strconv.Itoa(countForTable(db, "plays"))
	totalTracks := strconv.Itoa(countForTable(db, "tracks"))

	markdownFile := os.ExpandEnv("${HOME}/.traktor-charts.md")
	fp, err := os.Create(markdownFile)
	if err != nil {
		fmt.Println("Unable to create", markdownFile)
	}
	defer fp.Close()

	fp.WriteString("# My Traktor DJ Charts\n\n")
	fp.WriteString(totalPlays + " songs played, " + totalTracks + " were unique.\n\n")

	fmt.Println(totalPlays, "songs played, ", totalTracks, "were unique.")

	writeChartByYear(fp, db)
	writeChartByMonthAndYear(fp, db)

	fp.Sync()
}

func listenLink(ce ChartEntry) string {
	link := "https://www.youtube.com/results?search_query="
	return link + url.QueryEscape(ce.Artist+" "+ce.Title)
}

func delimiterFormatString() string {
	return "| %d | %s | %s | [YouTube](%s) |\n"
}

func outputTableHeader() string {
	return "| Number | Artist | Title | Check It |\n|---|---|---|---|\n"
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
)

var opers = map[string]ops{
	"STAR":  {6, "LEFT"},
	"PLUS":  {5, "LEFT"},
	"MIN":   {5, "LEFT"},
	"SLASH": {6, "LEFT"},
}

func NewPrsr() *Parser {
	return &Parser{
		pos: 0,
	}
}

func (p *Parser) parse(rl string) []cookie {
	//shunting yard algorrithm
	stack := []cookie{}  //symbols
	output := []cookie{} //numbers
	count := 0
	fmt.Println("rl : ", rl)
	for i := 0; i < len(p.tokens); i++ {
		fmt.Println("................ token is : ", p.tokens[count])
		switch {
		case p.tokens[count].isNumber():
			fmt.Println("----entered case : isNumber----")
			output = append(output, p.tokens[count])
			count++
		case p.tokens[count].isOperator():
			fmt.Println("----entered case : isOperator----")
			fmt.Println(" length of stack : ", len(stack))
			if len(stack) == 0 {
				stack = append(stack, p.tokens[count])
				count++
				break
			}
			if len(stack) >= 1 {
				fmt.Println("----entered : len(Stack >= 1)----")
				o1 := p.tokens[count]
				o2 := stack[len(stack)-1]

				//move the top of the stack to the ouput
				if o1.isHigherPrec(o2) {
					fmt.Println("----entered : o1.isHigherPrec(o2)----")
					fmt.Println("----stack before moval : ", stack, " ----")
					output = append(output, stack[0])
					fmt.Println("---- moveing stack item : ", stack[0], " in stack : ", stack, "----")
					stack = append(stack[:0], stack[0+1:]...)
					fmt.Println("----BEGIN | move top of stack to output | stack after  ----")
					fmt.Println(stack)
					fmt.Println("----END   | move top of stack to output | stack after  ----")
				}

			}
			stack = append(stack, p.tokens[count])

			count++
		case p.tokens[count].isComma():
			//loop this untill the top of the stack is a comma
			for {
				output = append(output, stack[len(stack)-1])
				stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)
			}
			count++
		case p.tokens[count].isLPAREN():
			stack = append(stack, p.tokens[count])
			count++
		case p.tokens[count].isRPAREN():
			holder := []cookie{}
			//loop this untill the top of the stack is a left parentheses
			for {
				//if it finds a left parentheses
				if stack[len(stack)-1].isLPAREN() {
					holder = append(holder, stack[len(stack)-1])
					stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)
					//if the top of the stack is a function operator
					if stack[len(stack)-1].isOperator() {
						output = append(output, holder[0])
						holder = append(holder[:0], holder[1:]...)
					}
				}
				output = append(output, stack[len(stack)-1])
				stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)

			}
			count++
		}

	}
	fmt.Println("stack at the end : ", stack)
	if len(stack) != 0 {
		fmt.Println("stack was not 0. it was : ", len(stack))
		for l, j := 0, len(stack)-1; l < j; l, j = l+1, j-1 {
			stack[l], stack[j] = stack[j], stack[l]
		}
		for m := 0; m <= len(stack)-1; m++ {
			fmt.Println("finally adding : ", stack[m], "to the output")
			output = append(output, stack[m])
		}
	}
	return output
}

func (p *Parser) Run(ln string) []cookie {
	tokens := lexicallyAnalize(ln)

	p.flush()
	p.tokens = tokens

	return p.parse(ln)
}

func (c *cookie) isRPAREN() bool {
	cc := strings.Split(c.t_sort, "_")[1]
	return cc == "RGT"
}

func (c *cookie) isLPAREN() bool {
	cc := strings.Split(c.t_sort, "_")[1]
	return cc == "LFT"
}

func (c *cookie) isNumber() bool {
	return c.t_sort == "INTERGER"
}

func (c *cookie) isOperator() bool {
	tok := strings.Split(c.t_sort, "_")[1]

	var ok bool
	if _, ok := opers[tok]; ok {

		return ok
	}
	return ok
}

func (c *cookie) isComma() bool {
	return strings.Split(c.t_sort, "_")[1] == "COMMA"
}

func (p *Parser) flush() {
	p.pos = 0
	p.tokens = nil
}

func (o1 cookie) isHigherPrec(o2 cookie) bool {
	o1o := strings.Split(o1.t_sort, "_")[1]
	o2o := strings.Split(o2.t_sort, "_")[1]

	if opers[o1o].assoc == "LEFT" && opers[o2o].prec >= opers[o1o].prec ||
		opers[o1o].assoc == "RIGHT" && opers[o2o].prec > opers[o1o].prec {
		return true
	}
	return false
}
<commit_msg>removed testing print functions<commit_after>package main

import (
	"strings"
)

var opers = map[string]ops{
	"STAR":  {6, "LEFT"},
	"PLUS":  {5, "LEFT"},
	"MIN":   {5, "LEFT"},
	"SLASH": {6, "LEFT"},
}

func NewPrsr() *Parser {
	return &Parser{
		pos: 0,
	}
}

func (p *Parser) parse(rl string) []cookie {
	//shunting yard algorrithm
	stack := []cookie{}  //symbols
	output := []cookie{} //numbers
	count := 0

	for i := 0; i < len(p.tokens); i++ {

		switch {
		case p.tokens[count].isNumber():

			output = append(output, p.tokens[count])
			count++
		case p.tokens[count].isOperator():

			if len(stack) == 0 {
				stack = append(stack, p.tokens[count])
				count++
				break
			}
			if len(stack) >= 1 {

				o1 := p.tokens[count]
				o2 := stack[len(stack)-1]

				//move the top of the stack to the ouput
				if o1.isHigherPrec(o2) {
					output = append(output, stack[0])

					stack = append(stack[:0], stack[0+1:]...)

				}

			}
			stack = append(stack, p.tokens[count])

			count++
		case p.tokens[count].isComma():
			//loop this untill the top of the stack is a comma
			for {
				output = append(output, stack[len(stack)-1])
				stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)
			}
			count++
		case p.tokens[count].isLPAREN():
			stack = append(stack, p.tokens[count])
			count++
		case p.tokens[count].isRPAREN():
			holder := []cookie{}
			//loop this untill the top of the stack is a left parentheses
			for {
				//if it finds a left parentheses
				if stack[len(stack)-1].isLPAREN() {
					holder = append(holder, stack[len(stack)-1])
					stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)
					//if the top of the stack is a function operator
					if stack[len(stack)-1].isOperator() {
						output = append(output, holder[0])
						holder = append(holder[:0], holder[1:]...)
					}
				}
				output = append(output, stack[len(stack)-1])
				stack = append(stack[:len(stack)-1], stack[len(stack)+1:]...)

			}
			count++
		}

	}

	if len(stack) != 0 {

		for l, j := 0, len(stack)-1; l < j; l, j = l+1, j-1 {
			stack[l], stack[j] = stack[j], stack[l]
		}
		for m := 0; m <= len(stack)-1; m++ {

			output = append(output, stack[m])
		}
	}
	return output
}

func (p *Parser) Run(ln string) []cookie {
	tokens := lexicallyAnalize(ln)

	p.flush()
	p.tokens = tokens

	return p.parse(ln)
}

func (c *cookie) isRPAREN() bool {
	cc := strings.Split(c.t_sort, "_")[1]
	return cc == "RGT"
}

func (c *cookie) isLPAREN() bool {
	cc := strings.Split(c.t_sort, "_")[1]
	return cc == "LFT"
}

func (c *cookie) isNumber() bool {
	return c.t_sort == "INTERGER"
}

func (c *cookie) isOperator() bool {
	tok := strings.Split(c.t_sort, "_")[1]

	var ok bool
	if _, ok := opers[tok]; ok {

		return ok
	}
	return ok
}

func (c *cookie) isComma() bool {
	return strings.Split(c.t_sort, "_")[1] == "COMMA"
}

func (p *Parser) flush() {
	p.pos = 0
	p.tokens = nil
}

func (o1 cookie) isHigherPrec(o2 cookie) bool {
	o1o := strings.Split(o1.t_sort, "_")[1]
	o2o := strings.Split(o2.t_sort, "_")[1]

	if opers[o1o].assoc == "LEFT" && opers[o2o].prec >= opers[o1o].prec ||
		opers[o1o].assoc == "RIGHT" && opers[o2o].prec > opers[o1o].prec {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package queue

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"

	log "github.com/SpirentOrion/logrus"
	"github.com/SpirentOrion/luddite/stats"
	"github.com/goamz/goamz/aws"
	"github.com/goamz/goamz/sqs"
)

const (
	statSqsSendSuffix  = ".send"
	statSqsErrorSuffix = ".error."
)

// Verify that SqsQueue implements Queue.
var _ Queue = &SqsQueue{}

// SqsParams holds properties for SQS-based queues.
type SqsParams struct {
	Region    string
	QueueName string
	AccessKey string
	SecretKey string
}

// NewSqsParams extracts SQS provider parameters from a
// generic string map and returns a SqsParams structure.
func NewSqsParams(params map[string]string) (*SqsParams, error) {
	p := &SqsParams{
		Region:    params["region"],
		QueueName: params["queue_name"],
		AccessKey: params["access_key"],
		SecretKey: params["secret_key"],
	}

	if p.Region == "" {
		return nil, errors.New("SQS providers require a 'region' parameter")
	}
	if p.QueueName == "" {
		return nil, errors.New("SQS providers require a 'queue_name' parameter")
	}

	return p, nil
}

type SqsQueue struct {
	logger      *log.Entry
	stats       stats.Stats
	statsPrefix string
	*sqs.Queue
}

func NewSqsQueue(params *SqsParams, logger *log.Entry, stats stats.Stats) (*SqsQueue, error) {
	auth, err := aws.GetAuth(params.AccessKey, params.SecretKey, "", time.Time{})
	if err != nil {
		return nil, err
	}
	sqs := sqs.New(auth, aws.Regions[params.Region])
	queue, err := sqs.CreateQueue(params.QueueName)
	if err != nil {
		return nil, err
	}
	return &SqsQueue{
		logger:      logger,
		stats:       stats,
		statsPrefix: fmt.Sprintf("queue.%s.%s.%s.", SQS_PROVIDER, params.Region, params.QueueName),
		Queue:       queue,
	}, nil
}

func (q *SqsQueue) Send(msg *Message) error {
	const op = "SendMessage"

	buf, err := json.Marshal(msg)
	if err != nil {
		q.logger.WithFields(log.Fields{
			"provider":   SQS_PROVIDER,
			"region":     q.Queue.Region,
			"queue_name": q.Queue.Name,
			"op":         op,
			"error":      err,
		}).Error()
		q.stats.Incr(q.statsPrefix+statSqsErrorSuffix, 1)
		return err
	}

	resp, err := q.SendMessage(string(buf))
	if err != nil {
		q.logger.WithFields(log.Fields{
			"provider":   SQS_PROVIDER,
			"region":     q.Queue.Region,
			"queue_name": q.Queue.Name,
			"op":         op,
			"error":      err,
		}).Error()
		q.stats.Incr(q.statsPrefix+statSqsErrorSuffix, 1)
		return err
	}

	q.logger.WithFields(log.Fields{
		"provider":   SQS_PROVIDER,
		"region":     q.Queue.Region,
		"queue_name": q.Queue.Name,
		"op":         op,
		"message_id": resp.Id,
	}).Info()
	q.stats.Incr(q.statsPrefix+statSqsSendSuffix, 1)
	return nil
}
<commit_msg>Use GetQueue rather than CreateQueue<commit_after>package queue

import (
	"encoding/json"
	"errors"
	"fmt"
	"time"

	log "github.com/SpirentOrion/logrus"
	"github.com/SpirentOrion/luddite/stats"
	"github.com/goamz/goamz/aws"
	"github.com/goamz/goamz/sqs"
)

const (
	statSqsSendSuffix  = ".send"
	statSqsErrorSuffix = ".error."
)

// Verify that SqsQueue implements Queue.
var _ Queue = &SqsQueue{}

// SqsParams holds properties for SQS-based queues.
type SqsParams struct {
	Region    string
	QueueName string
	AccessKey string
	SecretKey string
}

// NewSqsParams extracts SQS provider parameters from a
// generic string map and returns a SqsParams structure.
func NewSqsParams(params map[string]string) (*SqsParams, error) {
	p := &SqsParams{
		Region:    params["region"],
		QueueName: params["queue_name"],
		AccessKey: params["access_key"],
		SecretKey: params["secret_key"],
	}

	if p.Region == "" {
		return nil, errors.New("SQS providers require a 'region' parameter")
	}
	if p.QueueName == "" {
		return nil, errors.New("SQS providers require a 'queue_name' parameter")
	}

	return p, nil
}

type SqsQueue struct {
	logger      *log.Entry
	stats       stats.Stats
	statsPrefix string
	*sqs.Queue
}

func NewSqsQueue(params *SqsParams, logger *log.Entry, stats stats.Stats) (*SqsQueue, error) {
	auth, err := aws.GetAuth(params.AccessKey, params.SecretKey, "", time.Time{})
	if err != nil {
		return nil, err
	}
	sqs := sqs.New(auth, aws.Regions[params.Region])
	queue, err := sqs.GetQueue(params.QueueName)
	if err != nil {
		return nil, err
	}
	return &SqsQueue{
		logger:      logger,
		stats:       stats,
		statsPrefix: fmt.Sprintf("queue.%s.%s.%s.", SQS_PROVIDER, params.Region, params.QueueName),
		Queue:       queue,
	}, nil
}

func (q *SqsQueue) Send(msg *Message) error {
	const op = "SendMessage"

	buf, err := json.Marshal(msg)
	if err != nil {
		q.logger.WithFields(log.Fields{
			"provider":   SQS_PROVIDER,
			"region":     q.Queue.Region,
			"queue_name": q.Queue.Name,
			"op":         op,
			"error":      err,
		}).Error()
		q.stats.Incr(q.statsPrefix+statSqsErrorSuffix, 1)
		return err
	}

	resp, err := q.SendMessage(string(buf))
	if err != nil {
		q.logger.WithFields(log.Fields{
			"provider":   SQS_PROVIDER,
			"region":     q.Queue.Region,
			"queue_name": q.Queue.Name,
			"op":         op,
			"error":      err,
		}).Error()
		q.stats.Incr(q.statsPrefix+statSqsErrorSuffix, 1)
		return err
	}

	q.logger.WithFields(log.Fields{
		"provider":   SQS_PROVIDER,
		"region":     q.Queue.Region,
		"queue_name": q.Queue.Name,
		"op":         op,
		"message_id": resp.Id,
	}).Info()
	q.stats.Incr(q.statsPrefix+statSqsSendSuffix, 1)
	return nil
}
<|endoftext|>


<commit_before>package redbutton

import (
	"io"
	"time"
)

const PollInterval = 200 * time.Millisecond

//go:generate stringer -type=Event

type Event int

const (
	Unknown Event = iota
	Disabled
	Pressed
	Enabled
)

func Report(dev io.ReadWriter) (Event, error) {
	// leading zero disables sending of report number
	buf := []byte{0, 0, 0, 0, 0, 0, 0, 0, 2}
	if _, err := dev.Write(buf); err != nil {
		return Unknown, err
	}
	if _, err := dev.Read(buf[:8]); err != nil {
		return Unknown, err
	}
	return Event(buf[0] & 3), nil
}

func Poll(dev io.ReadWriter, d time.Duration) <-chan Event {
	if d == 0 {
		d = PollInterval
	}
	ch := make(chan Event)
	go func() {
		prev := Disabled
		tick := time.NewTicker(d)
		defer tick.Stop()
		defer close(ch)
		for range tick.C {
			ev, err := Report(dev)
			if err != nil {
				return
			}
			if ev != prev && prev != Pressed {
				ch <- ev
			}
			prev = ev
		}
	}()
	return ch
}
<commit_msg>keyed element<commit_after>package redbutton

import (
	"io"
	"time"
)

const PollInterval = 200 * time.Millisecond

//go:generate stringer -type=Event

type Event int

const (
	Unknown Event = iota
	Disabled
	Pressed
	Enabled
)

func Report(dev io.ReadWriter) (Event, error) {
	// leading zero disables sending of report number
	buf := []byte{8: 2}
	if _, err := dev.Write(buf); err != nil {
		return Unknown, err
	}
	if _, err := dev.Read(buf[:8]); err != nil {
		return Unknown, err
	}
	return Event(buf[0] & 3), nil
}

func Poll(dev io.ReadWriter, d time.Duration) <-chan Event {
	if d == 0 {
		d = PollInterval
	}
	ch := make(chan Event)
	go func() {
		prev := Disabled
		tick := time.NewTicker(d)
		defer tick.Stop()
		defer close(ch)
		for range tick.C {
			ev, err := Report(dev)
			if err != nil {
				return
			}
			if ev != prev && prev != Pressed {
				ch <- ev
			}
			prev = ev
		}
	}()
	return ch
}
<|endoftext|>


<commit_before>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"sync"
)

// The RegionSet manages multiple regions,
// merging any regions overlapping.
//
// Note that regions that are right next to each other
// are not merged into a single region. This is because
// otherwise it would not be possible to have multiple
// cursors right next to each other.
type RegionSet struct {
	regions []Region
	lock    sync.Mutex
}

// Adjusts all the regions in the set
func (r *RegionSet) Adjust(position, delta int) {
	r.lock.Lock()
	defer r.lock.Unlock()
	for i := range r.regions {
		r.regions[i].Adjust(position, delta)
	}
	r.flush()
}

// TODO(q): There should be a on modified callback on the RegionSet
func (r *RegionSet) flush() {
	for i := 0; i < len(r.regions); i++ {
		for j := i + 1; j < len(r.regions); {
			if r.regions[i] == r.regions[j] || r.regions[i].Intersects(r.regions[j]) || r.regions[j].Covers(r.regions[i]) {
				r.regions[i] = r.regions[i].Cover(r.regions[j])
				copy(r.regions[j:], r.regions[j+1:])
				r.regions = r.regions[:len(r.regions)-1]
				j = i + 1
			} else {
				j++
			}
		}
	}
}

// Removes the given region from the set
func (r *RegionSet) Substract(r2 Region) {
	r3 := r.Cut(r2)
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = r3.regions
}

// Adds the given region to the set
func (r *RegionSet) Add(r2 Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = append(r.regions, r2)
	r.flush()
}

// Clears the set
func (r *RegionSet) Clear() {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = r.regions[0:0]
	r.flush()
}

// Gets the region at index i
func (r *RegionSet) Get(i int) Region {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.regions[i]
}

// Compares two regions given by their indices
func (r *RegionSet) Less(i, j int) bool {
	if bi, bj := r.regions[i].Begin(), r.regions[j].Begin(); bi < bj {
		return true
	} else if bi == bj {
		return r.regions[i].End() < r.regions[j].End()
	}
	return false
}

// Swaps two regions ath the given indices
func (r *RegionSet) Swap(i, j int) {
	r.regions[i], r.regions[j] = r.regions[j], r.regions[i]
}

// Returns the number of regions contained in the set
func (r *RegionSet) Len() int {
	return len(r.regions)
}

// Adds all regions in the array to the set
func (r *RegionSet) AddAll(rs []Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = append(r.regions, rs...)
	r.flush()
}

// Returns whether the specified region is part of the set
func (r *RegionSet) Contains(r2 Region) bool {
	r.lock.Lock()
	defer r.lock.Unlock()

	for i := range r.regions {
		if r.regions[i] == r2 || (r.regions[i].Contains(r2.Begin()) && r.regions[i].Contains(r2.End())) {
			return true
		}
	}
	return false
}

// Returns a copy of the regions in the set
func (r *RegionSet) Regions() (ret []Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	ret = make([]Region, len(r.regions))
	copy(ret, r.regions)
	return
}

// Returns whether the set contains at least one
// region that isn't empty.
func (r *RegionSet) HasNonEmpty() bool {
	r.lock.Lock()
	defer r.lock.Unlock()
	for _, r := range r.regions {
		if !r.Empty() {
			return true
		}
	}
	return false
}

// Opposite of #HasNonEmpty
func (r *RegionSet) HasEmpty() bool {
	r.lock.Lock()
	defer r.lock.Unlock()
	for _, r := range r.regions {
		if r.Empty() {
			return true
		}
	}
	return false
}

// Cuts away the provided region from the set, and returns
// the new set
func (r *RegionSet) Cut(r2 Region) (ret RegionSet) {
	r.lock.Lock()
	defer r.lock.Unlock()

	for i := 0; i < len(r.regions); i++ {
		for _, xor := range r.regions[i].Cut(r2) {
			if !xor.Empty() {
				ret.Add(xor)
			}
		}
	}
	return
}
<commit_msg>regionset: remove Less and Swap which were leftovers from sort intf.<commit_after>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"sync"
)

// The RegionSet manages multiple regions,
// merging any regions overlapping.
//
// Note that regions that are right next to each other
// are not merged into a single region. This is because
// otherwise it would not be possible to have multiple
// cursors right next to each other.
type RegionSet struct {
	regions []Region
	lock    sync.Mutex
}

// Adjusts all the regions in the set
func (r *RegionSet) Adjust(position, delta int) {
	r.lock.Lock()
	defer r.lock.Unlock()
	for i := range r.regions {
		r.regions[i].Adjust(position, delta)
	}
	r.flush()
}

// TODO(q): There should be a on modified callback on the RegionSet
func (r *RegionSet) flush() {
	for i := 0; i < len(r.regions); i++ {
		for j := i + 1; j < len(r.regions); {
			if r.regions[i] == r.regions[j] || r.regions[i].Intersects(r.regions[j]) || r.regions[j].Covers(r.regions[i]) {
				r.regions[i] = r.regions[i].Cover(r.regions[j])
				copy(r.regions[j:], r.regions[j+1:])
				r.regions = r.regions[:len(r.regions)-1]
				j = i + 1
			} else {
				j++
			}
		}
	}
}

// Removes the given region from the set
func (r *RegionSet) Substract(r2 Region) {
	r3 := r.Cut(r2)
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = r3.regions
}

// Adds the given region to the set
func (r *RegionSet) Add(r2 Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = append(r.regions, r2)
	r.flush()
}

// Clears the set
func (r *RegionSet) Clear() {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = r.regions[0:0]
	r.flush()
}

// Gets the region at index i
func (r *RegionSet) Get(i int) Region {
	r.lock.Lock()
	defer r.lock.Unlock()
	return r.regions[i]
}

// Returns the number of regions contained in the set
func (r *RegionSet) Len() int {
	return len(r.regions)
}

// Adds all regions in the array to the set
func (r *RegionSet) AddAll(rs []Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	r.regions = append(r.regions, rs...)
	r.flush()
}

// Returns whether the specified region is part of the set
func (r *RegionSet) Contains(r2 Region) bool {
	r.lock.Lock()
	defer r.lock.Unlock()

	for i := range r.regions {
		if r.regions[i] == r2 || (r.regions[i].Contains(r2.Begin()) && r.regions[i].Contains(r2.End())) {
			return true
		}
	}
	return false
}

// Returns a copy of the regions in the set
func (r *RegionSet) Regions() (ret []Region) {
	r.lock.Lock()
	defer r.lock.Unlock()
	ret = make([]Region, len(r.regions))
	copy(ret, r.regions)
	return
}

// Returns whether the set contains at least one
// region that isn't empty.
func (r *RegionSet) HasNonEmpty() bool {
	r.lock.Lock()
	defer r.lock.Unlock()
	for _, r := range r.regions {
		if !r.Empty() {
			return true
		}
	}
	return false
}

// Opposite of #HasNonEmpty
func (r *RegionSet) HasEmpty() bool {
	r.lock.Lock()
	defer r.lock.Unlock()
	for _, r := range r.regions {
		if r.Empty() {
			return true
		}
	}
	return false
}

// Cuts away the provided region from the set, and returns
// the new set
func (r *RegionSet) Cut(r2 Region) (ret RegionSet) {
	r.lock.Lock()
	defer r.lock.Unlock()

	for i := 0; i < len(r.regions); i++ {
		for _, xor := range r.regions[i].Cut(r2) {
			if !xor.Empty() {
				ret.Add(xor)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/eknkc/amber"
	"github.com/russross/blackfriday"
	"github.com/yosssi/gcss"
	"github.com/yuin/gopher-lua"
	"io"
	"log"
	"net/http"
	"strings"
)

// Retrieve all the arguments given to a lua function
// and gather the strings in a buffer.
func arguments2buffer(L *lua.LState) bytes.Buffer {
	var buf bytes.Buffer
	top := L.GetTop()
	// Add all the string arguments to the buffer
	for i := 1; i <= top; i++ {
		buf.WriteString(L.Get(i).String())
		if i != top {
			buf.WriteString(" ")
		}
	}
	buf.WriteString("\n")
	return buf
}

// Expose functions that are related to rendering text, to the given Lua state
func exportRenderFunctions(w http.ResponseWriter, req *http.Request, L *lua.LState) {

	// Output Markdown as HTML
	L.SetGlobal("mprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)
		// Convert the buffer to markdown and return the translated string
		w.Write(blackfriday.MarkdownCommon([]byte(buf.String())))
		return 0 // number of results
	}))

	// TODO: Add two functions. One to compile amber templates and
	// store the result by filename and one to render data by using
	// compiled templates.

	// Output text as rendered amber.
	// TODO: Add caching, compilation and reuse
	L.SetGlobal("aprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)

		// Use the buffer as a template.
		// Options are "Pretty printing, but without line numbers."
		tpl, err := amber.Compile(buf.String(), amber.Options{true, false})
		if err != nil {
			if DEBUG_MODE {
				// TODO: Show where in the source code things went wrong. Make it prettier.
				fmt.Fprint(w, "Could not compile Amber template:\n\t"+err.Error()+"\n\n"+buf.String())
			} else {
				log.Println("ERROR: Could not compile Amber tamplate:")
				log.Println(err.Error())
				log.Println("\n" + buf.String())
			}
			return 0 // number of results
		}
		//somedata := map[string]string{"": ""}
		tpl.Execute(w, nil)
		return 0 // number of results
	}))

	// Output text as rendered GCSS
	// TODO: Add caching, compilation and reuse
	L.SetGlobal("gprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)
		// Transform GCSS to CSS and output the result.
		// Ignoring the number of bytes written.
		if _, err := gcss.Compile(w, bytes.NewReader(buf.Bytes())); err != nil {
			if DEBUG_MODE {
				// TODO: Show where in the source code things went wrong. Make it prettier.
				fmt.Fprint(w, "Could not compile GCSS:\n\t"+err.Error()+"\n\n"+buf.String())
			} else {
				log.Println("ERROR: Could not compile GCSS:")
				log.Println(err.Error())
				log.Println("\n" + buf.String())
			}
			//return 0 // number of results
		}
		return 0 // number of results
	}))

}

// Write the given source bytes as markdown wrapped in HTML to a writer, with a title
func markdownPage(w io.Writer, b []byte, title string) {

	// Convert from Markdown to HTML
	htmlbody := string(blackfriday.MarkdownCommon(b))

	// TODO: Check if handling "# title <tags" on the first line is valid
	// Markdown or not. Submit a patch to blackfriday if it is.

	h1title := ""
	if strings.HasPrefix(htmlbody, "
#") {
		fields := strings.Split(htmlbody, "<")
		if len(fields) > 2 {
			h1title = fields[1][2:]
			htmlbody = htmlbody[len("
"+h1title):]
			if strings.HasPrefix(h1title, "#") {
				h1title = h1title[1:]
			}
		}
	}

	htmlbytes := []byte("<!doctype html><title>" + title + "</title>
" + h1title + "
" + htmlbody + "")
	w.Write(htmlbytes)
}

// Write the given source bytes as Amber converted to HTML, to a writer.
func amberPage(w io.Writer, b []byte, title string) {
	ambertext := string(b)
	tpl, err := amber.Compile(ambertext, amber.Options{true, false})
	if err != nil {
		if DEBUG_MODE {
			// TODO: Show where in the source code things went wrong. Make it prettier.
			fmt.Fprint(w, "Could not compile Amber template:\n\t"+err.Error()+"\n\n"+ambertext)
		} else {
			log.Println("ERROR: Could not compile Amber tamplate:")
			log.Println(err.Error())
			log.Println("\n" + ambertext)
		}
		return

	}
	//somedata := map[string]string{"": ""}
	tpl.Execute(w, nil)
}

// Write the given source bytes as GCSS converted to CSS, to a writer.
func gcssPage(w io.Writer, b []byte, title string) {
	if _, err := gcss.Compile(w, bytes.NewReader(b)); err != nil {
		if DEBUG_MODE {
			// TODO: Show where in the source code things went wrong. Make it prettier.
			fmt.Fprint(w, "Could not compile GCSS:\n\t"+err.Error()+"\n\n"+string(b))
		} else {
			log.Println("ERROR: Could not compile GCSS:")
			log.Println(err.Error())
			log.Println("\n" + string(b))
		}
		return
	}
}
<commit_msg>Better error handling for Amber<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/eknkc/amber"
	"github.com/russross/blackfriday"
	"github.com/yosssi/gcss"
	"github.com/yuin/gopher-lua"
	"io"
	"log"
	"net/http"
	"strings"
	//	"bufio"
)

// Retrieve all the arguments given to a lua function
// and gather the strings in a buffer.
func arguments2buffer(L *lua.LState) bytes.Buffer {
	var buf bytes.Buffer
	top := L.GetTop()
	// Add all the string arguments to the buffer
	for i := 1; i <= top; i++ {
		buf.WriteString(L.Get(i).String())
		if i != top {
			buf.WriteString(" ")
		}
	}
	buf.WriteString("\n")
	return buf
}

// Expose functions that are related to rendering text, to the given Lua state
func exportRenderFunctions(w http.ResponseWriter, req *http.Request, L *lua.LState) {

	// Output Markdown as HTML
	L.SetGlobal("mprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)
		// Convert the buffer to markdown and return the translated string
		w.Write(blackfriday.MarkdownCommon([]byte(buf.String())))
		return 0 // number of results
	}))

	// TODO: Add two functions. One to compile amber templates and
	// store the result by filename and one to render data by using
	// compiled templates.

	// Output text as rendered amber.
	// TODO: Add caching, compilation and reuse
	L.SetGlobal("aprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)

		// Use the buffer as a template.
		// Options are "Pretty printing, but without line numbers."
		tpl, err := amber.Compile(buf.String(), amber.Options{true, false})
		if err != nil {
			if DEBUG_MODE {
				// TODO: Show where in the source code things went wrong. Make it prettier.
				fmt.Fprint(w, "Could not compile Amber template:\n\t"+err.Error()+"\n\n"+buf.String())
			} else {
				log.Println("ERROR: Could not compile Amber template:")
				log.Println(err.Error())
				log.Println("\n" + buf.String())
			}
			return 0 // number of results
		}
		//somedata := map[string]string{"": ""}
		tpl.Execute(w, nil)
		return 0 // number of results
	}))

	// Output text as rendered GCSS
	// TODO: Add caching, compilation and reuse
	L.SetGlobal("gprint", L.NewFunction(func(L *lua.LState) int {
		buf := arguments2buffer(L)
		// Transform GCSS to CSS and output the result.
		// Ignoring the number of bytes written.
		if _, err := gcss.Compile(w, bytes.NewReader(buf.Bytes())); err != nil {
			if DEBUG_MODE {
				// TODO: Show where in the source code things went wrong. Make it prettier.
				fmt.Fprint(w, "Could not compile GCSS:\n\t"+err.Error()+"\n\n"+buf.String())
			} else {
				log.Println("ERROR: Could not compile GCSS:")
				log.Println(err.Error())
				log.Println("\n" + buf.String())
			}
			//return 0 // number of results
		}
		return 0 // number of results
	}))

}

// Write the given source bytes as markdown wrapped in HTML to a writer, with a title
func markdownPage(w io.Writer, b []byte, title string) {

	// Convert from Markdown to HTML
	htmlbody := string(blackfriday.MarkdownCommon(b))

	// TODO: Check if handling "# title <tags" on the first line is valid
	// Markdown or not. Submit a patch to blackfriday if it is.

	h1title := ""
	if strings.HasPrefix(htmlbody, "
#") {
		fields := strings.Split(htmlbody, "<")
		if len(fields) > 2 {
			h1title = fields[1][2:]
			htmlbody = htmlbody[len("
"+h1title):]
			if strings.HasPrefix(h1title, "#") {
				h1title = h1title[1:]
			}
		}
	}

	htmlbytes := []byte("<!doctype html><title>" + title + "</title>
" + h1title + "
" + htmlbody + "")
	w.Write(htmlbytes)
}

// Write the given source bytes as Amber converted to HTML, to a writer.
func amberPage(w io.Writer, b []byte, title string) {
	ambertext := string(b)
	tpl, err := amber.Compile(ambertext, amber.Options{true, false})
	if err != nil {
		if DEBUG_MODE {
			// TODO: Show where in the source code things went wrong. Make it prettier.
			fmt.Fprint(w, "Could not compile Amber template:\n\t"+err.Error()+"\n\n"+ambertext)
		} else {
			log.Println("ERROR: Could not compile Amber template:")
			log.Println(err.Error())
			log.Println("\n" + ambertext)
		}
		return

	}
	//somedata := map[string]string{"": ""}
	var buf bytes.Buffer
	//bufWriter := bufio.NewWriter(&buf)
	if err := tpl.Execute(&buf, "MISSING DATA"); err != nil {
		if DEBUG_MODE {
			// TODO: Make it prettier.
			fmt.Fprint(w, "Could not execute Amber template:\n\t"+err.Error())
		} else {
			log.Println("ERROR: Could not execute Amber template:")
			log.Println(err.Error())
		}
		return
	}
	buf.WriteTo(w)
}

// Write the given source bytes as GCSS converted to CSS, to a writer.
func gcssPage(w io.Writer, b []byte, title string) {
	if _, err := gcss.Compile(w, bytes.NewReader(b)); err != nil {
		if DEBUG_MODE {
			// TODO: Show where in the source code things went wrong. Make it prettier.
			fmt.Fprint(w, "Could not compile GCSS:\n\t"+err.Error()+"\n\n"+string(b))
		} else {
			log.Println("ERROR: Could not compile GCSS:")
			log.Println(err.Error())
			log.Println("\n" + string(b))
		}
		return
	}
}
<|endoftext|>


<commit_before>package rest

import (
	"code.google.com/p/goprotobuf/proto"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/golang/glog"
	"github.com/gorilla/mux"
	"github.com/qorio/omni/api"
	"github.com/qorio/omni/auth"
	omni_http "github.com/qorio/omni/http"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

var (
	ErrMissingInput       = errors.New("error-missing-input")
	ErrUnknownContentType = errors.New("error-no-content-type")
	ErrUnknownMethod      = errors.New("error-unknown-method")
)

var (
	json_marshaler = func(contentType string, resp http.ResponseWriter, typed proto.Message) error {
		if buff, err := json.Marshal(typed); err == nil {
			omni_http.SetCORSHeaders(resp)
			resp.Header().Add("Content-Type", contentType)
			resp.Write(buff)
			return nil
		} else {
			return err
		}
	}

	json_unmarshaler = func(body io.ReadCloser, typed proto.Message) error {
		dec := json.NewDecoder(body)
		return dec.Decode(typed)
	}

	proto_marshaler = func(contentType string, resp http.ResponseWriter, typed proto.Message) error {
		if buff, err := proto.Marshal(typed); err == nil {
			omni_http.SetCORSHeaders(resp)
			resp.Header().Add("Content-Type", contentType)
			resp.Write(buff)
			return nil
		} else {
			return err
		}
	}

	proto_unmarshaler = func(body io.ReadCloser, typed proto.Message) error {
		buff, err := ioutil.ReadAll(body)
		if err != nil {
			return err
		}
		return proto.Unmarshal(buff, typed)
	}

	marshalers = map[string]func(string, http.ResponseWriter, proto.Message) error{
		"":                     json_marshaler,
		"application/json":     json_marshaler,
		"application/protobuf": proto_marshaler,
	}

	unmarshalers = map[string]func(io.ReadCloser, proto.Message) error{
		"":                     json_unmarshaler,
		"application/json":     json_unmarshaler,
		"application/protobuf": proto_unmarshaler,
	}
)

type Handler func(http.ResponseWriter, *http.Request)

type ServiceMethodImpl struct {
	Api                  api.MethodSpec // note this is by copy -- so that behavior is deterministic after initialization
	Handler              Handler
	AuthenticatedHandler auth.HttpHandler
	ServiceId            string
}

func SetHandler(m api.MethodSpec, h Handler) *ServiceMethodImpl {
	if m.AuthScope != "" {
		panic(errors.New(fmt.Sprintf("Method %s has oauth scopes but binding to unauthed handler.", m)))
	}
	return &ServiceMethodImpl{
		Api:     m,
		Handler: h,
	}
}

func SetAuthenticatedHandler(serviceId string, m api.MethodSpec, h auth.HttpHandler) *ServiceMethodImpl {
	if m.AuthScope == "" {
		panic(errors.New(fmt.Sprintf("Method %s has no oauth scopes but binding to authenticated handler.", m)))
	}
	return &ServiceMethodImpl{
		Api:                  m,
		AuthenticatedHandler: h,
		ServiceId:            serviceId,
	}
}

type EngineEvent struct {
	Service       string
	ServiceMethod api.ServiceMethod
	Body          interface{}
}

type Engine interface {
	Bind(...*ServiceMethodImpl)
	ServeHTTP(http.ResponseWriter, *http.Request)
	NewAuthToken() *auth.Token
	SignedString(*auth.Token) (string, error)
	GetUrlParameter(*http.Request, string) string
	Unmarshal(*http.Request, proto.Message) error
	Marshal(*http.Request, proto.Message, http.ResponseWriter) error
	MarshalJSON(*http.Request, interface{}, http.ResponseWriter) error
	HandleError(http.ResponseWriter, *http.Request, string, int) error
	EventChannel() chan<- *EngineEvent
}

type engine struct {
	spec       *api.ServiceMethods
	router     *mux.Router
	auth       auth.Service
	event_chan chan *EngineEvent
	done_chan  chan bool
	webhooks   WebhookManager
}

func NewEngine(spec *api.ServiceMethods, auth auth.Service, webhooks WebhookManager) *engine {
	e := &engine{
		spec:       spec,
		router:     mux.NewRouter(),
		auth:       auth,
		event_chan: make(chan *EngineEvent),
		done_chan:  make(chan bool),
		webhooks:   webhooks,
	}
	return e
}

func (this *engine) Router() *mux.Router {
	return this.router
}

func (this *engine) NewAuthToken() *auth.Token {
	return this.auth.NewToken()
}

func (this *engine) SignedString(token *auth.Token) (string, error) {
	return this.auth.SignedString(token)
}

func (this *engine) ServeHTTP(resp http.ResponseWriter, request *http.Request) {
	// Also start listening on the event channel for any webhook calls
	go func() {
		for {
			select {

			case message := <-this.event_chan:
				this.do_callback(message)

			case done := <-this.done_chan:
				if done {
					glog.Infoln("REST engine event channel stopped.")
					return
				}
			}
		}
	}()

	this.router.ServeHTTP(resp, request)
}

func (this *engine) GetUrlParameter(req *http.Request, key string) string {
	vars := mux.Vars(req)
	if val, has := vars[key]; has {
		return val
	} else if err := req.ParseForm(); err == nil {
		if _, has := req.Form[key]; has {
			return req.Form[key][0]
		}
	}
	return ""
}

func (this *engine) Bind(endpoints ...*ServiceMethodImpl) {
	for i, ep := range endpoints {
		switch {
		case ep.Handler != nil:
			this.router.HandleFunc(ep.Api.UrlRoute, ep.Handler).Methods(string(ep.Api.HttpMethod))

		case ep.AuthenticatedHandler != nil:
			this.router.HandleFunc(ep.Api.UrlRoute,
				this.auth.RequiresAuth(ep.Api.AuthScope, func(token *auth.Token) []string {
					return strings.Split(token.GetString(ep.ServiceId+"/@scopes"), ",")
				}, ep.AuthenticatedHandler)).Methods(string(ep.Api.HttpMethod))

		case ep.Handler == nil && ep.AuthenticatedHandler == nil:
			panic(errors.New(fmt.Sprintf("No implementation for REST endpoint[%d]: %s", i, ep)))
		}

		// check the content type
		for _, ct := range ep.Api.ContentTypes {
			if _, has := marshalers[ct]; !has {
				panic(errors.New(fmt.Sprintf("Bad content type: %s", ct)))
			}
			if _, has := unmarshalers[ct]; !has {
				panic(errors.New(fmt.Sprintf("Bad content type: %s", ct)))
			}
		}
	}
}

func (this *engine) Unmarshal(req *http.Request, typed proto.Message) (err error) {
	contentType := req.Header.Get("Content-Type")
	if unmarshaler, has := unmarshalers[contentType]; has {
		return unmarshaler(req.Body, typed)
	} else {
		return ErrUnknownContentType
	}
}

func (this *engine) MarshalJSON(req *http.Request, any interface{}, resp http.ResponseWriter) (err error) {
	if buff, err := json.Marshal(any); err == nil {
		omni_http.SetCORSHeaders(resp)
		resp.Header().Add("Content-Type", "application/json")
		resp.Write(buff)
		return nil
	} else {
		return err
	}
}

func (this *engine) Marshal(req *http.Request, typed proto.Message, resp http.ResponseWriter) (err error) {
	contentType := req.Header.Get("Content-Type") // Usually the case when a client POSTs
	if contentType == "" {
		contentType = req.Header.Get("Accept") // Usually the case with GET
	}
	if marshaler, has := marshalers[contentType]; has {
		return marshaler(contentType, resp, typed)
	} else {
		return ErrUnknownContentType
	}
}

func (this *engine) HandleError(resp http.ResponseWriter, req *http.Request, message string, code int) (err error) {
	resp.WriteHeader(code)
	resp.Write([]byte(fmt.Sprintf("{\"error\":\"%s\"}", message)))
	return
}

func (this *engine) EventChannel() chan<- *EngineEvent {
	return this.event_chan
}

func (this *engine) do_callback(message *EngineEvent) error {
	if this.webhooks == nil {
		return nil
	}
	//methods := *this.spec
	if m, has := (*this.spec)[message.ServiceMethod]; has {
		if m.CallbackEvent != api.EventKey("") {
			return this.webhooks.Send(message.Service, string(m.CallbackEvent), message.Body, m.CallbackBodyTemplate)
		}
	}
	return ErrUnknownMethod
}
<commit_msg>Remove CORS headers inside of json / protobuff code to improve separation of concerns<commit_after>package rest

import (
	"code.google.com/p/goprotobuf/proto"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/golang/glog"
	"github.com/gorilla/mux"
	"github.com/qorio/omni/api"
	"github.com/qorio/omni/auth"
	omni_http "github.com/qorio/omni/http"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
)

var (
	ErrMissingInput       = errors.New("error-missing-input")
	ErrUnknownContentType = errors.New("error-no-content-type")
	ErrUnknownMethod      = errors.New("error-unknown-method")
)

var (
	json_marshaler = func(contentType string, resp http.ResponseWriter, typed proto.Message) error {
		if buff, err := json.Marshal(typed); err == nil {
			resp.Header().Add("Content-Type", contentType)
			resp.Write(buff)
			return nil
		} else {
			return err
		}
	}

	json_unmarshaler = func(body io.ReadCloser, typed proto.Message) error {
		dec := json.NewDecoder(body)
		return dec.Decode(typed)
	}

	proto_marshaler = func(contentType string, resp http.ResponseWriter, typed proto.Message) error {
		if buff, err := proto.Marshal(typed); err == nil {
			resp.Header().Add("Content-Type", contentType)
			resp.Write(buff)
			return nil
		} else {
			return err
		}
	}

	proto_unmarshaler = func(body io.ReadCloser, typed proto.Message) error {
		buff, err := ioutil.ReadAll(body)
		if err != nil {
			return err
		}
		return proto.Unmarshal(buff, typed)
	}

	marshalers = map[string]func(string, http.ResponseWriter, proto.Message) error{
		"":                     json_marshaler,
		"application/json":     json_marshaler,
		"application/protobuf": proto_marshaler,
	}

	unmarshalers = map[string]func(io.ReadCloser, proto.Message) error{
		"":                     json_unmarshaler,
		"application/json":     json_unmarshaler,
		"application/protobuf": proto_unmarshaler,
	}
)

type Handler func(http.ResponseWriter, *http.Request)

type ServiceMethodImpl struct {
	Api                  api.MethodSpec // note this is by copy -- so that behavior is deterministic after initialization
	Handler              Handler
	AuthenticatedHandler auth.HttpHandler
	ServiceId            string
}

func SetHandler(m api.MethodSpec, h Handler) *ServiceMethodImpl {
	if m.AuthScope != "" {
		panic(errors.New(fmt.Sprintf("Method %s has oauth scopes but binding to unauthed handler.", m)))
	}
	return &ServiceMethodImpl{
		Api:     m,
		Handler: h,
	}
}

func SetAuthenticatedHandler(serviceId string, m api.MethodSpec, h auth.HttpHandler) *ServiceMethodImpl {
	if m.AuthScope == "" {
		panic(errors.New(fmt.Sprintf("Method %s has no oauth scopes but binding to authenticated handler.", m)))
	}
	return &ServiceMethodImpl{
		Api:                  m,
		AuthenticatedHandler: h,
		ServiceId:            serviceId,
	}
}

type EngineEvent struct {
	Service       string
	ServiceMethod api.ServiceMethod
	Body          interface{}
}

type Engine interface {
	Bind(...*ServiceMethodImpl)
	ServeHTTP(http.ResponseWriter, *http.Request)
	NewAuthToken() *auth.Token
	SignedString(*auth.Token) (string, error)
	GetUrlParameter(*http.Request, string) string
	Unmarshal(*http.Request, proto.Message) error
	Marshal(*http.Request, proto.Message, http.ResponseWriter) error
	MarshalJSON(*http.Request, interface{}, http.ResponseWriter) error
	HandleError(http.ResponseWriter, *http.Request, string, int) error
	EventChannel() chan<- *EngineEvent
}

type engine struct {
	spec       *api.ServiceMethods
	router     *mux.Router
	auth       auth.Service
	event_chan chan *EngineEvent
	done_chan  chan bool
	webhooks   WebhookManager
}

func NewEngine(spec *api.ServiceMethods, auth auth.Service, webhooks WebhookManager) *engine {
	e := &engine{
		spec:       spec,
		router:     mux.NewRouter(),
		auth:       auth,
		event_chan: make(chan *EngineEvent),
		done_chan:  make(chan bool),
		webhooks:   webhooks,
	}
	return e
}

func (this *engine) Router() *mux.Router {
	return this.router
}

func (this *engine) NewAuthToken() *auth.Token {
	return this.auth.NewToken()
}

func (this *engine) SignedString(token *auth.Token) (string, error) {
	return this.auth.SignedString(token)
}

func (this *engine) ServeHTTP(resp http.ResponseWriter, request *http.Request) {
	// Also start listening on the event channel for any webhook calls
	go func() {
		for {
			select {

			case message := <-this.event_chan:
				this.do_callback(message)

			case done := <-this.done_chan:
				if done {
					glog.Infoln("REST engine event channel stopped.")
					return
				}
			}
		}
	}()

	this.router.ServeHTTP(resp, request)
}

func (this *engine) GetUrlParameter(req *http.Request, key string) string {
	vars := mux.Vars(req)
	if val, has := vars[key]; has {
		return val
	} else if err := req.ParseForm(); err == nil {
		if _, has := req.Form[key]; has {
			return req.Form[key][0]
		}
	}
	return ""
}

func (this *engine) Bind(endpoints ...*ServiceMethodImpl) {
	for i, ep := range endpoints {
		switch {
		case ep.Handler != nil:
			this.router.HandleFunc(ep.Api.UrlRoute, ep.Handler).Methods(string(ep.Api.HttpMethod))

		case ep.AuthenticatedHandler != nil:
			this.router.HandleFunc(ep.Api.UrlRoute,
				this.auth.RequiresAuth(ep.Api.AuthScope, func(token *auth.Token) []string {
					return strings.Split(token.GetString(ep.ServiceId+"/@scopes"), ",")
				}, ep.AuthenticatedHandler)).Methods(string(ep.Api.HttpMethod))

		case ep.Handler == nil && ep.AuthenticatedHandler == nil:
			panic(errors.New(fmt.Sprintf("No implementation for REST endpoint[%d]: %s", i, ep)))
		}

		// check the content type
		for _, ct := range ep.Api.ContentTypes {
			if _, has := marshalers[ct]; !has {
				panic(errors.New(fmt.Sprintf("Bad content type: %s", ct)))
			}
			if _, has := unmarshalers[ct]; !has {
				panic(errors.New(fmt.Sprintf("Bad content type: %s", ct)))
			}
		}
	}
}

func (this *engine) Unmarshal(req *http.Request, typed proto.Message) (err error) {
	contentType := req.Header.Get("Content-Type")
	if unmarshaler, has := unmarshalers[contentType]; has {
		return unmarshaler(req.Body, typed)
	} else {
		return ErrUnknownContentType
	}
}

func (this *engine) MarshalJSON(req *http.Request, any interface{}, resp http.ResponseWriter) (err error) {
	if buff, err := json.Marshal(any); err == nil {
		resp.Header().Add("Content-Type", "application/json")
		resp.Write(buff)
		return nil
	} else {
		return err
	}
}

func (this *engine) Marshal(req *http.Request, typed proto.Message, resp http.ResponseWriter) (err error) {
	contentType := req.Header.Get("Content-Type") // Usually the case when a client POSTs
	if contentType == "" {
		contentType = req.Header.Get("Accept") // Usually the case with GET
	}
	if marshaler, has := marshalers[contentType]; has {
		return marshaler(contentType, resp, typed)
	} else {
		return ErrUnknownContentType
	}
}

func (this *engine) HandleError(resp http.ResponseWriter, req *http.Request, message string, code int) (err error) {
	resp.WriteHeader(code)
	resp.Write([]byte(fmt.Sprintf("{\"error\":\"%s\"}", message)))
	return
}

func (this *engine) EventChannel() chan<- *EngineEvent {
	return this.event_chan
}

func (this *engine) do_callback(message *EngineEvent) error {
	if this.webhooks == nil {
		return nil
	}
	//methods := *this.spec
	if m, has := (*this.spec)[message.ServiceMethod]; has {
		if m.CallbackEvent != api.EventKey("") {
			return this.webhooks.Send(message.Service, string(m.CallbackEvent), message.Body, m.CallbackBodyTemplate)
		}
	}
	return ErrUnknownMethod
}
<|endoftext|>