<commit_before>package engine

import (
	"github.com/go-gl/gl"
	//"gl/glu"
	//"log"
	//"image/png"
	//"image"
	//"os"
	"log"

	"github.com/vova616/chipmunk/vect"
	//"glfw"
)

type OnAnimationEnd func(sprite *Sprite)

type Sprite struct {
	BaseComponent
	*Texture
	//buffer               gl.Buffer
	AnimationSpeed       float32
	texcoordsIndex       int
	endAnimation         int
	startAnimation       int
	animation            float32
	UVs                  AnimatedUV
	animMap              map[ID][2]int
	currentAnim          interface{}
	AnimationEndCallback OnAnimationEnd

	Tiling Vector

	Render bool

	Color Color

	align Align
}

func NewSprite(tex *Texture) *Sprite {
	return NewSprite3(tex, AnimatedUV{NewUV(0, 0, 1, 1, float32(tex.Width())/float32(tex.Height()))})
}

func NewSprite2(tex *Texture, uv UV) *Sprite {
	return NewSprite3(tex, AnimatedUV{uv})
}

func NewSprite3(tex *Texture, uv AnimatedUV) *Sprite {

	sp := &Sprite{
		BaseComponent: NewComponent(),
		Texture:       tex,
		//buffer:         gl.GenBuffer(),
		AnimationSpeed: 1,
		endAnimation:   len(uv),
		UVs:            uv,
		Render:         true,
		Color:          Color_White,
		align:          AlignCenter,
		Tiling:         Vector{1, 1, 0},
	}
	//sp.CreateVBO(uv...)

	return sp
}

func (p *Sprite) BindAnimations(animMap map[ID][2]int) {
	p.animMap = animMap
}

func (p *Sprite) SetAnimation(id ID) {
	a, e := p.animMap[id]
	if !e {
		panic("no such id")
	}
	p.currentAnim = id
	p.animation = float32(a[0])
	p.startAnimation = a[0]
	p.endAnimation = a[1]
}

func (p *Sprite) Align() Align {
	return p.align
}

func (p *Sprite) SetAlign(align Align) {
	p.align = align
}

func (p *Sprite) CurrentAnimation() interface{} {
	return p.currentAnim
}

func (sp *Sprite) OnComponentAdd() {
	sp.gameObject.Sprite = sp
}

/*
func (sp *Sprite) CreateVBO(uvs ...UV) {
	l := len(uvs)

	if l == 0 {
		sp.buffer.Bind(gl.ARRAY_BUFFER)
		gl.BufferData(gl.ARRAY_BUFFER, 1, []byte{1}, gl.STATIC_DRAW)
		return
	}

	lt := l * 12
	_ = lt
	data := make([]float32, 20*l)

	vertexCount := 0
	texcoordsIndex := lt * 4
	for i, uv := range uvs {

		yratio := float32(1)
		xratio := uv.Ratio
		ygrid := float32(-0.5)
		xgrid := float32(-uv.Ratio / 2)

		vertexCount += 4

		data[(i*12)+0] = xgrid
		data[(i*12)+1] = ygrid
		data[(i*12)+2] = 1
		data[(i*12)+3] = (xratio) + xgrid
		data[(i*12)+4] = ygrid
		data[(i*12)+5] = 1
		data[(i*12)+6] = (xratio) + xgrid
		data[(i*12)+7] = (yratio) + ygrid
		data[(i*12)+8] = 1
		data[(i*12)+9] = xgrid
		data[(i*12)+10] = (yratio) + ygrid
		data[(i*12)+11] = 1

		data[lt+(i*8)+0] = uv.U1
		data[lt+(i*8)+1] = uv.V2
		data[lt+(i*8)+2] = uv.U2
		data[lt+(i*8)+3] = uv.V2

		data[lt+(i*8)+4] = uv.U2
		data[lt+(i*8)+5] = uv.V1
		data[lt+(i*8)+6] = uv.U1
		data[lt+(i*8)+7] = uv.V1
	}

	sp.texcoordsIndex = texcoordsIndex
	sp.buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, data, gl.STATIC_DRAW)
}
*/

func (sp *Sprite) Start() {

}

func (sp *Sprite) RealWorldSize() (s Vector) {
	currentUV := sp.UVs[int(sp.animation)]
	s = sp.Transform().WorldScale()
	s.X *= currentUV.Ratio
	return
}

func (sp *Sprite) RealSize() (s Vector) {
	currentUV := sp.UVs[int(sp.animation)]
	s = sp.Transform().Scale()
	s.X *= currentUV.Ratio
	return
}

func (sp *Sprite) CurrentAnimationIndex() int {
	return int(sp.animation) - sp.startAnimation
}

func (sp *Sprite) AnimationLength() int {
	return sp.endAnimation - sp.startAnimation
}

func (sp *Sprite) SetAnimationIndex(index int) {
	if index <= 0 {
		sp.animation = float32(sp.startAnimation)
	} else {
		sp.animation = float32((index % (sp.endAnimation - sp.startAnimation)) + sp.startAnimation)
	}
}

var renders = 0

func (sp *Sprite) Update() {
	if sp.AnimationSpeed != 0 {
		if int(sp.animation) < sp.endAnimation {
			sp.animation += float32(float64(sp.AnimationSpeed) * DeltaTime())
		}
		for sp.animation >= float32(sp.endAnimation) {
			if sp.AnimationEndCallback != nil {
				sp.AnimationEndCallback(sp)
			}
			//If something has been changed in callback
			if sp.animation >= float32(sp.endAnimation) {
				sp.animation = float32(sp.startAnimation) + (sp.animation - float32(sp.endAnimation))
			}
		}
	}
	sp.UpdateShape()
	if renders != 0 && Debug && 1 == 2 {
		camera := GetScene().SceneBase().Camera
		log.Println(renders, camera.Transform().WorldPosition(), camera.Transform().Matrix())
	}
	renders = 0
}

/*
Todo: make this an interface.
*/
func (sp *Sprite) UpdateShape() {
	if sp.GameObject().Physics != nil {
		ph := sp.GameObject().Physics
		box := ph.Box
		cir := ph.Shape.GetAsCircle()

		scale := sp.Transform().WorldScale()
		ratio := sp.UVs[int(sp.animation)].Ratio
		scale.X *= ratio

		if box != nil {
			update := false
			if vect.Float(scale.Y) != box.Height || vect.Float(scale.X) != box.Width {
				box.Height = vect.Float(scale.Y)
				box.Width = vect.Float(scale.X)
				//box.Position = Vect{box.Width/2, box.Height/2}
				update = true
			}

			c := sp.align.Vector()
			center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
			center.X *= vect.Float(scale.X)
			center.Y *= vect.Float(scale.Y)

			if box.Position.X != center.X || box.Position.Y != center.Y {
				update = true
				box.Position.X, box.Position.Y = center.X, center.Y
			}

			if update {
				box.UpdatePoly()
				if !ph.Body.MomentIsInf() && box.Height != 0 && box.Width != 0 {
					ph.Body.SetMoment(vect.Float(box.Moment(float32(ph.Body.Mass()))))
				}
			}
		} else if cir != nil {
			update := false
			s := float32(0)
			if scale.X > scale.Y {
				s = scale.X
			} else {
				s = scale.Y
			}
			if float32(cir.Radius) != s/2 {
				cir.Radius = vect.Float(s / 2)
				update = true
			}

			c := sp.align.Vector()
			center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
			center.X *= vect.Float(s)
			center.Y *= vect.Float(s)

			if cir.Position.X != center.X || cir.Position.Y != center.Y {
				update = true
				cir.Position.X, cir.Position.Y = center.X, center.Y
			}

			if update {
				sp.GameObject().Physics.Body.UpdateShapes()
				if !ph.Body.MomentIsInf() && cir.Radius != 0 {
					//log.Println(sp.gameObject.name, cir.Radius, cir.Moment(float32(ph.Body.Mass())), scale.X, scale.Y, ph.Body.Mass(), cir.Position)
					ph.Body.SetMoment(vect.Float(cir.Moment(float32(ph.Body.Mass()))))
				}
			}
		}
	}
}

func Abs(val float32) float32 {
	if val < 0 {
		return -val
	}
	return val
}

func (sp *Sprite) Draw() {
	if sp.Texture != nil && sp.Render {
		/*
			Temporal camera distance check
		*/
		currentUV := sp.UVs[int(sp.animation)]
		if !InsideScreen(currentUV.Ratio, sp.Transform().WorldPosition(), sp.Transform().WorldScale()) {
			return
		}

		renders++

		TextureMaterial.Begin(sp.GameObject())

		mp := TextureMaterial.ProjMatrix
		mv := TextureMaterial.ViewMatrix
		mm := TextureMaterial.ModelMatrix
		tx := TextureMaterial.Texture
		ac := TextureMaterial.AddColor
		ti := TextureMaterial.Tiling
		of := TextureMaterial.Offset

		defaultBuffer.Bind(gl.ARRAY_BUFFER)
		TextureMaterial.Verts.EnableArray()
		TextureMaterial.Verts.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
		TextureMaterial.UV.EnableArray()
		TextureMaterial.UV.AttribPointer(2, gl.FLOAT, false, 0, uintptr(12*4))

		v := sp.align.Vector()
		v.X *= currentUV.Ratio

		camera := GetScene().SceneBase().Camera
		view := camera.InvertedMatrix()
		model := Identity()
		model.Scale(currentUV.Ratio, 1, 1)
		model.Translate(v.X, v.Y, 0)
		model.Mul(sp.GameObject().Transform().Matrix())
		model.Translate(0.75, 0.75, 0)

		mv.UniformMatrix4fv(false, view)
		mp.UniformMatrix4f(false, (*[16]float32)(camera.Projection))
		mm.UniformMatrix4fv(false, model)

		sp.Bind()
		tx.Uniform1i(0)

		ac.Uniform4f(sp.Color.R, sp.Color.G, sp.Color.B, sp.Color.A)
		ti.Uniform2f((currentUV.U2-currentUV.U1)*sp.Tiling.X, (currentUV.V2-currentUV.V1)*sp.Tiling.Y)
		of.Uniform2f(currentUV.U1, currentUV.V1)

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

		TextureMaterial.End(sp.GameObject())
	}
}

func (sp *Sprite) DrawScreen() {
	if sp.Texture != nil && sp.Render {

		camera := GetScene().SceneBase().Camera
		pos := sp.Transform().WorldPosition()
		scale := sp.Transform().WorldScale()

		TextureMaterial.Begin(sp.GameObject())

		mp := TextureMaterial.ProjMatrix
		mv := TextureMaterial.ViewMatrix
		mm := TextureMaterial.ModelMatrix
		tx := TextureMaterial.Texture
		ac := TextureMaterial.AddColor
		ti := TextureMaterial.Tiling
		of := TextureMaterial.Offset

		defaultBuffer.Bind(gl.ARRAY_BUFFER)
		TextureMaterial.Verts.EnableArray()
		TextureMaterial.Verts.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
		TextureMaterial.UV.EnableArray()
		TextureMaterial.UV.AttribPointer(2, gl.FLOAT, false, 0, uintptr(12*4))

		currentUV := sp.UVs[int(sp.animation)]

		view := Identity()
		model := Identity()
		model.Scale(scale.X*currentUV.Ratio, scale.Y, 1)
		model.Translate((float32(Width)/2)+pos.X+0.75, (float32(Height)/2)+pos.Y+0.75, 1)

		mv.UniformMatrix4fv(false, view)
		mp.UniformMatrix4f(false, (*[16]float32)(camera.Projection))
		mm.UniformMatrix4fv(false, model)

		ti.Uniform2f((currentUV.U2-currentUV.U1)*sp.Tiling.X, (currentUV.V2-currentUV.V1)*sp.Tiling.Y)
		of.Uniform2f(currentUV.U1, currentUV.V1)

		sp.Bind()
		gl.ActiveTexture(gl.TEXTURE0)
		tx.Uniform1i(0)

		//ac.Uniform4f(1, 1, 1, 0)
		ac.Uniform4f(sp.Color.R, sp.Color.G, sp.Color.B, sp.Color.A)

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

		TextureMaterial.End(sp.GameObject())
	}
}
<commit_msg>better sprite drawing.<commit_after>package engine

import (
	"github.com/go-gl/gl"
	//"gl/glu"
	//"log"
	//"image/png"
	//"image"
	//"os"
	"log"

	"github.com/vova616/chipmunk/vect"
	//"glfw"
)

type OnAnimationEnd func(sprite *Sprite)

type Sprite struct {
	BaseComponent
	*Texture
	//buffer               gl.Buffer
	AnimationSpeed       float32
	texcoordsIndex       int
	endAnimation         int
	startAnimation       int
	animation            float32
	UVs                  AnimatedUV
	animMap              map[ID][2]int
	currentAnim          interface{}
	AnimationEndCallback OnAnimationEnd

	Tiling Vector

	Render bool

	Color Color

	align Align
}

func NewSprite(tex *Texture) *Sprite {
	return NewSprite3(tex, AnimatedUV{NewUV(0, 0, 1, 1, float32(tex.Width())/float32(tex.Height()))})
}

func NewSprite2(tex *Texture, uv UV) *Sprite {
	return NewSprite3(tex, AnimatedUV{uv})
}

func NewSprite3(tex *Texture, uv AnimatedUV) *Sprite {

	sp := &Sprite{
		BaseComponent: NewComponent(),
		Texture:       tex,
		//buffer:         gl.GenBuffer(),
		AnimationSpeed: 1,
		endAnimation:   len(uv),
		UVs:            uv,
		Render:         true,
		Color:          Color_White,
		align:          AlignCenter,
		Tiling:         Vector{1, 1, 0},
	}
	//sp.CreateVBO(uv...)

	return sp
}

func (p *Sprite) BindAnimations(animMap map[ID][2]int) {
	p.animMap = animMap
}

func (p *Sprite) SetAnimation(id ID) {
	a, e := p.animMap[id]
	if !e {
		panic("no such id")
	}
	p.currentAnim = id
	p.animation = float32(a[0])
	p.startAnimation = a[0]
	p.endAnimation = a[1]
}

func (p *Sprite) Align() Align {
	return p.align
}

func (p *Sprite) SetAlign(align Align) {
	p.align = align
}

func (p *Sprite) CurrentAnimation() interface{} {
	return p.currentAnim
}

func (sp *Sprite) OnComponentAdd() {
	sp.gameObject.Sprite = sp
}

/*
func (sp *Sprite) CreateVBO(uvs ...UV) {
	l := len(uvs)

	if l == 0 {
		sp.buffer.Bind(gl.ARRAY_BUFFER)
		gl.BufferData(gl.ARRAY_BUFFER, 1, []byte{1}, gl.STATIC_DRAW)
		return
	}

	lt := l * 12
	_ = lt
	data := make([]float32, 20*l)

	vertexCount := 0
	texcoordsIndex := lt * 4
	for i, uv := range uvs {

		yratio := float32(1)
		xratio := uv.Ratio
		ygrid := float32(-0.5)
		xgrid := float32(-uv.Ratio / 2)

		vertexCount += 4

		data[(i*12)+0] = xgrid
		data[(i*12)+1] = ygrid
		data[(i*12)+2] = 1
		data[(i*12)+3] = (xratio) + xgrid
		data[(i*12)+4] = ygrid
		data[(i*12)+5] = 1
		data[(i*12)+6] = (xratio) + xgrid
		data[(i*12)+7] = (yratio) + ygrid
		data[(i*12)+8] = 1
		data[(i*12)+9] = xgrid
		data[(i*12)+10] = (yratio) + ygrid
		data[(i*12)+11] = 1

		data[lt+(i*8)+0] = uv.U1
		data[lt+(i*8)+1] = uv.V2
		data[lt+(i*8)+2] = uv.U2
		data[lt+(i*8)+3] = uv.V2

		data[lt+(i*8)+4] = uv.U2
		data[lt+(i*8)+5] = uv.V1
		data[lt+(i*8)+6] = uv.U1
		data[lt+(i*8)+7] = uv.V1
	}

	sp.texcoordsIndex = texcoordsIndex
	sp.buffer.Bind(gl.ARRAY_BUFFER)
	gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, data, gl.STATIC_DRAW)
}
*/

func (sp *Sprite) Start() {

}

func (sp *Sprite) RealWorldSize() (s Vector) {
	currentUV := sp.UVs[int(sp.animation)]
	s = sp.Transform().WorldScale()
	s.X *= currentUV.Ratio
	return
}

func (sp *Sprite) RealSize() (s Vector) {
	currentUV := sp.UVs[int(sp.animation)]
	s = sp.Transform().Scale()
	s.X *= currentUV.Ratio
	return
}

func (sp *Sprite) CurrentAnimationIndex() int {
	return int(sp.animation) - sp.startAnimation
}

func (sp *Sprite) AnimationLength() int {
	return sp.endAnimation - sp.startAnimation
}

func (sp *Sprite) SetAnimationIndex(index int) {
	if index <= 0 {
		sp.animation = float32(sp.startAnimation)
	} else {
		sp.animation = float32((index % (sp.endAnimation - sp.startAnimation)) + sp.startAnimation)
	}
}

var renders = 0

func (sp *Sprite) Update() {
	if sp.AnimationSpeed != 0 {
		if int(sp.animation) < sp.endAnimation {
			sp.animation += float32(float64(sp.AnimationSpeed) * DeltaTime())
		}
		for sp.animation >= float32(sp.endAnimation) {
			if sp.AnimationEndCallback != nil {
				sp.AnimationEndCallback(sp)
			}
			//If something has been changed in callback
			if sp.animation >= float32(sp.endAnimation) {
				sp.animation = float32(sp.startAnimation) + (sp.animation - float32(sp.endAnimation))
			}
		}
	}
	sp.UpdateShape()
	if renders != 0 && Debug && 1 == 2 {
		camera := GetScene().SceneBase().Camera
		log.Println(renders, camera.Transform().WorldPosition(), camera.Transform().Matrix())
	}
	renders = 0
}

/*
Todo: make this an interface.
*/
func (sp *Sprite) UpdateShape() {
	if sp.GameObject().Physics != nil {
		ph := sp.GameObject().Physics
		box := ph.Box
		cir := ph.Shape.GetAsCircle()

		scale := sp.Transform().WorldScale()
		ratio := sp.UVs[int(sp.animation)].Ratio
		scale.X *= ratio

		if box != nil {
			update := false
			if vect.Float(scale.Y) != box.Height || vect.Float(scale.X) != box.Width {
				box.Height = vect.Float(scale.Y)
				box.Width = vect.Float(scale.X)
				//box.Position = Vect{box.Width/2, box.Height/2}
				update = true
			}

			c := sp.align.Vector()
			center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
			center.X *= vect.Float(scale.X)
			center.Y *= vect.Float(scale.Y)

			if box.Position.X != center.X || box.Position.Y != center.Y {
				update = true
				box.Position.X, box.Position.Y = center.X, center.Y
			}

			if update {
				box.UpdatePoly()
				if !ph.Body.MomentIsInf() && box.Height != 0 && box.Width != 0 {
					ph.Body.SetMoment(vect.Float(box.Moment(float32(ph.Body.Mass()))))
				}
			}
		} else if cir != nil {
			update := false
			s := float32(0)
			if scale.X > scale.Y {
				s = scale.X
			} else {
				s = scale.Y
			}
			if float32(cir.Radius) != s/2 {
				cir.Radius = vect.Float(s / 2)
				update = true
			}

			c := sp.align.Vector()
			center := vect.Vect{vect.Float(c.X), vect.Float(c.Y)}
			center.X *= vect.Float(s)
			center.Y *= vect.Float(s)

			if cir.Position.X != center.X || cir.Position.Y != center.Y {
				update = true
				cir.Position.X, cir.Position.Y = center.X, center.Y
			}

			if update {
				sp.GameObject().Physics.Body.UpdateShapes()
				if !ph.Body.MomentIsInf() && cir.Radius != 0 {
					//log.Println(sp.gameObject.name, cir.Radius, cir.Moment(float32(ph.Body.Mass())), scale.X, scale.Y, ph.Body.Mass(), cir.Position)
					ph.Body.SetMoment(vect.Float(cir.Moment(float32(ph.Body.Mass()))))
				}
			}
		}
	}
}

func Abs(val float32) float32 {
	if val < 0 {
		return -val
	}
	return val
}

func (sp *Sprite) Draw() {
	if sp.Texture != nil && sp.Render {
		/*
			Temporal camera distance check
		*/
		currentUV := sp.UVs[int(sp.animation)]
		if !InsideScreen(currentUV.Ratio, sp.Transform().WorldPosition(), sp.Transform().WorldScale()) {
			return
		}

		renders++

		TextureMaterial.Begin(sp.GameObject())

		mp := TextureMaterial.ProjMatrix
		mv := TextureMaterial.ViewMatrix
		mm := TextureMaterial.ModelMatrix
		tx := TextureMaterial.Texture
		ac := TextureMaterial.AddColor
		ti := TextureMaterial.Tiling
		of := TextureMaterial.Offset

		defaultBuffer.Bind(gl.ARRAY_BUFFER)
		TextureMaterial.Verts.EnableArray()
		TextureMaterial.Verts.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
		TextureMaterial.UV.EnableArray()
		TextureMaterial.UV.AttribPointer(2, gl.FLOAT, false, 0, uintptr(12*4))

		v := sp.align.Vector()
		v.X *= currentUV.Ratio

		camera := GetScene().SceneBase().Camera
		view := camera.InvertedMatrix()
		model := Identity()
		model.Scale(currentUV.Ratio, 1, 1)
		model.Translate(v.X, v.Y, 0)
		model.Mul(sp.GameObject().Transform().Matrix())

		mv.UniformMatrix4f(false, (*[16]float32)(&view))
		mp.UniformMatrix4f(false, (*[16]float32)(camera.Projection))
		mm.UniformMatrix4f(false, (*[16]float32)(&model))

		sp.Bind()
		tx.Uniform1i(0)

		ac.Uniform4f(sp.Color.R, sp.Color.G, sp.Color.B, sp.Color.A)
		ti.Uniform2f((currentUV.U2-currentUV.U1)*sp.Tiling.X, (currentUV.V2-currentUV.V1)*sp.Tiling.Y)
		of.Uniform2f(currentUV.U1, currentUV.V1)

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

		TextureMaterial.End(sp.GameObject())
	}
}

func (sp *Sprite) DrawScreen() {
	if sp.Texture != nil && sp.Render {

		camera := GetScene().SceneBase().Camera
		pos := sp.Transform().WorldPosition()
		scale := sp.Transform().WorldScale()

		TextureMaterial.Begin(sp.GameObject())

		mp := TextureMaterial.ProjMatrix
		mv := TextureMaterial.ViewMatrix
		mm := TextureMaterial.ModelMatrix
		tx := TextureMaterial.Texture
		ac := TextureMaterial.AddColor
		ti := TextureMaterial.Tiling
		of := TextureMaterial.Offset

		defaultBuffer.Bind(gl.ARRAY_BUFFER)
		TextureMaterial.Verts.EnableArray()
		TextureMaterial.Verts.AttribPointer(3, gl.FLOAT, false, 0, uintptr(0))
		TextureMaterial.UV.EnableArray()
		TextureMaterial.UV.AttribPointer(2, gl.FLOAT, false, 0, uintptr(12*4))

		currentUV := sp.UVs[int(sp.animation)]

		view := Identity()
		model := Identity()
		model.Scale(scale.X*currentUV.Ratio, scale.Y, 1)
		model.Translate((float32(Width)/2)+pos.X+0.75, (float32(Height)/2)+pos.Y+0.75, 1)

		mv.UniformMatrix4fv(false, view)
		mp.UniformMatrix4f(false, (*[16]float32)(camera.Projection))
		mm.UniformMatrix4fv(false, model)

		ti.Uniform2f((currentUV.U2-currentUV.U1)*sp.Tiling.X, (currentUV.V2-currentUV.V1)*sp.Tiling.Y)
		of.Uniform2f(currentUV.U1, currentUV.V1)

		sp.Bind()
		gl.ActiveTexture(gl.TEXTURE0)
		tx.Uniform1i(0)

		//ac.Uniform4f(1, 1, 1, 0)
		ac.Uniform4f(sp.Color.R, sp.Color.G, sp.Color.B, sp.Color.A)

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

		TextureMaterial.End(sp.GameObject())
	}
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"time"

	log "github.com/coreos/fleet/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/fleet/machine"
	"github.com/coreos/fleet/registry"
)

const (
	// time between triggering reconciliation routine
	reconcileInterval = 2 * time.Second

	// name of role that represents the lead engine in a cluster
	engineRoleName = "engine-leader"
	// time the role will be leased before the lease must be renewed
	engineRoleLeasePeriod = 10 * time.Second
)

type Engine struct {
	rec      Reconciler
	registry registry.Registry
	machine  machine.Machine

	lease registry.Lease
}

func New(reg registry.Registry, mach machine.Machine) *Engine {
	rec := &wipReconciler{reg, mach}
	return &Engine{rec, reg, mach, nil}
}

func (e *Engine) Run(stop chan bool) {
	ticker := time.Tick(reconcileInterval)
	machID := e.machine.State().ID

	for {
		select {
		case <-stop:
			log.V(1).Info("Engine exiting due to stop signal")
			return
		case <-ticker:
			log.V(1).Info("Engine tick")

			e.lease = ensureLeader(e.lease, e.registry, machID)
			if e.lease == nil {
				continue
			}

			start := time.Now()
			e.rec.Reconcile()
			elapsed := time.Now().Sub(start)

			msg := fmt.Sprintf("Engine completed reconciliation in %s", elapsed)
			if elapsed > reconcileInterval {
				log.Warning(msg)
			} else {
				log.V(1).Info(msg)
			}
		}
	}
}

func (e *Engine) Purge() {
	if e.lease == nil {
		return
	}
	err := e.lease.Release()
	if err != nil {
		log.Errorf("Failed to release lease: %v", err)
	}
}

// ensureLeader will attempt to renew a non-nil Lease, falling back to
// acquiring a new Lease on the lead engine role.
func ensureLeader(prev registry.Lease, reg registry.Registry, machID string) (cur registry.Lease) {
	if prev != nil {
		err := prev.Renew(engineRoleLeasePeriod)
		if err == nil {
			cur = prev
			return
		} else {
			log.Errorf("Engine leadership could not be renewed: %v", err)
		}
	}

	var err error
	cur, err = reg.LeaseRole(engineRoleName, machID, engineRoleLeasePeriod)
	if err != nil {
		log.Errorf("Failed acquiring engine leadership: %v", err)
	} else if cur == nil {
		log.V(1).Infof("Unable to acquire engine leadership")
	} else {
		log.Infof("Acquired engine leadership")
	}

	return
}
<commit_msg>engine: switch back to dumb reconciler<commit_after>package engine

import (
	"fmt"
	"time"

	log "github.com/coreos/fleet/Godeps/_workspace/src/github.com/golang/glog"

	"github.com/coreos/fleet/machine"
	"github.com/coreos/fleet/registry"
)

const (
	// time between triggering reconciliation routine
	reconcileInterval = 2 * time.Second

	// name of role that represents the lead engine in a cluster
	engineRoleName = "engine-leader"
	// time the role will be leased before the lease must be renewed
	engineRoleLeasePeriod = 10 * time.Second
)

type Engine struct {
	rec      Reconciler
	registry registry.Registry
	machine  machine.Machine

	lease registry.Lease
}

func New(reg registry.Registry, mach machine.Machine) *Engine {
	rec := &dumbReconciler{reg, mach}
	return &Engine{rec, reg, mach, nil}
}

func (e *Engine) Run(stop chan bool) {
	ticker := time.Tick(reconcileInterval)
	machID := e.machine.State().ID

	for {
		select {
		case <-stop:
			log.V(1).Info("Engine exiting due to stop signal")
			return
		case <-ticker:
			log.V(1).Info("Engine tick")

			e.lease = ensureLeader(e.lease, e.registry, machID)
			if e.lease == nil {
				continue
			}

			start := time.Now()
			e.rec.Reconcile()
			elapsed := time.Now().Sub(start)

			msg := fmt.Sprintf("Engine completed reconciliation in %s", elapsed)
			if elapsed > reconcileInterval {
				log.Warning(msg)
			} else {
				log.V(1).Info(msg)
			}
		}
	}
}

func (e *Engine) Purge() {
	if e.lease == nil {
		return
	}
	err := e.lease.Release()
	if err != nil {
		log.Errorf("Failed to release lease: %v", err)
	}
}

// ensureLeader will attempt to renew a non-nil Lease, falling back to
// acquiring a new Lease on the lead engine role.
func ensureLeader(prev registry.Lease, reg registry.Registry, machID string) (cur registry.Lease) {
	if prev != nil {
		err := prev.Renew(engineRoleLeasePeriod)
		if err == nil {
			cur = prev
			return
		} else {
			log.Errorf("Engine leadership could not be renewed: %v", err)
		}
	}

	var err error
	cur, err = reg.LeaseRole(engineRoleName, machID, engineRoleLeasePeriod)
	if err != nil {
		log.Errorf("Failed acquiring engine leadership: %v", err)
	} else if cur == nil {
		log.V(1).Infof("Unable to acquire engine leadership")
	} else {
		log.Infof("Acquired engine leadership")
	}

	return
}
<|endoftext|>


<commit_before>package envh

import (
	"regexp"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestCreateTreeFromDelimiterFilteringByRegexp(t *testing.T) {
	setTestingEnvsForTree()

	n := createTreeFromDelimiterFilteringByRegexp(regexp.MustCompile("ENVH"), "_")

	for key, expected := range map[string]string{"TEST3": "test1", "TEST4": "test2", "TEST6": "test3", "TEST1": "test5", "TEST2": "test4"} {
		nodes := n.findAllChildsByKey(key, true)

		assert.Len(t, *nodes, 1, "Must contains 1 element")
		assert.Equal(t, expected, (*nodes)[0].value, "Must have correct value")
	}

	nodes := n.findAllChildsByKey("TEST2", false)

	assert.Len(t, *nodes, 2, "Must contains 2 elements")
}
<commit_msg>Split test function in 2 functions<commit_after>package envh

import (
	"regexp"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestCreateTreeFromDelimiterFilteringByRegexp(t *testing.T) {
	setTestingEnvsForTree()

	n := createTreeFromDelimiterFilteringByRegexp(regexp.MustCompile("ENVH"), "_")

	for key, expected := range map[string]string{"TEST3": "test1", "TEST4": "test2", "TEST6": "test3", "TEST1": "test5", "TEST2": "test4"} {
		nodes := n.findAllChildsByKey(key, true)

		assert.Len(t, *nodes, 1, "Must contains 1 element")
		assert.Equal(t, expected, (*nodes)[0].value, "Must have correct value")
	}
}

func TestCreateTreeFromDelimiterFilteringByRegexpAndFindAllKeysWithAKey(t *testing.T) {
	setTestingEnvsForTree()

	n := createTreeFromDelimiterFilteringByRegexp(regexp.MustCompile("ENVH"), "_")

	nodes := n.findAllChildsByKey("TEST2", false)

	assert.Len(t, *nodes, 2, "Must contains 2 elements")
}
<|endoftext|>


<commit_before>package whiplash

import (
	"testing"
)

func TestGetConfig(t *testing.T) {
	// try nonexistant file
	c, err := New("./test_corpus/zzzzxxxx")
	if err == nil {
		t.Errorf("Tried using nonexistant config file, but err is nil and config is %v", c)
	}
	// try non-json file
	c, err = New("./test_corpus/notjson.config")
	if err == nil {
		t.Errorf("Tried using non-json config file, but err is nil and config is %v", c)
	}
	// try json file which isn't a config for us
	c, err = New("./test_corpus/badjson.config")
	if err == nil {
		t.Errorf("Tried using non-json config file, but err is nil and config is %v", c)
	}
	// try json file which is a config but doesn't have an agg addr
	c, err = New("./test_corpus/badjson2.config")
	if err == nil {
		t.Errorf("Tried using bad config file, but err is nil and config is %v", c)
	}
	// use good config file
	c, err = New("./test_corpus/test.config")
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	if c.CephConfLoc != "./test_corpus/ceph.mon.conf" {
		t.Errorf("c.CephConfLoc should be ./test_corpus/ceph.mon.conf but got: %v", c.CephConfLoc)
	}
	if c.Aggregator.BindAddr != "127.0.0.1" {
		t.Errorf("c.Aggregator.BindAddr should be 127.0.0.1 but got: %v", c.Aggregator.BindAddr)
	}
	if c.Aggregator.BindPort != "61089" {
		t.Errorf("c.Aggregator.BindPort should be 61089 but got: %v", c.Aggregator.BindPort)
	}
}

func TestGetConfigGetIface(t *testing.T) {
	// read the test config file
	c, err := New("./test_corpus/test.config")
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	_, err = getIface(c.Aggregator.BindAddr)
	if err != nil {
		t.Fatalf("Expected 127.0.0.1 to be a valid iface but got: %v", err)
	}
}

func TestGetConfigParseCephConf(t *testing.T) {
	// bad file first, just to be sure
	c, err := New("./test_corpus/test2.config")
	if err == nil {
		t.Errorf("Opening nonexistent file worked; got: %v", c)
	}
	// read the test config file
	c, err = New("./test_corpus/test.config")
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	if c.CephConf["osd"]["admin socket"] != "/var/run/ceph/ceph-$name.asok" {
		t.Errorf("`admin socket` value not as expected: %v", c.CephConf["osd"]["admin socket"])
	}
}
<commit_msg>fixed config tests<commit_after>package whiplash

import (
	"testing"
)

func TestGetConfig(t *testing.T) {
	// try nonexistant file
	c, err := New("./test_corpus/zzzzxxxx", false)
	if err == nil {
		t.Errorf("Tried using nonexistant config file, but err is nil and config is %v", c)
	}
	// try non-json file
	c, err = New("./test_corpus/notjson.config", false)
	if err == nil {
		t.Errorf("Tried using non-json config file, but err is nil and config is %v", c)
	}
	// try json file which isn't a config for us
	c, err = New("./test_corpus/badjson.config", false)
	if err == nil {
		t.Errorf("Tried using non-json config file, but err is nil and config is %v", c)
	}
	// try json file which is a config but doesn't have an agg addr
	c, err = New("./test_corpus/badjson2.config", false)
	if err == nil {
		t.Errorf("Tried using bad config file, but err is nil and config is %v", c)
	}
	// use good config file
	c, err = New("./test_corpus/test.config", false)
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	if c.CephConfLoc != "./test_corpus/ceph.mon.conf" {
		t.Errorf("c.CephConfLoc should be ./test_corpus/ceph.mon.conf but got: %v", c.CephConfLoc)
	}
	if c.Aggregator.BindAddr != "127.0.0.1" {
		t.Errorf("c.Aggregator.BindAddr should be 127.0.0.1 but got: %v", c.Aggregator.BindAddr)
	}
	if c.Aggregator.BindPort != "61089" {
		t.Errorf("c.Aggregator.BindPort should be 61089 but got: %v", c.Aggregator.BindPort)
	}
}

func TestGetConfigGetIface(t *testing.T) {
	// read the test config file
	c, err := New("./test_corpus/test.config", false)
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	_, err = getIface(c.Aggregator.BindAddr)
	if err != nil {
		t.Fatalf("Expected 127.0.0.1 to be a valid iface but got: %v", err)
	}
}

func TestGetConfigParseCephConf(t *testing.T) {
	// bad file first, just to be sure
	c, err := New("./test_corpus/nofilenamedthis.config", true)
	if err == nil {
		t.Errorf("Opening nonexistent file worked; got: %v", c)
	}
	// read the test config file
	c, err = New("./test_corpus/test.config", true)
	if err != nil {
		t.Fatalf("Tried using test.config file, but got: %v", err)
	}
	if c.CephConf["osd"]["admin socket"] != "/var/run/ceph/ceph-$name.asok" {
		t.Errorf("`admin socket` value not as expected: '%v'", c.CephConf["osd"]["admin socket"])
	}
}
<|endoftext|>


<commit_before>package core_types

import (
	abci "github.com/tendermint/abci/types"
	"github.com/tendermint/go-crypto"
	"github.com/tendermint/go-p2p"
	"github.com/tendermint/go-rpc/types"
	"github.com/tendermint/go-wire"
	"github.com/tendermint/tendermint/types"
)

type ResultBlockchainInfo struct {
	LastHeight int                `json:"last_height"`
	BlockMetas []*types.BlockMeta `json:"block_metas"`
}

type ResultGenesis struct {
	Genesis *types.GenesisDoc `json:"genesis"`
}

type ResultBlock struct {
	BlockMeta *types.BlockMeta `json:"block_meta"`
	Block     *types.Block     `json:"block"`
}

type ResultCommit struct {
	Header          *types.Header `json:"header"`
	Commit          *types.Commit `json:"commit"`
	CanonicalCommit bool          `json:"canonical"`
}

type ResultStatus struct {
	NodeInfo          *p2p.NodeInfo `json:"node_info"`
	PubKey            crypto.PubKey `json:"pub_key"`
	LatestBlockHash   []byte        `json:"latest_block_hash"`
	LatestAppHash     []byte        `json:"latest_app_hash"`
	LatestBlockHeight int           `json:"latest_block_height"`
	LatestBlockTime   int64         `json:"latest_block_time"` // nano
}

type ResultNetInfo struct {
	Listening bool     `json:"listening"`
	Listeners []string `json:"listeners"`
	Peers     []Peer   `json:"peers"`
}

type ResultDialSeeds struct {
}

type Peer struct {
	p2p.NodeInfo     `json:"node_info"`
	IsOutbound       bool                 `json:"is_outbound"`
	ConnectionStatus p2p.ConnectionStatus `json:"connection_status"`
}

type ResultValidators struct {
	BlockHeight int                `json:"block_height"`
	Validators  []*types.Validator `json:"validators"`
}

type ResultDumpConsensusState struct {
	RoundState      string   `json:"round_state"`
	PeerRoundStates []string `json:"peer_round_states"`
}

type ResultBroadcastTx struct {
	Code abci.CodeType `json:"code"`
	Data []byte        `json:"data"`
	Log  string        `json:"log"`

	TxID []byte `json:"tx_id"`
}

type ResultBroadcastTxCommit struct {
	CheckTx   *abci.ResponseCheckTx   `json:"check_tx"`
	DeliverTx *abci.ResponseDeliverTx `json:"deliver_tx"`
	TxID      []byte                  `json:"tx_id"`
	Height    int                     `json:"height"`
}

type ResultTx struct {
	Height    uint64                 `json:"height"`
	Index     uint32                 `json:"index"`
	DeliverTx abci.ResponseDeliverTx `json:"deliver_tx"`
	Tx        types.Tx               `json:"tx"`
	Proof     types.TxProof          `json:"proof,omitempty"`
}

type ResultUnconfirmedTxs struct {
	N   int        `json:"n_txs"`
	Txs []types.Tx `json:"txs"`
}

type ResultABCIInfo struct {
	Response abci.ResponseInfo `json:"response"`
}

type ResultABCIQuery struct {
	Response abci.ResponseQuery `json:"response"`
}

type ResultUnsafeFlushMempool struct{}

type ResultUnsafeSetConfig struct{}

type ResultUnsafeProfile struct{}

type ResultSubscribe struct {
}

type ResultUnsubscribe struct {
}

type ResultEvent struct {
	Name string            `json:"name"`
	Data types.TMEventData `json:"data"`
}

//----------------------------------------
// response & result types

const (
	// 0x0 bytes are for the blockchain
	ResultTypeGenesis        = byte(0x01)
	ResultTypeBlockchainInfo = byte(0x02)
	ResultTypeBlock          = byte(0x03)
	ResultTypeCommit         = byte(0x04)

	// 0x2 bytes are for the network
	ResultTypeStatus    = byte(0x20)
	ResultTypeNetInfo   = byte(0x21)
	ResultTypeDialSeeds = byte(0x22)

	// 0x4 bytes are for the consensus
	ResultTypeValidators         = byte(0x40)
	ResultTypeDumpConsensusState = byte(0x41)

	// 0x6 bytes are for txs / the application
	ResultTypeBroadcastTx       = byte(0x60)
	ResultTypeUnconfirmedTxs    = byte(0x61)
	ResultTypeBroadcastTxCommit = byte(0x62)
	ResultTypeTx                = byte(0x63)

	// 0x7 bytes are for querying the application
	ResultTypeABCIQuery = byte(0x70)
	ResultTypeABCIInfo  = byte(0x71)

	// 0x8 bytes are for events
	ResultTypeSubscribe   = byte(0x80)
	ResultTypeUnsubscribe = byte(0x81)
	ResultTypeEvent       = byte(0x82)

	// 0xa bytes for testing
	ResultTypeUnsafeSetConfig        = byte(0xa0)
	ResultTypeUnsafeStartCPUProfiler = byte(0xa1)
	ResultTypeUnsafeStopCPUProfiler  = byte(0xa2)
	ResultTypeUnsafeWriteHeapProfile = byte(0xa3)
	ResultTypeUnsafeFlushMempool     = byte(0xa4)
)

type TMResult interface {
	rpctypes.Result
}

// for wire.readReflect
var _ = wire.RegisterInterface(
	struct{ TMResult }{},
	wire.ConcreteType{&ResultGenesis{}, ResultTypeGenesis},
	wire.ConcreteType{&ResultBlockchainInfo{}, ResultTypeBlockchainInfo},
	wire.ConcreteType{&ResultBlock{}, ResultTypeBlock},
	wire.ConcreteType{&ResultCommit{}, ResultTypeCommit},
	wire.ConcreteType{&ResultStatus{}, ResultTypeStatus},
	wire.ConcreteType{&ResultNetInfo{}, ResultTypeNetInfo},
	wire.ConcreteType{&ResultDialSeeds{}, ResultTypeDialSeeds},
	wire.ConcreteType{&ResultValidators{}, ResultTypeValidators},
	wire.ConcreteType{&ResultDumpConsensusState{}, ResultTypeDumpConsensusState},
	wire.ConcreteType{&ResultBroadcastTx{}, ResultTypeBroadcastTx},
	wire.ConcreteType{&ResultBroadcastTxCommit{}, ResultTypeBroadcastTxCommit},
	wire.ConcreteType{&ResultTx{}, ResultTypeTx},
	wire.ConcreteType{&ResultUnconfirmedTxs{}, ResultTypeUnconfirmedTxs},
	wire.ConcreteType{&ResultSubscribe{}, ResultTypeSubscribe},
	wire.ConcreteType{&ResultUnsubscribe{}, ResultTypeUnsubscribe},
	wire.ConcreteType{&ResultEvent{}, ResultTypeEvent},
	wire.ConcreteType{&ResultUnsafeSetConfig{}, ResultTypeUnsafeSetConfig},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeStartCPUProfiler},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeStopCPUProfiler},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeWriteHeapProfile},
	wire.ConcreteType{&ResultUnsafeFlushMempool{}, ResultTypeUnsafeFlushMempool},
	wire.ConcreteType{&ResultABCIQuery{}, ResultTypeABCIQuery},
	wire.ConcreteType{&ResultABCIInfo{}, ResultTypeABCIInfo},
)
<commit_msg>rpc/core/types: uintX -> int<commit_after>package core_types

import (
	abci "github.com/tendermint/abci/types"
	"github.com/tendermint/go-crypto"
	"github.com/tendermint/go-p2p"
	"github.com/tendermint/go-rpc/types"
	"github.com/tendermint/go-wire"
	"github.com/tendermint/tendermint/types"
)

type ResultBlockchainInfo struct {
	LastHeight int                `json:"last_height"`
	BlockMetas []*types.BlockMeta `json:"block_metas"`
}

type ResultGenesis struct {
	Genesis *types.GenesisDoc `json:"genesis"`
}

type ResultBlock struct {
	BlockMeta *types.BlockMeta `json:"block_meta"`
	Block     *types.Block     `json:"block"`
}

type ResultCommit struct {
	Header          *types.Header `json:"header"`
	Commit          *types.Commit `json:"commit"`
	CanonicalCommit bool          `json:"canonical"`
}

type ResultStatus struct {
	NodeInfo          *p2p.NodeInfo `json:"node_info"`
	PubKey            crypto.PubKey `json:"pub_key"`
	LatestBlockHash   []byte        `json:"latest_block_hash"`
	LatestAppHash     []byte        `json:"latest_app_hash"`
	LatestBlockHeight int           `json:"latest_block_height"`
	LatestBlockTime   int64         `json:"latest_block_time"` // nano
}

type ResultNetInfo struct {
	Listening bool     `json:"listening"`
	Listeners []string `json:"listeners"`
	Peers     []Peer   `json:"peers"`
}

type ResultDialSeeds struct {
}

type Peer struct {
	p2p.NodeInfo     `json:"node_info"`
	IsOutbound       bool                 `json:"is_outbound"`
	ConnectionStatus p2p.ConnectionStatus `json:"connection_status"`
}

type ResultValidators struct {
	BlockHeight int                `json:"block_height"`
	Validators  []*types.Validator `json:"validators"`
}

type ResultDumpConsensusState struct {
	RoundState      string   `json:"round_state"`
	PeerRoundStates []string `json:"peer_round_states"`
}

type ResultBroadcastTx struct {
	Code abci.CodeType `json:"code"`
	Data []byte        `json:"data"`
	Log  string        `json:"log"`

	TxID []byte `json:"tx_id"`
}

type ResultBroadcastTxCommit struct {
	CheckTx   *abci.ResponseCheckTx   `json:"check_tx"`
	DeliverTx *abci.ResponseDeliverTx `json:"deliver_tx"`
	TxID      []byte                  `json:"tx_id"`
	Height    int                     `json:"height"`
}

type ResultTx struct {
	Height    int                    `json:"height"`
	Index     int                    `json:"index"`
	DeliverTx abci.ResponseDeliverTx `json:"deliver_tx"`
	Tx        types.Tx               `json:"tx"`
	Proof     types.TxProof          `json:"proof,omitempty"`
}

type ResultUnconfirmedTxs struct {
	N   int        `json:"n_txs"`
	Txs []types.Tx `json:"txs"`
}

type ResultABCIInfo struct {
	Response abci.ResponseInfo `json:"response"`
}

type ResultABCIQuery struct {
	Response abci.ResponseQuery `json:"response"`
}

type ResultUnsafeFlushMempool struct{}

type ResultUnsafeSetConfig struct{}

type ResultUnsafeProfile struct{}

type ResultSubscribe struct {
}

type ResultUnsubscribe struct {
}

type ResultEvent struct {
	Name string            `json:"name"`
	Data types.TMEventData `json:"data"`
}

//----------------------------------------
// response & result types

const (
	// 0x0 bytes are for the blockchain
	ResultTypeGenesis        = byte(0x01)
	ResultTypeBlockchainInfo = byte(0x02)
	ResultTypeBlock          = byte(0x03)
	ResultTypeCommit         = byte(0x04)

	// 0x2 bytes are for the network
	ResultTypeStatus    = byte(0x20)
	ResultTypeNetInfo   = byte(0x21)
	ResultTypeDialSeeds = byte(0x22)

	// 0x4 bytes are for the consensus
	ResultTypeValidators         = byte(0x40)
	ResultTypeDumpConsensusState = byte(0x41)

	// 0x6 bytes are for txs / the application
	ResultTypeBroadcastTx       = byte(0x60)
	ResultTypeUnconfirmedTxs    = byte(0x61)
	ResultTypeBroadcastTxCommit = byte(0x62)
	ResultTypeTx                = byte(0x63)

	// 0x7 bytes are for querying the application
	ResultTypeABCIQuery = byte(0x70)
	ResultTypeABCIInfo  = byte(0x71)

	// 0x8 bytes are for events
	ResultTypeSubscribe   = byte(0x80)
	ResultTypeUnsubscribe = byte(0x81)
	ResultTypeEvent       = byte(0x82)

	// 0xa bytes for testing
	ResultTypeUnsafeSetConfig        = byte(0xa0)
	ResultTypeUnsafeStartCPUProfiler = byte(0xa1)
	ResultTypeUnsafeStopCPUProfiler  = byte(0xa2)
	ResultTypeUnsafeWriteHeapProfile = byte(0xa3)
	ResultTypeUnsafeFlushMempool     = byte(0xa4)
)

type TMResult interface {
	rpctypes.Result
}

// for wire.readReflect
var _ = wire.RegisterInterface(
	struct{ TMResult }{},
	wire.ConcreteType{&ResultGenesis{}, ResultTypeGenesis},
	wire.ConcreteType{&ResultBlockchainInfo{}, ResultTypeBlockchainInfo},
	wire.ConcreteType{&ResultBlock{}, ResultTypeBlock},
	wire.ConcreteType{&ResultCommit{}, ResultTypeCommit},
	wire.ConcreteType{&ResultStatus{}, ResultTypeStatus},
	wire.ConcreteType{&ResultNetInfo{}, ResultTypeNetInfo},
	wire.ConcreteType{&ResultDialSeeds{}, ResultTypeDialSeeds},
	wire.ConcreteType{&ResultValidators{}, ResultTypeValidators},
	wire.ConcreteType{&ResultDumpConsensusState{}, ResultTypeDumpConsensusState},
	wire.ConcreteType{&ResultBroadcastTx{}, ResultTypeBroadcastTx},
	wire.ConcreteType{&ResultBroadcastTxCommit{}, ResultTypeBroadcastTxCommit},
	wire.ConcreteType{&ResultTx{}, ResultTypeTx},
	wire.ConcreteType{&ResultUnconfirmedTxs{}, ResultTypeUnconfirmedTxs},
	wire.ConcreteType{&ResultSubscribe{}, ResultTypeSubscribe},
	wire.ConcreteType{&ResultUnsubscribe{}, ResultTypeUnsubscribe},
	wire.ConcreteType{&ResultEvent{}, ResultTypeEvent},
	wire.ConcreteType{&ResultUnsafeSetConfig{}, ResultTypeUnsafeSetConfig},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeStartCPUProfiler},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeStopCPUProfiler},
	wire.ConcreteType{&ResultUnsafeProfile{}, ResultTypeUnsafeWriteHeapProfile},
	wire.ConcreteType{&ResultUnsafeFlushMempool{}, ResultTypeUnsafeFlushMempool},
	wire.ConcreteType{&ResultABCIQuery{}, ResultTypeABCIQuery},
	wire.ConcreteType{&ResultABCIInfo{}, ResultTypeABCIInfo},
)
<|endoftext|>


<commit_before>/* Copyright 2017 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

    https://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.
*/

// Binary gnmi_target behaves as a gNMI Target.
package main

import (
	"flag"
	"net"

	"golang.org/x/net/context"

	log "github.com/golang/glog"
	"github.com/google/gnxi/credentials"
	"github.com/google/gnxi/target"
	"github.com/openconfig/gnmi/proto/gnmi"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/reflection"
)

var (
	bind = flag.String("bind_address", ":32123", "Bind to address:port or just :port.")
)

type subscriber struct {
	grpc.ServerStream
}

func (subs *subscriber) Send(m *gnmi.SubscribeResponse) error {
	return nil
}

func (subs *subscriber) Recv() (*gnmi.SubscribeRequest, error) {
	return nil, nil
}

type server struct{}

func (s *server) Capabilities(ctx context.Context, in *gnmi.CapabilityRequest) (*gnmi.CapabilityResponse, error) {
	log.Infoln("served Capabilities request")
	return nil, grpc.Errorf(codes.Unimplemented, "Capabilities() is not implemented.")
}

func (s *server) Get(ctx context.Context, in *gnmi.GetRequest) (*gnmi.GetResponse, error) {
	msg, ok := credentials.AuthorizeUser(ctx)
	if !ok {
		log.Infoln("denied a Get request,", msg)
		return nil, grpc.Errorf(codes.PermissionDenied, msg)
	}
	log.Infoln("served a Get request, ", msg)
	return target.ReflectGetRequest(in), nil
}

func (s *server) Set(ctx context.Context, in *gnmi.SetRequest) (*gnmi.SetResponse, error) {
	log.Infoln("served a Set request")
	return nil, grpc.Errorf(codes.Unimplemented, "Set() is not implemented.")
}

func (s *server) Subscribe(subs gnmi.GNMI_SubscribeServer) error {
	log.Infoln("served a Subscribe request")
	return grpc.Errorf(codes.Unimplemented, "Subscribe() is not implemented.")
}

func main() {
	flag.Parse()

	s := grpc.NewServer(credentials.ServerCredentials()...)

	gnmi.RegisterGNMIServer(s, &server{})
	reflection.Register(s)

	log.Infoln("starting to listen on", *bind)
	listen, err := net.Listen("tcp", *bind)
	if err != nil {
		log.Exitf("failed to listen: %v", err)
	}

	log.Infoln("starting to serve")
	if err := s.Serve(listen); err != nil {
		log.Exitf("failed to serve: %v", err)
	}
}
<commit_msg>add in-memory gnmi target for device config<commit_after>/* Copyright 2017 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

    https://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 gnmi_target implements an in-memory gnmi target for device config.
package main

// Typical usage:
// go run gnmi_target.go -bind :10161 \
//		-config openconfig-openflow.json \
//		-ca ca.pem -cert target_cert.pem -key target_key.pem \
//		-username foo -password bar

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"reflect"

	log "github.com/golang/glog"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/reflection"
	"google.golang.org/grpc/status"

	"github.com/google/gnxi/credentials"
	"github.com/google/gnxi/utils/target/gnmi/model_data"
	"github.com/google/gnxi/utils/target/gnmi/model_data/gostruct"
	"github.com/google/gnxi/utils/target/gnmi/server"

	pb "github.com/openconfig/gnmi/proto/gnmi"
)

type target struct {
	*server.Server
}

func new(model *server.Model, config []byte) (*target, error) {
	s, err := server.NewServer(model, config, nil)
	if err != nil {
		return nil, err
	}
	return &target{Server: s}, nil
}

// Get overrides the Get func of server.Server to provide user auth.
func (t *target) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse, error) {
	msg, ok := credentials.AuthorizeUser(ctx)
	if !ok {
		log.Infof("denied a Get request: %v", msg)
		return nil, status.Error(codes.PermissionDenied, msg)
	}
	log.Infof("allowed a Get request: %v", msg)
	return t.Server.Get(ctx, req)
}

// Set overrides the Set func of server.Server to provide user auth.
func (t *target) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse, error) {
	msg, ok := credentials.AuthorizeUser(ctx)
	if !ok {
		log.Infof("denied a Get request: %v", msg)
		return nil, status.Error(codes.PermissionDenied, msg)
	}
	log.Infof("allowed a Get request: %v", msg)
	return t.Server.Set(ctx, req)
}

var (
	bindAddr   = flag.String("bind", ":10161", "Bind to address:port or just :port.")
	configFile = flag.String("config", "", "IETF JSON file for target startup config")
)

func main() {
	model := server.NewModel(model_data.ModelData,
		reflect.TypeOf((*gostruct.Device)(nil)),
		gostruct.SchemaTree["Device"],
		gostruct.Unmarshal)

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Supported models:\n")
		for _, m := range model.SupportedModels() {
			fmt.Fprintf(os.Stderr, "  %s\n", m)
		}
		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	opts := credentials.ServerCredentials()
	g := grpc.NewServer(opts...)

	var configData []byte
	if *configFile != "" {
		var err error
		configData, err = ioutil.ReadFile(*configFile)
		if err != nil {
			log.Exitf("error in reading config file: %v", err)
		}
	}
	t, err := new(model, configData)
	if err != nil {
		log.Exitf("error in creating gnmi target: %v", err)
	}
	pb.RegisterGNMIServer(g, t)
	reflection.Register(g)

	log.Infof("starting to listen on", *bindAddr)
	listen, err := net.Listen("tcp", *bindAddr)
	if err != nil {
		log.Exitf("failed to listen: %v", err)
	}

	log.Info("starting to serve")
	if err := g.Serve(listen); err != nil {
		log.Exitf("failed to serve: %v", err)
	}
}
<|endoftext|>


<commit_before>package linux

func (k *LinuxKernel) Getuid32() int {
	return k.PosixKernel.Getuid()
}

func (k *LinuxKernel) Stat64() int {
	return 0
}
<commit_msg>add some -32 suffixed linux syscalls<commit_after>package linux

func (k *LinuxKernel) Getuid32() int {
	return k.PosixKernel.Getuid()
}

func (k *LinuxKernel) Getgid32() int {
	return k.PosixKernel.Getgid()
}

func (k *LinuxKernel) Setgid32(gid int32) int {
	return k.PosixKernel.Setgid(int(gid))
}

func (k *LinuxKernel) Setuid32(uid int32) int {
	return k.PosixKernel.Setuid(int(uid))
}

func (k *LinuxKernel) Stat64() int {
	return 0
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mysql

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"context"
)

type filePosFlavor struct {
	format     BinlogFormat
	file       string
	savedEvent BinlogEvent
}

// newFilePosFlavor creates a new filePos flavor.
func newFilePosFlavor() flavor {
	return &filePosFlavor{}
}

// masterGTIDSet is part of the Flavor interface.
func (flv *filePosFlavor) masterGTIDSet(c *Conn) (GTIDSet, error) {
	qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */)
	if err != nil {
		return nil, err
	}
	if len(qr.Rows) == 0 {
		return nil, errors.New("no master status")
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return nil, err
	}
	pos, err := strconv.Atoi(resultMap["Position"])
	if err != nil {
		return nil, fmt.Errorf("invalid FilePos GTID (%v): expecting pos to be an integer", resultMap["Position"])
	}

	return filePosGTID{
		file: resultMap["File"],
		pos:  pos,
	}, nil
}

func (flv *filePosFlavor) startReplicationCommand() string {
	return "unsupported"
}

func (flv *filePosFlavor) restartReplicationCommands() []string {
	return []string{"unsupported"}
}

func (flv *filePosFlavor) stopReplicationCommand() string {
	return "unsupported"
}

func (flv *filePosFlavor) stopIOThreadCommand() string {
	return "unsupported"
}

// sendBinlogDumpCommand is part of the Flavor interface.
func (flv *filePosFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, startPos Position) error {
	rpos, ok := startPos.GTIDSet.(filePosGTID)
	if !ok {
		return fmt.Errorf("startPos.GTIDSet is wrong type - expected filePosGTID, got: %#v", startPos.GTIDSet)
	}

	flv.file = rpos.file
	return c.WriteComBinlogDump(serverID, rpos.file, uint32(rpos.pos), 0)
}

// readBinlogEvent is part of the Flavor interface.
func (flv *filePosFlavor) readBinlogEvent(c *Conn) (BinlogEvent, error) {
	if ret := flv.savedEvent; ret != nil {
		flv.savedEvent = nil
		return ret, nil
	}

	for {
		result, err := c.ReadPacket()
		if err != nil {
			return nil, err
		}
		switch result[0] {
		case EOFPacket:
			return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", io.EOF)
		case ErrPacket:
			return nil, ParseErrorPacket(result)
		}

		event := &filePosBinlogEvent{binlogEvent: binlogEvent(result[1:])}
		switch event.Type() {
		case eGTIDEvent, eAnonymousGTIDEvent, ePreviousGTIDsEvent, eMariaGTIDListEvent:
			// Don't transmit fake or irrelevant events because we should not
			// resume replication at these positions.
			continue
		case eMariaGTIDEvent:
			// Copied from mariadb flavor.
			const FLStandalone = 1
			flags2 := result[8+4]
			// This means that it's also a BEGIN event.
			if flags2&FLStandalone == 0 {
				return newFilePosQueryEvent("begin", event.Timestamp()), nil
			}
			// Otherwise, don't send this event.
			continue
		case eFormatDescriptionEvent:
			format, err := event.Format()
			if err != nil {
				return nil, err
			}
			flv.format = format
		case eRotateEvent:
			if !flv.format.IsZero() {
				stripped, _, _ := event.StripChecksum(flv.format)
				_, flv.file = stripped.(*filePosBinlogEvent).rotate(flv.format)
				// No need to transmit. Just update the internal position for the next event.
				continue
			}
		case eXIDEvent, eTableMapEvent,
			eWriteRowsEventV0, eWriteRowsEventV1, eWriteRowsEventV2,
			eDeleteRowsEventV0, eDeleteRowsEventV1, eDeleteRowsEventV2,
			eUpdateRowsEventV0, eUpdateRowsEventV1, eUpdateRowsEventV2:
			flv.savedEvent = event
			return newFilePosGTIDEvent(flv.file, event.nextPosition(flv.format), event.Timestamp()), nil
		case eQueryEvent:
			q, err := event.Query(flv.format)
			if err == nil && strings.HasPrefix(q.SQL, "#") {
				continue
			}
			flv.savedEvent = event
			return newFilePosGTIDEvent(flv.file, event.nextPosition(flv.format), event.Timestamp()), nil
		default:
			// For unrecognized events, send a fake "repair" event so that
			// the position gets transmitted.
			if !flv.format.IsZero() {
				if v := event.nextPosition(flv.format); v != 0 {
					flv.savedEvent = newFilePosQueryEvent("repair", event.Timestamp())
					return newFilePosGTIDEvent(flv.file, v, event.Timestamp()), nil
				}
			}
		}
		return event, nil
	}
}

// resetReplicationCommands is part of the Flavor interface.
func (flv *filePosFlavor) resetReplicationCommands(c *Conn) []string {
	return []string{
		"unsupported",
	}
}

// setReplicationPositionCommands is part of the Flavor interface.
func (flv *filePosFlavor) setReplicationPositionCommands(pos Position) []string {
	return []string{
		"unsupported",
	}
}

// setReplicationPositionCommands is part of the Flavor interface.
func (flv *filePosFlavor) changeMasterArg() string {
	return "unsupported"
}

// status is part of the Flavor interface.
func (flv *filePosFlavor) status(c *Conn) (ReplicationStatus, error) {
	qr, err := c.ExecuteFetch("SHOW SLAVE STATUS", 100, true /* wantfields */)
	if err != nil {
		return ReplicationStatus{}, err
	}
	if len(qr.Rows) == 0 {
		// The query returned no data, meaning the server
		// is not configured as a replica.
		return ReplicationStatus{}, ErrNotReplica
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return ReplicationStatus{}, err
	}

	return parseFilePosReplicationStatus(resultMap)
}

func parseFilePosReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) {
	status := parseReplicationStatus(resultMap)

	status.Position = status.FilePosition
	status.RelayLogPosition = status.FileRelayLogPosition

	return status, nil
}

// masterStatus is part of the Flavor interface.
func (flv *filePosFlavor) masterStatus(c *Conn) (MasterStatus, error) {
	qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */)
	if err != nil {
		return MasterStatus{}, err
	}
	if len(qr.Rows) == 0 {
		// The query returned no data. We don't know how this could happen.
		return MasterStatus{}, ErrNoMasterStatus
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return MasterStatus{}, err
	}

	return parseFilePosMasterStatus(resultMap)
}

func parseFilePosMasterStatus(resultMap map[string]string) (MasterStatus, error) {
	status := parseMasterStatus(resultMap)

	status.Position = status.FilePosition

	return status, nil
}

// waitUntilPositionCommand is part of the Flavor interface.
func (flv *filePosFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) {
	filePosPos, ok := pos.GTIDSet.(filePosGTID)
	if !ok {
		return "", fmt.Errorf("Position is not filePos compatible: %#v", pos.GTIDSet)
	}

	if deadline, ok := ctx.Deadline(); ok {
		timeout := time.Until(deadline)
		if timeout <= 0 {
			return "", fmt.Errorf("timed out waiting for position %v", pos)
		}
		return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d, %.6f)", filePosPos.file, filePosPos.pos, timeout.Seconds()), nil
	}

	return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d)", filePosPos.file, filePosPos.pos), nil
}

func (*filePosFlavor) startReplicationUntilAfter(pos Position) string {
	return "unsupported"
}

// enableBinlogPlaybackCommand is part of the Flavor interface.
func (*filePosFlavor) enableBinlogPlaybackCommand() string {
	return ""
}

// disableBinlogPlaybackCommand is part of the Flavor interface.
func (*filePosFlavor) disableBinlogPlaybackCommand() string {
	return ""
}

// baseShowTablesWithSizes is part of the Flavor interface.
func (*filePosFlavor) baseShowTablesWithSizes() string {
	return ""
}
<commit_msg>add query for filepos flavor<commit_after>/*
Copyright 2019 The Vitess Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package mysql

import (
	"errors"
	"fmt"
	"io"
	"strconv"
	"strings"
	"time"

	"context"
)

type filePosFlavor struct {
	format     BinlogFormat
	file       string
	savedEvent BinlogEvent
}

// newFilePosFlavor creates a new filePos flavor.
func newFilePosFlavor() flavor {
	return &filePosFlavor{}
}

// masterGTIDSet is part of the Flavor interface.
func (flv *filePosFlavor) masterGTIDSet(c *Conn) (GTIDSet, error) {
	qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */)
	if err != nil {
		return nil, err
	}
	if len(qr.Rows) == 0 {
		return nil, errors.New("no master status")
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return nil, err
	}
	pos, err := strconv.Atoi(resultMap["Position"])
	if err != nil {
		return nil, fmt.Errorf("invalid FilePos GTID (%v): expecting pos to be an integer", resultMap["Position"])
	}

	return filePosGTID{
		file: resultMap["File"],
		pos:  pos,
	}, nil
}

func (flv *filePosFlavor) startReplicationCommand() string {
	return "unsupported"
}

func (flv *filePosFlavor) restartReplicationCommands() []string {
	return []string{"unsupported"}
}

func (flv *filePosFlavor) stopReplicationCommand() string {
	return "unsupported"
}

func (flv *filePosFlavor) stopIOThreadCommand() string {
	return "unsupported"
}

// sendBinlogDumpCommand is part of the Flavor interface.
func (flv *filePosFlavor) sendBinlogDumpCommand(c *Conn, serverID uint32, startPos Position) error {
	rpos, ok := startPos.GTIDSet.(filePosGTID)
	if !ok {
		return fmt.Errorf("startPos.GTIDSet is wrong type - expected filePosGTID, got: %#v", startPos.GTIDSet)
	}

	flv.file = rpos.file
	return c.WriteComBinlogDump(serverID, rpos.file, uint32(rpos.pos), 0)
}

// readBinlogEvent is part of the Flavor interface.
func (flv *filePosFlavor) readBinlogEvent(c *Conn) (BinlogEvent, error) {
	if ret := flv.savedEvent; ret != nil {
		flv.savedEvent = nil
		return ret, nil
	}

	for {
		result, err := c.ReadPacket()
		if err != nil {
			return nil, err
		}
		switch result[0] {
		case EOFPacket:
			return nil, NewSQLError(CRServerLost, SSUnknownSQLState, "%v", io.EOF)
		case ErrPacket:
			return nil, ParseErrorPacket(result)
		}

		event := &filePosBinlogEvent{binlogEvent: binlogEvent(result[1:])}
		switch event.Type() {
		case eGTIDEvent, eAnonymousGTIDEvent, ePreviousGTIDsEvent, eMariaGTIDListEvent:
			// Don't transmit fake or irrelevant events because we should not
			// resume replication at these positions.
			continue
		case eMariaGTIDEvent:
			// Copied from mariadb flavor.
			const FLStandalone = 1
			flags2 := result[8+4]
			// This means that it's also a BEGIN event.
			if flags2&FLStandalone == 0 {
				return newFilePosQueryEvent("begin", event.Timestamp()), nil
			}
			// Otherwise, don't send this event.
			continue
		case eFormatDescriptionEvent:
			format, err := event.Format()
			if err != nil {
				return nil, err
			}
			flv.format = format
		case eRotateEvent:
			if !flv.format.IsZero() {
				stripped, _, _ := event.StripChecksum(flv.format)
				_, flv.file = stripped.(*filePosBinlogEvent).rotate(flv.format)
				// No need to transmit. Just update the internal position for the next event.
				continue
			}
		case eXIDEvent, eTableMapEvent,
			eWriteRowsEventV0, eWriteRowsEventV1, eWriteRowsEventV2,
			eDeleteRowsEventV0, eDeleteRowsEventV1, eDeleteRowsEventV2,
			eUpdateRowsEventV0, eUpdateRowsEventV1, eUpdateRowsEventV2:
			flv.savedEvent = event
			return newFilePosGTIDEvent(flv.file, event.nextPosition(flv.format), event.Timestamp()), nil
		case eQueryEvent:
			q, err := event.Query(flv.format)
			if err == nil && strings.HasPrefix(q.SQL, "#") {
				continue
			}
			flv.savedEvent = event
			return newFilePosGTIDEvent(flv.file, event.nextPosition(flv.format), event.Timestamp()), nil
		default:
			// For unrecognized events, send a fake "repair" event so that
			// the position gets transmitted.
			if !flv.format.IsZero() {
				if v := event.nextPosition(flv.format); v != 0 {
					flv.savedEvent = newFilePosQueryEvent("repair", event.Timestamp())
					return newFilePosGTIDEvent(flv.file, v, event.Timestamp()), nil
				}
			}
		}
		return event, nil
	}
}

// resetReplicationCommands is part of the Flavor interface.
func (flv *filePosFlavor) resetReplicationCommands(c *Conn) []string {
	return []string{
		"unsupported",
	}
}

// setReplicationPositionCommands is part of the Flavor interface.
func (flv *filePosFlavor) setReplicationPositionCommands(pos Position) []string {
	return []string{
		"unsupported",
	}
}

// setReplicationPositionCommands is part of the Flavor interface.
func (flv *filePosFlavor) changeMasterArg() string {
	return "unsupported"
}

// status is part of the Flavor interface.
func (flv *filePosFlavor) status(c *Conn) (ReplicationStatus, error) {
	qr, err := c.ExecuteFetch("SHOW SLAVE STATUS", 100, true /* wantfields */)
	if err != nil {
		return ReplicationStatus{}, err
	}
	if len(qr.Rows) == 0 {
		// The query returned no data, meaning the server
		// is not configured as a replica.
		return ReplicationStatus{}, ErrNotReplica
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return ReplicationStatus{}, err
	}

	return parseFilePosReplicationStatus(resultMap)
}

func parseFilePosReplicationStatus(resultMap map[string]string) (ReplicationStatus, error) {
	status := parseReplicationStatus(resultMap)

	status.Position = status.FilePosition
	status.RelayLogPosition = status.FileRelayLogPosition

	return status, nil
}

// masterStatus is part of the Flavor interface.
func (flv *filePosFlavor) masterStatus(c *Conn) (MasterStatus, error) {
	qr, err := c.ExecuteFetch("SHOW MASTER STATUS", 100, true /* wantfields */)
	if err != nil {
		return MasterStatus{}, err
	}
	if len(qr.Rows) == 0 {
		// The query returned no data. We don't know how this could happen.
		return MasterStatus{}, ErrNoMasterStatus
	}

	resultMap, err := resultToMap(qr)
	if err != nil {
		return MasterStatus{}, err
	}

	return parseFilePosMasterStatus(resultMap)
}

func parseFilePosMasterStatus(resultMap map[string]string) (MasterStatus, error) {
	status := parseMasterStatus(resultMap)

	status.Position = status.FilePosition

	return status, nil
}

// waitUntilPositionCommand is part of the Flavor interface.
func (flv *filePosFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) {
	filePosPos, ok := pos.GTIDSet.(filePosGTID)
	if !ok {
		return "", fmt.Errorf("Position is not filePos compatible: %#v", pos.GTIDSet)
	}

	if deadline, ok := ctx.Deadline(); ok {
		timeout := time.Until(deadline)
		if timeout <= 0 {
			return "", fmt.Errorf("timed out waiting for position %v", pos)
		}
		return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d, %.6f)", filePosPos.file, filePosPos.pos, timeout.Seconds()), nil
	}

	return fmt.Sprintf("SELECT MASTER_POS_WAIT('%s', %d)", filePosPos.file, filePosPos.pos), nil
}

func (*filePosFlavor) startReplicationUntilAfter(pos Position) string {
	return "unsupported"
}

// enableBinlogPlaybackCommand is part of the Flavor interface.
func (*filePosFlavor) enableBinlogPlaybackCommand() string {
	return ""
}

// disableBinlogPlaybackCommand is part of the Flavor interface.
func (*filePosFlavor) disableBinlogPlaybackCommand() string {
	return ""
}

// baseShowTablesWithSizes is part of the Flavor interface.
func (*filePosFlavor) baseShowTablesWithSizes() string {
	return TablesWithSize57
}
<|endoftext|>


<commit_before>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package test

import (
	"strings"
	"testing"

	"github.com/youtube/vitess/go/vt/topo"
	"golang.org/x/net/context"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// CheckVSchema runs the tests on the VSchema part of the API
func CheckVSchema(ctx context.Context, t *testing.T, ts topo.Impl) {
	if err := ts.CreateKeyspace(ctx, "test_keyspace", &topodatapb.Keyspace{}); err != nil {
		t.Fatalf("CreateKeyspace: %v", err)
	}

	shard := &topodatapb.Shard{
		KeyRange: newKeyRange("b0-c0"),
	}
	if err := ts.CreateShard(ctx, "test_keyspace", "b0-c0", shard); err != nil {
		t.Fatalf("CreateShard: %v", err)
	}

	got, err := ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want := "{}"
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", `{ "Sharded": true }`)
	if err != nil {
		t.Error(err)
	}

	got, err = ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want = `{ "Sharded": true }`
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", `{ "Sharded": false }`)
	if err != nil {
		t.Error(err)
	}

	got, err = ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want = `{ "Sharded": false }`
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", "invalid")
	want = "Unmarshal failed:"
	if err == nil || !strings.HasPrefix(err.Error(), want) {
		t.Errorf("SaveVSchema: %v, must start with %s", err, want)
	}

	// test GetShardNames
	shards, err := ts.GetShardNames(ctx, "test_keyspace")
	if err != nil {
		t.Errorf("GetShardNames: %v", err)
	}
	if len(shards) != 1 || shards[0] != "b0-c0" {
		t.Errorf(`GetShardNames: want [ "b0-c0" ], got %v`, shards)
	}
}
<commit_msg>v3: comment fix<commit_after>// Copyright 2015, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package test

import (
	"strings"
	"testing"

	"github.com/youtube/vitess/go/vt/topo"
	"golang.org/x/net/context"

	topodatapb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// CheckVSchema runs the tests on the VSchema part of the API
func CheckVSchema(ctx context.Context, t *testing.T, ts topo.Impl) {
	if err := ts.CreateKeyspace(ctx, "test_keyspace", &topodatapb.Keyspace{}); err != nil {
		t.Fatalf("CreateKeyspace: %v", err)
	}

	shard := &topodatapb.Shard{
		KeyRange: newKeyRange("b0-c0"),
	}
	if err := ts.CreateShard(ctx, "test_keyspace", "b0-c0", shard); err != nil {
		t.Fatalf("CreateShard: %v", err)
	}

	got, err := ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want := "{}"
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", `{ "Sharded": true }`)
	if err != nil {
		t.Error(err)
	}

	got, err = ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want = `{ "Sharded": true }`
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", `{ "Sharded": false }`)
	if err != nil {
		t.Error(err)
	}

	got, err = ts.GetVSchema(ctx, "test_keyspace")
	if err != nil {
		t.Error(err)
	}
	want = `{ "Sharded": false }`
	if got != want {
		t.Errorf("GetVSchema: %s, want %s", got, want)
	}

	err = ts.SaveVSchema(ctx, "test_keyspace", "invalid")
	want = "Unmarshal failed:"
	if err == nil || !strings.HasPrefix(err.Error(), want) {
		t.Errorf("SaveVSchema: %v, must start with %s", err, want)
	}

	// Make sure the vschema is not returned as a shard name,
	// because they share the same directory location.
	shards, err := ts.GetShardNames(ctx, "test_keyspace")
	if err != nil {
		t.Errorf("GetShardNames: %v", err)
	}
	if len(shards) != 1 || shards[0] != "b0-c0" {
		t.Errorf(`GetShardNames: want [ "b0-c0" ], got %v`, shards)
	}
}
<|endoftext|>


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

// Package redirect provides hooks to register HTTP handlers that redirect old
// godoc paths to their new equivalents and assist in accessing the issue
// tracker, wiki, code review system, etc.
package redirect

import (
	"net/http"
	"regexp"
)

// Register registers HTTP handlers that redirect old godoc paths to their new
// equivalents and assist in accessing the issue tracker, wiki, code review
// system, etc. If mux is nil it uses http.DefaultServeMux.
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	handlePathRedirects(mux, pkgRedirects, "/pkg/")
	handlePathRedirects(mux, cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		mux.Handle(p, PrefixHandler(p, redirect))
	}
	for path, redirect := range redirects {
		mux.Handle(path, Handler(redirect))
	}
}

func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
	for source, target := range redirects {
		h := Handler(prefix + target + "/")
		p := prefix + source
		mux.Handle(p, h)
		mux.Handle(p+"/", h)
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"gotest":    "go",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":       "/blog/",
	"/build":      "http://build.golang.org",
	"/change":     "https://code.google.com/p/go/source/list",
	"/cl":         "https://gocodereview.appspot.com/",
	"/cmd/godoc/": "http://godoc.org/code.google.com/p/go.tools/cmd/godoc/",
	"/cmd/vet/":   "http://godoc.org/code.google.com/p/go.tools/cmd/vet/",
	"/issue":      "https://code.google.com/p/go/issues",
	"/issue/new":  "https://code.google.com/p/go/issues/entry",
	"/issues":     "https://code.google.com/p/go/issues",
	"/play":       "http://play.golang.org",

	// THESE DO NOT WORK FOR GO 1.1 SITES SUCH AS golang.org.
	// DO NOT RE-ENABLE.
	// "/ref":        "/doc/#references",
	// "/ref/":       "/doc/#references",
	// "/ref/mem":    "/doc/mem",
	// "/ref/spec":   "/doc/spec",

	// In fact, becuase golang.org pulls some pages from tip, there
	// are already links on the main golang.org page pointing at
	// the non-existent /doc/spec etc URLs. So redirect the other way.
	"/doc/mem":  "/ref/mem",
	"/doc/spec": "/ref/spec",

	"/talks": "http://talks.golang.org",
	"/tour":  "http://tour.golang.org",
	"/wiki":  "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func Handler(target string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	})
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func PrefixHandler(prefix, baseURL string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	})
}
<commit_msg>go.tools/godoc: reverse reversed redirects<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package redirect provides hooks to register HTTP handlers that redirect old
// godoc paths to their new equivalents and assist in accessing the issue
// tracker, wiki, code review system, etc.
package redirect

import (
	"net/http"
	"regexp"
)

// Register registers HTTP handlers that redirect old godoc paths to their new
// equivalents and assist in accessing the issue tracker, wiki, code review
// system, etc. If mux is nil it uses http.DefaultServeMux.
func Register(mux *http.ServeMux) {
	if mux == nil {
		mux = http.DefaultServeMux
	}
	handlePathRedirects(mux, pkgRedirects, "/pkg/")
	handlePathRedirects(mux, cmdRedirects, "/cmd/")
	for prefix, redirect := range prefixHelpers {
		p := "/" + prefix + "/"
		mux.Handle(p, PrefixHandler(p, redirect))
	}
	for path, redirect := range redirects {
		mux.Handle(path, Handler(redirect))
	}
}

func handlePathRedirects(mux *http.ServeMux, redirects map[string]string, prefix string) {
	for source, target := range redirects {
		h := Handler(prefix + target + "/")
		p := prefix + source
		mux.Handle(p, h)
		mux.Handle(p+"/", h)
	}
}

// Packages that were renamed between r60 and go1.
var pkgRedirects = map[string]string{
	"asn1":              "encoding/asn1",
	"big":               "math/big",
	"cmath":             "math/cmplx",
	"csv":               "encoding/csv",
	"exec":              "os/exec",
	"exp/template/html": "html/template",
	"gob":               "encoding/gob",
	"http":              "net/http",
	"http/cgi":          "net/http/cgi",
	"http/fcgi":         "net/http/fcgi",
	"http/httptest":     "net/http/httptest",
	"http/pprof":        "net/http/pprof",
	"json":              "encoding/json",
	"mail":              "net/mail",
	"rand":              "math/rand",
	"rpc":               "net/rpc",
	"rpc/jsonrpc":       "net/rpc/jsonrpc",
	"scanner":           "text/scanner",
	"smtp":              "net/smtp",
	"tabwriter":         "text/tabwriter",
	"template":          "text/template",
	"template/parse":    "text/template/parse",
	"url":               "net/url",
	"utf16":             "unicode/utf16",
	"utf8":              "unicode/utf8",
	"xml":               "encoding/xml",
}

// Commands that were renamed between r60 and go1.
var cmdRedirects = map[string]string{
	"gofix":     "fix",
	"goinstall": "go",
	"gopack":    "pack",
	"gotest":    "go",
	"govet":     "vet",
	"goyacc":    "yacc",
}

var redirects = map[string]string{
	"/blog":       "/blog/",
	"/build":      "http://build.golang.org",
	"/change":     "https://code.google.com/p/go/source/list",
	"/cl":         "https://gocodereview.appspot.com/",
	"/cmd/godoc/": "http://godoc.org/code.google.com/p/go.tools/cmd/godoc/",
	"/cmd/vet/":   "http://godoc.org/code.google.com/p/go.tools/cmd/vet/",
	"/issue":      "https://code.google.com/p/go/issues",
	"/issue/new":  "https://code.google.com/p/go/issues/entry",
	"/issues":     "https://code.google.com/p/go/issues",
	"/play":       "http://play.golang.org",

	// THESE DO NOT WORK FOR GO 1.1 SITES SUCH AS golang.org.
	// DO NOT RE-ENABLE.
	// "/ref":        "/doc/#references",
	// "/ref/":       "/doc/#references",
	// "/ref/mem":    "/doc/mem",
	// "/ref/spec":   "/doc/spec",

	// In fact, because golang.org pulls some pages from tip, there
	// are already links on the main golang.org page pointing at
	// the non-existent /ref/spec etc URLs. So redirect the other way.
	"/ref/mem":  "/doc/mem",
	"/ref/spec": "/doc/spec",

	"/talks": "http://talks.golang.org",
	"/tour":  "http://tour.golang.org",
	"/wiki":  "https://code.google.com/p/go-wiki/w/list",

	"/doc/articles/c_go_cgo.html":                    "/blog/c-go-cgo",
	"/doc/articles/concurrency_patterns.html":        "/blog/go-concurrency-patterns-timing-out-and",
	"/doc/articles/defer_panic_recover.html":         "/blog/defer-panic-and-recover",
	"/doc/articles/error_handling.html":              "/blog/error-handling-and-go",
	"/doc/articles/gobs_of_data.html":                "/blog/gobs-of-data",
	"/doc/articles/godoc_documenting_go_code.html":   "/blog/godoc-documenting-go-code",
	"/doc/articles/gos_declaration_syntax.html":      "/blog/gos-declaration-syntax",
	"/doc/articles/image_draw.html":                  "/blog/go-imagedraw-package",
	"/doc/articles/image_package.html":               "/blog/go-image-package",
	"/doc/articles/json_and_go.html":                 "/blog/json-and-go",
	"/doc/articles/json_rpc_tale_of_interfaces.html": "/blog/json-rpc-tale-of-interfaces",
	"/doc/articles/laws_of_reflection.html":          "/blog/laws-of-reflection",
	"/doc/articles/race_detector.html":               "/blog/race-detector",
	"/doc/articles/slices_usage_and_internals.html":  "/blog/go-slices-usage-and-internals",
	"/doc/go_for_cpp_programmers.html":               "https://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers",
	"/doc/go_tutorial.html":                          "http://tour.golang.org/",
}

var prefixHelpers = map[string]string{
	"change": "https://code.google.com/p/go/source/detail?r=",
	"cl":     "https://codereview.appspot.com/",
	"issue":  "https://code.google.com/p/go/issues/detail?id=",
	"play":   "http://play.golang.org/",
	"talks":  "http://talks.golang.org/",
	"wiki":   "https://code.google.com/p/go-wiki/wiki/",
}

func Handler(target string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, target, http.StatusMovedPermanently)
	})
}

var validId = regexp.MustCompile(`^[A-Za-z0-9-]*$`)

func PrefixHandler(prefix, baseURL string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if p := r.URL.Path; p == prefix {
			// redirect /prefix/ to /prefix
			http.Redirect(w, r, p[:len(p)-1], http.StatusFound)
			return
		}
		id := r.URL.Path[len(prefix):]
		if !validId.MatchString(id) {
			http.Error(w, "Not found", http.StatusNotFound)
			return
		}
		target := baseURL + id
		http.Redirect(w, r, target, http.StatusFound)
	})
}
<|endoftext|>


<commit_before>package detector

import (
	"bytes"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"

	"qiniupkg.com/x/log.v7"

	"gopkg.in/mgo.v2/bson"
	"gopkg.in/robfig/cron.v2"
)

// TaskArgs is a task query struct
type TaskArgs struct {
	ID       string        `json:"id,omitempty"`
	Name     string        `json:"name,omitempty"`
	URL      string        `json:"url,omitempty"`
	Protocol string        `json:"protocol,omitempty"`
	Interval time.Duration `json:"interval,omitempty"`
	Creator  string        `json:"creator,omitempty"`
}

// Task Cron
type Task struct {
	// Task options
	ID          bson.ObjectId `bson:"_id,omitempty"         json:"id"`
	Name        string        `bson:"name,omitempty"        json:"name"`
	Description string        `bson:"description,omitempty" json:"description"`
	Creator     string        `bson:"creator,omitempty"     json:"creator"`
	CreatedAt   time.Time     `bson:"created_at"            json:"created_at"`
	UpdatedAt   time.Time     `bson:"updated_at"            json:"updated_at"`
	Interval    time.Duration `bson:"interval,omitempty"    json:"interval"`
	Enabled     bool          `bson:"enabled,omitempty"     json:"enabled"`
	Status      string        `bson:"status,omitempty"      json:"status"`

	// HTTP Request args
	URL         string                 `bson:"url,omitempty"          json:"url"`
	Protocol    string                 `bson:"protocol,omitempty"     json:"protocol"`
	Method      string                 `bson:"method,omitempty"       json:"method"`
	ContentType string                 `bson:"content_type,omitempty" json:"content_type"`
	UserAgent   string                 `bson:"user_agent,omitempty"   json:"user_agent"`
	Username    string                 `bson:"username,omitempty"     json:"username"`
	Password    string                 `bson:"password,omitempty"     json:"password"`
	Body        map[string]interface{} `bson:"body,omitempty"         json:"body"`
	BodyForm    map[string][]string    `bson:"body_form,omitempty"    json:"body_form"`

	// HTTP Response results
	LastStatusCode int           `bson:"last_status,omitempty"  json:"last_status"`
	TimeLatency    time.Duration `bson:"time_latency,omitempty" json:"time_latency"`

	// Job Info
	Job Job `json:"job"`
}

// Job cron exec
type Job struct {
	ID      cron.EntryID `json:"id"`
	status  uint32
	Status  string        `json:"status"`
	Latency time.Duration `json:"latency"`
	running sync.Mutex

	Next time.Time `json:"next"`
	Prev time.Time `json:"prev"`
}

// JobStatusUpdate Update task cron job status
func (t *Task) JobStatusUpdate() string {
	if atomic.LoadUint32(&t.Job.status) > 0 {
		t.Job.Status = "RUNNING"
	} else {
		t.Job.Status = "IDLE"
	}

	entry := MainCron.Entry(t.Job.ID)
	t.Job.Prev = entry.Prev
	t.Job.Next = entry.Next

	return t.Job.Status
}

// Run auto trigger in cron
func (t *Task) Run() {
	start := time.Now()

	// If the job panics, just print a stack trace.
	// Don't let the whole process die.
	defer func() {
		if err := recover(); err != nil {
			var buf bytes.Buffer
			logger := log.New(&buf, "Runner Log: ", log.Lshortfile)
			logger.Panic(err, "\n", string(debug.Stack()))
		}
	}()

	if !selfConcurrent {
		t.Job.running.Lock()
		defer t.Job.running.Unlock()
	}

	if workPermits != nil {
		workPermits <- struct{}{}
		defer func() { <-workPermits }()
	}

	atomic.StoreUint32(&t.Job.status, 1)
	t.JobStatusUpdate()

	defer atomic.StoreUint32(&t.Job.status, 0)
	defer t.JobStatusUpdate()

	// TODO

	t.Job.Latency = time.Since(start)
}

// Start task
func (t *Task) Start() {
	entry := MainCron.Entry(t.Job.ID)
	if entry.ID == 0 && t.Interval > 0 {
		t.Job.ID = MainCron.Schedule(cron.Every(t.Interval), t)
	}
	t.Job.Next = entry.Next
	t.Job.Prev = entry.Prev
}

// Stop task
func (t *Task) Stop() {
	if t.Job.ID > 0 {
		MainCron.Remove(t.Job.ID)
		t.Job.ID = 0
	}
}
<commit_msg>Update task struct<commit_after>package detector

import (
	"bytes"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"

	"qiniupkg.com/x/log.v7"

	"gopkg.in/mgo.v2/bson"
	"gopkg.in/robfig/cron.v2"
)

// TaskArgs is a task query struct
type TaskArgs struct {
	ID       string        `json:"id,omitempty"`
	Name     string        `json:"name,omitempty"`
	URL      string        `json:"url,omitempty"`
	Protocol string        `json:"protocol,omitempty"`
	Interval time.Duration `json:"interval,omitempty"`
	Creator  string        `json:"creator,omitempty"`
}

// Task Cron
type Task struct {
	// Task options
	ID          bson.ObjectId `bson:"_id,omitempty"         json:"id"`
	Name        string        `bson:"name,omitempty"        json:"name"`
	Description string        `bson:"description,omitempty" json:"description"`
	Creator     string        `bson:"creator,omitempty"     json:"creator"`
	CreatedAt   time.Time     `bson:"created_at"            json:"created_at"`
	UpdatedAt   time.Time     `bson:"updated_at"            json:"updated_at"`
	Interval    time.Duration `bson:"interval,omitempty"    json:"interval"`
	Enabled     bool          `bson:"enabled,omitempty"     json:"enabled"`
	Status      string        `bson:"status,omitempty"      json:"status"`

	// HTTP Request args
	URL         string                 `bson:"url,omitempty"          json:"url"`
	Protocol    string                 `bson:"protocol,omitempty"     json:"protocol"`
	Method      string                 `bson:"method,omitempty"       json:"method"`
	ContentType string                 `bson:"content_type,omitempty" json:"content_type"`
	UserAgent   string                 `bson:"user_agent,omitempty"   json:"user_agent"`
	Username    string                 `bson:"username,omitempty"     json:"username"`
	Password    string                 `bson:"password,omitempty"     json:"password"`
	BodyJSON    map[string]interface{} `bson:"body_json,omitempty"    json:"body_json"`
	BodyForm    map[string]string      `bson:"body_form,omitempty"    json:"body_form"`
	BodyRaw     string                 `bson:"body_raw,omitempty"     json:"body_raw"`

	// HTTP Response results
	LastStatusCode int           `bson:"last_status,omitempty"  json:"last_status"`
	TimeLatency    time.Duration `bson:"time_latency,omitempty" json:"time_latency"`

	// Job Info
	Job Job `json:"job"`
}

// Job cron exec
type Job struct {
	ID      cron.EntryID `json:"id"`
	status  uint32
	Status  string        `json:"status"`
	Latency time.Duration `json:"latency"`
	running sync.Mutex

	Next time.Time `json:"next"`
	Prev time.Time `json:"prev"`
}

// JobStatusUpdate Update task cron job status
func (t *Task) JobStatusUpdate() string {
	if atomic.LoadUint32(&t.Job.status) > 0 {
		t.Job.Status = "RUNNING"
	} else {
		t.Job.Status = "IDLE"
	}

	entry := MainCron.Entry(t.Job.ID)
	t.Job.Prev = entry.Prev
	t.Job.Next = entry.Next

	return t.Job.Status
}

// Run auto trigger in cron
func (t *Task) Run() {
	start := time.Now()

	// If the job panics, just print a stack trace.
	// Don't let the whole process die.
	defer func() {
		if err := recover(); err != nil {
			var buf bytes.Buffer
			logger := log.New(&buf, "Runner Log: ", log.Lshortfile)
			logger.Panic(err, "\n", string(debug.Stack()))
		}
	}()

	if !selfConcurrent {
		t.Job.running.Lock()
		defer t.Job.running.Unlock()
	}

	if workPermits != nil {
		workPermits <- struct{}{}
		defer func() { <-workPermits }()
	}

	atomic.StoreUint32(&t.Job.status, 1)
	t.JobStatusUpdate()

	defer atomic.StoreUint32(&t.Job.status, 0)
	defer t.JobStatusUpdate()

	// TODO

	t.Job.Latency = time.Since(start)
}

// Start task
func (t *Task) Start() {
	entry := MainCron.Entry(t.Job.ID)
	if entry.ID == 0 && t.Interval > 0 {
		t.Job.ID = MainCron.Schedule(cron.Every(t.Interval), t)
	}
	t.Job.Next = entry.Next
	t.Job.Prev = entry.Prev
}

// Stop task
func (t *Task) Stop() {
	if t.Job.ID > 0 {
		MainCron.Remove(t.Job.ID)
		t.Job.ID = 0
	}
}
<|endoftext|>