<commit_before>package grifts

import (
	"html/template"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/markbates/grift/grift"
)

var _ = grift.Desc("shoulders", "Generates a file listing all of the 3rd party packages used by buffalo.")
var _ = grift.Add("shoulders", func(c *grift.Context) error {
	giants := map[string]string{
		"github.com/markbates/refresh": "github.com/markbates/refresh",
		"github.com/markbates/grift":   "github.com/markbates/grift",
		"github.com/markbates/pop":     "github.com/markbates/pop",
		"github.com/spf13/cobra":       "github.com/spf13/cobra",
		"github.com/motemen/gore":      "github.com/motemen/gore",
	}

	for _, p := range []string{".", "./render"} {
		cmd := exec.Command("go", "list", "-f", `'* {{ join .Deps  "\n"}}'`, p)
		b, err := cmd.Output()
		if err != nil {
			return err
		}

		list := strings.Split(string(b), "\n")

		for _, g := range list {
			if strings.Contains(g, "github.com") {
				giants[g] = g
			}
		}
	}

	f, err := os.Create(path.Join(os.Getenv("GOPATH"), "src", "github.com", "gobuffalo", "buffalo", "SHOULDERS.md"))
	if err != nil {
		return err
	}
	t, err := template.New("").Parse(shouldersTemplate)
	if err != nil {
		return err
	}
	err = t.Execute(f, giants)
	if err != nil {
		return err
	}

	return commitAndPushShoulders()
})

func commitAndPushShoulders() error {
	cmd := exec.Command("git", "commit", "SHOULDERS.md", "-m", "Updated SHOULDERS.md")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	err := cmd.Run()
	if err != nil {
		return err
	}

	cmd = exec.Command("git", "push", "origin")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

var shouldersTemplate = `
# Buffalo Stands on the Shoulders of Giants

Buffalo does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them altogether in the best way possible. Without these giants this project would not be possible. Please make sure to check them out and thank them for all of their hard work.

Thank you to the following **GIANTS**:

{{ range $k, $v := .}}
* [{{$k}}](https://{{$v}})
{{ end }}
`
<commit_msg>added a "shoulders:list" task<commit_after>package grifts

import (
	"fmt"
	"html/template"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/markbates/grift/grift"
)

var _ = grift.Desc("shoulders", "Prints a listing all of the 3rd party packages used by buffalo.")
var _ = grift.Add("shoulders:list", func(c *grift.Context) error {
	giants := map[string]string{
		"github.com/markbates/refresh": "github.com/markbates/refresh",
		"github.com/markbates/grift":   "github.com/markbates/grift",
		"github.com/markbates/pop":     "github.com/markbates/pop",
		"github.com/spf13/cobra":       "github.com/spf13/cobra",
		"github.com/motemen/gore":      "github.com/motemen/gore",
	}

	for _, p := range []string{".", "./render"} {
		cmd := exec.Command("go", "list", "-f", `'* {{ join .Deps  "\n"}}'`, p)
		b, err := cmd.Output()
		if err != nil {
			return err
		}

		list := strings.Split(string(b), "\n")

		for _, g := range list {
			if strings.Contains(g, "github.com") || strings.Contains(g, "bitbucket.org") {
				fmt.Println(g)
				giants[g] = g
			}
		}
	}
	c.Set("giants", giants)
	return nil
})

var _ = grift.Desc("shoulders", "Generates a file listing all of the 3rd party packages used by buffalo.")
var _ = grift.Add("shoulders", func(c *grift.Context) error {
	err := grift.Run("shoulders:list", c)
	if err != nil {
		return err
	}
	f, err := os.Create(path.Join(os.Getenv("GOPATH"), "src", "github.com", "gobuffalo", "buffalo", "SHOULDERS.md"))
	if err != nil {
		return err
	}
	t, err := template.New("").Parse(shouldersTemplate)
	if err != nil {
		return err
	}
	err = t.Execute(f, c.Get("giants"))
	if err != nil {
		return err
	}

	return commitAndPushShoulders()
})

func commitAndPushShoulders() error {
	cmd := exec.Command("git", "commit", "SHOULDERS.md", "-m", "Updated SHOULDERS.md")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	err := cmd.Run()
	if err != nil {
		return err
	}

	cmd = exec.Command("git", "push", "origin")
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Stdout = os.Stdout
	return cmd.Run()
}

var shouldersTemplate = `
# Buffalo Stands on the Shoulders of Giants

Buffalo does not try to reinvent the wheel! Instead, it uses the already great wheels developed by the Go community and puts them altogether in the best way possible. Without these giants this project would not be possible. Please make sure to check them out and thank them for all of their hard work.

Thank you to the following **GIANTS**:

{{ range $k, $v := .}}
* [{{$k}}](https://{{$v}})
{{ end }}
`
<|endoftext|>


<commit_before>package audio

import (
	"testing"
  "fmt"
)

func Test(t *testing.T) {
	queue := NewQueue()
  fmt.Println("Push nothing")
  if queue.Pull(1) != "NONE" {
    t.Fail()
  }

  fmt.Println("Push in order")
  queue.Push(2, "a")
  queue.Push(3, "b")
  queue.Push(4, "c")
  if queue.Pull(2) != "a" {
    t.Fail()
  }
  if queue.Pull(3) != "b" {
    t.Fail()
  }
  if queue.Pull(4) != "c" {
    t.Fail()
  }

  fmt.Println("Push out of order")
  queue.Push(7, "f")
  queue.Push(6, "e")
  queue.Push(5, "d")
  if queue.Pull(5) != "d" {
    t.Fail()
  }
  if queue.Pull(6) != "e" {
    t.Fail()
  }
  if queue.Pull(7) != "f" {
    t.Fail()
  }
}
<commit_msg>make tests pretty<commit_after>package audio

import (
	"testing"
)

func TestInOrder(t *testing.T) {
	queue := NewQueue()
  queue.Push(2, "a")
  queue.Push(3, "b")
  queue.Push(4, "c")
  if queue.Pull(2) != "a" {
    t.Fail()
  }
  if queue.Pull(3) != "b" {
    t.Fail()
  }
  if queue.Pull(4) != "c" {
    t.Fail()
  }
}

func TestOutOfOrder(t *testing.T) {
	queue := NewQueue()
  queue.Push(7, "f")
  queue.Push(6, "e")
  queue.Push(5, "d")
  if queue.Pull(5) != "d" {
    t.Fail()
  }
  if queue.Pull(6) != "e" {
    t.Fail()
  }
  if queue.Pull(7) != "f" {
    t.Fail()
  }
}

func TestNotInQueue(t *testing.T) {
	queue := NewQueue()
  if queue.Pull(0) != "NONE" {
    t.Fail()
  }
  if queue.Pull(1) != "NONE" {
    t.Fail()
  }
}
<|endoftext|>


<commit_before>package streamer

import (
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

var _ io.ReadCloser = &TailReader{}

var ErrAlreadyClosed = fmt.Errorf("TailReader already closed")

type TailReader struct {
	r     io.Reader
	drain int32
}

/*
	Proxies another reader, disregarding EOFs and blocking instead until
	the user closes.
*/
func NewTailReader(r io.Reader) *TailReader {
	return &TailReader{
		r: r,
	}
}

func (r *TailReader) Read(msg []byte) (n int, err error) {
	for n == 0 && err == nil {
		n, err = r.r.Read(msg)
		if err == io.EOF {
			// We don't pass EOF up until we're commanded to be closed.
			// This could be a "temporary" EOF and appends will still be incoming.
			if n > 0 {
				// If any bytes, pass them up immediately.
				return n, nil
			}
			// If we got EOF, have no buffer, and are at this instant closed, leave.
			if r.drain > 0 {
				return 0, io.EOF
			}
			// Pause before retrying.
			// We're effectively required to block here, because otherwise the reader may spin;
			// this is not a clueful wait; but it does prevent pegging a core.
			// Quite dumb in this case is also quite fool-proof.
			err = nil
			<-time.After(1 * time.Millisecond)
		}
	}
	// anything other than an eof, we have no behavioral changes to make; pass up.
	return n, err
}

/*
	Breaks any readers currently blocked.
*/
func (r *TailReader) Close() error {
	if swapped := atomic.CompareAndSwapInt32(&r.drain, 0, 1); swapped != true {
		return ErrAlreadyClosed
	}
	return nil
}
<commit_msg>Drag up the poller interval for a blocking read.<commit_after>package streamer

import (
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

var _ io.ReadCloser = &TailReader{}

var ErrAlreadyClosed = fmt.Errorf("TailReader already closed")

type TailReader struct {
	r     io.Reader
	drain int32
}

/*
	Proxies another reader, disregarding EOFs and blocking instead until
	the user closes.
*/
func NewTailReader(r io.Reader) *TailReader {
	return &TailReader{
		r: r,
	}
}

func (r *TailReader) Read(msg []byte) (n int, err error) {
	for n == 0 && err == nil {
		n, err = r.r.Read(msg)
		if err == io.EOF {
			// We don't pass EOF up until we're commanded to be closed.
			// This could be a "temporary" EOF and appends will still be incoming.
			if n > 0 {
				// If any bytes, pass them up immediately.
				return n, nil
			}
			// If we got EOF, have no buffer, and are at this instant closed, leave.
			if r.drain > 0 {
				return 0, io.EOF
			}
			// Pause before retrying.
			// We're effectively required to block here, because otherwise the reader may spin;
			// this is not a clueful wait; but it does prevent pegging a core.
			// Quite dumb in this case is also quite fool-proof.
			err = nil
			<-time.After(20 * time.Millisecond)
		}
	}
	// anything other than an eof, we have no behavioral changes to make; pass up.
	return n, err
}

/*
	Breaks any readers currently blocked.
*/
func (r *TailReader) Close() error {
	if swapped := atomic.CompareAndSwapInt32(&r.drain, 0, 1); swapped != true {
		return ErrAlreadyClosed
	}
	return nil
}
<|endoftext|>


<commit_before>package testutil

import (
	"bytes"
	"fmt"
	"path/filepath"
	"regexp"
	"time"

	"v.io/x/devtools/lib/collect"
	"v.io/x/devtools/lib/util"
	"v.io/x/devtools/lib/xunit"
)

// generateXUnitTestSuite generates an xUnit test suite that
// encapsulates the given input.
func generateXUnitTestSuite(ctx *util.Context, success bool, pkg string, duration time.Duration, output string) *xunit.TestSuite {
	// Generate an xUnit test suite describing the result.
	s := xunit.TestSuite{Name: pkg}
	c := xunit.TestCase{
		Classname: pkg,
		Name:      "Test",
		Time:      fmt.Sprintf("%.2f", duration.Seconds()),
	}
	if !success {
		fmt.Fprintf(ctx.Stdout(), "%s ... failed\n%v\n", pkg, output)
		f := xunit.Failure{
			Message: "vrpc",
			Data:    output,
		}
		c.Failures = append(c.Failures, f)
		s.Failures++
	} else {
		fmt.Fprintf(ctx.Stdout(), "%s ... ok\n", pkg)
	}
	s.Tests++
	s.Cases = append(s.Cases, c)
	return &s
}

// testProdService test the given production service.
func testProdService(ctx *util.Context, service prodService) (*xunit.TestSuite, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	bin := filepath.Join(root, "release", "go", "bin", "vrpc")
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	start := time.Now()
	if err := ctx.Run().TimedCommandWithOpts(DefaultTestTimeout, opts, bin, "signature", service.objectName); err != nil {
		return generateXUnitTestSuite(ctx, false, service.name, time.Now().Sub(start), out.String()), nil
	}
	if !service.regexp.Match(out.Bytes()) {
		fmt.Fprintf(ctx.Stderr(), "couldn't match regexp `%s` in output:\n%v\n", service.regexp, out.String())
		return generateXUnitTestSuite(ctx, false, service.name, time.Now().Sub(start), "mismatching signature"), nil
	}
	return generateXUnitTestSuite(ctx, true, service.name, time.Now().Sub(start), ""), nil
}

type prodService struct {
	name       string
	objectName string
	regexp     *regexp.Regexp
}

// vanadiumProdServicesTest runs a test of vanadium production services.
func vanadiumProdServicesTest(ctx *util.Context, testName string, _ ...TestOpt) (_ *TestResult, e error) {
	// Initialize the test.
	cleanup, err := initTest(ctx, testName, nil)
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Install the vrpc tool.
	if err := ctx.Run().Command("v23", "go", "install", "v.io/x/ref/cmd/vrpc"); err != nil {
		return nil, internalTestError{err, "Install VRPC"}
	}

	// Describe the test cases.
	namespaceRoot := "/ns.dev.v.io:8101"
	allPassed, suites := true, []xunit.TestSuite{}
	services := []prodService{
		prodService{
			name:       "mounttable",
			objectName: namespaceRoot,
			regexp:     regexp.MustCompile(`MountTable[[:space:]]+interface`),
		},
		prodService{
			name:       "application repository",
			objectName: namespaceRoot + "/applicationd",
			regexp:     regexp.MustCompile(`Application[[:space:]]+interface`),
		},
		prodService{
			name:       "binary repository",
			objectName: namespaceRoot + "/binaryd",
			regexp:     regexp.MustCompile(`Binary[[:space:]]+interface`),
		},
		prodService{
			name:       "macaroon service",
			objectName: namespaceRoot + "/identity/dev.v.io/macaroon",
			regexp:     regexp.MustCompile(`MacaroonBlesser[[:space:]]+interface`),
		},
		prodService{
			name:       "google identity service",
			objectName: namespaceRoot + "/identity/dev.v.io/google",
			regexp:     regexp.MustCompile(`OAuthBlesser[[:space:]]+interface`),
		},
		prodService{
			name:       "binary discharger",
			objectName: namespaceRoot + "/identity/dev.v.io/discharger",
			regexp:     regexp.MustCompile(`Discharger[[:space:]]+interface`),
		},
	}

	for _, service := range services {
		suite, err := testProdService(ctx, service)
		if err != nil {
			return nil, err
		}
		allPassed = allPassed && (suite.Failures == 0)
		suites = append(suites, *suite)
	}

	// Create the xUnit report.
	if err := xunit.CreateReport(ctx, testName, suites); err != nil {
		return nil, err
	}
	if !allPassed {
		return &TestResult{Status: TestFailed}, nil
	}
	return &TestResult{Status: TestPassed}, nil
}
<commit_msg>testutil: updating the Vanadium object names of our core services<commit_after>package testutil

import (
	"bytes"
	"fmt"
	"path/filepath"
	"regexp"
	"time"

	"v.io/x/devtools/lib/collect"
	"v.io/x/devtools/lib/util"
	"v.io/x/devtools/lib/xunit"
)

// generateXUnitTestSuite generates an xUnit test suite that
// encapsulates the given input.
func generateXUnitTestSuite(ctx *util.Context, success bool, pkg string, duration time.Duration, output string) *xunit.TestSuite {
	// Generate an xUnit test suite describing the result.
	s := xunit.TestSuite{Name: pkg}
	c := xunit.TestCase{
		Classname: pkg,
		Name:      "Test",
		Time:      fmt.Sprintf("%.2f", duration.Seconds()),
	}
	if !success {
		fmt.Fprintf(ctx.Stdout(), "%s ... failed\n%v\n", pkg, output)
		f := xunit.Failure{
			Message: "vrpc",
			Data:    output,
		}
		c.Failures = append(c.Failures, f)
		s.Failures++
	} else {
		fmt.Fprintf(ctx.Stdout(), "%s ... ok\n", pkg)
	}
	s.Tests++
	s.Cases = append(s.Cases, c)
	return &s
}

// testProdService test the given production service.
func testProdService(ctx *util.Context, service prodService) (*xunit.TestSuite, error) {
	root, err := util.VanadiumRoot()
	if err != nil {
		return nil, err
	}
	bin := filepath.Join(root, "release", "go", "bin", "vrpc")
	var out bytes.Buffer
	opts := ctx.Run().Opts()
	opts.Stdout = &out
	opts.Stderr = &out
	start := time.Now()
	if err := ctx.Run().TimedCommandWithOpts(DefaultTestTimeout, opts, bin, "signature", service.objectName); err != nil {
		return generateXUnitTestSuite(ctx, false, service.name, time.Now().Sub(start), out.String()), nil
	}
	if !service.regexp.Match(out.Bytes()) {
		fmt.Fprintf(ctx.Stderr(), "couldn't match regexp `%s` in output:\n%v\n", service.regexp, out.String())
		return generateXUnitTestSuite(ctx, false, service.name, time.Now().Sub(start), "mismatching signature"), nil
	}
	return generateXUnitTestSuite(ctx, true, service.name, time.Now().Sub(start), ""), nil
}

type prodService struct {
	name       string
	objectName string
	regexp     *regexp.Regexp
}

// vanadiumProdServicesTest runs a test of vanadium production services.
func vanadiumProdServicesTest(ctx *util.Context, testName string, _ ...TestOpt) (_ *TestResult, e error) {
	// Initialize the test.
	cleanup, err := initTest(ctx, testName, nil)
	if err != nil {
		return nil, internalTestError{err, "Init"}
	}
	defer collect.Error(func() error { return cleanup() }, &e)

	// Install the vrpc tool.
	if err := ctx.Run().Command("v23", "go", "install", "v.io/x/ref/cmd/vrpc"); err != nil {
		return nil, internalTestError{err, "Install VRPC"}
	}

	// Describe the test cases.
	namespaceRoot := "/ns.dev.v.io:8101"
	allPassed, suites := true, []xunit.TestSuite{}
	services := []prodService{
		prodService{
			name:       "mounttable",
			objectName: namespaceRoot,
			regexp:     regexp.MustCompile(`MountTable[[:space:]]+interface`),
		},
		prodService{
			name:       "application repository",
			objectName: namespaceRoot + "/applications",
			regexp:     regexp.MustCompile(`Application[[:space:]]+interface`),
		},
		prodService{
			name:       "binary repository",
			objectName: namespaceRoot + "/binaries",
			regexp:     regexp.MustCompile(`Binary[[:space:]]+interface`),
		},
		prodService{
			name:       "macaroon service",
			objectName: namespaceRoot + "/identity/dev.v.io/root/identityd/macaroon",
			regexp:     regexp.MustCompile(`MacaroonBlesser[[:space:]]+interface`),
		},
		prodService{
			name:       "google identity service",
			objectName: namespaceRoot + "/identity/dev.v.io/root/identityd/google",
			regexp:     regexp.MustCompile(`OAuthBlesser[[:space:]]+interface`),
		},
		prodService{
			name:       "binary discharger",
			objectName: namespaceRoot + "/identity/dev.v.io/root/identityd/discharger",
			regexp:     regexp.MustCompile(`Discharger[[:space:]]+interface`),
		},
	}

	for _, service := range services {
		suite, err := testProdService(ctx, service)
		if err != nil {
			return nil, err
		}
		allPassed = allPassed && (suite.Failures == 0)
		suites = append(suites, *suite)
	}

	// Create the xUnit report.
	if err := xunit.CreateReport(ctx, testName, suites); err != nil {
		return nil, err
	}
	if !allPassed {
		return &TestResult{Status: TestFailed}, nil
	}
	return &TestResult{Status: TestPassed}, nil
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"fmt"
	libkb "github.com/keybase/client/go/libkb"
)

type BlockOpsStandard struct {
	config Config
}

func (b *BlockOpsStandard) Get(
	id BlockId, context BlockContext, decryptKey Key, block Block) (
	err error) {
	bserv := b.config.BlockServer()
	// TODO: use server-side block key half along with directory
	// secret key
	var buf []byte
	if buf, err = bserv.Get(id, context); err == nil {
		if context.GetQuotaSize() != uint32(len(buf)) {
			panic(fmt.Sprintf("expected %d bytes, got %d bytes", context.GetQuotaSize(), len(buf)))
		}
		// decrypt the block and unmarshal it
		crypto := b.config.Crypto()
		var debuf []byte
		// TODO: use server-side block key half along with directory
		// secret key
		if debuf, err = crypto.Decrypt(buf, decryptKey); err == nil {
			err = b.config.Codec().Decode(debuf, block)
		}
	}
	return
}

func (b *BlockOpsStandard) Ready(
	block Block, encryptKey Key) (id BlockId, buf []byte, err error) {
	// TODO: add padding
	// first marshal the block
	var plainbuf []byte
	if plainbuf, err = b.config.Codec().Encode(block); err == nil {
		// then encrypt it
		crypto := b.config.Crypto()
		// TODO: use server-side block key half along with directory
		// secret key
		var enbuf []byte
		if enbuf, err = crypto.Encrypt(plainbuf, encryptKey); err == nil {
			// now get the block ID for the buffer
			if h, err2 := crypto.Hash(enbuf); err2 != nil {
				return id, buf, err2
			} else if nhs, ok := h.(libkb.NodeHashShort); !ok {
				return id, buf, &BadCryptoError{id}
			} else {
				return BlockId(nhs), enbuf, nil
			}
		}
	}
	return
}

func (b *BlockOpsStandard) Put(
	id BlockId, context BlockContext, buf []byte) (err error) {
	if context.GetQuotaSize() != uint32(len(buf)) {
		panic(fmt.Sprintf("expected %d bytes, got %d bytes", context.GetQuotaSize(), len(buf)))
	}
	bserv := b.config.BlockServer()
	err = bserv.Put(id, context, buf)
	return
}

func (b *BlockOpsStandard) Delete(id BlockId, context BlockContext) error {
	bserv := b.config.BlockServer()
	err := bserv.Delete(id, context)
	return err
}
<commit_msg>Add more checks in block_ops.go<commit_after>package libkbfs

import (
	"fmt"
	libkb "github.com/keybase/client/go/libkb"
)

type BlockOpsStandard struct {
	config Config
}

func (b *BlockOpsStandard) Get(
	id BlockId, context BlockContext, decryptKey Key, block Block) (
	err error) {
	bserv := b.config.BlockServer()
	// TODO: use server-side block key half along with directory
	// secret key
	var buf []byte
	if buf, err = bserv.Get(id, context); err == nil {
		if context.GetQuotaSize() != uint32(len(buf)) {
			panic(fmt.Sprintf("expected %d bytes, got %d bytes", context.GetQuotaSize(), len(buf)))
		}
		// decrypt the block and unmarshal it
		crypto := b.config.Crypto()
		var debuf []byte
		// TODO: use server-side block key half along with directory
		// secret key
		if debuf, err = crypto.Decrypt(buf, decryptKey); err == nil {
			if len(debuf) > len(buf) {
				panic(fmt.Sprintf("expected at most %d bytes, got %d bytes", len(buf), len(debuf)))
			}
			err = b.config.Codec().Decode(debuf, block)
		}
	}
	return
}

func (b *BlockOpsStandard) Ready(
	block Block, encryptKey Key) (id BlockId, buf []byte, err error) {
	// TODO: add padding
	// first marshal the block
	var plainbuf []byte
	if plainbuf, err = b.config.Codec().Encode(block); err == nil {
		// then encrypt it
		crypto := b.config.Crypto()
		// TODO: use server-side block key half along with directory
		// secret key
		var enbuf []byte
		if enbuf, err = crypto.Encrypt(plainbuf, encryptKey); err == nil {
			if len(enbuf) < len(plainbuf) {
				panic(fmt.Sprintf("expected at lease %d bytes, got %d bytes", len(plainbuf), len(enbuf)))
			}
			// now get the block ID for the buffer
			if h, err2 := crypto.Hash(enbuf); err2 != nil {
				return id, buf, err2
			} else if nhs, ok := h.(libkb.NodeHashShort); !ok {
				return id, buf, &BadCryptoError{id}
			} else {
				return BlockId(nhs), enbuf, nil
			}
		}
	}
	return
}

func (b *BlockOpsStandard) Put(
	id BlockId, context BlockContext, buf []byte) (err error) {
	if context.GetQuotaSize() != uint32(len(buf)) {
		panic(fmt.Sprintf("expected %d bytes, got %d bytes", context.GetQuotaSize(), len(buf)))
	}
	bserv := b.config.BlockServer()
	err = bserv.Put(id, context, buf)
	return
}

func (b *BlockOpsStandard) Delete(id BlockId, context BlockContext) error {
	bserv := b.config.BlockServer()
	err := bserv.Delete(id, context)
	return err
}
<|endoftext|>


<commit_before>package linkedin

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var apiRoot = "https://api.linkedin.com" // api domain
var apiUser = "/v1/people/:id"           // user root
var apiGroup = "/v1/groups/:id"          // group root

// api endpoint path
var apiUrls = map[string]string{
	"profile":     apiUser + ":fields",             // user profile request
	"connections": apiUser + "/connections:fields", // user connections request
	"group":       apiGroup + ":fields",            // group info request
}

// api base
type API struct {
	oauth_key    string // your oauth key
	oauth_secret string // your oauth secret
	access_token string // the user's access token
}

// Set your api key and secret
func (a *API) SetCredentials(key string, secret string) {
	a.oauth_key = key
	a.oauth_secret = secret
}

// Set the access token for this user
func (a *API) SetToken(token string) {
	a.access_token = token
}

// Get the user's access token
func (a API) GetToken() (t string) {
	return a.access_token
}

// Compile the authentication URL
func (a API) AuthUrl(state string, redirect_url string) string {
	aURL := "https://www.linkedin.com/oauth/v2/authorization?"
	params := url.Values{}
	params.Set("response_type", "code")
	params.Set("client_secret", a.oauth_secret)
	params.Set("client_id", a.oauth_key)
	params.Set("state", state)
	params.Set("redirect_uri", redirect_url)
	return aURL + params.Encode()
}

// Convenience method to redirect the user to the authentication url
func (a API) Auth(w http.ResponseWriter, r *http.Request, state string, redirect_url string) {
	http.Redirect(w, r, a.AuthUrl(state, redirect_url), http.StatusFound)
}

// Convert an authorization code to an access token
func (a *API) RetrieveAccessToken(client *http.Client, code string, redirect_url string) (t string, e error) {
	aURL := "https://www.linkedin.com/oauth/v2/accessToken?"
	params := url.Values{}
	params.Set("client_id", a.oauth_key)
	params.Set("client_secret", a.oauth_secret)
	params.Set("grant_type", "authorization_code")
	params.Set("redirect_uri", redirect_url)
	params.Set("code", code)
	resp, err := client.Post(aURL+params.Encode(), "application/x-www-form-urlencoded", nil)
	if err != nil {
		return t, err
	}
	// read the response data
	data, _ := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	// decode the response data to json
	var response map[string]interface{}
	err = json.Unmarshal(data, &response)
	if err != nil {
		return t, err
	}
	// if there is an "error" index something went wrong
	if _, err := response["error"]; err {
		return t, errors.New(response["error"].(string) + " - " + response["error_description"].(string))
	}
	// pull out the token
	t = response["access_token"].(string)
	// set my access token
	a.SetToken(t)
	// return token
	return t, nil
}

// format the given user id for api calls
func getUserIdString(id string) (uid string) {
	if id == "~" || id == "" {
		return "~" // me
	} else if strings.Contains(id, "http") {
		return "url=" + url.QueryEscape(id) // someone else
	} else {
		return "id=" + id // someone else's url
	}
}

// format the given group id for api calls
func getGroupIdString(id interface{}) (gid string, err error) {
	switch t := id.(type) {
	case string:
		if strings.Contains(id.(string), "http") {
			return "url=" + url.QueryEscape(id.(string)), nil // group url
		}
		return id.(string), nil // group id as a string
	case uint64:
		return strconv.FormatUint(id.(uint64), 10), nil // group id as an int
	default:
		return gid, errors.New(fmt.Sprintf("Group ID type exception: Expecting string or uint64 got %T", t))
	}
}

// Make a call to get info about the given user's profile
func (a API) Profile(client *http.Client, user_id string, fields Fields) (j map[string]interface{}, err error) {
	return a.request(client, "profile", map[string]string{
		"id":     getUserIdString(user_id),
		"fields": fields.Encode(),
	}, nil)
}

// Make a call to get info about the given user's connections
func (a API) Connections(client *http.Client, user_id string, fields Fields, params url.Values) (j map[string]interface{}, err error) {
	return a.request(client, "connections", map[string]string{
		"id":     getUserIdString(user_id),
		"fields": fields.Encode(),
	}, params)
}

// Make a call to get info about the given group
/*func (a API) Group(client *http.Client, group_id interface{}, fields Fields) (j map[string]interface{}, err error) {
	gid, err := getGroupIdString(group_id)
	if err != nil {
		return j, err
	}

	return a.request(client, "group", map[string]string{
		"id": gid,
		"fields": fields.Encode(),
	}, nil)
}*/

// Make a raw api call
func (a API) Raw(client *http.Client, u interface{}) (j map[string]interface{}, e error) {
	endpoint := url.URL{} // initialize the url

	switch t := u.(type) {
	default:
		return nil, errors.New(fmt.Sprintf("Expecting string or *url.URL, got %v: %#v", t, u))
	case string: // the url provided is a string so we need to parse it
		ep, err := url.Parse(u.(string))
		if err != nil {
			return nil, err
		}
		endpoint = *ep
	case url.URL: // the url provided is already parsed
		endpoint = u.(url.URL)
	}

	qs := endpoint.Query()
	qs.Add("oauth2_access_token", a.access_token) // add the access token to the query

	req, _ := http.NewRequest("GET", apiRoot+endpoint.Path+"?"+qs.Encode(), nil) // make a new request
	req.URL.Opaque = endpoint.Path                                               // make sure it doesn't query string encode the path
	req.Header.Add("x-li-format", "json")                                        // we want json

	r, err := client.Do(req) // send the request

	if err != nil {
		return nil, err
	}

	data, _ := ioutil.ReadAll(r.Body) // read the response data
	r.Body.Close()

	var d map[string]interface{}
	err = json.Unmarshal(data, &d) // convert the response data to json

	if err != nil {
		return nil, err
	}

	if _, error := d["errorCode"]; error { // if an error code is provided in the json something went wrong
		err = errors.New(string(data))
		return nil, err
	}

	return d, nil
}

// Convenience method for normal api calls
func (a API) request(client *http.Client, endpoint string, options map[string]string, params url.Values) (j map[string]interface{}, e error) {
	ep, ok := apiUrls[endpoint]
	if !ok {
		return nil, errors.New("Endpoint \"" + endpoint + "\" not defined")
	}

	for field, value := range options {
		ep = strings.Replace(ep, ":"+field, value, -1)
	}

	if len(params) > 0 {
		ep += "?" + params.Encode()
	}

	u, err := url.Parse(ep)
	if err != nil {
		return nil, err
	}

	return a.Raw(client, *u)
}

//Conveient method for raw api calls which returns JSON in bytes format
//
//This is an open format so anyone if wanted to unmarshal to struct or any map[string]interface{}
func (a API) RawResult(client *http.Client, u interface{}) (j []byte, e error) {
	endpoint := url.URL{} // initialize the url

	switch t := u.(type) {
	default:
		return nil, errors.New(fmt.Sprintf("Expecting string or *url.URL, got %v: %#v", t, u))
	case string: // the url provided is a string so we need to parse it
		ep, err := url.Parse(u.(string))
		if err != nil {
			return nil, err
		}
		endpoint = *ep
	case url.URL: // the url provided is already parsed
		endpoint = u.(url.URL)
	}

	qs := endpoint.Query()
	qs.Add("oauth2_access_token", a.access_token) // add the access token to the query

	req, _ := http.NewRequest("GET", apiRoot+endpoint.Path+"?"+qs.Encode(), nil) // make a new request
	req.URL.Opaque = endpoint.Path                                               // make sure it doesn't query string encode the path
	req.Header.Add("x-li-format", "json")                                        // we want json

	r, err := client.Do(req) // send the request

	if err != nil {
		return nil, err
	}

	data, _ := ioutil.ReadAll(r.Body) // read the response data
	r.Body.Close()

	return data, nil
}

//Convenient method for normal POST/PUT call
//
//This api call will allow you to submit a comment and shares to linkedin
//
//https://developer.linkedin.com/docs/company-pages#company_comment
//https://developer.linkedin.com/docs/company-pages#company_share
func (a *API) SendRequest(client *http.Client, u interface{}, method string, params map[string]interface{}) (j map[string]interface{}, e error) {
	endpoint := url.URL{} // initialize the url
	switch t := u.(type) {
	default:
		return nil, errors.New(fmt.Sprintf("Expecting string or *url.URL, got %v: %#v", t, u))
	case string: // the url provided is a string so we need to parse it
		ep, err := url.Parse(u.(string))
		if err != nil {
			return nil, err
		}
		endpoint = *ep
	case url.URL: // the url provided is already parsed
		endpoint = u.(url.URL)
	}

	qs := endpoint.Query()
	qs.Add("oauth2_access_token", a.access_token) // add the access token to the query
	jsonStr, err := json.Marshal(params)
	if err != nil {
		fmt.Println("Can't reach linkedin server: ", err)
	}
	buf := bytes.NewBuffer([]byte(jsonStr))                                       //Create new buffer with the json bytes
	req, _ := http.NewRequest(method, apiRoot+endpoint.Path+"?"+qs.Encode(), buf) // make a new request
	req.URL.Opaque = endpoint.Path                                                // make sure it doesn't query string encode the path
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("x-li-format", "json") // sending to json format

	r, err := client.Do(req) // send the request
	if err != nil {
		return nil, err
	}

	data, _ := ioutil.ReadAll(r.Body) // read the response data
	r.Body.Close()
	var d map[string]interface{}
	if len(data) > 0 {
		err = json.Unmarshal(data, &d)
		// convert the response data to json
		// It willl happen only if it fails to send
		if err != nil {
			return nil, err
		}
		if _, error := d["errorCode"]; error { // if an error code is provided in the json something went wrong
			err = errors.New(string(data))
			return nil, err
		}
	}
	return d, nil
}
<commit_msg>Linkedin API v2 compatibility<commit_after>package linkedin

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var (
	apiVer     = "/v2/"
	apiRoot    = "https://api.linkedin.com" + apiVer // api domain
	apiProfile = apiRoot + "me"                      // user root
	//PeopleURL https://docs.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api?context=linkedin/marketing/context
	PeopleURL = apiRoot + "people/(id:{people-id})"
	apiGroup  = "groups/:id" // group root
	//OrgURL https://docs.microsoft.com/en-us/linkedin/marketing/integrations/community-management/organizations/organization-access-control#find-access-control-information
	OrgURL = apiRoot + "organizationAcls"
	//PageURL https://docs.microsoft.com/en-us/linkedin/marketing/integrations/community-management/organizations/organization-lookup-api h
	PageURL = apiRoot + "organizations"
	//ShareURL  https://docs.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/share-api
	ShareURL = apiRoot + "shares"
	//CommentURL https://docs.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/network-update-social-actions#retrieve-social-actions
	CommentURL     = apiRoot + "socialActions/{activity-id}/comments"
	authURL        = "https://www.linkedin.com/oauth/v2/authorization"
	accessTokenURL = "https://www.linkedin.com/oauth/v2/accessToken"
	scopes         = []string{"r_organization_social", "w_organization_social", "rw_organization_admin", "rw_ads", "r_ads_reporting", "r_liteprofile"}
	//ProfileURL ....
	ProfileURL = apiProfile
)

// api endpoint path
var apiUrls = map[string]string{
	"profile":     apiProfile,                         // user profile request
	"connections": apiProfile + "/connections:fields", // user connections request
	"group":       apiGroup + ":fields",               // group info request
}

// API base
type API struct {
	OauthKey     string // your oauth key
	OauthSecret  string // your oauth secret
	AccessToken  string // the user's access token
	RefreshToken string
}

// SetCredentials your api key and secret
func (a *API) SetCredentials(key string, secret string) {
	a.OauthKey = key
	a.OauthSecret = secret
}

// SetToken the access token for this user
func (a *API) SetToken(token string) {
	a.AccessToken = token
}

// GetToken the user's access token
func (a API) GetToken() (t string) {
	return a.AccessToken
}

//AuthURL Compile the authentication URL
func (a API) AuthURL(state string, redirectURL string) (URL string) {
	scp := strings.Join(scopes, "%20")
	return authURL + "?response_type=code&client_id=" + a.OauthKey +
		"&state=" + state + "&redirect_uri=" + redirectURL + "&scope=" + scp
}

//Auth Convenience method to redirect the user to the authentication url
func (a API) Auth(w http.ResponseWriter, r *http.Request, state string, redirectURL string) {
	http.Redirect(w, r, a.AuthURL(state, redirectURL), http.StatusFound)
}

//RetrieveAccessToken Convert an authorization code to an access token
func (a *API) RetrieveAccessToken(client *http.Client, code string, redirectURL string) ([]byte, error) {
	var response []byte
	// send the request
	resp, err := client.Get(accessTokenURL + "?grant_type=authorization_code&code=" + code + "&redirect_uri=" +
		redirectURL + "&client_id=" + a.OauthKey + "&client_secret=" + a.OauthSecret)

	if err != nil {
		return response, err
	}
	response, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return response, err
	}
	defer resp.Body.Close()

	return response, nil
}

// format the given user id for api calls
func getUserIdString(id string) (uid string) {
	if id == "~" || id == "" {
		return "~" // me
	} else if strings.Contains(id, "http") {
		return "url=" + url.QueryEscape(id) // someone else
	} else {
		return "id=" + id // someone else's url
	}
}

//getGroupIdString format the given group id for api calls
func getGroupIdString(id interface{}) (gid string, err error) {
	switch t := id.(type) {
	case string:
		if strings.Contains(id.(string), "http") {
			return "url=" + url.QueryEscape(id.(string)), nil // group url
		}
		return id.(string), nil // group id as a string
	case uint64:
		return strconv.FormatUint(id.(uint64), 10), nil // group id as an int
	default:
		return gid, fmt.Errorf("Group ID type exception: Expecting string or uint64 got %T", t)
	}
}

//Raw Make an http request to get results
func (a API) Raw(client *http.Client, u string, params url.Values) ([]byte, error) {
	req, err := http.NewRequest("GET", u, nil) // make a new request
	if err != nil {
		return nil, err
	}
	if params != nil {
		req.URL.RawQuery = params.Encode()
	}
	token := a.GetToken()
	req.Header.Add("Authorization", "Bearer "+token)
	req.Header.Add("X-Restli-Protocol-Version", "2.0.0")

	r, err := client.Do(req) // send the request

	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(r.Body) // read the response data
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()

	return data, nil
}

// Convenience method for normal api calls
func (a API) request(client *http.Client, endpoint string, options map[string]string, params url.Values) ([]byte, error) {
	ep, ok := apiUrls[endpoint]
	if !ok {
		return nil, errors.New("Endpoint \"" + endpoint + "\" not defined")
	}

	for field, value := range options {
		ep = strings.Replace(ep, ":"+field, value, -1)
	}

	if len(params) > 0 {
		ep += "?" + params.Encode()
	}

	return a.Raw(client, ep, nil)
}

//RawNonHeader Conveient method for raw api calls which returns JSON in bytes format
//
//This is an open format so anyone if wanted to unmarshal to struct or any map[string]interface{}
func (a API) RawNonHeader(client *http.Client, URL string, params url.Values) (j []byte, e error) {
	req, err := http.NewRequest("GET", URL, nil) // make a new request
	if err != nil {
		return nil, err
	}
	if params != nil {
		req.URL.RawQuery = params.Encode()
	}
	token := a.GetToken()
	req.Header.Add("Authorization", "Bearer "+token)
	r, err := client.Do(req) // send the request
	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(r.Body) // read the response data
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()

	return data, nil
}

//SendRequest Convenient method for normal POST/PUT call
//
//This api call will allow you to submit a comment and shares to linkedin
//
//https://developer.linkedin.com/docs/company-pages#company_comment
//https://developer.linkedin.com/docs/company-pages#company_share
func (a *API) SendRequest(client *http.Client, URL string, params map[string]interface{}) ([]byte, error) {
	if params == nil {
		return nil, errors.New("empty params can not send")
	}
	jsonByte, err := json.Marshal(params)
	if err != nil {
		return nil, err
	}
	log.Printf("jsonByte=%v", string(jsonByte))
	req, err := http.NewRequest(http.MethodPost, URL, bytes.NewBuffer(jsonByte))
	if err != nil {
		return nil, err
	}
	token := a.GetToken()
	req.Header.Add("Authorization", "Bearer "+token)
	//req.Header.Add("X-Restli-Protocol-Version", "2.0.0")
	//req.Header.Add("Content-Type", "application/json")

	r, err := client.Do(req) // send the request

	if err != nil {
		return nil, err
	}

	data, err := ioutil.ReadAll(r.Body) // read the response data
	if err != nil {
		return nil, err
	}
	defer r.Body.Close()

	return data, nil
}
<|endoftext|>


<commit_before>package define

import (
	"fmt"
	"runtime"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////////////

// SetExtend 设置扩展
func (record LogRecord) SetExtend(tp uint8, data []interface{}) {
	record.Extend = make([]interface{}, 1, len(data)+1)
	record.Extend[0] = tp
	record.Extend = append(record.Extend, data...)
}

// GetExtend 获取扩展
func (record LogRecord) GetExtend() (tp uint8, data []interface{}) {
	tp = EXNone
	data = nil
	elen := len(record.Extend)
	if elen > 0 {
		tp = record.Extend[0].(uint8)
		if elen > 1 {
			data = record.Extend[1:]
		}
	}
	return
}

////////////////////////////////////////////////////////////////////////////////////

// Close 关闭
func (log Logger) Close() {
	for key, filt := range log {
		if filt != nil {
			filt.Close()
		}
		delete(log, key)
	}
}

// AddFilter 增加过滤器
func (log Logger) AddFilter(tag string, writer LogWriter, lvl uint8) Logger {
	log[tag] = &Filter{writer, lvl}
	return log
}

// checkSkip 检查
func (log Logger) checkSkip(lvl uint8) bool {
	for _, filt := range log {
		if filt != nil && lvl >= filt.Level {
			return false
		}
	}
	return true
}

// checkReport 上报
func (log Logger) checkReport(rptp uint8) bool {
	if rptp <= 0 {
		return true
	}
	for _, filt := range log {
		if filt != nil && rptp == filt.GetReportType() {
			return true
		}
	}
	return false
}

// dispatchLog 分发日志
func (log Logger) dispatchLog(rec *LogRecord, rptp uint8) {
	if rec != nil {
		for _, filt := range log {
			if filt != nil && rec.Level >= filt.Level {
				if rptp > 0 && rptp != filt.GetReportType() {
					continue
				}
				filt.LogWrite(rec)
			}
		}
	}
}

// getRunCaller 获取调用地址
func getRunCaller(skip int) string {
	pc, _, lineno, ok := runtime.Caller(skip + 1)
	if ok {
		return fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
	}
	return ""
}

// Send a formatted log message internally
func (log Logger) intLogf(skip int, lvl uint8, format string, args ...interface{}) {
	if log.checkSkip(lvl) == true {
		return
	}
	msg := format
	if len(args) > 0 {
		msg = fmt.Sprintf(format, args...)
	}
	log.dispatchLog(&LogRecord{
		Level:   lvl,
		Created: time.Now(),
		Source:  getRunCaller(skip + 1),
		Message: msg,
	}, 0)
}

// Log Send a log message with manual level, source, and message.
func (log Logger) Log(lvl uint8, source, message string) {
	if log.checkSkip(lvl) == true {
		return
	}
	log.dispatchLog(&LogRecord{
		Level:   lvl,
		Created: time.Now(),
		Source:  source,
		Message: message,
	}, 0)
}

// Logf format 日志输出
func (log Logger) Logf(lvl uint8, format string, args ...interface{}) {
	log.intLogf(1, lvl, format, args...)
}

// Logfs format 日志输出
func (log Logger) Logfs(skip int, lvl uint8, format string, args ...interface{}) {
	if skip <= 0 {
		skip = 1
	}
	log.intLogf(skip, lvl, format, args...)
}

// LogReport 上报
func (log Logger) LogReport(skip int, rptp, extp uint8, exdt ...interface{}) {
	if log.checkSkip(REPORT) == true || log.checkReport(rptp) == false {
		return
	}
	record := &LogRecord{
		Level:   REPORT,
		Created: time.Now(),
		Source:  getRunCaller(skip + 1),
	}
	if extp > 0 {
		record.SetExtend(extp, exdt)
	} else if len(exdt) > 0 {
		record.Message = exdt[0].(string)
	}
	log.dispatchLog(record, rptp)
}

func (log Logger) getArg(arg0 interface{}, larg int) string {
	var msg string
	switch first := arg0.(type) {
	case string:
		msg = first
	case func() string:
		msg = first()
	default:
		msg = fmt.Sprint(arg0) + strings.Repeat(" %v", larg)
	}
	return msg
}

// LogCmm 日志输出处理
func (log Logger) LogCmm(lvl uint8, arg0 interface{}, args ...interface{}) {
	log.Logf(lvl, log.getArg(arg0, len(args)), args...)
}

// LogCmms 日志输出处理
func (log Logger) LogCmms(skip int, lvl uint8, arg0 interface{}, args ...interface{}) {
	log.Logfs(skip, lvl, log.getArg(arg0, len(args)), args...)
}

// Finest 最好log
func (log Logger) Finest(arg0 interface{}, args ...interface{}) {
	log.LogCmm(FINEST, arg0, args...)
}

// Fine 好log
func (log Logger) Fine(arg0 interface{}, args ...interface{}) {
	log.LogCmm(FINE, arg0, args...)
}

// Debug 调试log
func (log Logger) Debug(arg0 interface{}, args ...interface{}) {
	log.LogCmm(DEBUG, arg0, args...)
}

// Trace 追踪log
func (log Logger) Trace(arg0 interface{}, args ...interface{}) {
	log.LogCmm(TRACE, arg0, args...)
}

// Info 信息log
func (log Logger) Info(arg0 interface{}, args ...interface{}) {
	log.LogCmm(INFO, arg0, args...)
}

// Warn 警告log
func (log Logger) Warn(arg0 interface{}, args ...interface{}) {
	log.LogCmm(WARNING, arg0, args...)
}

// Error 错误log
func (log Logger) Error(arg0 interface{}, args ...interface{}) {
	log.LogCmm(ERROR, arg0, args...)
}

// Fatal 致命log
func (log Logger) Fatal(arg0 interface{}, args ...interface{}) {
	log.LogCmm(FATAL, arg0, args...)
}

// Report 上报log
func (log Logger) Report(rptp uint8, arg0 interface{}, args ...interface{}) {
	log.Reports(2, rptp, arg0, args...)
}

// Reports 上报log
func (log Logger) Reports(skip int, rptp uint8, arg0 interface{}, args ...interface{}) {
	msg := log.getArg(arg0, len(args))
	if len(args) > 0 {
		msg = fmt.Sprintf(msg, args...)
	}
	if skip <= 0 {
		skip = 1
	}
	log.LogReport(skip, rptp, 0, msg)
}

// Flume flume上报
func (log Logger) Flume(arg0 interface{}, args ...interface{}) {
	log.Report(FLUME, arg0, args...)
}

// FlumeAPI flume api上报
func (log Logger) FlumeAPI(url string, header interface{}, body interface{}) {
	log.LogReport(1, FLUME, EXUrlHeadBody, url, header, body)
}

// CatTransaction cat transaction支持
func (log Logger) CatTransaction(name string, status interface{}, data interface{}) {
	log.LogReport(1, CAT, EXCatTransaction, name, status, data)
}

// CatEvent cat event支持
func (log Logger) CatEvent(name string, status interface{}, data interface{}) {
	log.LogReport(1, CAT, EXCatEvent, name, status, data)
}

// CatError cat error支持
func (log Logger) CatError(name string, err interface{}) {
	log.LogReport(1, CAT, EXCatError, name, err)
}

// CatMetricCount cat metric count支持
func (log Logger) CatMetricCount(name string, count ...int) {
	if len(count) <= 0 {
		log.LogReport(1, CAT, EXCatMetricCount, name)
	} else {
		log.LogReport(1, CAT, EXCatMetricCount, name, count[0])
	}
}

// CatMetricDuration cat metric duration支持
func (log Logger) CatMetricDuration(name string, duration int64) {
	log.LogReport(1, CAT, EXCatMetricDuration, name, duration)
}
<commit_msg>update<commit_after>package define

import (
	"fmt"
	"runtime"
	"strings"
	"time"
)

////////////////////////////////////////////////////////////////////////////////////

// SetExtend 设置扩展
func (record LogRecord) SetExtend(tp uint8, data []interface{}) {
	record.Extend = make([]interface{}, 1, len(data)+1)
	record.Extend[0] = tp
	record.Extend = append(record.Extend, data...)
}

// GetExtend 获取扩展
func (record LogRecord) GetExtend() (tp uint8, data []interface{}) {
	tp = EXNone
	data = nil
	elen := len(record.Extend)
	if elen > 0 {
		tp = record.Extend[0].(uint8)
		if elen > 1 {
			data = record.Extend[1:]
		}
	}
	return
}

////////////////////////////////////////////////////////////////////////////////////

// Close 关闭
func (log Logger) Close() {
	for key, filt := range log {
		if filt != nil {
			filt.Close()
		}
		delete(log, key)
	}
}

// AddFilter 增加过滤器
func (log Logger) AddFilter(tag string, writer LogWriter, lvl uint8) Logger {
	log[tag] = &Filter{writer, lvl}
	return log
}

// checkSkip 检查
func (log Logger) checkSkip(lvl uint8) bool {
	for _, filt := range log {
		if filt != nil && lvl >= filt.Level {
			return false
		}
	}
	return true
}

// checkReport 上报
func (log Logger) checkReport(rptp uint8) bool {
	if rptp <= 0 {
		return true
	}
	for _, filt := range log {
		if filt != nil && rptp == filt.GetReportType() {
			return true
		}
	}
	return false
}

// dispatchLog 分发日志
func (log Logger) dispatchLog(rec *LogRecord, rptp uint8) {
	if rec != nil {
		for _, filt := range log {
			if filt != nil && rec.Level >= filt.Level {
				if rptp > 0 && rptp != filt.GetReportType() {
					continue
				}
				filt.LogWrite(rec)
			}
		}
	}
}

// getRunCaller 获取调用地址
func getRunCaller(skip int) string {
	pc, _, lineno, ok := runtime.Caller(skip + 1)
	if ok {
		return fmt.Sprintf("%s:%d", runtime.FuncForPC(pc).Name(), lineno)
	}
	return ""
}

// Send a formatted log message internally
func (log Logger) intLogf(skip int, lvl uint8, format string, args ...interface{}) {
	if log.checkSkip(lvl) == true {
		return
	}
	msg := format
	if len(args) > 0 {
		msg = fmt.Sprintf(format, args...)
	}
	log.dispatchLog(&LogRecord{
		Level:   lvl,
		Created: time.Now(),
		Source:  getRunCaller(skip + 1),
		Message: msg,
	}, 0)
}

// Log Send a log message with manual level, source, and message.
func (log Logger) Log(lvl uint8, source, message string) {
	if log.checkSkip(lvl) == true {
		return
	}
	log.dispatchLog(&LogRecord{
		Level:   lvl,
		Created: time.Now(),
		Source:  source,
		Message: message,
	}, 0)
}

// Logf format 日志输出
func (log Logger) Logf(skip int, lvl uint8, format string, args ...interface{}) {
	if skip <= 0 {
		skip = 1
	}
	log.intLogf(skip, lvl, format, args...)
}

// LogReport 上报
func (log Logger) LogReport(skip int, rptp, extp uint8, exdt ...interface{}) {
	if log.checkSkip(REPORT) == true || log.checkReport(rptp) == false {
		return
	}
	record := &LogRecord{
		Level:   REPORT,
		Created: time.Now(),
		Source:  getRunCaller(skip + 1),
	}
	if extp > 0 {
		record.SetExtend(extp, exdt)
	} else if len(exdt) > 0 {
		record.Message = exdt[0].(string)
	}
	log.dispatchLog(record, rptp)
}

func (log Logger) getArg(arg interface{}, larg int) string {
	var msg string
	switch first := arg.(type) {
	case string:
		msg = first
	case func() string:
		msg = first()
	default:
		msg = fmt.Sprint(arg) + strings.Repeat(" %v", larg)
	}
	return msg
}

// LogCmm 日志输出处理
func (log Logger) LogCmm(lvl uint8, arg interface{}, args ...interface{}) {
	log.LogCmms(4, lvl, arg, args...)
}

// LogCmms 日志输出处理
func (log Logger) LogCmms(skip int, lvl uint8, arg interface{}, args ...interface{}) {
	log.Logf(skip, lvl, log.getArg(arg, len(args)), args...)
}

// Finest 最好log
func (log Logger) Finest(arg interface{}, args ...interface{}) {
	log.LogCmm(FINEST, arg, args...)
}

// Fine 好log
func (log Logger) Fine(arg interface{}, args ...interface{}) {
	log.LogCmm(FINE, arg, args...)
}

// Debug 调试log
func (log Logger) Debug(arg interface{}, args ...interface{}) {
	log.LogCmm(DEBUG, arg, args...)
}

// Trace 追踪log
func (log Logger) Trace(arg interface{}, args ...interface{}) {
	log.LogCmm(TRACE, arg, args...)
}

// Info 信息log
func (log Logger) Info(arg interface{}, args ...interface{}) {
	log.LogCmm(INFO, arg, args...)
}

// Warn 警告log
func (log Logger) Warn(arg interface{}, args ...interface{}) {
	log.LogCmm(WARNING, arg, args...)
}

// Error 错误log
func (log Logger) Error(arg interface{}, args ...interface{}) {
	log.LogCmm(ERROR, arg, args...)
}

// Fatal 致命log
func (log Logger) Fatal(arg interface{}, args ...interface{}) {
	log.LogCmm(FATAL, arg, args...)
}

// Report 上报log
func (log Logger) Report(rptp uint8, arg interface{}, args ...interface{}) {
	log.Reports(4, rptp, arg, args...)
}

// Reports 上报log
func (log Logger) Reports(skip int, rptp uint8, arg interface{}, args ...interface{}) {
	msg := log.getArg(arg, len(args))
	if len(args) > 0 {
		msg = fmt.Sprintf(msg, args...)
	}
	if skip <= 0 {
		skip = 2
	}
	log.LogReport(skip, rptp, 0, msg)
}

// Flume flume上报
func (log Logger) Flume(arg interface{}, args ...interface{}) {
	log.Report(FLUME, arg, args...)
}

// FlumeAPI flume api上报
func (log Logger) FlumeAPI(url string, header interface{}, body interface{}) {
	log.LogReport(2, FLUME, EXUrlHeadBody, url, header, body)
}

// CatTransaction cat transaction支持
func (log Logger) CatTransaction(name string, status interface{}, data interface{}) {
	log.LogReport(2, CAT, EXCatTransaction, name, status, data)
}

// CatEvent cat event支持
func (log Logger) CatEvent(name string, status interface{}, data interface{}) {
	log.LogReport(2, CAT, EXCatEvent, name, status, data)
}

// CatError cat error支持
func (log Logger) CatError(name string, err interface{}) {
	log.LogReport(2, CAT, EXCatError, name, err)
}

// CatMetricCount cat metric count支持
func (log Logger) CatMetricCount(name string, count ...int) {
	if len(count) <= 0 {
		log.LogReport(2, CAT, EXCatMetricCount, name)
	} else {
		log.LogReport(2, CAT, EXCatMetricCount, name, count[0])
	}
}

// CatMetricDuration cat metric duration支持
func (log Logger) CatMetricDuration(name string, duration int64) {
	log.LogReport(2, CAT, EXCatMetricDuration, name, duration)
}
<|endoftext|>


<commit_before>package dropp

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	gq "github.com/PuerkitoBio/goquery"
)

// Snapshot contains a snapshot of the current status of an item.
type Snapshot struct {
	Availability string
	OnEbay       bool
	Price        float64
	CreatedAt    time.Time
}

// SnapshotDiff Is created if there is a difference between the current and the
// previous snaphot.
type SnapshotDiff struct {
	ItemName       string
	ItemURL        string
	PreviousAva    string
	PreviousStatus bool
	PreviousPrice  float64
	CurrentAva     string
	CurrentStatus  bool
	CurrentPrice   float64
}

// EbayPrice contains the price and currency as fetched from the Ebay service
type EbayPrice struct {
	CurrencyID string `json:"_currencyID"`
	Value      string `json:"value"`
}

// EbayItem is the full item generated by the Ebay service
type EbayItem struct {
	CurrentPrice EbayPrice `json:"current_price"`
	ID           string    `json:"id"`
	ItemName     string    `json:"name"`
	StockCount   string    `json:"quantity"`
	SoldCount    string    `json:"quantity_sold"`
	Status       string    `json:"status"`
	ItemPageURL  string    `json:"url"`
}

// BGData is a partial representation ot the data JSON for a BG item
type BGData struct {
	Message string  `json:"message"`
	Price   float64 `json:"final_price"`
}

func (snap *Snapshot) getBGAva(response *http.Response) {
	// Scrape the page and get availability
	log.Print("Scraping BG page to retrieve availability")
	doc, err := gq.NewDocumentFromResponse(response)
	if err != nil {
		panic(err.Error())
	}
	ava := doc.Find(".status").Text()
	snap.Availability = ava
	return
}
func (snap *Snapshot) getSourceData(response *http.Response) {
	data := BGData{}
	err := json.NewDecoder(response.Body).Decode(&data)
	if err != nil {
		log.Printf("Error while decoding BG data for item %s: %s", response.Request.URL, err)
		return
	}
	snap.Availability = data.Message
	snap.Price = data.Price
}

func (snap *Snapshot) getEbayStatus(response *http.Response) {
	ebayItem := EbayItem{}

	err := json.NewDecoder(response.Body).Decode(&ebayItem)
	if err != nil {
		log.Printf("Error while converting the Ebay JSON %s", err)
		return
	}

	log.Printf("The status of item %s is %s", ebayItem.ID, ebayItem.Status)

	if ebayItem.Status == "Active" {
		snap.OnEbay = true
	} else {
		snap.OnEbay = false
	}
}
<commit_msg>[DPP-97] Added european JSON data unmarshalling fallback<commit_after>package dropp

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"time"

	gq "github.com/PuerkitoBio/goquery"
)

// Snapshot contains a snapshot of the current status of an item.
type Snapshot struct {
	Availability string
	OnEbay       bool
	Price        float64
	CreatedAt    time.Time
}

// SnapshotDiff Is created if there is a difference between the current and the
// previous snaphot.
type SnapshotDiff struct {
	ItemName       string
	ItemURL        string
	PreviousAva    string
	PreviousStatus bool
	PreviousPrice  float64
	CurrentAva     string
	CurrentStatus  bool
	CurrentPrice   float64
}

// EbayPrice contains the price and currency as fetched from the Ebay service
type EbayPrice struct {
	CurrencyID string `json:"_currencyID"`
	Value      string `json:"value"`
}

// EbayItem is the full item generated by the Ebay service
type EbayItem struct {
	CurrentPrice EbayPrice `json:"current_price"`
	ID           string    `json:"id"`
	ItemName     string    `json:"name"`
	StockCount   string    `json:"quantity"`
	SoldCount    string    `json:"quantity_sold"`
	Status       string    `json:"status"`
	ItemPageURL  string    `json:"url"`
}

// BGData is a partial representation ot the data JSON for a Chinese BG item
type BGData struct {
	Message string  `json:"message"`
	Price   float64 `json:"final_price"`
}

// BGDataEuro is a partial representation ot the data JSON for a Euro BG item
type BGDataEuro struct {
	Message string `json:"message"`
	Price   string `json:"final_price"`
}

func (snap *Snapshot) getBGAva(response *http.Response) {
	// Scrape the page and get availability
	log.Print("Scraping BG page to retrieve availability")
	doc, err := gq.NewDocumentFromResponse(response)
	if err != nil {
		panic(err.Error())
	}
	ava := doc.Find(".status").Text()
	snap.Availability = ava
	return
}
func (snap *Snapshot) getSourceData(response *http.Response) {
	data := BGData{}
	dataEuro := BGDataEuro{}
	var respBody []byte

	// Copy body content in a buffer variable so that it can be re-read and
	// close the request body.
	respBody, err := ioutil.ReadAll(response.Body)
	response.Body = ioutil.NopCloser(bytes.NewBuffer(respBody))

	// Try unmarshalling a the response using the proper object.
	err = json.Unmarshal(respBody, &data)
	if err != nil {
		log.Printf("Error while decoding BG data for item %s: %s",
			response.Request.URL,
			err)
		log.Print("Trying to parse object as EU data")

		// If the previous unmarshalling fails try agin with a different schema.
		err := json.Unmarshal(respBody, &dataEuro)
		if err != nil {
			log.Printf("Error while decoding European BG data for item %s: %s",
				response.Request.URL,
				err)
			log.Print("Giving up on trying to parse BG data")
			return
		}
		log.Printf("European price: %s", dataEuro.Price)
		price, err := strconv.ParseFloat(dataEuro.Price, 64)
		if err != nil {
			log.Printf("Error while decoding European BG price for item %s: %s",
				response.Request.URL,
				err)
			return
		}

		// Update the price in the proper object.
		data.Message = dataEuro.Message
		data.Price = price
	}

	snap.Availability = data.Message
	snap.Price = data.Price
}

func (snap *Snapshot) getEbayStatus(response *http.Response) {
	ebayItem := EbayItem{}

	err := json.NewDecoder(response.Body).Decode(&ebayItem)
	if err != nil {
		log.Printf("Error while converting the Ebay JSON %s", err)
		return
	}

	log.Printf("The status of item %s is %s", ebayItem.ID, ebayItem.Status)

	if ebayItem.Status == "Active" {
		snap.OnEbay = true
	} else {
		snap.OnEbay = false
	}
}
<|endoftext|>


<commit_before>// +build !windows

package main

import "syscall"

func verifyDiskStorage(storagePath string) (uint64, error) {
	var stat syscall.Statfs_t
	err := syscall.Statfs(storagePath, &stat)
	if err != nil {
		return 0, err
	}
	avail := stat.Bavail * uint64(stat.Bsize)
	return avail, nil
}
<commit_msg>rename method<commit_after>// +build !windows

package main

import "syscall"

func osDiskStat(storagePath string) (uint64, error) {
	var stat syscall.Statfs_t
	err := syscall.Statfs(storagePath, &stat)
	if err != nil {
		return 0, err
	}
	avail := stat.Bavail * uint64(stat.Bsize)
	return avail, nil
}
<|endoftext|>


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

// +build appengine

package build

import (
	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/mail"
	"bytes"
	"encoding/gob"
	"fmt"
	"text/template"
)

const (
	mailFrom   = "builder@golang.org" // use this for sending any mail
	failMailTo = "golang-dev@googlegroups.com"
	domain     = "build.golang.org"
)

// failIgnore is a set of builders that we don't email about because
// they're too flaky.
var failIgnore = map[string]bool{
	"netbsd-386-bsiegert":   true,
	"netbsd-amd64-bsiegert": true,
}

// notifyOnFailure checks whether the supplied Commit or the subsequent
// Commit (if present) breaks the build for this builder.
// If either of those commits break the build an email notification is sent
// from a delayed task. (We use a task because this way the mail won't be
// sent if the enclosing datastore transaction fails.)
//
// This must be run in a datastore transaction, and the provided *Commit must
// have been retrieved from the datastore within that transaction.
func notifyOnFailure(c appengine.Context, com *Commit, builder string) error {
	if failIgnore[builder] {
		return nil
	}

	// TODO(adg): implement notifications for packages
	if com.PackagePath != "" {
		return nil
	}

	p := &Package{Path: com.PackagePath}
	var broken *Commit
	cr := com.Result(builder, "")
	if cr == nil {
		return fmt.Errorf("no result for %s/%s", com.Hash, builder)
	}
	q := datastore.NewQuery("Commit").Ancestor(p.Key(c))
	if cr.OK {
		// This commit is OK. Notify if next Commit is broken.
		next := new(Commit)
		q = q.Filter("ParentHash=", com.Hash)
		if err := firstMatch(c, q, next); err != nil {
			if err == datastore.ErrNoSuchEntity {
				// OK at tip, no notification necessary.
				return nil
			}
			return err
		}
		if nr := next.Result(builder, ""); nr != nil && !nr.OK {
			c.Debugf("commit ok: %#v\nresult: %#v", com, cr)
			c.Debugf("next commit broken: %#v\nnext result:%#v", next, nr)
			broken = next
		}
	} else {
		// This commit is broken. Notify if the previous Commit is OK.
		prev := new(Commit)
		q = q.Filter("Hash=", com.ParentHash)
		if err := firstMatch(c, q, prev); err != nil {
			if err == datastore.ErrNoSuchEntity {
				// No previous result, let the backfill of
				// this result trigger the notification.
				return nil
			}
			return err
		}
		if pr := prev.Result(builder, ""); pr != nil && pr.OK {
			c.Debugf("commit broken: %#v\nresult: %#v", com, cr)
			c.Debugf("previous commit ok: %#v\nprevious result:%#v", prev, pr)
			broken = com
		}
	}
	var err error
	if broken != nil && !broken.FailNotificationSent {
		c.Infof("%s is broken commit; notifying", broken.Hash)
		sendFailMailLater.Call(c, broken, builder) // add task to queue
		broken.FailNotificationSent = true
		_, err = datastore.Put(c, broken.Key(c), broken)
	}
	return err
}

// firstMatch executes the query q and loads the first entity into v.
func firstMatch(c appengine.Context, q *datastore.Query, v interface{}) error {
	t := q.Limit(1).Run(c)
	_, err := t.Next(v)
	if err == datastore.Done {
		err = datastore.ErrNoSuchEntity
	}
	return err
}

var (
	sendFailMailLater = delay.Func("sendFailMail", sendFailMail)
	sendFailMailTmpl  = template.Must(
		template.New("notify.txt").
			Funcs(template.FuncMap(tmplFuncs)).
			ParseFiles("build/notify.txt"),
	)
)

func init() {
	gob.Register(&Commit{}) // for delay
}

// sendFailMail sends a mail notification that the build failed on the
// provided commit and builder.
func sendFailMail(c appengine.Context, com *Commit, builder string) {
	// TODO(adg): handle packages

	// get Result
	r := com.Result(builder, "")
	if r == nil {
		c.Errorf("finding result for %q: %+v", builder, com)
		return
	}

	// get Log
	k := datastore.NewKey(c, "Log", r.LogHash, 0, nil)
	l := new(Log)
	if err := datastore.Get(c, k, l); err != nil {
		c.Errorf("finding Log record %v: %v", r.LogHash, err)
		return
	}

	// prepare mail message
	var body bytes.Buffer
	err := sendFailMailTmpl.Execute(&body, map[string]interface{}{
		"Builder": builder, "Commit": com, "Result": r, "Log": l,
		"Hostname": domain,
	})
	if err != nil {
		c.Errorf("rendering mail template: %v", err)
		return
	}
	subject := fmt.Sprintf("%s broken by %s", builder, shortDesc(com.Desc))
	msg := &mail.Message{
		Sender:  mailFrom,
		To:      []string{failMailTo},
		ReplyTo: failMailTo,
		Subject: subject,
		Body:    body.String(),
	}

	// send mail
	if err := mail.Send(c, msg); err != nil {
		c.Errorf("sending mail: %v", err)
	}
}
<commit_msg>go.tools/dashboard: update CL on build failure<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build appengine

package build

import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"text/template"

	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/mail"
	"appengine/urlfetch"
)

const (
	mailFrom   = "builder@golang.org" // use this for sending any mail
	failMailTo = "golang-dev@googlegroups.com"
	domain     = "build.golang.org"
	gobotBase  = "http://research.swtch.com/gobot_codereview"
)

// failIgnore is a set of builders that we don't email about because
// they're too flaky.
var failIgnore = map[string]bool{
	"netbsd-386-bsiegert":   true,
	"netbsd-amd64-bsiegert": true,
}

// notifyOnFailure checks whether the supplied Commit or the subsequent
// Commit (if present) breaks the build for this builder.
// If either of those commits break the build an email notification is sent
// from a delayed task. (We use a task because this way the mail won't be
// sent if the enclosing datastore transaction fails.)
//
// This must be run in a datastore transaction, and the provided *Commit must
// have been retrieved from the datastore within that transaction.
func notifyOnFailure(c appengine.Context, com *Commit, builder string) error {
	if failIgnore[builder] {
		return nil
	}

	// TODO(adg): implement notifications for packages
	if com.PackagePath != "" {
		return nil
	}

	p := &Package{Path: com.PackagePath}
	var broken *Commit
	cr := com.Result(builder, "")
	if cr == nil {
		return fmt.Errorf("no result for %s/%s", com.Hash, builder)
	}
	q := datastore.NewQuery("Commit").Ancestor(p.Key(c))
	if cr.OK {
		// This commit is OK. Notify if next Commit is broken.
		next := new(Commit)
		q = q.Filter("ParentHash=", com.Hash)
		if err := firstMatch(c, q, next); err != nil {
			if err == datastore.ErrNoSuchEntity {
				// OK at tip, no notification necessary.
				return nil
			}
			return err
		}
		if nr := next.Result(builder, ""); nr != nil && !nr.OK {
			c.Debugf("commit ok: %#v\nresult: %#v", com, cr)
			c.Debugf("next commit broken: %#v\nnext result:%#v", next, nr)
			broken = next
		}
	} else {
		// This commit is broken. Notify if the previous Commit is OK.
		prev := new(Commit)
		q = q.Filter("Hash=", com.ParentHash)
		if err := firstMatch(c, q, prev); err != nil {
			if err == datastore.ErrNoSuchEntity {
				// No previous result, let the backfill of
				// this result trigger the notification.
				return nil
			}
			return err
		}
		if pr := prev.Result(builder, ""); pr != nil && pr.OK {
			c.Debugf("commit broken: %#v\nresult: %#v", com, cr)
			c.Debugf("previous commit ok: %#v\nprevious result:%#v", prev, pr)
			broken = com
		}
	}
	var err error
	if broken != nil && !broken.FailNotificationSent {
		c.Infof("%s is broken commit; notifying", broken.Hash)
		notifyLater.Call(c, broken, builder) // add task to queue
		broken.FailNotificationSent = true
		_, err = datastore.Put(c, broken.Key(c), broken)
	}
	return err
}

// firstMatch executes the query q and loads the first entity into v.
func firstMatch(c appengine.Context, q *datastore.Query, v interface{}) error {
	t := q.Limit(1).Run(c)
	_, err := t.Next(v)
	if err == datastore.Done {
		err = datastore.ErrNoSuchEntity
	}
	return err
}

var notifyLater = delay.Func("notify", notify)

// notify tries to update the CL for the given Commit with a failure message.
// If it doesn't succeed, it sends a failure email to golang-dev.
func notify(c appengine.Context, com *Commit, builder string) {
	if !updateCL(c, com, builder) {
		// Send a mail notification if the CL can't be found.
		sendFailMail(c, com, builder)
	}
}

// updateCL updates the CL for the given Commit with a failure message
// for the given builder.
func updateCL(c appengine.Context, com *Commit, builder string) bool {
	cl, err := lookupCL(c, com)
	if err != nil {
		c.Errorf("could not find CL for %v: %v", com.Hash, err)
		return false
	}
	url := fmt.Sprintf("%v?cl=%v&brokebuild=%v", gobotBase, cl, builder)
	r, err := urlfetch.Client(c).Post(url, "text/plain", nil)
	if err != nil {
		c.Errorf("could not update CL %v: %v", cl, err)
		return false
	}
	r.Body.Close()
	if r.StatusCode != http.StatusOK {
		c.Errorf("could not update CL %v: %v", cl, r.Status)
		return false
	}
	return true
}

var clURL = regexp.MustCompile(`https://codereview.appspot.com/([0-9]+)`)

// lookupCL consults code.google.com for the full change description for the
// provided Commit, and returns the relevant CL number.
func lookupCL(c appengine.Context, com *Commit) (string, error) {
	url := "https://code.google.com/p/go/source/detail?r=" + com.Hash
	r, err := urlfetch.Client(c).Get(url)
	if err != nil {
		return "", err
	}
	defer r.Body.Close()
	if r.StatusCode != http.StatusOK {
		return "", fmt.Errorf("retrieving %v: %v", url, r.Status)
	}
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return "", err
	}
	m := clURL.FindAllSubmatch(b, -1)
	if m == nil {
		return "", errors.New("no CL URL found on changeset page")
	}
	// Return the last visible codereview URL on the page,
	// in case the change description refers to another CL.
	return string(m[len(m)-1][1]), nil
}

var sendFailMailTmpl = template.Must(template.New("notify.txt").
	Funcs(template.FuncMap(tmplFuncs)).
	ParseFiles("build/notify.txt"))

func init() {
	gob.Register(&Commit{}) // for delay
}

// sendFailMail sends a mail notification that the build failed on the
// provided commit and builder.
func sendFailMail(c appengine.Context, com *Commit, builder string) {
	// TODO(adg): handle packages

	// get Result
	r := com.Result(builder, "")
	if r == nil {
		c.Errorf("finding result for %q: %+v", builder, com)
		return
	}

	// get Log
	k := datastore.NewKey(c, "Log", r.LogHash, 0, nil)
	l := new(Log)
	if err := datastore.Get(c, k, l); err != nil {
		c.Errorf("finding Log record %v: %v", r.LogHash, err)
		return
	}

	// prepare mail message
	var body bytes.Buffer
	err := sendFailMailTmpl.Execute(&body, map[string]interface{}{
		"Builder": builder, "Commit": com, "Result": r, "Log": l,
		"Hostname": domain,
	})
	if err != nil {
		c.Errorf("rendering mail template: %v", err)
		return
	}
	subject := fmt.Sprintf("%s broken by %s", builder, shortDesc(com.Desc))
	msg := &mail.Message{
		Sender:  mailFrom,
		To:      []string{failMailTo},
		ReplyTo: failMailTo,
		Subject: subject,
		Body:    body.String(),
	}

	// send mail
	if err := mail.Send(c, msg); err != nil {
		c.Errorf("sending mail: %v", err)
	}
}
<|endoftext|>


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

//go:build ebitencbackend
// +build ebitencbackend

// TODO: This implementation is very similar to github.com/hajimehoshi/oto/v2's player.go
// Unify them if possible.

package cbackend

import (
	"errors"
	"io"
	"runtime"
	"sync"
)

type playerState int

const (
	playerPaused playerState = iota
	playerPlay
	playerClosed
)

type players struct {
	players map[*playerImpl]struct{}
	buf     []float32
	cond    *sync.Cond
}

func newPlayers() *players {
	p := &players{
		cond: sync.NewCond(&sync.Mutex{}),
	}
	go p.loop()
	return p
}

func (ps *players) shouldWait() bool {
	for p := range ps.players {
		if p.canReadSourceToBuffer() {
			return false
		}
	}
	return true
}

func (ps *players) wait() {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	for ps.shouldWait() {
		ps.cond.Wait()
	}
}

func (ps *players) loop() {
	var players []*playerImpl
	for {
		ps.wait()

		ps.cond.L.Lock()
		players = players[:0]
		for p := range ps.players {
			players = append(players, p)
		}
		ps.cond.L.Unlock()

		for _, p := range players {
			p.readSourceToBuffer()
		}
	}
}

func (ps *players) addPlayer(player *playerImpl) {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	if ps.players == nil {
		ps.players = map[*playerImpl]struct{}{}
	}
	ps.players[player] = struct{}{}
	ps.cond.Signal()
}

func (ps *players) removePlayer(player *playerImpl) {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	delete(ps.players, player)
	ps.cond.Signal()
}

func (ps *players) read(buf []float32) {
	ps.cond.L.Lock()
	players := make([]*playerImpl, 0, len(ps.players))
	for p := range ps.players {
		players = append(players, p)
	}
	ps.cond.L.Unlock()

	for i := range buf {
		buf[i] = 0
	}
	for _, p := range players {
		p.readBufferAndAdd(buf)
	}
	ps.cond.Signal()
}

type Player struct {
	p *playerImpl
}

type playerImpl struct {
	context    *Context
	src        io.Reader
	volume     float64
	err        error
	state      playerState
	tmpbuf     []byte
	buf        []byte
	eof        bool
	bufferSize int

	m sync.Mutex
}

func newPlayer(context *Context, src io.Reader) *Player {
	p := &Player{
		p: &playerImpl{
			context:    context,
			src:        src,
			volume:     1,
			bufferSize: context.defaultBufferSize(),
		},
	}
	runtime.SetFinalizer(p, (*Player).Close)
	return p
}

func (p *Player) Err() error {
	return p.p.Err()
}

func (p *playerImpl) Err() error {
	p.m.Lock()
	defer p.m.Unlock()

	return p.err
}

func (p *Player) Play() {
	p.p.Play()
}

func (p *playerImpl) Play() {
	ch := make(chan struct{})
	go func() {
		p.m.Lock()
		defer p.m.Unlock()

		close(ch)
		p.playImpl()
	}()
	<-ch
}

func (p *Player) SetBufferSize(bufferSize int) {
	p.p.setBufferSize(bufferSize)
}

func (p *playerImpl) setBufferSize(bufferSize int) {
	p.m.Lock()
	defer p.m.Unlock()

	orig := p.bufferSize
	p.bufferSize = bufferSize
	if bufferSize == 0 {
		p.bufferSize = p.context.defaultBufferSize()
	}
	if orig != p.bufferSize {
		p.tmpbuf = nil
	}
}

func (p *playerImpl) ensureTmpBuf() []byte {
	if p.tmpbuf == nil {
		p.tmpbuf = make([]byte, p.bufferSize)
	}
	return p.tmpbuf
}

func (p *playerImpl) playImpl() {
	if p.err != nil {
		return
	}
	if p.state != playerPaused {
		return
	}

	if !p.eof {
		buf := p.ensureTmpBuf()
		for len(p.buf) < p.bufferSize {
			n, err := p.src.Read(buf)
			if err != nil && err != io.EOF {
				p.setErrorImpl(err)
				return
			}
			p.buf = append(p.buf, buf[:n]...)
			if err == io.EOF {
				p.eof = true
				break
			}
		}
	}

	if !p.eof || len(p.buf) > 0 {
		p.state = playerPlay
	}

	p.m.Unlock()
	p.context.players.addPlayer(p)
	p.m.Lock()
}

func (p *Player) Pause() {
	p.p.Pause()
}

func (p *playerImpl) Pause() {
	p.m.Lock()
	defer p.m.Unlock()

	if p.state != playerPlay {
		return
	}
	p.state = playerPaused
}

func (p *Player) Seek(offset int64, whence int) (int64, error) {
	return p.p.Seek(offset, whence)
}

func (p *playerImpl) Seek(offset int64, whence int) (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	if p.state == playerPlay {
		defer p.playImpl()
	}

	// Reset the internal buffer.
	p.resetImpl()

	// Check if the source implements io.Seeker.
	s, ok := p.src.(io.Seeker)
	if !ok {
		return 0, errors.New("cbackend: the source must implement io.Seeker")
	}
	newOffset, err := s.Seek(offset, whence)
	if err != nil {
		return newOffset, err
	}

	return newOffset, nil
}

func (p *Player) Reset() {
	p.p.Reset()
}

func (p *playerImpl) Reset() {
	p.m.Lock()
	defer p.m.Unlock()
	p.resetImpl()
}

func (p *playerImpl) resetImpl() {
	if p.state == playerClosed {
		return
	}
	p.state = playerPaused
	p.buf = p.buf[:0]
	p.eof = false
}

func (p *Player) IsPlaying() bool {
	return p.p.IsPlaying()
}

func (p *playerImpl) IsPlaying() bool {
	p.m.Lock()
	defer p.m.Unlock()
	return p.state == playerPlay
}

func (p *Player) Volume() float64 {
	return p.p.Volume()
}

func (p *playerImpl) Volume() float64 {
	p.m.Lock()
	defer p.m.Unlock()
	return p.volume
}

func (p *Player) SetVolume(volume float64) {
	p.p.SetVolume(volume)
}

func (p *playerImpl) SetVolume(volume float64) {
	p.m.Lock()
	defer p.m.Unlock()
	p.volume = volume
}

func (p *Player) UnplayedBufferSize() int {
	return p.p.UnplayedBufferSize()
}

func (p *playerImpl) UnplayedBufferSize() int {
	p.m.Lock()
	defer p.m.Unlock()
	return len(p.buf)
}

func (p *Player) Close() error {
	runtime.SetFinalizer(p, nil)
	return p.p.Close()
}

func (p *playerImpl) Close() error {
	p.m.Lock()
	defer p.m.Unlock()
	return p.closeImpl()
}

func (p *playerImpl) closeImpl() error {
	p.m.Unlock()
	p.context.players.removePlayer(p)
	p.m.Lock()

	if p.state == playerClosed {
		return p.err
	}
	p.state = playerClosed
	p.buf = nil
	return p.err
}

func (p *playerImpl) readBufferAndAdd(buf []float32) int {
	p.m.Lock()
	defer p.m.Unlock()

	if p.state != playerPlay {
		return 0
	}

	bitDepthInBytes := p.context.bitDepthInBytes
	n := len(p.buf) / bitDepthInBytes
	if n > len(buf) {
		n = len(buf)
	}
	volume := float32(p.volume)
	src := p.buf[:n*bitDepthInBytes]

	for i := 0; i < n; i++ {
		var v float32
		switch bitDepthInBytes {
		case 1:
			v8 := src[i]
			v = float32(v8-(1<<7)) / (1 << 7)
		case 2:
			v16 := int16(src[2*i]) | (int16(src[2*i+1]) << 8)
			v = float32(v16) / (1 << 15)
		}
		buf[i] += v * volume
	}

	copy(p.buf, p.buf[n*bitDepthInBytes:])
	p.buf = p.buf[:len(p.buf)-n*bitDepthInBytes]

	if p.eof && len(p.buf) == 0 {
		p.state = playerPaused
	}

	return n
}

func (p *playerImpl) canReadSourceToBuffer() bool {
	p.m.Lock()
	defer p.m.Unlock()

	if p.eof {
		return false
	}
	return len(p.buf) < p.bufferSize
}

func (p *playerImpl) readSourceToBuffer() {
	p.m.Lock()
	defer p.m.Unlock()

	if p.err != nil {
		return
	}
	if p.state == playerClosed {
		return
	}

	if len(p.buf) >= p.bufferSize {
		return
	}

	buf := p.ensureTmpBuf()
	n, err := p.src.Read(buf)

	if err != nil && err != io.EOF {
		p.setErrorImpl(err)
		return
	}

	p.buf = append(p.buf, buf[:n]...)
	if err == io.EOF {
		p.eof = true
		if len(p.buf) == 0 {
			p.state = playerPaused
		}
	}
}

func (p *playerImpl) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}
<commit_msg>audio/internal/cbackend: add comments<commit_after>// Copyright 2021 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build ebitencbackend
// +build ebitencbackend

// TODO: This implementation is very similar to github.com/hajimehoshi/oto/v2's player.go
// Unify them if possible.

package cbackend

import (
	"errors"
	"io"
	"runtime"
	"sync"
)

type playerState int

const (
	playerPaused playerState = iota
	playerPlay
	playerClosed
)

type players struct {
	players map[*playerImpl]struct{}
	buf     []float32
	cond    *sync.Cond
}

func newPlayers() *players {
	p := &players{
		cond: sync.NewCond(&sync.Mutex{}),
	}
	go p.loop()
	return p
}

func (ps *players) shouldWait() bool {
	for p := range ps.players {
		if p.canReadSourceToBuffer() {
			return false
		}
	}
	return true
}

func (ps *players) wait() {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	for ps.shouldWait() {
		ps.cond.Wait()
	}
}

func (ps *players) loop() {
	var players []*playerImpl
	for {
		ps.wait()

		ps.cond.L.Lock()
		players = players[:0]
		for p := range ps.players {
			players = append(players, p)
		}
		ps.cond.L.Unlock()

		for _, p := range players {
			p.readSourceToBuffer()
		}
	}
}

func (ps *players) addPlayer(player *playerImpl) {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	if ps.players == nil {
		ps.players = map[*playerImpl]struct{}{}
	}
	ps.players[player] = struct{}{}
	ps.cond.Signal()
}

func (ps *players) removePlayer(player *playerImpl) {
	ps.cond.L.Lock()
	defer ps.cond.L.Unlock()

	delete(ps.players, player)
	ps.cond.Signal()
}

func (ps *players) read(buf []float32) {
	ps.cond.L.Lock()
	players := make([]*playerImpl, 0, len(ps.players))
	for p := range ps.players {
		players = append(players, p)
	}
	ps.cond.L.Unlock()

	for i := range buf {
		buf[i] = 0
	}
	for _, p := range players {
		p.readBufferAndAdd(buf)
	}
	ps.cond.Signal()
}

type Player struct {
	p *playerImpl
}

type playerImpl struct {
	context    *Context
	src        io.Reader
	volume     float64
	err        error
	state      playerState
	tmpbuf     []byte
	buf        []byte
	eof        bool
	bufferSize int

	m sync.Mutex
}

func newPlayer(context *Context, src io.Reader) *Player {
	p := &Player{
		p: &playerImpl{
			context:    context,
			src:        src,
			volume:     1,
			bufferSize: context.defaultBufferSize(),
		},
	}
	runtime.SetFinalizer(p, (*Player).Close)
	return p
}

func (p *Player) Err() error {
	return p.p.Err()
}

func (p *playerImpl) Err() error {
	p.m.Lock()
	defer p.m.Unlock()

	return p.err
}

func (p *Player) Play() {
	p.p.Play()
}

func (p *playerImpl) Play() {
	ch := make(chan struct{})
	go func() {
		p.m.Lock()
		defer p.m.Unlock()

		close(ch)
		p.playImpl()
	}()
	<-ch
}

func (p *Player) SetBufferSize(bufferSize int) {
	p.p.setBufferSize(bufferSize)
}

func (p *playerImpl) setBufferSize(bufferSize int) {
	p.m.Lock()
	defer p.m.Unlock()

	orig := p.bufferSize
	p.bufferSize = bufferSize
	if bufferSize == 0 {
		p.bufferSize = p.context.defaultBufferSize()
	}
	if orig != p.bufferSize {
		p.tmpbuf = nil
	}
}

func (p *playerImpl) ensureTmpBuf() []byte {
	if p.tmpbuf == nil {
		p.tmpbuf = make([]byte, p.bufferSize)
	}
	return p.tmpbuf
}

func (p *playerImpl) playImpl() {
	if p.err != nil {
		return
	}
	if p.state != playerPaused {
		return
	}

	if !p.eof {
		buf := p.ensureTmpBuf()
		for len(p.buf) < p.bufferSize {
			n, err := p.src.Read(buf)
			if err != nil && err != io.EOF {
				p.setErrorImpl(err)
				return
			}
			p.buf = append(p.buf, buf[:n]...)
			if err == io.EOF {
				p.eof = true
				break
			}
		}
	}

	if !p.eof || len(p.buf) > 0 {
		p.state = playerPlay
	}

	p.m.Unlock()
	p.context.players.addPlayer(p)
	p.m.Lock()
}

func (p *Player) Pause() {
	p.p.Pause()
}

func (p *playerImpl) Pause() {
	p.m.Lock()
	defer p.m.Unlock()

	if p.state != playerPlay {
		return
	}
	p.state = playerPaused
}

func (p *Player) Seek(offset int64, whence int) (int64, error) {
	return p.p.Seek(offset, whence)
}

func (p *playerImpl) Seek(offset int64, whence int) (int64, error) {
	p.m.Lock()
	defer p.m.Unlock()

	// If a player is playing, keep playing even after this seeking.
	if p.state == playerPlay {
		defer p.playImpl()
	}

	// Reset the internal buffer.
	p.resetImpl()

	// Check if the source implements io.Seeker.
	s, ok := p.src.(io.Seeker)
	if !ok {
		return 0, errors.New("cbackend: the source must implement io.Seeker")
	}
	newOffset, err := s.Seek(offset, whence)
	if err != nil {
		return newOffset, err
	}

	return newOffset, nil
}

func (p *Player) Reset() {
	p.p.Reset()
}

func (p *playerImpl) Reset() {
	p.m.Lock()
	defer p.m.Unlock()
	p.resetImpl()
}

func (p *playerImpl) resetImpl() {
	if p.state == playerClosed {
		return
	}
	p.state = playerPaused
	p.buf = p.buf[:0]
	p.eof = false
}

func (p *Player) IsPlaying() bool {
	return p.p.IsPlaying()
}

func (p *playerImpl) IsPlaying() bool {
	p.m.Lock()
	defer p.m.Unlock()
	return p.state == playerPlay
}

func (p *Player) Volume() float64 {
	return p.p.Volume()
}

func (p *playerImpl) Volume() float64 {
	p.m.Lock()
	defer p.m.Unlock()
	return p.volume
}

func (p *Player) SetVolume(volume float64) {
	p.p.SetVolume(volume)
}

func (p *playerImpl) SetVolume(volume float64) {
	p.m.Lock()
	defer p.m.Unlock()
	p.volume = volume
}

func (p *Player) UnplayedBufferSize() int {
	return p.p.UnplayedBufferSize()
}

func (p *playerImpl) UnplayedBufferSize() int {
	p.m.Lock()
	defer p.m.Unlock()
	return len(p.buf)
}

func (p *Player) Close() error {
	runtime.SetFinalizer(p, nil)
	return p.p.Close()
}

func (p *playerImpl) Close() error {
	p.m.Lock()
	defer p.m.Unlock()
	return p.closeImpl()
}

func (p *playerImpl) closeImpl() error {
	p.m.Unlock()
	p.context.players.removePlayer(p)
	p.m.Lock()

	if p.state == playerClosed {
		return p.err
	}
	p.state = playerClosed
	p.buf = nil
	return p.err
}

func (p *playerImpl) readBufferAndAdd(buf []float32) int {
	p.m.Lock()
	defer p.m.Unlock()

	if p.state != playerPlay {
		return 0
	}

	bitDepthInBytes := p.context.bitDepthInBytes
	n := len(p.buf) / bitDepthInBytes
	if n > len(buf) {
		n = len(buf)
	}
	volume := float32(p.volume)
	src := p.buf[:n*bitDepthInBytes]

	for i := 0; i < n; i++ {
		var v float32
		switch bitDepthInBytes {
		case 1:
			v8 := src[i]
			v = float32(v8-(1<<7)) / (1 << 7)
		case 2:
			v16 := int16(src[2*i]) | (int16(src[2*i+1]) << 8)
			v = float32(v16) / (1 << 15)
		}
		buf[i] += v * volume
	}

	copy(p.buf, p.buf[n*bitDepthInBytes:])
	p.buf = p.buf[:len(p.buf)-n*bitDepthInBytes]

	if p.eof && len(p.buf) == 0 {
		p.state = playerPaused
	}

	return n
}

func (p *playerImpl) canReadSourceToBuffer() bool {
	p.m.Lock()
	defer p.m.Unlock()

	if p.eof {
		return false
	}
	return len(p.buf) < p.bufferSize
}

func (p *playerImpl) readSourceToBuffer() {
	p.m.Lock()
	defer p.m.Unlock()

	if p.err != nil {
		return
	}
	if p.state == playerClosed {
		return
	}

	if len(p.buf) >= p.bufferSize {
		return
	}

	buf := p.ensureTmpBuf()
	n, err := p.src.Read(buf)

	if err != nil && err != io.EOF {
		p.setErrorImpl(err)
		return
	}

	p.buf = append(p.buf, buf[:n]...)
	if err == io.EOF {
		p.eof = true
		if len(p.buf) == 0 {
			p.state = playerPaused
		}
	}
}

func (p *playerImpl) setErrorImpl(err error) {
	p.err = err
	p.closeImpl()
}
<|endoftext|>


<commit_before>package adaptor

import (
	"fmt"
	"reflect"

	"github.com/compose/transporter/pkg/pipe"
)

var (
	// Adaptors is a registry of adaptor types, constructors and configs
	Adaptors = make(Registry)
)

func init() {
	Register("mongo", "a mongodb adaptor that functions as both a source and a sink", NewMongodb, MongodbConfig{})
	Register("file", "an adaptor that reads / writes files", NewFile, FileConfig{})
	Register("elasticsearch", "an elasticsearch sink adaptor", NewElasticsearch, dbConfig{})
	// Register("influx", "an InfluxDB sink adaptor", NewInfluxdb, dbConfig{})
	Register("transformer", "an adaptor that transforms documents using a javascript function", NewTransformer, TransformerConfig{})
	Register("rethinkdb", "a rethinkdb sink adaptor", NewRethinkdb, dbConfig{})
}

// Register registers an adaptor (database adaptor) for use with Transporter
// The second argument, fn, is a constructor that returns an instance of the
// given adaptor, config is an instance of the adaptor's config struct
func Register(name, desc string, fn func(*pipe.Pipe, string, Config) (StopStartListener, error), config interface{}) {
	Adaptors[name] = RegistryEntry{
		Name:        name,
		Description: desc,
		Constructor: fn,
		Config:      config,
	}
}

// Registry maps the adaptor's name to the RegistryEntry
type Registry map[string]RegistryEntry

// RegistryEntry stores the adaptor constructor and configuration struct
type RegistryEntry struct {
	Name        string
	Description string
	Constructor func(*pipe.Pipe, string, Config) (StopStartListener, error)
	Config      interface{}
}

// About inspects the  RegistryEntry's Config object, and uses
// each field's tags as a docstring
func (r *RegistryEntry) About() string {
	doc := fmt.Sprintf("%s %s\n\n", r.Name, r.Description)
	t := reflect.TypeOf(r.Config)
	doc += fmt.Sprintf("%-15s %-10s %s\n", "name", "type", "description")
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		doc += fmt.Sprintf("%-15s %-10s %s\n", f.Tag.Get("json"), f.Type, f.Tag.Get("doc"))
	}

	return doc
}
<commit_msg>Registers the custom configuration type<commit_after>package adaptor

import (
	"fmt"
	"reflect"

	"github.com/compose/transporter/pkg/pipe"
)

var (
	// Adaptors is a registry of adaptor types, constructors and configs
	Adaptors = make(Registry)
)

func init() {
	Register("mongo", "a mongodb adaptor that functions as both a source and a sink", NewMongodb, MongodbConfig{})
	Register("file", "an adaptor that reads / writes files", NewFile, FileConfig{})
	Register("elasticsearch", "an elasticsearch sink adaptor", NewElasticsearch, dbConfig{})
	// Register("influx", "an InfluxDB sink adaptor", NewInfluxdb, dbConfig{})
	Register("transformer", "an adaptor that transforms documents using a javascript function", NewTransformer, TransformerConfig{})
	Register("rethinkdb", "a rethinkdb sink adaptor", NewRethinkdb, rethinkDbConfig{})
}

// Register registers an adaptor (database adaptor) for use with Transporter
// The second argument, fn, is a constructor that returns an instance of the
// given adaptor, config is an instance of the adaptor's config struct
func Register(name, desc string, fn func(*pipe.Pipe, string, Config) (StopStartListener, error), config interface{}) {
	Adaptors[name] = RegistryEntry{
		Name:        name,
		Description: desc,
		Constructor: fn,
		Config:      config,
	}
}

// Registry maps the adaptor's name to the RegistryEntry
type Registry map[string]RegistryEntry

// RegistryEntry stores the adaptor constructor and configuration struct
type RegistryEntry struct {
	Name        string
	Description string
	Constructor func(*pipe.Pipe, string, Config) (StopStartListener, error)
	Config      interface{}
}

// About inspects the  RegistryEntry's Config object, and uses
// each field's tags as a docstring
func (r *RegistryEntry) About() string {
	doc := fmt.Sprintf("%s %s\n\n", r.Name, r.Description)
	t := reflect.TypeOf(r.Config)
	doc += fmt.Sprintf("%-15s %-10s %s\n", "name", "type", "description")
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		doc += fmt.Sprintf("%-15s %-10s %s\n", f.Tag.Get("json"), f.Type, f.Tag.Get("doc"))
	}

	return doc
}
<|endoftext|>