<commit_before>package types

// block.go defines the Block type for Sia, and provides some helper functions
// for working with blocks.

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

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
)

const (
	// BlockHeaderSize is the size, in bytes, of a block header.
	// 32 (ParentID) + 8 (Nonce) + 8 (Timestamp) + 32 (MerkleRoot)
	BlockHeaderSize = 80
)

type (
	// A Block is a summary of changes to the state that have occurred since the
	// previous block. Blocks reference the ID of the previous block (their
	// "parent"), creating the linked-list commonly known as the blockchain. Their
	// primary function is to bundle together transactions on the network. Blocks
	// are created by "miners," who collect transactions from other nodes, and
	// then try to pick a Nonce that results in a block whose BlockID is below a
	// given Target.
	Block struct {
		ParentID     BlockID         `json:"parentid"`
		Nonce        BlockNonce      `json:"nonce"`
		Timestamp    Timestamp       `json:"timestamp"`
		MinerPayouts []SiacoinOutput `json:"minerpayouts"`
		Transactions []Transaction   `json:"transactions"`
	}

	// A BlockHeader, when encoded, is an 80-byte constant size field
	// containing enough information to do headers-first block downloading.
	// Hashing the header results in the block ID.
	BlockHeader struct {
		ParentID   BlockID     `json:"parentid"`
		Nonce      BlockNonce  `json:"nonce"`
		Timestamp  Timestamp   `json:"timestamp"`
		MerkleRoot crypto.Hash `json:"merkleroot"`
	}

	BlockHeight uint64
	BlockID     crypto.Hash
	BlockNonce  [8]byte
)

// CalculateCoinbase calculates the coinbase for a given height. The coinbase
// equation is:
//
//     coinbase := max(InitialCoinbase - height, MinimumCoinbase) * SiacoinPrecision
func CalculateCoinbase(height BlockHeight) Currency {
	base := InitialCoinbase - uint64(height)
	if uint64(height) > InitialCoinbase || base < MinimumCoinbase {
		base = MinimumCoinbase
	}
	return NewCurrency64(base).Mul(SiacoinPrecision)
}

// CalculateNumSiacoins calculates the number of siacoins in circulation at a
// given height.
func CalculateNumSiacoins(height BlockHeight) Currency {
	deflationBlocks := BlockHeight(InitialCoinbase - MinimumCoinbase)
	avgDeflationSiacoins := CalculateCoinbase(0).Add(CalculateCoinbase(height)).Div(NewCurrency64(2))
	if height <= deflationBlocks {
		deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(height + 1)))
		return deflationSiacoins
	}
	deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(deflationBlocks + 1)))
	trailingSiacoins := NewCurrency64(uint64(height - deflationBlocks)).Mul(CalculateCoinbase(height))
	return deflationSiacoins.Add(trailingSiacoins)
}

// CalculateSubsidy takes a block and a height and determines the block
// subsidy.
func (b Block) CalculateSubsidy(height BlockHeight) Currency {
	subsidy := CalculateCoinbase(height)
	for _, txn := range b.Transactions {
		for _, fee := range txn.MinerFees {
			subsidy = subsidy.Add(fee)
		}
	}
	return subsidy
}

// Header returns the header of a block.
func (b Block) Header() BlockHeader {
	return BlockHeader{
		ParentID:   b.ParentID,
		Nonce:      b.Nonce,
		Timestamp:  b.Timestamp,
		MerkleRoot: b.MerkleRoot(),
	}
}

// ID returns the ID of a Block, which is calculated by hashing the
// concatenation of the block's parent's ID, nonce, and the result of the
// b.MerkleRoot().
func (b Block) ID() BlockID {
	return BlockID(crypto.HashObject(b.Header()))
}

// ID returns the ID of a Block, which is calculated by hashing the header.
func (h BlockHeader) ID() BlockID {
	return BlockID(crypto.HashObject(h))
}

// MerkleRoot calculates the Merkle root of a Block. The leaves of the Merkle
// tree are composed of the Timestamp, the miner outputs (one leaf per
// payout), and the transactions (one leaf per transaction).
func (b Block) MerkleRoot() crypto.Hash {
	tree := crypto.NewTree()
	for _, payout := range b.MinerPayouts {
		tree.PushObject(payout)
	}
	for _, txn := range b.Transactions {
		tree.PushObject(txn)
	}
	return tree.Root()
}

// MinerPayoutID returns the ID of the miner payout at the given index, which
// is calculated by hashing the concatenation of the BlockID and the payout
// index.
func (b Block) MinerPayoutID(i uint64) SiacoinOutputID {
	return SiacoinOutputID(crypto.HashAll(
		b.ID(),
		i,
	))
}

// MarshalSia implements the encoding.SiaMarshaler interface.
func (b Block) MarshalSia(w io.Writer) error {
	w.Write(b.ParentID[:])
	w.Write(b.Nonce[:])
	w.Write(encoding.EncUint64(uint64(b.Timestamp)))
	return encoding.NewEncoder(w).EncodeAll(b.MinerPayouts, b.Transactions)
}

// UnmarshalSia implements the encoding.SiaUnmarshaler interface.
func (b *Block) UnmarshalSia(r io.Reader) error {
	io.ReadFull(r, b.ParentID[:])
	io.ReadFull(r, b.Nonce[:])
	tsBytes := make([]byte, 8)
	io.ReadFull(r, tsBytes)
	b.Timestamp = Timestamp(encoding.DecUint64(tsBytes))
	return encoding.NewDecoder(r).DecodeAll(&b.MinerPayouts, &b.Transactions)
}

// MarshalJSON marshales a block id as a hex string.
func (bid BlockID) MarshalJSON() ([]byte, error) {
	return json.Marshal(bid.String())
}

// String prints the block id in hex.
func (bid BlockID) String() string {
	return fmt.Sprintf("%x", bid[:])
}

// UnmarshalJSON decodes the json hex string of the block id.
func (bid *BlockID) UnmarshalJSON(b []byte) error {
	if len(b) != crypto.HashSize*2+2 {
		return crypto.ErrHashWrongLen
	}

	var bidBytes []byte
	_, err := fmt.Sscanf(string(b[1:len(b)-1]), "%x", &bidBytes)
	if err != nil {
		return errors.New("could not unmarshal BlockID: " + err.Error())
	}
	copy(bid[:], bidBytes)
	return nil
}
<commit_msg>Move Header.ID() method to above all Block methods<commit_after>package types

// block.go defines the Block type for Sia, and provides some helper functions
// for working with blocks.

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

	"github.com/NebulousLabs/Sia/crypto"
	"github.com/NebulousLabs/Sia/encoding"
)

const (
	// BlockHeaderSize is the size, in bytes, of a block header.
	// 32 (ParentID) + 8 (Nonce) + 8 (Timestamp) + 32 (MerkleRoot)
	BlockHeaderSize = 80
)

type (
	// A Block is a summary of changes to the state that have occurred since the
	// previous block. Blocks reference the ID of the previous block (their
	// "parent"), creating the linked-list commonly known as the blockchain. Their
	// primary function is to bundle together transactions on the network. Blocks
	// are created by "miners," who collect transactions from other nodes, and
	// then try to pick a Nonce that results in a block whose BlockID is below a
	// given Target.
	Block struct {
		ParentID     BlockID         `json:"parentid"`
		Nonce        BlockNonce      `json:"nonce"`
		Timestamp    Timestamp       `json:"timestamp"`
		MinerPayouts []SiacoinOutput `json:"minerpayouts"`
		Transactions []Transaction   `json:"transactions"`
	}

	// A BlockHeader, when encoded, is an 80-byte constant size field
	// containing enough information to do headers-first block downloading.
	// Hashing the header results in the block ID.
	BlockHeader struct {
		ParentID   BlockID     `json:"parentid"`
		Nonce      BlockNonce  `json:"nonce"`
		Timestamp  Timestamp   `json:"timestamp"`
		MerkleRoot crypto.Hash `json:"merkleroot"`
	}

	BlockHeight uint64
	BlockID     crypto.Hash
	BlockNonce  [8]byte
)

// CalculateCoinbase calculates the coinbase for a given height. The coinbase
// equation is:
//
//     coinbase := max(InitialCoinbase - height, MinimumCoinbase) * SiacoinPrecision
func CalculateCoinbase(height BlockHeight) Currency {
	base := InitialCoinbase - uint64(height)
	if uint64(height) > InitialCoinbase || base < MinimumCoinbase {
		base = MinimumCoinbase
	}
	return NewCurrency64(base).Mul(SiacoinPrecision)
}

// CalculateNumSiacoins calculates the number of siacoins in circulation at a
// given height.
func CalculateNumSiacoins(height BlockHeight) Currency {
	deflationBlocks := BlockHeight(InitialCoinbase - MinimumCoinbase)
	avgDeflationSiacoins := CalculateCoinbase(0).Add(CalculateCoinbase(height)).Div(NewCurrency64(2))
	if height <= deflationBlocks {
		deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(height + 1)))
		return deflationSiacoins
	}
	deflationSiacoins := avgDeflationSiacoins.Mul(NewCurrency64(uint64(deflationBlocks + 1)))
	trailingSiacoins := NewCurrency64(uint64(height - deflationBlocks)).Mul(CalculateCoinbase(height))
	return deflationSiacoins.Add(trailingSiacoins)
}

// ID returns the ID of a Block, which is calculated by hashing the header.
func (h BlockHeader) ID() BlockID {
	return BlockID(crypto.HashObject(h))
}

// CalculateSubsidy takes a block and a height and determines the block
// subsidy.
func (b Block) CalculateSubsidy(height BlockHeight) Currency {
	subsidy := CalculateCoinbase(height)
	for _, txn := range b.Transactions {
		for _, fee := range txn.MinerFees {
			subsidy = subsidy.Add(fee)
		}
	}
	return subsidy
}

// Header returns the header of a block.
func (b Block) Header() BlockHeader {
	return BlockHeader{
		ParentID:   b.ParentID,
		Nonce:      b.Nonce,
		Timestamp:  b.Timestamp,
		MerkleRoot: b.MerkleRoot(),
	}
}

// ID returns the ID of a Block, which is calculated by hashing the
// concatenation of the block's parent's ID, nonce, and the result of the
// b.MerkleRoot(). It is equivalent to calling block.Header().ID()
func (b Block) ID() BlockID {
	return b.Header().ID()
}

// MerkleRoot calculates the Merkle root of a Block. The leaves of the Merkle
// tree are composed of the Timestamp, the miner outputs (one leaf per
// payout), and the transactions (one leaf per transaction).
func (b Block) MerkleRoot() crypto.Hash {
	tree := crypto.NewTree()
	for _, payout := range b.MinerPayouts {
		tree.PushObject(payout)
	}
	for _, txn := range b.Transactions {
		tree.PushObject(txn)
	}
	return tree.Root()
}

// MinerPayoutID returns the ID of the miner payout at the given index, which
// is calculated by hashing the concatenation of the BlockID and the payout
// index.
func (b Block) MinerPayoutID(i uint64) SiacoinOutputID {
	return SiacoinOutputID(crypto.HashAll(
		b.ID(),
		i,
	))
}

// MarshalSia implements the encoding.SiaMarshaler interface.
func (b Block) MarshalSia(w io.Writer) error {
	w.Write(b.ParentID[:])
	w.Write(b.Nonce[:])
	w.Write(encoding.EncUint64(uint64(b.Timestamp)))
	return encoding.NewEncoder(w).EncodeAll(b.MinerPayouts, b.Transactions)
}

// UnmarshalSia implements the encoding.SiaUnmarshaler interface.
func (b *Block) UnmarshalSia(r io.Reader) error {
	io.ReadFull(r, b.ParentID[:])
	io.ReadFull(r, b.Nonce[:])
	tsBytes := make([]byte, 8)
	io.ReadFull(r, tsBytes)
	b.Timestamp = Timestamp(encoding.DecUint64(tsBytes))
	return encoding.NewDecoder(r).DecodeAll(&b.MinerPayouts, &b.Transactions)
}

// MarshalJSON marshales a block id as a hex string.
func (bid BlockID) MarshalJSON() ([]byte, error) {
	return json.Marshal(bid.String())
}

// String prints the block id in hex.
func (bid BlockID) String() string {
	return fmt.Sprintf("%x", bid[:])
}

// UnmarshalJSON decodes the json hex string of the block id.
func (bid *BlockID) UnmarshalJSON(b []byte) error {
	if len(b) != crypto.HashSize*2+2 {
		return crypto.ErrHashWrongLen
	}

	var bidBytes []byte
	_, err := fmt.Sscanf(string(b[1:len(b)-1]), "%x", &bidBytes)
	if err != nil {
		return errors.New("could not unmarshal BlockID: " + err.Error())
	}
	copy(bid[:], bidBytes)
	return nil
}
<|endoftext|>


<commit_before>package engi

import (
	"log"
)

type Camera struct {
	Point
	tracking *Entity
}

func (cam *Camera) FollowEntity(entity *Entity) {
	cam.tracking = entity
	var space *SpaceComponent
	if !cam.tracking.GetComponent(&space) {
		return
	}

	cam.Point = space.Position
}

func (cam *Camera) Update(dt float32) {
	// maxPoints := 8
	if cam.tracking != nil {
		var space *SpaceComponent
		if !cam.tracking.GetComponent(&space) {
			return
		}
		lerp := float32(.09)
		cam.X += ((space.Position.X + space.Width/2) - (cam.X + Width()/2)) * lerp
		cam.Y += ((space.Position.Y + space.Height/2) - (cam.Y + Height()/2)) * lerp
		log.Println(cam.X, cam.Y)
	}
}
<commit_msg>Fixed camera movement bug<commit_after>package engi

import (
	"log"
)

type Camera struct {
	Point
	tracking *Entity
}

func (cam *Camera) FollowEntity(entity *Entity) {
	cam.tracking = entity
	var space *SpaceComponent
	if !cam.tracking.GetComponent(&space) {
		return
	}

	centerDiference(&cam.Point, Width(), Height(), space)
	// cam.Point = space.Position
}

func (cam *Camera) Update(dt float32) {
	// maxPoints := 8
	if cam.tracking != nil {
		var space *SpaceComponent
		if !cam.tracking.GetComponent(&space) {
			return
		}
		// lerp := float32(.09)
		log.Println(cam.Point)
		centerDiference(&cam.Point, Width(), Height(), space)

	}
}

func centerDiference(to *Point, width, height float32, space *SpaceComponent) {
	to.X += ((space.Position.X + space.Width/2) - (to.X + width/2))
	to.Y += ((space.Position.Y + space.Height/2) - (to.Y + height/2))
}
<|endoftext|>


<commit_before>package ui

/*
#include <SDL.h>

#cgo darwin CFLAGS: -I/Library/Frameworks/SDL2.framework/Headers
#cgo darwin LDFLAGS: -framework SDL2

#cgo linux pkg-config: sdl2
*/
import "C"

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"unsafe"
)

// A Canvas can draw to a window.
// The drawing operations can only be safely used within the main go routine.
type Canvas struct {
	win  *Window
	font font
}

// Clear clears the canvas with the drawing color.
func (c Canvas) Clear() {
	if C.SDL_RenderClear(c.win.rend) < 0 {
		panic(sdlError())
	}
}

// SetColor sets the color used for drawing operations (DrawPoints, DrawLines, DrawRects, FillRects, and Clear).
func (c Canvas) SetColor(col color.Color) {
	r, g, b, a := col.RGBA()
	f := 255.0 / 0xFFFF
	r8 := C.Uint8(float64(r) * f)
	g8 := C.Uint8(float64(g) * f)
	b8 := C.Uint8(float64(b) * f)
	a8 := C.Uint8(float64(a) * f)
	if C.SDL_SetRenderDrawColor(c.win.rend, r8, g8, b8, a8) < 0 {
		panic(sdlError())
	}
}

// Color returns the current drawing color.
func (c Canvas) color() color.Color {
	var r, g, b, a C.Uint8
	if C.SDL_GetRenderDrawColor(c.win.rend, &r, &g, &b, &a) < 0 {
		panic(sdlError())
	}
	return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
}

// DrawPoints draws multiple points on the canvas.
func (c Canvas) DrawPoints(points ...image.Point) {
	if C.SDL_RenderDrawPoints(c.win.rend, sdlPoints(points), C.int(len(points))) < 0 {
		panic(sdlError())
	}
}

// DrawLines draws a series of connected lines on the canvas.
func (c Canvas) DrawLines(points ...image.Point) {
	if C.SDL_RenderDrawLines(c.win.rend, sdlPoints(points), C.int(len(points))) < 0 {
		panic(sdlError())
	}
}

func sdlPoints(points []image.Point) *C.SDL_Point {
	pts := make([]C.SDL_Point, len(points))
	for i, p := range points {
		pts[i].x = C.int(p.X)
		pts[i].y = C.int(p.Y)
	}
	return &pts[0]
}

// DrawRects draws some number of rectangles on the canvas.
func (c Canvas) DrawRects(rects ...image.Rectangle) {
	if C.SDL_RenderDrawRects(c.win.rend, sdlRects(rects), C.int(len(rects))) < 0 {
		panic(sdlError())
	}
}

// FillRects fills some number of rectangles on the canvas with the drawing color.
func (c Canvas) FillRects(rects ...image.Rectangle) {
	if C.SDL_RenderFillRects(c.win.rend, sdlRects(rects), C.int(len(rects))) < 0 {
		panic(sdlError())
	}
}

func sdlRects(rects []image.Rectangle) *C.SDL_Rect {
	rs := make([]C.SDL_Rect, len(rects))
	for i := range rects {
		rs[i] = *sdlRect(&rects[i])
	}
	return &rs[0]
}

func sdlRect(rect *image.Rectangle) *C.SDL_Rect {
	if rect == nil {
		return nil
	}
	return &C.SDL_Rect{
		x: C.int(rect.Min.X),
		y: C.int(rect.Min.Y),
		w: C.int(rect.Dx()),
		h: C.int(rect.Dy()),
	}
}

// DrawPNG draws the image loaded from a PNG file to the canvas.
// The image is drawn with the upper-left corner located at x, y.
func (c Canvas) DrawPNG(path string, x, y int) {
	tex, ok := c.win.imgs[path]
	if !ok {
		img := loadPNG(path)
		tex = texture{
			tex:    texFromImage(c.win.rend, img),
			width:  img.Bounds().Dx(),
			height: img.Bounds().Dy(),
		}
		c.win.imgs[path] = tex
	}
	dst := image.Rect(x, y, x+tex.width, y+tex.height)
	if C.SDL_RenderCopy(c.win.rend, tex.tex, nil, sdlRect(&dst)) < 0 {
		panic(sdlError())
	}
}

// SetFont sets the current font face and size (in points).
func (c *Canvas) SetFont(path string, size int) {
	c.font = getFont(path, size)
}

// FillString fills a string of text in the current font and draw color.  The width and height
// of the string is returned.
func (c Canvas) FillString(s string, x, y int) (width, height int) {
	img := c.font.draw(s, c.color())
	tex := texFromImage(c.win.rend, img)
	defer C.SDL_DestroyTexture(tex)
	b := img.Bounds()
	w, h := b.Dx(), b.Dy()
	dst := image.Rect(x, y, x+w, y+h)
	if C.SDL_RenderCopy(c.win.rend, tex, nil, sdlRect(&dst)) < 0 {
		panic(sdlError())
	}
	return w, h
}

func texFromImage(rend *C.SDL_Renderer, img *image.NRGBA) *C.SDL_Texture {
	b := img.Bounds()
	w, h := b.Dx(), b.Dy()
	fmt := C.SDL_PIXELFORMAT_ABGR8888
	acc := C.SDL_TEXTUREACCESS_STATIC
	tex := C.SDL_CreateTexture(rend, C.Uint32(fmt), C.int(acc), C.int(w), C.int(h))
	if tex == nil {
		panic(sdlError())
	}
	if C.SDL_UpdateTexture(tex, nil, unsafe.Pointer(&img.Pix[0]), C.int(img.Stride)) < 0 {
		panic(sdlError())
	}
	if C.SDL_SetTextureBlendMode(tex, C.SDL_BLENDMODE_BLEND) < 0 {
		panic(sdlError())
	}
	return tex
}

func loadPNG(path string) *image.NRGBA {
	r, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		panic(err)
	}
	return img.(*image.NRGBA)
}
<commit_msg>Improve the comment on FillString.<commit_after>package ui

/*
#include <SDL.h>

#cgo darwin CFLAGS: -I/Library/Frameworks/SDL2.framework/Headers
#cgo darwin LDFLAGS: -framework SDL2

#cgo linux pkg-config: sdl2
*/
import "C"

import (
	"image"
	"image/color"
	"image/png"
	"os"
	"unsafe"
)

// A Canvas can draw to a window.
// The drawing operations can only be safely used within the main go routine.
type Canvas struct {
	win  *Window
	font font
}

// Clear clears the canvas with the drawing color.
func (c Canvas) Clear() {
	if C.SDL_RenderClear(c.win.rend) < 0 {
		panic(sdlError())
	}
}

// SetColor sets the color used for drawing operations (DrawPoints, DrawLines, DrawRects, FillRects, and Clear).
func (c Canvas) SetColor(col color.Color) {
	r, g, b, a := col.RGBA()
	f := 255.0 / 0xFFFF
	r8 := C.Uint8(float64(r) * f)
	g8 := C.Uint8(float64(g) * f)
	b8 := C.Uint8(float64(b) * f)
	a8 := C.Uint8(float64(a) * f)
	if C.SDL_SetRenderDrawColor(c.win.rend, r8, g8, b8, a8) < 0 {
		panic(sdlError())
	}
}

// Color returns the current drawing color.
func (c Canvas) color() color.Color {
	var r, g, b, a C.Uint8
	if C.SDL_GetRenderDrawColor(c.win.rend, &r, &g, &b, &a) < 0 {
		panic(sdlError())
	}
	return color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
}

// DrawPoints draws multiple points on the canvas.
func (c Canvas) DrawPoints(points ...image.Point) {
	if C.SDL_RenderDrawPoints(c.win.rend, sdlPoints(points), C.int(len(points))) < 0 {
		panic(sdlError())
	}
}

// DrawLines draws a series of connected lines on the canvas.
func (c Canvas) DrawLines(points ...image.Point) {
	if C.SDL_RenderDrawLines(c.win.rend, sdlPoints(points), C.int(len(points))) < 0 {
		panic(sdlError())
	}
}

func sdlPoints(points []image.Point) *C.SDL_Point {
	pts := make([]C.SDL_Point, len(points))
	for i, p := range points {
		pts[i].x = C.int(p.X)
		pts[i].y = C.int(p.Y)
	}
	return &pts[0]
}

// DrawRects draws some number of rectangles on the canvas.
func (c Canvas) DrawRects(rects ...image.Rectangle) {
	if C.SDL_RenderDrawRects(c.win.rend, sdlRects(rects), C.int(len(rects))) < 0 {
		panic(sdlError())
	}
}

// FillRects fills some number of rectangles on the canvas with the drawing color.
func (c Canvas) FillRects(rects ...image.Rectangle) {
	if C.SDL_RenderFillRects(c.win.rend, sdlRects(rects), C.int(len(rects))) < 0 {
		panic(sdlError())
	}
}

func sdlRects(rects []image.Rectangle) *C.SDL_Rect {
	rs := make([]C.SDL_Rect, len(rects))
	for i := range rects {
		rs[i] = *sdlRect(&rects[i])
	}
	return &rs[0]
}

func sdlRect(rect *image.Rectangle) *C.SDL_Rect {
	if rect == nil {
		return nil
	}
	return &C.SDL_Rect{
		x: C.int(rect.Min.X),
		y: C.int(rect.Min.Y),
		w: C.int(rect.Dx()),
		h: C.int(rect.Dy()),
	}
}

// DrawPNG draws the image loaded from a PNG file to the canvas.
// The image is drawn with the upper-left corner located at x, y.
func (c Canvas) DrawPNG(path string, x, y int) {
	tex, ok := c.win.imgs[path]
	if !ok {
		img := loadPNG(path)
		tex = texture{
			tex:    texFromImage(c.win.rend, img),
			width:  img.Bounds().Dx(),
			height: img.Bounds().Dy(),
		}
		c.win.imgs[path] = tex
	}
	dst := image.Rect(x, y, x+tex.width, y+tex.height)
	if C.SDL_RenderCopy(c.win.rend, tex.tex, nil, sdlRect(&dst)) < 0 {
		panic(sdlError())
	}
}

// SetFont sets the current font face and size (in points).
func (c *Canvas) SetFont(path string, size int) {
	c.font = getFont(path, size)
}

// FillString fills a string of text in the current font and draw color.  X and y specify the
// upper-left corner of the bounding box of the text, and the width and height of the
// bounding box is returned.
func (c Canvas) FillString(s string, x, y int) (width, height int) {
	img := c.font.draw(s, c.color())
	tex := texFromImage(c.win.rend, img)
	defer C.SDL_DestroyTexture(tex)
	b := img.Bounds()
	w, h := b.Dx(), b.Dy()
	dst := image.Rect(x, y, x+w, y+h)
	if C.SDL_RenderCopy(c.win.rend, tex, nil, sdlRect(&dst)) < 0 {
		panic(sdlError())
	}
	return w, h
}

func texFromImage(rend *C.SDL_Renderer, img *image.NRGBA) *C.SDL_Texture {
	b := img.Bounds()
	w, h := b.Dx(), b.Dy()
	fmt := C.SDL_PIXELFORMAT_ABGR8888
	acc := C.SDL_TEXTUREACCESS_STATIC
	tex := C.SDL_CreateTexture(rend, C.Uint32(fmt), C.int(acc), C.int(w), C.int(h))
	if tex == nil {
		panic(sdlError())
	}
	if C.SDL_UpdateTexture(tex, nil, unsafe.Pointer(&img.Pix[0]), C.int(img.Stride)) < 0 {
		panic(sdlError())
	}
	if C.SDL_SetTextureBlendMode(tex, C.SDL_BLENDMODE_BLEND) < 0 {
		panic(sdlError())
	}
	return tex
}

func loadPNG(path string) *image.NRGBA {
	r, err := os.Open(path)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	img, err := png.Decode(r)
	if err != nil {
		panic(err)
	}
	return img.(*image.NRGBA)
}
<|endoftext|>


<commit_before>package filefixture

import (
	"archive/tar"
	"bytes"
	"fmt"
	"strings"
	"time"

	"polydawn.net/repeatr/lib/fs"
)

type FixtureFile struct {
	Metadata fs.Metadata
	Body     []byte
}

type Fixture struct {
	Name  string
	Files []FixtureFile
}

type ComparisonOptions uint32

const (
	ComparePerms = ComparisonOptions(0001)
	CompareMtime = ComparisonOptions(0002)
	CompareAtime = ComparisonOptions(0004)
	CompareUid   = ComparisonOptions(0010)
	CompareGid   = ComparisonOptions(0020)
	CompareSize  = ComparisonOptions(0040)
	CompareBody  = ComparisonOptions(0100)

	CompareDefaults = ComparePerms | CompareMtime | CompareUid | CompareGid |
		CompareSize | CompareBody
	CompareAll = CompareDefaults | CompareAtime
)

func (f Fixture) defaults() Fixture {
	for i, ff := range f.Files {
		f.Files[i] = defaults(ff)
	}
	return f
}

func defaults(f FixtureFile) FixtureFile {
	if f.Metadata.Typeflag == '\x00' {
		if f.Body == nil {
			f.Metadata.Typeflag = tar.TypeDir
		} else {
			f.Metadata.Typeflag = tar.TypeReg
		}
	}
	if f.Metadata.Mode == 0 {
		switch f.Metadata.Typeflag {
		case tar.TypeDir:
			f.Metadata.Mode = 0755
		default:
			f.Metadata.Mode = 0644
		}
	}
	if f.Metadata.Size == 0 {
		f.Metadata.Size = int64(len(f.Body))
	}
	if f.Metadata.Uid == 0 {
		f.Metadata.Uid = 10000
	}
	if f.Metadata.Gid == 0 {
		f.Metadata.Gid = 10000
	}
	if f.Metadata.ModTime.IsZero() {
		f.Metadata.ModTime = time.Unix(0, 0).UTC()
	}
	if f.Metadata.AccessTime.IsZero() {
		f.Metadata.AccessTime = time.Unix(0, 0).UTC()
	}
	return f
}

/*
	Create files described by the fixtures on the real filesystem path given.
*/
func (ffs Fixture) Create(basePath string) {
	for _, f := range ffs.Files {
		fs.PlaceFile(basePath, f.Metadata, bytes.NewBuffer(f.Body))
	}
}

/*
	Scan a real filesystem and see it as fixture file descriptions.
	Usually used as a prelude to a pair of `Describe` calls followed by
	an equality assertion.

	Note that this loads all file bodies into memory at once, so it
	is not wise to use on large filesystems.

	Result will be sorted by filename, as per usual.
*/
func Scan(basePath string) Fixture {
	return Fixture{} // TODO
}

/*
	Produces a string where every line describes a one entry in the
	set of file descriptions.  This is useful for handing into "ShouldResemble"
	assertions, which will not only pass/fail but do character diffs which
	effectively cover the whole structure in one shot.

*/
func (ffs Fixture) Describe(opts ComparisonOptions) string {
	lines := make([]string, len(ffs.Files))
	for i, f := range ffs.Files {
		lines[i] = f.Describe(opts)
	}
	return strings.Join(lines, "\n")
}

/*
	As per `FixtureFiles.Describe`, but this is for a single entry.
*/
func (ff FixtureFile) Describe(opts ComparisonOptions) string {
	parts := []struct {
		Key   string
		Value interface{}
	}{
		{"Name:%q", ff.Metadata.Name},
		{"Type:%q", ff.Metadata.Typeflag},
		{"Perms:%q", ff.Metadata.FileMode()},
		{"Mtime:%q", ff.Metadata.ModTime},
		{"Atime:%q", ff.Metadata.AccessTime},
		{"Uid:%d", ff.Metadata.Uid},
		{"Gid:%d", ff.Metadata.Gid},
		{"DM:%d", ff.Metadata.Devmajor},
		{"Dm:%d", ff.Metadata.Devminor},
		{"Link:%q", ff.Metadata.Linkname},
		{"Size:%d", ff.Metadata.Size},
		{"Body:%q", ff.Body},
	}
	// my kingdom for a ternary operator
	if opts&ComparePerms == 0 {
		parts[2].Value = "-"
	}
	if opts&CompareMtime == 0 {
		parts[3].Value = "-"
	}
	if opts&CompareAtime == 0 {
		parts[4].Value = "-"
	}
	if opts&CompareUid == 0 {
		parts[5].Value = "-"
	}
	if opts&CompareGid == 0 {
		parts[6].Value = "-"
	}
	if opts&CompareSize == 0 {
		parts[10].Value = "-"
	}
	if opts&CompareBody == 0 {
		parts[11].Value = "-"
	}
	var pattern string
	var values []interface{}
	for _, part := range parts {
		pattern += "\t" + part.Key
		values = append(values, part.Value)
	}
	return fmt.Sprintf(pattern, values...)
}
<commit_msg>you cannae stop mae<commit_after>package filefixture

import (
	"archive/tar"
	"bytes"
	"fmt"
	"strings"
	"time"

	"polydawn.net/repeatr/lib/fs"
)

type FixtureFile struct {
	Metadata fs.Metadata
	Body     []byte
}

type Fixture struct {
	Name  string
	Files []FixtureFile
}

type ComparisonOptions uint32

const (
	ComparePerms = ComparisonOptions(0001)
	CompareMtime = ComparisonOptions(0002)
	CompareAtime = ComparisonOptions(0004)
	CompareUid   = ComparisonOptions(0010)
	CompareGid   = ComparisonOptions(0020)
	CompareSize  = ComparisonOptions(0040)
	CompareBody  = ComparisonOptions(0100)

	CompareDefaults = ComparePerms | CompareMtime | CompareUid | CompareGid |
		CompareSize | CompareBody
	CompareAll = CompareDefaults | CompareAtime
)

func (f Fixture) defaults() Fixture {
	for i, ff := range f.Files {
		f.Files[i] = defaults(ff)
	}
	return f
}

func defaults(f FixtureFile) FixtureFile {
	if f.Metadata.Typeflag == '\x00' {
		if f.Body == nil {
			f.Metadata.Typeflag = tar.TypeDir
		} else {
			f.Metadata.Typeflag = tar.TypeReg
		}
	}
	if f.Metadata.Mode == 0 {
		switch f.Metadata.Typeflag {
		case tar.TypeDir:
			f.Metadata.Mode = 0755
		default:
			f.Metadata.Mode = 0644
		}
	}
	if f.Metadata.Size == 0 {
		f.Metadata.Size = int64(len(f.Body))
	}
	if f.Metadata.Uid == 0 {
		f.Metadata.Uid = 10000
	}
	if f.Metadata.Gid == 0 {
		f.Metadata.Gid = 10000
	}
	if f.Metadata.ModTime.IsZero() {
		f.Metadata.ModTime = time.Unix(0, 0).UTC()
	}
	if f.Metadata.AccessTime.IsZero() {
		f.Metadata.AccessTime = time.Unix(0, 0).UTC()
	}
	return f
}

/*
	Create files described by the fixtures on the real filesystem path given.
*/
func (ffs Fixture) Create(basePath string) {
	for _, f := range ffs.Files {
		fs.PlaceFile(basePath, f.Metadata, bytes.NewBuffer(f.Body))
	}
}

/*
	Scan a real filesystem and see it as fixture file descriptions.
	Usually used as a prelude to a pair of `Describe` calls followed by
	an equality assertion.

	Note that this loads all file bodies into memory at once, so it
	is not wise to use on large filesystems.

	Result will be sorted by filename, as per usual.
*/
func Scan(basePath string) Fixture {
	return Fixture{} // TODO
}

/*
	Produces a string where every line describes a one entry in the
	set of file descriptions.  This is useful for handing into "ShouldResemble"
	assertions, which will not only pass/fail but do character diffs which
	effectively cover the whole structure in one shot.

*/
func (ffs Fixture) Describe(opts ComparisonOptions) string {
	lines := make([]string, len(ffs.Files))
	for i, f := range ffs.Files {
		lines[i] = f.Describe(opts)
	}
	return strings.Join(lines, "\n")
}

/*
	As per `FixtureFiles.Describe`, but this is for a single entry.
*/
func (ff FixtureFile) Describe(opts ComparisonOptions) string {
	parts := []struct {
		Key   string
		Value interface{}
	}{
		{"Name:%q", ff.Metadata.Name},
		{"Type:%q", ff.Metadata.Typeflag},
		{"Perms:%q", (map[bool]interface{}{true: "-", false: ff.Metadata.FileMode()})[opts&ComparePerms == 0]},
		{"Mtime:%q", (map[bool]interface{}{true: "-", false: ff.Metadata.ModTime})[opts&CompareMtime == 0]},
		{"Atime:%q", (map[bool]interface{}{true: "-", false: ff.Metadata.AccessTime})[opts&CompareAtime == 0]},
		{"Uid:%d", (map[bool]interface{}{true: "-", false: ff.Metadata.Uid})[opts&CompareUid == 0]},
		{"Gid:%d", (map[bool]interface{}{true: "-", false: ff.Metadata.Gid})[opts&CompareGid == 0]},
		{"DM:%d", ff.Metadata.Devmajor},
		{"Dm:%d", ff.Metadata.Devminor},
		{"Link:%q", ff.Metadata.Linkname},
		{"Size:%d", (map[bool]interface{}{true: "-", false: ff.Metadata.Size})[opts&CompareSize == 0]},
		{"Body:%q", (map[bool]interface{}{true: "-", false: ff.Body})[opts&CompareBody == 0]},
	}
	var pattern string
	var values []interface{}
	for _, part := range parts {
		pattern += "\t" + part.Key
		values = append(values, part.Value)
	}
	return fmt.Sprintf(pattern, values...)
}
<|endoftext|>


<commit_before>// +build go1.9

// Copyright 2018 Microsoft Corporation
//
// 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.

// This code was auto-generated by:
// github.com/Azure/azure-sdk-for-go/tools/profileBuilder

package trafficmanager

import original "github.com/Azure/azure-sdk-for-go/services/trafficmanager/mgmt/2017-09-01-preview/trafficmanager"

const (
	DefaultBaseURI = original.DefaultBaseURI
)

type BaseClient = original.BaseClient
type EndpointsClient = original.EndpointsClient
type GeographicHierarchiesClient = original.GeographicHierarchiesClient
type HeatMapClient = original.HeatMapClient
type EndpointMonitorStatus = original.EndpointMonitorStatus

const (
	CheckingEndpoint EndpointMonitorStatus = original.CheckingEndpoint
	Degraded         EndpointMonitorStatus = original.Degraded
	Disabled         EndpointMonitorStatus = original.Disabled
	Inactive         EndpointMonitorStatus = original.Inactive
	Online           EndpointMonitorStatus = original.Online
	Stopped          EndpointMonitorStatus = original.Stopped
)

type EndpointStatus = original.EndpointStatus

const (
	EndpointStatusDisabled EndpointStatus = original.EndpointStatusDisabled
	EndpointStatusEnabled  EndpointStatus = original.EndpointStatusEnabled
)

type MonitorProtocol = original.MonitorProtocol

const (
	HTTP  MonitorProtocol = original.HTTP
	HTTPS MonitorProtocol = original.HTTPS
	TCP   MonitorProtocol = original.TCP
)

type ProfileMonitorStatus = original.ProfileMonitorStatus

const (
	ProfileMonitorStatusCheckingEndpoints ProfileMonitorStatus = original.ProfileMonitorStatusCheckingEndpoints
	ProfileMonitorStatusDegraded          ProfileMonitorStatus = original.ProfileMonitorStatusDegraded
	ProfileMonitorStatusDisabled          ProfileMonitorStatus = original.ProfileMonitorStatusDisabled
	ProfileMonitorStatusInactive          ProfileMonitorStatus = original.ProfileMonitorStatusInactive
	ProfileMonitorStatusOnline            ProfileMonitorStatus = original.ProfileMonitorStatusOnline
)

type ProfileStatus = original.ProfileStatus

const (
	ProfileStatusDisabled ProfileStatus = original.ProfileStatusDisabled
	ProfileStatusEnabled  ProfileStatus = original.ProfileStatusEnabled
)

type TrafficRoutingMethod = original.TrafficRoutingMethod

const (
	Geographic  TrafficRoutingMethod = original.Geographic
	Performance TrafficRoutingMethod = original.Performance
	Priority    TrafficRoutingMethod = original.Priority
	Weighted    TrafficRoutingMethod = original.Weighted
)

type CheckTrafficManagerRelativeDNSNameAvailabilityParameters = original.CheckTrafficManagerRelativeDNSNameAvailabilityParameters
type CloudError = original.CloudError
type CloudErrorBody = original.CloudErrorBody
type DeleteOperationResult = original.DeleteOperationResult
type DNSConfig = original.DNSConfig
type Endpoint = original.Endpoint
type EndpointProperties = original.EndpointProperties
type GeographicHierarchy = original.GeographicHierarchy
type GeographicHierarchyProperties = original.GeographicHierarchyProperties
type HeatMapEndpoint = original.HeatMapEndpoint
type HeatMapModel = original.HeatMapModel
type HeatMapProperties = original.HeatMapProperties
type MonitorConfig = original.MonitorConfig
type NameAvailability = original.NameAvailability
type Profile = original.Profile
type ProfileListResult = original.ProfileListResult
type ProfileProperties = original.ProfileProperties
type ProxyResource = original.ProxyResource
type QueryExperience = original.QueryExperience
type Region = original.Region
type Resource = original.Resource
type TrackedResource = original.TrackedResource
type TrafficFlow = original.TrafficFlow
type UserMetricsKeyModel = original.UserMetricsKeyModel
type ProfilesClient = original.ProfilesClient
type UserMetricsKeysClient = original.UserMetricsKeysClient

func New(subscriptionID string) BaseClient {
	return original.New(subscriptionID)
}
func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient {
	return original.NewWithBaseURI(baseURI, subscriptionID)
}
func NewEndpointsClient(subscriptionID string) EndpointsClient {
	return original.NewEndpointsClient(subscriptionID)
}
func NewEndpointsClientWithBaseURI(baseURI string, subscriptionID string) EndpointsClient {
	return original.NewEndpointsClientWithBaseURI(baseURI, subscriptionID)
}
func NewGeographicHierarchiesClient(subscriptionID string) GeographicHierarchiesClient {
	return original.NewGeographicHierarchiesClient(subscriptionID)
}
func NewGeographicHierarchiesClientWithBaseURI(baseURI string, subscriptionID string) GeographicHierarchiesClient {
	return original.NewGeographicHierarchiesClientWithBaseURI(baseURI, subscriptionID)
}
func NewHeatMapClient(subscriptionID string) HeatMapClient {
	return original.NewHeatMapClient(subscriptionID)
}
func NewHeatMapClientWithBaseURI(baseURI string, subscriptionID string) HeatMapClient {
	return original.NewHeatMapClientWithBaseURI(baseURI, subscriptionID)
}
func PossibleEndpointMonitorStatusValues() []EndpointMonitorStatus {
	return original.PossibleEndpointMonitorStatusValues()
}
func PossibleEndpointStatusValues() []EndpointStatus {
	return original.PossibleEndpointStatusValues()
}
func PossibleMonitorProtocolValues() []MonitorProtocol {
	return original.PossibleMonitorProtocolValues()
}
func PossibleProfileMonitorStatusValues() []ProfileMonitorStatus {
	return original.PossibleProfileMonitorStatusValues()
}
func PossibleProfileStatusValues() []ProfileStatus {
	return original.PossibleProfileStatusValues()
}
func PossibleTrafficRoutingMethodValues() []TrafficRoutingMethod {
	return original.PossibleTrafficRoutingMethodValues()
}
func NewProfilesClient(subscriptionID string) ProfilesClient {
	return original.NewProfilesClient(subscriptionID)
}
func NewProfilesClientWithBaseURI(baseURI string, subscriptionID string) ProfilesClient {
	return original.NewProfilesClientWithBaseURI(baseURI, subscriptionID)
}
func NewUserMetricsKeysClient(subscriptionID string) UserMetricsKeysClient {
	return original.NewUserMetricsKeysClient(subscriptionID)
}
func NewUserMetricsKeysClientWithBaseURI(baseURI string, subscriptionID string) UserMetricsKeysClient {
	return original.NewUserMetricsKeysClientWithBaseURI(baseURI, subscriptionID)
}
func UserAgent() string {
	return original.UserAgent() + " profiles/preview"
}
func Version() string {
	return original.Version()
}
<commit_msg>Generated from 1f98e6e0bf2913694871fc8d13a644054a6879af (#1783) (#1785)<commit_after>// +build go1.9

// Copyright 2018 Microsoft Corporation
//
// 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.

// This code was auto-generated by:
// github.com/Azure/azure-sdk-for-go/tools/profileBuilder

package trafficmanager

import original "github.com/Azure/azure-sdk-for-go/services/trafficmanager/mgmt/2018-03-01/trafficmanager"

const (
	DefaultBaseURI = original.DefaultBaseURI
)

type BaseClient = original.BaseClient
type EndpointsClient = original.EndpointsClient
type GeographicHierarchiesClient = original.GeographicHierarchiesClient
type HeatMapClient = original.HeatMapClient
type EndpointMonitorStatus = original.EndpointMonitorStatus

const (
	CheckingEndpoint EndpointMonitorStatus = original.CheckingEndpoint
	Degraded         EndpointMonitorStatus = original.Degraded
	Disabled         EndpointMonitorStatus = original.Disabled
	Inactive         EndpointMonitorStatus = original.Inactive
	Online           EndpointMonitorStatus = original.Online
	Stopped          EndpointMonitorStatus = original.Stopped
)

type EndpointStatus = original.EndpointStatus

const (
	EndpointStatusDisabled EndpointStatus = original.EndpointStatusDisabled
	EndpointStatusEnabled  EndpointStatus = original.EndpointStatusEnabled
)

type MonitorProtocol = original.MonitorProtocol

const (
	HTTP  MonitorProtocol = original.HTTP
	HTTPS MonitorProtocol = original.HTTPS
	TCP   MonitorProtocol = original.TCP
)

type ProfileMonitorStatus = original.ProfileMonitorStatus

const (
	ProfileMonitorStatusCheckingEndpoints ProfileMonitorStatus = original.ProfileMonitorStatusCheckingEndpoints
	ProfileMonitorStatusDegraded          ProfileMonitorStatus = original.ProfileMonitorStatusDegraded
	ProfileMonitorStatusDisabled          ProfileMonitorStatus = original.ProfileMonitorStatusDisabled
	ProfileMonitorStatusInactive          ProfileMonitorStatus = original.ProfileMonitorStatusInactive
	ProfileMonitorStatusOnline            ProfileMonitorStatus = original.ProfileMonitorStatusOnline
)

type ProfileStatus = original.ProfileStatus

const (
	ProfileStatusDisabled ProfileStatus = original.ProfileStatusDisabled
	ProfileStatusEnabled  ProfileStatus = original.ProfileStatusEnabled
)

type TrafficRoutingMethod = original.TrafficRoutingMethod

const (
	Geographic  TrafficRoutingMethod = original.Geographic
	Performance TrafficRoutingMethod = original.Performance
	Priority    TrafficRoutingMethod = original.Priority
	Weighted    TrafficRoutingMethod = original.Weighted
)

type CheckTrafficManagerRelativeDNSNameAvailabilityParameters = original.CheckTrafficManagerRelativeDNSNameAvailabilityParameters
type CloudError = original.CloudError
type CloudErrorBody = original.CloudErrorBody
type DeleteOperationResult = original.DeleteOperationResult
type DNSConfig = original.DNSConfig
type Endpoint = original.Endpoint
type EndpointProperties = original.EndpointProperties
type EndpointPropertiesCustomHeadersItem = original.EndpointPropertiesCustomHeadersItem
type GeographicHierarchy = original.GeographicHierarchy
type GeographicHierarchyProperties = original.GeographicHierarchyProperties
type HeatMapEndpoint = original.HeatMapEndpoint
type HeatMapModel = original.HeatMapModel
type HeatMapProperties = original.HeatMapProperties
type MonitorConfig = original.MonitorConfig
type MonitorConfigCustomHeadersItem = original.MonitorConfigCustomHeadersItem
type MonitorConfigExpectedStatusCodeRangesItem = original.MonitorConfigExpectedStatusCodeRangesItem
type NameAvailability = original.NameAvailability
type Profile = original.Profile
type ProfileListResult = original.ProfileListResult
type ProfileProperties = original.ProfileProperties
type ProxyResource = original.ProxyResource
type QueryExperience = original.QueryExperience
type Region = original.Region
type Resource = original.Resource
type TrackedResource = original.TrackedResource
type TrafficFlow = original.TrafficFlow
type ProfilesClient = original.ProfilesClient

func New(subscriptionID string) BaseClient {
	return original.New(subscriptionID)
}
func NewWithBaseURI(baseURI string, subscriptionID string) BaseClient {
	return original.NewWithBaseURI(baseURI, subscriptionID)
}
func NewEndpointsClient(subscriptionID string) EndpointsClient {
	return original.NewEndpointsClient(subscriptionID)
}
func NewEndpointsClientWithBaseURI(baseURI string, subscriptionID string) EndpointsClient {
	return original.NewEndpointsClientWithBaseURI(baseURI, subscriptionID)
}
func NewGeographicHierarchiesClient(subscriptionID string) GeographicHierarchiesClient {
	return original.NewGeographicHierarchiesClient(subscriptionID)
}
func NewGeographicHierarchiesClientWithBaseURI(baseURI string, subscriptionID string) GeographicHierarchiesClient {
	return original.NewGeographicHierarchiesClientWithBaseURI(baseURI, subscriptionID)
}
func NewHeatMapClient(subscriptionID string) HeatMapClient {
	return original.NewHeatMapClient(subscriptionID)
}
func NewHeatMapClientWithBaseURI(baseURI string, subscriptionID string) HeatMapClient {
	return original.NewHeatMapClientWithBaseURI(baseURI, subscriptionID)
}
func PossibleEndpointMonitorStatusValues() []EndpointMonitorStatus {
	return original.PossibleEndpointMonitorStatusValues()
}
func PossibleEndpointStatusValues() []EndpointStatus {
	return original.PossibleEndpointStatusValues()
}
func PossibleMonitorProtocolValues() []MonitorProtocol {
	return original.PossibleMonitorProtocolValues()
}
func PossibleProfileMonitorStatusValues() []ProfileMonitorStatus {
	return original.PossibleProfileMonitorStatusValues()
}
func PossibleProfileStatusValues() []ProfileStatus {
	return original.PossibleProfileStatusValues()
}
func PossibleTrafficRoutingMethodValues() []TrafficRoutingMethod {
	return original.PossibleTrafficRoutingMethodValues()
}
func NewProfilesClient(subscriptionID string) ProfilesClient {
	return original.NewProfilesClient(subscriptionID)
}
func NewProfilesClientWithBaseURI(baseURI string, subscriptionID string) ProfilesClient {
	return original.NewProfilesClientWithBaseURI(baseURI, subscriptionID)
}
func UserAgent() string {
	return original.UserAgent() + " profiles/preview"
}
func Version() string {
	return original.Version()
}
<|endoftext|>


<commit_before>package dht

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

var configFilePrefix string

func init() {
	configFilePrefix = mkdirStore()
}

// mkdirStore() creates a directory to load and save the configuration from.
// Uses ~/.taipeitorrent if $HOME is set, otherwise falls back to
// /var/run/taipeitorrent. It's very much UNIX only at the moment, but making
// it generic should be fairly easy.
func mkdirStore() string {
	dir := "/var/run/taipeitorrent"
	env := os.Environ()
	for _, e := range env {
		if strings.HasPrefix(e, "HOME=") {
			dir = strings.SplitN(e, "=", 2)[1] + "/.taipeitorrent"
		}
	}
	// Ignore errors.
	os.Mkdir(dir, 0750)

	if s, err := os.Stat(dir); err != nil {
		log.Fatal("stat config dir", err)
	} else if !s.IsDir() {
		log.Fatalf("Dir %v expected directory, got %v", dir, s)
	}
	return dir
}

type DHTStore struct {
	// The rest of the stack uses string, but that confuses the json
	// Marshaller. []byte is more correct anyway.
	Id      []byte
	Port    int
	Remotes map[string][]byte // Key: IP, Value: node ID.
}

func openStore(port int) (cfg *DHTStore) {
	cfg = &DHTStore{}

	// If a node is running in port 30610, the config should be in
	// ~/.taipeitorrent/dht-36010
	p := fmt.Sprintf("%v-%v", configFilePrefix+"/dht", port)
	f, err := os.Open(p)
	if err != nil {
		// log.Println(err)
		return cfg
	}
	defer f.Close()

	if err = json.NewDecoder(f).Decode(cfg); err != nil {
		log.Println(err)
	}
	return
}

// saveStore tries to safe the provided config in a safe way.
func saveStore(s DHTStore) {

	tmp, err := ioutil.TempFile(configFilePrefix, "taipeitorrent")
	if err != nil {
		log.Println("saveStore tempfile:", err)
		return
	}
	defer tmp.Close()

	enc := json.NewEncoder(tmp)
	if err = enc.Encode(s); err != nil {
		log.Println("saveStore json encoding:", err)
		return
	}

	// Write worked, so now we can replace the existing file, which is atomic AFAIK.
	p := fmt.Sprintf("%v-%v", configFilePrefix+"/dht", s.Port)
	if err := os.Rename(tmp.Name(), p); err != nil {
		log.Println("saveStore failed when replacing existing config:", err)
	}
	log.Println("Saved DHT routing table to the filesystem.")
}
<commit_msg>DHT config store, Win support<commit_after>package dht

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"strings"
)

var configFilePrefix string

func init() {
	configFilePrefix = mkdirStore()
}

// mkdirStore() creates a directory to load and save the configuration from.
// Uses ~/.taipeitorrent if $HOME is set, otherwise falls back to
// /var/run/taipeitorrent.
func mkdirStore() string {
	dir := "/var/run/taipeitorrent"
	env := os.Environ()
	for _, e := range env {
		if strings.HasPrefix(e, "HOME=") {
			dir = strings.SplitN(e, "=", 2)[1]
			dir = path.Join(dir, ".taipeitorrent")
		}
	}
	// Ignore errors.
	os.MkdirAll(dir, 0750)

	if s, err := os.Stat(dir); err != nil {
		log.Fatal("stat config dir", err)
	} else if !s.IsDir() {
		log.Fatalf("Dir %v expected directory, got %v", dir, s)
	}
	return dir
}

type DHTStore struct {
	// The rest of the stack uses string, but that confuses the json
	// Marshaller. []byte is more correct anyway.
	Id      []byte
	Port    int
	Remotes map[string][]byte // Key: IP, Value: node ID.
}

func openStore(port int) (cfg *DHTStore) {
	cfg = &DHTStore{}

	// If a node is running in port 30610, the config should be in
	// ~/.taipeitorrent/dht-36010
	p := fmt.Sprintf("%v-%v", path.Join(configFilePrefix, "dht"), port)
	f, err := os.Open(p)
	if err != nil {
		// log.Println(err)
		return cfg
	}
	defer f.Close()

	if err = json.NewDecoder(f).Decode(cfg); err != nil {
		log.Println(err)
	}
	return
}

// saveStore tries to safe the provided config in a safe way.
func saveStore(s DHTStore) {

	tmp, err := ioutil.TempFile(configFilePrefix, "taipeitorrent")
	if err != nil {
		log.Println("saveStore tempfile:", err)
		return
	}
	err = json.NewEncoder(tmp).Encode(s)
	// The file has to be closed already otherwise it can't be renamed on
	// Windows.
	tmp.Close()
	if err != nil {
		log.Println("saveStore json encoding:", err)
		return
	}

	// Write worked, so replace the existing file. That's atomic in Linux, but
	// not on Windows.
	p := fmt.Sprintf("%v-%v", configFilePrefix+"/dht", s.Port)
	if err := os.Rename(tmp.Name(), p); err != nil {
		// if os.IsExist(err) {
		// Not working for Windows:
		// http://code.google.com/p/go/issues/detail?id=3828

		// It's not possible to atomically rename files on Windows, so I
		// have to delete it and try again. If the program crashes between
		// the unlink and the rename operation, it lose the configuration,
		// unfortunately.
		if err := os.Remove(p); err != nil {
			log.Println("saveStore failed to remove the existing config:", err)
			return
		}
		if err := os.Rename(tmp.Name(), p); err != nil {
			log.Println("saveStore failed to rename file after deleting the original config:", err)
			return
		}
		// } else {
		// 	log.Println("saveStore failed when replacing existing config:", err)
		// }
	} else {
		log.Println("Saved DHT routing table to the filesystem.")
	}
}
<|endoftext|>


<commit_before>package onpar_test

import (
	"reflect"
	"testing"

	"github.com/apoydence/onpar"
)

func TestSingleNestedSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	if len(objs) != 3 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objs), 3)
	}

	objA := findSpec(objs, "DA-A")
	if objA == nil {
		t.Fatal("unable to find spec A")
	}

	if len(objA.c) != 4 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objA.c), 4)
	}

	if !reflect.DeepEqual(objA.c, []string{"-BeforeEach", "DA-A", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objA.c)
	}
}

func TestInvokeFirstChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objB := findSpec(objs, "DB-B")
	if objB == nil {
		t.Fatal("unable to find spec B")
	}

	if len(objB.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objB.c), 6)
	}

	if !reflect.DeepEqual(objB.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-B", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objB.c)
	}
}

func TestInvokeSecondChildAndPeerSpec(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objC := findSpec(objs, "DB-C")
	if objC == nil {
		t.Fatal("unable to find spec C")
	}

	if len(objC.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objC.c), 6)
	}

	if !reflect.DeepEqual(objC.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-C", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objC.c)
	}
}

func TestDoNotInvokeStrandedBeforeEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-BeforeEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked BeforeEach")
	}
}

func TestDoNotInvokeStrandedAfterEach(t *testing.T) {
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-AfterEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked AfterEach")
	}
}

func createScaffolding() (*onpar.Onpar, <-chan *testObject) {
	o := onpar.New()
	objs := make(chan *testObject, 100)

	o.BeforeEach(func(t *testing.T) (int, string, *testObject) {
		obj := NewTestObject()
		obj.Use("-BeforeEach")

		objs <- obj

		return 99, "something", obj
	})

	o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
		o.Use("-AfterEach")
	})

	o.Group("DA", func() {
		o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-AfterEach")
			o.Close()
		})

		o.Spec("A", func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-A")
		})

		o.Group("DB", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) float64 {
				o.Use("DB-BeforeEach")
				return 101
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-AfterEach")
			})

			o.Spec("B", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-B")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})

			o.Spec("C", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-C")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})
		})

		o.Group("DC", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-BeforeEach")
				t.Fatalf("should not have been invoked")
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-AfterEach")
				t.Fatalf("should not have been invoked")
			})
		})
	})

	return o, objs
}

func chanToSlice(c <-chan *testObject) []*testObject {
	var results []*testObject
	l := len(c)
	for i := 0; i < l; i++ {
		results = append(results, <-c)
	}
	return results
}

func findSpec(objs []*testObject, name string) *testObject {
	for _, obj := range objs {
		for _, specName := range obj.c {
			if name == specName {
				return obj
			}
		}
	}
	return nil
}

type testObject struct {
	c    []string
	done bool
}

func NewTestObject() *testObject {
	return &testObject{
		c: make([]string, 0),
	}
}

func (t *testObject) Use(i string) {
	t.c = append(t.c, i)
}

func (t *testObject) Close() {
	if t.done {
		panic("close() called too many times")
	}
	t.done = true
}
<commit_msg>Sets t.Parallel() for tests<commit_after>package onpar_test

import (
	"reflect"
	"testing"

	"github.com/apoydence/onpar"
)

func TestSingleNestedSpec(t *testing.T) {
	t.Parallel()
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	if len(objs) != 3 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objs), 3)
	}

	objA := findSpec(objs, "DA-A")
	if objA == nil {
		t.Fatal("unable to find spec A")
	}

	if len(objA.c) != 4 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objA.c), 4)
	}

	if !reflect.DeepEqual(objA.c, []string{"-BeforeEach", "DA-A", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objA.c)
	}
}

func TestInvokeFirstChildAndPeerSpec(t *testing.T) {
	t.Parallel()
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objB := findSpec(objs, "DB-B")
	if objB == nil {
		t.Fatal("unable to find spec B")
	}

	if len(objB.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objB.c), 6)
	}

	if !reflect.DeepEqual(objB.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-B", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objB.c)
	}
}

func TestInvokeSecondChildAndPeerSpec(t *testing.T) {
	t.Parallel()
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objC := findSpec(objs, "DB-C")
	if objC == nil {
		t.Fatal("unable to find spec C")
	}

	if len(objC.c) != 6 {
		t.Fatalf("expected objs (len=%d) to have len %d", len(objC.c), 6)
	}

	if !reflect.DeepEqual(objC.c, []string{"-BeforeEach", "DB-BeforeEach", "DB-C", "DB-AfterEach", "DA-AfterEach", "-AfterEach"}) {
		t.Fatalf("invalid call order for spec A: %v", objC.c)
	}
}

func TestDoNotInvokeStrandedBeforeEach(t *testing.T) {
	t.Parallel()
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-BeforeEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked BeforeEach")
	}
}

func TestDoNotInvokeStrandedAfterEach(t *testing.T) {
	t.Parallel()
	o, c := createScaffolding()

	t.Run("FakeSpecs", func(tt *testing.T) {
		o.Run(tt)
	})
	objs := chanToSlice(c)

	objCBeforeEach := findSpec(objs, "DC-AfterEach")
	if objCBeforeEach != nil {
		t.Fatal("should not have invoked AfterEach")
	}
}

func createScaffolding() (*onpar.Onpar, <-chan *testObject) {
	o := onpar.New()
	objs := make(chan *testObject, 100)

	o.BeforeEach(func(t *testing.T) (int, string, *testObject) {
		obj := NewTestObject()
		obj.Use("-BeforeEach")

		objs <- obj

		return 99, "something", obj
	})

	o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
		o.Use("-AfterEach")
	})

	o.Group("DA", func() {
		o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-AfterEach")
			o.Close()
		})

		o.Spec("A", func(t *testing.T, i int, s string, o *testObject) {
			if i != 99 {
				t.Fatalf("expected %d = %d", i, 99)
			}

			if s != "something" {
				t.Fatalf("expected %s = %s", s, "something")
			}

			o.Use("DA-A")
		})

		o.Group("DB", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) float64 {
				o.Use("DB-BeforeEach")
				return 101
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-AfterEach")
			})

			o.Spec("B", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-B")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})

			o.Spec("C", func(t *testing.T, i int, s string, o *testObject, f float64) {
				o.Use("DB-C")
				if i != 99 {
					t.Fatalf("expected %d = %d", i, 99)
				}

				if s != "something" {
					t.Fatalf("expected %s = %s", s, "something")
				}

				if f != 101 {
					t.Fatalf("expected %f = %f", f, 101.0)
				}
			})
		})

		o.Group("DC", func() {
			o.BeforeEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-BeforeEach")
				t.Fatalf("should not have been invoked")
			})

			o.AfterEach(func(t *testing.T, i int, s string, o *testObject) {
				o.Use("DC-AfterEach")
				t.Fatalf("should not have been invoked")
			})
		})
	})

	return o, objs
}

func chanToSlice(c <-chan *testObject) []*testObject {
	var results []*testObject
	l := len(c)
	for i := 0; i < l; i++ {
		results = append(results, <-c)
	}
	return results
}

func findSpec(objs []*testObject, name string) *testObject {
	for _, obj := range objs {
		for _, specName := range obj.c {
			if name == specName {
				return obj
			}
		}
	}
	return nil
}

type testObject struct {
	c    []string
	done bool
}

func NewTestObject() *testObject {
	return &testObject{
		c: make([]string, 0),
	}
}

func (t *testObject) Use(i string) {
	t.c = append(t.c, i)
}

func (t *testObject) Close() {
	if t.done {
		panic("close() called too many times")
	}
	t.done = true
}
<|endoftext|>


<commit_before>package amazonec2

import (
	"errors"
)

type region struct {
	AmiId string
}

// Ubuntu 16.04 LTS 20180228.1 hvm:ebs-ssd (amd64)
// See https://cloud-images.ubuntu.com/locator/ec2/
var regionDetails map[string]*region = map[string]*region{
	"ap-northeast-1":  {"ami-bcb7f6da"},
	"ap-northeast-2":  {"ami-5073de3e"},
	"ap-southeast-1":  {"ami-41e4af3d"},
	"ap-southeast-2":  {"ami-c1498fa3"},
	"ap-south-1":      {"ami-1083dc7f"},
	"ca-central-1":    {"ami-8d9e19e9"},
	"cn-north-1":      {"ami-cc4499a1"}, // Note: this is 20180126
	"cn-northwest-1":  {"ami-fd0e1a9f"}, // Note: this is 20180126
	"eu-central-1":    {"ami-bc4925d3"},
	"eu-west-1":       {"ami-0b541372"},
	"eu-west-2":       {"ami-ff46a298"},
	"eu-west-3":       {"ami-9465d3e9"},
	"sa-east-1":       {"ami-b5501bd9"},
	"us-east-1":       {"ami-927185ef"},
	"us-east-2":       {"ami-b9daeddc"},
	"us-west-1":       {"ami-264c4646"},
	"us-west-2":       {"ami-78a22900"},
	"us-gov-west-1":   {"ami-2561ea44"},
	"custom-endpoint": {""},
}

func awsRegionsList() []string {
	var list []string

	for k := range regionDetails {
		list = append(list, k)
	}

	return list
}

func validateAwsRegion(region string) (string, error) {
	for _, v := range awsRegionsList() {
		if v == region {
			return region, nil
		}
	}

	return "", errors.New("Invalid region specified")
}
<commit_msg>Add AWS region eu-north-1<commit_after>package amazonec2

import (
	"errors"
)

type region struct {
	AmiId string
}

// Ubuntu 16.04 LTS 20180228.1 hvm:ebs-ssd (amd64)
// See https://cloud-images.ubuntu.com/locator/ec2/
var regionDetails map[string]*region = map[string]*region{
	"ap-northeast-1":  {"ami-bcb7f6da"},
	"ap-northeast-2":  {"ami-5073de3e"},
	"ap-southeast-1":  {"ami-41e4af3d"},
	"ap-southeast-2":  {"ami-c1498fa3"},
	"ap-south-1":      {"ami-1083dc7f"},
	"ca-central-1":    {"ami-8d9e19e9"},
	"cn-north-1":      {"ami-cc4499a1"}, // Note: this is 20180126
	"cn-northwest-1":  {"ami-fd0e1a9f"}, // Note: this is 20180126
	"eu-north-1":      {"ami-017ff17f"},
	"eu-central-1":    {"ami-bc4925d3"},
	"eu-west-1":       {"ami-0b541372"},
	"eu-west-2":       {"ami-ff46a298"},
	"eu-west-3":       {"ami-9465d3e9"},
	"sa-east-1":       {"ami-b5501bd9"},
	"us-east-1":       {"ami-927185ef"},
	"us-east-2":       {"ami-b9daeddc"},
	"us-west-1":       {"ami-264c4646"},
	"us-west-2":       {"ami-78a22900"},
	"us-gov-west-1":   {"ami-2561ea44"},
	"custom-endpoint": {""},
}

func awsRegionsList() []string {
	var list []string

	for k := range regionDetails {
		list = append(list, k)
	}

	return list
}

func validateAwsRegion(region string) (string, error) {
	for _, v := range awsRegionsList() {
		if v == region {
			return region, nil
		}
	}

	return "", errors.New("Invalid region specified")
}
<|endoftext|>


<commit_before>package core

import (
	bstk "github.com/OpenBazaar/go-blockstackclient"
	"github.com/OpenBazaar/openbazaar-go/bitcoin"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	"github.com/OpenBazaar/openbazaar-go/net"
	"github.com/OpenBazaar/openbazaar-go/repo"
	sto "github.com/OpenBazaar/openbazaar-go/storage"
	"github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/routing/dht"
	"github.com/op/go-logging"
	"golang.org/x/net/context"
	"gx/ipfs/QmRBqJF7hb8ZSpRcMwUt8hNhydWcxGEhtk81HKq6oUwKvs/go-libp2p-peer"
	"path"
)

var log = logging.MustGetLogger("core")

var Node *OpenBazaarNode

type OpenBazaarNode struct {
	// Context for issuing IPFS commands
	Context commands.Context

	// IPFS node object
	IpfsNode *core.IpfsNode

	// The roothash of the node directory inside the openbazaar repo.
	// This directory hash is published on IPNS at our peer ID making
	// the directory publicly viewable on the network.
	RootHash string

	// The path to the openbazaar repo in the file system.
	RepoPath string

	// The OpenBazaar network service for direct communication between peers
	Service net.NetworkService

	// Database for storing node specific data
	Datastore repo.Datastore

	// Websocket channel used for pushing data to the UI.
	Broadcast chan []byte

	// Bitcoin wallet implementation
	Wallet bitcoin.BitcoinWallet

	// Storage for our outgoing messages
	MessageStorage sto.OfflineMessagingStorage

	// A service that periodically checks the dht for outstanding messages
	MessageRetriever *net.MessageRetriever

	// A service that periodically republishes active pointers
	PointerRepublisher *net.PointerRepublisher

	// Used to resolve blockchainIDs to OpenBazaar IDs
	Resolver *bstk.BlockstackClient

	// A service that periodically fetches and caches the bitcoin exchange rates
	ExchangeRates bitcoin.ExchangeRates

	// TODO: Libsignal Client
}

// Unpin the current node repo, re-add it, then publish to ipns
func (n *OpenBazaarNode) SeedNode() error {
	if err := ipfs.UnPinDir(n.Context, n.RootHash); err != nil {
		return err
	}
	hash, aerr := ipfs.AddDirectory(n.Context, path.Join(n.RepoPath, "root"))
	if aerr != nil {
		return aerr
	}
	go n.publish(hash)
	return nil
}

func (n *OpenBazaarNode) publish(hash string) {
	n.Broadcast <- []byte(`{"status": "publishing"}`)
	_, err := ipfs.Publish(n.Context, hash)
	if err != nil {
		n.Broadcast <- []byte(`{"status": "error publishing"}`)
	} else {
		n.RootHash = hash
		n.Broadcast <- []byte(`{"status": "publish complete"}`)
	}
}

// This is a placeholder until the libsignal is operational
// For now we will just encrypt outgoing offline messages with the long lived identity key.
func (n *OpenBazaarNode) EncryptMessage(peerId peer.ID, message []byte) (ct []byte, rerr error) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	pubKey, err := n.IpfsNode.Routing.(*dht.IpfsDHT).GetPublicKey(ctx, peerId)
	if err != nil {
		log.Errorf("Failed to find public key for %s", peerId.Pretty())
		return nil, err
	}
	ciphertext, err := pubKey.Encrypt(message)
	if err != nil {
		return nil, err
	}
	return ciphertext, nil
}
<commit_msg>Move the unpin operation to after publish<commit_after>package core

import (
	bstk "github.com/OpenBazaar/go-blockstackclient"
	"github.com/OpenBazaar/openbazaar-go/bitcoin"
	"github.com/OpenBazaar/openbazaar-go/ipfs"
	"github.com/OpenBazaar/openbazaar-go/net"
	"github.com/OpenBazaar/openbazaar-go/repo"
	sto "github.com/OpenBazaar/openbazaar-go/storage"
	"github.com/ipfs/go-ipfs/commands"
	"github.com/ipfs/go-ipfs/core"
	"github.com/ipfs/go-ipfs/routing/dht"
	"github.com/op/go-logging"
	"golang.org/x/net/context"
	"gx/ipfs/QmRBqJF7hb8ZSpRcMwUt8hNhydWcxGEhtk81HKq6oUwKvs/go-libp2p-peer"
	"path"
)

var log = logging.MustGetLogger("core")

var Node *OpenBazaarNode

type OpenBazaarNode struct {
	// Context for issuing IPFS commands
	Context commands.Context

	// IPFS node object
	IpfsNode *core.IpfsNode

	// The roothash of the node directory inside the openbazaar repo.
	// This directory hash is published on IPNS at our peer ID making
	// the directory publicly viewable on the network.
	RootHash string

	// The path to the openbazaar repo in the file system.
	RepoPath string

	// The OpenBazaar network service for direct communication between peers
	Service net.NetworkService

	// Database for storing node specific data
	Datastore repo.Datastore

	// Websocket channel used for pushing data to the UI.
	Broadcast chan []byte

	// Bitcoin wallet implementation
	Wallet bitcoin.BitcoinWallet

	// Storage for our outgoing messages
	MessageStorage sto.OfflineMessagingStorage

	// A service that periodically checks the dht for outstanding messages
	MessageRetriever *net.MessageRetriever

	// A service that periodically republishes active pointers
	PointerRepublisher *net.PointerRepublisher

	// Used to resolve blockchainIDs to OpenBazaar IDs
	Resolver *bstk.BlockstackClient

	// A service that periodically fetches and caches the bitcoin exchange rates
	ExchangeRates bitcoin.ExchangeRates

	// TODO: Libsignal Client
}

// Unpin the current node repo, re-add it, then publish to ipns
func (n *OpenBazaarNode) SeedNode() error {
	hash, aerr := ipfs.AddDirectory(n.Context, path.Join(n.RepoPath, "root"))
	if aerr != nil {
		return aerr
	}
	go n.publish(hash)
	return nil
}

func (n *OpenBazaarNode) publish(hash string) {
	n.Broadcast <- []byte(`{"status": "publishing"}`)
	_, err := ipfs.Publish(n.Context, hash)
	perr := ipfs.UnPinDir(n.Context, n.RootHash)
	n.RootHash = hash
	if err != nil || perr != nil {
		n.Broadcast <- []byte(`{"status": "error publishing"}`)
	} else {
		n.Broadcast <- []byte(`{"status": "publish complete"}`)
	}

}

// This is a placeholder until the libsignal is operational
// For now we will just encrypt outgoing offline messages with the long lived identity key.
func (n *OpenBazaarNode) EncryptMessage(peerId peer.ID, message []byte) (ct []byte, rerr error) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	pubKey, err := n.IpfsNode.Routing.(*dht.IpfsDHT).GetPublicKey(ctx, peerId)
	if err != nil {
		log.Errorf("Failed to find public key for %s", peerId.Pretty())
		return nil, err
	}
	ciphertext, err := pubKey.Encrypt(message)
	if err != nil {
		return nil, err
	}
	return ciphertext, nil
}
<|endoftext|>


<commit_before>package main

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

var prefixes = "0123456789abcdef"

type CacheEntry struct {
	HTTPCode int
	Expires  time.Time
}

type diskCacheEntry struct {
	Data []byte
	CacheEntry
}

type DiskCache struct {
	cacheRoot  string
	cacheFiles map[string]CacheEntry
	sync.RWMutex
}

func (d *DiskCache) init() {
	d.Lock()
	defer d.Unlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to load uninitialized cache.")
	}

	os.Mkdir(d.cacheRoot, 0770)

	for _, dir := range prefixes {
		dirName := d.cacheRoot + "/" + string(dir)
		err := os.Mkdir(dirName, 0770)
		if err != nil {
			//Either cannot create directory, or directory already exists, let's try opening it to find out.
			dirf, derr := os.Open(dirName)
			if derr != nil {
				// Couldn't open directory, panic.
				log.Fatalf("Couldn't create or open %s: %s/%s", dirName, err, derr)
			}

			files, err := dirf.Readdirnames(0)
			if err != nil {
				log.Fatalf("Couldn't read %s: %s", dirName, err)
			}

			var de diskCacheEntry
			for _, filename := range files {
				fullname := dirName + "/" + filename

				jsondata, err := ioutil.ReadFile(fullname)
				if err != nil {
					log.Fatalf("Failed to read %s: %s", fullname, err)
				}

				err = json.Unmarshal(jsondata, &de)
				if err != nil {
					log.Printf("Recovering from cache consistency error for %s: %s ", fullname, err)
				}

				if err != nil || time.Now().After(de.Expires) {
					err := os.Remove(fullname)
					if err != nil {
						log.Fatalf("Failed to remove expired cache entry %s: %s", fullname, err)
					}
					continue
				}

				d.cacheFiles[filename] = de.CacheEntry
			}
		}
	}
}

var cleanOnce = &sync.Once{}

func (d *DiskCache) clean() {
	log.Printf("Cleaning Up.")
	now := time.Now()

	cleancount := 0
	for tag, ce := range d.cacheFiles {
		if now.After(ce.Expires) {
			os.Remove(d.cacheRoot + "/" + string(tag[0]) + "/" + tag)
			delete(d.cacheFiles, tag)

			cleancount++
		}
	}
	log.Printf("Cleaned up %d entries.", cleancount)
	cleanOnce = &sync.Once{}
}

var storeCount int64

func (d *DiskCache) filename(tag string) string {
	return d.cacheRoot + "/" + string(tag[0]) + "/" + tag
}

func (d *DiskCache) Store(cacheTag string, HTTPCode int, data []byte, Expires time.Time) error {
	d.Lock()
	defer d.Unlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to store to uninitialized cache.")
	}

	storeCount++
	if storeCount%500 == 0 {
		go cleanOnce.Do(func() { d.clean() })
	}

	ce := CacheEntry{HTTPCode, Expires}

	de := diskCacheEntry{data, ce}
	jsondata, err := json.Marshal(&de)
	if err != nil {
		log.Printf("Unknown JSON Marshal Error: %s", err)
		return err
	}

	err = ioutil.WriteFile(d.filename(cacheTag), jsondata, 0660)
	if err != nil {
		log.Printf("Unknown File Error: %s", err)
		return err
	}

	log.Printf("Stored Cache for %s Expires: %s", cacheTag, ce.Expires)
	d.cacheFiles[cacheTag] = ce
	return nil
}

func (d *DiskCache) Get(cacheTag string) (int, []byte, time.Time, error) {
	d.RLock()
	defer d.RUnlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to get from uninitialized cache.")
	}

	ce, exists := d.cacheFiles[cacheTag]
	if !exists || time.Now().After(ce.Expires) {
		return 0, nil, ce.Expires, fmt.Errorf("Not cached.")
	}

	jsondata, err := ioutil.ReadFile(d.filename(cacheTag))
	if err != nil {
		delete(d.cacheFiles, cacheTag)
		return 0, nil, ce.Expires, fmt.Errorf("Cache error - File not found.")
	}

	var de diskCacheEntry
	err = json.Unmarshal(jsondata, &de)
	if err != nil || de.Expires != ce.Expires {
		log.Printf("Cache consistency error: %s (Got: %s Expected: %s)", err, de.Expires, ce.Expires)

		delete(d.cacheFiles, cacheTag)
		return 0, nil, ce.Expires, fmt.Errorf("Cache error - Cache invalid.")
	}

	return ce.HTTPCode, de.Data, ce.Expires, nil
}

func (d *DiskCache) LogStats() {
	d.RLock()
	defer d.RUnlock()

	entries := 0
	expired := 0

	now := time.Now()
	for _, ce := range d.cacheFiles {
		entries++
		if now.After(ce.Expires) {
			expired++
		}
	}

	log.Printf("Cache Entries: %d  Expired Entries: %d", entries, expired)
}

func NewDiskCache(rootDir string) *DiskCache {
	var dc DiskCache

	dc.cacheRoot = rootDir
	dc.cacheFiles = make(map[string]CacheEntry)

	dc.init()

	return &dc
}
<commit_msg>minor refactor<commit_after>package main

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

var prefixes = "0123456789abcdef"

type CacheEntry struct {
	HTTPCode int
	Expires  time.Time
}

type diskCacheEntry struct {
	Data []byte
	CacheEntry
}

type DiskCache struct {
	cacheRoot  string
	cacheFiles map[string]CacheEntry
	sync.RWMutex
}

func (d *DiskCache) init() {
	d.Lock()
	defer d.Unlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to load uninitialized cache.")
	}

	os.Mkdir(d.cacheRoot, 0770)

	for _, dir := range prefixes {
		dirName := d.cacheRoot + "/" + string(dir)
		err := os.Mkdir(dirName, 0770)
		if err != nil {
			//Either cannot create directory, or directory already exists, let's try opening it to find out.
			dirf, derr := os.Open(dirName)
			if derr != nil {
				// Couldn't open directory, panic.
				log.Fatalf("Couldn't create or open %s: %s/%s", dirName, err, derr)
			}

			files, err := dirf.Readdirnames(0)
			if err != nil {
				log.Fatalf("Couldn't read %s: %s", dirName, err)
			}

			var de diskCacheEntry
			for _, filename := range files {
				fullname := dirName + "/" + filename

				jsondata, err := ioutil.ReadFile(fullname)
				if err != nil {
					log.Fatalf("Failed to read %s: %s", fullname, err)
				}

				err = json.Unmarshal(jsondata, &de)
				if err != nil {
					log.Printf("Recovering from cache consistency error for %s: %s ", fullname, err)
				}

				if err != nil || time.Now().After(de.Expires) {
					err := os.Remove(fullname)
					if err != nil {
						log.Fatalf("Failed to remove expired cache entry %s: %s", fullname, err)
					}
					continue
				}

				d.cacheFiles[filename] = de.CacheEntry
			}
		}
	}
}

var cleanOnce = &sync.Once{}

func (d *DiskCache) clean() {
	log.Printf("Cleaning Up.")
	now := time.Now()

	cleancount := 0
	for tag, ce := range d.cacheFiles {
		if now.After(ce.Expires) {
			os.Remove(d.filename(tag))
			delete(d.cacheFiles, tag)

			cleancount++
		}
	}
	log.Printf("Cleaned up %d entries.", cleancount)
	cleanOnce = &sync.Once{}
}

var storeCount int64

func (d *DiskCache) filename(tag string) string {
	return d.cacheRoot + "/" + string(tag[0]) + "/" + tag
}

func (d *DiskCache) Store(cacheTag string, HTTPCode int, data []byte, Expires time.Time) error {
	d.Lock()
	defer d.Unlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to store to uninitialized cache.")
	}

	storeCount++
	if storeCount%500 == 0 {
		go cleanOnce.Do(func() { d.clean() })
	}

	ce := CacheEntry{HTTPCode, Expires}

	de := diskCacheEntry{data, ce}
	jsondata, err := json.Marshal(&de)
	if err != nil {
		log.Printf("Unknown JSON Marshal Error: %s", err)
		return err
	}

	err = ioutil.WriteFile(d.filename(cacheTag), jsondata, 0660)
	if err != nil {
		log.Printf("Unknown File Error: %s", err)
		return err
	}

	log.Printf("Stored Cache for %s Expires: %s", cacheTag, ce.Expires)
	d.cacheFiles[cacheTag] = ce
	return nil
}

func (d *DiskCache) Get(cacheTag string) (int, []byte, time.Time, error) {
	d.RLock()
	defer d.RUnlock()

	if d.cacheFiles == nil {
		log.Fatalf("Tried to get from uninitialized cache.")
	}

	ce, exists := d.cacheFiles[cacheTag]
	if !exists || time.Now().After(ce.Expires) {
		return 0, nil, ce.Expires, fmt.Errorf("Not cached.")
	}

	jsondata, err := ioutil.ReadFile(d.filename(cacheTag))
	if err != nil {
		delete(d.cacheFiles, cacheTag)
		return 0, nil, ce.Expires, fmt.Errorf("Cache error - File not found.")
	}

	var de diskCacheEntry
	err = json.Unmarshal(jsondata, &de)
	if err != nil || de.Expires != ce.Expires {
		log.Printf("Cache consistency error: %s (Got: %s Expected: %s)", err, de.Expires, ce.Expires)

		delete(d.cacheFiles, cacheTag)
		return 0, nil, ce.Expires, fmt.Errorf("Cache error - Cache invalid.")
	}

	return ce.HTTPCode, de.Data, ce.Expires, nil
}

func (d *DiskCache) LogStats() {
	d.RLock()
	defer d.RUnlock()

	entries := 0
	expired := 0

	now := time.Now()
	for _, ce := range d.cacheFiles {
		entries++
		if now.After(ce.Expires) {
			expired++
		}
	}

	log.Printf("Cache Entries: %d  Expired Entries: %d", entries, expired)
}

func NewDiskCache(rootDir string) *DiskCache {
	var dc DiskCache

	dc.cacheRoot = rootDir
	dc.cacheFiles = make(map[string]CacheEntry)

	dc.init()

	return &dc
}
<|endoftext|>


<commit_before>package ot

import (
	"testing"
)

func TestRetainOpComposeRetain(t *testing.T) {
	cases := []struct {
		ret1 RetainOp
		ret2 RetainOp
		exp  [3]Op
	}{
		{
			ret1: 6,
			ret2: 6,
			exp:  [3]Op{RetainOp(6), Noop, Noop},
		},
		{
			ret1: 6,
			ret2: 3,
			exp:  [3]Op{RetainOp(3), RetainOp(3), Noop},
		},
		{
			ret1: 6,
			ret2: 9,
			exp:  [3]Op{RetainOp(6), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ret1.ComposeRetain(c.ret2)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestInsertOpComposeRetain(t *testing.T) {
	cases := []struct {
		ins InsertOp
		ret RetainOp
		exp [3]Op
	}{
		{
			ins: "foobar",
			ret: 6,
			exp: [3]Op{InsertOp("foobar"), Noop, Noop},
		},
		{
			ins: "foobar",
			ret: 3,
			exp: [3]Op{InsertOp("foo"), InsertOp("bar"), Noop},
		},
		{
			ins: "foobar",
			ret: 9,
			exp: [3]Op{InsertOp("foobar"), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ins.ComposeRetain(c.ret)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestRetainOpComposeDelete(t *testing.T) {
	cases := []struct {
		ret RetainOp
		del DeleteOp
		exp [3]Op
	}{
		{
			ret: 6,
			del: 6,
			exp: [3]Op{DeleteOp(6), Noop, Noop},
		},
		{
			ret: 6,
			del: 3,
			exp: [3]Op{DeleteOp(3), RetainOp(3), Noop},
		},
		{
			ret: 6,
			del: 9,
			exp: [3]Op{DeleteOp(6), Noop, DeleteOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ret.ComposeDelete(c.del)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestInsertOpComposeDelete(t *testing.T) {
	cases := []struct {
		ins InsertOp
		del DeleteOp
		exp [3]Op
	}{
		{
			ins: "foobar",
			del: 6,
			exp: [3]Op{Noop, Noop, Noop},
		},
		{
			ins: "foobar",
			del: 3,
			exp: [3]Op{Noop, InsertOp("bar"), Noop},
		},
		{
			ins: "foobar",
			del: 9,
			exp: [3]Op{Noop, Noop, DeleteOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ins.ComposeDelete(c.del)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestRetainOpTransformRetain(t *testing.T) {
	cases := []struct {
		ret1 RetainOp
		ret2 RetainOp
		exp  [4]Op
	}{
		{
			ret1: 6,
			ret2: 6,
			exp:  [4]Op{RetainOp(6), RetainOp(6), Noop, Noop},
		},
		{
			ret1: 6,
			ret2: 3,
			exp:  [4]Op{RetainOp(3), RetainOp(3), RetainOp(3), Noop},
		},
		{
			ret1: 6,
			ret2: 9,
			exp:  [4]Op{RetainOp(6), RetainOp(6), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, y, p, q := c.ret1.TransformRetain(c.ret2)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if y != c.exp[1] {
			t.Fatalf("%d: expected y == %#v, got %#v", i, c.exp[1], y)
		}
		if p != c.exp[2] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[3] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}
<commit_msg>Implement delete-retain transform test<commit_after>package ot

import (
	"testing"
)

func TestRetainOpComposeRetain(t *testing.T) {
	cases := []struct {
		ret1 RetainOp
		ret2 RetainOp
		exp  [3]Op
	}{
		{
			ret1: 6,
			ret2: 6,
			exp:  [3]Op{RetainOp(6), Noop, Noop},
		},
		{
			ret1: 6,
			ret2: 3,
			exp:  [3]Op{RetainOp(3), RetainOp(3), Noop},
		},
		{
			ret1: 6,
			ret2: 9,
			exp:  [3]Op{RetainOp(6), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ret1.ComposeRetain(c.ret2)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestInsertOpComposeRetain(t *testing.T) {
	cases := []struct {
		ins InsertOp
		ret RetainOp
		exp [3]Op
	}{
		{
			ins: "foobar",
			ret: 6,
			exp: [3]Op{InsertOp("foobar"), Noop, Noop},
		},
		{
			ins: "foobar",
			ret: 3,
			exp: [3]Op{InsertOp("foo"), InsertOp("bar"), Noop},
		},
		{
			ins: "foobar",
			ret: 9,
			exp: [3]Op{InsertOp("foobar"), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ins.ComposeRetain(c.ret)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestRetainOpComposeDelete(t *testing.T) {
	cases := []struct {
		ret RetainOp
		del DeleteOp
		exp [3]Op
	}{
		{
			ret: 6,
			del: 6,
			exp: [3]Op{DeleteOp(6), Noop, Noop},
		},
		{
			ret: 6,
			del: 3,
			exp: [3]Op{DeleteOp(3), RetainOp(3), Noop},
		},
		{
			ret: 6,
			del: 9,
			exp: [3]Op{DeleteOp(6), Noop, DeleteOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ret.ComposeDelete(c.del)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestInsertOpComposeDelete(t *testing.T) {
	cases := []struct {
		ins InsertOp
		del DeleteOp
		exp [3]Op
	}{
		{
			ins: "foobar",
			del: 6,
			exp: [3]Op{Noop, Noop, Noop},
		},
		{
			ins: "foobar",
			del: 3,
			exp: [3]Op{Noop, InsertOp("bar"), Noop},
		},
		{
			ins: "foobar",
			del: 9,
			exp: [3]Op{Noop, Noop, DeleteOp(3)},
		},
	}
	for i, c := range cases {
		x, p, q := c.ins.ComposeDelete(c.del)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if p != c.exp[1] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[2] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestRetainOpTransformRetain(t *testing.T) {
	cases := []struct {
		ret1 RetainOp
		ret2 RetainOp
		exp  [4]Op
	}{
		{
			ret1: 6,
			ret2: 6,
			exp:  [4]Op{RetainOp(6), RetainOp(6), Noop, Noop},
		},
		{
			ret1: 6,
			ret2: 3,
			exp:  [4]Op{RetainOp(3), RetainOp(3), RetainOp(3), Noop},
		},
		{
			ret1: 6,
			ret2: 9,
			exp:  [4]Op{RetainOp(6), RetainOp(6), Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, y, p, q := c.ret1.TransformRetain(c.ret2)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if y != c.exp[1] {
			t.Fatalf("%d: expected y == %#v, got %#v", i, c.exp[1], y)
		}
		if p != c.exp[2] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[3] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}

func TestDeleteOpTransformRetain(t *testing.T) {
	cases := []struct {
		del DeleteOp
		ret RetainOp
		exp [4]Op
	}{
		{
			del: 6,
			ret: 6,
			exp: [4]Op{DeleteOp(6), Noop, Noop, Noop},
		},
		{
			del: 6,
			ret: 3,
			exp: [4]Op{DeleteOp(3), Noop, DeleteOp(3), Noop},
		},
		{
			del: 6,
			ret: 9,
			exp: [4]Op{DeleteOp(6), Noop, Noop, RetainOp(3)},
		},
	}
	for i, c := range cases {
		x, y, p, q := c.del.TransformRetain(c.ret)
		if x != c.exp[0] {
			t.Fatalf("%d: expected x == %#v, got %#v", i, c.exp[0], x)
		}
		if y != c.exp[1] {
			t.Fatalf("%d: expected y == %#v, got %#v", i, c.exp[1], y)
		}
		if p != c.exp[2] {
			t.Fatalf("%d: expected p == %#v, got %#v", i, c.exp[1], p)
		}
		if q != c.exp[3] {
			t.Fatalf("%d: expected q == %#v, got %#v", i, c.exp[2], q)
		}
	}
}
<|endoftext|>


<commit_before>package registry

import (
	"github.com/hashicorp/consul/api"

	"net"
	"net/url"
	"sort"
	"strconv"
	"strings"
)

type discovery struct {
	agent      *api.Agent
	health     *api.Health
	catalog    *api.Catalog
	datacenter string
}

func (d *discovery) Register(options ServiceOptions) error {
	var (
		host = options.Address
		port int
	)
	if strings.HasPrefix(host, "http") {
		url, err := url.Parse(host)
		if err != nil {
			return err
		}
		host = url.Host
	}
	if strings.Contains(host, ":") {
		h, p, err := net.SplitHostPort(host)
		if err != nil {
			return err
		}
		v, err := strconv.ParseUint(p, 10, 32)
		if err != nil {
			return err
		}
		host = h
		port = int(v)
	}
	return d.agent.ServiceRegister(&api.AgentServiceRegistration{
		ID:                options.ID,
		Name:              options.Name,
		Address:           host,
		Port:              port,
		Tags:              append(options.Tags, "DC="+d.datacenter),
		EnableTagOverride: true,
		Check: &api.AgentServiceCheck{
			Interval: options.Check.Interval,
			Timeout:  options.Check.Timeout,
			DeregisterCriticalServiceAfter: "10m",
			HTTP: options.Check.HTTP,
			TCP:  options.Check.TCP,
		},
	})
}

func (d *discovery) Deregister(ident string) error {
	return d.agent.ServiceDeregister(ident)
}

type sortServiceByID []Service

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

func (d *discovery) Lookup(filter *Filter) ([]Service, error) {
	var result []Service
	list, _, err := d.catalog.Services(nil)
	if err != nil {
		return nil, err
	}
	var names []string
	for name := range list {
		names = append(names, name)
		items, _, err := d.catalog.Service(name, "", nil)
		if err != nil {
			return nil, err
		}
		for _, item := range items {
			var (
				srv = Service{
					ID:         item.ServiceID,
					Name:       item.ServiceName,
					Datacenter: dc(item.ServiceTags),
					Address:    item.ServiceAddress,
					Port:       item.ServicePort,
					Tags:       item.ServiceTags,
					Status:     SERVICE_STATUS_UNDEFINED,
				}
			)
			result = append(result, srv)
		}
	}
	sort.Sort(sortServiceByID(result))
	status := func(status string) int8 {
		switch status {
		case "passing":
			return SERVICE_STATUS_PASSING
		case "warning":
			return SERVICE_STATUS_WARNING
		case "critical":
			return SERVICE_STATUS_CRITICAL
		}
		return SERVICE_STATUS_UNDEFINED
	}
	for _, name := range names {
		healthChecks, _, err := d.health.Checks(name, nil)
		if err != nil {
			return nil, err
		}
		for _, check := range healthChecks {
			if i := sort.Search(len(result), func(i int) bool { return result[i].ID >= check.ServiceID }); i < len(result) && result[i].ID == check.ServiceID {
				result[i].Status = status(check.Status)
			}
		}
	}
	services := make([]Service, 0, len(result))
	for _, srv := range result {
		if srv.test(filter) {
			services = append(services, srv)
		}
	}
	return services, nil
}

func dc(tags []string) string {
	for _, tag := range tags {
		if strings.HasPrefix(tag, "DC=") {
			return strings.TrimPrefix(tag, "DC=")
		}
	}
	return ""
}
<commit_msg>Lookup services around all data centers<commit_after>package registry

import (
	"github.com/hashicorp/consul/api"

	"fmt"
	"net"
	"net/url"
	"sort"
	"strconv"
	"strings"
)

type discovery struct {
	agent      *api.Agent
	health     *api.Health
	catalog    *api.Catalog
	datacenter string
}

func (d *discovery) Register(options ServiceOptions) error {
	var (
		host = options.Address
		port int
	)
	if strings.HasPrefix(host, "http") {
		url, err := url.Parse(host)
		if err != nil {
			return err
		}
		host = url.Host
	}
	if strings.Contains(host, ":") {
		h, p, err := net.SplitHostPort(host)
		if err != nil {
			return err
		}
		v, err := strconv.ParseUint(p, 10, 32)
		if err != nil {
			return err
		}
		host = h
		port = int(v)
	}
	return d.agent.ServiceRegister(&api.AgentServiceRegistration{
		ID:                options.ID,
		Name:              options.Name,
		Address:           host,
		Port:              port,
		Tags:              append(options.Tags, "DC="+d.datacenter),
		EnableTagOverride: true,
		Check: &api.AgentServiceCheck{
			Interval: options.Check.Interval,
			Timeout:  options.Check.Timeout,
			DeregisterCriticalServiceAfter: "10m",
			HTTP: options.Check.HTTP,
			TCP:  options.Check.TCP,
		},
	})
}

func (d *discovery) Deregister(ident string) error {
	return d.agent.ServiceDeregister(ident)
}

type sortServiceByID []Service

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

// Lookup services by filter
//
// If needed to lookup all services around all DCs,
// set DC filter to "all". It takes all DCs from discovery
// and polls services every of them
func (d *discovery) Lookup(filter *Filter) ([]Service, error) {
	if filter.Datacenter != "all" {
		return d.lookup(filter)
	}

	dcl, err := d.catalog.Datacenters()
	if err != nil {
		return nil, fmt.Errorf("datacenters list: %s", err)
	}

	var services []Service
	for _, dc := range dcl {
		filter.Datacenter = dc
		s, err := d.lookup(filter)
		if err != nil {
			return nil, fmt.Errorf("datacenter %s lookup: %s", dc, err)
		}
		services = append(services, s...)
	}

	return services, nil
}

func (d *discovery) lookup(filter *Filter) ([]Service, error) {
	var (
		result []Service
		q      = &api.QueryOptions{Datacenter: filter.Datacenter}
	)
	list, _, err := d.catalog.Services(q)
	if err != nil {
		return nil, err
	}
	var names []string
	for name := range list {
		names = append(names, name)
		items, _, err := d.catalog.Service(name, "", q)
		if err != nil {
			return nil, err
		}
		for _, item := range items {
			var (
				srv = Service{
					ID:         item.ServiceID,
					Name:       item.ServiceName,
					Datacenter: dc(item.ServiceTags),
					Address:    item.ServiceAddress,
					Port:       item.ServicePort,
					Tags:       item.ServiceTags,
					Status:     SERVICE_STATUS_UNDEFINED,
				}
			)
			result = append(result, srv)
		}
	}
	sort.Sort(sortServiceByID(result))
	status := func(status string) int8 {
		switch status {
		case "passing":
			return SERVICE_STATUS_PASSING
		case "warning":
			return SERVICE_STATUS_WARNING
		case "critical":
			return SERVICE_STATUS_CRITICAL
		}
		return SERVICE_STATUS_UNDEFINED
	}
	for _, name := range names {
		healthChecks, _, err := d.health.Checks(name, nil)
		if err != nil {
			return nil, err
		}
		for _, check := range healthChecks {
			if i := sort.Search(len(result), func(i int) bool { return result[i].ID >= check.ServiceID }); i < len(result) && result[i].ID == check.ServiceID {
				result[i].Status = status(check.Status)
			}
		}
	}
	services := make([]Service, 0, len(result))
	for _, srv := range result {
		if srv.test(filter) {
			services = append(services, srv)
		}
	}
	return services, nil
}

func dc(tags []string) string {
	for _, tag := range tags {
		if strings.HasPrefix(tag, "DC=") {
			return strings.TrimPrefix(tag, "DC=")
		}
	}
	return ""
}
<|endoftext|>