<commit_before>package shapes

import (
	"fmt"
	"image/color"

	"github.com/remogatto/mathgl"
	gl "github.com/remogatto/opengles2"
	"github.com/remogatto/shaders"
)

type World interface {
	// Projection returns the projection matrix used to render
	// the objects in the World.
	Projection() mathgl.Mat4f

	// View returns the view matrix used to render the World from
	// the point-of-view of a camera.
	View() mathgl.Mat4f
}

type Box struct {
	// Center of the box
	X, Y float32

	// Size of the box
	Width, Height float32

	// Color of the box
	color [16]float32

	// Vertices of the box
	vertices [8]float32

	program shaders.Program

	// Matrices
	projMatrix  mathgl.Mat4f
	modelMatrix mathgl.Mat4f
	viewMatrix  mathgl.Mat4f

	// GLSL variables IDs
	colorId       uint32
	posId         uint32
	projMatrixId  uint32
	modelMatrixId uint32
	viewMatrixId  uint32
}

func NewBox(width, height float32) *Box {

	// The box is built around its center
	vertices := [8]float32{
		-width / 2, -height / 2,
		width / 2, -height / 2,
		-width / 2, height / 2,
		width / 2, height / 2,
	}

	// Default color is blue
	color := [16]float32{
		0, 0, 1, 1,
		0, 0, 1, 1,
		0, 0, 1, 1,
		0, 0, 1, 1,
	}

	x, y := width/2, height/2

	// Shader sources

	vShaderSrc := (shaders.VertexShader)(
		`precision mediump float;
                 attribute vec4 pos;
                 attribute vec4 color;
                 varying vec4 vColor;
                 uniform mat4 model;
                 uniform mat4 projection;
                 uniform mat4 view;
                 void main() {
                     gl_Position = projection*model*view*pos;
                     vColor = color;
                 }`)
	fShaderSrc := (shaders.FragmentShader)(
		`precision mediump float;
                 varying vec4 vColor;
                 void main() {
                     gl_FragColor = vColor;
                 }`)

	// Link the program
	program := shaders.NewProgram(vShaderSrc.Compile(), fShaderSrc.Compile())
	program.Use()

	// Get variables IDs from shaders
	posId := program.GetAttribute("pos")
	colorId := program.GetAttribute("color")
	projMatrixId := program.GetUniform("projection")
	modelMatrixId := program.GetUniform("model")
	viewMatrixId := program.GetUniform("view")

	// Fill the model matrix with the identity.
	modelMatrix := mathgl.Ident4f()

	return &Box{
		X:             x,
		Y:             y,
		Width:         width,
		Height:        height,
		vertices:      vertices,
		color:         color,
		program:       program,
		posId:         posId,
		colorId:       colorId,
		projMatrixId:  projMatrixId,
		modelMatrixId: modelMatrixId,
		viewMatrixId:  viewMatrixId,
		modelMatrix:   modelMatrix,
	}
}

// AttachToWorld fills projection and view matrices.
func (box *Box) AttachToWorld(world World) {
	box.projMatrix = world.Projection()
	box.viewMatrix = world.View()
}

// Rotate the box around its center, by the given angle (in degrees).
func (box *Box) Rotate(angle float32) {
	box.modelMatrix = mathgl.Translate3D(box.X, box.Y, 0).Mul4(mathgl.HomogRotate3DZ(angle))
}

// Place the box at the given position
func (box *Box) Position(x, y float32) {
	box.X, box.Y = x, y
	box.modelMatrix = mathgl.Translate3D(x, y, 0)
}

// Draw actually renders the object on the surface.
func (box *Box) Draw() {
	box.program.Use()
	gl.VertexAttribPointer(box.posId, 2, gl.FLOAT, false, 0, &box.vertices[0])
	gl.EnableVertexAttribArray(box.posId)

	gl.VertexAttribPointer(box.colorId, 4, gl.FLOAT, false, 0, &box.color[0])
	gl.EnableVertexAttribArray(box.colorId)

	gl.UniformMatrix4fv(int32(box.modelMatrixId), 1, false, (*float32)(&box.modelMatrix[0]))
	gl.UniformMatrix4fv(int32(box.projMatrixId), 1, false, (*float32)(&box.projMatrix[0]))
	gl.UniformMatrix4fv(int32(box.viewMatrixId), 1, false, (*float32)(&box.viewMatrix[0]))

	gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)

	gl.Flush()
	gl.Finish()
}

// Set the color of the shape.
func (box *Box) Color(c color.Color) {
	// Convert to RGBA
	rgba := color.RGBAModel.Convert(c)
	r, g, b, a := rgba.RGBA()
	// Normalize the color components
	box.color = [16]float32{
		float32(r) / float32(65535), float32(g) / float32(65535), float32(b) / float32(65535), float32(a) / float32(65535),
		float32(r) / float32(65535), float32(g) / float32(65535), float32(b) / float32(65535), float32(a) / float32(65535),
		float32(r) / float32(65535), float32(g) / float32(65535), float32(b) / float32(65535), float32(a) / float32(65535),
		float32(r) / float32(65535), float32(g) / float32(65535), float32(b) / float32(65535), float32(a) / float32(65535),
	}
}

// String return a string representation of the original box vertices
// (before transformation).
func (box *Box) String() string {
	return fmt.Sprintf("%v", box.vertices)
}

type Line struct {
	// Points of the line
	X1, Y1, X2, Y2 float32

	// Color of the line
	color [8]float32

	program shaders.Program

	// Matrices
	projMatrix  mathgl.Mat4f
	modelMatrix mathgl.Mat4f
	viewMatrix  mathgl.Mat4f

	// GLSL variables IDs
	colorId       uint32
	posId         uint32
	projMatrixId  uint32
	modelMatrixId uint32
	viewMatrixId  uint32
}

func NewLine(x1, y1, x2, y2 float32) *Line {

	// Default color is blue
	color := [8]float32{
		0, 0, 1, 1,
		0, 0, 1, 1,
	}

	// Shader sources

	vShaderSrc := (shaders.VertexShader)(
		`precision mediump float;
                 attribute vec4 pos;
                 attribute vec4 color;
                 varying vec4 vColor;
                 uniform mat4 model;
                 uniform mat4 projection;
                 uniform mat4 view;
                 void main() {
                     gl_Position = projection*model*view*pos;
                     vColor = color;
                 }`)
	fShaderSrc := (shaders.FragmentShader)(
		`precision mediump float;
                 varying vec4 vColor;
                 void main() {
                     gl_FragColor = vColor;
                 }`)

	// Link the program
	program := shaders.NewProgram(vShaderSrc.Compile(), fShaderSrc.Compile())
	program.Use()

	// Get variables IDs from shaders
	posId := program.GetAttribute("pos")
	colorId := program.GetAttribute("color")
	projMatrixId := program.GetUniform("projection")
	modelMatrixId := program.GetUniform("model")
	viewMatrixId := program.GetUniform("view")

	// Fill the model matrix with the identity.
	modelMatrix := mathgl.Ident4f()

	return &Line{
		X1:            x1,
		Y1:            y1,
		X2:            x2,
		Y2:            y2,
		color:         color,
		program:       program,
		posId:         posId,
		colorId:       colorId,
		projMatrixId:  projMatrixId,
		modelMatrixId: modelMatrixId,
		viewMatrixId:  viewMatrixId,
		modelMatrix:   modelMatrix,
	}
}

// AttachToWorld fills projection and view matrices.
func (line *Line) AttachToWorld(world World) {
	line.projMatrix = world.Projection()
	line.viewMatrix = world.View()
}

// Draw actually renders the object on the surface.
func (line *Line) Draw() {

	vertices := [4]float32{
		line.X1, line.Y1,
		line.X2, line.Y2,
	}

	line.program.Use()
	gl.VertexAttribPointer(line.posId, 2, gl.FLOAT, false, 0, &vertices[0])
	gl.EnableVertexAttribArray(line.posId)

	gl.VertexAttribPointer(line.colorId, 4, gl.FLOAT, false, 0, &line.color[0])
	gl.EnableVertexAttribArray(line.colorId)

	gl.UniformMatrix4fv(int32(line.modelMatrixId), 1, false, (*float32)(&line.modelMatrix[0]))
	gl.UniformMatrix4fv(int32(line.projMatrixId), 1, false, (*float32)(&line.projMatrix[0]))
	gl.UniformMatrix4fv(int32(line.viewMatrixId), 1, false, (*float32)(&line.viewMatrix[0]))

	gl.DrawArrays(gl.LINES, 0, 2)

	gl.Flush()
	gl.Finish()
}

// Set the color of the shape.
func (line *Line) Color(c color.Color) {
	// Convert to RGBA
	rgba := color.RGBAModel.Convert(c)
	r, g, b, a := rgba.RGBA()
	// Normalize the color components
	line.color = [8]float32{
		float32(r / 65535), float32(g / 65535), float32(b / 65535), float32(a / 65535),
		float32(r / 65535), float32(g / 65535), float32(b / 65535), float32(a / 65535),
	}
}

// String return a string representation of the original box vertices
// (before transformation).
func (line *Line) String() string {
	return fmt.Sprintf("x1: %f y1: %f x2: %f y2: %f", line.X1, line.Y1, line.X2, line.Y2)
}
<commit_msg>Remove useless type conversion for denominators<commit_after>package shapes

import (
	"fmt"
	"image/color"

	"github.com/remogatto/mathgl"
	gl "github.com/remogatto/opengles2"
	"github.com/remogatto/shaders"
)

type World interface {
	// Projection returns the projection matrix used to render
	// the objects in the World.
	Projection() mathgl.Mat4f

	// View returns the view matrix used to render the World from
	// the point-of-view of a camera.
	View() mathgl.Mat4f
}

type Box struct {
	// Center of the box
	X, Y float32

	// Size of the box
	Width, Height float32

	// Color of the box
	color [16]float32

	// Vertices of the box
	vertices [8]float32

	program shaders.Program

	// Matrices
	projMatrix  mathgl.Mat4f
	modelMatrix mathgl.Mat4f
	viewMatrix  mathgl.Mat4f

	// GLSL variables IDs
	colorId       uint32
	posId         uint32
	projMatrixId  uint32
	modelMatrixId uint32
	viewMatrixId  uint32
}

func NewBox(width, height float32) *Box {

	// The box is built around its center
	vertices := [8]float32{
		-width / 2, -height / 2,
		width / 2, -height / 2,
		-width / 2, height / 2,
		width / 2, height / 2,
	}

	// Default color is blue
	color := [16]float32{
		0, 0, 1, 1,
		0, 0, 1, 1,
		0, 0, 1, 1,
		0, 0, 1, 1,
	}

	x, y := width/2, height/2

	// Shader sources

	vShaderSrc := (shaders.VertexShader)(
		`precision mediump float;
                 attribute vec4 pos;
                 attribute vec4 color;
                 varying vec4 vColor;
                 uniform mat4 model;
                 uniform mat4 projection;
                 uniform mat4 view;
                 void main() {
                     gl_Position = projection*model*view*pos;
                     vColor = color;
                 }`)
	fShaderSrc := (shaders.FragmentShader)(
		`precision mediump float;
                 varying vec4 vColor;
                 void main() {
                     gl_FragColor = vColor;
                 }`)

	// Link the program
	program := shaders.NewProgram(vShaderSrc.Compile(), fShaderSrc.Compile())
	program.Use()

	// Get variables IDs from shaders
	posId := program.GetAttribute("pos")
	colorId := program.GetAttribute("color")
	projMatrixId := program.GetUniform("projection")
	modelMatrixId := program.GetUniform("model")
	viewMatrixId := program.GetUniform("view")

	// Fill the model matrix with the identity.
	modelMatrix := mathgl.Ident4f()

	return &Box{
		X:             x,
		Y:             y,
		Width:         width,
		Height:        height,
		vertices:      vertices,
		color:         color,
		program:       program,
		posId:         posId,
		colorId:       colorId,
		projMatrixId:  projMatrixId,
		modelMatrixId: modelMatrixId,
		viewMatrixId:  viewMatrixId,
		modelMatrix:   modelMatrix,
	}
}

// AttachToWorld fills projection and view matrices.
func (box *Box) AttachToWorld(world World) {
	box.projMatrix = world.Projection()
	box.viewMatrix = world.View()
}

// Rotate the box around its center, by the given angle (in degrees).
func (box *Box) Rotate(angle float32) {
	box.modelMatrix = mathgl.Translate3D(box.X, box.Y, 0).Mul4(mathgl.HomogRotate3DZ(angle))
}

// Place the box at the given position
func (box *Box) Position(x, y float32) {
	box.X, box.Y = x, y
	box.modelMatrix = mathgl.Translate3D(x, y, 0)
}

// Draw actually renders the object on the surface.
func (box *Box) Draw() {
	box.program.Use()
	gl.VertexAttribPointer(box.posId, 2, gl.FLOAT, false, 0, &box.vertices[0])
	gl.EnableVertexAttribArray(box.posId)

	gl.VertexAttribPointer(box.colorId, 4, gl.FLOAT, false, 0, &box.color[0])
	gl.EnableVertexAttribArray(box.colorId)

	gl.UniformMatrix4fv(int32(box.modelMatrixId), 1, false, (*float32)(&box.modelMatrix[0]))
	gl.UniformMatrix4fv(int32(box.projMatrixId), 1, false, (*float32)(&box.projMatrix[0]))
	gl.UniformMatrix4fv(int32(box.viewMatrixId), 1, false, (*float32)(&box.viewMatrix[0]))

	gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)

	gl.Flush()
	gl.Finish()
}

// Set the color of the shape.
func (box *Box) Color(c color.Color) {
	// Convert to RGBA
	rgba := color.RGBAModel.Convert(c)
	r, g, b, a := rgba.RGBA()
	// Normalize the color components
	box.color = [16]float32{
		float32(r) / 65535, float32(g) / 65535, float32(b) / 65535, float32(a) / 65535,
		float32(r) / 65535, float32(g) / 65535, float32(b) / 65535, float32(a) / 65535,
		float32(r) / 65535, float32(g) / 65535, float32(b) / 65535, float32(a) / 65535,
		float32(r) / 65535, float32(g) / 65535, float32(b) / 65535, float32(a) / 65535,
	}
}

// String return a string representation of the original box vertices
// (before transformation).
func (box *Box) String() string {
	return fmt.Sprintf("%v", box.vertices)
}

type Line struct {
	// Points of the line
	X1, Y1, X2, Y2 float32

	// Color of the line
	color [8]float32

	program shaders.Program

	// Matrices
	projMatrix  mathgl.Mat4f
	modelMatrix mathgl.Mat4f
	viewMatrix  mathgl.Mat4f

	// GLSL variables IDs
	colorId       uint32
	posId         uint32
	projMatrixId  uint32
	modelMatrixId uint32
	viewMatrixId  uint32
}

func NewLine(x1, y1, x2, y2 float32) *Line {

	// Default color is blue
	color := [8]float32{
		0, 0, 1, 1,
		0, 0, 1, 1,
	}

	// Shader sources

	vShaderSrc := (shaders.VertexShader)(
		`precision mediump float;
                 attribute vec4 pos;
                 attribute vec4 color;
                 varying vec4 vColor;
                 uniform mat4 model;
                 uniform mat4 projection;
                 uniform mat4 view;
                 void main() {
                     gl_Position = projection*model*view*pos;
                     vColor = color;
                 }`)
	fShaderSrc := (shaders.FragmentShader)(
		`precision mediump float;
                 varying vec4 vColor;
                 void main() {
                     gl_FragColor = vColor;
                 }`)

	// Link the program
	program := shaders.NewProgram(vShaderSrc.Compile(), fShaderSrc.Compile())
	program.Use()

	// Get variables IDs from shaders
	posId := program.GetAttribute("pos")
	colorId := program.GetAttribute("color")
	projMatrixId := program.GetUniform("projection")
	modelMatrixId := program.GetUniform("model")
	viewMatrixId := program.GetUniform("view")

	// Fill the model matrix with the identity.
	modelMatrix := mathgl.Ident4f()

	return &Line{
		X1:            x1,
		Y1:            y1,
		X2:            x2,
		Y2:            y2,
		color:         color,
		program:       program,
		posId:         posId,
		colorId:       colorId,
		projMatrixId:  projMatrixId,
		modelMatrixId: modelMatrixId,
		viewMatrixId:  viewMatrixId,
		modelMatrix:   modelMatrix,
	}
}

// AttachToWorld fills projection and view matrices.
func (line *Line) AttachToWorld(world World) {
	line.projMatrix = world.Projection()
	line.viewMatrix = world.View()
}

// Draw actually renders the object on the surface.
func (line *Line) Draw() {

	vertices := [4]float32{
		line.X1, line.Y1,
		line.X2, line.Y2,
	}

	line.program.Use()
	gl.VertexAttribPointer(line.posId, 2, gl.FLOAT, false, 0, &vertices[0])
	gl.EnableVertexAttribArray(line.posId)

	gl.VertexAttribPointer(line.colorId, 4, gl.FLOAT, false, 0, &line.color[0])
	gl.EnableVertexAttribArray(line.colorId)

	gl.UniformMatrix4fv(int32(line.modelMatrixId), 1, false, (*float32)(&line.modelMatrix[0]))
	gl.UniformMatrix4fv(int32(line.projMatrixId), 1, false, (*float32)(&line.projMatrix[0]))
	gl.UniformMatrix4fv(int32(line.viewMatrixId), 1, false, (*float32)(&line.viewMatrix[0]))

	gl.DrawArrays(gl.LINES, 0, 2)

	gl.Flush()
	gl.Finish()
}

// Set the color of the shape.
func (line *Line) Color(c color.Color) {
	// Convert to RGBA
	rgba := color.RGBAModel.Convert(c)
	r, g, b, a := rgba.RGBA()
	// Normalize the color components
	line.color = [8]float32{
		float32(r / 65535), float32(g / 65535), float32(b / 65535), float32(a / 65535),
		float32(r / 65535), float32(g / 65535), float32(b / 65535), float32(a / 65535),
	}
}

// String return a string representation of the original box vertices
// (before transformation).
func (line *Line) String() string {
	return fmt.Sprintf("x1: %f y1: %f x2: %f y2: %f", line.X1, line.Y1, line.X2, line.Y2)
}
<|endoftext|>


<commit_before>package uspv

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
	"github.com/mit-dci/lit/wire"
	"golang.org/x/net/proxy"
)

// IP4 ...
func IP4(ipAddress string) bool {
	parseIP := net.ParseIP(ipAddress)
	if parseIP.To4() == nil {
		return false
	}
	return true
}

func (s *SPVCon) parseRemoteNode(remoteNode string) (string, string, error) {
	colonCount := strings.Count(remoteNode, ":")
	var conMode string
	if colonCount <= 1 {
		if colonCount == 0 {
			remoteNode = remoteNode + ":" + s.Param.DefaultPort
		}
		return remoteNode, "tcp4", nil
	} else if colonCount >= 5 {
		// ipv6 without remote port
		// assume users don't give ports with ipv6 nodes
		if !strings.Contains(remoteNode, "[") && !strings.Contains(remoteNode, "]") {
			remoteNode = "[" + remoteNode + "]" + ":" + s.Param.DefaultPort
		}
		conMode = "tcp6"
		return remoteNode, conMode, nil
	} else {
		return "", "", fmt.Errorf("Invalid ip")
	}
}

// GetListOfNodes contacts all DNSSeeds for the coin specified and then contacts
// each one of them in order to receive a list of ips and then returns a combined
// list
func (s *SPVCon) GetListOfNodes() ([]string, error) {
	var listOfNodes []string // slice of IP addrs returned from the DNS seed
	logging.Infof("Attempting to retrieve peers to connect to based on DNS Seed\n")

	for _, seed := range s.Param.DNSSeeds {
		temp, err := net.LookupHost(seed)
		// need this temp in order to capture the error from net.LookupHost
		// also need this to report the number of IPs we get from a seed
		if err != nil {
			logging.Infof("Have difficulty trying to connect to %s. Going to the next seed", seed)
			continue
		}
		listOfNodes = append(listOfNodes, temp...)
		logging.Infof("Got %d IPs from DNS seed %s\n", len(temp), seed)
	}
	if len(listOfNodes) == 0 {
		return nil, fmt.Errorf("No peers found connected to DNS Seeds. Please provide a host to connect to.")
	}
	logging.Info(listOfNodes)
	return listOfNodes, nil
}

// DialNode receives a list of node ips and then tries to connect to them one by one.
func (s *SPVCon) DialNode(listOfNodes []string) error {

	// now have some IPs, go through and try to connect to one.
	var err error
	for i, ip := range listOfNodes {
		// try to connect to all nodes in this range
		var conString, conMode string
		// need to check whether conString is ipv4 or ipv6
		conString, conMode, err = s.parseRemoteNode(ip)
		if err != nil {
			logging.Infof("parse error for node (skipped): %s", err)
			continue
		}
		logging.Infof("Attempting connection to node at %s\n",
			conString)

		if s.ProxyURL != "" {
			logging.Infof("Attempting to connect via proxy %s", s.ProxyURL)
			d, err := proxy.SOCKS5("tcp", s.ProxyURL, nil, proxy.Direct)
			if err != nil {
				return err
			}
			s.con, err = d.Dial(conMode, conString)
		} else {
			d := net.Dialer{Timeout: 2 * time.Second}
			s.con, err = d.Dial(conMode, conString)
		}

		if err != nil {
			if i != len(listOfNodes)-1 {
				logging.Warn(err.Error())
				continue
			} else if i == len(listOfNodes)-1 {
				logging.Error(err)
				// all nodes have been exhausted, we move on to the next one, if any.
				return fmt.Errorf(" Tried to connect to all available node Addresses. Failed")
			}
		}
		break
	}

	if s.con == nil {
		return fmt.Errorf("Failed to connect to a coin daemon")
	}

	return nil
}

// Handshake ...
func (s *SPVCon) Handshake(listOfNodes []string) error {
	// assign version bits for local node
	s.localVersion = VERSION
	myMsgVer, err := wire.NewMsgVersionFromConn(s.con, 0, 0)
	if err != nil {
		return err
	}
	err = myMsgVer.AddUserAgent("lit", "v0.1")
	if err != nil {
		return err
	}
	// must set this to enable SPV stuff
	myMsgVer.AddService(wire.SFNodeBloom)
	// set this to enable segWit
	myMsgVer.AddService(wire.SFNodeWitness)
	// this actually sends
	n, err := wire.WriteMessageWithEncodingN(
		s.con, myMsgVer, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		return err
	}
	s.WBytes += uint64(n)
	logging.Infof("wrote %d byte version message to %s\n",
		n, s.con.RemoteAddr().String())
	n, m, b, err := wire.ReadMessageWithEncodingN(
		s.con, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		logging.Error(err)
		return err
	}
	s.RBytes += uint64(n)
	logging.Infof("got %d byte response %x\n command: %s\n", n, b, m.Command())

	mv, ok := m.(*wire.MsgVersion)
	if ok {
		logging.Infof("connected to %s", mv.UserAgent)
	} else {
		return fmt.Errorf("Message wrong type and/or nil pointer received, pointer: %p", mv)
	}

	if mv.ProtocolVersion < 70013 {
		//70014 -> core v0.13.1, so we should be fine
		return fmt.Errorf("Remote node version: %x too old, disconnecting.", mv.ProtocolVersion)
	}

	if !((strings.Contains(s.Param.Name, "lite") && strings.Contains(mv.UserAgent, "LitecoinCore")) || strings.Contains(mv.UserAgent, "Satoshi") || strings.Contains(mv.UserAgent, "btcd")) && (len(listOfNodes) != 0) {
		// TODO: improve this filtering criterion
		return fmt.Errorf("Couldn't connect to this node. Returning!")
	}

	logging.Infof("remote reports version %x (dec %d)\n",
		mv.ProtocolVersion, mv.ProtocolVersion)

	// set remote height
	s.remoteHeight = mv.LastBlock
	// set remote version
	s.remoteVersion = uint32(mv.ProtocolVersion)

	mva := wire.NewMsgVerAck()
	n, err = wire.WriteMessageWithEncodingN(
		s.con, mva, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		return err
	}
	s.WBytes += uint64(n)
	return nil
}

// Connect dials out and connects to full nodes. Calls GetListOfNodes to get the
// list of nodes if the user has specified a YupString. Else, moves on to dial
// the node to see if its up and establishes a connection followed by Handshake()
// which sends out wire messages, checks for version string to prevent spam, etc.
func (s *SPVCon) Connect(remoteNode string) error {
	var err error
	var listOfNodes []string
	if lnutil.YupString(remoteNode) { // TODO Make this better.  Perhaps a "connection target"?
		s.randomNodesOK = true
		// if remoteNode is "yes" but no IP specified, use DNS seed
		listOfNodes, err = s.GetListOfNodes()
		if err != nil {
			logging.Error(err)
			return err
			// automatically quit if there are no other hosts to connect to.
		}
	} else { // else connect to user-specified node
		listOfNodes = []string{remoteNode}
	}
	handShakeFailed := false // need to be in this scope to access it here
	connEstablished := false
	for len(listOfNodes) != 0 && !connEstablished {
		err = s.DialNode(listOfNodes)
		if err != nil {
			logging.Error(err)
			logging.Infof("Couldn't dial node %s, Moving on", listOfNodes[0])
			listOfNodes = listOfNodes[1:]
			continue
		}
		err = s.Handshake(listOfNodes)
		if err != nil {
			// spam node or some other problem. Delete node from list and try again
			handShakeFailed = true
			logging.Infof("Handshake with %s failed. Moving on. Error: %s", listOfNodes[0], err.Error())
			if len(listOfNodes) == 1 { // this is the last node, error out
				return fmt.Errorf("Couldn't establish connection with any remote node. Exiting.")
			}
			logging.Error("Couldn't establish connection with node. Proceeding to the next one")
			listOfNodes = listOfNodes[1:]
			connEstablished = false
		} else {
			connEstablished = true
		}
	}

	if !handShakeFailed && !connEstablished {
		// this case happens when user provided node fails to connect
		return fmt.Errorf("Couldn't establish connection with node. Exiting.")
	}
	if handShakeFailed && !connEstablished {
		// this case is when the last node fails and we continue, only to exit the
		// loop and execute below code, which is unnecessary.
		return fmt.Errorf("Couldn't establish connection with any remote node after an instance of handshake. Exiting.")
	}
	go s.incomingMessageHandler()
	go s.outgoingMessageHandler()

	if s.HardMode {
		s.blockQueue = make(chan HashAndHeight, 32) // queue depth 32 for hardmode.
	} else {
		// for SPV, concurrent in-flight merkleblocks makes us miss txs.
		// The BloomUpdateAll setting seems like it should prevent it, but it
		// doesn't; occasionally it misses transactions, seems like with low
		// block index.  Could be a bug somewhere.  1 at a time merkleblock
		// seems OK.
		s.blockQueue = make(chan HashAndHeight, 1) // queue depth 1 for spv
	}
	s.fPositives = make(chan int32, 4000) // a block full, approx
	s.inWaitState = make(chan bool, 1)
	go s.fPositiveHandler()

	// if s.HardMode { // what about for non-hard?  send filter?
	// 	Ignore filters now; switch to filters fed to SPVcon from TS
	// 		filt, err := s.TS.GimmeFilter()
	// 		if err != nil {
	// 			return err
	// 		}
	// 		s.localFilter = filt
	// 		//		s.Refilter(filt)
	// }

	return nil
}

/*
Truncated header files
Like a regular header but the first 80 bytes is mostly empty.
The very first 4 bytes (big endian) says what height the empty 80 bytes
replace.  The next header, starting at offset 80, needs to be valid.
*/
func (s *SPVCon) openHeaderFile(hfn string) error {
	_, err := os.Stat(hfn)
	if err != nil {
		if os.IsNotExist(err) {
			var b bytes.Buffer
			// if StartHeader is defined, start with hardcoded height
			if s.Param.StartHeight != 0 {
				hdr := s.Param.StartHeader
				_, err := b.Write(hdr[:])
				if err != nil {
					return err
				}
			} else {
				err = s.Param.GenesisBlock.Header.Serialize(&b)
				if err != nil {
					return err
				}
			}
			err = ioutil.WriteFile(hfn, b.Bytes(), 0600)
			if err != nil {
				return err
			}
			logging.Infof("made genesis header %x\n", b.Bytes())
			logging.Infof("made genesis hash %s\n", s.Param.GenesisHash.String())
			logging.Infof("created hardcoded genesis header at %s\n", hfn)
		}
	}

	if s.Param.StartHeight != 0 {
		s.headerStartHeight = s.Param.StartHeight
	}

	s.headerFile, err = os.OpenFile(hfn, os.O_RDWR, 0600)
	if err != nil {
		return err
	}
	logging.Infof("opened header file %s\n", s.headerFile.Name())
	return nil
}
<commit_msg>Changed fmt<commit_after>package uspv

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"strings"
	"time"

	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/logging"
	"github.com/mit-dci/lit/wire"
	"golang.org/x/net/proxy"
)

// IP4 ...
func IP4(ipAddress string) bool {
	parseIP := net.ParseIP(ipAddress)
	if parseIP.To4() == nil {
		return false
	}
	return true
}

func (s *SPVCon) parseRemoteNode(remoteNode string) (string, string, error) {
	colonCount := strings.Count(remoteNode, ":")
	var conMode string
	if colonCount <= 1 {
		if colonCount == 0 {
			remoteNode = remoteNode + ":" + s.Param.DefaultPort
		}
		return remoteNode, "tcp4", nil
	} else if colonCount >= 5 {
		// ipv6 without remote port
		// assume users don't give ports with ipv6 nodes
		if !strings.Contains(remoteNode, "[") && !strings.Contains(remoteNode, "]") {
			remoteNode = "[" + remoteNode + "]" + ":" + s.Param.DefaultPort
		}
		conMode = "tcp6"
		return remoteNode, conMode, nil
	} else {
		return "", "", fmt.Errorf("Invalid ip")
	}
}

// GetListOfNodes contacts all DNSSeeds for the coin specified and then contacts
// each one of them in order to receive a list of ips and then returns a combined
// list
func (s *SPVCon) GetListOfNodes() ([]string, error) {
	var listOfNodes []string // slice of IP addrs returned from the DNS seed
	logging.Infof("Attempting to retrieve peers to connect to based on DNS Seed\n")

	for _, seed := range s.Param.DNSSeeds {
		temp, err := net.LookupHost(seed)
		// need this temp in order to capture the error from net.LookupHost
		// also need this to report the number of IPs we get from a seed
		if err != nil {
			logging.Infof("Have difficulty trying to connect to %s. Going to the next seed", seed)
			continue
		}
		listOfNodes = append(listOfNodes, temp...)
		logging.Infof("Got %d IPs from DNS seed %s\n", len(temp), seed)
	}
	if len(listOfNodes) == 0 {
		return nil, fmt.Errorf("No peers found connected to DNS Seeds. Please provide a host to connect to.")
	}
	logging.Info(listOfNodes)
	return listOfNodes, nil
}

// DialNode receives a list of node ips and then tries to connect to them one by one.
func (s *SPVCon) DialNode(listOfNodes []string) error {

	// now have some IPs, go through and try to connect to one.
	var err error
	for i, ip := range listOfNodes {
		// try to connect to all nodes in this range
		var conString, conMode string
		// need to check whether conString is ipv4 or ipv6
		conString, conMode, err = s.parseRemoteNode(ip)
		if err != nil {
			logging.Infof("parse error for node (skipped): %s", err)
			continue
		}
		logging.Infof("Attempting connection to node at %s\n",
			conString)

		if s.ProxyURL != "" {
			logging.Infof("Attempting to connect via proxy %s", s.ProxyURL)
			d, err := proxy.SOCKS5("tcp", s.ProxyURL, nil, proxy.Direct)
			if err != nil {
				return err
			}
			s.con, err = d.Dial(conMode, conString)
		} else {
			d := net.Dialer{Timeout: 2 * time.Second}
			s.con, err = d.Dial(conMode, conString)
		}

		if err != nil {
			if i != len(listOfNodes)-1 {
				logging.Warn(err.Error())
				continue
			} else if i == len(listOfNodes)-1 {
				logging.Error(err)
				// all nodes have been exhausted, we move on to the next one, if any.
				return fmt.Errorf(" Tried to connect to all available node Addresses. Failed")
			}
		}
		break
	}

	if s.con == nil {
		return fmt.Errorf("Failed to connect to a coin daemon")
	}

	return nil
}

// Handshake ...
func (s *SPVCon) Handshake(listOfNodes []string) error {
	// assign version bits for local node
	s.localVersion = VERSION
	myMsgVer, err := wire.NewMsgVersionFromConn(s.con, 0, 0)
	if err != nil {
		return err
	}
	err = myMsgVer.AddUserAgent("lit", "v0.1")
	if err != nil {
		return err
	}
	// must set this to enable SPV stuff
	myMsgVer.AddService(wire.SFNodeBloom)
	// set this to enable segWit
	myMsgVer.AddService(wire.SFNodeWitness)
	// this actually sends
	n, err := wire.WriteMessageWithEncodingN(
		s.con, myMsgVer, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		return err
	}
	s.WBytes += uint64(n)
	logging.Infof("wrote %d byte version message to %s\n",
		n, s.con.RemoteAddr().String())
	n, m, b, err := wire.ReadMessageWithEncodingN(
		s.con, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		logging.Error(err)
		return err
	}
	s.RBytes += uint64(n)
	logging.Infof("got %d byte response %x\n command: %s\n", n, b, m.Command())

	mv, ok := m.(*wire.MsgVersion)
	if ok {
		logging.Infof("connected to %s", mv.UserAgent)
	} else {
		return fmt.Errorf("Message wrong type and/or nil pointer received, mv: %v", mv)
	}

	if mv.ProtocolVersion < 70013 {
		//70014 -> core v0.13.1, so we should be fine
		return fmt.Errorf("Remote node version: %x too old, disconnecting.", mv.ProtocolVersion)
	}

	if !((strings.Contains(s.Param.Name, "lite") && strings.Contains(mv.UserAgent, "LitecoinCore")) || strings.Contains(mv.UserAgent, "Satoshi") || strings.Contains(mv.UserAgent, "btcd")) && (len(listOfNodes) != 0) {
		// TODO: improve this filtering criterion
		return fmt.Errorf("Couldn't connect to this node. Returning!")
	}

	logging.Infof("remote reports version %x (dec %d)\n",
		mv.ProtocolVersion, mv.ProtocolVersion)

	// set remote height
	s.remoteHeight = mv.LastBlock
	// set remote version
	s.remoteVersion = uint32(mv.ProtocolVersion)

	mva := wire.NewMsgVerAck()
	n, err = wire.WriteMessageWithEncodingN(
		s.con, mva, s.localVersion,
		wire.BitcoinNet(s.Param.NetMagicBytes), wire.LatestEncoding)
	if err != nil {
		return err
	}
	s.WBytes += uint64(n)
	return nil
}

// Connect dials out and connects to full nodes. Calls GetListOfNodes to get the
// list of nodes if the user has specified a YupString. Else, moves on to dial
// the node to see if its up and establishes a connection followed by Handshake()
// which sends out wire messages, checks for version string to prevent spam, etc.
func (s *SPVCon) Connect(remoteNode string) error {
	var err error
	var listOfNodes []string
	if lnutil.YupString(remoteNode) { // TODO Make this better.  Perhaps a "connection target"?
		s.randomNodesOK = true
		// if remoteNode is "yes" but no IP specified, use DNS seed
		listOfNodes, err = s.GetListOfNodes()
		if err != nil {
			logging.Error(err)
			return err
			// automatically quit if there are no other hosts to connect to.
		}
	} else { // else connect to user-specified node
		listOfNodes = []string{remoteNode}
	}
	handShakeFailed := false // need to be in this scope to access it here
	connEstablished := false
	for len(listOfNodes) != 0 && !connEstablished {
		err = s.DialNode(listOfNodes)
		if err != nil {
			logging.Error(err)
			logging.Infof("Couldn't dial node %s, Moving on", listOfNodes[0])
			listOfNodes = listOfNodes[1:]
			continue
		}
		err = s.Handshake(listOfNodes)
		if err != nil {
			// spam node or some other problem. Delete node from list and try again
			handShakeFailed = true
			logging.Infof("Handshake with %s failed. Moving on. Error: %s", listOfNodes[0], err.Error())
			if len(listOfNodes) == 1 { // this is the last node, error out
				return fmt.Errorf("Couldn't establish connection with any remote node. Exiting.")
			}
			logging.Error("Couldn't establish connection with node. Proceeding to the next one")
			listOfNodes = listOfNodes[1:]
			connEstablished = false
		} else {
			connEstablished = true
		}
	}

	if !handShakeFailed && !connEstablished {
		// this case happens when user provided node fails to connect
		return fmt.Errorf("Couldn't establish connection with node. Exiting.")
	}
	if handShakeFailed && !connEstablished {
		// this case is when the last node fails and we continue, only to exit the
		// loop and execute below code, which is unnecessary.
		return fmt.Errorf("Couldn't establish connection with any remote node after an instance of handshake. Exiting.")
	}
	go s.incomingMessageHandler()
	go s.outgoingMessageHandler()

	if s.HardMode {
		s.blockQueue = make(chan HashAndHeight, 32) // queue depth 32 for hardmode.
	} else {
		// for SPV, concurrent in-flight merkleblocks makes us miss txs.
		// The BloomUpdateAll setting seems like it should prevent it, but it
		// doesn't; occasionally it misses transactions, seems like with low
		// block index.  Could be a bug somewhere.  1 at a time merkleblock
		// seems OK.
		s.blockQueue = make(chan HashAndHeight, 1) // queue depth 1 for spv
	}
	s.fPositives = make(chan int32, 4000) // a block full, approx
	s.inWaitState = make(chan bool, 1)
	go s.fPositiveHandler()

	// if s.HardMode { // what about for non-hard?  send filter?
	// 	Ignore filters now; switch to filters fed to SPVcon from TS
	// 		filt, err := s.TS.GimmeFilter()
	// 		if err != nil {
	// 			return err
	// 		}
	// 		s.localFilter = filt
	// 		//		s.Refilter(filt)
	// }

	return nil
}

/*
Truncated header files
Like a regular header but the first 80 bytes is mostly empty.
The very first 4 bytes (big endian) says what height the empty 80 bytes
replace.  The next header, starting at offset 80, needs to be valid.
*/
func (s *SPVCon) openHeaderFile(hfn string) error {
	_, err := os.Stat(hfn)
	if err != nil {
		if os.IsNotExist(err) {
			var b bytes.Buffer
			// if StartHeader is defined, start with hardcoded height
			if s.Param.StartHeight != 0 {
				hdr := s.Param.StartHeader
				_, err := b.Write(hdr[:])
				if err != nil {
					return err
				}
			} else {
				err = s.Param.GenesisBlock.Header.Serialize(&b)
				if err != nil {
					return err
				}
			}
			err = ioutil.WriteFile(hfn, b.Bytes(), 0600)
			if err != nil {
				return err
			}
			logging.Infof("made genesis header %x\n", b.Bytes())
			logging.Infof("made genesis hash %s\n", s.Param.GenesisHash.String())
			logging.Infof("created hardcoded genesis header at %s\n", hfn)
		}
	}

	if s.Param.StartHeight != 0 {
		s.headerStartHeight = s.Param.StartHeight
	}

	s.headerFile, err = os.OpenFile(hfn, os.O_RDWR, 0600)
	if err != nil {
		return err
	}
	logging.Infof("opened header file %s\n", s.headerFile.Name())
	return nil
}
<|endoftext|>


<commit_before>package openstack

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

	"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
)

type stepCreateImage struct {
	UseBlockStorageVolume bool
}

func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	server := state.Get("server").(*servers.Server)
	ui := state.Get("ui").(packer.Ui)

	// We need the v2 compute client
	computeClient, err := config.computeV2Client()
	if err != nil {
		err = fmt.Errorf("Error initializing compute client: %s", err)
		state.Put("error", err)
		return multistep.ActionHalt
	}

	// We need the v2 image client
	imageClient, err := config.imageV2Client()
	if err != nil {
		err = fmt.Errorf("Error initializing image service client: %s", err)
		state.Put("error", err)
		return multistep.ActionHalt
	}

	// Create the image.
	// Image source depends on the type of the Compute instance. It can be
	// Block Storage service volume or regular Compute service local volume.
	ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
	var imageId string
	var blockStorageClient *gophercloud.ServiceClient
	if s.UseBlockStorageVolume {
		// We need the v3 block storage client.
		blockStorageClient, err = config.blockStorageV3Client()
		if err != nil {
			err = fmt.Errorf("Error initializing block storage client: %s", err)
			state.Put("error", err)
			return multistep.ActionHalt
		}
		volume := state.Get("volume_id").(string)
		image, err := volumeactions.UploadImage(blockStorageClient, volume, volumeactions.UploadImageOpts{
			DiskFormat: config.ImageDiskFormat,
			ImageName:  config.ImageName,
		}).Extract()
		if err != nil {
			err := fmt.Errorf("Error creating image: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
		imageId = image.ImageID
	} else {
		imageId, err = servers.CreateImage(computeClient, server.ID, servers.CreateImageOpts{
			Name:     config.ImageName,
			Metadata: config.ImageMetadata,
		}).ExtractImageID()
		if err != nil {
			err := fmt.Errorf("Error creating image: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
	}

	// Set the Image ID in the state
	ui.Message(fmt.Sprintf("Image: %s", imageId))
	state.Put("image", imageId)

	// Wait for the image to become ready
	ui.Say(fmt.Sprintf("Waiting for image %s (image id: %s) to become ready...", config.ImageName, imageId))
	if err := WaitForImage(ctx, imageClient, imageId); err != nil {
		err := fmt.Errorf("Error waiting for image: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	volume := state.Get("volume_id").(string)
	if len(config.ImageMetadata) > 0 && s.UseBlockStorageVolume {
		err = volumeactions.SetImageMetadata(blockStorageClient, volume, volumeactions.ImageMetadataOpts{
			Metadata: config.ImageMetadata,
		}).ExtractErr()
		if err != nil {
			err := fmt.Errorf("Error setting image metadata: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
	}

	return multistep.ActionContinue
}

func (s *stepCreateImage) Cleanup(multistep.StateBag) {
	// No cleanup...
}

// WaitForImage waits for the given Image ID to become ready.
func WaitForImage(ctx context.Context, client *gophercloud.ServiceClient, imageId string) error {
	maxNumErrors := 10
	numErrors := 0

	for {
		if err := ctx.Err(); err != nil {
			return err
		}
		image, err := images.Get(client, imageId).Extract()
		if err != nil {
			errCode, ok := err.(*gophercloud.ErrUnexpectedResponseCode)
			if ok && (errCode.Actual == 500 || errCode.Actual == 404) {
				numErrors++
				if numErrors >= maxNumErrors {
					log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err)
					return err
				}
				log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err)
				time.Sleep(2 * time.Second)
				continue
			}

			return err
		}

		if image.Status == "active" {
			return nil
		}

		log.Printf("Waiting for image creation status: %s", image.Status)
		time.Sleep(2 * time.Second)
	}
}
<commit_msg>builder/openstack: Fix interface conversion panic when attempting to find a volume when not using volumes<commit_after>package openstack

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

	"github.com/gophercloud/gophercloud/openstack/blockstorage/extensions/volumeactions"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
)

type stepCreateImage struct {
	UseBlockStorageVolume bool
}

func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	server := state.Get("server").(*servers.Server)
	ui := state.Get("ui").(packer.Ui)

	// We need the v2 compute client
	computeClient, err := config.computeV2Client()
	if err != nil {
		err = fmt.Errorf("Error initializing compute client: %s", err)
		state.Put("error", err)
		return multistep.ActionHalt
	}

	// We need the v2 image client
	imageClient, err := config.imageV2Client()
	if err != nil {
		err = fmt.Errorf("Error initializing image service client: %s", err)
		state.Put("error", err)
		return multistep.ActionHalt
	}

	// Create the image.
	// Image source depends on the type of the Compute instance. It can be
	// Block Storage service volume or regular Compute service local volume.
	ui.Say(fmt.Sprintf("Creating the image: %s", config.ImageName))
	var imageId string
	var blockStorageClient *gophercloud.ServiceClient
	if s.UseBlockStorageVolume {
		// We need the v3 block storage client.
		blockStorageClient, err = config.blockStorageV3Client()
		if err != nil {
			err = fmt.Errorf("Error initializing block storage client: %s", err)
			state.Put("error", err)
			return multistep.ActionHalt
		}
		volume := state.Get("volume_id").(string)
		image, err := volumeactions.UploadImage(blockStorageClient, volume, volumeactions.UploadImageOpts{
			DiskFormat: config.ImageDiskFormat,
			ImageName:  config.ImageName,
		}).Extract()
		if err != nil {
			err := fmt.Errorf("Error creating image: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
		imageId = image.ImageID
	} else {
		imageId, err = servers.CreateImage(computeClient, server.ID, servers.CreateImageOpts{
			Name:     config.ImageName,
			Metadata: config.ImageMetadata,
		}).ExtractImageID()
		if err != nil {
			err := fmt.Errorf("Error creating image: %s", err)
			state.Put("error", err)
			ui.Error(err.Error())
			return multistep.ActionHalt
		}
	}

	// Set the Image ID in the state
	ui.Message(fmt.Sprintf("Image: %s", imageId))
	state.Put("image", imageId)

	// Wait for the image to become ready
	ui.Say(fmt.Sprintf("Waiting for image %s (image id: %s) to become ready...", config.ImageName, imageId))
	if err := WaitForImage(ctx, imageClient, imageId); err != nil {
		err := fmt.Errorf("Error waiting for image: %s", err)
		state.Put("error", err)
		ui.Error(err.Error())
		return multistep.ActionHalt
	}

	if s.UseBlockStorageVolume {
		volume := state.Get("volume_id").(string)
		if len(config.ImageMetadata) > 0 {
			err = volumeactions.SetImageMetadata(blockStorageClient, volume, volumeactions.ImageMetadataOpts{
				Metadata: config.ImageMetadata,
			}).ExtractErr()
			if err != nil {
				err := fmt.Errorf("Error setting image metadata: %s", err)
				state.Put("error", err)
				ui.Error(err.Error())
				return multistep.ActionHalt
			}
		}
	}

	return multistep.ActionContinue
}

func (s *stepCreateImage) Cleanup(multistep.StateBag) {
	// No cleanup...
}

// WaitForImage waits for the given Image ID to become ready.
func WaitForImage(ctx context.Context, client *gophercloud.ServiceClient, imageId string) error {
	maxNumErrors := 10
	numErrors := 0

	for {
		if err := ctx.Err(); err != nil {
			return err
		}
		image, err := images.Get(client, imageId).Extract()
		if err != nil {
			errCode, ok := err.(*gophercloud.ErrUnexpectedResponseCode)
			if ok && (errCode.Actual == 500 || errCode.Actual == 404) {
				numErrors++
				if numErrors >= maxNumErrors {
					log.Printf("[ERROR] Maximum number of errors (%d) reached; failing with: %s", numErrors, err)
					return err
				}
				log.Printf("[ERROR] %d error received, will ignore and retry: %s", errCode.Actual, err)
				time.Sleep(2 * time.Second)
				continue
			}

			return err
		}

		if image.Status == "active" {
			return nil
		}

		log.Printf("Waiting for image creation status: %s", image.Status)
		time.Sleep(2 * time.Second)
	}
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/leptonyu/goeast/db"
	"github.com/leptonyu/goeast/wechat"
	"html/template"
	"net/http"
	"os"
	"strconv"
	"time"
)

func Template(key string, m interface{}) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		t := template.New(key)
		t, _ = t.ParseFiles("templates/" + key)
		t.Execute(w, m)
	}
}

func StartWeb(port int, dbname string, api string, init bool, config *db.DBConfig) {
	m := martini.Classic()
	m.NotFound(Template("404.tpl", m))
	m.Use(martini.Static("static", martini.StaticOptions{Prefix: "static"}))
	m.Get("/", Template("index.tpl", m))
	wc, err := config.CreateWeChat(dbname, api)
	if err != nil {
		panic(err)
	}
	if port == 8080 {
		go func() {
			for {
				a, err := wc.UpdateAccessToken()
				if err != nil {
					panic(err)
				}
				time.Sleep((-1 * time.Duration(time.Since(a.ExpireTime).Seconds())))
			}
		}()
		f := func(wait time.Duration, keys ...string) {
			if len(keys) > 0 {
				for {
					time.Sleep(wait)
					for _, v := range keys {
						config.Update(v)
					}
				}
			}
		}
		go f(30*time.Minute, db.Blog, db.Events)
		go f(24*time.Hour,
			db.Home,
			db.Campus,
			db.Contact,
			db.Galleries,
			db.One2one,
			db.Online,
			db.Onsite,
			db.Teachers,
			db.Testimonials)
	}
	wc.HandleFunc(wechat.MsgTypeText, func(w wechat.ResponseWriter, r *wechat.Request) error {
		txt := r.Content
		//sig := strings.ToLower(txt)
		w.ReplyText(txt)
		return nil
	})
	//Create api route
	ff := wc.CreateHandlerFunc()
	m.Get("/"+api, ff)
	m.Post("/"+api, ff)
	err = http.ListenAndServe(":"+strconv.Itoa(port), m)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("stop!")
	os.Exit(0)
}
<commit_msg>wechat<commit_after>package util

import (
	"fmt"
	"github.com/go-martini/martini"
	"github.com/leptonyu/goeast/db"
	"github.com/leptonyu/goeast/wechat"
	"html/template"
	"net/http"
	"os"
	"strconv"
	"time"
)

func Template(key string, m interface{}) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		t := template.New(key)
		t, _ = t.ParseFiles("templates/" + key)
		t.Execute(w, m)
	}
}

func StartWeb(port int, dbname string, api string, config *db.DBConfig) {
	m := martini.Classic()
	m.NotFound(Template("404.tpl", m))
	m.Use(martini.Static("static", martini.StaticOptions{Prefix: "static"}))
	m.Get("/", Template("index.tpl", m))
	wc, err := config.CreateWeChat(dbname, api)
	if err != nil {
		panic(err)
	}
	if port == 8080 {
		go func() {
			for {
				a, err := wc.UpdateAccessToken()
				if err != nil {
					panic(err)
				}
				time.Sleep((-1 * time.Duration(time.Since(a.ExpireTime).Seconds())))
			}
		}()
		f := func(wait time.Duration, keys ...string) {
			if len(keys) > 0 {
				for {
					time.Sleep(wait)
					for _, v := range keys {
						config.Update(v)
					}
				}
			}
		}
		go f(30*time.Minute, db.Blog, db.Events)
		go f(24*time.Hour,
			db.Home,
			db.Campus,
			db.Contact,
			db.Galleries,
			db.One2one,
			db.Online,
			db.Onsite,
			db.Teachers,
			db.Testimonials)
	}
	wc.HandleFunc(wechat.MsgTypeText, func(w wechat.ResponseWriter, r *wechat.Request) error {
		txt := r.Content
		//sig := strings.ToLower(txt)
		w.ReplyText(txt)
		return nil
	})
	//Create api route
	ff := wc.CreateHandlerFunc()
	m.Get("/"+api, ff)
	m.Post("/"+api, ff)
	err = http.ListenAndServe(":"+strconv.Itoa(port), m)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println("stop!")
	os.Exit(0)
}
<|endoftext|>


<commit_before>// Package util contains utility functions
package util

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"strconv"
	"time"
)

func GenerateCredentials(username, password, rawPem []byte) (*string, error) {
	unixStr := strconv.FormatInt(time.Now().Unix(), 10)

	userBase64 := base64.StdEncoding.EncodeToString(username)
	passBase64 := base64.StdEncoding.EncodeToString(password)
	timeBase64 := base64.StdEncoding.EncodeToString([]byte(unixStr))

	formated := fmt.Sprintf("%s:%s:%s", userBase64, passBase64, timeBase64)

	block, _ := pem.Decode(rawPem)
	if block == nil {
		return nil, errors.New("Could not Decode PEM")
	}

	pubKeyVal, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	rsaPubKey, ok := pubKeyVal.(*rsa.PublicKey)
	if !ok {
		return nil, errors.New("Could not make DER to an RSA PublicKey")
	}

	encr, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPubKey, []byte(formated))
	if err != nil {
		return nil, err
	}

	cred := base64.StdEncoding.EncodeToString(encr)
	return &cred, nil
}
<commit_msg>Fix return value<commit_after>// Package util contains utility functions
package util

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"fmt"
	"strconv"
	"time"
)

func GenerateCredentials(username, password, rawPem []byte) (cred string, err error) {
	cred = ""
	unixStr := strconv.FormatInt(time.Now().Unix(), 10)

	userBase64 := base64.StdEncoding.EncodeToString(username)
	passBase64 := base64.StdEncoding.EncodeToString(password)
	timeBase64 := base64.StdEncoding.EncodeToString([]byte(unixStr))

	formated := fmt.Sprintf("%s:%s:%s", userBase64, passBase64, timeBase64)

	block, _ := pem.Decode(rawPem)
	if block == nil {
		err = errors.New("Could not Decode PEM")
		return
	}

	pubKeyVal, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return
	}

	rsaPubKey, ok := pubKeyVal.(*rsa.PublicKey)
	if !ok {
		err = errors.New("Could not make DER to an RSA PublicKey")
		return
	}

	encr, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPubKey, []byte(formated))
	if err != nil {
		return
	}

	cred = base64.StdEncoding.EncodeToString(encr)
	return
}
<|endoftext|>


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

/*
Package util contains utilities which are shared between packages.
*/
package util

import (
	"errors"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

// SdkConfigPath tries to return the directory where the gcloud config is
// located.
func SdkConfigPath() (string, error) {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("APPDATA"), "gcloud"), nil
	}
	homeDir := unixHomeDir()
	if homeDir == "" {
		return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
	}
	return filepath.Join(homeDir, ".config", "gcloud"), nil
}

func unixHomeDir() string {
	usr, err := user.Current()
	if err == nil {
		return usr.HomeDir
	}
	return os.Getenv("HOME")
}

// DockerClientVersionStrings attempts to discover the version of the Docker client,
// returning the major, minor, and patch versions, or an error if unsuccessful.
func DockerClientVersionStrings() (string, string, string, error) {
	cmd := exec.Command("docker", "version", "--format", "'{{.Client.Version}}'")
	out, err := cmd.Output()
	if err != nil {
		return "", "", "", err
	}

	vstring := string(out)

	// Remove any leading/trailing whitespace
	vstring = strings.TrimSpace(vstring)

	// Remove any leading/trailing '
	vstring = strings.Trim(vstring, "'")

	ver := strings.Split(vstring, ".")

	if len(ver) != 3 {
		return "", "", "", errors.New("version string not of the form '<major>.<minor>.<patch>': " + vstring)
	}
	return ver[0], ver[1], ver[2], nil
}

// DockerClientVersion attempts to discover the major and minor version
// numbers of the Docker client, returning <major number>, <minor number>,
// <patch number>, <patch suffix>, nil if successful, 0, 0, err otherwise.
// e.g.
// '1.12.0' => 1, 12, 0, "", nil
// '1.13.0-dev' => 1, 13, 0, "dev", nil
// '1.what.0' => 0, 0, 0, "", nil
func DockerClientVersion() (int, int, int, string, error) {
	majorstr, minorstr, patchstr, err := DockerClientVersionStrings()
	if err != nil {
		return 0, 0, 0, "", err
	}

	major, err := strconv.Atoi(majorstr)
	if err != nil {
		return 0, 0, 0, "", err
	}
	minor, err := strconv.Atoi(minorstr)
	if err != nil {
		return 0, 0, 0, "", err
	}

	patchSplit := strings.Split(patchstr, "-")
	patch, err := strconv.Atoi(patchSplit[0])
	if err != nil {
		return 0, 0, 0, "", err
	}

	return major, minor, patch, patchSplit[1], nil
}
<commit_msg>update version string trim method to include whitespace<commit_after>// Copyright 2016 Google, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/*
Package util contains utilities which are shared between packages.
*/
package util

import (
	"errors"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"unicode"
)

// SdkConfigPath tries to return the directory where the gcloud config is
// located.
func SdkConfigPath() (string, error) {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("APPDATA"), "gcloud"), nil
	}
	homeDir := unixHomeDir()
	if homeDir == "" {
		return "", errors.New("unable to get current user home directory: os/user lookup failed; $HOME is empty")
	}
	return filepath.Join(homeDir, ".config", "gcloud"), nil
}

func unixHomeDir() string {
	usr, err := user.Current()
	if err == nil {
		return usr.HomeDir
	}
	return os.Getenv("HOME")
}

// DockerClientVersionStrings attempts to discover the version of the Docker client,
// returning the major, minor, and patch versions, or an error if unsuccessful.
func DockerClientVersionStrings() (string, string, string, error) {
	cmd := exec.Command("docker", "version", "--format", "'{{.Client.Version}}'")
	out, err := cmd.Output()
	if err != nil {
		return "", "", "", err
	}

	vstring := string(out)

	// Remove any leading/trailing whitespace or '
	vstring = strings.TrimFunc(vstring, func(r rune) bool {
		return unicode.IsSpace(r) || r == '\''
	})

	ver := strings.Split(vstring, ".")

	if len(ver) != 3 {
		return "", "", "", errors.New("version string not of the form '<major>.<minor>.<patch>': " + vstring)
	}
	return ver[0], ver[1], ver[2], nil
}

// DockerClientVersion attempts to discover the major and minor version
// numbers of the Docker client, returning <major number>, <minor number>,
// <patch number>, <patch suffix>, nil if successful, 0, 0, err otherwise.
// e.g.
// '1.12.0' => 1, 12, 0, "", nil
// '1.13.0-dev' => 1, 13, 0, "dev", nil
// '1.what.0' => 0, 0, 0, "", nil
func DockerClientVersion() (int, int, int, string, error) {
	majorstr, minorstr, patchstr, err := DockerClientVersionStrings()
	if err != nil {
		return 0, 0, 0, "", err
	}

	major, err := strconv.Atoi(majorstr)
	if err != nil {
		return 0, 0, 0, "", err
	}
	minor, err := strconv.Atoi(minorstr)
	if err != nil {
		return 0, 0, 0, "", err
	}

	patchSplit := strings.Split(patchstr, "-")
	patch, err := strconv.Atoi(patchSplit[0])
	if err != nil {
		return 0, 0, 0, "", err
	}

	return major, minor, patch, patchSplit[1], nil
}
<|endoftext|>


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

package console

import (
	"testing"
)

func TestUnderscoreToCamelcase(t *testing.T) {
	path := "browse_by_set"
	method := UnderscoreToCamelcase(path)
	if method != "BrowseBySet" {
		t.Error("pathToMethod failure")
	}
}

func TestCamelcaseToUnderscore(t *testing.T) {
	method := "BrowseBySet"
	path := CamelcaseToUnderscore(method)
	if path != "browse_by_set" {
		t.Errorf("methodToPath failure: %#v", path)
	}
}
<commit_msg>Improve test.<commit_after>// Copyright 2014 The zhgo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package console

import (
	"testing"
)

func TestUnderscoreToCamelcase(t *testing.T) {
	path := "browse_by_set"
	method := UnderscoreToCamelcase(path)
	if method != "BrowseBySet" {
		t.Error("pathToMethod failure")
	}
}

func TestCamelcaseToUnderscore(t *testing.T) {
	method := "BrowseBySet"
	path := CamelcaseToUnderscore(method)
	if path != "browse_by_set" {
		t.Errorf("methodToPath failure: %#v", path)
	}
}

func TestParseText(t *testing.T) {
	cmd := "ls.exe -l"
	sli := ParseText(cmd)
	if len(sli) != 2 || sli[0] != "ls.exe" || sli[1] != "-l" {
		t.Errorf("ParseText failure: %#v", cmd)
	}

	cmd = "cd {homePath}/gocode/src"
	sli = ParseText(cmd)
	if len(sli) != 2 || sli[0] != "cd" || sli[1] != "{homePath}/gocode/src" {
		t.Errorf("ParseText failure: %#v", cmd)
	}

	cmd = "run cd {basePath}/usr/local/apache24"
	sli = ParseText(cmd)
	if len(sli) != 3 || sli[0] != "run" || sli[1] != "cd" || sli[2] != "{basePath}/usr/local/apache24" {
		t.Errorf("ParseText failure: %#v", cmd)
	}

	cmd = "srv httpd.exe"
	sli = ParseText(cmd)
	if len(sli) != 2 || sli[0] != "srv" || sli[1] != "httpd.exe" {
		t.Errorf("ParseText failure: %#v", cmd)
	}

	cmd = "async 'D:/Program Files/Sublime Text 3/sublime_text.exe'"
	sli = ParseText(cmd)
	if len(sli) != 2 {
		t.Errorf("ParseText failure: %#v", cmd)
	}
}
<|endoftext|>


<commit_before>package capn_test

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"

	"github.com/glycerine/go-capnproto"
)

// some generally useful capnp/segment utilities

// shell out to display capnp bytes as human-readable text. Data flow:
//    in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnpDecodeSegment(seg *capn.Segment, capnpExePath string, capnpSchemaFilePath string, typeName string) string {

	// set defaults
	if capnpExePath == "" {
		capnpExePath = CheckAndGetCapnpPath()
	}

	if capnpSchemaFilePath == "" {
		capnpSchemaFilePath = "test.capnp"
	}

	if typeName == "" {
		typeName = "Z"
	}

	cs := []string{"decode", "--short", capnpSchemaFilePath, typeName}
	cmd := exec.Command(capnpExePath, cs...)
	cmdline := capnpExePath + " " + strings.Join(cs, " ")

	buf := new(bytes.Buffer)
	seg.WriteTo(buf)

	cmd.Stdin = buf

	var errout bytes.Buffer
	cmd.Stderr = &errout

	bs, err := cmd.Output()
	if err != nil {
		if err.Error() == "exit status 1" {
			cwd, _ := os.Getwd()
			fmt.Fprintf(os.Stderr, "\nCall to capnp in CapnpDecodeSegment(): '%s' in dir '%s' failed with status 1\n", cmdline, cwd)
			fmt.Printf("stderr: '%s'\n", string(errout.Bytes()))
			fmt.Printf("stdout: '%s'\n", string(bs))
		}
		panic(err)
	}
	return strings.TrimSpace(string(bs))
}

// reduce boilerplate, dump this segment to disk.
func SegToFile(seg *capn.Segment, filePath string) {
	file, err := os.Create(filePath)
	if err != nil {
		panic(err)
	}
	seg.WriteTo(file)
	file.Close()
}

// disk file of a capn segment -> in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnFileToText(serializedCapnpFilePathToDisplay string, capnpSchemaFilePath string, capnpExePath string) (string, error) {

	// a) read file into Segment

	byteslice, err := ioutil.ReadFile(serializedCapnpFilePathToDisplay)
	if err != nil {
		return "", err
	}

	seg, nbytes, err := capn.ReadFromMemoryZeroCopy(byteslice)

	if err == io.EOF {
		return "", err
	}
	if err != nil {
		return "", err
	}
	if nbytes == 0 {
		return "", errors.New(fmt.Sprintf("did not expect 0 bytes back from capn.ReadFromMemoryZeroCopy() on reading file '%s'", serializedCapnpFilePathToDisplay))
	}

	// b) tell CapnpDecodeSegment() to show the human-readable-text form of the message
	// warning: CapnpDecodeSegment() may panic on you. It is a testing utility so that
	//  is desirable. For production, do something else.
	return CapnpDecodeSegment(seg, capnpExePath, capnpSchemaFilePath, "Z"), nil
}

// return path to capnp if 'which' can find it. Feel free to replace this with
//   a more general configuration mechanism.
func CheckAndGetCapnpPath() string {

	whichCmd := exec.Command("which", "capnp")
	wbs, err := whichCmd.Output()
	if err != nil {
		panic("could not locate capnp with /usr/bin/which; put the capnp executable in your path; e.g /usr/local/bin/capnp")
	}

	path := strings.TrimSpace(string(wbs))

	cmd := exec.Command(path, "id")
	bs, err := cmd.Output()
	if err != nil || string(bs[:3]) != `@0x` {
		panic(fmt.Sprintf("%s id did not function: put a working capnp executable in your path. Err: %s", path, err))
	}

	return path
}
<commit_msg>another utility function for displaying []byte that contains capnp serialization<commit_after>package capn_test

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"

	"github.com/glycerine/go-capnproto"
)

// some generally useful capnp/segment utilities

// shell out to display capnp bytes as human-readable text. Data flow:
//    in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnpDecodeSegment(seg *capn.Segment, capnpExePath string, capnpSchemaFilePath string, typeName string) string {

	// set defaults
	if capnpExePath == "" {
		capnpExePath = CheckAndGetCapnpPath()
	}

	if capnpSchemaFilePath == "" {
		capnpSchemaFilePath = "test.capnp"
	}

	if typeName == "" {
		typeName = "Z"
	}

	cs := []string{"decode", "--short", capnpSchemaFilePath, typeName}
	cmd := exec.Command(capnpExePath, cs...)
	cmdline := capnpExePath + " " + strings.Join(cs, " ")

	buf := new(bytes.Buffer)
	seg.WriteTo(buf)

	cmd.Stdin = buf

	var errout bytes.Buffer
	cmd.Stderr = &errout

	bs, err := cmd.Output()
	if err != nil {
		if err.Error() == "exit status 1" {
			cwd, _ := os.Getwd()
			fmt.Fprintf(os.Stderr, "\nCall to capnp in CapnpDecodeSegment(): '%s' in dir '%s' failed with status 1\n", cmdline, cwd)
			fmt.Printf("stderr: '%s'\n", string(errout.Bytes()))
			fmt.Printf("stdout: '%s'\n", string(bs))
		}
		panic(err)
	}
	return strings.TrimSpace(string(bs))
}

// reduce boilerplate, dump this segment to disk.
func SegToFile(seg *capn.Segment, filePath string) {
	file, err := os.Create(filePath)
	if err != nil {
		panic(err)
	}
	seg.WriteTo(file)
	file.Close()
}

// disk file of a capn segment -> in-memory capn segment -> stdin to capnp decode -> stdout human-readble string form
func CapnFileToText(serializedCapnpFilePathToDisplay string, capnpSchemaFilePath string, capnpExePath string) (string, error) {

	// a) read file into Segment

	byteslice, err := ioutil.ReadFile(serializedCapnpFilePathToDisplay)
	if err != nil {
		return "", err
	}

	seg, nbytes, err := capn.ReadFromMemoryZeroCopy(byteslice)

	if err == io.EOF {
		return "", err
	}
	if err != nil {
		return "", err
	}
	if nbytes == 0 {
		return "", errors.New(fmt.Sprintf("did not expect 0 bytes back from capn.ReadFromMemoryZeroCopy() on reading file '%s'", serializedCapnpFilePathToDisplay))
	}

	// b) tell CapnpDecodeSegment() to show the human-readable-text form of the message
	// warning: CapnpDecodeSegment() may panic on you. It is a testing utility so that
	//  is desirable. For production, do something else.
	return CapnpDecodeSegment(seg, capnpExePath, capnpSchemaFilePath, "Z"), nil
}

// return path to capnp if 'which' can find it. Feel free to replace this with
//   a more general configuration mechanism.
func CheckAndGetCapnpPath() string {

	whichCmd := exec.Command("which", "capnp")
	wbs, err := whichCmd.Output()
	if err != nil {
		panic("could not locate capnp with /usr/bin/which; put the capnp executable in your path; e.g /usr/local/bin/capnp")
	}

	path := strings.TrimSpace(string(wbs))

	cmd := exec.Command(path, "id")
	bs, err := cmd.Output()
	if err != nil || string(bs[:3]) != `@0x` {
		panic(fmt.Sprintf("%s id did not function: put a working capnp executable in your path. Err: %s", path, err))
	}

	return path
}

// take an already (packed or unpacked, depending on the packed flag) buffer of a serialized segment, and display it
func CapnpDecodeBuf(buf []byte, capnpExePath string, capnpSchemaFilePath string, typeName string, packed bool) string {

	// set defaults
	if capnpExePath == "" {
		capnpExePath = CheckAndGetCapnpPath()
	}

	if capnpSchemaFilePath == "" {
		capnpSchemaFilePath = "test.capnp"
	}

	if typeName == "" {
		typeName = "Z"
	}

	cs := []string{"decode", "--short", capnpSchemaFilePath, typeName}
	if packed {
		cs = []string{"decode", "--short", "--packed", capnpSchemaFilePath, typeName}
	}
	cmd := exec.Command(capnpExePath, cs...)
	cmdline := capnpExePath + " " + strings.Join(cs, " ")

	cmd.Stdin = bytes.NewReader(buf)

	var errout bytes.Buffer
	cmd.Stderr = &errout

	bs, err := cmd.Output()
	if err != nil {
		if err.Error() == "exit status 1" {
			cwd, _ := os.Getwd()
			fmt.Fprintf(os.Stderr, "\nCall to capnp in CapnpDecodeBuf(): '%s' in dir '%s' failed with status 1\n", cmdline, cwd)
			fmt.Printf("stderr: '%s'\n", string(errout.Bytes()))
			fmt.Printf("stdout: '%s'\n", string(bs))
		}
		panic(err)
	}
	return strings.TrimSpace(string(bs))
}
<|endoftext|>


<commit_before>package main

import (
    "encoding/json"
    "errors"
    "github.com/alexjlockwood/gcm"
    "log"
)

//=====================
//
// Utility functions
//
//=====================

func sendMessageToGCM(token, jsonStr string) (bool, error) {
    if token == "" {
        errText := "Token was empty, exiting"
        log.Println(errText)
        return false, errors.New(errText)
    }

    if jsonStr == "" {
        errText := "Payload was empty, exiting"
        log.Println(errText)
        return false, errors.New(errText)
    }

    // Unpack the JSON payload
    var payload map[string]interface{}
    err := json.Unmarshal([]byte(jsonStr), &payload)
    if err != nil {
        log.Println("Can't unmarshal the json: " + err.Error())
        log.Println("Original: " + jsonStr)
        return false, err
    }

    // All is well, make & send the message
    msg := gcm.NewMessage(payload, token)
    sender := &gcm.Sender{ApiKey: settings.GCMAPIKey}
    go appendAttempts()
    result, err := sender.Send(msg, 2)
    if err != nil {
        log.Println("Failed to send message:")
        log.Println(err.Error())

        go appendFailures()

        return false, err
    }
    if result != nil {
        //log.Printf("Message sent: %s\n", payload["title"])
        if result.CanonicalIDs > 0 {
            go appendCanonicals()
            handleCanonicalsInResult(token, result.Results)
        }
    }

    return true, nil
}

func handleCanonicalsInResult(original string, results []gcm.Result) {
    for _, r := range results {
        canonicalReplacements = append(canonicalReplacements, canonicalReplacement{original, r.RegistrationID})
    }
}

func appendAttempts() {
    runReport.Attempts++
}

func appendFailures() {
    runReport.Failures++
}

func appendCanonicals() {
    runReport.Canonicals++
}
<commit_msg>Record the attempt before ever starting<commit_after>package main

import (
    "encoding/json"
    "errors"
    "github.com/alexjlockwood/gcm"
    "log"
)

//=====================
//
// Utility functions
//
//=====================

func sendMessageToGCM(token, jsonStr string) (bool, error) {
    if token == "" {
        errText := "Token was empty, exiting"
        log.Println(errText)
        return false, errors.New(errText)
    }

    if jsonStr == "" {
        errText := "Payload was empty, exiting"
        log.Println(errText)
        return false, errors.New(errText)
    }

    // Unpack the JSON payload
    var payload map[string]interface{}
    err := json.Unmarshal([]byte(jsonStr), &payload)
    if err != nil {
        log.Println("Can't unmarshal the json: " + err.Error())
        log.Println("Original: " + jsonStr)
        return false, err
    }

    // All is well, make & send the message
    go appendAttempts()

    msg := gcm.NewMessage(payload, token)
    sender := &gcm.Sender{ApiKey: settings.GCMAPIKey}
    result, err := sender.Send(msg, 2)
    if err != nil {
        log.Println("Failed to send message:")
        log.Println(err.Error())

        go appendFailures()
        return false, err
    }
    if result != nil {
        //log.Printf("Message sent: %s\n", payload["title"])
        if result.CanonicalIDs > 0 {
            go appendCanonicals()
            handleCanonicalsInResult(token, result.Results)
        }
    }

    return true, nil
}

func handleCanonicalsInResult(original string, results []gcm.Result) {
    for _, r := range results {
        canonicalReplacements = append(canonicalReplacements, canonicalReplacement{original, r.RegistrationID})
    }
}

func appendAttempts() {
    runReport.Attempts++
}

func appendFailures() {
    runReport.Failures++
}

func appendCanonicals() {
    runReport.Canonicals++
}
<|endoftext|>


<commit_before>package user_printer

import (
	"fmt"

	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/plugin/models"
)

type UserPrinter interface {
	PrintUsers(guid string, username string)
}

type SpaceUsersPluginPrinter struct {
	UserPrinter
	Roles       []string
	UserLister  func(spaceGuid string, role string) ([]models.UserFields, error)
	PluginModel *[]plugin_models.GetSpaceUsers_Model
	users       users
}

type SpaceUsersUiPrinter struct {
	UserPrinter
	Ui               terminal.UI
	UserLister       func(spaceGuid string, role string) ([]models.UserFields, error)
	Roles            []string
	RoleDisplayNames map[string]string
}

type OrgUsersPluginPrinter struct {
	UserPrinter
	Roles       []string
	UserLister  func(orgGuid string, role string) ([]models.UserFields, error)
	PluginModel *[]plugin_models.GetOrgUsers_Model
	users       users
}

type OrgUsersUiPrinter struct {
	UserPrinter
	Roles            []string
	RoleDisplayNames map[string]string
	UserLister       func(orgGuid string, role string) ([]models.UserFields, error)
	Ui               terminal.UI
}

type userWithRoles struct {
	models.UserFields
	Roles []string
}

type users struct {
	db map[string]userWithRoles
}

func NewOrgUsersPluginPrinter(
	pluginModel *[]plugin_models.GetOrgUsers_Model,
	userLister func(orgGuid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *OrgUsersPluginPrinter) {
	return &OrgUsersPluginPrinter{
		PluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		UserLister:  userLister,
		Roles:       roles,
	}
}

func NewSpaceUsersPluginPrinter(
	pluginModel *[]plugin_models.GetSpaceUsers_Model,
	userLister func(orgGuid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *SpaceUsersPluginPrinter) {
	return &SpaceUsersPluginPrinter{
		PluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		UserLister:  userLister,
		Roles:       roles,
	}
}

func (p *OrgUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		users, _ := p.UserLister(guid, role)
		for _, user := range users {
			p.users.StoreAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.PluginModel) = p.users.AsOrgUsers()
}

func (p *SpaceUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		users, _ := p.UserLister(guid, role)
		for _, user := range users {
			p.users.StoreAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.PluginModel) = p.users.AsSpaceUsers()
}

func (p *OrgUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching org-users for role {{.OrgRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                err.Error(),
					"OrgRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (p *SpaceUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching space-users for role {{.SpaceRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                  err.Error(),
					"SpaceRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (c *users) StoreAppendingRole(role string, username string, guid string, isAdmin bool) {
	u := c.db[username]
	u.Roles = append(u.Roles, role)
	u.Username = username
	u.Guid = guid
	u.IsAdmin = isAdmin
	c.db[username] = u
}

func (c *users) AsOrgUsers() (coll []plugin_models.GetOrgUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetOrgUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.Roles,
		})
	}
	return coll
}

func (c *users) AsSpaceUsers() (coll []plugin_models.GetSpaceUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetSpaceUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.Roles,
		})
	}
	return coll
}
<commit_msg>Shuffle and correct stuff<commit_after>package user_printer

import (
	"fmt"

	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/plugin/models"
)

type UserPrinter interface {
	PrintUsers(guid string, username string)
}

type SpaceUsersPluginPrinter struct {
	UserPrinter
	Roles       []string
	UserLister  func(spaceGuid string, role string) ([]models.UserFields, error)
	PluginModel *[]plugin_models.GetSpaceUsers_Model
	users       users
}

type OrgUsersPluginPrinter struct {
	UserPrinter
	Roles       []string
	UserLister  func(orgGuid string, role string) ([]models.UserFields, error)
	PluginModel *[]plugin_models.GetOrgUsers_Model
	users       users
}

type SpaceUsersUiPrinter struct {
	UserPrinter
	Ui               terminal.UI
	UserLister       func(spaceGuid string, role string) ([]models.UserFields, error)
	Roles            []string
	RoleDisplayNames map[string]string
}

type OrgUsersUiPrinter struct {
	UserPrinter
	Roles            []string
	RoleDisplayNames map[string]string
	UserLister       func(orgGuid string, role string) ([]models.UserFields, error)
	Ui               terminal.UI
}

type userWithRoles struct {
	models.UserFields
	Roles []string
}

type users struct {
	db map[string]userWithRoles
}

func NewOrgUsersPluginPrinter(
	pluginModel *[]plugin_models.GetOrgUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *OrgUsersPluginPrinter) {
	return &OrgUsersPluginPrinter{
		PluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		UserLister:  userLister,
		Roles:       roles,
	}
}

func NewSpaceUsersPluginPrinter(
	pluginModel *[]plugin_models.GetSpaceUsers_Model,
	userLister func(guid string, role string) ([]models.UserFields, error),
	roles []string,
) (printer *SpaceUsersPluginPrinter) {
	return &SpaceUsersPluginPrinter{
		PluginModel: pluginModel,
		users:       users{db: make(map[string]userWithRoles)},
		UserLister:  userLister,
		Roles:       roles,
	}
}

func (p *OrgUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		users, _ := p.UserLister(guid, role)
		for _, user := range users {
			p.users.StoreAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.PluginModel) = p.users.AsOrgUsers()
}

func (p *SpaceUsersPluginPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		users, _ := p.UserLister(guid, role)
		for _, user := range users {
			p.users.StoreAppendingRole(role, user.Username, user.Guid, user.IsAdmin)
		}
	}
	*(p.PluginModel) = p.users.AsSpaceUsers()
}

func (p *OrgUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching org-users for role {{.OrgRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                err.Error(),
					"OrgRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (p *SpaceUsersUiPrinter) PrintUsers(guid string, username string) {
	for _, role := range p.Roles {
		displayName := p.RoleDisplayNames[role]
		users, err := p.UserLister(guid, role)
		if err != nil {
			p.Ui.Failed(T("Failed fetching space-users for role {{.SpaceRoleToDisplayName}}.\n{{.Error}}",
				map[string]interface{}{
					"Error":                  err.Error(),
					"SpaceRoleToDisplayName": displayName,
				}))
			return
		}
		p.Ui.Say("")
		p.Ui.Say("%s", terminal.HeaderColor(displayName))

		if len(users) == 0 {
			p.Ui.Say(fmt.Sprintf("  "+T("No %s found"), displayName))
		} else {
			for _, user := range users {
				p.Ui.Say("  %s", user.Username)
			}
		}
	}
}

func (c *users) StoreAppendingRole(role string, username string, guid string, isAdmin bool) {
	u := c.db[username]
	u.Roles = append(u.Roles, role)
	u.Username = username
	u.Guid = guid
	u.IsAdmin = isAdmin
	c.db[username] = u
}

func (c *users) AsOrgUsers() (coll []plugin_models.GetOrgUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetOrgUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.Roles,
		})
	}
	return coll
}

func (c *users) AsSpaceUsers() (coll []plugin_models.GetSpaceUsers_Model) {
	for _, u := range c.db {
		coll = append(coll, plugin_models.GetSpaceUsers_Model{
			Guid:     u.Guid,
			Username: u.Username,
			IsAdmin:  u.IsAdmin,
			Roles:    u.Roles,
		})
	}
	return coll
}
<|endoftext|>


<commit_before>package update

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/flags"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

type configVariable struct {
	name        string
	description string
	validate    func(*app.Context, string) error
	needAuth    bool
}

type configVars []configVariable

var configVariables = configVars{
	{
		name:        "endpoint",
		description: "brain endpoint to connect to",
		validate:    validateEndpointForConfigFunc("endpoint"),
	},
	{
		name:        "api-endpoint",
		description: "endpoint for domains",
		validate:    validateEndpointForConfigFunc("api-endpoint"),
	},
	{
		name:        "billing-endpoint",
		description: "billing API endpoint to connect to",
		validate:    validateEndpointForConfigFunc("billing-endpoint"),
	},
	{
		name:        "spp-endpoint",
		description: "SPP endpoint to use",
		validate:    validateEndpointForConfigFunc("spp-endpoint"),
	},
	{
		name:        "auth-endpoint",
		description: "endpoint to authenticate to",
		validate:    validateEndpointForConfigFunc("auth-endpoint"),
	},
	{
		name:        "debug-level",
		description: "default debug level",
		validate:    validateIntForConfigFunc("debug-level"),
	},
	{
		name:        "token",
		description: "token used for authentication",
	},
	{
		name:        "user",
		description: "user that you log in as by default",
	},
	{
		name:        "account",
		description: "default account",
		validate:    validateAccountForConfig,
		needAuth:    true,
	},
	{
		name:        "group",
		description: "default group",
		validate:    validateGroupForConfig,
		needAuth:    true,
	},
}

func (variable configVariable) getFlags(c *app.Context) (string, bool) {
	return c.String(variable.name), c.Bool("unset-" + variable.name)
}

func (variable configVariable) present(c *app.Context) bool {
	set, unset := variable.getFlags(c)
	return set != "" || unset
}

func (variables configVars) present(c *app.Context) (out configVars) {
	out = configVars{}
	for _, variable := range variables {
		if variable.present(c) {
			out = append(out, variable)
		}
	}
	return
}

func (variables configVars) configFlags() (flags []cli.Flag) {
	flags = make([]cli.Flag, len(variables)*2)
	for i, variable := range variables {
		flags[i*2] = cli.StringFlag{
			Name:  variable.name,
			Usage: "Sets the " + variable.description,
		}
		flags[i*2+1] = cli.BoolFlag{
			Name:  "unset-" + variable.name,
			Usage: "Unsets the " + variable.description,
		}
	}
	return
}

func validateAccountForConfig(c *app.Context, name string) (err error) {
	_, err = c.Client().GetAccount(name)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such account %s - check your typing and specify --yubikey if necessary", name)
		}
		return err
	}
	return
}

func validateGroupForConfig(c *app.Context, name string) (err error) {
	// we can't just use with.Group because it expects NextArg() to be the account name - there's no way to pass one in.
	groupName := lib.ParseGroupName(name, c.Config().GetGroup())
	_, err = c.Client().GetGroup(groupName)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such group %v - check your typing and specify --yubikey if necessary", groupName)
		}
		return err
	}
	return
}

func validateEndpointForConfigFunc(variable string) func(*app.Context, string) error {
	return func(c *app.Context, endpoint string) error {
		url, err := url.Parse(endpoint)
		if err != nil {
			return err
		}
		if url.Scheme != "http" && url.Scheme != "https" {
			return errors.New(variable + " URL should start with http:// or https://")
		}
		if url.Host == "" {
			return errors.New(variable + " URL should have a hostname")
		}
		return nil
	}
}

func validateIntForConfigFunc(variable string) func(*app.Context, string) error {
	return func(c *app.Context, value string) error {
		_, err := strconv.ParseUint(value, 10, 32)
		if err != nil {
			return errors.New(variable + " must be an integer")
		}
		return nil
	}
}

func init() {
	Commands = append(Commands, cli.Command{
		Name:  "config",
		Usage: "manage the bytemark client's configuration",
		Description: `Manipulate the bytemark-client configuration

    Available variables:
        account - the default account, used when you do not explicitly state an account - defaults to the same as your user name
        token - the token used for authentication
        user - the user that you log in as by default
        group - the default group, used when you do not explicitly state a group (defaults to 'default')

        debug-level - the default debug level. Set to 0 unless you like lots of output.
	api-endpoint - the endpoint for domains (among other things?)
        auth-endpoint - the endpoint to authenticate to. https://auth.bytemark.co.uk is the default.
        endpoint - the brain endpoint to connect to. https://uk0.bigv.io is the default.
        billing-endpoint - the billing API endpoint to connect to. https://bmbilling.bytemark.co.uk is the default.
        spp-endpoint - the SPP endpoint to use. https://spp-submissions.bytemark.co.uk is the default.`,
		Flags:  append(configVariables.configFlags(), flags.Force),
		Action: configVariables.updateConfig,
	})
}

func (variables configVars) updateConfig(c *app.Context) error {
	presentVariables := variables.present(c)
	withAuth := false
	// first pass, validate
	if len(presentVariables) == 0 {
		return c.Help("missing arguments")
	}
	for _, variable := range presentVariables {
		set, unset := variable.getFlags(c)
		if set != "" && unset {
			return c.Help("cannot set and unset " + variable.name)
		}
		if set != "" && !flags.Forced(c) && variable.validate != nil {
			if variable.needAuth && !withAuth {
				err := with.Auth(c)
				if err != nil {
					return err
				}
				withAuth = true
			}
			err := variable.validate(c, variable.name)
			if err != nil {
				return err
			}
		}
	}
	// second pass, apply
	for _, variable := range presentVariables {
		set, unset := variable.getFlags(c)
		if unset {
			err := c.Config().Unset(variable.name)
			if err != nil {
				return err
			}
			log.Logf("Is has been unset. \r\n", variable.name)
		} else {
			oldVar, err := c.Config().GetV(variable.name)
			if err != nil {
				return err
			}
			err = c.Config().SetPersistent(variable.name, set, "CMD set")
			if err != nil {
				return err
			}

			if oldVar.Source == "config" {
				log.Logf("%s has been changed.\r\nOld value: %s\r\nNew value: %s\r\n", variable.name, oldVar.Value, c.Config().GetIgnoreErr(variable.name))
			} else {
				log.Logf("%s has been set. \r\nNew value: %s\r\n", variable.name, c.Config().GetIgnoreErr(variable.name))
			}
		}
	}
	return nil
}
<commit_msg>remove blindly copied comment<commit_after>package update

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/flags"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

type configVariable struct {
	name        string
	description string
	validate    func(*app.Context, string) error
	needAuth    bool
}

type configVars []configVariable

var configVariables = configVars{
	{
		name:        "endpoint",
		description: "brain endpoint to connect to",
		validate:    validateEndpointForConfigFunc("endpoint"),
	},
	{
		name:        "api-endpoint",
		description: "endpoint for domains",
		validate:    validateEndpointForConfigFunc("api-endpoint"),
	},
	{
		name:        "billing-endpoint",
		description: "billing API endpoint to connect to",
		validate:    validateEndpointForConfigFunc("billing-endpoint"),
	},
	{
		name:        "spp-endpoint",
		description: "SPP endpoint to use",
		validate:    validateEndpointForConfigFunc("spp-endpoint"),
	},
	{
		name:        "auth-endpoint",
		description: "endpoint to authenticate to",
		validate:    validateEndpointForConfigFunc("auth-endpoint"),
	},
	{
		name:        "debug-level",
		description: "default debug level",
		validate:    validateIntForConfigFunc("debug-level"),
	},
	{
		name:        "token",
		description: "token used for authentication",
	},
	{
		name:        "user",
		description: "user that you log in as by default",
	},
	{
		name:        "account",
		description: "default account",
		validate:    validateAccountForConfig,
		needAuth:    true,
	},
	{
		name:        "group",
		description: "default group",
		validate:    validateGroupForConfig,
		needAuth:    true,
	},
}

func (variable configVariable) getFlags(c *app.Context) (string, bool) {
	return c.String(variable.name), c.Bool("unset-" + variable.name)
}

func (variable configVariable) present(c *app.Context) bool {
	set, unset := variable.getFlags(c)
	return set != "" || unset
}

func (variables configVars) present(c *app.Context) (out configVars) {
	out = configVars{}
	for _, variable := range variables {
		if variable.present(c) {
			out = append(out, variable)
		}
	}
	return
}

func (variables configVars) configFlags() (flags []cli.Flag) {
	flags = make([]cli.Flag, len(variables)*2)
	for i, variable := range variables {
		flags[i*2] = cli.StringFlag{
			Name:  variable.name,
			Usage: "Sets the " + variable.description,
		}
		flags[i*2+1] = cli.BoolFlag{
			Name:  "unset-" + variable.name,
			Usage: "Unsets the " + variable.description,
		}
	}
	return
}

func validateAccountForConfig(c *app.Context, name string) (err error) {
	_, err = c.Client().GetAccount(name)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such account %s - check your typing and specify --yubikey if necessary", name)
		}
		return err
	}
	return
}

func validateGroupForConfig(c *app.Context, name string) (err error) {
	groupName := lib.ParseGroupName(name, c.Config().GetGroup())
	_, err = c.Client().GetGroup(groupName)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such group %v - check your typing and specify --yubikey if necessary", groupName)
		}
		return err
	}
	return
}

func validateEndpointForConfigFunc(variable string) func(*app.Context, string) error {
	return func(c *app.Context, endpoint string) error {
		url, err := url.Parse(endpoint)
		if err != nil {
			return err
		}
		if url.Scheme != "http" && url.Scheme != "https" {
			return errors.New(variable + " URL should start with http:// or https://")
		}
		if url.Host == "" {
			return errors.New(variable + " URL should have a hostname")
		}
		return nil
	}
}

func validateIntForConfigFunc(variable string) func(*app.Context, string) error {
	return func(c *app.Context, value string) error {
		_, err := strconv.ParseUint(value, 10, 32)
		if err != nil {
			return errors.New(variable + " must be an integer")
		}
		return nil
	}
}

func init() {
	Commands = append(Commands, cli.Command{
		Name:  "config",
		Usage: "manage the bytemark client's configuration",
		Description: `Manipulate the bytemark-client configuration

    Available variables:
        account - the default account, used when you do not explicitly state an account - defaults to the same as your user name
        token - the token used for authentication
        user - the user that you log in as by default
        group - the default group, used when you do not explicitly state a group (defaults to 'default')

        debug-level - the default debug level. Set to 0 unless you like lots of output.
	api-endpoint - the endpoint for domains (among other things?)
        auth-endpoint - the endpoint to authenticate to. https://auth.bytemark.co.uk is the default.
        endpoint - the brain endpoint to connect to. https://uk0.bigv.io is the default.
        billing-endpoint - the billing API endpoint to connect to. https://bmbilling.bytemark.co.uk is the default.
        spp-endpoint - the SPP endpoint to use. https://spp-submissions.bytemark.co.uk is the default.`,
		Flags:  append(configVariables.configFlags(), flags.Force),
		Action: configVariables.updateConfig,
	})
}

func (variables configVars) updateConfig(c *app.Context) error {
	presentVariables := variables.present(c)
	withAuth := false
	// first pass, validate
	if len(presentVariables) == 0 {
		return c.Help("missing arguments")
	}
	for _, variable := range presentVariables {
		set, unset := variable.getFlags(c)
		if set != "" && unset {
			return c.Help("cannot set and unset " + variable.name)
		}
		if set != "" && !flags.Forced(c) && variable.validate != nil {
			if variable.needAuth && !withAuth {
				err := with.Auth(c)
				if err != nil {
					return err
				}
				withAuth = true
			}
			err := variable.validate(c, variable.name)
			if err != nil {
				return err
			}
		}
	}
	// second pass, apply
	for _, variable := range presentVariables {
		set, unset := variable.getFlags(c)
		if unset {
			err := c.Config().Unset(variable.name)
			if err != nil {
				return err
			}
			log.Logf("Is has been unset. \r\n", variable.name)
		} else {
			oldVar, err := c.Config().GetV(variable.name)
			if err != nil {
				return err
			}
			err = c.Config().SetPersistent(variable.name, set, "CMD set")
			if err != nil {
				return err
			}

			if oldVar.Source == "config" {
				log.Logf("%s has been changed.\r\nOld value: %s\r\nNew value: %s\r\n", variable.name, oldVar.Value, c.Config().GetIgnoreErr(variable.name))
			} else {
				log.Logf("%s has been set. \r\nNew value: %s\r\n", variable.name, c.Config().GetIgnoreErr(variable.name))
			}
		}
	}
	return nil
}
<|endoftext|>