<commit_before>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"fmt"
	"math/rand"
	"time"
)

// pc is the program counter
type pc uint16

// Increments the counter
func (p *pc) Increment() {
	(*p) += 2
}

// The stack
type stack struct {
	data [16]pc
	sp   uint16 // Stack Pointer
}

// Push the addr to the stack
func (s *stack) Push(data pc) {
	s.data[s.sp] = data
	s.sp++
}

// Pop a value from stack
func (s *stack) Pop() pc {
	s.sp--
	return s.data[s.sp]
}

// cpu is the chip8 main cpu
type cpu struct {
	regs  [16]byte // Registers v0 - vF
	stack stack    // The Stack
	i     uint16   // Index
	pc    pc       // Program Counter

	sound  sound    // Sound Card
	gfx    gfx      // Graphics
	memory memory   // Memory - 4K
	keys   [16]bool // Key State
	dt     byte     // Delay Timer
	st     byte     // Sound Timer
}

// Chip8 Fonts
var font = [80]byte{
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
}

// newCpu creates a new cpu and initialize it
func newCpu(s sound) cpu {
	rand.Seed(time.Now().UTC().UnixNano())

	c := cpu{
		pc:    0x200,
		i:     0,
		dt:    0,
		st:    0,
		stack: stack{sp: 0},
		sound: s,
	}

	// Load font into memory
	for i, e := range font {
		c.memory.Write(uint16(i), e)
	}

	return c
}

// Step the cpu one instruction at a time
func (c *cpu) Step() {
	opcode := c.memory.ReadWord(uint16(c.pc))
	x := (opcode & 0x0F00) >> 8
	y := (opcode & 0x00F0) >> 4

	c.pc.Increment()

	switch opcode & 0xF000 {
	case 0x0000:
		switch opcode {
		case 0x00E0: // 00E0 - CLS
			c.gfx.Cls()
		case 0x00EE: // 00EE - RET
			c.pc = c.stack.Pop()
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0x1000: // 1nnn - JP addr
		c.pc = pc(opcode & 0x0FFF)
	case 0x2000: // 2nnn - CALL addr
		c.stack.Push(c.pc)
		c.pc = pc(opcode & 0x0FFF)
	case 0x3000: // 3xkk - SE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] == byte(kk) {
			c.pc.Increment()
		}
	case 0x4000: // 4xkk - SNE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] != byte(kk) {
			c.pc.Increment()
		}
	case 0x5000: // 5xy0 - SE Vx, Vy
		if c.regs[x] == c.regs[y] {
			c.pc.Increment()
		}
	case 0x6000: // 6xkk - LD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] = byte(kk)
	case 0x7000: // 7xkk - ADD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] += byte(kk)
	case 0x8000:
		switch opcode & 0x000F {
		case 0x0000: // 8xy0 - LD Vx, Vy
			c.regs[x] = c.regs[y]
		case 0x0001: // 8xy1 - OR Vx, Vy
			c.regs[x] |= c.regs[y]
		case 0x0002: // 8xy2 - AND Vx, Vy
			c.regs[x] &= c.regs[y]
		case 0x0003: // 8xy3 - XOR Vx, Vy
			c.regs[x] ^= c.regs[y]
		case 0x0004: // 8xy4 - ADD Vx, Vy
			r := uint16(c.regs[x]) + uint16(c.regs[y])

			if r > 0xFF {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] += c.regs[y]
		case 0x0005: // 8xy5 - SUB Vx, Vy
			if c.regs[x] > c.regs[y] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = c.regs[x] - c.regs[y]
		case 0x0006: // 8xy6 - SHR Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] / 2
		case 0x0007: // 8xy7 - SUBN Vx, Vy
			if c.regs[y] > c.regs[x] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}
			c.regs[x] = c.regs[y] - c.regs[x]
		case 0x000E: // 8xyE - SHL Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] * 2
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0x9000: // 9xy0 - SNE Vx, Vy
		if c.regs[x] != c.regs[y] {
			c.pc.Increment()
		}
	case 0xA000: // Annn - LD I, addr
		c.i = opcode & 0x0FFF
	case 0xB000: // Bnnn - JP V0, addr
		addr := opcode & 0x0FFF
		c.pc = pc(addr + uint16(c.regs[0]))
	case 0xC000: // Cxkk - RND Vx, byte
		kk := opcode & 0x00FF
		c.regs[x] = byte(rand.Intn(256)) & byte(kk)
	case 0xD000: // Dxyn - DRW Vx, Vy, nibble
		// TODO:  Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
	case 0xE000:
		switch opcode & 0x000F {
		case 0x000E: // Ex9E - SKP Vx
			if c.keys[x] {
				c.pc.Increment()
			}
		case 0x0001: // ExA1 - SKNP Vx
			if !c.keys[x] {
				c.pc.Increment()
			}
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0xF000:
		switch opcode & 0x00FF {
		case 0x0007: // Fx07 - LD Vx, DT
			c.regs[x] = c.dt
		case 0x000A: // Fx0A - LD Vx, K
			// TODO: Wait for a key press, store the value of the key in Vx.
			// All execution stops until a key is pressed, then the value of that key is stored in Vx.
		case 0x0015: // Fx15 - LD DT, Vx
			c.dt = c.regs[x]
		case 0x0018: // Fx18 - LD ST, Vx
			c.st = c.regs[x]
		case 0x001E: // Fx1E - ADD I, Vx
			c.i += uint16(c.regs[x])
		case 0x0029: // Fx29 - LD F, Vx
			c.i = uint16(c.regs[x] * 5) // 5 is the number of rows per character.
		case 0x0033: // Fx33 - LD B, Vx
			num := c.regs[x]

			for i := uint16(3); i > 0; i-- {
				c.memory.Write(c.i+i-1, num%10)
				num /= 10
			}
		case 0x0055: // Fx55 - LD [I], Vx
			for i := uint16(0); i <= x; i++ {
				c.memory.Write(c.i+i, c.regs[i])
			}
		case 0x0065: // Fx65 - LD Vx, [I]
			for i := uint16(0); i <= x; i++ {
				c.regs[i] = c.memory.Read(c.i + i)
			}
		}
	default:
		panic(fmt.Sprintf("Unknown opcode %X", opcode))
	}

	// Timers
	if c.dt > 0 {
		c.dt--
	}

	if c.st > 0 {
		if c.st == 1 {
			c.sound.Beep()
		}
		c.st--
	}
}
<commit_msg>Removed Unreachable code.<commit_after>// Copyright 2015 Claudemiro Alves Feitosa Neto. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package gochip8

import (
	"fmt"
	"math/rand"
	"time"
)

// pc is the program counter
type pc uint16

// Increments the counter
func (p *pc) Increment() {
	(*p) += 2
}

// The stack
type stack struct {
	data [16]pc
	sp   uint16 // Stack Pointer
}

// Push the addr to the stack
func (s *stack) Push(data pc) {
	s.data[s.sp] = data
	s.sp++
}

// Pop a value from stack
func (s *stack) Pop() pc {
	s.sp--
	return s.data[s.sp]
}

// cpu is the chip8 main cpu
type cpu struct {
	regs  [16]byte // Registers v0 - vF
	stack stack    // The Stack
	i     uint16   // Index
	pc    pc       // Program Counter

	sound  sound    // Sound Card
	gfx    gfx      // Graphics
	memory memory   // Memory - 4K
	keys   [16]bool // Key State
	dt     byte     // Delay Timer
	st     byte     // Sound Timer
}

// Chip8 Fonts
var font = [80]byte{
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80, // F
}

// newCpu creates a new cpu and initialize it
func newCpu(s sound) cpu {
	rand.Seed(time.Now().UTC().UnixNano())

	c := cpu{
		pc:    0x200,
		i:     0,
		dt:    0,
		st:    0,
		stack: stack{sp: 0},
		sound: s,
	}

	// Load font into memory
	for i, e := range font {
		c.memory.Write(uint16(i), e)
	}

	return c
}

// Step the cpu one instruction at a time
func (c *cpu) Step() {
	opcode := c.memory.ReadWord(uint16(c.pc))
	x := (opcode & 0x0F00) >> 8
	y := (opcode & 0x00F0) >> 4

	c.pc.Increment()

	switch opcode & 0xF000 {
	case 0x0000:
		switch opcode {
		case 0x00E0: // 00E0 - CLS
			c.gfx.Cls()
		case 0x00EE: // 00EE - RET
			c.pc = c.stack.Pop()
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0x1000: // 1nnn - JP addr
		c.pc = pc(opcode & 0x0FFF)
	case 0x2000: // 2nnn - CALL addr
		c.stack.Push(c.pc)
		c.pc = pc(opcode & 0x0FFF)
	case 0x3000: // 3xkk - SE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] == byte(kk) {
			c.pc.Increment()
		}
	case 0x4000: // 4xkk - SNE Vx, byte
		kk := opcode & 0x00FF

		if c.regs[x] != byte(kk) {
			c.pc.Increment()
		}
	case 0x5000: // 5xy0 - SE Vx, Vy
		if c.regs[x] == c.regs[y] {
			c.pc.Increment()
		}
	case 0x6000: // 6xkk - LD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] = byte(kk)
	case 0x7000: // 7xkk - ADD Vx, byte
		kk := opcode & 0x00FF

		c.regs[x] += byte(kk)
	case 0x8000:
		switch opcode & 0x000F {
		case 0x0000: // 8xy0 - LD Vx, Vy
			c.regs[x] = c.regs[y]
		case 0x0001: // 8xy1 - OR Vx, Vy
			c.regs[x] |= c.regs[y]
		case 0x0002: // 8xy2 - AND Vx, Vy
			c.regs[x] &= c.regs[y]
		case 0x0003: // 8xy3 - XOR Vx, Vy
			c.regs[x] ^= c.regs[y]
		case 0x0004: // 8xy4 - ADD Vx, Vy
			r := uint16(c.regs[x]) + uint16(c.regs[y])

			if r > 0xFF {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] += c.regs[y]
		case 0x0005: // 8xy5 - SUB Vx, Vy
			if c.regs[x] > c.regs[y] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}

			c.regs[x] = c.regs[x] - c.regs[y]
		case 0x0006: // 8xy6 - SHR Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] / 2
		case 0x0007: // 8xy7 - SUBN Vx, Vy
			if c.regs[y] > c.regs[x] {
				c.regs[0xF] = 1
			} else {
				c.regs[0xF] = 0
			}
			c.regs[x] = c.regs[y] - c.regs[x]
		case 0x000E: // 8xyE - SHL Vx {, Vy}
			c.regs[0xF] = c.regs[x] & 0x0001
			c.regs[x] = c.regs[x] * 2
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0x9000: // 9xy0 - SNE Vx, Vy
		if c.regs[x] != c.regs[y] {
			c.pc.Increment()
		}
	case 0xA000: // Annn - LD I, addr
		c.i = opcode & 0x0FFF
	case 0xB000: // Bnnn - JP V0, addr
		addr := opcode & 0x0FFF
		c.pc = pc(addr + uint16(c.regs[0]))
	case 0xC000: // Cxkk - RND Vx, byte
		kk := opcode & 0x00FF
		c.regs[x] = byte(rand.Intn(256)) & byte(kk)
	case 0xD000: // Dxyn - DRW Vx, Vy, nibble
		// TODO:  Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
	case 0xE000:
		switch opcode & 0x000F {
		case 0x000E: // Ex9E - SKP Vx
			if c.keys[x] {
				c.pc.Increment()
			}
		case 0x0001: // ExA1 - SKNP Vx
			if !c.keys[x] {
				c.pc.Increment()
			}
		default:
			panic(fmt.Sprintf("Unknown opcode 0x%X", opcode))
		}
	case 0xF000:
		switch opcode & 0x00FF {
		case 0x0007: // Fx07 - LD Vx, DT
			c.regs[x] = c.dt
		case 0x000A: // Fx0A - LD Vx, K
			// TODO: Wait for a key press, store the value of the key in Vx.
			// All execution stops until a key is pressed, then the value of that key is stored in Vx.
		case 0x0015: // Fx15 - LD DT, Vx
			c.dt = c.regs[x]
		case 0x0018: // Fx18 - LD ST, Vx
			c.st = c.regs[x]
		case 0x001E: // Fx1E - ADD I, Vx
			c.i += uint16(c.regs[x])
		case 0x0029: // Fx29 - LD F, Vx
			c.i = uint16(c.regs[x] * 5) // 5 is the number of rows per character.
		case 0x0033: // Fx33 - LD B, Vx
			num := c.regs[x]

			for i := uint16(3); i > 0; i-- {
				c.memory.Write(c.i+i-1, num%10)
				num /= 10
			}
		case 0x0055: // Fx55 - LD [I], Vx
			for i := uint16(0); i <= x; i++ {
				c.memory.Write(c.i+i, c.regs[i])
			}
		case 0x0065: // Fx65 - LD Vx, [I]
			for i := uint16(0); i <= x; i++ {
				c.regs[i] = c.memory.Read(c.i + i)
			}
		}
	}

	// Timers
	if c.dt > 0 {
		c.dt--
	}

	if c.st > 0 {
		if c.st == 1 {
			c.sound.Beep()
		}
		c.st--
	}
}
<|endoftext|>


<commit_before>package stack

import "jvmgo/ch05/instructions/base"
import "jvmgo/ch05/rtda"

// Duplicate the top operand stack value
type DUP struct{ base.NoOperandsInstruction }

func (self *DUP) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot := stack.PopSlot()
	stack.PushSlot(slot)
	stack.PushSlot(slot)
}

// Duplicate the top operand stack value and insert two values down
type DUP_X1 struct{ base.NoOperandsInstruction }

func (self *DUP_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// Duplicate the top operand stack value and insert two or three values down
type DUP_X2 struct{ base.NoOperandsInstruction }

func (self *DUP_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// Duplicate the top one or two operand stack values
type DUP2 struct{ base.NoOperandsInstruction }

func (self *DUP2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// Duplicate the top one or two operand stack values and insert two or three values down
type DUP2_X1 struct{ base.NoOperandsInstruction }

func (self *DUP2_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

// Duplicate the top one or two operand stack values and insert two, three, or four values down
type DUP2_X2 struct{ base.NoOperandsInstruction }

func (self *DUP2_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	slot4 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot4)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}
<commit_msg>+ comments<commit_after>package stack

import "jvmgo/ch05/instructions/base"
import "jvmgo/ch05/rtda"

/*
bottom -> top
[...][c][b][a]
             \_
               |
               V
[...][c][b][a][a]
*/
// Duplicate the top operand stack value
type DUP struct{ base.NoOperandsInstruction }

func (self *DUP) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot := stack.PopSlot()
	stack.PushSlot(slot)
	stack.PushSlot(slot)
}

/*
bottom -> top
[...][c][b][a]
          __/
         |
         V
[...][c][a][b][a]
*/
// Duplicate the top operand stack value and insert two values down
type DUP_X1 struct{ base.NoOperandsInstruction }

func (self *DUP_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
bottom -> top
[...][c][b][a]
       _____/
      |
      V
[...][a][c][b][a]
*/
// Duplicate the top operand stack value and insert two or three values down
type DUP_X2 struct{ base.NoOperandsInstruction }

func (self *DUP_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
bottom -> top
[...][c][b][a]____
          \____   |
               |  |
               V  V
[...][c][b][a][b][a]
*/
// Duplicate the top one or two operand stack values
type DUP2 struct{ base.NoOperandsInstruction }

func (self *DUP2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
bottom -> top
[...][c][b][a]
       _/ __/
      |  |
      V  V
[...][b][a][c][b][a]
*/
// Duplicate the top one or two operand stack values and insert two or three values down
type DUP2_X1 struct{ base.NoOperandsInstruction }

func (self *DUP2_X1) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}

/*
bottom -> top
[...][d][c][b][a]
       ____/ __/
      |   __/
      V  V
[...][b][a][d][c][b][a]
*/
// Duplicate the top one or two operand stack values and insert two, three, or four values down
type DUP2_X2 struct{ base.NoOperandsInstruction }

func (self *DUP2_X2) Execute(frame *rtda.Frame) {
	stack := frame.OperandStack()
	slot1 := stack.PopSlot()
	slot2 := stack.PopSlot()
	slot3 := stack.PopSlot()
	slot4 := stack.PopSlot()
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
	stack.PushSlot(slot4)
	stack.PushSlot(slot3)
	stack.PushSlot(slot2)
	stack.PushSlot(slot1)
}
<|endoftext|>


<commit_before>package bench

import (
	"fmt"
	"github.com/nats-io/nats"
	"strings"
	"testing"
	"time"
)

const (
	MsgSize = 8
	Million = 1000 * 1000
)

var baseTime = time.Now()

func millionMessagesSecondSample(seconds int) *Sample {
	messages := Million * seconds
	start := baseTime
	end := start.Add(time.Second * time.Duration(seconds))
	nc := new(nats.Conn)

	s := NewSample(messages, MsgSize, start, end, nc)
	s.MsgCnt = uint64(messages)
	s.MsgBytes = uint64(messages * MsgSize)
	s.IOBytes = s.MsgBytes
	return s
}

func TestDuration(t *testing.T) {
	s := millionMessagesSecondSample(1)
	duration := s.End.Sub(s.Start)
	if duration != s.Duration() || duration != time.Second {
		t.Fatal("Expected sample duration to be 1 second")
	}
}

func TestSeconds(t *testing.T) {
	s := millionMessagesSecondSample(1)
	seconds := s.End.Sub(s.Start).Seconds()
	if seconds != s.Seconds() || seconds != 1.0 {
		t.Fatal("Expected sample seconds to be 1 second")
	}
}

func TestRate(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if s.Rate() != Million {
		t.Fatal("Expected rate at 1 million msgs")
	}
}

func TestThoughput(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if s.Throughput() != Million*MsgSize {
		t.Fatal("Expected throughput at %d million bytes/sec", MsgSize)
	}
}

func TestStrings(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if len(s.String()) == 0 {
		t.Fatal("Sample didn't provide a String")
	}
}

func TestGroupDuration(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	duration := sg.End.Sub(sg.Start)
	if duration != sg.Duration() || duration != time.Duration(2)*time.Second {
		t.Fatal("Expected aggregate duration to be 2.0 seconds")
	}
}

func TestGroupSeconds(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	seconds := sg.End.Sub(sg.Start).Seconds()
	if seconds != sg.Seconds() || seconds != 3.0 {
		t.Fatal("Expected aggregate seconds to be 3.0 seconds")
	}
}

func TestGroupRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.Rate() != Million*2 {
		t.Fatal("Expected MsgRate at 2 million msg/sec")
	}
}

func TestGroupThoughput(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.Throughput() != 2*Million*MsgSize {
		t.Fatalf("Expected througput at %d million bytes/sec", 2*MsgSize)
	}
}

func TestMinMaxRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.MinRate() != sg.MaxRate() {
		t.Fatal("Expected MinRate == MaxRate")
	}
}

func TestAvgRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.MinRate() != sg.AvgRate() {
		t.Fatal("Expected MinRate == AvgRate")
	}
}

func TestStdDev(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.StdDev() != 0.0 {
		t.Fatal("Expected stddev to be zero")
	}
}

func TestBenchSetup(t *testing.T) {
	bench := NewBenchmark("test", 1, 1)
	bench.AddSubSample(millionMessagesSecondSample(1))
	bench.AddPubSample(millionMessagesSecondSample(1))
	bench.Close()
	if len(bench.RunID) == 0 {
		t.Fatal("Bench doesn't have a RunID")
	}
	if len(bench.Pubs.Samples) != 1 {
		t.Fatal("Expected one publisher")
	}
	if len(bench.Subs.Samples) != 1 {
		t.Fatal("Expected one subscriber")
	}
	if bench.MsgCnt != 2*Million {
		t.Fatal("Expected 2 million msgs")
	}
	if bench.IOBytes != 2*Million*MsgSize {
		t.Fatalf("Expected %d million bytes", 2*MsgSize)
	}
	if bench.Duration() != time.Second {
		t.Fatal("Expected duration to be 1 second")
	}
}

func makeBench(subs, pubs int) *Benchmark {
	bench := NewBenchmark("test", subs, pubs)
	for i := 0; i < subs; i++ {
		bench.AddSubSample(millionMessagesSecondSample(1))
	}
	for i := 0; i < pubs; i++ {
		bench.AddPubSample(millionMessagesSecondSample(1))
	}
	bench.Close()
	return bench
}

func TestCsv(t *testing.T) {
	bench := makeBench(1, 1)
	csv := bench.CSV()
	lines := strings.Split(csv, "\n")
	if len(lines) != 4 {
		t.Fatal("Expected 4 lines of output from the CSV string")
	}

	fields := strings.Split(lines[1], ",")
	if len(fields) != 7 {
		t.Fatal("Expected 7 fields")
	}
}

func TestBenchStrings(t *testing.T) {
	bench := makeBench(1, 1)
	s := bench.Report()
	lines := strings.Split(s, "\n")
	if len(lines) != 4 {
		t.Fatal("Expected 3 lines of output: header, pub, sub, empty")
	}

	bench = makeBench(2, 2)
	s = bench.Report()
	lines = strings.Split(s, "\n")
	if len(lines) != 10 {
		fmt.Printf("%q\n", s)

		t.Fatal("Expected 11 lines of output: header, pub header, pub x 2, stats, sub headers, sub x 2, stats, empty")
	}
}

func TestMsgsPerClient(t *testing.T) {
	zero := MsgsPerClient(0, 0)
	if len(zero) != 0 {
		t.Fatal("Expected 0 length for 0 clients")
	}
	onetwo := MsgsPerClient(1, 2)
	if len(onetwo) != 2 || onetwo[0] != 1 || onetwo[1] != 0 {
		t.Fatal("Expected uneven distribution")
	}
	twotwo := MsgsPerClient(2, 2)
	if len(twotwo) != 2 || twotwo[0] != 1 || twotwo[1] != 1 {
		t.Fatal("Expected even distribution")
	}
	threetwo := MsgsPerClient(3, 2)
	if len(threetwo) != 2 || threetwo[0] != 2 || threetwo[1] != 1 {
		t.Fatal("Expected uneven distribution")
	}
}
<commit_msg>Fix malformed logging statement<commit_after>package bench

import (
	"fmt"
	"github.com/nats-io/nats"
	"strings"
	"testing"
	"time"
)

const (
	MsgSize = 8
	Million = 1000 * 1000
)

var baseTime = time.Now()

func millionMessagesSecondSample(seconds int) *Sample {
	messages := Million * seconds
	start := baseTime
	end := start.Add(time.Second * time.Duration(seconds))
	nc := new(nats.Conn)

	s := NewSample(messages, MsgSize, start, end, nc)
	s.MsgCnt = uint64(messages)
	s.MsgBytes = uint64(messages * MsgSize)
	s.IOBytes = s.MsgBytes
	return s
}

func TestDuration(t *testing.T) {
	s := millionMessagesSecondSample(1)
	duration := s.End.Sub(s.Start)
	if duration != s.Duration() || duration != time.Second {
		t.Fatal("Expected sample duration to be 1 second")
	}
}

func TestSeconds(t *testing.T) {
	s := millionMessagesSecondSample(1)
	seconds := s.End.Sub(s.Start).Seconds()
	if seconds != s.Seconds() || seconds != 1.0 {
		t.Fatal("Expected sample seconds to be 1 second")
	}
}

func TestRate(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if s.Rate() != Million {
		t.Fatal("Expected rate at 1 million msgs")
	}
}

func TestThoughput(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if s.Throughput() != Million*MsgSize {
		t.Fatalf("Expected throughput at %d million bytes/sec", MsgSize)
	}
}

func TestStrings(t *testing.T) {
	s := millionMessagesSecondSample(60)
	if len(s.String()) == 0 {
		t.Fatal("Sample didn't provide a String")
	}
}

func TestGroupDuration(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	duration := sg.End.Sub(sg.Start)
	if duration != sg.Duration() || duration != time.Duration(2)*time.Second {
		t.Fatal("Expected aggregate duration to be 2.0 seconds")
	}
}

func TestGroupSeconds(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	seconds := sg.End.Sub(sg.Start).Seconds()
	if seconds != sg.Seconds() || seconds != 3.0 {
		t.Fatal("Expected aggregate seconds to be 3.0 seconds")
	}
}

func TestGroupRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.Rate() != Million*2 {
		t.Fatal("Expected MsgRate at 2 million msg/sec")
	}
}

func TestGroupThoughput(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.Throughput() != 2*Million*MsgSize {
		t.Fatalf("Expected througput at %d million bytes/sec", 2*MsgSize)
	}
}

func TestMinMaxRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.MinRate() != sg.MaxRate() {
		t.Fatal("Expected MinRate == MaxRate")
	}
}

func TestAvgRate(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.MinRate() != sg.AvgRate() {
		t.Fatal("Expected MinRate == AvgRate")
	}
}

func TestStdDev(t *testing.T) {
	sg := NewSampleGroup()
	sg.AddSample(millionMessagesSecondSample(1))
	sg.AddSample(millionMessagesSecondSample(2))
	sg.AddSample(millionMessagesSecondSample(3))
	if sg.StdDev() != 0.0 {
		t.Fatal("Expected stddev to be zero")
	}
}

func TestBenchSetup(t *testing.T) {
	bench := NewBenchmark("test", 1, 1)
	bench.AddSubSample(millionMessagesSecondSample(1))
	bench.AddPubSample(millionMessagesSecondSample(1))
	bench.Close()
	if len(bench.RunID) == 0 {
		t.Fatal("Bench doesn't have a RunID")
	}
	if len(bench.Pubs.Samples) != 1 {
		t.Fatal("Expected one publisher")
	}
	if len(bench.Subs.Samples) != 1 {
		t.Fatal("Expected one subscriber")
	}
	if bench.MsgCnt != 2*Million {
		t.Fatal("Expected 2 million msgs")
	}
	if bench.IOBytes != 2*Million*MsgSize {
		t.Fatalf("Expected %d million bytes", 2*MsgSize)
	}
	if bench.Duration() != time.Second {
		t.Fatal("Expected duration to be 1 second")
	}
}

func makeBench(subs, pubs int) *Benchmark {
	bench := NewBenchmark("test", subs, pubs)
	for i := 0; i < subs; i++ {
		bench.AddSubSample(millionMessagesSecondSample(1))
	}
	for i := 0; i < pubs; i++ {
		bench.AddPubSample(millionMessagesSecondSample(1))
	}
	bench.Close()
	return bench
}

func TestCsv(t *testing.T) {
	bench := makeBench(1, 1)
	csv := bench.CSV()
	lines := strings.Split(csv, "\n")
	if len(lines) != 4 {
		t.Fatal("Expected 4 lines of output from the CSV string")
	}

	fields := strings.Split(lines[1], ",")
	if len(fields) != 7 {
		t.Fatal("Expected 7 fields")
	}
}

func TestBenchStrings(t *testing.T) {
	bench := makeBench(1, 1)
	s := bench.Report()
	lines := strings.Split(s, "\n")
	if len(lines) != 4 {
		t.Fatal("Expected 3 lines of output: header, pub, sub, empty")
	}

	bench = makeBench(2, 2)
	s = bench.Report()
	lines = strings.Split(s, "\n")
	if len(lines) != 10 {
		fmt.Printf("%q\n", s)

		t.Fatal("Expected 11 lines of output: header, pub header, pub x 2, stats, sub headers, sub x 2, stats, empty")
	}
}

func TestMsgsPerClient(t *testing.T) {
	zero := MsgsPerClient(0, 0)
	if len(zero) != 0 {
		t.Fatal("Expected 0 length for 0 clients")
	}
	onetwo := MsgsPerClient(1, 2)
	if len(onetwo) != 2 || onetwo[0] != 1 || onetwo[1] != 0 {
		t.Fatal("Expected uneven distribution")
	}
	twotwo := MsgsPerClient(2, 2)
	if len(twotwo) != 2 || twotwo[0] != 1 || twotwo[1] != 1 {
		t.Fatal("Expected even distribution")
	}
	threetwo := MsgsPerClient(3, 2)
	if len(threetwo) != 2 || threetwo[0] != 2 || threetwo[1] != 1 {
		t.Fatal("Expected uneven distribution")
	}
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/funkygao/gocli"
	"github.com/siddontang/go-mysql/mysql"
	"github.com/siddontang/go-mysql/replication"
)

type Binlog struct {
	Ui  cli.Ui
	Cmd string
}

func (this *Binlog) Run(args []string) (exitCode int) {
	cmdFlags := flag.NewFlagSet("binlog", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	syncer := replication.NewBinlogSyncer(1001, "mysql")
	syncer.RegisterSlave("localhost", 3306, "root", "")
	binlogFile := "binlogFile"
	binlogPos := uint32(1)
	stream, err := syncer.StartSync(mysql.Position{binlogFile, binlogPos})
	if err != nil {
		panic(err)
	}
	for {
		evt, err := stream.GetEvent()
		if err != nil {
			panic(err)
		}

		evt.Dump(os.Stdout)
	}

	return
}

func (*Binlog) Synopsis() string {
	return "Sync binlog from MySQL master to elsewhere"
}

func (this *Binlog) Help() string {
	help := fmt.Sprintf(`
Usage: %s binlog [options]

    Sync binlog from MySQL master to elsewhere

Options:

`, this.Cmd)
	return strings.TrimSpace(help)
}
<commit_msg>a valid binlog filename<commit_after>package command

import (
	"flag"
	"fmt"
	"os"
	"strings"

	"github.com/funkygao/gocli"
	"github.com/siddontang/go-mysql/mysql"
	"github.com/siddontang/go-mysql/replication"
)

type Binlog struct {
	Ui  cli.Ui
	Cmd string
}

func (this *Binlog) Run(args []string) (exitCode int) {
	cmdFlags := flag.NewFlagSet("binlog", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	syncer := replication.NewBinlogSyncer(1001, "mysql")
	syncer.RegisterSlave("localhost", 3306, "root", "")
	binlogFile := "mysql-bin.000080"
	binlogPos := uint32(1)
	stream, err := syncer.StartSync(mysql.Position{binlogFile, binlogPos})
	if err != nil {
		panic(err)
	}
	for {
		evt, err := stream.GetEvent()
		if err != nil {
			panic(err)
		}

		evt.Dump(os.Stdout)
	}

	return
}

func (*Binlog) Synopsis() string {
	return "Sync binlog from MySQL master to elsewhere"
}

func (this *Binlog) Help() string {
	help := fmt.Sprintf(`
Usage: %s binlog [options]

    Sync binlog from MySQL master to elsewhere

Options:

`, this.Cmd)
	return strings.TrimSpace(help)
}
<|endoftext|>


<commit_before>package ctxerr

import (
	"bufio"
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"unicode/utf8"

	"github.com/fatih/color"
)

var (
	DefaultGutter  = " | "
	DefaultPointer = '^'
)

// Ctx points to runes in (multiline) strings.
type Ctx struct {
	lines   []string
	context int
	Region
	hint string
}

// New returns a new Ctx pointing to a region in input.
//
// See functions Point and Range.
func New(input string, region Region) Ctx {
	return Ctx{
		lines:  split(input, region),
		Region: region,
	}
}

// WithHint returns a Ctx with a text hint that is displayed near the region markers.
func (c Ctx) WithHint(hint string) Ctx {
	c.hint = hint
	return c
}

// WithContext returns a Ctx with a maximum amount of context lines.
//
//	 0: no lines of context.
//	-1: all lines, the full input string
//	 3: limited context of 3 lines
func (c Ctx) WithContext(context int) Ctx {
	if context < -1 {
		context = -1
	}
	c.context = context
	return c
}

func split(s string, r Region) []string {
	sc := bufio.NewScanner(strings.NewReader(s))
	l := []string{}
	for sc.Scan() {
		l = append(l, sc.Text())
	}
	return l
}

func (c Ctx) String() string {
	buf := &bytes.Buffer{}
	start, end := c.lineIndex()
	// length of highest line number
	linePosMaxLen := posLen(end)
	for i, line := range c.lines[start:end] {
		linePos := start + i + 1
		// write line no. gutter and actual line
		c.writeLineGutter(buf, linePos, linePosMaxLen)
		buf.WriteString(line)
		buf.WriteByte('\n')
		if linePos < c.start.line || linePos > c.end.line {
			// this was just context, don't point at it
			continue
		}
		// this line is being pointed at
		c.writeLineGutter(buf, 0, linePosMaxLen)
		buf.WriteString(strings.Repeat(" ", c.getPad(linePos)))
		buf.WriteString(color.RedString("%s", strings.Repeat(string(DefaultPointer), c.getDots(linePos, line))))
		if c.hint != "" && c.start.line == linePos {
			fmt.Fprintf(buf, " %s", c.hint)
		}
		buf.WriteString("\n")
	}
	return buf.String()
}

// start and end index of Ctx.lines including lines of context.
func (c Ctx) lineIndex() (start, end int) {
	if c.context < 0 {
		return 0, len(c.lines)
	}
	start = c.start.line - c.context - 1
	if start < 0 {
		start = 0
	}
	end = c.end.line + c.context
	if end > len(c.lines) {
		end = len(c.lines)
	}
	return
}

func posLen(i int) int {
	return len(strconv.Itoa(i))
}

func (c Ctx) getDots(pos int, line string) int {
	if c.isPointer() {
		return 1
	}
	if !c.isMultiLine() {
		return c.end.col - c.start.col + 1
	}
	if c.start.line == pos {
		return utf8.RuneCountInString(line) - c.start.col + 1
	}
	if c.end.line == pos {
		return c.end.col
	}
	return utf8.RuneCountInString(line)
}

func (c Ctx) getPad(pos int) int {
	pad := c.start.col - 1
	if c.isMultiLine() && c.start.line != pos {
		pad = 0
	}
	return pad
}

func (c Ctx) writeLineGutter(buf *bytes.Buffer, line, maxLen int) {
	pad := maxLen  // assume 0, meaning no line info
	if line != 0 { // otherwise exclude line no. from padding
		pad -= posLen(line)
	}
	buf.WriteString(strings.Repeat(" ", pad))
	if line != 0 {
		buf.WriteString(strconv.Itoa(line))
	}
	buf.WriteString(DefaultGutter)
}
<commit_msg>Comment Default* vars<commit_after>package ctxerr

import (
	"bufio"
	"bytes"
	"fmt"
	"strconv"
	"strings"
	"unicode/utf8"

	"github.com/fatih/color"
)

var (
	// DefaultGutter separates line numbers from content.
	DefaultGutter = " | "
	// DefaultPointer is the rune that points up at a region.
	DefaultPointer = '^'
)

// Ctx points to runes in (multiline) strings.
type Ctx struct {
	lines   []string
	context int
	Region
	hint string
}

// New returns a new Ctx pointing to a region in input.
//
// See functions Point and Range.
func New(input string, region Region) Ctx {
	return Ctx{
		lines:  split(input, region),
		Region: region,
	}
}

// WithHint returns a Ctx with a text hint that is displayed near the region markers.
func (c Ctx) WithHint(hint string) Ctx {
	c.hint = hint
	return c
}

// WithContext returns a Ctx with a maximum amount of context lines.
//
//	 0: no lines of context.
//	-1: all lines, the full input string
//	 3: limited context of 3 lines
func (c Ctx) WithContext(context int) Ctx {
	if context < -1 {
		context = -1
	}
	c.context = context
	return c
}

func split(s string, r Region) []string {
	sc := bufio.NewScanner(strings.NewReader(s))
	l := []string{}
	for sc.Scan() {
		l = append(l, sc.Text())
	}
	return l
}

func (c Ctx) String() string {
	buf := &bytes.Buffer{}
	start, end := c.lineIndex()
	// length of highest line number
	linePosMaxLen := posLen(end)
	for i, line := range c.lines[start:end] {
		linePos := start + i + 1
		// write line no. gutter and actual line
		c.writeLineGutter(buf, linePos, linePosMaxLen)
		buf.WriteString(line)
		buf.WriteByte('\n')
		if linePos < c.start.line || linePos > c.end.line {
			// this was just context, don't point at it
			continue
		}
		// this line is being pointed at
		c.writeLineGutter(buf, 0, linePosMaxLen)
		buf.WriteString(strings.Repeat(" ", c.getPad(linePos)))
		buf.WriteString(color.RedString("%s", strings.Repeat(string(DefaultPointer), c.getDots(linePos, line))))
		if c.hint != "" && c.start.line == linePos {
			fmt.Fprintf(buf, " %s", c.hint)
		}
		buf.WriteString("\n")
	}
	return buf.String()
}

// start and end index of Ctx.lines including lines of context.
func (c Ctx) lineIndex() (start, end int) {
	if c.context < 0 {
		return 0, len(c.lines)
	}
	start = c.start.line - c.context - 1
	if start < 0 {
		start = 0
	}
	end = c.end.line + c.context
	if end > len(c.lines) {
		end = len(c.lines)
	}
	return
}

func posLen(i int) int {
	return len(strconv.Itoa(i))
}

func (c Ctx) getDots(pos int, line string) int {
	if c.isPointer() {
		return 1
	}
	if !c.isMultiLine() {
		return c.end.col - c.start.col + 1
	}
	if c.start.line == pos {
		return utf8.RuneCountInString(line) - c.start.col + 1
	}
	if c.end.line == pos {
		return c.end.col
	}
	return utf8.RuneCountInString(line)
}

func (c Ctx) getPad(pos int) int {
	pad := c.start.col - 1
	if c.isMultiLine() && c.start.line != pos {
		pad = 0
	}
	return pad
}

func (c Ctx) writeLineGutter(buf *bytes.Buffer, line, maxLen int) {
	pad := maxLen  // assume 0, meaning no line info
	if line != 0 { // otherwise exclude line no. from padding
		pad -= posLen(line)
	}
	buf.WriteString(strings.Repeat(" ", pad))
	if line != 0 {
		buf.WriteString(strconv.Itoa(line))
	}
	buf.WriteString(DefaultGutter)
}
<|endoftext|>


<commit_before><commit_msg>Stop triggering consumers on i/o timeouts<commit_after><|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/panyam/relay/bindings/gen"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
)

func main() {
	var serviceName, operation string
	flag.StringVar(&serviceName, "service", "", "The service whose methods are to be extracted and for whome binding code is to be generated")
	flag.StringVar(&operation, "operation", "", "The operation within the service to be generated code for.  If this is empty or not provided then ALL operations in the service will code generated for them")

	flag.Parse()

	log.Println("Args: ", flag.Args())
	if serviceName == "" {
		log.Println("Service required")
	}

	parsedFiles := make(map[string]*ast.File)
	for _, srcFile := range flag.Args() {
		fset := token.NewFileSet() // positions are relative to fset
		parsedFile, err := parser.ParseFile(fset, srcFile, nil, parser.ParseComments|parser.AllErrors)
		if err != nil {
			log.Println("Parsing error: ", err)
			return
		}
		parsedFiles[srcFile] = parsedFile
	}

	fset := token.NewFileSet() // positions are relative to fset
	pkg, err := ast.NewPackage(fset, parsedFiles, types.GcImporter, types.Universe)
	if err != nil {
		log.Println("Package creation err: ", err)
		return
	}

	parsedFile := ast.MergePackageFiles(pkg, 0)
	log.Println("File Package: ", parsedFile.Name.Name)
	serviceDecl := gen.FindDecl(parsedFile, serviceName)
	nt := gen.NodeToType(serviceDecl)
	log.Println("ServiceType: ", nt)
}
<commit_msg>Taking individual class<commit_after>package main

import (
	"flag"
	"github.com/panyam/relay/bindings/gen"
	"go/ast"
	"go/parser"
	"go/token"
	"log"
)

func main() {
	var serviceName, operation string
	flag.StringVar(&serviceName, "service", "", "The service whose methods are to be extracted and for whome binding code is to be generated")
	flag.StringVar(&operation, "operation", "", "The operation within the service to be generated code for.  If this is empty or not provided then ALL operations in the service will code generated for them")

	flag.Parse()

	log.Println("Args: ", flag.Args())
	if serviceName == "" {
		log.Println("Service required")
	}

	parsedFiles := make(map[string]*ast.File)
	for _, srcFile := range flag.Args() {
		fset := token.NewFileSet() // positions are relative to fset
		parsedFile, err := parser.ParseFile(fset, srcFile, nil, parser.ParseComments|parser.AllErrors)
		if err != nil {
			log.Println("Parsing error: ", err)
			return
		}
		parsedFiles[srcFile] = parsedFile
	}

	/*
		fset := token.NewFileSet() // positions are relative to fset
		pkg, err := ast.NewPackage(fset, parsedFiles, types.GcImporter, types.Universe)
		if err != nil {
			log.Println("Package creation err: ", err)
			return
		}
		parsedFile := ast.MergePackageFiles(pkg, 0)
	*/
	parsedFile := ast.MergePackageFiles(pkg, 0)
	log.Println("File Package: ", parsedFile.Name.Name)
	serviceDecl := gen.FindDecl(parsedFile, serviceName)
	nt := gen.NodeToType(serviceDecl)
	log.Println("ServiceType: ", nt)
}
<|endoftext|>


<commit_before>package bitcoind

import (
	"bytes"
	"errors"
	"github.com/OpenBazaar/spvwallet"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcrpcclient"
	hd "github.com/btcsuite/btcutil/hdkeychain"
	"github.com/btcsuite/btcutil"
	"io/ioutil"
	"net/http"
)

type NotificationListener struct {
	client        *btcrpcclient.Client
	listeners     []func(spvwallet.TransactionCallback)
	masterPrivKey *hd.ExtendedKey
	params        *chaincfg.Params
	stealthFlag   []byte
}

func (l *NotificationListener) notify(w http.ResponseWriter, r *http.Request) {
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return
	}
	txid := string(b)
	hash, err := chainhash.NewHashFromStr(txid)
	if err != nil {
		return
	}
	tx, err := l.client.GetRawTransaction(hash)
	if err != nil {
		return
	}
	var outputs []spvwallet.TransactionOutput
	for i, txout := range tx.MsgTx().TxOut {
		out := spvwallet.TransactionOutput{ScriptPubKey: txout.PkScript, Value: txout.Value, Index: uint32(i)}
		outputs = append(outputs, out)

		// Check stealth
		if len(txout.PkScript) == 38 && txout.PkScript[0] == 0x6a && bytes.Equal(txout.PkScript[1:4], l.stealthFlag) {
			_, key, err := l.checkStealth(tx.MsgTx(), txout.PkScript)
			if err == nil {
				wif, err := btcutil.NewWIF(key, l.params, true)
				if err != nil {
					continue
				}
				err = l.client.ImportPrivKey(wif)
				if err != nil {
					continue
				}
				_, err = l.client.SendRawTransaction(tx.MsgTx(), true)
				if err != nil {
					continue
				}
			}
		}
	}
	var inputs []spvwallet.TransactionInput
	for _, txin := range tx.MsgTx().TxIn {
		in := spvwallet.TransactionInput{OutpointHash: txin.PreviousOutPoint.Hash.CloneBytes(), OutpointIndex: txin.PreviousOutPoint.Index}
		prev, err := l.client.GetRawTransaction(&txin.PreviousOutPoint.Hash)
		if err != nil {
			inputs = append(inputs, in)
			continue
		}
		in.LinkedScriptPubKey = prev.MsgTx().TxOut[txin.PreviousOutPoint.Index].PkScript
		in.Value = prev.MsgTx().TxOut[txin.PreviousOutPoint.Index].Value
		inputs = append(inputs, in)
	}
	cb := spvwallet.TransactionCallback{Txid: tx.Hash().CloneBytes(), Inputs: inputs, Outputs: outputs}
	for _, lis := range l.listeners {
		lis(cb)
	}
}

func startNotificationListener(client *btcrpcclient.Client, listeners []func(spvwallet.TransactionCallback), masterPrivKey *hd.ExtendedKey, params *chaincfg.Params) {
	pubKey, _ := masterPrivKey.ECPubKey()
	pubkeyBytes := pubKey.SerializeCompressed()
	f := []byte{FlagPrefix}
	f = append(f, pubkeyBytes[1:2]...)

	l := NotificationListener{
		client:        client,
		listeners:     listeners,
		masterPrivKey: masterPrivKey,
		params:        params,
		stealthFlag:   f,
	}
	http.HandleFunc("/", l.notify)
	http.ListenAndServe(":8330", nil)
}

func (l *NotificationListener) checkStealth(tx *wire.MsgTx, scriptPubkey []byte) (outIndex int, privkey *btcec.PrivateKey, err error) {
	// Extract the ephemeral public key from the script
	ephemPubkeyBytes := scriptPubkey[5:len(scriptPubkey)]
	ephemPubkey, err := btcec.ParsePubKey(ephemPubkeyBytes, btcec.S256())
	if err != nil {
		return 0, nil, err
	}
	mPrivKey, err := l.masterPrivKey.ECPrivKey()
	if err != nil {
		return 0, nil, err
	}
	// Calculate a shared secret using the master private key and ephemeral public key
	ss := btcec.GenerateSharedSecret(mPrivKey, ephemPubkey)

	// Create an HD key using the shared secret as the chaincode
	hdKey := hd.NewExtendedKey(
		l.params.HDPrivateKeyID[:],
		mPrivKey.Serialize(),
		ss,
		[]byte{0x00, 0x00, 0x00, 0x00},
		0,
		0,
		true)

	// Derive child key 0
	childKey, err := hdKey.Child(0)
	if err != nil {
		return 0, nil, err
	}
	addr, err := childKey.Address(l.params)
	if err != nil {
		return 0, nil, err
	}

	// Check to see if the p2pkh script for our derived child key matches any output scripts in this transaction
	for i, out := range tx.TxOut {
		if !bytes.Equal(addr.ScriptAddress(), out.PkScript) {
			privkey, err := childKey.ECPrivKey()
			if err != nil {
				return 0, nil, err
			}
			return i, privkey, nil
		}
	}
	return 0, nil, errors.New("Stealth transaction not for us")
}
<commit_msg>Fix bug in bitcoind stealth impl<commit_after>package bitcoind

import (
	"bytes"
	"errors"
	"github.com/OpenBazaar/spvwallet"
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcrpcclient"
	hd "github.com/btcsuite/btcutil/hdkeychain"
	"github.com/btcsuite/btcutil"
	"io/ioutil"
	"net/http"
)

type NotificationListener struct {
	client        *btcrpcclient.Client
	listeners     []func(spvwallet.TransactionCallback)
	masterPrivKey *hd.ExtendedKey
	params        *chaincfg.Params
	stealthFlag   []byte
}

func (l *NotificationListener) notify(w http.ResponseWriter, r *http.Request) {
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return
	}
	txid := string(b)
	hash, err := chainhash.NewHashFromStr(txid)
	if err != nil {
		return
	}
	tx, err := l.client.GetRawTransaction(hash)
	if err != nil {
		return
	}
	var outputs []spvwallet.TransactionOutput
	for i, txout := range tx.MsgTx().TxOut {
		out := spvwallet.TransactionOutput{ScriptPubKey: txout.PkScript, Value: txout.Value, Index: uint32(i)}
		outputs = append(outputs, out)

		// Check stealth
		if len(txout.PkScript) == 38 && txout.PkScript[0] == 0x6a && bytes.Equal(txout.PkScript[2:4], l.stealthFlag) {
			_, key, err := l.checkStealth(tx.MsgTx(), txout.PkScript)
			if err == nil {
				wif, err := btcutil.NewWIF(key, l.params, true)
				if err != nil {
					continue
				}
				err = l.client.ImportPrivKey(wif)
				if err != nil {
					continue
				}
				_, err = l.client.SendRawTransaction(tx.MsgTx(), true)
				if err != nil {
					continue
				}
			}
		}
	}
	var inputs []spvwallet.TransactionInput
	for _, txin := range tx.MsgTx().TxIn {
		in := spvwallet.TransactionInput{OutpointHash: txin.PreviousOutPoint.Hash.CloneBytes(), OutpointIndex: txin.PreviousOutPoint.Index}
		prev, err := l.client.GetRawTransaction(&txin.PreviousOutPoint.Hash)
		if err != nil {
			inputs = append(inputs, in)
			continue
		}
		in.LinkedScriptPubKey = prev.MsgTx().TxOut[txin.PreviousOutPoint.Index].PkScript
		in.Value = prev.MsgTx().TxOut[txin.PreviousOutPoint.Index].Value
		inputs = append(inputs, in)
	}
	cb := spvwallet.TransactionCallback{Txid: tx.Hash().CloneBytes(), Inputs: inputs, Outputs: outputs}
	for _, lis := range l.listeners {
		lis(cb)
	}
}

func startNotificationListener(client *btcrpcclient.Client, listeners []func(spvwallet.TransactionCallback), masterPrivKey *hd.ExtendedKey, params *chaincfg.Params) {
	pubKey, _ := masterPrivKey.ECPubKey()
	pubkeyBytes := pubKey.SerializeCompressed()
	f := []byte{FlagPrefix}
	f = append(f, pubkeyBytes[1:2]...)

	l := NotificationListener{
		client:        client,
		listeners:     listeners,
		masterPrivKey: masterPrivKey,
		params:        params,
		stealthFlag:   f,
	}
	http.HandleFunc("/", l.notify)
	http.ListenAndServe(":8330", nil)
}

func (l *NotificationListener) checkStealth(tx *wire.MsgTx, scriptPubkey []byte) (outIndex int, privkey *btcec.PrivateKey, err error) {
	// Extract the ephemeral public key from the script
	ephemPubkeyBytes := scriptPubkey[5:len(scriptPubkey)]
	ephemPubkey, err := btcec.ParsePubKey(ephemPubkeyBytes, btcec.S256())
	if err != nil {
		return 0, nil, err
	}
	mPrivKey, err := l.masterPrivKey.ECPrivKey()
	if err != nil {
		return 0, nil, err
	}
	// Calculate a shared secret using the master private key and ephemeral public key
	ss := btcec.GenerateSharedSecret(mPrivKey, ephemPubkey)

	// Create an HD key using the shared secret as the chaincode
	hdKey := hd.NewExtendedKey(
		l.params.HDPrivateKeyID[:],
		mPrivKey.Serialize(),
		ss,
		[]byte{0x00, 0x00, 0x00, 0x00},
		0,
		0,
		true)

	// Derive child key 0
	childKey, err := hdKey.Child(0)
	if err != nil {
		return 0, nil, err
	}
	addr, err := childKey.Address(l.params)
	if err != nil {
		return 0, nil, err
	}

	// Check to see if the p2pkh script for our derived child key matches any output scripts in this transaction
	for i, out := range tx.TxOut {
		if !bytes.Equal(addr.ScriptAddress(), out.PkScript) {
			privkey, err := childKey.ECPrivKey()
			if err != nil {
				return 0, nil, err
			}
			return i, privkey, nil
		}
	}
	return 0, nil, errors.New("Stealth transaction not for us")
}
<|endoftext|>


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

package colly

import (
	"encoding/xml"
	"strings"

	"github.com/antchfx/htmlquery"
	"github.com/antchfx/xmlquery"
	"golang.org/x/net/html"
)

// XMLElement is the representation of a XML tag.
type XMLElement struct {
	// Name is the name of the tag
	Name       string
	Text       string
	attributes interface{}
	// Request is the request object of the element's HTML document
	Request *Request
	// Response is the Response object of the element's HTML document
	Response *Response
	// DOM is the DOM object of the page. DOM is relative
	// to the current XMLElement and is either a html.Node or xmlquery.Node
	// based on how the XMLElement was created.
	DOM    interface{}
	isHTML bool
}

// NewXMLElementFromHTMLNode creates a XMLElement from a html.Node.
func NewXMLElementFromHTMLNode(resp *Response, s *html.Node) *XMLElement {
	return &XMLElement{
		Name:       s.Data,
		Request:    resp.Request,
		Response:   resp,
		Text:       htmlquery.InnerText(s),
		DOM:        s,
		attributes: s.Attr,
		isHTML:     true,
	}
}

// NewXMLElementFromXMLNode creates a XMLElement from a xmlquery.Node.
func NewXMLElementFromXMLNode(resp *Response, s *xmlquery.Node) *XMLElement {
	return &XMLElement{
		Name:       s.Data,
		Request:    resp.Request,
		Response:   resp,
		Text:       s.InnerText(),
		DOM:        s,
		attributes: s.Attr,
		isHTML:     false,
	}
}

// Attr returns the selected attribute of a HTMLElement or empty string
// if no attribute found
func (h *XMLElement) Attr(k string) string {
	if h.isHTML {
		for _, a := range h.attributes.([]html.Attribute) {
			if a.Key == k {
				return a.Val
			}
		}
	} else {
		for _, a := range h.attributes.([]xml.Attr) {
			if a.Name.Local == k {
				return a.Value
			}
		}
	}
	return ""
}

// ChildText returns the concatenated and stripped text content of the matching
// elements.
func (h *XMLElement) ChildText(xpathQuery string) string {
	if h.isHTML {
		return strings.TrimSpace(htmlquery.InnerText(htmlquery.FindOne(h.DOM.(*html.Node), xpathQuery)))
	}
	return strings.TrimSpace(xmlquery.FindOne(h.DOM.(*xmlquery.Node), xpathQuery).InnerText())
}

// ChildAttr returns the stripped text content of the first matching
// element's attribute.
func (h *XMLElement) ChildAttr(xpathQuery, attrName string) string {
	if h.isHTML {
		child := htmlquery.FindOne(h.DOM.(*html.Node), xpathQuery)
		if child != nil {
			for _, attr := range child.Attr {
				if attr.Key == attrName {
					return strings.TrimSpace(attr.Val)
				}
			}
		}
	} else {
		child := xmlquery.FindOne(h.DOM.(*xmlquery.Node), xpathQuery)
		if child != nil {
			for _, attr := range child.Attr {
				if attr.Name.Local == attrName {
					return strings.TrimSpace(attr.Value)
				}
			}
		}
	}

	return ""
}

// ChildAttrs returns the stripped text content of all the matching
// element's attributes.
func (h *XMLElement) ChildAttrs(xpathQuery, attrName string) []string {
	var res []string
	if h.isHTML {
		htmlquery.FindEach(h.DOM.(*html.Node), xpathQuery, func(i int, child *html.Node) {
			for _, attr := range child.Attr {
				if attr.Key == attrName {
					res = append(res, strings.TrimSpace(attr.Val))
				}
			}
		})
	} else {
		xmlquery.FindEach(h.DOM.(*xmlquery.Node), xpathQuery, func(i int, child *xmlquery.Node) {
			for _, attr := range child.Attr {
				if attr.Name.Local == attrName {
					res = append(res, strings.TrimSpace(attr.Value))
				}
			}
		})
	}
	return res
}
<commit_msg>fix ChildText panic if xpath does not exist in xml<commit_after>// Copyright 2018 Adam Tauber
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package colly

import (
	"encoding/xml"
	"strings"

	"github.com/antchfx/htmlquery"
	"github.com/antchfx/xmlquery"
	"golang.org/x/net/html"
)

// XMLElement is the representation of a XML tag.
type XMLElement struct {
	// Name is the name of the tag
	Name       string
	Text       string
	attributes interface{}
	// Request is the request object of the element's HTML document
	Request *Request
	// Response is the Response object of the element's HTML document
	Response *Response
	// DOM is the DOM object of the page. DOM is relative
	// to the current XMLElement and is either a html.Node or xmlquery.Node
	// based on how the XMLElement was created.
	DOM    interface{}
	isHTML bool
}

// NewXMLElementFromHTMLNode creates a XMLElement from a html.Node.
func NewXMLElementFromHTMLNode(resp *Response, s *html.Node) *XMLElement {
	return &XMLElement{
		Name:       s.Data,
		Request:    resp.Request,
		Response:   resp,
		Text:       htmlquery.InnerText(s),
		DOM:        s,
		attributes: s.Attr,
		isHTML:     true,
	}
}

// NewXMLElementFromXMLNode creates a XMLElement from a xmlquery.Node.
func NewXMLElementFromXMLNode(resp *Response, s *xmlquery.Node) *XMLElement {
	return &XMLElement{
		Name:       s.Data,
		Request:    resp.Request,
		Response:   resp,
		Text:       s.InnerText(),
		DOM:        s,
		attributes: s.Attr,
		isHTML:     false,
	}
}

// Attr returns the selected attribute of a HTMLElement or empty string
// if no attribute found
func (h *XMLElement) Attr(k string) string {
	if h.isHTML {
		for _, a := range h.attributes.([]html.Attribute) {
			if a.Key == k {
				return a.Val
			}
		}
	} else {
		for _, a := range h.attributes.([]xml.Attr) {
			if a.Name.Local == k {
				return a.Value
			}
		}
	}
	return ""
}

// ChildText returns the concatenated and stripped text content of the matching
// elements.
func (h *XMLElement) ChildText(xpathQuery string) string {
	if h.isHTML {
		return strings.TrimSpace(htmlquery.InnerText(htmlquery.FindOne(h.DOM.(*html.Node), xpathQuery)))
	}
	n := xmlquery.FindOne(h.DOM.(*xmlquery.Node), xpathQuery)
	if n == nil {
		return ""
	}
	return strings.TrimSpace(n.InnerText())
}

// ChildAttr returns the stripped text content of the first matching
// element's attribute.
func (h *XMLElement) ChildAttr(xpathQuery, attrName string) string {
	if h.isHTML {
		child := htmlquery.FindOne(h.DOM.(*html.Node), xpathQuery)
		if child != nil {
			for _, attr := range child.Attr {
				if attr.Key == attrName {
					return strings.TrimSpace(attr.Val)
				}
			}
		}
	} else {
		child := xmlquery.FindOne(h.DOM.(*xmlquery.Node), xpathQuery)
		if child != nil {
			for _, attr := range child.Attr {
				if attr.Name.Local == attrName {
					return strings.TrimSpace(attr.Value)
				}
			}
		}
	}

	return ""
}

// ChildAttrs returns the stripped text content of all the matching
// element's attributes.
func (h *XMLElement) ChildAttrs(xpathQuery, attrName string) []string {
	var res []string
	if h.isHTML {
		htmlquery.FindEach(h.DOM.(*html.Node), xpathQuery, func(i int, child *html.Node) {
			for _, attr := range child.Attr {
				if attr.Key == attrName {
					res = append(res, strings.TrimSpace(attr.Val))
				}
			}
		})
	} else {
		xmlquery.FindEach(h.DOM.(*xmlquery.Node), xpathQuery, func(i int, child *xmlquery.Node) {
			for _, attr := range child.Attr {
				if attr.Name.Local == attrName {
					res = append(res, strings.TrimSpace(attr.Value))
				}
			}
		})
	}
	return res
}
<|endoftext|>


<commit_before>package transactions

import (
	"fmt"

	"github.com/luistm/go-bank-cli/lib"
	"github.com/luistm/go-bank-cli/lib/customerrors"
	"github.com/luistm/go-bank-cli/lib/sellers"
)

// NewInteractor creates a new transactions Interactor
func NewInteractor(r *repository, sellerRepository lib.Repository) *Interactor {
	return &Interactor{transactionsRepository: r, sellersRepository: sellerRepository}
}

// Interactor for transactions ...
type Interactor struct {
	transactionsRepository Fetcher
	sellersRepository      lib.Repository
}

// LoadDataFromRecords fetches raw data from a repository and processes it into objects
// to be persisted in storage.
func (i *Interactor) LoadDataFromRecords() error {

	if i.transactionsRepository == nil {
		return customerrors.ErrRepositoryUndefined
	}

	transactions, err := i.transactionsRepository.GetAll()
	if err != nil {
		return &customerrors.ErrRepository{Msg: err.Error()}
	}

	if i.sellersRepository == nil {
		return customerrors.ErrInteractorUndefined
	}

	for _, t := range transactions {
		err := i.sellersRepository.Save(t.s)
		if err != nil {
			return &customerrors.ErrInteractor{Msg: err.Error()}
		}
	}

	return nil
}

// ReportFromRecords makes a report from an input file.
// TODO: If a Seller has a pretty name, that name will be used.
func (i *Interactor) ReportFromRecords() (*Report, error) {

	if i.transactionsRepository == nil {
		return &Report{}, customerrors.ErrRepositoryUndefined
	}

	r := &Report{}
	transactions, err := i.transactionsRepository.GetAll()
	if err != nil {
		return r, &customerrors.ErrRepository{Msg: err.Error()}
	}

	for _, transaction := range transactions {
		// log.Println(transaction.s)

		slls, err := i.sellersRepository.GetAll()
		if err != nil {
			return r, &customerrors.ErrRepository{
				Msg: fmt.Sprintf("failed to fetch seller, %s", err.Error()),
			}
		}

		for _, s := range slls {
			if s.ID() == transaction.s.ID() {
				transaction.s = s.(*sellers.Seller)
				break
			}
		}

	}

	// If a Seller has a pretty name, that name will be used.
	// sellerRepository.GetAll()
	// For each seller in repository, get the pretty name

	r.transactions = transactions

	return r, nil
}
<commit_msg>Adds new TODO<commit_after>package transactions

import (
	"fmt"

	"github.com/luistm/go-bank-cli/lib"
	"github.com/luistm/go-bank-cli/lib/customerrors"
	"github.com/luistm/go-bank-cli/lib/sellers"
)

// NewInteractor creates a new transactions Interactor
func NewInteractor(r *repository, sellerRepository lib.Repository) *Interactor {
	return &Interactor{transactionsRepository: r, sellersRepository: sellerRepository}
}

// Interactor for transactions ...
type Interactor struct {
	transactionsRepository Fetcher
	sellersRepository      lib.Repository
}

// LoadDataFromRecords fetches raw data from a repository and processes it into objects
// to be persisted in storage.
func (i *Interactor) LoadDataFromRecords() error {

	if i.transactionsRepository == nil {
		return customerrors.ErrRepositoryUndefined
	}

	transactions, err := i.transactionsRepository.GetAll()
	if err != nil {
		return &customerrors.ErrRepository{Msg: err.Error()}
	}

	if i.sellersRepository == nil {
		return customerrors.ErrInteractorUndefined
	}

	for _, t := range transactions {
		err := i.sellersRepository.Save(t.s)
		if err != nil {
			return &customerrors.ErrInteractor{Msg: err.Error()}
		}
	}

	return nil
}

// ReportFromRecords makes a report from an input file.
// If a Seller has a pretty name, that name will be used.
func (i *Interactor) ReportFromRecords() (*Report, error) {

	if i.transactionsRepository == nil {
		return &Report{}, customerrors.ErrRepositoryUndefined
	}

	r := &Report{}
	transactions, err := i.transactionsRepository.GetAll()
	if err != nil {
		return r, &customerrors.ErrRepository{Msg: err.Error()}
	}

	for _, transaction := range transactions {
		// TODO: Fetch only the needed sellers, not all the sellers
		allSellers, err := i.sellersRepository.GetAll()
		if err != nil {
			return r, &customerrors.ErrRepository{
				Msg: fmt.Sprintf("failed to fetch seller, %s", err.Error()),
			}
		}
		for _, s := range allSellers {
			if s.ID() == transaction.s.ID() {
				transaction.s = s.(*sellers.Seller)
				break
			}
		}
	}

	r.transactions = transactions

	return r, nil
}
<|endoftext|>


<commit_before>// Package dht implements a distributed hash table that satisfies the ipfs routing
// interface. This DHT is modeled after kademlia with Coral and S/Kademlia modifications.
package dht

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	pb "github.com/libp2p/go-libp2p-kad-dht/pb"
	providers "github.com/libp2p/go-libp2p-kad-dht/providers"
	routing "github.com/libp2p/go-libp2p-routing"

	proto "github.com/gogo/protobuf/proto"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	ci "github.com/libp2p/go-libp2p-crypto"
	host "github.com/libp2p/go-libp2p-host"
	kb "github.com/libp2p/go-libp2p-kbucket"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	protocol "github.com/libp2p/go-libp2p-protocol"
	record "github.com/libp2p/go-libp2p-record"
	recpb "github.com/libp2p/go-libp2p-record/pb"
	base32 "github.com/whyrusleeping/base32"
)

var log = logging.Logger("dht")

var ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0"
var ProtocolDHTOld protocol.ID = "/ipfs/dht"

// NumBootstrapQueries defines the number of random dht queries to do to
// collect members of the routing table.
const NumBootstrapQueries = 5

// TODO. SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-dht/index.js

// IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
// It is used to implement the base IpfsRouting module.
type IpfsDHT struct {
	host      host.Host        // the network services we need
	self      peer.ID          // Local peer (yourself)
	peerstore pstore.Peerstore // Peer Registry

	datastore ds.Datastore // Local data

	routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
	providers    *providers.ProviderManager

	birth    time.Time  // When this peer started up
	diaglock sync.Mutex // lock to make diagnostics work better

	Validator record.Validator // record validator funcs
	Selector  record.Selector  // record selection funcs

	ctx  context.Context
	proc goprocess.Process

	clientOnly bool

	strmap map[peer.ID]*messageSender
	smlk   sync.Mutex
}

// NewDHT creates a new DHT object with the given peer as the 'local' host
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
	h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	return &IpfsDHT{
		datastore:    dstore,
		self:         h.ID(),
		peerstore:    h.Peerstore(),
		host:         h,
		strmap:       make(map[peer.ID]*messageSender),
		ctx:          ctx,
		providers:    providers.NewProviderManager(ctx, h.ID(), dstore),
		birth:        time.Now(),
		routingTable: kb.NewRoutingTable(KValue, kb.ConvertPeerID(h.ID()), time.Minute, h.Peerstore()),

		Validator: make(record.Validator),
		Selector:  make(record.Selector),
	}
}

// putValueToPeer stores the given key/value pair at the peer 'p'
func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
	key string, rec *recpb.Record) error {

	pmes := pb.NewMessage(pb.Message_PUT_VALUE, key, 0)
	pmes.Record = rec
	rpmes, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return err
	case nil:
		break
	}

	if err != nil {
		return err
	}

	if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
		return errors.New("value not put correctly")
	}
	return nil
}

var errInvalidRecord = errors.New("received invalid record")

// getValueOrPeers queries a particular peer p for the value for
// key. It returns either the value or a list of closer peers.
// NOTE: It will update the dht's peerstore with any new addresses
// it finds for the given peer.
func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []pstore.PeerInfo, error) {

	pmes, err := dht.getValueSingle(ctx, p, key)
	if err != nil {
		return nil, nil, err
	}

	// Perhaps we were given closer peers
	peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())

	if record := pmes.GetRecord(); record != nil {
		// Success! We were given the value
		log.Debug("getValueOrPeers: got value")

		// make sure record is valid.
		err = dht.verifyRecordOnline(ctx, record)
		if err != nil {
			log.Info("Received invalid record! (discarded)")
			// return a sentinal to signify an invalid record was received
			err = errInvalidRecord
			record = new(recpb.Record)
		}
		return record, peers, err
	}

	if len(peers) > 0 {
		log.Debug("getValueOrPeers: peers")
		return nil, peers, nil
	}

	log.Warning("getValueOrPeers: routing.ErrNotFound")
	return nil, nil, routing.ErrNotFound
}

// getValueSingle simply performs the get value RPC with the given parameters
func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID, key string) (*pb.Message, error) {
	meta := logging.LoggableMap{
		"key":  key,
		"peer": p,
	}

	defer log.EventBegin(ctx, "getValueSingle", meta).Done()

	pmes := pb.NewMessage(pb.Message_GET_VALUE, key, 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// getLocal attempts to retrieve the value from the datastore
func (dht *IpfsDHT) getLocal(key string) (*recpb.Record, error) {
	log.Debugf("getLocal %s", key)

	v, err := dht.datastore.Get(mkDsKey(key))
	if err != nil {
		return nil, err
	}
	log.Debugf("found %s in local datastore")

	byt, ok := v.([]byte)
	if !ok {
		return nil, errors.New("value stored in datastore not []byte")
	}
	rec := new(recpb.Record)
	err = proto.Unmarshal(byt, rec)
	if err != nil {
		return nil, err
	}

	err = dht.verifyRecordLocally(rec)
	if err != nil {
		log.Debugf("local record verify failed: %s (discarded)", err)
		return nil, err
	}

	return rec, nil
}

// getOwnPrivateKey attempts to load the local peers private
// key from the peerstore.
func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
	sk := dht.peerstore.PrivKey(dht.self)
	if sk == nil {
		log.Warningf("%s dht cannot get own private key!", dht.self)
		return nil, fmt.Errorf("cannot get private key to sign record!")
	}
	return sk, nil
}

// putLocal stores the key value pair in the datastore
func (dht *IpfsDHT) putLocal(key string, rec *recpb.Record) error {
	data, err := proto.Marshal(rec)
	if err != nil {
		return err
	}

	return dht.datastore.Put(mkDsKey(key), data)
}

// Update signals the routingTable to Update its last-seen status
// on the given peer.
func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
	log.Event(ctx, "updatePeer", p)
	dht.routingTable.Update(p)
}

// FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
func (dht *IpfsDHT) FindLocal(id peer.ID) pstore.PeerInfo {
	p := dht.routingTable.Find(id)
	if p != "" {
		return dht.peerstore.PeerInfo(p)
	}
	return pstore.PeerInfo{}
}

// findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findPeerSingle", p, id).Done()

	pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), id)
		fallthrough
	default:
		return nil, err
	}
}

func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key *cid.Cid) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findProvidersSingle", p, key).Done()

	pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, key.KeyString(), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// nearestPeersToQuery returns the routing tables closest peers.
func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
	closer := dht.routingTable.NearestPeers(kb.ConvertKey(pmes.GetKey()), count)
	return closer
}

// betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID {
	closer := dht.nearestPeersToQuery(pmes, count)

	// no node? nil
	if closer == nil {
		return nil
	}

	// == to self? thats bad
	for _, p := range closer {
		if p == dht.self {
			log.Debug("attempted to return self! this shouldn't happen...")
			return nil
		}
	}

	var filtered []peer.ID
	for _, clp := range closer {
		// Dont send a peer back themselves
		if p == clp {
			continue
		}

		filtered = append(filtered, clp)
	}

	// ok seems like closer nodes
	return filtered
}

// Context return dht's context
func (dht *IpfsDHT) Context() context.Context {
	return dht.ctx
}

// Process return dht's process
func (dht *IpfsDHT) Process() goprocess.Process {
	return dht.proc
}

// Close calls Process Close
func (dht *IpfsDHT) Close() error {
	return dht.proc.Close()
}

func mkDsKey(s string) ds.Key {
	return ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte(s)))
}
<commit_msg>Remove outdated comment; fixes #23<commit_after>// Package dht implements a distributed hash table that satisfies the ipfs routing
// interface. This DHT is modeled after kademlia with Coral and S/Kademlia modifications.
package dht

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	pb "github.com/libp2p/go-libp2p-kad-dht/pb"
	providers "github.com/libp2p/go-libp2p-kad-dht/providers"
	routing "github.com/libp2p/go-libp2p-routing"

	proto "github.com/gogo/protobuf/proto"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	ci "github.com/libp2p/go-libp2p-crypto"
	host "github.com/libp2p/go-libp2p-host"
	kb "github.com/libp2p/go-libp2p-kbucket"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	protocol "github.com/libp2p/go-libp2p-protocol"
	record "github.com/libp2p/go-libp2p-record"
	recpb "github.com/libp2p/go-libp2p-record/pb"
	base32 "github.com/whyrusleeping/base32"
)

var log = logging.Logger("dht")

var ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0"
var ProtocolDHTOld protocol.ID = "/ipfs/dht"

// NumBootstrapQueries defines the number of random dht queries to do to
// collect members of the routing table.
const NumBootstrapQueries = 5

// IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
// It is used to implement the base IpfsRouting module.
type IpfsDHT struct {
	host      host.Host        // the network services we need
	self      peer.ID          // Local peer (yourself)
	peerstore pstore.Peerstore // Peer Registry

	datastore ds.Datastore // Local data

	routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
	providers    *providers.ProviderManager

	birth    time.Time  // When this peer started up
	diaglock sync.Mutex // lock to make diagnostics work better

	Validator record.Validator // record validator funcs
	Selector  record.Selector  // record selection funcs

	ctx  context.Context
	proc goprocess.Process

	clientOnly bool

	strmap map[peer.ID]*messageSender
	smlk   sync.Mutex
}

// NewDHT creates a new DHT object with the given peer as the 'local' host
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
	h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	return &IpfsDHT{
		datastore:    dstore,
		self:         h.ID(),
		peerstore:    h.Peerstore(),
		host:         h,
		strmap:       make(map[peer.ID]*messageSender),
		ctx:          ctx,
		providers:    providers.NewProviderManager(ctx, h.ID(), dstore),
		birth:        time.Now(),
		routingTable: kb.NewRoutingTable(KValue, kb.ConvertPeerID(h.ID()), time.Minute, h.Peerstore()),

		Validator: make(record.Validator),
		Selector:  make(record.Selector),
	}
}

// putValueToPeer stores the given key/value pair at the peer 'p'
func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
	key string, rec *recpb.Record) error {

	pmes := pb.NewMessage(pb.Message_PUT_VALUE, key, 0)
	pmes.Record = rec
	rpmes, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return err
	case nil:
		break
	}

	if err != nil {
		return err
	}

	if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
		return errors.New("value not put correctly")
	}
	return nil
}

var errInvalidRecord = errors.New("received invalid record")

// getValueOrPeers queries a particular peer p for the value for
// key. It returns either the value or a list of closer peers.
// NOTE: It will update the dht's peerstore with any new addresses
// it finds for the given peer.
func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []pstore.PeerInfo, error) {

	pmes, err := dht.getValueSingle(ctx, p, key)
	if err != nil {
		return nil, nil, err
	}

	// Perhaps we were given closer peers
	peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())

	if record := pmes.GetRecord(); record != nil {
		// Success! We were given the value
		log.Debug("getValueOrPeers: got value")

		// make sure record is valid.
		err = dht.verifyRecordOnline(ctx, record)
		if err != nil {
			log.Info("Received invalid record! (discarded)")
			// return a sentinal to signify an invalid record was received
			err = errInvalidRecord
			record = new(recpb.Record)
		}
		return record, peers, err
	}

	if len(peers) > 0 {
		log.Debug("getValueOrPeers: peers")
		return nil, peers, nil
	}

	log.Warning("getValueOrPeers: routing.ErrNotFound")
	return nil, nil, routing.ErrNotFound
}

// getValueSingle simply performs the get value RPC with the given parameters
func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID, key string) (*pb.Message, error) {
	meta := logging.LoggableMap{
		"key":  key,
		"peer": p,
	}

	defer log.EventBegin(ctx, "getValueSingle", meta).Done()

	pmes := pb.NewMessage(pb.Message_GET_VALUE, key, 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// getLocal attempts to retrieve the value from the datastore
func (dht *IpfsDHT) getLocal(key string) (*recpb.Record, error) {
	log.Debugf("getLocal %s", key)

	v, err := dht.datastore.Get(mkDsKey(key))
	if err != nil {
		return nil, err
	}
	log.Debugf("found %s in local datastore")

	byt, ok := v.([]byte)
	if !ok {
		return nil, errors.New("value stored in datastore not []byte")
	}
	rec := new(recpb.Record)
	err = proto.Unmarshal(byt, rec)
	if err != nil {
		return nil, err
	}

	err = dht.verifyRecordLocally(rec)
	if err != nil {
		log.Debugf("local record verify failed: %s (discarded)", err)
		return nil, err
	}

	return rec, nil
}

// getOwnPrivateKey attempts to load the local peers private
// key from the peerstore.
func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
	sk := dht.peerstore.PrivKey(dht.self)
	if sk == nil {
		log.Warningf("%s dht cannot get own private key!", dht.self)
		return nil, fmt.Errorf("cannot get private key to sign record!")
	}
	return sk, nil
}

// putLocal stores the key value pair in the datastore
func (dht *IpfsDHT) putLocal(key string, rec *recpb.Record) error {
	data, err := proto.Marshal(rec)
	if err != nil {
		return err
	}

	return dht.datastore.Put(mkDsKey(key), data)
}

// Update signals the routingTable to Update its last-seen status
// on the given peer.
func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
	log.Event(ctx, "updatePeer", p)
	dht.routingTable.Update(p)
}

// FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
func (dht *IpfsDHT) FindLocal(id peer.ID) pstore.PeerInfo {
	p := dht.routingTable.Find(id)
	if p != "" {
		return dht.peerstore.PeerInfo(p)
	}
	return pstore.PeerInfo{}
}

// findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findPeerSingle", p, id).Done()

	pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), id)
		fallthrough
	default:
		return nil, err
	}
}

func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key *cid.Cid) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findProvidersSingle", p, key).Done()

	pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, key.KeyString(), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// nearestPeersToQuery returns the routing tables closest peers.
func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
	closer := dht.routingTable.NearestPeers(kb.ConvertKey(pmes.GetKey()), count)
	return closer
}

// betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID {
	closer := dht.nearestPeersToQuery(pmes, count)

	// no node? nil
	if closer == nil {
		return nil
	}

	// == to self? thats bad
	for _, p := range closer {
		if p == dht.self {
			log.Debug("attempted to return self! this shouldn't happen...")
			return nil
		}
	}

	var filtered []peer.ID
	for _, clp := range closer {
		// Dont send a peer back themselves
		if p == clp {
			continue
		}

		filtered = append(filtered, clp)
	}

	// ok seems like closer nodes
	return filtered
}

// Context return dht's context
func (dht *IpfsDHT) Context() context.Context {
	return dht.ctx
}

// Process return dht's process
func (dht *IpfsDHT) Process() goprocess.Process {
	return dht.proc
}

// Close calls Process Close
func (dht *IpfsDHT) Close() error {
	return dht.proc.Close()
}

func mkDsKey(s string) ds.Key {
	return ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte(s)))
}
<|endoftext|>


<commit_before>// Package lunk provides a set of tools for structured logging in the style of
// Google's Dapper or Twitter's Zipkin.
//
// The Context Of Structured Logging
//
// When we consider a complex event in a distributed system, we're actually
// considering a partially-ordered tree of events from various services,
// libraries, and modules.
//
// Consider a user-initiated web request. Their browser sends an HTTP request to
// an edge server, which extracts the credentials (e.g., OAuth token) and
// authenticates the request by communicating with an internal authentication
// service, which returns a signed set of internal credentials (e.g., signed user
// ID). The edge web server then proxies the request to a cluster of web servers,
// each running a PHP application. The PHP application loads some data from
// several databases, places the user in a number of treatment groups for running
// A/B experiments, writes some data to a Dynamo-style distributed database, and
// returns an HTML response. The edge server receives this response and proxies
// it to the user's browser.
//
// In this scenario we have a number of infrastructure-specific events:
//
//     1.  The edge server handled a request, which took 142ms and whose response
//         had a status of "200 OK".
//     2.  The edge server sent a request to the authentication service, which
//         took 5ms to handle and identified the principal as user 14002.
//     3.  The authentication service handled a request, which took 4ms to handle
//         and was served entirely from memory.
//     4.  The edge server proxied a request to the app cluster, which took 132ms
//         and whose response had a status of "200 OK".
//     5.  The app load balancer handled a request, which took 131ms and whose
//         response had a status of "200 OK".
//     6.  The app load balancer proxied a request to the app, which took 130ms
//         and was handled by app server 10.
//     7.  The app handled a request, which took 129ms, and was handled by
//         PhotoController.
//     8.  The app sent a query to database A, which took 1ms.
//     9.  The app sent a query to database B, which took 53ms.
//     10. The app rendered template "photo.tpl", which took 4ms.
//     11. The app wrote a value to the distributed database, which took 10ms.
//     12. The distributed database handled the write locally on one node, and
//         proxied it to two others, which took 9ms.
//     13. Those distributed database nodes concurrently handled the write
//         locally, which took 4ms and 8ms.
//
// This scenario also involves a number of events which have little to do with
// the infrastructure, but are still critical information for the business the
// system supports:
//
//     14. The app gave the user the control treatment for experiment 15 ("Really
//         Big Buttons v2").
//     15. The app gave the user the experimental treatment for experiment 54
//         ("More Yelling v1").
//     16. User 14002 viewed photo 1819 ("rude-puppy.gif").
//
// There are a number of different teams all trying to monitor and improve
// aspects of this system. Operational staff need to know if a particular host or
// service is experiencing a latency spike or drop in throughput. Development
// staff need to know if their application's response times have gone down as a
// result of a recent deploy. Customer support staff need to know if the system
// is operating nominally as a whole, and for customers in particular. Product
// designers and managers need to know the effect of an A/B test on user
// behavior. But the fact that these teams will be consuming the data in
// different ways for different purposes does mean that they are working on
// different systems.
//
// In order to instrument the various components of the system, we need a common
// data model.
//
// Trees Of Events
//
// We adopt Dapper's notion of a tree to mean a partially-ordered tree of events
// from a distributed system. A tree in Lunk is identified by its root ID, which
// is the unique ID of its root event. All events in a common tree share a root
// ID.  In our photo example, we would assign a unique root ID as soon as the
// edge server received the request.
//
// Events inside a tree are casually ordered: each event has a unique ID, and an
// optional parent ID. By passing the IDs across systems, we establish casual
// ordering between events. In our photo example, the two database queries from
// the app would share the same parent ID--the ID of the event corresponding to
// the app handling the request which caused those queries.
//
// Each event has a schema of properties, which allow us to record specific
// pieces of information about each event. For HTTP requests, we can record the
// method, the request URI, the elapsed time to handle the request, etc.
//
// Event Aggregation
//
// Lunk is agnostic in terms of aggregation technologies, but two use cases seem
// clear: real-time process monitoring and offline causational analysis.
//
// For real-time process monitoring, events can be streamed to a aggregation
// service like Riemann (http://riemann.io) or Storm
// (http://storm.incubator.apache.org), which can calculate process statistics
// (e.g., the 95th percentile latency for the edge server responses) in
// real-time. This allows for adaptive monitoring of all services, with the
// option of including example root IDs in the alerts (e.g., 95th percentile
// latency is over 300ms, mostly as a result of requests like those in tree
// XXXXX).
//
// For offline causational analysis, events can be written in batches to
// batch processing systems like Hadoop or OLAP databases like Vertica. These
// aggregates can be queried to answer questions traditionally reserved for
// A/B testing systems. "Did users who were show the new navbar view more
// photos?" "Did the new image optimization algorithm we enabled for 1% of views
// run faster? Did it produce smaller images? Did it have any effect on user
// engagement?" "Did any services have increased exception rates after any recent
// deploys?" &tc &tc
//
// Observing Specific Events
//
// By capturing the root ID of a particular web request, we can assemble a
// partially-ordered tree of events which were involved in the handling of that
// request. All events with a common root ID are in a common tree, which allows
// for O(M) retrieval for a tree of M events.
package lunk
<commit_msg>Definitely not casually ordering things.<commit_after>// Package lunk provides a set of tools for structured logging in the style of
// Google's Dapper or Twitter's Zipkin.
//
// The Context Of Structured Logging
//
// When we consider a complex event in a distributed system, we're actually
// considering a partially-ordered tree of events from various services,
// libraries, and modules.
//
// Consider a user-initiated web request. Their browser sends an HTTP request to
// an edge server, which extracts the credentials (e.g., OAuth token) and
// authenticates the request by communicating with an internal authentication
// service, which returns a signed set of internal credentials (e.g., signed user
// ID). The edge web server then proxies the request to a cluster of web servers,
// each running a PHP application. The PHP application loads some data from
// several databases, places the user in a number of treatment groups for running
// A/B experiments, writes some data to a Dynamo-style distributed database, and
// returns an HTML response. The edge server receives this response and proxies
// it to the user's browser.
//
// In this scenario we have a number of infrastructure-specific events:
//
//     1.  The edge server handled a request, which took 142ms and whose response
//         had a status of "200 OK".
//     2.  The edge server sent a request to the authentication service, which
//         took 5ms to handle and identified the principal as user 14002.
//     3.  The authentication service handled a request, which took 4ms to handle
//         and was served entirely from memory.
//     4.  The edge server proxied a request to the app cluster, which took 132ms
//         and whose response had a status of "200 OK".
//     5.  The app load balancer handled a request, which took 131ms and whose
//         response had a status of "200 OK".
//     6.  The app load balancer proxied a request to the app, which took 130ms
//         and was handled by app server 10.
//     7.  The app handled a request, which took 129ms, and was handled by
//         PhotoController.
//     8.  The app sent a query to database A, which took 1ms.
//     9.  The app sent a query to database B, which took 53ms.
//     10. The app rendered template "photo.tpl", which took 4ms.
//     11. The app wrote a value to the distributed database, which took 10ms.
//     12. The distributed database handled the write locally on one node, and
//         proxied it to two others, which took 9ms.
//     13. Those distributed database nodes concurrently handled the write
//         locally, which took 4ms and 8ms.
//
// This scenario also involves a number of events which have little to do with
// the infrastructure, but are still critical information for the business the
// system supports:
//
//     14. The app gave the user the control treatment for experiment 15 ("Really
//         Big Buttons v2").
//     15. The app gave the user the experimental treatment for experiment 54
//         ("More Yelling v1").
//     16. User 14002 viewed photo 1819 ("rude-puppy.gif").
//
// There are a number of different teams all trying to monitor and improve
// aspects of this system. Operational staff need to know if a particular host or
// service is experiencing a latency spike or drop in throughput. Development
// staff need to know if their application's response times have gone down as a
// result of a recent deploy. Customer support staff need to know if the system
// is operating nominally as a whole, and for customers in particular. Product
// designers and managers need to know the effect of an A/B test on user
// behavior. But the fact that these teams will be consuming the data in
// different ways for different purposes does mean that they are working on
// different systems.
//
// In order to instrument the various components of the system, we need a common
// data model.
//
// Trees Of Events
//
// We adopt Dapper's notion of a tree to mean a partially-ordered tree of events
// from a distributed system. A tree in Lunk is identified by its root ID, which
// is the unique ID of its root event. All events in a common tree share a root
// ID.  In our photo example, we would assign a unique root ID as soon as the
// edge server received the request.
//
// Events inside a tree are causally ordered: each event has a unique ID, and an
// optional parent ID. By passing the IDs across systems, we establish causal
// ordering between events. In our photo example, the two database queries from
// the app would share the same parent ID--the ID of the event corresponding to
// the app handling the request which caused those queries.
//
// Each event has a schema of properties, which allow us to record specific
// pieces of information about each event. For HTTP requests, we can record the
// method, the request URI, the elapsed time to handle the request, etc.
//
// Event Aggregation
//
// Lunk is agnostic in terms of aggregation technologies, but two use cases seem
// clear: real-time process monitoring and offline causational analysis.
//
// For real-time process monitoring, events can be streamed to a aggregation
// service like Riemann (http://riemann.io) or Storm
// (http://storm.incubator.apache.org), which can calculate process statistics
// (e.g., the 95th percentile latency for the edge server responses) in
// real-time. This allows for adaptive monitoring of all services, with the
// option of including example root IDs in the alerts (e.g., 95th percentile
// latency is over 300ms, mostly as a result of requests like those in tree
// XXXXX).
//
// For offline causational analysis, events can be written in batches to
// batch processing systems like Hadoop or OLAP databases like Vertica. These
// aggregates can be queried to answer questions traditionally reserved for
// A/B testing systems. "Did users who were show the new navbar view more
// photos?" "Did the new image optimization algorithm we enabled for 1% of views
// run faster? Did it produce smaller images? Did it have any effect on user
// engagement?" "Did any services have increased exception rates after any recent
// deploys?" &tc &tc
//
// Observing Specific Events
//
// By capturing the root ID of a particular web request, we can assemble a
// partially-ordered tree of events which were involved in the handling of that
// request. All events with a common root ID are in a common tree, which allows
// for O(M) retrieval for a tree of M events.
package lunk
<|endoftext|>