<commit_before>package game

import (
	"github.com/svera/acquire/board"
	"github.com/svera/acquire/corporation"
	"github.com/svera/acquire/fsm"
	"github.com/svera/acquire/player"
	"github.com/svera/acquire/tileset"
	"testing"
)

func TestNewGameWrongNumberPlayers(t *testing.T) {
	players, corporations, board, tileset := setup()
	players = players[:1]

	if _, err := New(board, players, corporations, tileset); err.Error() != WrongNumberPlayers {
		t.Errorf("Game must not be created with less than 3 players, got %d", len(players))
	}
}

func TestNewGameNotUniqueCorpIds(t *testing.T) {
	players, corporations, board, tileset := setup()

	corporations[0] = corporation.NewStub("A", 0, 0)
	corporations[1] = corporation.NewStub("B", 0, 0)

	if _, err := New(board, players, corporations, tileset); err.Error() != CorpIdNotUnique {
		t.Errorf("Corporations must have unique values, expecting %s error, got %s", CorpIdNotUnique, err.Error())
	}
}

func TestNewGameWrongNumberOfCorpsPerClass(t *testing.T) {
	players, corporations, board, tileset := setup()

	corporations[2] = corporation.NewStub("C", 0, 2)

	if _, err := New(board, players, corporations, tileset); err.Error() != WrongNumberCorpsClass {
		t.Errorf("Game must catch wrong number of corporations per class")
	}
}

func TestNewGameInitsPlayersTilesets(t *testing.T) {
	players, corporations, board, tileset := setup()
	New(board, players, corporations, tileset)

	for i, player := range players {
		if len(player.Tiles()) != 6 {
			t.Errorf("Players must have 6 tiles at the beginning, player %d got %d", i, len(player.Tiles()))
		}
	}
}

func TestAreEndConditionsReached(t *testing.T) {
	players, corporations, board, tileset := setup()
	game, _ := New(board, players, corporations, tileset)

	if game.AreEndConditionsReached() {
		t.Errorf("End game conditions not reached (no active corporations) but detected as it were")
	}

	corporations[0].(*corporation.Stub).SetSize(41)

	if !game.AreEndConditionsReached() {
		t.Errorf("End game conditions reached (a corporation bigger than 40 tiles) but not detected")
	}

	corporations[0].(*corporation.Stub).SetSize(11)

	if !game.AreEndConditionsReached() {
		t.Errorf("End game conditions reached (all active corporations safe) but not detected")
	}

	corporations[0].(*corporation.Stub).SetSize(11)
	corporations[1].(*corporation.Stub).SetSize(2)

	if game.AreEndConditionsReached() {
		t.Errorf("End game conditions not reached but detected as it were")
	}

}

func TestGetMainStockHolders(t *testing.T) {
	players, corporations, board, tileset := setup()

	players[0].(*player.Stub).SetShares(corporations[0], 8)

	game, _ := New(board, players, corporations, tileset)
	stockHolders := game.GetMainStockHolders(corporations[0])
	expectedStockHolders := map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[0]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there's just one player with stock in a defunct corporation, " +
				"he/she must get both majority and minority bonuses",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[1]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"Wrong main stock holders",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 8)
	players[2].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0], players[1]},
		"minority": {},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there are two or more majority stock holders in a defunct corporation, " +
				"the majority bonus must be splitted between them (no minority bonus given)",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 5)
	players[2].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[1], players[2]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there are two or more minority stock holders in a defunct corporation, " +
				"the minority bonus must be splitted between them",
		)
	}

}

func TestPlayTileFoundCorporation(t *testing.T) {
	players, corporations, bd, ts := setup()
	tileToPlay := tileset.Position{Number: 6, Letter: "E"}
	bd.PutTile(tileset.Position{Number: 5, Letter: "E"})

	game, _ := New(bd, players, corporations, ts)
	playerTiles := players[0].Tiles()
	players[0].DiscardTile(playerTiles[0])
	players[0].PickTile(tileToPlay)
	game.PlayTile(tileToPlay)

	if game.state.Name() != "FoundCorp" {
		t.Errorf("Game must be in state FoundCorp, got %s", game.state.Name())
	}
}

func TestPlayTileGrowCorporation(t *testing.T) {
	players, corporations, bd, ts := setup()
	tileToPlay := tileset.Position{Number: 6, Letter: "E"}
	corpTiles := []tileset.Position{{Number: 7, Letter: "E"}, {Number: 8, Letter: "E"}}
	corporations[0].AddTiles(corpTiles)
	bd.SetTiles(corporations[0], corpTiles)
	bd.PutTile(tileset.Position{Number: 5, Letter: "E"})

	game, _ := New(bd, players, corporations, ts)
	playerTiles := players[0].Tiles()
	players[0].DiscardTile(playerTiles[0])
	players[0].PickTile(tileToPlay)
	game.PlayTile(tileToPlay)

	expectedCorpSize := 4

	if game.state.Name() != "BuyStock" {
		t.Errorf("Game must be in state BuyStock, got %s", game.state.Name())
	}
	if corporations[0].Size() != expectedCorpSize {
		t.Errorf("Corporation size must be %d, got %d", expectedCorpSize, corporations[0].Size())
	}
}

func TestBuyStock(t *testing.T) {
	players, corporations, bd, ts := setup()
	corporations[0].AddTiles(
		[]tileset.Position{
			{Number: 1, Letter: "A"},
			{Number: 2, Letter: "A"},
		},
	)
	buys := map[int]int{0: 2}
	var expectedAvailableStock int = 23
	var expectedPlayerStock int = 2
	game, _ := New(bd, players, corporations, ts)
	game.state = &fsm.BuyStock{}
	game.BuyStock(buys)

	if corporations[0].Stock() != expectedAvailableStock {
		t.Errorf("Corporation stock shares have not decreased, must be %d, got %d", expectedAvailableStock, corporations[0].Stock())
	}
	if players[0].Shares(corporations[0]) != expectedPlayerStock {
		t.Errorf("Player stock shares have not increased, must be %d, got %d", expectedPlayerStock, players[0].Shares(corporations[0]))
	}
}

func TestBuyStockWithNotEnoughCash(t *testing.T) {
	players, corporations, bd, ts := setup()
	players[0].(*player.Stub).SetCash(100)

	corporations[0].AddTiles(
		[]tileset.Position{
			{Number: 1, Letter: "A"},
			{Number: 2, Letter: "A"},
		},
	)

	buys := map[int]int{0: 2}
	game, _ := New(bd, players, corporations, ts)
	err := game.BuyStock(buys)
	if err == nil {
		t.Errorf("Trying to buy stock shares without enough money must throw error")
	}
}

// Testing that if player has an permanently unplayable tile, this is exchanged:
// In the following example, tile 6D is unplayable because it would merge safe
// corporations 0 and 1
//
//    5 6  7 8
// D [0]><[1]
func TestDrawTile(t *testing.T) {
	players, corporations, bd, ts := setup()
	corporations[0].(*corporation.Stub).SetSize(11)
	corporations[1].(*corporation.Stub).SetSize(15)
	unplayableTile := tileset.Position{Number: 6, Letter: "D"}
	bd.SetTiles(corporations[0], []tileset.Position{{Number: 5, Letter: "D"}})
	bd.SetTiles(corporations[1], []tileset.Position{{Number: 7, Letter: "D"}})

	game, _ := New(bd, players, corporations, ts)
	players[0].(*player.Stub).SetTiles([]tileset.Position{unplayableTile})
	game.tileset.(*tileset.Stub).DiscardTile(unplayableTile)
	game.state = &fsm.BuyStock{}
	game.drawTile()
	for _, tile := range players[0].Tiles() {
		if tile.Number == unplayableTile.Number && tile.Letter == unplayableTile.Letter {
			t.Errorf("Unplayable tile not discarded after drawing new tile, got %v", players[0].Tiles())
		}
	}
}

func setup() ([]player.Interface, [7]corporation.Interface, board.Interface, tileset.Interface) {
	var players []player.Interface
	players = append(players, player.NewStub("Test1"))
	players = append(players, player.NewStub("Test2"))
	players = append(players, player.NewStub("Test3"))

	var corporations [7]corporation.Interface
	corporations[0] = corporation.NewStub("A", 0, 0)
	corporations[1] = corporation.NewStub("B", 0, 1)
	corporations[2] = corporation.NewStub("C", 1, 2)
	corporations[3] = corporation.NewStub("D", 1, 3)
	corporations[4] = corporation.NewStub("E", 1, 4)
	corporations[5] = corporation.NewStub("F", 2, 5)
	corporations[6] = corporation.NewStub("G", 2, 6)

	board := board.New()
	tileset := tileset.NewStub()
	return players, corporations, board, tileset
}

func slicesSameContent(slice1 []player.ShareInterface, slice2 []player.ShareInterface) bool {
	if len(slice1) != len(slice2) {
		return false
	}
	var inSlice bool
	for _, val1 := range slice1 {
		inSlice = false
		for _, val2 := range slice2 {
			if val1 == val2 {
				inSlice = true
				break
			}
		}
		if !inSlice {
			return false
		}
	}
	return true
}
<commit_msg>Added test cases for FoundCorp<commit_after>package game

import (
	"github.com/svera/acquire/board"
	"github.com/svera/acquire/corporation"
	"github.com/svera/acquire/fsm"
	"github.com/svera/acquire/player"
	"github.com/svera/acquire/tileset"
	"testing"
)

func TestNewGameWrongNumberPlayers(t *testing.T) {
	players, corporations, board, tileset := setup()
	players = players[:1]

	if _, err := New(board, players, corporations, tileset); err.Error() != WrongNumberPlayers {
		t.Errorf("Game must not be created with less than 3 players, got %d", len(players))
	}
}

func TestNewGameNotUniqueCorpIds(t *testing.T) {
	players, corporations, board, tileset := setup()

	corporations[0] = corporation.NewStub("A", 0, 0)
	corporations[1] = corporation.NewStub("B", 0, 0)

	if _, err := New(board, players, corporations, tileset); err.Error() != CorpIdNotUnique {
		t.Errorf("Corporations must have unique values, expecting %s error, got %s", CorpIdNotUnique, err.Error())
	}
}

func TestNewGameWrongNumberOfCorpsPerClass(t *testing.T) {
	players, corporations, board, tileset := setup()

	corporations[2] = corporation.NewStub("C", 0, 2)

	if _, err := New(board, players, corporations, tileset); err.Error() != WrongNumberCorpsClass {
		t.Errorf("Game must catch wrong number of corporations per class")
	}
}

func TestNewGameInitsPlayersTilesets(t *testing.T) {
	players, corporations, board, tileset := setup()
	New(board, players, corporations, tileset)

	for i, player := range players {
		if len(player.Tiles()) != 6 {
			t.Errorf("Players must have 6 tiles at the beginning, player %d got %d", i, len(player.Tiles()))
		}
	}
}

func TestAreEndConditionsReached(t *testing.T) {
	players, corporations, board, tileset := setup()
	game, _ := New(board, players, corporations, tileset)

	if game.AreEndConditionsReached() {
		t.Errorf("End game conditions not reached (no active corporations) but detected as it were")
	}

	corporations[0].(*corporation.Stub).SetSize(41)

	if !game.AreEndConditionsReached() {
		t.Errorf("End game conditions reached (a corporation bigger than 40 tiles) but not detected")
	}

	corporations[0].(*corporation.Stub).SetSize(11)

	if !game.AreEndConditionsReached() {
		t.Errorf("End game conditions reached (all active corporations safe) but not detected")
	}

	corporations[0].(*corporation.Stub).SetSize(11)
	corporations[1].(*corporation.Stub).SetSize(2)

	if game.AreEndConditionsReached() {
		t.Errorf("End game conditions not reached but detected as it were")
	}

}

func TestGetMainStockHolders(t *testing.T) {
	players, corporations, board, tileset := setup()

	players[0].(*player.Stub).SetShares(corporations[0], 8)

	game, _ := New(board, players, corporations, tileset)
	stockHolders := game.GetMainStockHolders(corporations[0])
	expectedStockHolders := map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[0]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there's just one player with stock in a defunct corporation, " +
				"he/she must get both majority and minority bonuses",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[1]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"Wrong main stock holders",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 8)
	players[2].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0], players[1]},
		"minority": {},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there are two or more majority stock holders in a defunct corporation, " +
				"the majority bonus must be splitted between them (no minority bonus given)",
		)
	}

	players[1].(*player.Stub).SetShares(corporations[0], 5)
	players[2].(*player.Stub).SetShares(corporations[0], 5)

	stockHolders = game.GetMainStockHolders(corporations[0])
	expectedStockHolders = map[string][]player.ShareInterface{
		"majority": {players[0]},
		"minority": {players[1], players[2]},
	}
	if !slicesSameContent(stockHolders["majority"], expectedStockHolders["majority"]) ||
		!slicesSameContent(stockHolders["minority"], expectedStockHolders["minority"]) {
		t.Errorf(
			"If there are two or more minority stock holders in a defunct corporation, " +
				"the minority bonus must be splitted between them",
		)
	}

}

func TestPlayTileFoundCorporation(t *testing.T) {
	players, corporations, bd, ts := setup()
	tileToPlay := tileset.Position{Number: 6, Letter: "E"}
	bd.PutTile(tileset.Position{Number: 5, Letter: "E"})

	game, _ := New(bd, players, corporations, ts)
	playerTiles := players[0].Tiles()
	players[0].DiscardTile(playerTiles[0])
	players[0].PickTile(tileToPlay)
	game.PlayTile(tileToPlay)

	if game.state.Name() != "FoundCorp" {
		t.Errorf("Game must be in state FoundCorp, got %s", game.state.Name())
	}
}

func TestFoundCorporation(t *testing.T) {
	players, corporations, bd, ts := setup()
	game, _ := New(bd, players, corporations, ts)
	if err := game.FoundCorporation(corporations[0]); err == nil {
		t.Errorf("Game in a state different than FoundCorp must not execute FoundCorporation()")
	}
	game.state = &fsm.FoundCorp{}
	newCorpTiles := []tileset.Position{
		{Number: 5, Letter: "E"},
		{Number: 6, Letter: "E"},
	}
	game.newCorpTiles = newCorpTiles
	game.FoundCorporation(corporations[0])
	if game.state.Name() != "BuyStock" {
		t.Errorf("Game must be in state BuyStock, got %s", game.state.Name())
	}
	if players[0].Shares(corporations[0]) != 1 {
		t.Errorf("Player must have 1 share of corporation stock, got %d", players[0].Shares(corporations[0]))
	}
	if corporations[0].Size() != 2 {
		t.Errorf("Corporation must have 2 tiles, got %d", corporations[0].Size())
	}
	if game.board.Cell(newCorpTiles[0]) != 0 || game.board.Cell(newCorpTiles[1]) != 0 {
		t.Errorf("Corporation tiles are not set on board")
	}
}

func TestPlayTileGrowCorporation(t *testing.T) {
	players, corporations, bd, ts := setup()
	tileToPlay := tileset.Position{Number: 6, Letter: "E"}
	corpTiles := []tileset.Position{{Number: 7, Letter: "E"}, {Number: 8, Letter: "E"}}
	corporations[0].AddTiles(corpTiles)
	bd.SetTiles(corporations[0], corpTiles)
	bd.PutTile(tileset.Position{Number: 5, Letter: "E"})

	game, _ := New(bd, players, corporations, ts)
	playerTiles := players[0].Tiles()
	players[0].DiscardTile(playerTiles[0])
	players[0].PickTile(tileToPlay)
	game.PlayTile(tileToPlay)

	expectedCorpSize := 4

	if game.state.Name() != "BuyStock" {
		t.Errorf("Game must be in state BuyStock, got %s", game.state.Name())
	}
	if corporations[0].Size() != expectedCorpSize {
		t.Errorf("Corporation size must be %d, got %d", expectedCorpSize, corporations[0].Size())
	}
}

func TestBuyStock(t *testing.T) {
	players, corporations, bd, ts := setup()
	corporations[0].AddTiles(
		[]tileset.Position{
			{Number: 1, Letter: "A"},
			{Number: 2, Letter: "A"},
		},
	)
	buys := map[int]int{0: 2}
	var expectedAvailableStock int = 23
	var expectedPlayerStock int = 2
	game, _ := New(bd, players, corporations, ts)
	game.state = &fsm.BuyStock{}
	game.BuyStock(buys)

	if corporations[0].Stock() != expectedAvailableStock {
		t.Errorf("Corporation stock shares have not decreased, must be %d, got %d", expectedAvailableStock, corporations[0].Stock())
	}
	if players[0].Shares(corporations[0]) != expectedPlayerStock {
		t.Errorf("Player stock shares have not increased, must be %d, got %d", expectedPlayerStock, players[0].Shares(corporations[0]))
	}
}

func TestBuyStockWithNotEnoughCash(t *testing.T) {
	players, corporations, bd, ts := setup()
	players[0].(*player.Stub).SetCash(100)

	corporations[0].AddTiles(
		[]tileset.Position{
			{Number: 1, Letter: "A"},
			{Number: 2, Letter: "A"},
		},
	)

	buys := map[int]int{0: 2}
	game, _ := New(bd, players, corporations, ts)
	err := game.BuyStock(buys)
	if err == nil {
		t.Errorf("Trying to buy stock shares without enough money must throw error")
	}
}

// Testing that if player has an permanently unplayable tile, this is exchanged:
// In the following example, tile 6D is unplayable because it would merge safe
// corporations 0 and 1
//
//    5 6  7 8
// D [0]><[1]
func TestDrawTile(t *testing.T) {
	players, corporations, bd, ts := setup()
	corporations[0].(*corporation.Stub).SetSize(11)
	corporations[1].(*corporation.Stub).SetSize(15)
	unplayableTile := tileset.Position{Number: 6, Letter: "D"}
	bd.SetTiles(corporations[0], []tileset.Position{{Number: 5, Letter: "D"}})
	bd.SetTiles(corporations[1], []tileset.Position{{Number: 7, Letter: "D"}})

	game, _ := New(bd, players, corporations, ts)
	players[0].(*player.Stub).SetTiles([]tileset.Position{unplayableTile})
	game.tileset.(*tileset.Stub).DiscardTile(unplayableTile)
	game.state = &fsm.BuyStock{}
	game.drawTile()
	for _, tile := range players[0].Tiles() {
		if tile.Number == unplayableTile.Number && tile.Letter == unplayableTile.Letter {
			t.Errorf("Unplayable tile not discarded after drawing new tile, got %v", players[0].Tiles())
		}
	}
}

func setup() ([]player.Interface, [7]corporation.Interface, board.Interface, tileset.Interface) {
	var players []player.Interface
	players = append(players, player.NewStub("Test1"))
	players = append(players, player.NewStub("Test2"))
	players = append(players, player.NewStub("Test3"))

	var corporations [7]corporation.Interface
	corporations[0] = corporation.NewStub("A", 0, 0)
	corporations[1] = corporation.NewStub("B", 0, 1)
	corporations[2] = corporation.NewStub("C", 1, 2)
	corporations[3] = corporation.NewStub("D", 1, 3)
	corporations[4] = corporation.NewStub("E", 1, 4)
	corporations[5] = corporation.NewStub("F", 2, 5)
	corporations[6] = corporation.NewStub("G", 2, 6)

	board := board.New()
	tileset := tileset.NewStub()
	return players, corporations, board, tileset
}

func slicesSameContent(slice1 []player.ShareInterface, slice2 []player.ShareInterface) bool {
	if len(slice1) != len(slice2) {
		return false
	}
	var inSlice bool
	for _, val1 := range slice1 {
		inSlice = false
		for _, val2 := range slice2 {
			if val1 == val2 {
				inSlice = true
				break
			}
		}
		if !inSlice {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/vault/sdk/helper/consts"
	"github.com/hashicorp/vault/sdk/helper/parseutil"
	"github.com/hashicorp/vault/sdk/version"
	"github.com/hashicorp/vault/vault"
)

func handleSysHealth(core *vault.Core) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			handleSysHealthGet(core, w, r)
		case "HEAD":
			handleSysHealthHead(core, w, r)
		default:
			respondError(w, http.StatusMethodNotAllowed, nil)
		}
	})
}

func fetchStatusCode(r *http.Request, field string) (int, bool, bool) {
	var err error
	statusCode := http.StatusOK
	if statusCodeStr, statusCodeOk := r.URL.Query()[field]; statusCodeOk {
		statusCode, err = strconv.Atoi(statusCodeStr[0])
		if err != nil || len(statusCodeStr) < 1 {
			return http.StatusBadRequest, false, false
		}
		return statusCode, true, true
	}
	return statusCode, false, true
}

func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) {
	code, body, err := getSysHealth(core, r)

	if err != nil {
		core.Logger().Error("error checking health", "error", err)
		respondError(w, code, nil)
		return
	}

	if body == nil {
		respondError(w, code, nil)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)

	// Generate the response
	enc := json.NewEncoder(w)
	enc.Encode(body)
}

func handleSysHealthHead(core *vault.Core, w http.ResponseWriter, r *http.Request) {
	code, body, _ := getSysHealth(core, r)

	if body != nil {
		w.Header().Set("Content-Type", "application/json")
	}
	w.WriteHeader(code)
}

func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, error) {
	var err error

	// Check if being a standby is allowed for the purpose of a 200 OK
	standbyOKStr, standbyOK := r.URL.Query()["standbyok"]
	if standbyOK {
		standbyOK, err = parseutil.ParseBool(standbyOKStr[0])
		if err != nil {
			return http.StatusBadRequest, nil, errwrap.Wrapf("bad value for standbyok parameter: {{err}}", err)
		}
	}
	perfStandbyOKStr, perfStandbyOK := r.URL.Query()["perfstandbyok"]
	if perfStandbyOK {
		perfStandbyOK, err = parseutil.ParseBool(perfStandbyOKStr[0])
		if err != nil {
			return http.StatusBadRequest, nil, errwrap.Wrapf("bad value for perfstandbyok parameter: {{err}}", err)
		}
	}

	uninitCode := http.StatusNotImplemented
	if code, found, ok := fetchStatusCode(r, "uninitcode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		uninitCode = code
	}

	sealedCode := http.StatusServiceUnavailable
	if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		sealedCode = code
	}

	standbyCode := http.StatusTooManyRequests // Consul warning code
	if code, found, ok := fetchStatusCode(r, "standbycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		standbyCode = code
	}

	activeCode := http.StatusOK
	if code, found, ok := fetchStatusCode(r, "activecode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		activeCode = code
	}

	drSecondaryCode := 472 // unofficial 4xx status code
	if code, found, ok := fetchStatusCode(r, "drsecondarycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		drSecondaryCode = code
	}

	perfStandbyCode := 473 // unofficial 4xx status code
	if code, found, ok := fetchStatusCode(r, "performancestandbycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		perfStandbyCode = code
	}

	ctx := context.Background()

	// Check system status
	sealed := core.Sealed()
	standby, perfStandby := core.HealthParams()
	var replicationState consts.ReplicationState
	if standby {
		replicationState = core.ActiveNodeReplicationState()
	} else {
		replicationState = core.ReplicationState()
	}

	init, err := core.Initialized(ctx)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// Determine the status code
	code := activeCode
	switch {
	case !init:
		code = uninitCode
	case sealed:
		code = sealedCode
	case replicationState.HasState(consts.ReplicationDRSecondary):
		code = drSecondaryCode
	case perfStandby:
		if !perfStandbyOK {
			code = perfStandbyCode
		}
	case standby:
		if !standbyOK {
			code = standbyCode
		}
	}

	// Fetch the local cluster name and identifier
	var clusterName, clusterID string
	if !sealed {
		cluster, err := core.Cluster(ctx)
		if err != nil {
			return http.StatusInternalServerError, nil, err
		}
		if cluster == nil {
			return http.StatusInternalServerError, nil, fmt.Errorf("failed to fetch cluster details")
		}
		clusterName = cluster.Name
		clusterID = cluster.ID
	}

	// Format the body
	body := &HealthResponse{
		Initialized:                init,
		Sealed:                     sealed,
		Standby:                    standby,
		PerformanceStandby:         perfStandby,
		ReplicationPerformanceMode: replicationState.GetPerformanceString(),
		ReplicationDRMode:          replicationState.GetDRString(),
		ServerTimeUTC:              time.Now().UTC().Unix(),
		Version:                    version.GetVersion().VersionNumber(),
		ClusterName:                clusterName,
		ClusterID:                  clusterID,
	}

	if init && !sealed && !standby {
		body.LastWAL = vault.LastWAL(core)
	}

	return code, body, nil
}

type HealthResponse struct {
	Initialized                bool   `json:"initialized"`
	Sealed                     bool   `json:"sealed"`
	Standby                    bool   `json:"standby"`
	PerformanceStandby         bool   `json:"performance_standby"`
	ReplicationPerformanceMode string `json:"replication_performance_mode"`
	ReplicationDRMode          string `json:"replication_dr_mode"`
	ServerTimeUTC              int64  `json:"server_time_utc"`
	Version                    string `json:"version"`
	ClusterName                string `json:"cluster_name,omitempty"`
	ClusterID                  string `json:"cluster_id,omitempty"`
	LastWAL                    uint64 `json:"last_wal,omitempty"`
}
<commit_msg>Fix build<commit_after>package http

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/vault/sdk/helper/consts"
	"github.com/hashicorp/vault/sdk/helper/parseutil"
	"github.com/hashicorp/vault/sdk/version"
	"github.com/hashicorp/vault/vault"
)

func handleSysHealth(core *vault.Core) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case "GET":
			handleSysHealthGet(core, w, r)
		case "HEAD":
			handleSysHealthHead(core, w, r)
		default:
			respondError(w, http.StatusMethodNotAllowed, nil)
		}
	})
}

func fetchStatusCode(r *http.Request, field string) (int, bool, bool) {
	var err error
	statusCode := http.StatusOK
	if statusCodeStr, statusCodeOk := r.URL.Query()[field]; statusCodeOk {
		statusCode, err = strconv.Atoi(statusCodeStr[0])
		if err != nil || len(statusCodeStr) < 1 {
			return http.StatusBadRequest, false, false
		}
		return statusCode, true, true
	}
	return statusCode, false, true
}

func handleSysHealthGet(core *vault.Core, w http.ResponseWriter, r *http.Request) {
	code, body, err := getSysHealth(core, r)

	if err != nil {
		core.Logger().Error("error checking health", "error", err)
		respondError(w, code, nil)
		return
	}

	if body == nil {
		respondError(w, code, nil)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)

	// Generate the response
	enc := json.NewEncoder(w)
	enc.Encode(body)
}

func handleSysHealthHead(core *vault.Core, w http.ResponseWriter, r *http.Request) {
	code, body, _ := getSysHealth(core, r)

	if body != nil {
		w.Header().Set("Content-Type", "application/json")
	}
	w.WriteHeader(code)
}

func getSysHealth(core *vault.Core, r *http.Request) (int, *HealthResponse, error) {
	var err error

	// Check if being a standby is allowed for the purpose of a 200 OK
	standbyOKStr, standbyOK := r.URL.Query()["standbyok"]
	if standbyOK {
		standbyOK, err = parseutil.ParseBool(standbyOKStr[0])
		if err != nil {
			return http.StatusBadRequest, nil, errwrap.Wrapf("bad value for standbyok parameter: {{err}}", err)
		}
	}
	perfStandbyOKStr, perfStandbyOK := r.URL.Query()["perfstandbyok"]
	if perfStandbyOK {
		perfStandbyOK, err = parseutil.ParseBool(perfStandbyOKStr[0])
		if err != nil {
			return http.StatusBadRequest, nil, errwrap.Wrapf("bad value for perfstandbyok parameter: {{err}}", err)
		}
	}

	uninitCode := http.StatusNotImplemented
	if code, found, ok := fetchStatusCode(r, "uninitcode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		uninitCode = code
	}

	sealedCode := http.StatusServiceUnavailable
	if code, found, ok := fetchStatusCode(r, "sealedcode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		sealedCode = code
	}

	standbyCode := http.StatusTooManyRequests // Consul warning code
	if code, found, ok := fetchStatusCode(r, "standbycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		standbyCode = code
	}

	activeCode := http.StatusOK
	if code, found, ok := fetchStatusCode(r, "activecode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		activeCode = code
	}

	drSecondaryCode := 472 // unofficial 4xx status code
	if code, found, ok := fetchStatusCode(r, "drsecondarycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		drSecondaryCode = code
	}

	perfStandbyCode := 473 // unofficial 4xx status code
	if code, found, ok := fetchStatusCode(r, "performancestandbycode"); !ok {
		return http.StatusBadRequest, nil, nil
	} else if found {
		perfStandbyCode = code
	}

	ctx := context.Background()

	// Check system status
	sealed := core.Sealed()
	standby, perfStandby := core.StandbyStates()
	var replicationState consts.ReplicationState
	if standby {
		replicationState = core.ActiveNodeReplicationState()
	} else {
		replicationState = core.ReplicationState()
	}

	init, err := core.Initialized(ctx)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// Determine the status code
	code := activeCode
	switch {
	case !init:
		code = uninitCode
	case sealed:
		code = sealedCode
	case replicationState.HasState(consts.ReplicationDRSecondary):
		code = drSecondaryCode
	case perfStandby:
		if !perfStandbyOK {
			code = perfStandbyCode
		}
	case standby:
		if !standbyOK {
			code = standbyCode
		}
	}

	// Fetch the local cluster name and identifier
	var clusterName, clusterID string
	if !sealed {
		cluster, err := core.Cluster(ctx)
		if err != nil {
			return http.StatusInternalServerError, nil, err
		}
		if cluster == nil {
			return http.StatusInternalServerError, nil, fmt.Errorf("failed to fetch cluster details")
		}
		clusterName = cluster.Name
		clusterID = cluster.ID
	}

	// Format the body
	body := &HealthResponse{
		Initialized:                init,
		Sealed:                     sealed,
		Standby:                    standby,
		PerformanceStandby:         perfStandby,
		ReplicationPerformanceMode: replicationState.GetPerformanceString(),
		ReplicationDRMode:          replicationState.GetDRString(),
		ServerTimeUTC:              time.Now().UTC().Unix(),
		Version:                    version.GetVersion().VersionNumber(),
		ClusterName:                clusterName,
		ClusterID:                  clusterID,
	}

	if init && !sealed && !standby {
		body.LastWAL = vault.LastWAL(core)
	}

	return code, body, nil
}

type HealthResponse struct {
	Initialized                bool   `json:"initialized"`
	Sealed                     bool   `json:"sealed"`
	Standby                    bool   `json:"standby"`
	PerformanceStandby         bool   `json:"performance_standby"`
	ReplicationPerformanceMode string `json:"replication_performance_mode"`
	ReplicationDRMode          string `json:"replication_dr_mode"`
	ServerTimeUTC              int64  `json:"server_time_utc"`
	Version                    string `json:"version"`
	ClusterName                string `json:"cluster_name,omitempty"`
	ClusterID                  string `json:"cluster_id,omitempty"`
	LastWAL                    uint64 `json:"last_wal,omitempty"`
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

package gcs

import (
	"io"
	"log"
	"math/rand"
	"net"
	"net/url"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
)

// A bucket that wraps another, calling its methods in a retry loop with
// randomized exponential backoff.
type retryBucket struct {
	maxSleep time.Duration
	wrapped  Bucket
}

func newRetryBucket(
	maxSleep time.Duration,
	wrapped Bucket) (b Bucket) {
	b = &retryBucket{
		maxSleep: maxSleep,
		wrapped:  wrapped,
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func shouldRetry(err error) (b bool) {
	// HTTP 50x errors.
	if typed, ok := err.(*googleapi.Error); ok {
		if typed.Code >= 500 && typed.Code < 600 {
			b = true
			return
		}
	}

	// Network errors, which tend to show up transiently when doing lots of
	// operations in parallel. For example:
	//
	//     dial tcp 74.125.203.95:443: too many open files
	//
	if _, ok := err.(*net.OpError); ok {
		b = true
		return
	}

	// Sometimes the HTTP package helpfully encapsulates the real error in a URL
	// error.
	if urlErr, ok := err.(*url.Error); ok {
		b = shouldRetry(urlErr.Err)
		return
	}

	return
}

// Exponential backoff for a function that might fail.
//
// This is essentially what is described in the "Best practices" section of the
// "Upload Objects" docs:
//
//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
//
// with the following exceptions:
//
//  *  We perform backoff for all operations.
//
//  *  The random component scales with the delay, so that the first sleep
//     cannot be as long as one second. The algorithm used matches the
//     description at http://en.wikipedia.org/wiki/Exponential_backoff.
//
func expBackoff(
	ctx context.Context,
	maxSleep time.Duration,
	f func() error) (err error) {
	const baseDelay = time.Millisecond
	var totalSleep time.Duration

	for n := uint(0); ; n++ {
		// Make an attempt. Stop if successful.
		err = f()
		if err == nil {
			return
		}

		// Do we want to retry?
		if !shouldRetry(err) {
			log.Printf(
				"Not retrying error of type %T (%q): %#v",
				err,
				err.Error(),
				err)

			return
		}

		// Choose a a delay in [0, 2^n * baseDelay).
		d := (1 << n) * baseDelay
		d = time.Duration(float64(d) * rand.Float64())

		// Are we out of credit?
		if totalSleep+d > maxSleep {
			// Return the most recent error.
			return
		}

		// Sleep, returning early if cancelled.
		log.Printf("Retrying after error of type %T (%q) in %v", err, err, d)

		select {
		case <-ctx.Done():
			err = ctx.Err()
			return

		case <-time.After(d):
			totalSleep += d
			continue
		}
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (rb *retryBucket) Name() (name string) {
	name = rb.wrapped.Name()
	return
}

func (rb *retryBucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			rc, err = rb.wrapped.NewReader(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.CreateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.StatObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			listing, err = rb.wrapped.ListObjects(ctx, req)
			return
		})
	return
}

func (rb *retryBucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.UpdateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			err = rb.wrapped.DeleteObject(ctx, name)
			return
		})

	return
}
<commit_msg>Retry on HTTP 429, too.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

package gcs

import (
	"io"
	"log"
	"math/rand"
	"net"
	"net/url"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
)

// A bucket that wraps another, calling its methods in a retry loop with
// randomized exponential backoff.
type retryBucket struct {
	maxSleep time.Duration
	wrapped  Bucket
}

func newRetryBucket(
	maxSleep time.Duration,
	wrapped Bucket) (b Bucket) {
	b = &retryBucket{
		maxSleep: maxSleep,
		wrapped:  wrapped,
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func shouldRetry(err error) (b bool) {
	// HTTP 50x errors.
	if typed, ok := err.(*googleapi.Error); ok {
		if typed.Code >= 500 && typed.Code < 600 {
			b = true
			return
		}
	}

	// HTTP 429 errors (GCS uses these for rate limiting).
	if typed, ok := err.(*googleapi.Error); ok {
		if typed.Code == 429 {
			b = true
			return
		}
	}

	// Network errors, which tend to show up transiently when doing lots of
	// operations in parallel. For example:
	//
	//     dial tcp 74.125.203.95:443: too many open files
	//
	if _, ok := err.(*net.OpError); ok {
		b = true
		return
	}

	// Sometimes the HTTP package helpfully encapsulates the real error in a URL
	// error.
	if urlErr, ok := err.(*url.Error); ok {
		b = shouldRetry(urlErr.Err)
		return
	}

	return
}

// Exponential backoff for a function that might fail.
//
// This is essentially what is described in the "Best practices" section of the
// "Upload Objects" docs:
//
//     https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload
//
// with the following exceptions:
//
//  *  We perform backoff for all operations.
//
//  *  The random component scales with the delay, so that the first sleep
//     cannot be as long as one second. The algorithm used matches the
//     description at http://en.wikipedia.org/wiki/Exponential_backoff.
//
//  *  We retry more types of errors; see shouldRetry above.
//
func expBackoff(
	ctx context.Context,
	maxSleep time.Duration,
	f func() error) (err error) {
	const baseDelay = time.Millisecond
	var totalSleep time.Duration

	for n := uint(0); ; n++ {
		// Make an attempt. Stop if successful.
		err = f()
		if err == nil {
			return
		}

		// Do we want to retry?
		if !shouldRetry(err) {
			log.Printf(
				"Not retrying error of type %T (%q): %#v",
				err,
				err.Error(),
				err)

			return
		}

		// Choose a a delay in [0, 2^n * baseDelay).
		d := (1 << n) * baseDelay
		d = time.Duration(float64(d) * rand.Float64())

		// Are we out of credit?
		if totalSleep+d > maxSleep {
			// Return the most recent error.
			return
		}

		// Sleep, returning early if cancelled.
		log.Printf("Retrying after error of type %T (%q) in %v", err, err, d)

		select {
		case <-ctx.Done():
			err = ctx.Err()
			return

		case <-time.After(d):
			totalSleep += d
			continue
		}
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (rb *retryBucket) Name() (name string) {
	name = rb.wrapped.Name()
	return
}

func (rb *retryBucket) NewReader(
	ctx context.Context,
	req *ReadObjectRequest) (rc io.ReadCloser, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			rc, err = rb.wrapped.NewReader(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.CreateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) StatObject(
	ctx context.Context,
	req *StatObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.StatObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) ListObjects(
	ctx context.Context,
	req *ListObjectsRequest) (listing *Listing, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			listing, err = rb.wrapped.ListObjects(ctx, req)
			return
		})
	return
}

func (rb *retryBucket) UpdateObject(
	ctx context.Context,
	req *UpdateObjectRequest) (o *Object, err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			o, err = rb.wrapped.UpdateObject(ctx, req)
			return
		})

	return
}

func (rb *retryBucket) DeleteObject(
	ctx context.Context,
	name string) (err error) {
	err = expBackoff(
		ctx,
		rb.maxSleep,
		func() (err error) {
			err = rb.wrapped.DeleteObject(ctx, name)
			return
		})

	return
}
<|endoftext|>


<commit_before>package gosom

import "math"

// A DistanceFunction calculates and returns the distance between to points.
type DistanceFunction func(from, to []float64) (distance float64)

// A CoolingFunction returns the cooling alpha [1..0] for an input value [0..1].
type CoolingFunction func(input float64) (output float64)

// A NeighborhoodFunction returns the influence [1..0] of a distance [0..1].
type NeighborhoodFunction func(distance float64) (influence float64)

func EuclideanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += (from[i] - to[i]) * (from[i] - to[i])
	}

	return math.Sqrt(d)
}

func ManhattanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += math.Abs(to[i]- from[i])
	}

	return d
}

func LinearCooling(input float64) (output float64) {
	return 1.0 - input
}

func SoftCooling(input float64) (output float64) {
	d := -math.Log(0.2 / 1.2)
	return (1.2 * math.Exp(-input * d)) - 0.2
}

func MediumCooling(input float64) (output float64) {
	return 1.005 * math.Pow(0.005 / 1.0, input) - 0.005
}

func HardCooling(input float64) (output float64) {
	d := 1.0 / 101.0
	return (1.0 + d) / (1 + 100 * input) - d
}

func BubbleNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return 1.0
	} else {
		return 0.0
	}
}

func ConeNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return (1.0 - d) / 1.0
	} else {
		return 0.0
	}
}

func GaussianNeighborhood(distance float64) (influence float64) {
	stdDev := 5.5
	norm := (2.0 * math.Pow(2.0, 2.0)) / math.Pow(stdDev, 2.0)
	return math.Exp((-distance * distance) / norm)
}

func MexicanHatNeighborhood(distance float64) (influence float64) {
	norm := 3.0 / (2.0)
	square := math.Pow(distance * norm, 2.0)
	return (1.0 - square) * math.Exp(-square)
}
<commit_msg>corrected<commit_after>package gosom

import "math"

// A DistanceFunction calculates and returns the distance between to points.
type DistanceFunction func(from, to []float64) (distance float64)

// A CoolingFunction returns the cooling alpha [1..0] for an input value [0..1].
type CoolingFunction func(input float64) (output float64)

// A NeighborhoodFunction returns the influence [1..0] of a distance [0..1].
type NeighborhoodFunction func(distance float64) (influence float64)

func EuclideanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += (from[i] - to[i]) * (from[i] - to[i])
	}

	return math.Sqrt(d)
}

func ManhattanDistance(from, to []float64) (distance float64) {
	d := 0.0
	l := Min(len(from), len(to))

	for i:=0; i<l; i++ {
		d += math.Abs(to[i]- from[i])
	}

	return d
}

func LinearCooling(input float64) (output float64) {
	return 1.0 - input
}

func SoftCooling(input float64) (output float64) {
	d := -math.Log(0.2 / 1.2)
	return (1.2 * math.Exp(-input * d)) - 0.2
}

func MediumCooling(input float64) (output float64) {
	return 1.005 * math.Pow(0.005 / 1.0, input) - 0.005
}

func HardCooling(input float64) (output float64) {
	d := 1.0 / 101.0
	return (1.0 + d) / (1 + 100 * input) - d
}

func BubbleNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return 1.0
	} else {
		return 0.0
	}
}

func ConeNeighborhood(distance float64) (influence float64) {
	d := math.Abs(distance)

	if d < 1.0 {
		return (1.0 - d) / 1.0
	} else {
		return 0.0
	}
}

func GaussianNeighborhood(distance float64) (influence float64) {
	stdDev := 5.5
	norm := (2.0 * math.Pow(2.0, 2.0)) / math.Pow(stdDev, 2.0)
	return math.Exp((-distance * distance) / norm)
}

func MexicanHatNeighborhood(distance float64) (influence float64) {
	norm := 3.0 / 2.0
	square := math.Pow(distance * norm, 2.0)
	return (1.0 - square) * math.Exp(-square)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2017, AverageSecurityGuy
# All rights reserved.

Demonstrate function usage in Go

Usage:

$ go run functions.go string
*/

package main

import (
    "os"
    "fmt"
)

// Declare a function that takes two parameters and does not return a value.
// The variable is declared before the type. Variables of the same type can be
// declared at the same time before stating the type:
// func some_func(a, b, c string, i, j int)
func write_string(s string, n int) {
    for i := 0; i < n; i++ {
        fmt.Println(s)
    }
}

// Declare a function that takes a string and returns a boolean value.
func short_string(s string) bool {
    return len(s) < 5
}

// Declare a function that returns two values. You can return as many value as
// needed by placing them in the comma delimited return list.
func test_string(s string) (int, bool) {
    l := len(s)
    return l, l < 5
}

func main() {

    // Check the number of arguments we have. The name of the script is the
    // first argument.
    if len(os.Args) != 2 {

        // If we don't have the correct number of arguments then print a
        // message. Println will automatically add a newline at the end of the
        // string. Always use double quotes for strings, single quotes have a
        // different meaning, which we are not going to discuss.
        fmt.Println("Usage: go run functions.go string")

        // Exit the program
        os.Exit(1)
    }

    // Declare and assign a variable. The alternative is to do it in two steps:
    // var str string
    // str = os.Args[1]
    str := os.Args[1]

    // Call a function with two parameters.
    write_string(str, 10)

    // Call a function and catch the return value.
    ans := short_string(str)
    if ans == true {
        fmt.Println("String is short")
    } else {
        fmt.Println("String is not short")
    }

    // Call a function and get both return values. If you don't need all of the
    // return values from a function, you can throw away the return values you
    // do not want or need. using an underscore:
    // _, b := test_string(str)
    n, b := test_string(str)
    if b == true {
        fmt.Printf("The string is short: %d characters.\n", n)
    } else {
        fmt.Printf("The string is not short: %d characters.\n", n)
    }
}
<commit_msg>Day 2<commit_after>/*
Copyright (c) 2017, AverageSecurityGuy
# All rights reserved.

Demonstrate function usage in Go

Usage:

$ go run functions.go string
*/

package main

import (
	"fmt"
	"os"
)

// Declare a function that takes two parameters and does not return a value.
// The variable is declared before the type. Variables of the same type can be
// declared at the same time before stating the type:
// func some_func(a, b, c string, i, j int)
func write_string(s string, n int) {
	for i := 0; i < n; i++ {
		fmt.Println(s)
	}
}

// Declare a function that takes a string and returns a boolean value.
func short_string(s string) bool {
	return len(s) < 5
}

// Declare a function that returns two values. You can return as many value as
// needed by placing them in the comma delimited return list.
func test_string(s string) (int, bool) {
	l := len(s)
	return l, l < 5
}

func main() {

	// Check the number of arguments we have. The name of the script is the
	// first argument.
	if len(os.Args) != 2 {

		// If we don't have the correct number of arguments then print a
		// message. Println will automatically add a newline at the end of the
		// string. Always use double quotes for strings, single quotes have a
		// different meaning, which we are not going to discuss.
		fmt.Println("Usage: go run functions.go string")

		// Exit the program
		os.Exit(1)
	}

	// Declare and assign a variable. The alternative is to do it in two steps:
	// var str string
	// str = os.Args[1]
	str := os.Args[1]

	// Call a function with two parameters.
	write_string(str, 10)

	// Call a function and catch the return value.
	ans := short_string(str)
	if ans == true {
		fmt.Println("String is short")
	} else {
		fmt.Println("String is not short")
	}

	// Call a function and get both return values. If you don't need all of the
	// return values from a function, you can throw away the return values you
	// do not want or need. using an underscore:
	// _, b := test_string(str)
	n, b := test_string(str)
	if b == true {
		fmt.Printf("The string is short: %d characters.\n", n)
	} else {
		fmt.Printf("The string is not short: %d characters.\n", n)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, Inc.
//
// 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.

package capnslog

import (
	"fmt"
	"os"
)

type PackageLogger struct {
	pkg   string
	level LogLevel
}

const calldepth = 2

func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...interface{}) {
	logger.Lock()
	defer logger.Unlock()
	if inLevel != CRITICAL && p.level < inLevel {
		return
	}
	if logger.formatter != nil {
		logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
	}
}

func (p *PackageLogger) LevelAt(l LogLevel) bool {
	logger.Lock()
	defer logger.Unlock()
	return p.level >= l
}

// Log a formatted string at any level between ERROR and TRACE
func (p *PackageLogger) Logf(l LogLevel, format string, args ...interface{}) {
	p.internalLog(calldepth, l, fmt.Sprintf(format, args...))
}

// Log a message at any level between ERROR and TRACE
func (p *PackageLogger) Log(l LogLevel, args ...interface{}) {
	p.internalLog(calldepth, l, fmt.Sprint(args...))
}

// log stdlib compatibility

func (p *PackageLogger) Println(args ...interface{}) {
	p.internalLog(calldepth, INFO, fmt.Sprintln(args...))
}

func (p *PackageLogger) Printf(format string, args ...interface{}) {
	p.Logf(INFO, format, args...)
}

func (p *PackageLogger) Print(args ...interface{}) {
	p.internalLog(calldepth, INFO, fmt.Sprint(args...))
}

// Panic and fatal

func (p *PackageLogger) Panicf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Panic(args ...interface{}) {
	s := fmt.Sprint(args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Panicln(args ...interface{}) {
	s := fmt.Sprintln(args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
	p.Logf(CRITICAL, format, args...)
	os.Exit(1)
}

func (p *PackageLogger) Fatal(args ...interface{}) {
	s := fmt.Sprint(args...)
	p.internalLog(calldepth, CRITICAL, s)
	os.Exit(1)
}

func (p *PackageLogger) Fatalln(args ...interface{}) {
	s := fmt.Sprintln(args...)
	p.internalLog(calldepth, CRITICAL, s)
	os.Exit(1)
}

// Error Functions

func (p *PackageLogger) Errorf(format string, args ...interface{}) {
	p.Logf(ERROR, format, args...)
}

func (p *PackageLogger) Error(entries ...interface{}) {
	p.internalLog(calldepth, ERROR, entries...)
}

// Warning Functions

func (p *PackageLogger) Warningf(format string, args ...interface{}) {
	p.Logf(WARNING, format, args...)
}

func (p *PackageLogger) Warning(entries ...interface{}) {
	p.internalLog(calldepth, WARNING, entries...)
}

// Notice Functions

func (p *PackageLogger) Noticef(format string, args ...interface{}) {
	p.Logf(NOTICE, format, args...)
}

func (p *PackageLogger) Notice(entries ...interface{}) {
	p.internalLog(calldepth, NOTICE, entries...)
}

// Info Functions

func (p *PackageLogger) Infof(format string, args ...interface{}) {
	p.Logf(INFO, format, args...)
}

func (p *PackageLogger) Info(entries ...interface{}) {
	p.internalLog(calldepth, INFO, entries...)
}

// Debug Functions

func (p *PackageLogger) Debugf(format string, args ...interface{}) {
	if p.level < DEBUG {
		return
	}
	p.Logf(DEBUG, format, args...)
}

func (p *PackageLogger) Debug(entries ...interface{}) {
	if p.level < DEBUG {
		return
	}
	p.internalLog(calldepth, DEBUG, entries...)
}

// Trace Functions

func (p *PackageLogger) Tracef(format string, args ...interface{}) {
	if p.level < TRACE {
		return
	}
	p.Logf(TRACE, format, args...)
}

func (p *PackageLogger) Trace(entries ...interface{}) {
	if p.level < TRACE {
		return
	}
	p.internalLog(calldepth, TRACE, entries...)
}

func (p *PackageLogger) Flush() {
	logger.Lock()
	defer logger.Unlock()
	logger.formatter.Flush()
}
<commit_msg>capnslog: allow to set PackageLogger level<commit_after>// Copyright 2015 CoreOS, Inc.
//
// 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.

package capnslog

import (
	"fmt"
	"os"
)

type PackageLogger struct {
	pkg   string
	level LogLevel
}

const calldepth = 2

func (p *PackageLogger) internalLog(depth int, inLevel LogLevel, entries ...interface{}) {
	logger.Lock()
	defer logger.Unlock()
	if inLevel != CRITICAL && p.level < inLevel {
		return
	}
	if logger.formatter != nil {
		logger.formatter.Format(p.pkg, inLevel, depth+1, entries...)
	}
}

// SetLevel allows users to change the current logging level.
func (p *PackageLogger) SetLevel(l LogLevel) {
	logger.Lock()
	defer logger.Unlock()
	p.level = l
}

// LevelAt checks if the given log level will be outputted under current setting.
func (p *PackageLogger) LevelAt(l LogLevel) bool {
	logger.Lock()
	defer logger.Unlock()
	return p.level >= l
}

// Log a formatted string at any level between ERROR and TRACE
func (p *PackageLogger) Logf(l LogLevel, format string, args ...interface{}) {
	p.internalLog(calldepth, l, fmt.Sprintf(format, args...))
}

// Log a message at any level between ERROR and TRACE
func (p *PackageLogger) Log(l LogLevel, args ...interface{}) {
	p.internalLog(calldepth, l, fmt.Sprint(args...))
}

// log stdlib compatibility

func (p *PackageLogger) Println(args ...interface{}) {
	p.internalLog(calldepth, INFO, fmt.Sprintln(args...))
}

func (p *PackageLogger) Printf(format string, args ...interface{}) {
	p.Logf(INFO, format, args...)
}

func (p *PackageLogger) Print(args ...interface{}) {
	p.internalLog(calldepth, INFO, fmt.Sprint(args...))
}

// Panic and fatal

func (p *PackageLogger) Panicf(format string, args ...interface{}) {
	s := fmt.Sprintf(format, args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Panic(args ...interface{}) {
	s := fmt.Sprint(args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Panicln(args ...interface{}) {
	s := fmt.Sprintln(args...)
	p.internalLog(calldepth, CRITICAL, s)
	panic(s)
}

func (p *PackageLogger) Fatalf(format string, args ...interface{}) {
	p.Logf(CRITICAL, format, args...)
	os.Exit(1)
}

func (p *PackageLogger) Fatal(args ...interface{}) {
	s := fmt.Sprint(args...)
	p.internalLog(calldepth, CRITICAL, s)
	os.Exit(1)
}

func (p *PackageLogger) Fatalln(args ...interface{}) {
	s := fmt.Sprintln(args...)
	p.internalLog(calldepth, CRITICAL, s)
	os.Exit(1)
}

// Error Functions

func (p *PackageLogger) Errorf(format string, args ...interface{}) {
	p.Logf(ERROR, format, args...)
}

func (p *PackageLogger) Error(entries ...interface{}) {
	p.internalLog(calldepth, ERROR, entries...)
}

// Warning Functions

func (p *PackageLogger) Warningf(format string, args ...interface{}) {
	p.Logf(WARNING, format, args...)
}

func (p *PackageLogger) Warning(entries ...interface{}) {
	p.internalLog(calldepth, WARNING, entries...)
}

// Notice Functions

func (p *PackageLogger) Noticef(format string, args ...interface{}) {
	p.Logf(NOTICE, format, args...)
}

func (p *PackageLogger) Notice(entries ...interface{}) {
	p.internalLog(calldepth, NOTICE, entries...)
}

// Info Functions

func (p *PackageLogger) Infof(format string, args ...interface{}) {
	p.Logf(INFO, format, args...)
}

func (p *PackageLogger) Info(entries ...interface{}) {
	p.internalLog(calldepth, INFO, entries...)
}

// Debug Functions

func (p *PackageLogger) Debugf(format string, args ...interface{}) {
	if p.level < DEBUG {
		return
	}
	p.Logf(DEBUG, format, args...)
}

func (p *PackageLogger) Debug(entries ...interface{}) {
	if p.level < DEBUG {
		return
	}
	p.internalLog(calldepth, DEBUG, entries...)
}

// Trace Functions

func (p *PackageLogger) Tracef(format string, args ...interface{}) {
	if p.level < TRACE {
		return
	}
	p.Logf(TRACE, format, args...)
}

func (p *PackageLogger) Trace(entries ...interface{}) {
	if p.level < TRACE {
		return
	}
	p.internalLog(calldepth, TRACE, entries...)
}

func (p *PackageLogger) Flush() {
	logger.Lock()
	defer logger.Unlock()
	logger.formatter.Flush()
}
<|endoftext|>


<commit_before>package tabletserver

import (
	"time"

	"github.com/youtube/vitess/go/vt/servenv"
)

// This file contains the status web page export for tabletserver

var queryserviceStatusTemplate = `

State: {{.State}}

Queryservice History

    Time
    Target Tablet Type
    Serving State

  {{range .History}}

    {{.Time.Format "Jan 2, 2006 at 15:04:05 (MST)"}}
    {{.TabletType}}
    {{.ServingState}}

  {{end}}

QPS: {{.CurrentQPS}}

`

type queryserviceStatus struct {
	State      string
	History    []interface{}
	CurrentQPS float64
}

// AddStatusPart registers the status part for the status page.
func (tsv *TabletServer) AddStatusPart() {
	servenv.AddStatusPart("Queryservice", queryserviceStatusTemplate, func() interface{} {
		status := queryserviceStatus{
			State:   tsv.GetState(),
			History: tsv.history.Records(),
		}
		rates := tsv.qe.queryServiceStats.QPSRates.Get()
		if qps, ok := rates["All"]; ok && len(qps) > 0 {
			status.CurrentQPS = qps[0]
		}
		return status
	})
}

type historyRecord struct {
	Time         time.Time
	TabletType   string
	ServingState string
}

// IsDuplicate implements history.Deduplicable
func (r *historyRecord) IsDuplicate(other interface{}) bool {
	rother, ok := other.(*historyRecord)
	if !ok {
		return false
	}
	return r.TabletType == rother.TabletType && r.ServingState == rother.ServingState
}
<commit_msg>tabletserver: Status page: Add comment that the QPS placeholder text will be replaced by the JavaScript graph.<commit_after>package tabletserver

import (
	"time"

	"github.com/youtube/vitess/go/vt/servenv"
)

// This file contains the status web page export for tabletserver

var queryserviceStatusTemplate = `

State: {{.State}}

Queryservice History

    Time
    Target Tablet Type
    Serving State

  {{range .History}}

    {{.Time.Format "Jan 2, 2006 at 15:04:05 (MST)"}}
    {{.TabletType}}
    {{.ServingState}}

  {{end}}

QPS: {{.CurrentQPS}}

`

type queryserviceStatus struct {
	State      string
	History    []interface{}
	CurrentQPS float64
}

// AddStatusPart registers the status part for the status page.
func (tsv *TabletServer) AddStatusPart() {
	servenv.AddStatusPart("Queryservice", queryserviceStatusTemplate, func() interface{} {
		status := queryserviceStatus{
			State:   tsv.GetState(),
			History: tsv.history.Records(),
		}
		rates := tsv.qe.queryServiceStats.QPSRates.Get()
		if qps, ok := rates["All"]; ok && len(qps) > 0 {
			status.CurrentQPS = qps[0]
		}
		return status
	})
}

type historyRecord struct {
	Time         time.Time
	TabletType   string
	ServingState string
}

// IsDuplicate implements history.Deduplicable
func (r *historyRecord) IsDuplicate(other interface{}) bool {
	rother, ok := other.(*historyRecord)
	if !ok {
		return false
	}
	return r.TabletType == rother.TabletType && r.ServingState == rother.ServingState
}
<|endoftext|>


<commit_before>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"tcpcall/proto"
	"time"
)

type RRegistry map[proto.SeqNum]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Locker
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

// Connect to server side.
func Dial(dst string, conf ClientConf) (c *Client, err error) {
	c = &Client{
		peer:       dst,
		config:     conf,
		registry:   RRegistry{},
		registryMu: &sync.Mutex{},
		closeChan:  make(chan bool, 50),
	}
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) (rep []byte, err error) {
	return c.ReqChunks([][]byte{payload}, timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) (rep []byte, err error) {
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     make(chan RRReply, 1),
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()
	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		return nil, OverloadError
	}
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	defer c.popRegistry(req.SeqNum)
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	// wait for the response
	select {
	case reply := <-entry.Chan:
		if reply.Error == nil {
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		return nil, RemoteCrashedError
	case <-time.After(entry.Deadline.Sub(time.Now())):
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		return err
	}
	c.log("cast sent")
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-time.After(time.Second / 5):
		}
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		p := payload.(*proto.PacketReply)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{p.Reply, nil}
		}
	case proto.ERROR:
		p := payload.(*proto.PacketError)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum proto.SeqNum) *RREntry {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	res := c.registry[seqnum]
	if res != nil {
		delete(c.registry, seqnum)
	}
	return res
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<commit_msg>golang (style): use more idiomatic way for map lookup<commit_after>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"tcpcall/proto"
	"time"
)

type RRegistry map[proto.SeqNum]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Locker
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

// Connect to server side.
func Dial(dst string, conf ClientConf) (c *Client, err error) {
	c = &Client{
		peer:       dst,
		config:     conf,
		registry:   RRegistry{},
		registryMu: &sync.Mutex{},
		closeChan:  make(chan bool, 50),
	}
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) (rep []byte, err error) {
	return c.ReqChunks([][]byte{payload}, timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) (rep []byte, err error) {
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     make(chan RRReply, 1),
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()
	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		return nil, OverloadError
	}
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	defer c.popRegistry(req.SeqNum)
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	// wait for the response
	select {
	case reply := <-entry.Chan:
		if reply.Error == nil {
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		return nil, RemoteCrashedError
	case <-time.After(entry.Deadline.Sub(time.Now())):
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		return err
	}
	c.log("cast sent")
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-time.After(time.Second / 5):
		}
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		p := payload.(*proto.PacketReply)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{p.Reply, nil}
		}
	case proto.ERROR:
		p := payload.(*proto.PacketError)
		if entry, ok := c.popRegistry(p.SeqNum); ok {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum proto.SeqNum) (e *RREntry, ok bool) {
	c.registryMu.Lock()
	res, ok := c.registry[seqnum]
	if ok {
		delete(c.registry, seqnum)
	}
	c.registryMu.Unlock()
	return res, ok
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"time"
)

func main() {

	// check current parent folder
	// dir, _ := os.Getwd()
	// fmt.Println("Current dir: " + dir)

	fmt.Println("* Preparing and moving api.json and responses files ...")

	if os.Args == nil || len(os.Args) == 1 {
		fmt.Println("ERROR: You must provide path to api.json")
		os.Exit(1)
	}
	apiPath := os.Args[1]

	// check for relative path
	fmt.Printf("args: %v", os.Args)

	relativePath := ""
	if len(os.Args) == 3 {
		relativePath = os.Args[2]
	}

	var docTemplate = template.Must(template.New("doc").ParseFiles(relativePath + "theme/index.html"))

	// clean input dir
	os.RemoveAll(relativePath + "input")
	os.Mkdir(relativePath+"input", os.ModePerm)

	// copy api.json
	CopyFile(apiPath+"/api.json", relativePath+"input/api.json")

	// copy responses if exist
	err := CopyDir(apiPath+"/responses", relativePath+"input/responses")
	if err != nil {
		log.Fatal(err)
	} else {
		log.Print("Files copied.")
	}

	fmt.Println("* Start api docs generation...")
	fmt.Println("* Read input: api.json")

	file, e := ioutil.ReadFile(relativePath + "input/api.json")
	if e != nil {
		fmt.Printf("ERROR: File error: %v\n", e)
		os.Exit(1)
	}
	var api API
	err = json.Unmarshal(file, &api)
	if err != nil {
		panic(err)
	}

	fmt.Printf("* Load resources (%v)", len(api.Endpoints))
	fmt.Println("")
	for i, endpoint := range api.Endpoints {

		fmt.Printf("::: %v", endpoint.Response)

		resource := relativePath + "input/responses/" + endpoint.Response
		fmt.Printf("* Resource: %v", resource)
		response, e := ioutil.ReadFile(resource)
		if e != nil {
			fmt.Printf("ERROR: File error: %v\n", e)
			os.Exit(1)
		}
		api.Endpoints[i].Response = string(response)
		api.Endpoints[i].Example = createCurlExample(api.Base.Url, &endpoint)

		if len(endpoint.Params) > 0 {
			api.Endpoints[i].HasParams = true
		} else {
			api.Endpoints[i].HasParams = false
		}

		if len(endpoint.UrlParams) > 0 {
			api.Endpoints[i].HasUrlParams = true
		} else {
			api.Endpoints[i].HasUrlParams = false
		}
	}

	fmt.Println("* Create doc")
	doc := &Doc{
		Title:       api.Title,
		GeneratedAt: time.Now().Format(time.RFC1123),
		Api:         api,
	}

	f, _ := os.Create(relativePath + "theme/doc.html")
	docTemplate.ExecuteTemplate(f, "doc", doc)

	fmt.Println("* Finish docs generation")
}

func createCurlExample(baseUrl string, endpoint *Endpoint) string {
	example := "" // todo
	return example
}

// model
type Doc struct {
	Title       string
	GeneratedAt string
	Api         API
}

type API struct {
	Title     string     `json:"title"`
	Base      Base       `json:"base"`
	Endpoints []Endpoint `json:"endpoints"`
}

type Base struct {
	Url     string   `json:"url"`
	Headers []Header `json:"headers"`
}

type Header struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

type Endpoint struct {
	Endpoint     string       `json:"endpoint"`
	Title        string       `json:"title"`
	Description  string       `json:"description"`
	Method       string       `json:"method"`
	UrlParams    []Param      `json:"url-params"`
	Params       []Param      `json:"params"`
	Response     string       `json:"response"`
	ResultCodes  []ResultCode `json:"codes"`
	Example      string
	HasUrlParams bool
	HasParams    bool
}

type Param struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Type        string `json:"type"`
	Value       string `json:"value"`
	Must        bool   `json:"must"`
	Default     string `json:"default"`
	Options     string `json:"options"`
}

type ResultCode struct {
	Code        int    `json:"code"`
	Type        string `json:"type"`
	Description string `json:"description"`
}

// utils
func CopyFile(source string, dest string) (err error) {
	sf, err := os.Open(source)
	if err != nil {
		return err
	}
	defer sf.Close()
	df, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer df.Close()
	_, err = io.Copy(df, sf)
	if err == nil {
		si, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, si.Mode())
		}

	}

	return
}

func CopyDir(source string, dest string) (err error) {

	// get properties of source dir
	fi, err := os.Stat(source)
	if err != nil {
		return err
	}

	if !fi.IsDir() {
		return &IOError{"Source is not a directory"}
	}

	// ensure dest dir does not already exist

	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return &IOError{"Destination already exists"}
	}

	// create dest dir

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	entries, err := ioutil.ReadDir(source)

	for _, entry := range entries {

		sfp := source + "/" + entry.Name()
		dfp := dest + "/" + entry.Name()
		if entry.IsDir() {
			err = CopyDir(sfp, dfp)
			if err != nil {
				log.Println(err)
			}
		} else {
			// perform copy
			err = CopyFile(sfp, dfp)
			if err != nil {
				log.Println(err)
			}
		}

	}
	return
}

type IOError struct {
	What string
}

func (e *IOError) Error() string {
	return e.What
}
<commit_msg>Clean prints<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"os"
	"time"
)

func main() {

	// check current parent folder
	// dir, _ := os.Getwd()
	// fmt.Println("Current dir: " + dir)

	fmt.Println("* Preparing and moving api.json and responses files ...")

	if os.Args == nil || len(os.Args) == 1 {
		fmt.Println("ERROR: You must provide path to api.json")
		os.Exit(1)
	}
	apiPath := os.Args[1]

	// check for relative path
	fmt.Printf("args: %v", os.Args)

	relativePath := ""
	if len(os.Args) == 3 {
		relativePath = os.Args[2]
	}

	var docTemplate = template.Must(template.New("doc").ParseFiles(relativePath + "theme/index.html"))

	// clean input dir
	os.RemoveAll(relativePath + "input")
	os.Mkdir(relativePath+"input", os.ModePerm)

	// copy api.json
	CopyFile(apiPath+"/api.json", relativePath+"input/api.json")

	// copy responses if exist
	err := CopyDir(apiPath+"/responses", relativePath+"input/responses")
	if err != nil {
		log.Fatal(err)
	} else {
		log.Print("Files copied.")
	}

	fmt.Println("* Start api docs generation...")
	fmt.Println("* Read input: api.json")

	file, e := ioutil.ReadFile(relativePath + "input/api.json")
	if e != nil {
		fmt.Printf("ERROR: File error: %v\n", e)
		os.Exit(1)
	}
	var api API
	err = json.Unmarshal(file, &api)
	if err != nil {
		panic(err)
	}

	fmt.Printf("* Load resources (%v)", len(api.Endpoints))
	fmt.Println("")
	for i, endpoint := range api.Endpoints {
		resource := relativePath + "input/responses/" + endpoint.Response
		fmt.Printf("* Resource: %v", resource)
		fmt.Println("")
		response, e := ioutil.ReadFile(resource)
		if e != nil {
			fmt.Printf("ERROR: File error: %v\n", e)
			os.Exit(1)
		}
		api.Endpoints[i].Response = string(response)
		api.Endpoints[i].Example = createCurlExample(api.Base.Url, &endpoint)

		if len(endpoint.Params) > 0 {
			api.Endpoints[i].HasParams = true
		} else {
			api.Endpoints[i].HasParams = false
		}

		if len(endpoint.UrlParams) > 0 {
			api.Endpoints[i].HasUrlParams = true
		} else {
			api.Endpoints[i].HasUrlParams = false
		}
	}

	fmt.Println("* Create doc")
	doc := &Doc{
		Title:       api.Title,
		GeneratedAt: time.Now().Format(time.RFC1123),
		Api:         api,
	}

	f, _ := os.Create(relativePath + "theme/doc.html")
	docTemplate.ExecuteTemplate(f, "doc", doc)

	fmt.Println("* Finish docs generation")
}

func createCurlExample(baseUrl string, endpoint *Endpoint) string {
	example := "" // todo
	return example
}

// model
type Doc struct {
	Title       string
	GeneratedAt string
	Api         API
}

type API struct {
	Title     string     `json:"title"`
	Base      Base       `json:"base"`
	Endpoints []Endpoint `json:"endpoints"`
}

type Base struct {
	Url     string   `json:"url"`
	Headers []Header `json:"headers"`
}

type Header struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

type Endpoint struct {
	Endpoint     string       `json:"endpoint"`
	Title        string       `json:"title"`
	Description  string       `json:"description"`
	Method       string       `json:"method"`
	UrlParams    []Param      `json:"url-params"`
	Params       []Param      `json:"params"`
	Response     string       `json:"response"`
	ResultCodes  []ResultCode `json:"codes"`
	Example      string
	HasUrlParams bool
	HasParams    bool
}

type Param struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Type        string `json:"type"`
	Value       string `json:"value"`
	Must        bool   `json:"must"`
	Default     string `json:"default"`
	Options     string `json:"options"`
}

type ResultCode struct {
	Code        int    `json:"code"`
	Type        string `json:"type"`
	Description string `json:"description"`
}

// utils
func CopyFile(source string, dest string) (err error) {
	sf, err := os.Open(source)
	if err != nil {
		return err
	}
	defer sf.Close()
	df, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer df.Close()
	_, err = io.Copy(df, sf)
	if err == nil {
		si, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, si.Mode())
		}

	}

	return
}

func CopyDir(source string, dest string) (err error) {

	// get properties of source dir
	fi, err := os.Stat(source)
	if err != nil {
		return err
	}

	if !fi.IsDir() {
		return &IOError{"Source is not a directory"}
	}

	// ensure dest dir does not already exist

	_, err = os.Open(dest)
	if !os.IsNotExist(err) {
		return &IOError{"Destination already exists"}
	}

	// create dest dir

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	entries, err := ioutil.ReadDir(source)

	for _, entry := range entries {

		sfp := source + "/" + entry.Name()
		dfp := dest + "/" + entry.Name()
		if entry.IsDir() {
			err = CopyDir(sfp, dfp)
			if err != nil {
				log.Println(err)
			}
		} else {
			// perform copy
			err = CopyFile(sfp, dfp)
			if err != nil {
				log.Println(err)
			}
		}

	}
	return
}

type IOError struct {
	What string
}

func (e *IOError) Error() string {
	return e.What
}
<|endoftext|>


<commit_before>package main

import (
	"time"
)

type jargon struct {
	name   string
	quote  string
	source string
	date   time.Time
}

var jargonCollection []jargon

func main() {
}
<commit_msg>add jargon.ID<commit_after>package main

import (
	"time"
)

type jargon struct {
	ID     int
	name   string
	quote  string
	source string
	date   time.Time
}

var jargonCollection []jargon

func main() {
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes 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.
*/

package cephfs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
)

const (
	cephUserPrefix         = "user-"
	cephEntityClientPrefix = "client."
)

type cephEntityCaps struct {
	Mds string `json:"mds"`
	Mon string `json:"mon"`
	Osd string `json:"osd"`
}

type cephEntity struct {
	Entity string         `json:"entity"`
	Key    string         `json:"key"`
	Caps   cephEntityCaps `json:"caps"`
}

func (ent *cephEntity) toCredentials() *credentials {
	return &credentials{
		id:  ent.Entity[len(cephEntityClientPrefix):],
		key: ent.Key,
	}
}

func getCephUserName(volID volumeID) string {
	return cephUserPrefix + string(volID)
}

func getCephUser(adminCr *credentials, volID volumeID) (*cephEntity, error) {
	entityName := cephEntityClientPrefix + getCephUserName(volID)

	var ents []cephEntity
	args := [...]string{
		"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"get", entityName,
	}

	out, err := execCommand("ceph", args[:]...)
	if err != nil {
		return nil, fmt.Errorf("cephfs: ceph failed with following error: %s\ncephfs: ceph output: %s", err, out)
	}

	// Workaround for output from `ceph auth get`
	// Contains non-json data: "exported keyring for ENTITY\n\n"
	offset := bytes.Index(out, []byte("[{"))

	if json.NewDecoder(bytes.NewReader(out[offset:])).Decode(&ents); err != nil {
		return nil, fmt.Errorf("failed to decode json: %v", err)
	}

	if len(ents) != 1 {
		return nil, fmt.Errorf("got unexpected number of entities for %s: expected 1, got %d", entityName, len(ents))
	}

	return &ents[0], nil
}

func createCephUser(volOptions *volumeOptions, adminCr *credentials, volID volumeID) (*cephEntity, error) {
	caps := cephEntityCaps{
		Mds: fmt.Sprintf("allow rw path=%s", getVolumeRootPathCeph(volID)),
		Mon: "allow r",
		Osd: fmt.Sprintf("allow rw pool=%s namespace=%s", volOptions.Pool, getVolumeNamespace(volID)),
	}

	var ents []cephEntity
	args := [...]string{
		"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"get-or-create", cephEntityClientPrefix + getCephUserName(volID),
		"mds", caps.Mds,
		"mon", caps.Mon,
		"osd", caps.Osd,
	}

	if err := execCommandJSON(&ents, "ceph", args[:]...); err != nil {
		return nil, fmt.Errorf("error creating ceph user: %v", err)
	}

	return &ents[0], nil
}

func deleteCephUser(adminCr *credentials, volID volumeID) error {
	userID := getCephUserName(volID)

	args := [...]string{
		"-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"auth", "rm", cephEntityClientPrefix + userID,
	}

	if err := execCommandAndValidate("ceph", args[:]...); err != nil {
		return err
	}

	os.Remove(getCephKeyringPath(volID, userID))
	os.Remove(getCephSecretPath(volID, userID))

	return nil
}
<commit_msg>Fix error checking issue in json Decode<commit_after>/*
Copyright 2018 The Kubernetes 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.
*/

package cephfs

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
)

const (
	cephUserPrefix         = "user-"
	cephEntityClientPrefix = "client."
)

type cephEntityCaps struct {
	Mds string `json:"mds"`
	Mon string `json:"mon"`
	Osd string `json:"osd"`
}

type cephEntity struct {
	Entity string         `json:"entity"`
	Key    string         `json:"key"`
	Caps   cephEntityCaps `json:"caps"`
}

func (ent *cephEntity) toCredentials() *credentials {
	return &credentials{
		id:  ent.Entity[len(cephEntityClientPrefix):],
		key: ent.Key,
	}
}

func getCephUserName(volID volumeID) string {
	return cephUserPrefix + string(volID)
}

func getCephUser(adminCr *credentials, volID volumeID) (*cephEntity, error) {
	entityName := cephEntityClientPrefix + getCephUserName(volID)

	var ents []cephEntity
	args := [...]string{
		"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"get", entityName,
	}

	out, err := execCommand("ceph", args[:]...)
	if err != nil {
		return nil, fmt.Errorf("cephfs: ceph failed with following error: %s\ncephfs: ceph output: %s", err, out)
	}

	// Workaround for output from `ceph auth get`
	// Contains non-json data: "exported keyring for ENTITY\n\n"
	offset := bytes.Index(out, []byte("[{"))

	if err = json.NewDecoder(bytes.NewReader(out[offset:])).Decode(&ents); err != nil {
		return nil, fmt.Errorf("failed to decode json: %v", err)
	}

	if len(ents) != 1 {
		return nil, fmt.Errorf("got unexpected number of entities for %s: expected 1, got %d", entityName, len(ents))
	}

	return &ents[0], nil
}

func createCephUser(volOptions *volumeOptions, adminCr *credentials, volID volumeID) (*cephEntity, error) {
	caps := cephEntityCaps{
		Mds: fmt.Sprintf("allow rw path=%s", getVolumeRootPathCeph(volID)),
		Mon: "allow r",
		Osd: fmt.Sprintf("allow rw pool=%s namespace=%s", volOptions.Pool, getVolumeNamespace(volID)),
	}

	var ents []cephEntity
	args := [...]string{
		"auth", "-f", "json", "-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"get-or-create", cephEntityClientPrefix + getCephUserName(volID),
		"mds", caps.Mds,
		"mon", caps.Mon,
		"osd", caps.Osd,
	}

	if err := execCommandJSON(&ents, "ceph", args[:]...); err != nil {
		return nil, fmt.Errorf("error creating ceph user: %v", err)
	}

	return &ents[0], nil
}

func deleteCephUser(adminCr *credentials, volID volumeID) error {
	userID := getCephUserName(volID)

	args := [...]string{
		"-c", getCephConfPath(volID), "-n", cephEntityClientPrefix + adminCr.id,
		"auth", "rm", cephEntityClientPrefix + userID,
	}

	if err := execCommandAndValidate("ceph", args[:]...); err != nil {
		return err
	}

	os.Remove(getCephKeyringPath(volID, userID))
	os.Remove(getCephSecretPath(volID, userID))

	return nil
}
<|endoftext|>