<commit_before>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package mdns

import "fmt"
import "net"

func NewServer(addr string, maddr string) (*net.UDPAddr, *net.UDPConn, error) {
	saddr, err := net.ResolveUDPAddr("udp", addr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not resolve address '%s': ", addr, err);
	}

	smaddr, err := net.ResolveUDPAddr("udp", maddr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not resolve address '%s': ", addr, err);
	}

	udp, err := net.ListenUDP("udp", saddr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not listen: %s", err);
	}

	err = SetTTL(udp, 1);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set TTL: %s", err);
	}

	err = SetLoop(udp, 0);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set loop: %s", err);
	}

	err = AddMembership(udp, smaddr.IP);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not join group: %s", err);
	}

	err = SetPktInfo(udp, 1);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set PKTINFO: %s", err);
	}

	return smaddr, udp, nil;
}

func MakeResponse(client *net.UDPAddr, req *Message) (*Message) {
	rsp := new(Message);

	rsp.Header.Flags |= FlagQR;
	rsp.Header.Flags |= FlagAA;

	if req.Header.Flags & FlagRD != 0 {
		rsp.Header.Flags |= FlagRD;
		rsp.Header.Flags |= FlagRA;
	}

	if client.Port != 5353 {
		rsp.Header.Id = req.Header.Id;
	}

	return rsp;
}

func Read(udp *net.UDPConn) (*Message, *net.IPNet, *net.IPNet, *net.UDPAddr, error) {
	var local4 *net.IPNet;
	var local6 *net.IPNet;

	pkt := make([]byte, 65536);
	oob := make([]byte, 40);

	n, oobn, _, from, err := udp.ReadMsgUDP(pkt, oob);

	if oobn > 0 {
		pktinfo := ParseOob(oob[:oobn]);

		if pktinfo != nil {
			ifi, err := net.InterfaceByIndex(int(pktinfo.Ifindex));
			if err != nil {
				return nil, nil, nil, nil,
				  fmt.Errorf("Could not find if: %s", err);
			}

			addrs, err := ifi.Addrs();
			if err != nil {
				return nil, nil, nil, nil,
				  fmt.Errorf("Could not find addrs: %s", err);
			}

			for _, a := range addrs {
				if a.(*net.IPNet).IP.To4() != nil {
					local4 = a.(*net.IPNet);
				} else {
					local6 = a.(*net.IPNet);
				}
			}
		}
	}

	req, err := Unpack(pkt[:n]);
	if err != nil {
		return nil, nil, nil, nil,
		  fmt.Errorf("Could not unpack request: %s", err);
	}

	return req, local4, local6, from, err;
}

func Write(udp *net.UDPConn, addr *net.UDPAddr, msg *Message) (error) {
	pkt, err := Pack(msg);
	if err != nil {
		return fmt.Errorf("Could not pack response: %s", err);
	}

	_, err = udp.WriteToUDP(pkt, addr);
	if err != nil {
		return fmt.Errorf("Could not write to network: %s", err);
	}

	return nil;
}
<commit_msg>mdns: fix some error messages<commit_after>/*
 * Minimal multicast DNS server.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package mdns

import "fmt"
import "net"

func NewServer(addr string, maddr string) (*net.UDPAddr, *net.UDPConn, error) {
	saddr, err := net.ResolveUDPAddr("udp", addr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not resolve address '%s': %s", addr, err);
	}

	smaddr, err := net.ResolveUDPAddr("udp", maddr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not resolve address '%s': %s", maddr, err);
	}

	udp, err := net.ListenUDP("udp", saddr);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not listen: %s", err);
	}

	err = SetTTL(udp, 1);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set TTL: %s", err);
	}

	err = SetLoop(udp, 0);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set loop: %s", err);
	}

	err = AddMembership(udp, smaddr.IP);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not join group: %s", err);
	}

	err = SetPktInfo(udp, 1);
	if err != nil {
		return nil, nil, fmt.Errorf("Could not set PKTINFO: %s", err);
	}

	return smaddr, udp, nil;
}

func MakeResponse(client *net.UDPAddr, req *Message) (*Message) {
	rsp := new(Message);

	rsp.Header.Flags |= FlagQR;
	rsp.Header.Flags |= FlagAA;

	if req.Header.Flags & FlagRD != 0 {
		rsp.Header.Flags |= FlagRD;
		rsp.Header.Flags |= FlagRA;
	}

	if client.Port != 5353 {
		rsp.Header.Id = req.Header.Id;
	}

	return rsp;
}

func Read(udp *net.UDPConn) (*Message, *net.IPNet, *net.IPNet, *net.UDPAddr, error) {
	var local4 *net.IPNet;
	var local6 *net.IPNet;

	pkt := make([]byte, 65536);
	oob := make([]byte, 40);

	n, oobn, _, from, err := udp.ReadMsgUDP(pkt, oob);
	if err != nil {
		return nil, nil, nil, nil,
		  fmt.Errorf("Could not read: %s", err);
	}

	if oobn > 0 {
		pktinfo := ParseOob(oob[:oobn]);

		if pktinfo != nil {
			ifi, err := net.InterfaceByIndex(int(pktinfo.Ifindex));
			if err != nil {
				return nil, nil, nil, nil,
				  fmt.Errorf("Could not find if: %s", err);
			}

			addrs, err := ifi.Addrs();
			if err != nil {
				return nil, nil, nil, nil,
				  fmt.Errorf("Could not find addrs: %s", err);
			}

			for _, a := range addrs {
				if a.(*net.IPNet).IP.To4() != nil {
					local4 = a.(*net.IPNet);
				} else {
					local6 = a.(*net.IPNet);
				}
			}
		}
	}

	req, err := Unpack(pkt[:n]);
	if err != nil {
		return nil, nil, nil, nil,
		  fmt.Errorf("Could not unpack request: %s", err);
	}

	return req, local4, local6, from, err;
}

func Write(udp *net.UDPConn, addr *net.UDPAddr, msg *Message) (error) {
	pkt, err := Pack(msg);
	if err != nil {
		return fmt.Errorf("Could not pack response: %s", err);
	}

	_, err = udp.WriteToUDP(pkt, addr);
	if err != nil {
		return fmt.Errorf("Could not write to network: %s", err);
	}

	return nil;
}
<|endoftext|>


<commit_before>package prototime

import (
	"time"

	"go.pedge.io/google-protobuf"
)

// TimeToTimestamp converts a go Time to a protobuf Timestamp.
func TimeToTimestamp(t time.Time) *google_protobuf.Timestamp {
	return &google_protobuf.Timestamp{
		Seconds: t.UnixNano() / int64(time.Second),
		Nanos:   int32(t.UnixNano() % int64(time.Second)),
	}
}

// TimestampToTime converts a protobuf Timestamp to a go Time.
func TimestampToTime(timestamp *google_protobuf.Timestamp) time.Time {
	return time.Unix(
		timestamp.Seconds,
		int64(timestamp.Nanos),
	).UTC()
}

// TimestampLess returns true if i is before j.
func TimestampLess(i *google_protobuf.Timestamp, j *google_protobuf.Timestamp) bool {
	if i == nil {
		return true
	}
	if j == nil {
		return false
	}
	if i.Seconds < j.Seconds {
		return true
	}
	if i.Seconds > j.Seconds {
		return false
	}
	return i.Nanos < j.Nanos
}

// DurationToProto converts a go Duration to a protobuf Duration.
func DurationToProto(d time.Duration) *google_protobuf.Duration {
	return &google_protobuf.Duration{
		Seconds: int64(d) / int64(time.Second),
		Nanos:   int32(int64(d) % int64(time.Second)),
	}
}

// DurationFromProto converts a protobuf Duration to a go Duration.
func DurationFromProto(duration *google_protobuf.Duration) time.Duration {
	return time.Duration((duration.Seconds * int64(time.Second)) + int64(duration.Nanos))
}
<commit_msg>update vendor<commit_after>package prototime

import (
	"time"

	"go.pedge.io/google-protobuf"
)

// TimeToTimestamp converts a go Time to a protobuf Timestamp.
func TimeToTimestamp(t time.Time) *google_protobuf.Timestamp {
	return &google_protobuf.Timestamp{
		Seconds: t.UnixNano() / int64(time.Second),
		Nanos:   int32(t.UnixNano() % int64(time.Second)),
	}
}

// TimestampToTime converts a protobuf Timestamp to a go Time.
func TimestampToTime(timestamp *google_protobuf.Timestamp) time.Time {
	if timestamp == nil {
		return time.Unix(0, 0).UTC()
	}
	return time.Unix(
		timestamp.Seconds,
		int64(timestamp.Nanos),
	).UTC()
}

// TimestampLess returns true if i is before j.
func TimestampLess(i *google_protobuf.Timestamp, j *google_protobuf.Timestamp) bool {
	if i == nil {
		return true
	}
	if j == nil {
		return false
	}
	if i.Seconds < j.Seconds {
		return true
	}
	if i.Seconds > j.Seconds {
		return false
	}
	return i.Nanos < j.Nanos
}

// DurationToProto converts a go Duration to a protobuf Duration.
func DurationToProto(d time.Duration) *google_protobuf.Duration {
	return &google_protobuf.Duration{
		Seconds: int64(d) / int64(time.Second),
		Nanos:   int32(int64(d) % int64(time.Second)),
	}
}

// DurationFromProto converts a protobuf Duration to a go Duration.
func DurationFromProto(duration *google_protobuf.Duration) time.Duration {
	if duration == nil {
		return 0
	}
	return time.Duration((duration.Seconds * int64(time.Second)) + int64(duration.Nanos))
}
<|endoftext|>


<commit_before>// +build from_src_run

// Copyright 2013 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.

// The run program is invoked via "go run" from src/run.bash or
// src/run.bat conditionally builds and runs the cmd/api tool.
//
// TODO(bradfitz): the "conditional" condition is always true.
// We should only do this if the user has the hg codereview extension
// enabled and verifies that the go.tools subrepo is checked out with
// a suitably recently version. In prep for the cmd/api rewrite.
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

// goToolsVersion is the hg revision of the go.tools subrepo we need
// to build cmd/api.  This only needs to be updated whenever a go/types
// bug fix is needed by the cmd/api tool.
const goToolsVersion = "6698ca2900e2"

var goroot string

func main() {
	log.SetFlags(0)
	goroot = os.Getenv("GOROOT") // should be set by run.{bash,bat}
	if goroot == "" {
		log.Fatal("No $GOROOT set.")
	}
	isGoDeveloper := exec.Command("hg", "pq").Run() == nil
	if !isGoDeveloper && !forceAPICheck() {
		fmt.Println("Skipping cmd/api checks; hg codereview extension not available and GO_FORCE_API_CHECK not set")
		return
	}

	gopath := prepGoPath()

	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
	cmd.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
	}

	out, err = exec.Command("go", "tool", "api",
		"-c", file("go1", "go1.1"),
		"-next", file("next"),
		"-except", file("except")).CombinedOutput()
	if err != nil {
		log.Fatalf("Error running API checker: %v\n%s", err, out)
	}
}

// file expands s to $GOROOT/api/s.txt.
// If there are more than 1, they're comma-separated.
func file(s ...string) string {
	if len(s) > 1 {
		return file(s[0]) + "," + file(s[1:]...)
	}
	return filepath.Join(goroot, "api", s[0]+".txt")
}

// GO_FORCE_API_CHECK is set by builders.
func forceAPICheck() bool {
	v, _ := strconv.ParseBool(os.Getenv("GO_FORCE_API_CHECK"))
	return v
}

// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
// It tries to re-use a go.tools checkout from a previous run if possible,
// else it hg clones it.
func prepGoPath() string {
	const tempBase = "go.tools.TMP"

	// The GOPATH we'll return
	gopath := filepath.Join(os.TempDir(), "gopath-api", goToolsVersion)

	// cloneDir is where we run "hg clone".
	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")

	// The dir we clone into. We only atomically rename it to finalDir on
	// clone success.
	tmpDir := filepath.Join(cloneDir, tempBase)

	// finalDir is where the checkout will live once it's complete.
	// If this exists already, we're done.
	finalDir := filepath.Join(cloneDir, "go.tools")

	if fi, err := os.Stat(finalDir); err == nil && fi.IsDir() {
		return gopath
	}

	if err := os.MkdirAll(cloneDir, 0700); err != nil {
		log.Fatal(err)
	}
	cmd := exec.Command("hg",
		"clone", "--rev="+goToolsVersion,
		"https://code.google.com/p/go.tools",
		tempBase)
	cmd.Dir = cloneDir
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
	}
	if err := os.Rename(tmpDir, finalDir); err != nil {
		log.Fatal(err)
	}
	return gopath
}
<commit_msg>cmd/api: show output of api tool even if exit status is 0<commit_after>// +build from_src_run

// Copyright 2013 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.

// The run program is invoked via "go run" from src/run.bash or
// src/run.bat conditionally builds and runs the cmd/api tool.
//
// TODO(bradfitz): the "conditional" condition is always true.
// We should only do this if the user has the hg codereview extension
// enabled and verifies that the go.tools subrepo is checked out with
// a suitably recently version. In prep for the cmd/api rewrite.
package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
)

// goToolsVersion is the hg revision of the go.tools subrepo we need
// to build cmd/api.  This only needs to be updated whenever a go/types
// bug fix is needed by the cmd/api tool.
const goToolsVersion = "6698ca2900e2"

var goroot string

func main() {
	log.SetFlags(0)
	goroot = os.Getenv("GOROOT") // should be set by run.{bash,bat}
	if goroot == "" {
		log.Fatal("No $GOROOT set.")
	}
	isGoDeveloper := exec.Command("hg", "pq").Run() == nil
	if !isGoDeveloper && !forceAPICheck() {
		fmt.Println("Skipping cmd/api checks; hg codereview extension not available and GO_FORCE_API_CHECK not set")
		return
	}

	gopath := prepGoPath()

	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
	cmd.Env = append([]string{"GOPATH=" + gopath}, os.Environ()...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
	}

	out, err = exec.Command("go", "tool", "api",
		"-c", file("go1", "go1.1"),
		"-next", file("next"),
		"-except", file("except")).CombinedOutput()
	if err != nil {
		log.Fatalf("Error running API checker: %v\n%s", err, out)
	}
	fmt.Print(string(out))
}

// file expands s to $GOROOT/api/s.txt.
// If there are more than 1, they're comma-separated.
func file(s ...string) string {
	if len(s) > 1 {
		return file(s[0]) + "," + file(s[1:]...)
	}
	return filepath.Join(goroot, "api", s[0]+".txt")
}

// GO_FORCE_API_CHECK is set by builders.
func forceAPICheck() bool {
	v, _ := strconv.ParseBool(os.Getenv("GO_FORCE_API_CHECK"))
	return v
}

// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
// It tries to re-use a go.tools checkout from a previous run if possible,
// else it hg clones it.
func prepGoPath() string {
	const tempBase = "go.tools.TMP"

	// The GOPATH we'll return
	gopath := filepath.Join(os.TempDir(), "gopath-api", goToolsVersion)

	// cloneDir is where we run "hg clone".
	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")

	// The dir we clone into. We only atomically rename it to finalDir on
	// clone success.
	tmpDir := filepath.Join(cloneDir, tempBase)

	// finalDir is where the checkout will live once it's complete.
	// If this exists already, we're done.
	finalDir := filepath.Join(cloneDir, "go.tools")

	if fi, err := os.Stat(finalDir); err == nil && fi.IsDir() {
		return gopath
	}

	if err := os.MkdirAll(cloneDir, 0700); err != nil {
		log.Fatal(err)
	}
	cmd := exec.Command("hg",
		"clone", "--rev="+goToolsVersion,
		"https://code.google.com/p/go.tools",
		tempBase)
	cmd.Dir = cloneDir
	out, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
	}
	if err := os.Rename(tmpDir, finalDir); err != nil {
		log.Fatal(err)
	}
	return gopath
}
<|endoftext|>


<commit_before>package checkerlution

import (
	"code.google.com/p/dsallings-couch-go"
	"encoding/json"
	"fmt"
	"github.com/couchbaselabs/logg"
	"github.com/nu7hatch/gouuid"
	ng "github.com/tleyden/neurgo"
	"io"
	"strings"
	"time"
)

const (
	SERVER_URL   = "http://localhost:4984/checkers"
	GAME_DOC_ID  = "game:checkers"
	VOTES_DOC_ID = "votes:checkers"
	RED_TEAM     = 0
	BLUE_TEAM    = 1
)

type Game struct {
	cortex               *ng.Cortex
	currentGameState     GameStateVector
	gameState            GameState
	currentPossibleMove  ValidMoveCortexInput
	latestActuatorOutput []float64
	ourTeamId            int
	db                   couch.Database
}

type Changes map[string]interface{}

func NewGame(ourTeamId int) *Game {
	game := &Game{ourTeamId: ourTeamId}
	return game
}

// Follow the changes feed and on each change callback
// call game.handleChanges() which will drive the game
func (game *Game) GameLoop() {

	game.InitGame()

	curSinceValue := "0"

	handleChange := func(reader io.Reader) string {
		changes := decodeChanges(reader)
		game.handleChanges(changes)
		curSinceValue = calculateNextSinceValue(curSinceValue, changes)
		time.Sleep(time.Second * 5)
		return curSinceValue
	}

	options := Changes{"since": "0"}
	game.db.Changes(handleChange, options)

}

// - (optional) make sure one of the changes is a game, if not, ignore it
// - get the latest game document
// - if it's not our turn, do nothing
// - if it is our turn
//   - parse out the required data structures needed to pass to cortex
//   - call cortex to calculate next move
//   - make next move by inserting a new revision of votes doc
func (game *Game) handleChanges(changes Changes) {
	logg.LogTo("DEBUG", "handleChanges called with %v", changes)
	gameDocChanged := game.checkGameDocInChanges(changes)
	if gameDocChanged {
		gameState, err := game.fetchLatestGameState()
		game.gameState = gameState
		if err != nil {
			logg.LogError(err)
			return
		}
		logg.LogTo("DEBUG", "gameState: %v", gameState)
		if isOurTurn := game.isOurTurn(gameState); !isOurTurn {
			logg.LogTo("DEBUG", "It's not our turn, ignoring changes")
			return
		}

		gameStateVector := game.extractGameStateVector(gameState)

		logg.LogTo("DEBUG", "gameStateVector: %v", gameStateVector)

		possibleMoves := game.extractPossibleMoves(gameState)

		if len(possibleMoves) == 0 {
			logg.LogTo("MAIN", "No possibleMoves, ignoring changes")
			return
		}

		logg.LogTo("DEBUG", "possibleMoves: %v", possibleMoves)

		bestMove := game.ChooseBestMove(gameStateVector, possibleMoves)

		logg.LogTo("DEBUG", "bestMove: %v", bestMove)

		game.PostChosenMove(bestMove)

	}

}

func (game Game) extractPossibleMoves(gameState GameState) []ValidMoveCortexInput {

	moves := make([]ValidMoveCortexInput, 0)

	ourTeam := gameState.Teams[game.ourTeamId]

	for pieceIndex, piece := range ourTeam.Pieces {
		piece.PieceId = pieceIndex
		for _, validMove := range piece.ValidMoves {
			moveInput := NewValidMoveCortexInput(validMove, piece)
			moves = append(moves, moveInput)
		}
	}

	return moves
}

func (game Game) opponentTeamId() int {
	switch game.ourTeamId {
	case RED_TEAM:
		return BLUE_TEAM
	default:
		return RED_TEAM
	}
}

func (game Game) extractGameStateVector(gameState GameState) GameStateVector {
	gameStateVector := NewGameStateVector()
	gameStateVector.loadFromGameState(gameState, game.ourTeamId)
	return gameStateVector
}

func (game Game) isOurTurn(gameState GameState) bool {
	return gameState.ActiveTeam == game.ourTeamId
}

func (game Game) checkGameDocInChanges(changes Changes) bool {
	foundGameDoc := false
	changeResultsRaw := changes["results"]
	changeResults := changeResultsRaw.([]interface{})
	for _, changeResultRaw := range changeResults {
		changeResult := changeResultRaw.(map[string]interface{})
		docIdRaw := changeResult["id"]
		docId := docIdRaw.(string)
		if strings.Contains(docId, GAME_DOC_ID) {
			foundGameDoc = true
		}
	}
	return foundGameDoc
}

func (game Game) fetchLatestGameState() (gameState GameState, err error) {
	gameStateFetched := &GameState{}
	err = game.db.Retrieve(GAME_DOC_ID, gameStateFetched)
	if err == nil {
		gameState = *gameStateFetched
	}
	return
}

func (game *Game) InitGame() {
	game.CreateNeurgoCortex()
	cortex := game.cortex
	cortex.Run()
	game.InitDbConnection()
}

func (game *Game) InitDbConnection() {
	db, error := couch.Connect(SERVER_URL)
	if error != nil {
		logg.LogPanic("Error connecting to %v: %v", SERVER_URL, error)
	}
	game.db = db
}

func (game *Game) ChooseBestMove(gameStateVector GameStateVector, possibleMoves []ValidMoveCortexInput) (bestMove ValidMoveCortexInput) {

	// Todo: the code below is an implementation of a single MoveChooser
	// but an interface should be designed so this is pluggable

	game.currentGameState = gameStateVector
	logg.LogTo("MAIN", "gameStateVector: %v", gameStateVector)

	var bestMoveRating []float64
	bestMoveRating = []float64{-1000000000}

	for _, move := range possibleMoves {

		logg.LogTo("MAIN", "feed possible move to cortex: %v", move)

		// present it to the neural net
		game.currentPossibleMove = move
		game.cortex.SyncSensors()
		game.cortex.SyncActuators()

		logg.LogTo("MAIN", "done sync'ing actuators")

		logg.LogTo("MAIN", "actuator output %v bestMoveRating: %v", game.latestActuatorOutput[0], bestMoveRating[0])
		if game.latestActuatorOutput[0] > bestMoveRating[0] {
			logg.LogTo("MAIN", "actuator output > bestMoveRating")
			bestMove = move
			bestMoveRating[0] = game.latestActuatorOutput[0]
		} else {
			logg.LogTo("MAIN", "actuator output < bestMoveRating, ignoring")
		}

	}
	return

}

func (game *Game) PostChosenMove(move ValidMoveCortexInput) {

	logg.LogTo("MAIN", "post chosen move: %v", move.validMove)

	if len(move.validMove.Locations) == 0 {
		logg.LogTo("MAIN", "invalid move, ignoring: %v", move.validMove)
	}

	u4, err := uuid.NewV4()
	if err != nil {
		logg.LogError(err)
		return
	}

	votes := &OutgoingVotes{}
	votes.Id = fmt.Sprintf("vote:%s", u4)
	votes.Turn = game.gameState.Turn
	votes.PieceId = move.validMove.PieceId
	votes.TeamId = game.ourTeamId
	votes.GameId = game.gameState.Number

	// TODO: this is actually a bug, because if there is a
	// double jump it will only send the first jump move
	endLocation := move.validMove.Locations[0]
	locations := []int{move.validMove.StartLocation, endLocation}
	votes.Locations = locations

	newId, newRevision, err := game.db.Insert(votes)

	logg.LogTo("MAIN", "newId: %v, newRevision: %v err: %v", newId, newRevision, err)
	if err != nil {
		logg.LogError(err)
		return
	}

}

func (game *Game) CreateNeurgoCortex() {

	nodeId := ng.NewCortexId("cortex")
	game.cortex = &ng.Cortex{
		NodeId: nodeId,
	}
	game.CreateSensors()
	game.CreateActuator()
	game.CreateNeuron()
	game.ConnectNodes()
}

func (game *Game) ConnectNodes() {

	cortex := game.cortex

	cortex.Init()

	// connect sensors -> neuron(s)
	for _, sensor := range cortex.Sensors {
		for _, neuron := range cortex.Neurons {
			sensor.ConnectOutbound(neuron)
			weights := ng.RandomWeights(sensor.VectorLength)
			neuron.ConnectInboundWeighted(sensor, weights)
		}
	}

	// connect neuron to actuator
	for _, neuron := range cortex.Neurons {
		for _, actuator := range cortex.Actuators {
			neuron.ConnectOutbound(actuator)
			actuator.ConnectInbound(neuron)
		}
	}

}

func (game *Game) CreateNeuron() {
	neuron := &ng.Neuron{
		ActivationFunction: ng.EncodableSigmoid(),
		NodeId:             ng.NewNeuronId("Neuron", 0.25),
		Bias:               ng.RandomBias(),
	}
	game.cortex.SetNeurons([]*ng.Neuron{neuron})
}

func (game *Game) CreateActuator() {

	actuatorNodeId := ng.NewActuatorId("Actuator", 0.5)
	actuatorFunc := func(outputs []float64) {
		logg.LogTo("MAIN", "actuator func called with: %v", outputs)
		game.latestActuatorOutput = outputs
		game.cortex.SyncChan <- actuatorNodeId // TODO: this should be in actuator itself, not in this function
	}
	actuator := &ng.Actuator{
		NodeId:           actuatorNodeId,
		VectorLength:     1,
		ActuatorFunction: actuatorFunc,
	}
	game.cortex.SetActuators([]*ng.Actuator{actuator})

}

func (game *Game) CreateSensors() {

	sensorLayer := 0.0

	sensorFuncGameState := func(syncCounter int) []float64 {
		logg.LogTo("MAIN", "sensor func game state called")
		return game.currentGameState
	}
	sensorGameStateNodeId := ng.NewSensorId("SensorGameState", sensorLayer)
	sensorGameState := &ng.Sensor{
		NodeId:         sensorGameStateNodeId,
		VectorLength:   32,
		SensorFunction: sensorFuncGameState,
	}

	sensorFuncPossibleMove := func(syncCounter int) []float64 {
		logg.LogTo("MAIN", "sensor func possible move called")
		return game.currentPossibleMove.VectorRepresentation()
	}
	sensorPossibleMoveNodeId := ng.NewSensorId("SensorPossibleMove", sensorLayer)
	sensorPossibleMove := &ng.Sensor{
		NodeId:         sensorPossibleMoveNodeId,
		VectorLength:   5, // start_location, is_king, final_location, will_be_king, amt_would_capture
		SensorFunction: sensorFuncPossibleMove,
	}
	game.cortex.SetSensors([]*ng.Sensor{sensorGameState, sensorPossibleMove})

}

func decodeChanges(reader io.Reader) Changes {
	changes := make(Changes)
	decoder := json.NewDecoder(reader)
	decoder.Decode(&changes)
	return changes
}

func calculateNextSinceValue(curSinceValue string, changes Changes) string {
	lastSeq := changes["last_seq"]
	lastSeqAsString := lastSeq.(string)
	if lastSeq != nil && len(lastSeqAsString) > 0 {
		return lastSeqAsString
	}
	return curSinceValue
}
<commit_msg>point to github.com/tleyden/dsallings-couch-go for now<commit_after>package checkerlution

import (
	"encoding/json"
	"fmt"
	"github.com/couchbaselabs/logg"
	"github.com/nu7hatch/gouuid"
	"github.com/tleyden/dsallings-couch-go"
	ng "github.com/tleyden/neurgo"
	"io"
	"strings"
	"time"
)

const (
	SERVER_URL   = "http://localhost:4984/checkers"
	GAME_DOC_ID  = "game:checkers"
	VOTES_DOC_ID = "votes:checkers"
	RED_TEAM     = 0
	BLUE_TEAM    = 1
)

type Game struct {
	cortex               *ng.Cortex
	currentGameState     GameStateVector
	gameState            GameState
	currentPossibleMove  ValidMoveCortexInput
	latestActuatorOutput []float64
	ourTeamId            int
	db                   couch.Database
}

type Changes map[string]interface{}

func NewGame(ourTeamId int) *Game {
	game := &Game{ourTeamId: ourTeamId}
	return game
}

// Follow the changes feed and on each change callback
// call game.handleChanges() which will drive the game
func (game *Game) GameLoop() {

	game.InitGame()

	curSinceValue := "0"

	handleChange := func(reader io.Reader) string {
		changes := decodeChanges(reader)
		game.handleChanges(changes)
		curSinceValue = calculateNextSinceValue(curSinceValue, changes)
		time.Sleep(time.Second * 5)
		return curSinceValue
	}

	options := Changes{"since": "0"}
	game.db.Changes(handleChange, options)

}

// - (optional) make sure one of the changes is a game, if not, ignore it
// - get the latest game document
// - if it's not our turn, do nothing
// - if it is our turn
//   - parse out the required data structures needed to pass to cortex
//   - call cortex to calculate next move
//   - make next move by inserting a new revision of votes doc
func (game *Game) handleChanges(changes Changes) {
	logg.LogTo("DEBUG", "handleChanges called with %v", changes)
	gameDocChanged := game.checkGameDocInChanges(changes)
	if gameDocChanged {
		gameState, err := game.fetchLatestGameState()
		game.gameState = gameState
		if err != nil {
			logg.LogError(err)
			return
		}
		logg.LogTo("DEBUG", "gameState: %v", gameState)
		if isOurTurn := game.isOurTurn(gameState); !isOurTurn {
			logg.LogTo("DEBUG", "It's not our turn, ignoring changes")
			return
		}

		gameStateVector := game.extractGameStateVector(gameState)

		logg.LogTo("DEBUG", "gameStateVector: %v", gameStateVector)

		possibleMoves := game.extractPossibleMoves(gameState)

		if len(possibleMoves) == 0 {
			logg.LogTo("MAIN", "No possibleMoves, ignoring changes")
			return
		}

		logg.LogTo("DEBUG", "possibleMoves: %v", possibleMoves)

		bestMove := game.ChooseBestMove(gameStateVector, possibleMoves)

		logg.LogTo("DEBUG", "bestMove: %v", bestMove)

		game.PostChosenMove(bestMove)

	}

}

func (game Game) extractPossibleMoves(gameState GameState) []ValidMoveCortexInput {

	moves := make([]ValidMoveCortexInput, 0)

	ourTeam := gameState.Teams[game.ourTeamId]

	for pieceIndex, piece := range ourTeam.Pieces {
		piece.PieceId = pieceIndex
		for _, validMove := range piece.ValidMoves {
			moveInput := NewValidMoveCortexInput(validMove, piece)
			moves = append(moves, moveInput)
		}
	}

	return moves
}

func (game Game) opponentTeamId() int {
	switch game.ourTeamId {
	case RED_TEAM:
		return BLUE_TEAM
	default:
		return RED_TEAM
	}
}

func (game Game) extractGameStateVector(gameState GameState) GameStateVector {
	gameStateVector := NewGameStateVector()
	gameStateVector.loadFromGameState(gameState, game.ourTeamId)
	return gameStateVector
}

func (game Game) isOurTurn(gameState GameState) bool {
	return gameState.ActiveTeam == game.ourTeamId
}

func (game Game) checkGameDocInChanges(changes Changes) bool {
	foundGameDoc := false
	changeResultsRaw := changes["results"]
	changeResults := changeResultsRaw.([]interface{})
	for _, changeResultRaw := range changeResults {
		changeResult := changeResultRaw.(map[string]interface{})
		docIdRaw := changeResult["id"]
		docId := docIdRaw.(string)
		if strings.Contains(docId, GAME_DOC_ID) {
			foundGameDoc = true
		}
	}
	return foundGameDoc
}

func (game Game) fetchLatestGameState() (gameState GameState, err error) {
	gameStateFetched := &GameState{}
	err = game.db.Retrieve(GAME_DOC_ID, gameStateFetched)
	if err == nil {
		gameState = *gameStateFetched
	}
	return
}

func (game *Game) InitGame() {
	game.CreateNeurgoCortex()
	cortex := game.cortex
	cortex.Run()
	game.InitDbConnection()
}

func (game *Game) InitDbConnection() {
	db, error := couch.Connect(SERVER_URL)
	if error != nil {
		logg.LogPanic("Error connecting to %v: %v", SERVER_URL, error)
	}
	game.db = db
}

func (game *Game) ChooseBestMove(gameStateVector GameStateVector, possibleMoves []ValidMoveCortexInput) (bestMove ValidMoveCortexInput) {

	// Todo: the code below is an implementation of a single MoveChooser
	// but an interface should be designed so this is pluggable

	game.currentGameState = gameStateVector
	logg.LogTo("MAIN", "gameStateVector: %v", gameStateVector)

	var bestMoveRating []float64
	bestMoveRating = []float64{-1000000000}

	for _, move := range possibleMoves {

		logg.LogTo("MAIN", "feed possible move to cortex: %v", move)

		// present it to the neural net
		game.currentPossibleMove = move
		game.cortex.SyncSensors()
		game.cortex.SyncActuators()

		logg.LogTo("MAIN", "done sync'ing actuators")

		logg.LogTo("MAIN", "actuator output %v bestMoveRating: %v", game.latestActuatorOutput[0], bestMoveRating[0])
		if game.latestActuatorOutput[0] > bestMoveRating[0] {
			logg.LogTo("MAIN", "actuator output > bestMoveRating")
			bestMove = move
			bestMoveRating[0] = game.latestActuatorOutput[0]
		} else {
			logg.LogTo("MAIN", "actuator output < bestMoveRating, ignoring")
		}

	}
	return

}

func (game *Game) PostChosenMove(move ValidMoveCortexInput) {

	logg.LogTo("MAIN", "post chosen move: %v", move.validMove)

	if len(move.validMove.Locations) == 0 {
		logg.LogTo("MAIN", "invalid move, ignoring: %v", move.validMove)
	}

	u4, err := uuid.NewV4()
	if err != nil {
		logg.LogError(err)
		return
	}

	votes := &OutgoingVotes{}
	votes.Id = fmt.Sprintf("vote:%s", u4)
	votes.Turn = game.gameState.Turn
	votes.PieceId = move.validMove.PieceId
	votes.TeamId = game.ourTeamId
	votes.GameId = game.gameState.Number

	// TODO: this is actually a bug, because if there is a
	// double jump it will only send the first jump move
	endLocation := move.validMove.Locations[0]
	locations := []int{move.validMove.StartLocation, endLocation}
	votes.Locations = locations

	newId, newRevision, err := game.db.Insert(votes)

	logg.LogTo("MAIN", "newId: %v, newRevision: %v err: %v", newId, newRevision, err)
	if err != nil {
		logg.LogError(err)
		return
	}

}

func (game *Game) CreateNeurgoCortex() {

	nodeId := ng.NewCortexId("cortex")
	game.cortex = &ng.Cortex{
		NodeId: nodeId,
	}
	game.CreateSensors()
	game.CreateActuator()
	game.CreateNeuron()
	game.ConnectNodes()
}

func (game *Game) ConnectNodes() {

	cortex := game.cortex

	cortex.Init()

	// connect sensors -> neuron(s)
	for _, sensor := range cortex.Sensors {
		for _, neuron := range cortex.Neurons {
			sensor.ConnectOutbound(neuron)
			weights := ng.RandomWeights(sensor.VectorLength)
			neuron.ConnectInboundWeighted(sensor, weights)
		}
	}

	// connect neuron to actuator
	for _, neuron := range cortex.Neurons {
		for _, actuator := range cortex.Actuators {
			neuron.ConnectOutbound(actuator)
			actuator.ConnectInbound(neuron)
		}
	}

}

func (game *Game) CreateNeuron() {
	neuron := &ng.Neuron{
		ActivationFunction: ng.EncodableSigmoid(),
		NodeId:             ng.NewNeuronId("Neuron", 0.25),
		Bias:               ng.RandomBias(),
	}
	game.cortex.SetNeurons([]*ng.Neuron{neuron})
}

func (game *Game) CreateActuator() {

	actuatorNodeId := ng.NewActuatorId("Actuator", 0.5)
	actuatorFunc := func(outputs []float64) {
		logg.LogTo("MAIN", "actuator func called with: %v", outputs)
		game.latestActuatorOutput = outputs
		game.cortex.SyncChan <- actuatorNodeId // TODO: this should be in actuator itself, not in this function
	}
	actuator := &ng.Actuator{
		NodeId:           actuatorNodeId,
		VectorLength:     1,
		ActuatorFunction: actuatorFunc,
	}
	game.cortex.SetActuators([]*ng.Actuator{actuator})

}

func (game *Game) CreateSensors() {

	sensorLayer := 0.0

	sensorFuncGameState := func(syncCounter int) []float64 {
		logg.LogTo("MAIN", "sensor func game state called")
		return game.currentGameState
	}
	sensorGameStateNodeId := ng.NewSensorId("SensorGameState", sensorLayer)
	sensorGameState := &ng.Sensor{
		NodeId:         sensorGameStateNodeId,
		VectorLength:   32,
		SensorFunction: sensorFuncGameState,
	}

	sensorFuncPossibleMove := func(syncCounter int) []float64 {
		logg.LogTo("MAIN", "sensor func possible move called")
		return game.currentPossibleMove.VectorRepresentation()
	}
	sensorPossibleMoveNodeId := ng.NewSensorId("SensorPossibleMove", sensorLayer)
	sensorPossibleMove := &ng.Sensor{
		NodeId:         sensorPossibleMoveNodeId,
		VectorLength:   5, // start_location, is_king, final_location, will_be_king, amt_would_capture
		SensorFunction: sensorFuncPossibleMove,
	}
	game.cortex.SetSensors([]*ng.Sensor{sensorGameState, sensorPossibleMove})

}

func decodeChanges(reader io.Reader) Changes {
	changes := make(Changes)
	decoder := json.NewDecoder(reader)
	decoder.Decode(&changes)
	return changes
}

func calculateNextSinceValue(curSinceValue string, changes Changes) string {
	lastSeq := changes["last_seq"]
	lastSeqAsString := lastSeq.(string)
	if lastSeq != nil && len(lastSeqAsString) > 0 {
		return lastSeqAsString
	}
	return curSinceValue
}
<|endoftext|>


<commit_before>package rest

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

	"github.com/krix38/ScorchedGo/properties"
)

type connectionInfo struct {
	SignedIn bool
}

var ConnectionStatus = createRestHandler(connectionStatus, []string{"GET"})

func connectionStatus() interface{}{
		/* TODO: check connection status */
		return connectionInfo{SignedIn: false}
}

func createRestHandler(handler func() interface{}, acceptedMethods []string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		for _, method := range acceptedMethods {
			if r.Method == method {
				w.Header().Set("Content-Type", "application/json")
				object := handler()
				jsonObject, err := json.Marshal(object)
				if err != nil {
					log.Fatal(properties.Messages.DebugJsonParseFail)
				}
				w.Write(jsonObject)
				return
			}
		}
		http.Error(w, properties.Messages.BadMethod+": "+r.Method, http.StatusBadRequest)
	}
}
<commit_msg>passing request and response args to rest handler - might by useful in some cases<commit_after>package rest

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

	"github.com/krix38/ScorchedGo/properties"
)

type connectionInfo struct {
	SignedIn bool
}

var ConnectionStatus = createRestHandler(connectionStatus, []string{"GET"})

func connectionStatus(w http.ResponseWriter, r *http.Request) interface{}{
		/* TODO: check connection status */
		return connectionInfo{SignedIn: false}
}

func createRestHandler(handler func(w http.ResponseWriter, r *http.Request) interface{}, acceptedMethods []string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		for _, method := range acceptedMethods {
			if r.Method == method {
				w.Header().Set("Content-Type", "application/json")
				object := handler(w, r)
				jsonObject, err := json.Marshal(object)
				if err != nil {
					log.Fatal(properties.Messages.DebugJsonParseFail)
				}
				w.Write(jsonObject)
				return
			}
		}
		http.Error(w, properties.Messages.BadMethod+": "+r.Method, http.StatusBadRequest)
	}
}
<|endoftext|>


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

// This program makes a call to the specified API, authenticated with OAuth2.
// a list of example APIs can be found at https://code.google.com/oauthplayground/
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"

	"code.google.com/p/goauth2/oauth"
)

var (
	clientId     = flag.String("id", "", "Client ID")
	clientSecret = flag.String("secret", "", "Client Secret")
	apiURL       = flag.String("api", "https://www.googleapis.com/auth/userinfo.profile", "API URL")
	apiRequest   = flag.String("req", "https://www.googleapis.com/oauth2/v1/userinfo", "API request")
	code         = flag.String("code", "", "Authorization Code")
	cachefile    = flag.String("cachefile", "request.token", "Token cache file")
	cache        = flag.Bool("cache", false, "Read token from cache")

	tokenCache oauth.CacheFile
)

const usageMsg = `
You must either specify both -id and -secret, or -cache to use saved tokens

To obtain client id and secret, see the "OAuth 2 Credentials" section under
the "API Access" tab on this page: https://code.google.com/apis/console/

After you receive a valid code, specify it using -code; then subsequent calls only need -cache
`

func main() {
	flag.Parse()
	if (*clientId == "" || *clientSecret == "") && !*cache {
		flag.Usage()
		fmt.Fprint(os.Stderr, usageMsg)
		return
	}

	// Set up a configuration
	config := &oauth.Config{
		ClientId:     *clientId,
		ClientSecret: *clientSecret,
		Scope:        *apiURL,
		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
		TokenURL:     "https://accounts.google.com/o/oauth2/token",
		RedirectURL:  "http://localhost/",
	}

	// Step one, get an authorization code from the data provider.
	// ("Please ask the user if I can access this resource.")
	if *code == "" && !*cache {
		url := config.AuthCodeURL("")
		fmt.Println("Visit this URL to get a code, then run again with -code=YOUR_CODE")
		fmt.Println(url)
		return
	}

	// Set up a Transport with our config, define the cache
	t := &oauth.Transport{Config: config}
	tokenCache = oauth.CacheFile(*cachefile)

	// Step two, exchange the authorization code for an access token.
	// Cache the token for later use
	// ("Here's the code you gave the user, now give me a token!")
	if !*cache {
		tok, err := t.Exchange(*code)
		if err != nil {
			log.Fatal(err)
		}
		err = tokenCache.PutToken(tok)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("Token is cached in %v\n", tokenCache)
		return
		// We needn't return here; we could just use the Transport
		// to make authenticated requests straight away.
		// The process has been split up to demonstrate how one might
		// restore Credentials that have been previously stored.
	} else {
		// Step three, make the actual request using the cached token to authenticate.
		// ("Here's the token, let me in!")
		ctoken, err := tokenCache.Token()
		if err != nil {
			log.Fatal(err)
		}
		t.Token = &oauth.Token{AccessToken: ctoken.AccessToken}
	}

	// Make the request.
	r, err := t.Client().Get(*apiRequest)
	if err != nil {
		log.Fatal(err)
	}
	defer r.Body.Close()
	// Write the response to standard output.
	io.Copy(os.Stdout, r.Body)
	fmt.Println()
}
<commit_msg>goauth2: add -auth -token -redirect, and -ap flags allowing the example to work with other OAuth2 providers Tested with Microsoft, Google, and Meetup<commit_after>// Copyright 2011 The goauth2 Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This program makes a call to the specified API, authenticated with OAuth2.
// a list of example APIs can be found at https://code.google.com/oauthplayground/
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"

	"code.google.com/p/goauth2/oauth"
)

var (
	clientId     = flag.String("id", "", "Client ID")
	clientSecret = flag.String("secret", "", "Client Secret")
	authURL      = flag.String("auth", "https://accounts.google.com/o/oauth2/auth", "Authorization URL")
	tokenURL     = flag.String("token", "https://accounts.google.com/o/oauth2/token", "Token URL")
	apiURL       = flag.String("api", "https://www.googleapis.com/auth/userinfo.profile", "API URL")
	redirectURL  = flag.String("redirect", "http://localhost/", "Redirect URL")
	apiRequest   = flag.String("req", "https://www.googleapis.com/oauth2/v1/userinfo", "API request")
	code         = flag.String("code", "", "Authorization Code")
	cachefile    = flag.String("cachefile", "request.token", "Token cache file")
	authparam    = flag.String("ap", "", "Authorization parameter")
	cache        = flag.Bool("cache", false, "Read token from cache")

	tokenCache oauth.CacheFile
)

const usageMsg = `
You must either specify both -id and -secret, or -cache to use saved tokens

To obtain client id and secret, see the "OAuth 2 Credentials" section under
the "API Access" tab on this page: https://code.google.com/apis/console/

After you receive a valid code, specify it using -code; then subsequent calls only need -cache
`

func main() {
	flag.Parse()
	if (*clientId == "" || *clientSecret == "") && !*cache {
		flag.Usage()
		fmt.Fprint(os.Stderr, usageMsg)
		return
	}
	// Set up a configuration
	config := &oauth.Config{
		ClientId:     *clientId,
		ClientSecret: *clientSecret,
		Scope:        *apiURL,
		AuthURL:      *authURL,
		TokenURL:     *tokenURL,
		RedirectURL:  *redirectURL,
	}

	// Step one, get an authorization code from the data provider.
	// ("Please ask the user if I can access this resource.")
	if *code == "" && !*cache {
		url := config.AuthCodeURL("")
		fmt.Println("Visit this URL to get a code, then run again with -code=YOUR_CODE\n")
		fmt.Println(url)
		return
	}

	// Set up a Transport with our config, define the cache
	t := &oauth.Transport{Config: config}
	tokenCache = oauth.CacheFile(*cachefile)

	// Step two, exchange the authorization code for an access token.
	// Cache the token for later use
	// ("Here's the code you gave the user, now give me a token!")
	if !*cache {
		tok, err := t.Exchange(*code)
		if err != nil {
			log.Fatal("Exchange:", err)
		}
		err = tokenCache.PutToken(tok)
		if err != nil {
			log.Fatal("Cache write:", err)
		}
		fmt.Printf("Token is cached in %v\n", tokenCache)
		return
		// We needn't return here; we could just use the Transport
		// to make authenticated requests straight away.
		// The process has been split up to demonstrate how one might
		// restore Credentials that have been previously stored.
	} else {
		// Step three, make the actual request using the cached token to authenticate.
		// ("Here's the token, let me in!")
		ctoken, err := tokenCache.Token()
		if err != nil {
			log.Fatal("Cache read:", err)
		}
		t.Token = &oauth.Token{AccessToken: ctoken.AccessToken}
		// Tack on the extra parameters, if specified.
		if *authparam != "" {
			*apiRequest += *authparam + ctoken.AccessToken
		}
	}

	// Make the request.
	r, err := t.Client().Get(*apiRequest)
	if err != nil {
		log.Fatal("Request:", err)
	}
	defer r.Body.Close()
	// Write the response to standard output.
	io.Copy(os.Stdout, r.Body)
	fmt.Println()
}
<|endoftext|>


<commit_before>package gentle

import (
	"errors"
	"github.com/afex/hystrix-go/hystrix"
	log15 "gopkg.in/inconshreveable/log15.v2"
	"time"
)

// Rate limiting pattern is used to limit the speed of a series of Handle().
type RateLimitedHandler struct {
	Name    string
	Log     log15.Logger
	handler Handler
	limiter RateLimit
}

func NewRateLimitedHandler(name string, handler Handler, limiter RateLimit) *RateLimitedHandler {
	return &RateLimitedHandler{
		Name:    name,
		Log:     Log.New("mixin", "handler_rate", "name", name),
		handler: handler,
		limiter: limiter,
	}
}

// Handle() is blocked when the limit is exceeded.
func (r *RateLimitedHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	r.limiter.Wait(1, 0)
	msg_out, err := r.handler.Handle(msg)
	if err != nil {
		r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(), "err", err)
		return nil, err
	}
	r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(), "msg_out", msg_out.Id())
	return msg, nil
}

// RetryHandler takes an Handler. When Handler.Handle() encounters an error,
// RetryHandler back off for some time and then retries.
type RetryHandler struct {
	Name     string
	Log      log15.Logger
	handler  Handler
	backoffs []time.Duration
}

func NewRetryHandler(name string, handler Handler, backoffs []time.Duration) *RetryHandler {
	if len(backoffs) == 0 {
		Log.Warn("NewRetryHandler() len(backoffs) == 0")
	}
	return &RetryHandler{
		Name:     name,
		Log:      Log.New("mixin", "handler_retry", "name", name),
		handler:  handler,
		backoffs: backoffs,
	}
}

func (r *RetryHandler) Handle(msg Message) (Message, error) {
	begin := time.Now()
	bk := r.backoffs
	to_wait := 0 * time.Second
	for {
		r.Log.Debug("[Handler] Handle() ...","msg_in", msg.Id(),
			"count", len(r.backoffs)-len(bk)+1, "wait", to_wait)
		// A negative or zero duration causes Sleep to return immediately.
		time.Sleep(to_wait)
		// assert end_allowed.Sub(now) != 0
		msg_out, err := r.handler.Handle(msg)
		if err == nil {
			r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(),
				"msg_out", msg_out.Id(),
				"timespan", time.Now().Sub(begin))
			return msg_out, err
		}
		if len(bk) == 0 {
			r.Log.Error("[Handler] Handle() err and no more backing off",
				"err", err, "msg_in", msg.Id(),
				"timespan", time.Now().Sub(begin))
			return nil, err
		} else {
			r.Log.Error("[Handler] Handle() err, backing off ...",
				"err", err, "msg_in", msg.Id(),
				"timespan", time.Now().Sub(begin))
			to_wait = bk[0]
			bk = bk[1:]
		}
	}
}

// CircuitBreakerHandler is a handler equipped with a circuit-breaker.
type CircuitBreakerHandler struct {
	Name    string
	Log     log15.Logger
	Circuit string
	handler Handler
}

// In hystrix-go, a circuit-breaker must be given a unique name.
// NewCircuitBreakerHandler() creates a CircuitBreakerHandler with a
// circuit-breaker named $circuit.
func NewCircuitBreakerHandler(name string, handler Handler, circuit string) *CircuitBreakerHandler {
	return &CircuitBreakerHandler{
		Name: name,
		Log: Log.New("mixin", "handler_circuit", "name", name,
			"circuit", circuit),
		Circuit: circuit,
		handler: handler,
	}
}

func (r *CircuitBreakerHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	result := make(chan *tuple, 1)
	err := hystrix.Do(r.Circuit, func() error {
		msg_out, err := r.handler.Handle(msg)
		if err != nil {
			r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(), "err", err)
			result <- &tuple{
				fst: msg_out,
				snd: err,
			}
			return err
		}
		r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(), "msg_out", msg_out.Id())
		result <- &tuple{
			fst: msg_out,
			snd: err,
		}
		return nil
	}, nil)
	// hystrix.ErrTimeout doesn't interrupt work anyway.
	// It just contributes to circuit's metrics.
	if err != nil {
		r.Log.Warn("[Handler] Circuit err", "msg_in", msg.Id(), "err", err)
		if err != hystrix.ErrTimeout {
			// Can be ErrCircuitOpen, ErrMaxConcurrency or
			// Handle()'s err.
			return nil, err
		}
	}
	tp := <-result
	if tp.snd == nil {
		return tp.fst.(Message), nil
	}
	return nil, tp.snd.(error)
}

// Bulkhead pattern is used to limit the number of concurrent Handle().
type BulkheadHandler struct {
	Name      string
	Log       log15.Logger
	handler   Handler
	semaphore chan *struct{}
}

// Create a BulkheadHandler that allows at maximum $max_concurrency Handle() to
// run concurrently.
func NewBulkheadHandler(name string, handler Handler, max_concurrency int) *BulkheadHandler {
	if max_concurrency <= 0 {
		panic(errors.New("max_concurrent must be greater than 0"))
	}
	return &BulkheadHandler{
		Name:      name,
		Log:       Log.New("mixin", "handler_bulk", "name", name),
		handler:   handler,
		semaphore: make(chan *struct{}, max_concurrency),
	}
}

// Handle() is blocked when the limit is exceeded.
func (r *BulkheadHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	r.semaphore <- &struct{}{}
	defer func() { <-r.semaphore }()
	msg_out, err := r.handler.Handle(msg)
	if err != nil {
		r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(),
			"err", err)
	} else {
		r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(),
			"msg_out", msg_out.Id())
	}
	return msg_out, err
}
<commit_msg>RatedLimitedHandler Handle() returns msg_out<commit_after>package gentle

import (
	"errors"
	"github.com/afex/hystrix-go/hystrix"
	log15 "gopkg.in/inconshreveable/log15.v2"
	"time"
)

// Rate limiting pattern is used to limit the speed of a series of Handle().
type RateLimitedHandler struct {
	Name    string
	Log     log15.Logger
	handler Handler
	limiter RateLimit
}

func NewRateLimitedHandler(name string, handler Handler, limiter RateLimit) *RateLimitedHandler {
	return &RateLimitedHandler{
		Name:    name,
		Log:     Log.New("mixin", "handler_rate", "name", name),
		handler: handler,
		limiter: limiter,
	}
}

// Handle() is blocked when the limit is exceeded.
func (r *RateLimitedHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	r.limiter.Wait(1, 0)
	msg_out, err := r.handler.Handle(msg)
	if err != nil {
		r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(), "err", err)
		return nil, err
	}
	r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(), "msg_out", msg_out.Id())
	return msg_out, nil
}

// RetryHandler takes an Handler. When Handler.Handle() encounters an error,
// RetryHandler back off for some time and then retries.
type RetryHandler struct {
	Name     string
	Log      log15.Logger
	handler  Handler
	backoffs []time.Duration
}

func NewRetryHandler(name string, handler Handler, backoffs []time.Duration) *RetryHandler {
	if len(backoffs) == 0 {
		Log.Warn("NewRetryHandler() len(backoffs) == 0")
	}
	return &RetryHandler{
		Name:     name,
		Log:      Log.New("mixin", "handler_retry", "name", name),
		handler:  handler,
		backoffs: backoffs,
	}
}

func (r *RetryHandler) Handle(msg Message) (Message, error) {
	begin := time.Now()
	bk := r.backoffs
	to_wait := 0 * time.Second
	for {
		r.Log.Debug("[Handler] Handle() ...","msg_in", msg.Id(),
			"count", len(r.backoffs)-len(bk)+1, "wait", to_wait)
		// A negative or zero duration causes Sleep to return immediately.
		time.Sleep(to_wait)
		// assert end_allowed.Sub(now) != 0
		msg_out, err := r.handler.Handle(msg)
		if err == nil {
			r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(),
				"msg_out", msg_out.Id(),
				"timespan", time.Now().Sub(begin))
			return msg_out, err
		}
		if len(bk) == 0 {
			r.Log.Error("[Handler] Handle() err and no more backing off",
				"err", err, "msg_in", msg.Id(),
				"timespan", time.Now().Sub(begin))
			return nil, err
		} else {
			r.Log.Error("[Handler] Handle() err, backing off ...",
				"err", err, "msg_in", msg.Id(),
				"timespan", time.Now().Sub(begin))
			to_wait = bk[0]
			bk = bk[1:]
		}
	}
}

// CircuitBreakerHandler is a handler equipped with a circuit-breaker.
type CircuitBreakerHandler struct {
	Name    string
	Log     log15.Logger
	Circuit string
	handler Handler
}

// In hystrix-go, a circuit-breaker must be given a unique name.
// NewCircuitBreakerHandler() creates a CircuitBreakerHandler with a
// circuit-breaker named $circuit.
func NewCircuitBreakerHandler(name string, handler Handler, circuit string) *CircuitBreakerHandler {
	return &CircuitBreakerHandler{
		Name: name,
		Log: Log.New("mixin", "handler_circuit", "name", name,
			"circuit", circuit),
		Circuit: circuit,
		handler: handler,
	}
}

func (r *CircuitBreakerHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	result := make(chan *tuple, 1)
	err := hystrix.Do(r.Circuit, func() error {
		msg_out, err := r.handler.Handle(msg)
		if err != nil {
			r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(), "err", err)
			result <- &tuple{
				fst: msg_out,
				snd: err,
			}
			return err
		}
		r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(), "msg_out", msg_out.Id())
		result <- &tuple{
			fst: msg_out,
			snd: err,
		}
		return nil
	}, nil)
	// hystrix.ErrTimeout doesn't interrupt work anyway.
	// It just contributes to circuit's metrics.
	if err != nil {
		r.Log.Warn("[Handler] Circuit err", "msg_in", msg.Id(), "err", err)
		if err != hystrix.ErrTimeout {
			// Can be ErrCircuitOpen, ErrMaxConcurrency or
			// Handle()'s err.
			return nil, err
		}
	}
	tp := <-result
	if tp.snd == nil {
		return tp.fst.(Message), nil
	}
	return nil, tp.snd.(error)
}

// Bulkhead pattern is used to limit the number of concurrent Handle().
type BulkheadHandler struct {
	Name      string
	Log       log15.Logger
	handler   Handler
	semaphore chan *struct{}
}

// Create a BulkheadHandler that allows at maximum $max_concurrency Handle() to
// run concurrently.
func NewBulkheadHandler(name string, handler Handler, max_concurrency int) *BulkheadHandler {
	if max_concurrency <= 0 {
		panic(errors.New("max_concurrent must be greater than 0"))
	}
	return &BulkheadHandler{
		Name:      name,
		Log:       Log.New("mixin", "handler_bulk", "name", name),
		handler:   handler,
		semaphore: make(chan *struct{}, max_concurrency),
	}
}

// Handle() is blocked when the limit is exceeded.
func (r *BulkheadHandler) Handle(msg Message) (Message, error) {
	r.Log.Debug("[Handler] Handle() ...", "msg_in", msg.Id())
	r.semaphore <- &struct{}{}
	defer func() { <-r.semaphore }()
	msg_out, err := r.handler.Handle(msg)
	if err != nil {
		r.Log.Error("[Handler] Handle() err", "msg_in", msg.Id(),
			"err", err)
	} else {
		r.Log.Debug("[Handler] Handle() ok", "msg_in", msg.Id(),
			"msg_out", msg_out.Id())
	}
	return msg_out, err
}
<|endoftext|>


<commit_before>package logrus

import (
	"encoding/json"
	"errors"

	"testing"
)

func TestErrorNotLost(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["error"] != "wild walrus" {
		t.Fatal("Error field not set")
	}
}

func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["omg"] != "wild walrus" {
		t.Fatal("Error field not set")
	}
}
<commit_msg>json_formatter: add tests for field clashes and newline<commit_after>package logrus

import (
	"encoding/json"
	"errors"

	"testing"
)

func TestErrorNotLost(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("error", errors.New("wild walrus")))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["error"] != "wild walrus" {
		t.Fatal("Error field not set")
	}
}

func TestErrorNotLostOnFieldNotNamedError(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("omg", errors.New("wild walrus")))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["omg"] != "wild walrus" {
		t.Fatal("Error field not set")
	}
}

func TestFieldClashWithTime(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("time", "right now!"))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["fields.time"] != "right now!" {
		t.Fatal("fields.time not set to original time field")
	}

	if entry["time"] != "0001-01-01T00:00:00Z" {
		t.Fatal("time field not set to current time, was: ", entry["time"])
	}
}

func TestFieldClashWithMsg(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("msg", "something"))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["fields.msg"] != "something" {
		t.Fatal("fields.msg not set to original msg field")
	}
}

func TestFieldClashWithLevel(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("level", "something"))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	entry := make(map[string]interface{})
	err = json.Unmarshal(b, &entry)
	if err != nil {
		t.Fatal("Unable to unmarshal formatted entry: ", err)
	}

	if entry["fields.level"] != "something" {
		t.Fatal("fields.level not set to original level field")
	}
}

func TestJSONEntryEndsWithNewline(t *testing.T) {
	formatter := &JSONFormatter{}

	b, err := formatter.Format(WithField("level", "something"))
	if err != nil {
		t.Fatal("Unable to format entry: ", err)
	}

	if b[len(b)-1] != '\n' {
		t.Fatal("Expected JSON log entry to end with a newline")
	}
}
<|endoftext|>


<commit_before>package noop

import (
	"io"
	"v2ray.com/core/common/alloc"
	"v2ray.com/core/common/loader"
	"v2ray.com/core/transport/internet"
)

type NoOpAuthenticator struct{}

func (this NoOpAuthenticator) Overhead() int {
	return 0
}
func (this NoOpAuthenticator) Open(payload *alloc.Buffer) bool {
	return true
}
func (this NoOpAuthenticator) Seal(payload *alloc.Buffer) {}

type NoOpAuthenticatorFactory struct{}

func (this NoOpAuthenticatorFactory) Create(config interface{}) internet.Authenticator {
	return NoOpAuthenticator{}
}

type NoOpConnectionAuthenticator struct{}

func (NoOpConnectionAuthenticator) Open(reader io.Reader) (bool, io.Reader) {
	return true, reader
}

func (NoOpConnectionAuthenticator) Seal(writer io.Writer) io.Writer {
	return writer
}

type NoOpConnectionAuthenticatorFactory struct{}

func (NoOpConnectionAuthenticatorFactory) Create(config interface{}) internet.ConnectionAuthenticator {
	return NoOpConnectionAuthenticator{}
}

func init() {
	internet.RegisterAuthenticator(loader.GetType(new(Config)), NoOpAuthenticatorFactory{})
	internet.RegisterConnectionAuthenticator(loader.GetType(new(Config)), NoOpConnectionAuthenticatorFactory{})
}
<commit_msg>fix type def<commit_after>package noop

import (
	"io"
	"v2ray.com/core/common/alloc"
	"v2ray.com/core/common/loader"
	"v2ray.com/core/transport/internet"
)

type NoOpAuthenticator struct{}

func (this NoOpAuthenticator) Overhead() int {
	return 0
}
func (this NoOpAuthenticator) Open(payload *alloc.Buffer) bool {
	return true
}
func (this NoOpAuthenticator) Seal(payload *alloc.Buffer) {}

type NoOpAuthenticatorFactory struct{}

func (this NoOpAuthenticatorFactory) Create(config interface{}) internet.Authenticator {
	return NoOpAuthenticator{}
}

type NoOpConnectionAuthenticator struct{}

func (NoOpConnectionAuthenticator) Open(reader io.Reader) (io.Reader, error) {
	return reader, nil
}

func (NoOpConnectionAuthenticator) Seal(writer io.Writer) io.Writer {
	return writer
}

type NoOpConnectionAuthenticatorFactory struct{}

func (NoOpConnectionAuthenticatorFactory) Create(config interface{}) internet.ConnectionAuthenticator {
	return NoOpConnectionAuthenticator{}
}

func init() {
	internet.RegisterAuthenticator(loader.GetType(new(Config)), NoOpAuthenticatorFactory{})
	internet.RegisterConnectionAuthenticator(loader.GetType(new(Config)), NoOpConnectionAuthenticatorFactory{})
}
<|endoftext|>


<commit_before>package google

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/hashicorp/errwrap"
)

const defaultBatchSendIntervalSec = 3

// RequestBatcher is a global batcher object that keeps track of
// existing batches.
// In general, a batcher should be created per service that requires batching
// in order to prevent blocking batching for one service due to another,
// and to minimize the possibility of overlap in batchKey formats
// (see SendRequestWithTimeout)
type RequestBatcher struct {
	sync.Mutex

	*batchingConfig
	parentCtx context.Context
	batches   map[string]*startedBatch
	debugId   string
}

// BatchRequest represents a single request to a global batcher.
type BatchRequest struct {
	// ResourceName represents the underlying resource for which
	// a request is made. Its format is determined by what SendF expects, but
	// typically should be the name of the parent GCP resource being changed.
	ResourceName string

	// Body is this request's data to be passed to SendF, and may be combined
	// with other bodies using CombineF.
	Body interface{}

	// CombineF function determines how to combine bodies from two batches.
	CombineF batcherCombineFunc

	// SendF function determines how to actually send a batched request to a
	// third party service. The arguments given to this function are
	// (ResourceName, Body) where Body may have been combined with other request
	// Bodies.
	SendF batcherSendFunc

	// ID for debugging request. This should be specific to a single request
	// (i.e. per Terraform resource)
	DebugId string
}

// These types are meant to be the public interface to batchers. They define
// logic to manage batch data type and behavior, and require service-specific
// implementations per type of request per service.
// Function type for combine existing batches and additional batch data
type batcherCombineFunc func(body interface{}, toAdd interface{}) (interface{}, error)

// Function type for sending a batch request
type batcherSendFunc func(resourceName string, body interface{}) (interface{}, error)

// batchResponse bundles an API response (data, error) tuple.
type batchResponse struct {
	body interface{}
	err  error
}

// startedBatch refers to a processed batch whose timer to send the request has
// already been started. The responses for the request is sent to each listener
// channel, representing parallel callers that are waiting on requests
// combined into this batch.
type startedBatch struct {
	batchKey string
	*BatchRequest

	listeners []chan batchResponse
	timer     *time.Timer
}

// batchingConfig contains user configuration for controlling batch requests.
type batchingConfig struct {
	sendAfter      time.Duration
	enableBatching bool
}

// Initializes a new batcher.
func NewRequestBatcher(debugId string, ctx context.Context, config *batchingConfig) *RequestBatcher {
	batcher := &RequestBatcher{
		debugId:        debugId,
		parentCtx:      ctx,
		batchingConfig: config,
		batches:        make(map[string]*startedBatch),
	}

	go func(b *RequestBatcher) {
		<-ctx.Done()
		b.stop()
	}(batcher)

	return batcher
}

func (b *RequestBatcher) stop() {
	b.Lock()
	defer b.Unlock()

	log.Printf("[DEBUG] Stopping batcher %q", b.debugId)
	for batchKey, batch := range b.batches {
		log.Printf("[DEBUG] Cleaning up batch request %q", batchKey)
		batch.timer.Stop()
		for _, l := range batch.listeners {
			close(l)
		}
	}
}

// SendRequestWithTimeout is expected to be called per parallel call.
// It manages waiting on the result of a batch request.
//
// Batch requests are grouped by the given batchKey. batchKey
// should be unique to the API request being sent, most likely similar to
// the HTTP request URL with GCP resource ID included in the URL (the caller
// may choose to use a key with method if needed to diff GET/read and
// POST/create)
//
// As an example, for google_project_service, the
// batcher is called to batch services.batchEnable() calls for a project
// $PROJECT. The calling code uses the template
// "serviceusage:projects/$PROJECT/services:batchEnable", which mirrors the HTTP request:
// POST https://serviceusage.googleapis.com/v1/projects/$PROJECT/services:batchEnable
func (b *RequestBatcher) SendRequestWithTimeout(batchKey string, request *BatchRequest, timeout time.Duration) (interface{}, error) {
	if request == nil {
		return nil, fmt.Errorf("error, cannot request batching for nil BatchRequest")
	}
	if request.CombineF == nil {
		return nil, fmt.Errorf("error, cannot request batching for BatchRequest with nil CombineF")
	}
	if request.SendF == nil {
		return nil, fmt.Errorf("error, cannot request batching for BatchRequest with nil SendF")
	}
	if !b.enableBatching {
		log.Printf("[DEBUG] Batching is disabled, sending single request for %q", request.DebugId)
		return request.SendF(request.ResourceName, request.Body)
	}

	respCh, err := b.registerBatchRequest(batchKey, request)
	if err != nil {
		return nil, fmt.Errorf("error adding request to batch: %s", err)
	}

	ctx, cancel := context.WithTimeout(b.parentCtx, timeout)
	defer cancel()

	select {
	case resp := <-respCh:
		if resp.err != nil {
			// use wrapf so we can potentially extract the original error type
			return nil, errwrap.Wrapf(fmt.Sprintf("Batch %q for request %q returned error: {{err}}", batchKey, request.DebugId), resp.err)
		}
		return resp.body, nil
	case <-ctx.Done():
		break
	}
	return nil, fmt.Errorf("Request %s timed out after %v", batchKey, timeout)
}

// registerBatchRequest safely sees if an existing batch has been started
// with the given batchKey. If a batch exists, this will combine the new
// request into this existing batch. Else, this method manages starting a new
// batch and adding it to the RequestBatcher's started batches.
func (b *RequestBatcher) registerBatchRequest(batchKey string, newRequest *BatchRequest) (<-chan batchResponse, error) {
	b.Lock()
	defer b.Unlock()

	// If batch already exists, combine this request into existing request.
	if batch, ok := b.batches[batchKey]; ok {
		return batch.addRequest(newRequest)
	}

	log.Printf("[DEBUG] Creating new batch %q from request %q", newRequest.DebugId, batchKey)
	// The calling goroutine will need a channel to wait on for a response.
	respCh := make(chan batchResponse, 1)

	// Create a new batch.
	b.batches[batchKey] = &startedBatch{
		BatchRequest: newRequest,
		batchKey:     batchKey,
		listeners:    []chan batchResponse{respCh},
	}

	// Start a timer to send the request
	b.batches[batchKey].timer = time.AfterFunc(b.sendAfter, func() {
		batch := b.popBatch(batchKey)

		var resp batchResponse
		if batch == nil {
			log.Printf("[DEBUG] Batch not found in saved batches, running single request batch %q", batchKey)
			resp = newRequest.send()
		} else {
			log.Printf("[DEBUG] Sending batch %q combining %d requests)", batchKey, len(batch.listeners))
			resp = batch.send()
		}

		// Send message to all goroutines waiting on result.
		for _, ch := range batch.listeners {
			ch <- resp
			close(ch)
		}
	})

	return respCh, nil
}

// popBatch safely gets and removes a batch with given batchkey from the
// RequestBatcher's started batches.
func (b *RequestBatcher) popBatch(batchKey string) *startedBatch {
	b.Lock()
	defer b.Unlock()

	batch, ok := b.batches[batchKey]
	if !ok {
		log.Printf("[DEBUG] Batch with ID %q not found in batcher", batchKey)
		return nil
	}

	delete(b.batches, batchKey)
	return batch
}

func (batch *startedBatch) addRequest(newRequest *BatchRequest) (<-chan batchResponse, error) {
	log.Printf("[DEBUG] Adding batch request %q to existing batch %q", newRequest.DebugId, batch.batchKey)
	if batch.CombineF == nil {
		return nil, fmt.Errorf("Provider Error: unable to add request %q to batch %q with no CombineF", newRequest.DebugId, batch.batchKey)
	}
	newBody, err := batch.CombineF(batch.Body, newRequest.Body)
	if err != nil {
		return nil, fmt.Errorf("Provider Error: Unable to combine request %q data into existing batch %q: %v", newRequest.DebugId, batch.batchKey, err)
	}
	batch.Body = newBody

	log.Printf("[DEBUG] Added batch request %q to batch. New batch body: %v", newRequest.DebugId, batch.Body)

	respCh := make(chan batchResponse, 1)
	batch.listeners = append(batch.listeners, respCh)
	return respCh, nil
}

func (req *BatchRequest) send() batchResponse {
	if req.SendF == nil {
		return batchResponse{
			err: fmt.Errorf("provider error: Batch request has no SendBatch function"),
		}
	}
	v, err := req.SendF(req.ResourceName, req.Body)
	return batchResponse{v, err}
}
<commit_msg>Batch errors now indicate how to disable batching<commit_after>package google

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/hashicorp/errwrap"
)

const defaultBatchSendIntervalSec = 3

// RequestBatcher is a global batcher object that keeps track of
// existing batches.
// In general, a batcher should be created per service that requires batching
// in order to prevent blocking batching for one service due to another,
// and to minimize the possibility of overlap in batchKey formats
// (see SendRequestWithTimeout)
type RequestBatcher struct {
	sync.Mutex

	*batchingConfig
	parentCtx context.Context
	batches   map[string]*startedBatch
	debugId   string
}

// BatchRequest represents a single request to a global batcher.
type BatchRequest struct {
	// ResourceName represents the underlying resource for which
	// a request is made. Its format is determined by what SendF expects, but
	// typically should be the name of the parent GCP resource being changed.
	ResourceName string

	// Body is this request's data to be passed to SendF, and may be combined
	// with other bodies using CombineF.
	Body interface{}

	// CombineF function determines how to combine bodies from two batches.
	CombineF batcherCombineFunc

	// SendF function determines how to actually send a batched request to a
	// third party service. The arguments given to this function are
	// (ResourceName, Body) where Body may have been combined with other request
	// Bodies.
	SendF batcherSendFunc

	// ID for debugging request. This should be specific to a single request
	// (i.e. per Terraform resource)
	DebugId string
}

// These types are meant to be the public interface to batchers. They define
// logic to manage batch data type and behavior, and require service-specific
// implementations per type of request per service.
// Function type for combine existing batches and additional batch data
type batcherCombineFunc func(body interface{}, toAdd interface{}) (interface{}, error)

// Function type for sending a batch request
type batcherSendFunc func(resourceName string, body interface{}) (interface{}, error)

// batchResponse bundles an API response (data, error) tuple.
type batchResponse struct {
	body interface{}
	err  error
}

// startedBatch refers to a processed batch whose timer to send the request has
// already been started. The responses for the request is sent to each listener
// channel, representing parallel callers that are waiting on requests
// combined into this batch.
type startedBatch struct {
	batchKey string
	*BatchRequest

	listeners []chan batchResponse
	timer     *time.Timer
}

// batchingConfig contains user configuration for controlling batch requests.
type batchingConfig struct {
	sendAfter      time.Duration
	enableBatching bool
}

// Initializes a new batcher.
func NewRequestBatcher(debugId string, ctx context.Context, config *batchingConfig) *RequestBatcher {
	batcher := &RequestBatcher{
		debugId:        debugId,
		parentCtx:      ctx,
		batchingConfig: config,
		batches:        make(map[string]*startedBatch),
	}

	go func(b *RequestBatcher) {
		<-ctx.Done()
		b.stop()
	}(batcher)

	return batcher
}

func (b *RequestBatcher) stop() {
	b.Lock()
	defer b.Unlock()

	log.Printf("[DEBUG] Stopping batcher %q", b.debugId)
	for batchKey, batch := range b.batches {
		log.Printf("[DEBUG] Cleaning up batch request %q", batchKey)
		batch.timer.Stop()
		for _, l := range batch.listeners {
			close(l)
		}
	}
}

// SendRequestWithTimeout is expected to be called per parallel call.
// It manages waiting on the result of a batch request.
//
// Batch requests are grouped by the given batchKey. batchKey
// should be unique to the API request being sent, most likely similar to
// the HTTP request URL with GCP resource ID included in the URL (the caller
// may choose to use a key with method if needed to diff GET/read and
// POST/create)
//
// As an example, for google_project_service, the
// batcher is called to batch services.batchEnable() calls for a project
// $PROJECT. The calling code uses the template
// "serviceusage:projects/$PROJECT/services:batchEnable", which mirrors the HTTP request:
// POST https://serviceusage.googleapis.com/v1/projects/$PROJECT/services:batchEnable
func (b *RequestBatcher) SendRequestWithTimeout(batchKey string, request *BatchRequest, timeout time.Duration) (interface{}, error) {
	if request == nil {
		return nil, fmt.Errorf("error, cannot request batching for nil BatchRequest")
	}
	if request.CombineF == nil {
		return nil, fmt.Errorf("error, cannot request batching for BatchRequest with nil CombineF")
	}
	if request.SendF == nil {
		return nil, fmt.Errorf("error, cannot request batching for BatchRequest with nil SendF")
	}
	if !b.enableBatching {
		log.Printf("[DEBUG] Batching is disabled, sending single request for %q", request.DebugId)
		return request.SendF(request.ResourceName, request.Body)
	}

	respCh, err := b.registerBatchRequest(batchKey, request)
	if err != nil {
		return nil, fmt.Errorf("error adding request to batch: %s", err)
	}

	ctx, cancel := context.WithTimeout(b.parentCtx, timeout)
	defer cancel()

	select {
	case resp := <-respCh:
		if resp.err != nil {
			// use wrapf so we can potentially extract the original error type
			errMsg := fmt.Sprintf(
				"Batch %q for request %q returned error: {{err}}. To debug individual requests, try disabling batching: https://www.terraform.io/docs/providers/google/guides/provider_reference.html#enable_batching",
				batchKey, request.DebugId)
			return nil, errwrap.Wrapf(errMsg, resp.err)
		}
		return resp.body, nil
	case <-ctx.Done():
		break
	}
	return nil, fmt.Errorf("Request %s timed out after %v", batchKey, timeout)
}

// registerBatchRequest safely sees if an existing batch has been started
// with the given batchKey. If a batch exists, this will combine the new
// request into this existing batch. Else, this method manages starting a new
// batch and adding it to the RequestBatcher's started batches.
func (b *RequestBatcher) registerBatchRequest(batchKey string, newRequest *BatchRequest) (<-chan batchResponse, error) {
	b.Lock()
	defer b.Unlock()

	// If batch already exists, combine this request into existing request.
	if batch, ok := b.batches[batchKey]; ok {
		return batch.addRequest(newRequest)
	}

	log.Printf("[DEBUG] Creating new batch %q from request %q", newRequest.DebugId, batchKey)
	// The calling goroutine will need a channel to wait on for a response.
	respCh := make(chan batchResponse, 1)

	// Create a new batch.
	b.batches[batchKey] = &startedBatch{
		BatchRequest: newRequest,
		batchKey:     batchKey,
		listeners:    []chan batchResponse{respCh},
	}

	// Start a timer to send the request
	b.batches[batchKey].timer = time.AfterFunc(b.sendAfter, func() {
		batch := b.popBatch(batchKey)

		var resp batchResponse
		if batch == nil {
			log.Printf("[DEBUG] Batch not found in saved batches, running single request batch %q", batchKey)
			resp = newRequest.send()
		} else {
			log.Printf("[DEBUG] Sending batch %q combining %d requests)", batchKey, len(batch.listeners))
			resp = batch.send()
		}

		// Send message to all goroutines waiting on result.
		for _, ch := range batch.listeners {
			ch <- resp
			close(ch)
		}
	})

	return respCh, nil
}

// popBatch safely gets and removes a batch with given batchkey from the
// RequestBatcher's started batches.
func (b *RequestBatcher) popBatch(batchKey string) *startedBatch {
	b.Lock()
	defer b.Unlock()

	batch, ok := b.batches[batchKey]
	if !ok {
		log.Printf("[DEBUG] Batch with ID %q not found in batcher", batchKey)
		return nil
	}

	delete(b.batches, batchKey)
	return batch
}

func (batch *startedBatch) addRequest(newRequest *BatchRequest) (<-chan batchResponse, error) {
	log.Printf("[DEBUG] Adding batch request %q to existing batch %q", newRequest.DebugId, batch.batchKey)
	if batch.CombineF == nil {
		return nil, fmt.Errorf("Provider Error: unable to add request %q to batch %q with no CombineF", newRequest.DebugId, batch.batchKey)
	}
	newBody, err := batch.CombineF(batch.Body, newRequest.Body)
	if err != nil {
		return nil, fmt.Errorf("Provider Error: Unable to combine request %q data into existing batch %q: %v", newRequest.DebugId, batch.batchKey, err)
	}
	batch.Body = newBody

	log.Printf("[DEBUG] Added batch request %q to batch. New batch body: %v", newRequest.DebugId, batch.Body)

	respCh := make(chan batchResponse, 1)
	batch.listeners = append(batch.listeners, respCh)
	return respCh, nil
}

func (req *BatchRequest) send() batchResponse {
	if req.SendF == nil {
		return batchResponse{
			err: fmt.Errorf("provider error: Batch request has no SendBatch function"),
		}
	}
	v, err := req.SendF(req.ResourceName, req.Body)
	return batchResponse{v, err}
}
<|endoftext|>


<commit_before>package rabbitmq

import (
	"errors"
	"fmt"
	"github.com/streadway/amqp"
)

type Consumer struct {
	conn       *amqp.Connection
	channel    *amqp.Channel
	deliveries <-chan amqp.Delivery
	tag        string
	handler    func(deliveries <-chan amqp.Delivery)
	done       chan error
	session    Session
}

func (c *Consumer) Deliveries() <-chan amqp.Delivery {
	return c.deliveries
}

func NewConsumer(e Exchange, q Queue, bo BindingOptions, co ConsumerOptions) (*Consumer, error) {

	if co.Tag == "" {
		return nil, errors.New("Tag is not defined in consumer options")
	}

	c := &Consumer{
		conn:    nil,
		channel: nil,
		tag:     co.Tag,
		done:    make(chan error),
		session: Session{
			Exchange:        e,
			Queue:           q,
			ConsumerOptions: co,
			BindingOptions:  bo,
		},
	}
	err := c.connect()
	if err != nil {
		return nil, err
	}

	// go func() {
	//  fmt.Printf("closing: %s", <-c.conn.NotifyClose(make(chan *amqp.Error)))
	// }()

	return c, nil
}

func (c *Consumer) connect() error {

	e := c.session.Exchange
	q := c.session.Queue
	bo := c.session.BindingOptions
	co := c.session.ConsumerOptions

	var err error

	c.conn, err = amqp.Dial(getConnectionString())
	if err != nil {
		return err
	}
	handleErrors(c.conn)
	// got Connection, getting Channel
	c.channel, err = c.conn.Channel()
	if err != nil {
		return err
	}

	// got channel, declaring Exchange
	if err = c.channel.ExchangeDeclare(
		e.Name,       // name of the exchange
		e.Type,       // type
		e.Durable,    // durable
		e.AutoDelete, // delete when complete
		e.Internal,   // internal
		e.NoWait,     // noWait
		e.Args,       // arguments
	); err != nil {
		return err
	}

	// declaring Queue
	queue, err := c.channel.QueueDeclare(
		q.Name,       // name of the queue
		q.Durable,    // durable
		q.AutoDelete, // delete when usused
		q.Exclusive,  // exclusive
		q.NoWait,     // noWait
		q.Args,       // arguments
	)
	if err != nil {
		return err
	}

	// declared Queue, binding to Exchange
	if err = c.channel.QueueBind(
		// bind to real queue
		queue.Name,    // name of the queue
		bo.RoutingKey, // bindingKey
		e.Name,        // sourceExchange
		bo.NoWait,     // noWait
		bo.Args,       // arguments
	); err != nil {
		return err
	}

	// Queue bound to Exchange, starting Consume
	deliveries, err := c.channel.Consume(
		// consume from real queue
		queue.Name,   // name
		co.Tag,       // consumerTag,
		co.AutoAck,   // autoAck
		co.Exclusive, // exclusive
		co.NoLocal,   // noLocal
		co.NoWait,    // noWait
		co.Args,      // arguments
	)
	if err != nil {
		return err
	}

	c.deliveries = deliveries

	return nil
}

func (c *Consumer) Consume(handler func(deliveries <-chan amqp.Delivery)) {
	c.handler = handler
	// handle all consumer errors, if required re-connect

	handler(c.deliveries)
	fmt.Println("handle: deliveries channel closed")
	c.done <- nil
}

func (c *Consumer) Shutdown() error {
	err := shutdown(c.conn, c.channel, c.tag)
	if err != nil {
		return nil
	}
	defer fmt.Println("Consumer shutdown OK")
	fmt.Println("Waiting for handler to exit")
	return <-c.done
}

func (c *Consumer) RegisterSignalHandler() {
	registerSignalHandler(c)
}
<commit_msg>[Rabbitmq] Fixing inline comments<commit_after>package rabbitmq

import (
	"errors"
	"fmt"
	"github.com/streadway/amqp"
)

type Consumer struct {
	conn       *amqp.Connection
	channel    *amqp.Channel
	deliveries <-chan amqp.Delivery
	tag        string
	handler    func(deliveries <-chan amqp.Delivery)
	done       chan error
	session    Session
}

func (c *Consumer) Deliveries() <-chan amqp.Delivery {
	return c.deliveries
}

func NewConsumer(e Exchange, q Queue, bo BindingOptions, co ConsumerOptions) (*Consumer, error) {

	if co.Tag == "" {
		return nil, errors.New("Tag is not defined in consumer options")
	}

	c := &Consumer{
		conn:    nil,
		channel: nil,
		tag:     co.Tag,
		done:    make(chan error),
		session: Session{
			Exchange:        e,
			Queue:           q,
			ConsumerOptions: co,
			BindingOptions:  bo,
		},
	}
	err := c.connect()
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (c *Consumer) connect() error {

	e := c.session.Exchange
	q := c.session.Queue
	bo := c.session.BindingOptions
	co := c.session.ConsumerOptions

	var err error

	// getting Connection
	c.conn, err = amqp.Dial(getConnectionString())
	if err != nil {
		return err
	}
	handleErrors(c.conn)
	// getting Channel
	c.channel, err = c.conn.Channel()
	if err != nil {
		return err
	}

	// got channel, declaring Exchange
	if err = c.channel.ExchangeDeclare(
		e.Name,       // name of the exchange
		e.Type,       // type
		e.Durable,    // durable
		e.AutoDelete, // delete when complete
		e.Internal,   // internal
		e.NoWait,     // noWait
		e.Args,       // arguments
	); err != nil {
		return err
	}

	// declaring Queue
	queue, err := c.channel.QueueDeclare(
		q.Name,       // name of the queue
		q.Durable,    // durable
		q.AutoDelete, // delete when usused
		q.Exclusive,  // exclusive
		q.NoWait,     // noWait
		q.Args,       // arguments
	)
	if err != nil {
		return err
	}

	// declared Queue, binding to Exchange
	if err = c.channel.QueueBind(
		// bind to real queue
		queue.Name,    // name of the queue
		bo.RoutingKey, // bindingKey
		e.Name,        // sourceExchange
		bo.NoWait,     // noWait
		bo.Args,       // arguments
	); err != nil {
		return err
	}

	// Queue bound to Exchange, starting Consume
	deliveries, err := c.channel.Consume(
		// consume from real queue
		queue.Name,   // name
		co.Tag,       // consumerTag,
		co.AutoAck,   // autoAck
		co.Exclusive, // exclusive
		co.NoLocal,   // noLocal
		co.NoWait,    // noWait
		co.Args,      // arguments
	)
	if err != nil {
		return err
	}

	// should we stop streaming, in order not to consume from server?
	c.deliveries = deliveries

	return nil
}

func (c *Consumer) Consume(handler func(deliveries <-chan amqp.Delivery)) {
	c.handler = handler

	// handle all consumer errors, if required re-connect
	// there are problems with reconnection logic
	handler(c.deliveries)

	// change fmt -> log
	fmt.Println("handle: deliveries channel closed")
	c.done <- nil
}

func (c *Consumer) Shutdown() error {
	err := shutdown(c.conn, c.channel, c.tag)
	if err != nil {
		return nil
	}
	// change fmt -> log
	defer fmt.Println("Consumer shutdown OK")
	fmt.Println("Waiting for handler to exit")
	return <-c.done
}

func (c *Consumer) RegisterSignalHandler() {
	registerSignalHandler(c)
}
<|endoftext|>