<commit_before>package core

import (
	"log"

	"github.com/nikhan/go-fetch"
)

// NewBlock creates a new block from a spec
func NewBlock(s Spec) *Block {
	var in []Route
	var out []Output

	for _, v := range s.Inputs {

		q, _ := fetch.Parse(".")
		in = append(in, Route{
			Name: v.Name,
			Path: q,
			C:    make(chan Message),
		})
	}

	for _, v := range s.Outputs {
		out = append(out, Output{
			Name:        v.Name,
			Connections: make(map[Connection]struct{}),
		})
	}

	return &Block{
		state: BlockState{
			make(MessageMap),
			make(MessageMap),
			make(Manifest),
			false,
		},
		routing: BlockRouting{
			Inputs:        in,
			Outputs:       out,
			InterruptChan: make(chan Interrupt),
			Shared: SharedStore{
				Type: s.Shared,
			},
		},
		kernel: s.Kernel,
	}
}

// suture: the main routine the block runs
func (b *Block) Serve() {
	for {
		var interrupt Interrupt

		b.routing.RLock()
		for {
			interrupt = b.receive()
			if interrupt != nil {
				break
			}

			interrupt = b.process()
			if interrupt != nil {
				break
			}

			interrupt = b.broadcast()
			if interrupt != nil {
				break
			}

			b.crank()
		}
		b.routing.RUnlock()
		b.routing.Lock()
		if ok := interrupt(); !ok {
			return
		}
		b.routing.Unlock()
	}
}

// todo: proper getter/setters of route properties
// 	GetRouteValue, GetRoutePath, GetRouteChan

// Input returns the specfied Route
func (b *Block) Input(id RouteID) Route {
	b.routing.RLock()
	defer b.routing.RUnlock()
	return b.routing.Inputs[id]
}

// Outputs return a list of manifest pairs for the block
func (b *Block) Outputs() []ManifestPair {
	var m []ManifestPair
	b.routing.RLock()
	for id, out := range b.routing.Outputs {
		for c, _ := range out.Connections {
			m = append(m, ManifestPair{id, c})
		}
	}
	b.routing.RUnlock()
	return m
}

// sets a store for the block. can be set to nil
func (b *Block) Store(s Store) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Shared.Store = s
		return true
	}
}

// RouteValue sets the route to always be the specified value
func (b *Block) RouteValue(id RouteID, v Message) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Inputs[id].Value = &v
		return true
	}
}

// RoutePath sets a Route's Path to the supplied go-fetch Query
func (b *Block) RoutePath(id RouteID, p *fetch.Query) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Inputs[id].Path = p
		b.routing.Inputs[id].Value = nil
		return true
	}
}

// Connect connects a Route, specified by ID, to a connection
func (b *Block) Connect(id RouteID, c Connection) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Outputs[id].Connections[c] = struct{}{}
		return true
	}
}

// Disconnect removes a connection from a Route
func (b *Block) Disconnect(id RouteID, c Connection) {
	b.routing.InterruptChan <- func() bool {
		delete(b.routing.Outputs[id].Connections, c)
		return true
	}
}

// suture: stop the block
func (b *Block) Stop() {
	b.routing.InterruptChan <- func() bool {
		return false
	}
}

// wait and listen for all kernel inputs to be filled.
func (b *Block) receive() Interrupt {
	var err error
	for id, input := range b.routing.Inputs {
		//if we have already received a value on this input, skip.
		if _, ok := b.state.inputValues[RouteID(id)]; ok {
			continue
		}

		// if there is a value set for this input, place value on
		// buffer and set it in map.
		if input.Value != nil {
			b.state.inputValues[RouteID(id)] = *input.Value
			continue
		}

		select {
		case m := <-input.C:
			b.state.inputValues[RouteID(id)], err = fetch.Run(input.Path, m)
			if err != nil {
				log.Fatal(err)
			}
		case f := <-b.routing.InterruptChan:
			return f
		}
	}
	return nil
}

// run kernel on inputs, produce outputs
func (b *Block) process() Interrupt {
	if b.state.Processed == true {
		return nil
	}

	// if this kernel relies on an external shared state then we need to
	// block until an interrupt connects us to a shared external state.
	if b.routing.Shared.Type != NONE && b.routing.Shared.Store == nil {
		select {
		case f := <-b.routing.InterruptChan:
			return f
		}
	}

	// we should only be able to get here if
	// - we don't need an shared state
	// - we have an external shared state and it has been attached
	if b.routing.Shared.Type != NONE {
		b.routing.Shared.Store.Lock()
	}

	// run the kernel
	interrupt := b.kernel(b.state.inputValues,
		b.state.outputValues,
		b.routing.Shared.Store,
		b.routing.InterruptChan)

	if interrupt != nil {
		if b.routing.Shared.Type != NONE {
			b.routing.Shared.Store.Unlock()
		}
		return interrupt
	}

	if b.routing.Shared.Type != NONE {
		b.routing.Shared.Store.Unlock()
	}

	b.state.Processed = true

	return nil
}

// broadcast the kernel output to all connections on all outputs.
func (b *Block) broadcast() Interrupt {
	for id, out := range b.routing.Outputs {
		// if there no connection for this output then wait until there
		// is one. that means we have to wait for an interrupt.
		if len(out.Connections) == 0 {
			select {
			case f := <-b.routing.InterruptChan:
				return f
			}
		}
		for c, _ := range out.Connections {
			// check to see if we have delivered a message to this
			// connection for this block crank. if we have, then
			// skip this delivery.
			m := ManifestPair{id, c}
			if _, ok := b.state.manifest[m]; ok {
				continue
			}

			select {
			case c <- b.state.outputValues[RouteID(id)]:
				// set that we have delivered the message.
				b.state.manifest[m] = struct{}{}
			case f := <-b.routing.InterruptChan:
				return f
			}
		}

	}
	return nil
}

// cleanup all block state for this crank of the block
func (b *Block) crank() {
	for k, _ := range b.state.inputValues {
		delete(b.state.inputValues, k)
	}
	for k, _ := range b.state.outputValues {
		delete(b.state.outputValues, k)
	}
	for k, _ := range b.state.manifest {
		delete(b.state.manifest, k)
	}
	b.state.Processed = false
}
<commit_msg>removing defer from Input<commit_after>package core

import (
	"log"

	"github.com/nikhan/go-fetch"
)

// NewBlock creates a new block from a spec
func NewBlock(s Spec) *Block {
	var in []Route
	var out []Output

	for _, v := range s.Inputs {

		q, _ := fetch.Parse(".")
		in = append(in, Route{
			Name: v.Name,
			Path: q,
			C:    make(chan Message),
		})
	}

	for _, v := range s.Outputs {
		out = append(out, Output{
			Name:        v.Name,
			Connections: make(map[Connection]struct{}),
		})
	}

	return &Block{
		state: BlockState{
			make(MessageMap),
			make(MessageMap),
			make(Manifest),
			false,
		},
		routing: BlockRouting{
			Inputs:        in,
			Outputs:       out,
			InterruptChan: make(chan Interrupt),
			Shared: SharedStore{
				Type: s.Shared,
			},
		},
		kernel: s.Kernel,
	}
}

// suture: the main routine the block runs
func (b *Block) Serve() {
	for {
		var interrupt Interrupt

		b.routing.RLock()
		for {
			interrupt = b.receive()
			if interrupt != nil {
				break
			}

			interrupt = b.process()
			if interrupt != nil {
				break
			}

			interrupt = b.broadcast()
			if interrupt != nil {
				break
			}

			b.crank()
		}
		b.routing.RUnlock()
		b.routing.Lock()
		if ok := interrupt(); !ok {
			return
		}
		b.routing.Unlock()
	}
}

// todo: proper getter/setters of route properties
// 	GetRouteValue, GetRoutePath, GetRouteChan

// Input returns the specfied Route
func (b *Block) Input(id RouteID) Route {
	b.routing.RLock()
	// not entirely sure about this
	// may need a more thorough copy in the future (?)
	r := b.routing.Inputs[id]
	b.routing.RUnlock()
	return r
}

// Outputs return a list of manifest pairs for the block
func (b *Block) Outputs() []ManifestPair {
	var m []ManifestPair
	b.routing.RLock()
	for id, out := range b.routing.Outputs {
		for c, _ := range out.Connections {
			m = append(m, ManifestPair{id, c})
		}
	}
	b.routing.RUnlock()
	return m
}

// sets a store for the block. can be set to nil
func (b *Block) Store(s Store) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Shared.Store = s
		return true
	}
}

// RouteValue sets the route to always be the specified value
func (b *Block) RouteValue(id RouteID, v Message) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Inputs[id].Value = &v
		return true
	}
}

// RoutePath sets a Route's Path to the supplied go-fetch Query
func (b *Block) RoutePath(id RouteID, p *fetch.Query) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Inputs[id].Path = p
		b.routing.Inputs[id].Value = nil
		return true
	}
}

// Connect connects a Route, specified by ID, to a connection
func (b *Block) Connect(id RouteID, c Connection) {
	b.routing.InterruptChan <- func() bool {
		b.routing.Outputs[id].Connections[c] = struct{}{}
		return true
	}
}

// Disconnect removes a connection from a Route
func (b *Block) Disconnect(id RouteID, c Connection) {
	b.routing.InterruptChan <- func() bool {
		delete(b.routing.Outputs[id].Connections, c)
		return true
	}
}

// suture: stop the block
func (b *Block) Stop() {
	b.routing.InterruptChan <- func() bool {
		return false
	}
}

// wait and listen for all kernel inputs to be filled.
func (b *Block) receive() Interrupt {
	var err error
	for id, input := range b.routing.Inputs {
		//if we have already received a value on this input, skip.
		if _, ok := b.state.inputValues[RouteID(id)]; ok {
			continue
		}

		// if there is a value set for this input, place value on
		// buffer and set it in map.
		if input.Value != nil {
			b.state.inputValues[RouteID(id)] = *input.Value
			continue
		}

		select {
		case m := <-input.C:
			b.state.inputValues[RouteID(id)], err = fetch.Run(input.Path, m)
			if err != nil {
				log.Fatal(err)
			}
		case f := <-b.routing.InterruptChan:
			return f
		}
	}
	return nil
}

// run kernel on inputs, produce outputs
func (b *Block) process() Interrupt {
	if b.state.Processed == true {
		return nil
	}

	// if this kernel relies on an external shared state then we need to
	// block until an interrupt connects us to a shared external state.
	if b.routing.Shared.Type != NONE && b.routing.Shared.Store == nil {
		select {
		case f := <-b.routing.InterruptChan:
			return f
		}
	}

	// we should only be able to get here if
	// - we don't need an shared state
	// - we have an external shared state and it has been attached
	if b.routing.Shared.Type != NONE {
		b.routing.Shared.Store.Lock()
	}

	// run the kernel
	interrupt := b.kernel(b.state.inputValues,
		b.state.outputValues,
		b.routing.Shared.Store,
		b.routing.InterruptChan)

	if interrupt != nil {
		if b.routing.Shared.Type != NONE {
			b.routing.Shared.Store.Unlock()
		}
		return interrupt
	}

	if b.routing.Shared.Type != NONE {
		b.routing.Shared.Store.Unlock()
	}

	b.state.Processed = true

	return nil
}

// broadcast the kernel output to all connections on all outputs.
func (b *Block) broadcast() Interrupt {
	for id, out := range b.routing.Outputs {
		// if there no connection for this output then wait until there
		// is one. that means we have to wait for an interrupt.
		if len(out.Connections) == 0 {
			select {
			case f := <-b.routing.InterruptChan:
				return f
			}
		}
		for c, _ := range out.Connections {
			// check to see if we have delivered a message to this
			// connection for this block crank. if we have, then
			// skip this delivery.
			m := ManifestPair{id, c}
			if _, ok := b.state.manifest[m]; ok {
				continue
			}

			select {
			case c <- b.state.outputValues[RouteID(id)]:
				// set that we have delivered the message.
				b.state.manifest[m] = struct{}{}
			case f := <-b.routing.InterruptChan:
				return f
			}
		}

	}
	return nil
}

// cleanup all block state for this crank of the block
func (b *Block) crank() {
	for k, _ := range b.state.inputValues {
		delete(b.state.inputValues, k)
	}
	for k, _ := range b.state.outputValues {
		delete(b.state.outputValues, k)
	}
	for k, _ := range b.state.manifest {
		delete(b.state.manifest, k)
	}
	b.state.Processed = false
}
<|endoftext|>


<commit_before>package mocks

import (
	"fmt"
	"go/ast"
	"go/token"
	"strconv"
	"strings"
	"unicode"
)

type Mock struct {
	typeName   string
	implements *ast.InterfaceType
}

func For(typ *ast.TypeSpec) (Mock, error) {
	inter, ok := typ.Type.(*ast.InterfaceType)
	if !ok {
		return Mock{}, fmt.Errorf("TypeSpec.Type expected to be *ast.InterfaceType, was %T", typ.Type)
	}
	m := Mock{
		typeName:   typ.Name.String(),
		implements: inter,
	}
	return m, nil
}

func (m *Mock) Name() string {
	return "mock" + strings.ToUpper(m.typeName[0:1]) + m.typeName[1:]
}

func (m *Mock) Methods() (methods []Method) {
	for _, method := range m.implements.Methods.List {
		switch methodType := method.Type.(type) {
		case *ast.FuncType:
			newMethod := Method{
				receiver:   m,
				name:       method.Names[0].String(),
				implements: methodType,
			}
			methods = append(methods, newMethod)
		}
	}
	return
}

func (m Mock) Constructor(chanSize int) *ast.FuncDecl {
	decl := &ast.FuncDecl{}
	typeRunes := []rune(m.Name())
	typeRunes[0] = unicode.ToUpper(typeRunes[0])
	decl.Name = &ast.Ident{Name: "new" + string(typeRunes)}
	decl.Type = &ast.FuncType{
		Results: &ast.FieldList{List: []*ast.Field{{
			Type: &ast.StarExpr{
				X: &ast.Ident{Name: m.Name()},
			},
		}}},
	}
	decl.Body = &ast.BlockStmt{List: m.constructorBody(chanSize)}
	return decl
}

func (m Mock) Decl() *ast.GenDecl {
	spec := &ast.TypeSpec{}
	spec.Name = &ast.Ident{Name: m.Name()}
	spec.Type = m.structType()
	return &ast.GenDecl{
		Tok:   token.TYPE,
		Specs: []ast.Spec{spec},
	}
}

func (m Mock) Ast(chanSize int) []ast.Decl {
	decls := []ast.Decl{
		m.Decl(),
		m.Constructor(chanSize),
	}
	for _, method := range m.Methods() {
		decls = append(decls, method.Ast())
	}
	return decls
}

func (m Mock) makeChan(typ ast.Expr, size int) *ast.CallExpr {
	return &ast.CallExpr{
		Fun: &ast.Ident{Name: "make"},
		Args: []ast.Expr{
			&ast.ChanType{Dir: ast.SEND | ast.RECV, Value: typ},
			&ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(size)},
		},
	}
}

func (m Mock) paramChanInit(method Method, chanSize int) []ast.Stmt {
	return m.typeChanInit(method.name+"Input", method.params(), chanSize)
}

func (m Mock) returnChanInit(method Method, chanSize int) []ast.Stmt {
	return m.typeChanInit(method.name+"Output", method.results(), chanSize)
}

func (m Mock) typeChanInit(fieldName string, fields []*ast.Field, chanSize int) (inputInits []ast.Stmt) {
	for _, field := range fields {
		for _, name := range field.Names {
			inputInits = append(inputInits, &ast.AssignStmt{
				Lhs: []ast.Expr{selectors("m", fieldName, name.String())},
				Tok: token.ASSIGN,
				Rhs: []ast.Expr{m.makeChan(field.Type, chanSize)},
			})
		}
	}
	return inputInits
}

func (m Mock) chanInit(method Method, chanSize int) []ast.Stmt {
	stmts := []ast.Stmt{
		&ast.AssignStmt{
			Lhs: []ast.Expr{selectors("m", method.name+"Called")},
			Tok: token.ASSIGN,
			Rhs: []ast.Expr{m.makeChan(&ast.Ident{Name: "bool"}, chanSize)},
		},
	}
	stmts = append(stmts, m.paramChanInit(method, chanSize)...)
	stmts = append(stmts, m.returnChanInit(method, chanSize)...)
	return stmts
}

func (m Mock) constructorBody(chanSize int) []ast.Stmt {
	structAlloc := &ast.AssignStmt{
		Lhs: []ast.Expr{&ast.Ident{Name: "m"}},
		Tok: token.DEFINE,
		Rhs: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.CompositeLit{Type: &ast.Ident{Name: m.Name()}}}},
	}
	stmts := []ast.Stmt{structAlloc}
	for _, method := range m.Methods() {
		stmts = append(stmts, m.chanInit(method, chanSize)...)
	}
	stmts = append(stmts, &ast.ReturnStmt{Results: []ast.Expr{&ast.Ident{Name: "m"}}})
	return stmts
}

func (m Mock) chanStruct(list []*ast.Field) *ast.StructType {
	typ := &ast.StructType{Fields: &ast.FieldList{}}
	for _, f := range list {
		typ.Fields.List = append(typ.Fields.List, &ast.Field{
			Names: f.Names,
			Type: &ast.ChanType{
				Dir:   ast.SEND | ast.RECV,
				Value: f.Type,
			},
		})
	}
	return typ
}

func (m Mock) methodTypes(method Method) []*ast.Field {
	fields := []*ast.Field{
		{
			Names: []*ast.Ident{{Name: method.name + "Called"}},
			Type: &ast.ChanType{
				Dir:   ast.SEND | ast.RECV,
				Value: &ast.Ident{Name: "bool"},
			},
		},
	}
	if len(method.params()) > 0 {
		fields = append(fields, &ast.Field{
			Names: []*ast.Ident{{Name: method.name + "Input"}},
			Type:  m.chanStruct(method.params()),
		})
	}
	if len(method.results()) > 0 {
		fields = append(fields, &ast.Field{
			Names: []*ast.Ident{{Name: method.name + "Output"}},
			Type:  m.chanStruct(method.results()),
		})
	}
	return fields
}

func (m Mock) structType() *ast.StructType {
	structType := &ast.StructType{Fields: &ast.FieldList{}}
	for _, method := range m.Methods() {
		structType.Fields.List = append(structType.Fields.List, m.methodTypes(method)...)
	}
	return structType
}
<commit_msg>Add functionality to prepend package name to local types<commit_after>package mocks

import (
	"fmt"
	"go/ast"
	"go/token"
	"strconv"
	"strings"
	"unicode"
)

type Mock struct {
	typeName   string
	implements *ast.InterfaceType
}

func For(typ *ast.TypeSpec) (Mock, error) {
	inter, ok := typ.Type.(*ast.InterfaceType)
	if !ok {
		return Mock{}, fmt.Errorf("TypeSpec.Type expected to be *ast.InterfaceType, was %T", typ.Type)
	}
	m := Mock{
		typeName:   typ.Name.String(),
		implements: inter,
	}
	return m, nil
}

func (m Mock) Name() string {
	return "mock" + strings.ToUpper(m.typeName[0:1]) + m.typeName[1:]
}

func (m Mock) Methods() (methods []Method) {
	for _, method := range m.implements.Methods.List {
		switch methodType := method.Type.(type) {
		case *ast.FuncType:
			methods = append(methods, MethodFor(m, method.Names[0].String(), methodType))
		}
	}
	return
}

func (m Mock) PrependLocalPackage(name string) {
	for _, m := range m.Methods() {
		m.PrependLocalPackage(name)
	}
}

func (m Mock) Constructor(chanSize int) *ast.FuncDecl {
	decl := &ast.FuncDecl{}
	typeRunes := []rune(m.Name())
	typeRunes[0] = unicode.ToUpper(typeRunes[0])
	decl.Name = &ast.Ident{Name: "new" + string(typeRunes)}
	decl.Type = &ast.FuncType{
		Results: &ast.FieldList{List: []*ast.Field{{
			Type: &ast.StarExpr{
				X: &ast.Ident{Name: m.Name()},
			},
		}}},
	}
	decl.Body = &ast.BlockStmt{List: m.constructorBody(chanSize)}
	return decl
}

func (m Mock) Decl() *ast.GenDecl {
	spec := &ast.TypeSpec{}
	spec.Name = &ast.Ident{Name: m.Name()}
	spec.Type = m.structType()
	return &ast.GenDecl{
		Tok:   token.TYPE,
		Specs: []ast.Spec{spec},
	}
}

func (m Mock) Ast(chanSize int) []ast.Decl {
	decls := []ast.Decl{
		m.Decl(),
		m.Constructor(chanSize),
	}
	for _, method := range m.Methods() {
		decls = append(decls, method.Ast())
	}
	return decls
}

func (m Mock) makeChan(typ ast.Expr, size int) *ast.CallExpr {
	return &ast.CallExpr{
		Fun: &ast.Ident{Name: "make"},
		Args: []ast.Expr{
			&ast.ChanType{Dir: ast.SEND | ast.RECV, Value: typ},
			&ast.BasicLit{Kind: token.INT, Value: strconv.Itoa(size)},
		},
	}
}

func (m Mock) paramChanInit(method Method, chanSize int) []ast.Stmt {
	return m.typeChanInit(method.name+"Input", method.params(), chanSize)
}

func (m Mock) returnChanInit(method Method, chanSize int) []ast.Stmt {
	return m.typeChanInit(method.name+"Output", method.results(), chanSize)
}

func (m Mock) typeChanInit(fieldName string, fields []*ast.Field, chanSize int) (inputInits []ast.Stmt) {
	for _, field := range fields {
		for _, name := range field.Names {
			inputInits = append(inputInits, &ast.AssignStmt{
				Lhs: []ast.Expr{selectors("m", fieldName, name.String())},
				Tok: token.ASSIGN,
				Rhs: []ast.Expr{m.makeChan(field.Type, chanSize)},
			})
		}
	}
	return inputInits
}

func (m Mock) chanInit(method Method, chanSize int) []ast.Stmt {
	stmts := []ast.Stmt{
		&ast.AssignStmt{
			Lhs: []ast.Expr{selectors("m", method.name+"Called")},
			Tok: token.ASSIGN,
			Rhs: []ast.Expr{m.makeChan(&ast.Ident{Name: "bool"}, chanSize)},
		},
	}
	stmts = append(stmts, m.paramChanInit(method, chanSize)...)
	stmts = append(stmts, m.returnChanInit(method, chanSize)...)
	return stmts
}

func (m Mock) constructorBody(chanSize int) []ast.Stmt {
	structAlloc := &ast.AssignStmt{
		Lhs: []ast.Expr{&ast.Ident{Name: "m"}},
		Tok: token.DEFINE,
		Rhs: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.CompositeLit{Type: &ast.Ident{Name: m.Name()}}}},
	}
	stmts := []ast.Stmt{structAlloc}
	for _, method := range m.Methods() {
		stmts = append(stmts, m.chanInit(method, chanSize)...)
	}
	stmts = append(stmts, &ast.ReturnStmt{Results: []ast.Expr{&ast.Ident{Name: "m"}}})
	return stmts
}

func (m Mock) chanStruct(list []*ast.Field) *ast.StructType {
	typ := &ast.StructType{Fields: &ast.FieldList{}}
	for _, f := range list {
		typ.Fields.List = append(typ.Fields.List, &ast.Field{
			Names: f.Names,
			Type: &ast.ChanType{
				Dir:   ast.SEND | ast.RECV,
				Value: f.Type,
			},
		})
	}
	return typ
}

func (m Mock) methodTypes(method Method) []*ast.Field {
	fields := []*ast.Field{
		{
			Names: []*ast.Ident{{Name: method.name + "Called"}},
			Type: &ast.ChanType{
				Dir:   ast.SEND | ast.RECV,
				Value: &ast.Ident{Name: "bool"},
			},
		},
	}
	if len(method.params()) > 0 {
		fields = append(fields, &ast.Field{
			Names: []*ast.Ident{{Name: method.name + "Input"}},
			Type:  m.chanStruct(method.params()),
		})
	}
	if len(method.results()) > 0 {
		fields = append(fields, &ast.Field{
			Names: []*ast.Ident{{Name: method.name + "Output"}},
			Type:  m.chanStruct(method.results()),
		})
	}
	return fields
}

func (m Mock) structType() *ast.StructType {
	structType := &ast.StructType{Fields: &ast.FieldList{}}
	for _, method := range m.Methods() {
		structType.Fields.List = append(structType.Fields.List, m.methodTypes(method)...)
	}
	return structType
}
<|endoftext|>


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

package eng

import (
	"encoding/json"
	gl "github.com/chsc/gogl/gl33"
	"image"
	"image/draw"
	_ "image/png"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// A Texture wraps an opengl texture and is mostly used for loading
// images and constructing Regions.
type Texture struct {
	id        gl.Uint
	width     int
	height    int
	minFilter gl.Int
	maxFilter gl.Int
	uWrap     gl.Int
	vWrap     gl.Int
}

// NewTexture takes either a string path to an image file, an
// io.Reader containing image date or an image.Image and returns a Texture.
func NewTexture(data interface{}) *Texture {
	var m image.Image

	switch data := data.(type) {
	default:
		log.Fatal("NewTexture needs a string or io.Reader")
	case string:
		file, err := os.Open(data)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()
		img, _, err := image.Decode(file)
		if err != nil {
			panic(err)
		}
		m = img
	case io.Reader:
		img, _, err := image.Decode(data)
		if err != nil {
			panic(err)
		}
		m = img
	case image.Image:
		m = data
	}

	b := m.Bounds()
	newm := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(newm, newm.Bounds(), m, b.Min, draw.Src)

	width := m.Bounds().Max.X
	height := m.Bounds().Max.Y

	var id gl.Uint
	gl.GenTextures(1, &id)

	gl.Enable(gl.TEXTURE_2D)
	gl.BindTexture(gl.TEXTURE_2D, id)

	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)

	gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.Sizei(width), gl.Sizei(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Pointer(&newm.Pix[0]))

	gl.Disable(gl.TEXTURE_2D)

	return &Texture{id, width, height, gl.NEAREST, gl.NEAREST, gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE}
}

// Split creates Regions from every width, height rect going from left
// to right, then down. This is useful for simple images with uniform cells.
func (t *Texture) Split(w, h int) []*Region {
	x := 0
	y := 0
	width := t.Width()
	height := t.Height()

	rows := height / h
	cols := width / w

	startX := x
	tiles := make([]*Region, 0)
	for row := 0; row < rows; row++ {
		x = startX
		for col := 0; col < cols; col++ {
			tiles = append(tiles, NewRegion(t, x, y, w, h))
			x += w
		}
		y += h
	}

	return tiles
}

func (t *Texture) Unpack(path string) map[string]*Region {
	regions := make(map[string]*Region)

	file, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal(err)
	}

	var data interface{}
	err = json.Unmarshal(file, &data)
	if err != nil {
		log.Fatal(err)
	}

	root := data.(map[string]interface{})
	frames := root["frames"].([]interface{})
	for _, frameData := range frames {
		frame := frameData.(map[string]interface{})
		name := strings.Split(frame["filename"].(string), ".")[0]
		rect := frame["frame"].(map[string]interface{})
		x := int(rect["x"].(float64))
		y := int(rect["y"].(float64))
		w := int(rect["w"].(float64))
		h := int(rect["h"].(float64))
		regions[name] = NewRegion(t, x, y, w, h)
	}

	return regions
}

// Delete will dispose of the texture.
func (t *Texture) Delete() {
	gl.DeleteTextures(1, &t.id)
}

// Bind will bind the texture.
func (t *Texture) Bind() {
	gl.BindTexture(gl.TEXTURE_2D, t.id)
}

// Unbind will unbind all textures.
func (t *Texture) Unbind() {
	gl.BindTexture(gl.TEXTURE_2D, 0)
}

// Width returns the width of the texture.
func (t *Texture) Width() int {
	return t.width
}

// Height returns the height of the texture.
func (t *Texture) Height() int {
	return t.height
}

// SetFilter sets the filter type used when scaling a texture up or
// down. The default is nearest which will not doing any interpolation
// between pixels.
func (t *Texture) SetFilter(min, max gl.Int) {
	t.minFilter = min
	t.maxFilter = max
	t.Bind()
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, min)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, max)
}

// Returns the current min and max filters used.
func (t *Texture) Filter() (gl.Int, gl.Int) {
	return t.minFilter, t.maxFilter
}

func (t *Texture) SetWrap(u, v gl.Int) {
	t.uWrap = u
	t.vWrap = v
	t.Bind()
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, u)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, v)
}

func (t *Texture) Wrap() (gl.Int, gl.Int) {
	return t.uWrap, t.vWrap
}
<commit_msg>Default texture to linear filter<commit_after>// Copyright 2013 Joseph Hager. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package eng

import (
	"encoding/json"
	gl "github.com/chsc/gogl/gl33"
	"image"
	"image/draw"
	_ "image/png"
	"io"
	"io/ioutil"
	"log"
	"os"
	"strings"
)

// A Texture wraps an opengl texture and is mostly used for loading
// images and constructing Regions.
type Texture struct {
	id        gl.Uint
	width     int
	height    int
	minFilter gl.Int
	maxFilter gl.Int
	uWrap     gl.Int
	vWrap     gl.Int
}

// NewTexture takes either a string path to an image file, an
// io.Reader containing image date or an image.Image and returns a Texture.
func NewTexture(data interface{}) *Texture {
	var m image.Image

	switch data := data.(type) {
	default:
		log.Fatal("NewTexture needs a string or io.Reader")
	case string:
		file, err := os.Open(data)
		if err != nil {
			log.Fatal(err)
		}
		defer file.Close()
		img, _, err := image.Decode(file)
		if err != nil {
			panic(err)
		}
		m = img
	case io.Reader:
		img, _, err := image.Decode(data)
		if err != nil {
			panic(err)
		}
		m = img
	case image.Image:
		m = data
	}

	b := m.Bounds()
	newm := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy()))
	draw.Draw(newm, newm.Bounds(), m, b.Min, draw.Src)

	width := m.Bounds().Max.X
	height := m.Bounds().Max.Y

	var id gl.Uint
	gl.GenTextures(1, &id)

	gl.Enable(gl.TEXTURE_2D)
	gl.BindTexture(gl.TEXTURE_2D, id)

	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

	gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.Sizei(width), gl.Sizei(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Pointer(&newm.Pix[0]))

	gl.Disable(gl.TEXTURE_2D)

	return &Texture{id, width, height, gl.LINEAR, gl.LINEAR, gl.CLAMP_TO_EDGE, gl.CLAMP_TO_EDGE}
}

// Split creates Regions from every width, height rect going from left
// to right, then down. This is useful for simple images with uniform cells.
func (t *Texture) Split(w, h int) []*Region {
	x := 0
	y := 0
	width := t.Width()
	height := t.Height()

	rows := height / h
	cols := width / w

	startX := x
	tiles := make([]*Region, 0)
	for row := 0; row < rows; row++ {
		x = startX
		for col := 0; col < cols; col++ {
			tiles = append(tiles, NewRegion(t, x, y, w, h))
			x += w
		}
		y += h
	}

	return tiles
}

func (t *Texture) Unpack(path string) map[string]*Region {
	regions := make(map[string]*Region)

	file, err := ioutil.ReadFile(path)
	if err != nil {
		log.Fatal(err)
	}

	var data interface{}
	err = json.Unmarshal(file, &data)
	if err != nil {
		log.Fatal(err)
	}

	root := data.(map[string]interface{})
	frames := root["frames"].([]interface{})
	for _, frameData := range frames {
		frame := frameData.(map[string]interface{})
		name := strings.Split(frame["filename"].(string), ".")[0]
		rect := frame["frame"].(map[string]interface{})
		x := int(rect["x"].(float64))
		y := int(rect["y"].(float64))
		w := int(rect["w"].(float64))
		h := int(rect["h"].(float64))
		regions[name] = NewRegion(t, x, y, w, h)
	}

	return regions
}

// Delete will dispose of the texture.
func (t *Texture) Delete() {
	gl.DeleteTextures(1, &t.id)
}

// Bind will bind the texture.
func (t *Texture) Bind() {
	gl.BindTexture(gl.TEXTURE_2D, t.id)
}

// Unbind will unbind all textures.
func (t *Texture) Unbind() {
	gl.BindTexture(gl.TEXTURE_2D, 0)
}

// Width returns the width of the texture.
func (t *Texture) Width() int {
	return t.width
}

// Height returns the height of the texture.
func (t *Texture) Height() int {
	return t.height
}

// SetFilter sets the filter type used when scaling a texture up or
// down. The default is nearest which will not doing any interpolation
// between pixels.
func (t *Texture) SetFilter(min, max gl.Int) {
	t.minFilter = min
	t.maxFilter = max
	t.Bind()
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, min)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, max)
}

// Returns the current min and max filters used.
func (t *Texture) Filter() (gl.Int, gl.Int) {
	return t.minFilter, t.maxFilter
}

func (t *Texture) SetWrap(u, v gl.Int) {
	t.uWrap = u
	t.vWrap = v
	t.Bind()
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, u)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, v)
}

func (t *Texture) Wrap() (gl.Int, gl.Int) {
	return t.uWrap, t.vWrap
}
<|endoftext|>


<commit_before>package terminal

import (
	"fmt"
	"os"
	"regexp"
	"runtime"

	"golang.org/x/crypto/ssh/terminal"
)

type Color uint

const (
	red    Color = 31
	green        = 32
	yellow       = 33
	//	blue          = 34
	magenta = 35
	cyan    = 36
	grey    = 37
	white   = 38
)

var (
	colorize               func(message string, color Color, bold int) string
	OsSupportsColors       = runtime.GOOS != "windows"
	TerminalSupportsColors = isTerminal()
	UserAskedForColors     = ""
)

func init() {
	InitColorSupport()
}

func InitColorSupport() {
	if colorsEnabled() {
		colorize = func(message string, color Color, bold int) string {
			return fmt.Sprintf("\033[%d;%dm%s\033[0m", bold, color, message)
		}
	} else {
		colorize = func(message string, _ Color, _ int) string {
			return message
		}
	}
}

func colorsEnabled() bool {
	return userDidNotDisableColor() &&
		(userEnabledColors() || (TerminalSupportsColors && OsSupportsColors))
}

func userEnabledColors() bool {
	return UserAskedForColors == "true" || os.Getenv("CF_COLOR") == "true"
}

func userDidNotDisableColor() bool {
	return os.Getenv("CF_COLOR") != "false" && (UserAskedForColors != "false" || os.Getenv("CF_COLOR") == "true")
}

func Colorize(message string, color Color) string {
	return colorize(message, color, 0)
}

func ColorizeBold(message string, color Color) string {
	return colorize(message, color, 1)
}

var decolorizerRegex = regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]`)

func Decolorize(message string) string {
	return string(decolorizerRegex.ReplaceAll([]byte(message), []byte("")))
}

func HeaderColor(message string) string {
	return ColorizeBold(message, white)
}

func CommandColor(message string) string {
	return ColorizeBold(message, yellow)
}

func StoppedColor(message string) string {
	return ColorizeBold(message, grey)
}

func AdvisoryColor(message string) string {
	return ColorizeBold(message, yellow)
}

func CrashedColor(message string) string {
	return ColorizeBold(message, red)
}

func FailureColor(message string) string {
	return ColorizeBold(message, red)
}

func SuccessColor(message string) string {
	return ColorizeBold(message, green)
}

func EntityNameColor(message string) string {
	return ColorizeBold(message, cyan)
}

func PromptColor(message string) string {
	return ColorizeBold(message, cyan)
}

func TableContentHeaderColor(message string) string {
	return ColorizeBold(message, cyan)
}

func WarningColor(message string) string {
	return ColorizeBold(message, magenta)
}

func LogStdoutColor(message string) string {
	return Colorize(message, white)
}

func LogStderrColor(message string) string {
	return Colorize(message, red)
}

func LogHealthHeaderColor(message string) string {
	return Colorize(message, grey)
}

func LogAppHeaderColor(message string) string {
	return ColorizeBold(message, yellow)
}

func LogSysHeaderColor(message string) string {
	return ColorizeBold(message, cyan)
}

func isTerminal() bool {
	return terminal.IsTerminal(1)
}
<commit_msg>Remove the commented blue.<commit_after>package terminal

import (
	"fmt"
	"os"
	"regexp"
	"runtime"

	"golang.org/x/crypto/ssh/terminal"
)

type Color uint

const (
	red     Color = 31
	green         = 32
	yellow        = 33
	magenta       = 35
	cyan          = 36
	grey          = 37
	white         = 38
)

var (
	colorize               func(message string, color Color, bold int) string
	OsSupportsColors       = runtime.GOOS != "windows"
	TerminalSupportsColors = isTerminal()
	UserAskedForColors     = ""
)

func init() {
	InitColorSupport()
}

func InitColorSupport() {
	if colorsEnabled() {
		colorize = func(message string, color Color, bold int) string {
			return fmt.Sprintf("\033[%d;%dm%s\033[0m", bold, color, message)
		}
	} else {
		colorize = func(message string, _ Color, _ int) string {
			return message
		}
	}
}

func colorsEnabled() bool {
	return userDidNotDisableColor() &&
		(userEnabledColors() || (TerminalSupportsColors && OsSupportsColors))
}

func userEnabledColors() bool {
	return UserAskedForColors == "true" || os.Getenv("CF_COLOR") == "true"
}

func userDidNotDisableColor() bool {
	return os.Getenv("CF_COLOR") != "false" && (UserAskedForColors != "false" || os.Getenv("CF_COLOR") == "true")
}

func Colorize(message string, color Color) string {
	return colorize(message, color, 0)
}

func ColorizeBold(message string, color Color) string {
	return colorize(message, color, 1)
}

var decolorizerRegex = regexp.MustCompile(`\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]`)

func Decolorize(message string) string {
	return string(decolorizerRegex.ReplaceAll([]byte(message), []byte("")))
}

func HeaderColor(message string) string {
	return ColorizeBold(message, white)
}

func CommandColor(message string) string {
	return ColorizeBold(message, yellow)
}

func StoppedColor(message string) string {
	return ColorizeBold(message, grey)
}

func AdvisoryColor(message string) string {
	return ColorizeBold(message, yellow)
}

func CrashedColor(message string) string {
	return ColorizeBold(message, red)
}

func FailureColor(message string) string {
	return ColorizeBold(message, red)
}

func SuccessColor(message string) string {
	return ColorizeBold(message, green)
}

func EntityNameColor(message string) string {
	return ColorizeBold(message, cyan)
}

func PromptColor(message string) string {
	return ColorizeBold(message, cyan)
}

func TableContentHeaderColor(message string) string {
	return ColorizeBold(message, cyan)
}

func WarningColor(message string) string {
	return ColorizeBold(message, magenta)
}

func LogStdoutColor(message string) string {
	return Colorize(message, white)
}

func LogStderrColor(message string) string {
	return Colorize(message, red)
}

func LogHealthHeaderColor(message string) string {
	return Colorize(message, grey)
}

func LogAppHeaderColor(message string) string {
	return ColorizeBold(message, yellow)
}

func LogSysHeaderColor(message string) string {
	return ColorizeBold(message, cyan)
}

func isTerminal() bool {
	return terminal.IsTerminal(1)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package api_test

import (
	"math/rand"
	"reflect"
	"testing"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	apitesting "k8s.io/kubernetes/pkg/api/testing"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/diff"

	"github.com/google/gofuzz"
)

func TestDeepCopyApiObjects(t *testing.T) {
	for i := 0; i < *fuzzIters; i++ {
		for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
			f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
			for kind := range api.Scheme.KnownTypes(version) {
				doDeepCopyTest(t, version.WithKind(kind), f)
			}
		}
	}
}

func doDeepCopyTest(t *testing.T, kind unversioned.GroupVersionKind, f *fuzz.Fuzzer) {
	item, err := api.Scheme.New(kind)
	if err != nil {
		t.Fatalf("Could not create a %v: %s", kind, err)
	}
	f.Fuzz(item)
	itemCopy, err := api.Scheme.DeepCopy(item)
	if err != nil {
		t.Errorf("Could not deep copy a %v: %s", kind, err)
		return
	}

	if !reflect.DeepEqual(item, itemCopy) {
		t.Errorf("\nexpected: %#v\n\ngot:      %#v\n\ndiff:      %v", item, itemCopy, diff.ObjectGoPrintSideBySide(item, itemCopy))
	}
}

func TestDeepCopySingleType(t *testing.T) {
	for i := 0; i < *fuzzIters; i++ {
		for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
			f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
			doDeepCopyTest(t, version.WithKind("Pod"), f)
		}
	}
}
<commit_msg>Copy reflect diff<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package api_test

import (
	"math/rand"
	"reflect"
	"testing"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
	apitesting "k8s.io/kubernetes/pkg/api/testing"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/util/diff"

	"github.com/google/gofuzz"
)

func TestDeepCopyApiObjects(t *testing.T) {
	for i := 0; i < *fuzzIters; i++ {
		for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
			f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
			for kind := range api.Scheme.KnownTypes(version) {
				doDeepCopyTest(t, version.WithKind(kind), f)
			}
		}
	}
}

func doDeepCopyTest(t *testing.T, kind unversioned.GroupVersionKind, f *fuzz.Fuzzer) {
	item, err := api.Scheme.New(kind)
	if err != nil {
		t.Fatalf("Could not create a %v: %s", kind, err)
	}
	f.Fuzz(item)
	itemCopy, err := api.Scheme.DeepCopy(item)
	if err != nil {
		t.Errorf("Could not deep copy a %v: %s", kind, err)
		return
	}

	if !reflect.DeepEqual(item, itemCopy) {
		t.Errorf("\nexpected: %#v\n\ngot:      %#v\n\ndiff:      %v", item, itemCopy, diff.ObjectReflectDiff(item, itemCopy))
	}
}

func TestDeepCopySingleType(t *testing.T) {
	for i := 0; i < *fuzzIters; i++ {
		for _, version := range []unversioned.GroupVersion{testapi.Default.InternalGroupVersion(), *testapi.Default.GroupVersion()} {
			f := apitesting.FuzzerFor(t, version, rand.NewSource(rand.Int63()))
			doDeepCopyTest(t, version.WithKind("Pod"), f)
		}
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"os"
	"strings"
	"sync"

	RepRoutes "github.com/cloudfoundry-incubator/rep/routes"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	SchemaRouter "github.com/cloudfoundry-incubator/runtime-schema/router"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/urljoiner"
	"github.com/cloudfoundry/yagnats"
	"github.com/nu7hatch/gouuid"
	"github.com/tedsuo/router"
)

const DesireAppTopic = "diego.desire.app"

var ErrNoHealthCheckDefined = errors.New("no health check defined for stack")

type Handler struct {
	repAddrRelativeToExecutor string
	healthChecks              map[string]string
	natsClient                yagnats.NATSClient
	bbs                       Bbs.AppManagerBBS
	logger                    *steno.Logger
}

func NewHandler(
	repAddrRelativeToExecutor string,
	healthChecks map[string]string,
	natsClient yagnats.NATSClient,
	bbs Bbs.AppManagerBBS,
	logger *steno.Logger,
) Handler {
	return Handler{
		repAddrRelativeToExecutor: repAddrRelativeToExecutor,
		healthChecks:              healthChecks,
		natsClient:                natsClient,
		bbs:                       bbs,
		logger:                    logger,
	}
}

func (h Handler) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	wg := new(sync.WaitGroup)
	desiredApps := make(chan models.DesireAppRequestFromCC)
	h.listenForDesiredApps(desiredApps)

	close(ready)

	for {
		select {
		case msg := <-desiredApps:
			wg.Add(1)
			go func() {
				defer wg.Done()
				h.desireApp(msg)
			}()
		case <-signals:
			h.natsClient.UnsubscribeAll(DesireAppTopic)
			wg.Wait()
			return nil
		}
	}
}

func (h Handler) listenForDesiredApps(desiredApps chan models.DesireAppRequestFromCC) {
	h.natsClient.Subscribe(DesireAppTopic, func(message *yagnats.Message) {
		desireAppMessage := models.DesireAppRequestFromCC{}
		err := json.Unmarshal(message.Payload, &desireAppMessage)
		if err != nil {
			h.logger.Errorf("Failed to parse NATS message.")
			return
		}

		desiredApps <- desireAppMessage
	})
}

func (h Handler) desireApp(desireAppMessage models.DesireAppRequestFromCC) {

	lrpGuid := fmt.Sprintf("%s-%s", desireAppMessage.AppId, desireAppMessage.AppVersion)

	desiredLRP := models.DesiredLRP{
		ProcessGuid: lrpGuid,
		Instances:   desireAppMessage.NumInstances,
		MemoryMB:    desireAppMessage.MemoryMB,
		DiskMB:      desireAppMessage.DiskMB,
		Stack:       desireAppMessage.Stack,
		Routes:      desireAppMessage.Routes,
	}

	err := h.bbs.DesireLongRunningProcess(desiredLRP)
	if err != nil {
		h.logger.Errord(
			map[string]interface{}{
				"error": err.Error(),
			},
			"app-manager.desire-lrp.failed",
		)

		return
	}

	var numFiles *uint64
	if desireAppMessage.FileDescriptors != 0 {
		numFiles = &desireAppMessage.FileDescriptors
	}

	fileServerURL, err := h.bbs.GetAvailableFileServer()
	if err != nil {
		h.logger.Warnd(
			map[string]interface{}{
				"error": err.Error(),
			},
			"handler.get-available-file-server.failed",
		)

		return
	}

	healthCheckURL, err := h.healthCheckDownloadURL(desireAppMessage.Stack, fileServerURL)
	if err != nil {
		h.logger.Warnd(
			map[string]interface{}{
				"error": err.Error(),
				"stack": desireAppMessage.Stack,
			},
			"handler.construct-health-check-download-url.failed",
		)

		return
	}

	repRequests := router.NewRequestGenerator(
		"http://"+h.repAddrRelativeToExecutor,
		RepRoutes.Routes,
	)

	for index := 0; index < desireAppMessage.NumInstances; index++ {
		lrpIndex := index

		instanceGuid, err := uuid.NewV4()
		if err != nil {
			h.logger.Errorf("Error generating instance guid: %s", err.Error())
			continue
		}

		lrpEnv, err := createLrpEnv(desireAppMessage.Environment, lrpGuid, lrpIndex)
		if err != nil {
			h.logger.Warnd(
				map[string]interface{}{
					"error": err.Error(),
				},
				"handler.constructing-env.failed",
			)

			return
		}

		healthyHook, err := repRequests.RequestForHandler(
			RepRoutes.LRPRunning,
			router.Params{
				"process_guid":  lrpGuid,
				"index":         fmt.Sprintf("%d", lrpIndex),
				"instance_guid": instanceGuid.String(),
			},
			nil,
		)
		if err != nil {
			panic(err)
		}

		err = h.bbs.RequestLRPStartAuction(models.LRPStartAuction{
			ProcessGuid:  lrpGuid,
			InstanceGuid: instanceGuid.String(),
			State:        models.LRPStartAuctionStatePending,
			Index:        lrpIndex,

			MemoryMB: desireAppMessage.MemoryMB,
			DiskMB:   desireAppMessage.DiskMB,

			Ports: []models.PortMapping{
				{ContainerPort: 8080},
			},

			Stack: desireAppMessage.Stack,
			Log: models.LogConfig{
				Guid:       desireAppMessage.AppId,
				SourceName: "App",
				Index:      &lrpIndex,
			},
			Actions: []models.ExecutorAction{
				{
					Action: models.DownloadAction{
						From:    healthCheckURL.String(),
						To:      "/tmp/diego-health-check",
						Extract: true,
					},
				},
				{
					Action: models.DownloadAction{
						From:     desireAppMessage.DropletUri,
						To:       ".",
						Extract:  true,
						CacheKey: fmt.Sprintf("droplets-%s", lrpGuid),
					},
				},
				models.Parallel(
					models.ExecutorAction{
						models.RunAction{
							Script: strings.Join([]string{
								"cd ./app",
								"if [ -d .profile.d ]; then source .profile.d/*.sh; fi",
								desireAppMessage.StartCommand,
							}, " && "),
							Env:     lrpEnv,
							Timeout: 0,
							ResourceLimits: models.ResourceLimits{
								Nofile: numFiles,
							},
						},
					},
					models.ExecutorAction{
						models.MonitorAction{
							Action: models.ExecutorAction{
								models.RunAction{
									Script: "/tmp/diego-health-check/diego-health-check -addr=:8080",
								},
							},
							HealthyThreshold:   1,
							UnhealthyThreshold: 1,
							HealthyHook: models.HealthRequest{
								Method: healthyHook.Method,
								URL:    healthyHook.URL.String(),
							},
						},
					},
				),
			},
		})
		if err != nil {
			h.logger.Errorf("Error writing to BBS: %s", err.Error())
		}
	}
}

func (h Handler) start() {
	h.natsClient.Subscribe(DesireAppTopic, func(message *yagnats.Message) {
		desireAppMessage := models.DesireAppRequestFromCC{}
		err := json.Unmarshal(message.Payload, &desireAppMessage)
		if err != nil {
			h.logger.Errorf("Failed to parse NATS message.")
			return
		}

		lrpGuid := fmt.Sprintf("%s-%s", desireAppMessage.AppId, desireAppMessage.AppVersion)

		desiredLRP := models.DesiredLRP{
			ProcessGuid: lrpGuid,
			Instances:   desireAppMessage.NumInstances,
			MemoryMB:    desireAppMessage.MemoryMB,
			DiskMB:      desireAppMessage.DiskMB,
			Stack:       desireAppMessage.Stack,
			Routes:      desireAppMessage.Routes,
		}

		err = h.bbs.DesireLongRunningProcess(desiredLRP)
		if err != nil {
			h.logger.Errord(
				map[string]interface{}{
					"error": err.Error(),
				},
				"app-manager.desire-lrp.failed",
			)

			return
		}

		var numFiles *uint64
		if desireAppMessage.FileDescriptors != 0 {
			numFiles = &desireAppMessage.FileDescriptors
		}

		fileServerURL, err := h.bbs.GetAvailableFileServer()
		if err != nil {
			h.logger.Warnd(
				map[string]interface{}{
					"error": err.Error(),
				},
				"handler.get-available-file-server.failed",
			)

			return
		}

		healthCheckURL, err := h.healthCheckDownloadURL(desireAppMessage.Stack, fileServerURL)
		if err != nil {
			h.logger.Warnd(
				map[string]interface{}{
					"error": err.Error(),
					"stack": desireAppMessage.Stack,
				},
				"handler.construct-health-check-download-url.failed",
			)

			return
		}

		repRequests := router.NewRequestGenerator(
			"http://"+h.repAddrRelativeToExecutor,
			RepRoutes.Routes,
		)

		for index := 0; index < desireAppMessage.NumInstances; index++ {
			lrpIndex := index

			instanceGuid, err := uuid.NewV4()
			if err != nil {
				h.logger.Errorf("Error generating instance guid: %s", err.Error())
				continue
			}

			lrpEnv, err := createLrpEnv(desireAppMessage.Environment, lrpGuid, lrpIndex)
			if err != nil {
				h.logger.Warnd(
					map[string]interface{}{
						"error": err.Error(),
					},
					"handler.constructing-env.failed",
				)

				return
			}

			healthyHook, err := repRequests.RequestForHandler(
				RepRoutes.LRPRunning,
				router.Params{
					"process_guid":  lrpGuid,
					"index":         fmt.Sprintf("%d", lrpIndex),
					"instance_guid": instanceGuid.String(),
				},
				nil,
			)
			if err != nil {
				panic(err)
			}

			err = h.bbs.RequestLRPStartAuction(models.LRPStartAuction{
				ProcessGuid:  lrpGuid,
				InstanceGuid: instanceGuid.String(),
				State:        models.LRPStartAuctionStatePending,
				Index:        lrpIndex,

				MemoryMB: desireAppMessage.MemoryMB,
				DiskMB:   desireAppMessage.DiskMB,

				Ports: []models.PortMapping{
					{ContainerPort: 8080},
				},

				Stack: desireAppMessage.Stack,
				Log: models.LogConfig{
					Guid:       desireAppMessage.AppId,
					SourceName: "App",
					Index:      &lrpIndex,
				},
				Actions: []models.ExecutorAction{
					{
						Action: models.DownloadAction{
							From:    healthCheckURL.String(),
							To:      "/tmp/diego-health-check",
							Extract: true,
						},
					},
					{
						Action: models.DownloadAction{
							From:     desireAppMessage.DropletUri,
							To:       ".",
							Extract:  true,
							CacheKey: fmt.Sprintf("droplets-%s", lrpGuid),
						},
					},
					models.Parallel(
						models.ExecutorAction{
							models.RunAction{
								Script: strings.Join([]string{
									"cd ./app",
									"if [ -d .profile.d ]; then source .profile.d/*.sh; fi",
									desireAppMessage.StartCommand,
								}, " && "),
								Env:     lrpEnv,
								Timeout: 0,
								ResourceLimits: models.ResourceLimits{
									Nofile: numFiles,
								},
							},
						},
						models.ExecutorAction{
							models.MonitorAction{
								Action: models.ExecutorAction{
									models.RunAction{
										Script: "/tmp/diego-health-check/diego-health-check -addr=:8080",
									},
								},
								HealthyThreshold:   1,
								UnhealthyThreshold: 1,
								HealthyHook: models.HealthRequest{
									Method: healthyHook.Method,
									URL:    healthyHook.URL.String(),
								},
							},
						},
					),
				},
			})
			if err != nil {
				h.logger.Errorf("Error writing to BBS: %s", err.Error())
			}
		}
	})
}

func (h Handler) healthCheckDownloadURL(stack string, fileServerURL string) (*url.URL, error) {
	checkPath, ok := h.healthChecks[stack]
	if !ok {
		return nil, ErrNoHealthCheckDefined
	}

	staticRoute, ok := SchemaRouter.NewFileServerRoutes().RouteForHandler(SchemaRouter.FS_STATIC)
	if !ok {
		return nil, errors.New("couldn't generate the compiler download path")
	}

	urlString := urljoiner.Join(fileServerURL, staticRoute.Path, checkPath)

	url, err := url.ParseRequestURI(urlString)
	if err != nil {
		return nil, fmt.Errorf("failed to parse compiler download URL: %s", err)
	}

	return url, nil
}

func createLrpEnv(env []models.EnvironmentVariable, lrpGuid string, lrpIndex int) ([]models.EnvironmentVariable, error) {
	env = append(env, models.EnvironmentVariable{Key: "PORT", Value: "8080"})
	env = append(env, models.EnvironmentVariable{Key: "VCAP_APP_PORT", Value: "8080"})
	env = append(env, models.EnvironmentVariable{Key: "VCAP_APP_HOST", Value: "0.0.0.0"})
	env = append(env, models.EnvironmentVariable{Key: "TMPDIR", Value: "$HOME/tmp"})

	vcapAppEnv := map[string]interface{}{}
	vcapAppEnvIndex := -1
	for i, envVar := range env {
		if envVar.Key == "VCAP_APPLICATION" {
			vcapAppEnvIndex = i
			err := json.Unmarshal([]byte(envVar.Value), &vcapAppEnv)
			if err != nil {
				return env, err
			}
		}
	}

	if vcapAppEnvIndex == -1 {
		return env, nil
	}

	vcapAppEnv["port"] = 8080
	vcapAppEnv["host"] = "0.0.0.0"
	vcapAppEnv["instance_id"] = lrpGuid
	vcapAppEnv["instance_index"] = lrpIndex

	lrpEnv, err := json.Marshal(vcapAppEnv)
	if err != nil {
		return env, err
	}

	env[vcapAppEnvIndex] = models.EnvironmentVariable{Key: "VCAP_APPLICATION", Value: string(lrpEnv)}
	return env, nil
}
<commit_msg>nuke dead code<commit_after>package handler

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"os"
	"strings"
	"sync"

	RepRoutes "github.com/cloudfoundry-incubator/rep/routes"
	Bbs "github.com/cloudfoundry-incubator/runtime-schema/bbs"
	"github.com/cloudfoundry-incubator/runtime-schema/models"
	SchemaRouter "github.com/cloudfoundry-incubator/runtime-schema/router"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/gunk/urljoiner"
	"github.com/cloudfoundry/yagnats"
	"github.com/nu7hatch/gouuid"
	"github.com/tedsuo/router"
)

const DesireAppTopic = "diego.desire.app"

var ErrNoHealthCheckDefined = errors.New("no health check defined for stack")

type Handler struct {
	repAddrRelativeToExecutor string
	healthChecks              map[string]string
	natsClient                yagnats.NATSClient
	bbs                       Bbs.AppManagerBBS
	logger                    *steno.Logger
}

func NewHandler(
	repAddrRelativeToExecutor string,
	healthChecks map[string]string,
	natsClient yagnats.NATSClient,
	bbs Bbs.AppManagerBBS,
	logger *steno.Logger,
) Handler {
	return Handler{
		repAddrRelativeToExecutor: repAddrRelativeToExecutor,
		healthChecks:              healthChecks,
		natsClient:                natsClient,
		bbs:                       bbs,
		logger:                    logger,
	}
}

func (h Handler) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	wg := new(sync.WaitGroup)
	desiredApps := make(chan models.DesireAppRequestFromCC)
	h.listenForDesiredApps(desiredApps)

	close(ready)

	for {
		select {
		case msg := <-desiredApps:
			wg.Add(1)
			go func() {
				defer wg.Done()
				h.desireApp(msg)
			}()
		case <-signals:
			h.natsClient.UnsubscribeAll(DesireAppTopic)
			wg.Wait()
			return nil
		}
	}
}

func (h Handler) listenForDesiredApps(desiredApps chan models.DesireAppRequestFromCC) {
	h.natsClient.Subscribe(DesireAppTopic, func(message *yagnats.Message) {
		desireAppMessage := models.DesireAppRequestFromCC{}
		err := json.Unmarshal(message.Payload, &desireAppMessage)
		if err != nil {
			h.logger.Errorf("Failed to parse NATS message.")
			return
		}

		desiredApps <- desireAppMessage
	})
}

func (h Handler) desireApp(desireAppMessage models.DesireAppRequestFromCC) {

	lrpGuid := fmt.Sprintf("%s-%s", desireAppMessage.AppId, desireAppMessage.AppVersion)

	desiredLRP := models.DesiredLRP{
		ProcessGuid: lrpGuid,
		Instances:   desireAppMessage.NumInstances,
		MemoryMB:    desireAppMessage.MemoryMB,
		DiskMB:      desireAppMessage.DiskMB,
		Stack:       desireAppMessage.Stack,
		Routes:      desireAppMessage.Routes,
	}

	err := h.bbs.DesireLongRunningProcess(desiredLRP)
	if err != nil {
		h.logger.Errord(
			map[string]interface{}{
				"error": err.Error(),
			},
			"app-manager.desire-lrp.failed",
		)

		return
	}

	var numFiles *uint64
	if desireAppMessage.FileDescriptors != 0 {
		numFiles = &desireAppMessage.FileDescriptors
	}

	fileServerURL, err := h.bbs.GetAvailableFileServer()
	if err != nil {
		h.logger.Warnd(
			map[string]interface{}{
				"error": err.Error(),
			},
			"handler.get-available-file-server.failed",
		)

		return
	}

	healthCheckURL, err := h.healthCheckDownloadURL(desireAppMessage.Stack, fileServerURL)
	if err != nil {
		h.logger.Warnd(
			map[string]interface{}{
				"error": err.Error(),
				"stack": desireAppMessage.Stack,
			},
			"handler.construct-health-check-download-url.failed",
		)

		return
	}

	repRequests := router.NewRequestGenerator(
		"http://"+h.repAddrRelativeToExecutor,
		RepRoutes.Routes,
	)

	for index := 0; index < desireAppMessage.NumInstances; index++ {
		lrpIndex := index

		instanceGuid, err := uuid.NewV4()
		if err != nil {
			h.logger.Errorf("Error generating instance guid: %s", err.Error())
			continue
		}

		lrpEnv, err := createLrpEnv(desireAppMessage.Environment, lrpGuid, lrpIndex)
		if err != nil {
			h.logger.Warnd(
				map[string]interface{}{
					"error": err.Error(),
				},
				"handler.constructing-env.failed",
			)

			return
		}

		healthyHook, err := repRequests.RequestForHandler(
			RepRoutes.LRPRunning,
			router.Params{
				"process_guid":  lrpGuid,
				"index":         fmt.Sprintf("%d", lrpIndex),
				"instance_guid": instanceGuid.String(),
			},
			nil,
		)
		if err != nil {
			panic(err)
		}

		err = h.bbs.RequestLRPStartAuction(models.LRPStartAuction{
			ProcessGuid:  lrpGuid,
			InstanceGuid: instanceGuid.String(),
			State:        models.LRPStartAuctionStatePending,
			Index:        lrpIndex,

			MemoryMB: desireAppMessage.MemoryMB,
			DiskMB:   desireAppMessage.DiskMB,

			Ports: []models.PortMapping{
				{ContainerPort: 8080},
			},

			Stack: desireAppMessage.Stack,
			Log: models.LogConfig{
				Guid:       desireAppMessage.AppId,
				SourceName: "App",
				Index:      &lrpIndex,
			},
			Actions: []models.ExecutorAction{
				{
					Action: models.DownloadAction{
						From:    healthCheckURL.String(),
						To:      "/tmp/diego-health-check",
						Extract: true,
					},
				},
				{
					Action: models.DownloadAction{
						From:     desireAppMessage.DropletUri,
						To:       ".",
						Extract:  true,
						CacheKey: fmt.Sprintf("droplets-%s", lrpGuid),
					},
				},
				models.Parallel(
					models.ExecutorAction{
						models.RunAction{
							Script: strings.Join([]string{
								"cd ./app",
								"if [ -d .profile.d ]; then source .profile.d/*.sh; fi",
								desireAppMessage.StartCommand,
							}, " && "),
							Env:     lrpEnv,
							Timeout: 0,
							ResourceLimits: models.ResourceLimits{
								Nofile: numFiles,
							},
						},
					},
					models.ExecutorAction{
						models.MonitorAction{
							Action: models.ExecutorAction{
								models.RunAction{
									Script: "/tmp/diego-health-check/diego-health-check -addr=:8080",
								},
							},
							HealthyThreshold:   1,
							UnhealthyThreshold: 1,
							HealthyHook: models.HealthRequest{
								Method: healthyHook.Method,
								URL:    healthyHook.URL.String(),
							},
						},
					},
				),
			},
		})
		if err != nil {
			h.logger.Errorf("Error writing to BBS: %s", err.Error())
		}
	}
}

func (h Handler) healthCheckDownloadURL(stack string, fileServerURL string) (*url.URL, error) {
	checkPath, ok := h.healthChecks[stack]
	if !ok {
		return nil, ErrNoHealthCheckDefined
	}

	staticRoute, ok := SchemaRouter.NewFileServerRoutes().RouteForHandler(SchemaRouter.FS_STATIC)
	if !ok {
		return nil, errors.New("couldn't generate the compiler download path")
	}

	urlString := urljoiner.Join(fileServerURL, staticRoute.Path, checkPath)

	url, err := url.ParseRequestURI(urlString)
	if err != nil {
		return nil, fmt.Errorf("failed to parse compiler download URL: %s", err)
	}

	return url, nil
}

func createLrpEnv(env []models.EnvironmentVariable, lrpGuid string, lrpIndex int) ([]models.EnvironmentVariable, error) {
	env = append(env, models.EnvironmentVariable{Key: "PORT", Value: "8080"})
	env = append(env, models.EnvironmentVariable{Key: "VCAP_APP_PORT", Value: "8080"})
	env = append(env, models.EnvironmentVariable{Key: "VCAP_APP_HOST", Value: "0.0.0.0"})
	env = append(env, models.EnvironmentVariable{Key: "TMPDIR", Value: "$HOME/tmp"})

	vcapAppEnv := map[string]interface{}{}
	vcapAppEnvIndex := -1
	for i, envVar := range env {
		if envVar.Key == "VCAP_APPLICATION" {
			vcapAppEnvIndex = i
			err := json.Unmarshal([]byte(envVar.Value), &vcapAppEnv)
			if err != nil {
				return env, err
			}
		}
	}

	if vcapAppEnvIndex == -1 {
		return env, nil
	}

	vcapAppEnv["port"] = 8080
	vcapAppEnv["host"] = "0.0.0.0"
	vcapAppEnv["instance_id"] = lrpGuid
	vcapAppEnv["instance_index"] = lrpIndex

	lrpEnv, err := json.Marshal(vcapAppEnv)
	if err != nil {
		return env, err
	}

	env[vcapAppEnvIndex] = models.EnvironmentVariable{Key: "VCAP_APPLICATION", Value: string(lrpEnv)}
	return env, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package meta

import (
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
)

// Accessor takes an arbitary object pointer and returns meta.Interface.
// obj must be a pointer to an API type. An error is returned if the minimum
// required fields are missing. Fields that are not required return the default
// value and are a no-op if set.
// TODO: add a fast path for *TypeMeta and *ObjectMeta for internal objects
func Accessor(obj interface{}) (Interface, error) {
	v, err := conversion.EnforcePtr(obj)
	if err != nil {
		return nil, err
	}
	t := v.Type()
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
	}

	typeMeta := v.FieldByName("TypeMeta")
	if !typeMeta.IsValid() {
		return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
	}

	a := &genericAccessor{}
	if err := extractFromTypeMeta(typeMeta, a); err != nil {
		return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
	}

	objectMeta := v.FieldByName("ObjectMeta")
	if objectMeta.IsValid() {
		// look for the ObjectMeta fields
		if err := extractFromObjectMeta(objectMeta, a); err != nil {
			return nil, fmt.Errorf("unable to find object fields on %#v: %v", objectMeta, err)
		}
	} else {
		listMeta := v.FieldByName("ListMeta")
		if listMeta.IsValid() {
			// look for the ListMeta fields
			if err := extractFromListMeta(listMeta, a); err != nil {
				return nil, fmt.Errorf("unable to find list fields on %#v: %v", listMeta, err)
			}
		} else {
			// look for the older TypeMeta with all metadata
			if err := extractFromObjectMeta(typeMeta, a); err != nil {
				return nil, fmt.Errorf("unable to find object fields on %#v: %v", typeMeta, err)
			}
		}
	}

	return a, nil
}

// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
// and Kind of an in-memory internal object.
// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
// api conventions).
func TypeAccessor(obj interface{}) (TypeInterface, error) {
	v, err := conversion.EnforcePtr(obj)
	if err != nil {
		return nil, err
	}
	t := v.Type()
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
	}

	typeMeta := v.FieldByName("TypeMeta")
	if !typeMeta.IsValid() {
		return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
	}
	a := &genericAccessor{}
	if err := extractFromTypeMeta(typeMeta, a); err != nil {
		return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
	}
	return a, nil
}

// NewAccessor returns a MetadataAccessor that can retrieve
// or manipulate resource version on objects derived from core API
// metadata concepts.
func NewAccessor() MetadataAccessor {
	return resourceAccessor{}
}

// resourceAccessor implements ResourceVersioner and SelfLinker.
type resourceAccessor struct{}

func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Kind(), nil
}

func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetKind(kind)
	return nil
}

func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.APIVersion(), nil
}

func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetAPIVersion(version)
	return nil
}

func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Namespace(), nil
}

func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetNamespace(namespace)
	return nil
}

func (resourceAccessor) Name(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Name(), nil
}

func (resourceAccessor) SetName(obj runtime.Object, name string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetName(name)
	return nil
}

func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.UID(), nil
}

func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetUID(uid)
	return nil
}

func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.SelfLink(), nil
}

func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetSelfLink(selfLink)
	return nil
}

func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.Labels(), nil
}

func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetLabels(labels)
	return nil
}

func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.Annotations(), nil
}

func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetAnnotations(annotations)
	return nil
}

func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.ResourceVersion(), nil
}

func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetResourceVersion(version)
	return nil
}

// genericAccessor contains pointers to strings that can modify an arbitrary
// struct and implements the Accessor interface.
type genericAccessor struct {
	namespace       *string
	name            *string
	uid             *types.UID
	apiVersion      *string
	kind            *string
	resourceVersion *string
	selfLink        *string
	labels          *map[string]string
	annotations     *map[string]string
}

func (a genericAccessor) Namespace() string {
	if a.namespace == nil {
		return ""
	}
	return *a.namespace
}

func (a genericAccessor) SetNamespace(namespace string) {
	if a.namespace == nil {
		return
	}
	*a.namespace = namespace
}

func (a genericAccessor) Name() string {
	if a.name == nil {
		return ""
	}
	return *a.name
}

func (a genericAccessor) SetName(name string) {
	if a.name == nil {
		return
	}
	*a.name = name
}

func (a genericAccessor) UID() types.UID {
	if a.uid == nil {
		return ""
	}
	return *a.uid
}

func (a genericAccessor) SetUID(uid types.UID) {
	if a.uid == nil {
		return
	}
	*a.uid = uid
}

func (a genericAccessor) APIVersion() string {
	return *a.apiVersion
}

func (a genericAccessor) SetAPIVersion(version string) {
	*a.apiVersion = version
}

func (a genericAccessor) Kind() string {
	return *a.kind
}

func (a genericAccessor) SetKind(kind string) {
	*a.kind = kind
}

func (a genericAccessor) ResourceVersion() string {
	return *a.resourceVersion
}

func (a genericAccessor) SetResourceVersion(version string) {
	*a.resourceVersion = version
}

func (a genericAccessor) SelfLink() string {
	return *a.selfLink
}

func (a genericAccessor) SetSelfLink(selfLink string) {
	*a.selfLink = selfLink
}

func (a genericAccessor) Labels() map[string]string {
	if a.labels == nil {
		return nil
	}
	return *a.labels
}

func (a genericAccessor) SetLabels(labels map[string]string) {
	*a.labels = labels
}

func (a genericAccessor) Annotations() map[string]string {
	if a.annotations == nil {
		return nil
	}
	return *a.annotations
}

func (a genericAccessor) SetAnnotations(annotations map[string]string) {
	*a.annotations = annotations
}

// extractFromTypeMeta extracts pointers to version and kind fields from an object
func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
		return err
	}
	return nil
}

// extractFromObjectMeta extracts pointers to metadata fields from an object
func extractFromObjectMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "Namespace", &a.namespace); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Name", &a.name); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "UID", &a.uid); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "ResourceVersion", &a.resourceVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "SelfLink", &a.selfLink); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Labels", &a.labels); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Annotations", &a.annotations); err != nil {
		return err
	}
	return nil
}

// extractFromObjectMeta extracts pointers to metadata fields from a list object
func extractFromListMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "ResourceVersion", &a.resourceVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "SelfLink", &a.selfLink); err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix spelling typo in comments<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

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

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

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

package meta

import (
	"fmt"
	"reflect"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/conversion"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
)

// Accessor takes an arbitrary object pointer and returns meta.Interface.
// obj must be a pointer to an API type. An error is returned if the minimum
// required fields are missing. Fields that are not required return the default
// value and are a no-op if set.
// TODO: add a fast path for *TypeMeta and *ObjectMeta for internal objects
func Accessor(obj interface{}) (Interface, error) {
	v, err := conversion.EnforcePtr(obj)
	if err != nil {
		return nil, err
	}
	t := v.Type()
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
	}

	typeMeta := v.FieldByName("TypeMeta")
	if !typeMeta.IsValid() {
		return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
	}

	a := &genericAccessor{}
	if err := extractFromTypeMeta(typeMeta, a); err != nil {
		return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
	}

	objectMeta := v.FieldByName("ObjectMeta")
	if objectMeta.IsValid() {
		// look for the ObjectMeta fields
		if err := extractFromObjectMeta(objectMeta, a); err != nil {
			return nil, fmt.Errorf("unable to find object fields on %#v: %v", objectMeta, err)
		}
	} else {
		listMeta := v.FieldByName("ListMeta")
		if listMeta.IsValid() {
			// look for the ListMeta fields
			if err := extractFromListMeta(listMeta, a); err != nil {
				return nil, fmt.Errorf("unable to find list fields on %#v: %v", listMeta, err)
			}
		} else {
			// look for the older TypeMeta with all metadata
			if err := extractFromObjectMeta(typeMeta, a); err != nil {
				return nil, fmt.Errorf("unable to find object fields on %#v: %v", typeMeta, err)
			}
		}
	}

	return a, nil
}

// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
// and Kind of an in-memory internal object.
// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
// api conventions).
func TypeAccessor(obj interface{}) (TypeInterface, error) {
	v, err := conversion.EnforcePtr(obj)
	if err != nil {
		return nil, err
	}
	t := v.Type()
	if v.Kind() != reflect.Struct {
		return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
	}

	typeMeta := v.FieldByName("TypeMeta")
	if !typeMeta.IsValid() {
		return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
	}
	a := &genericAccessor{}
	if err := extractFromTypeMeta(typeMeta, a); err != nil {
		return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
	}
	return a, nil
}

// NewAccessor returns a MetadataAccessor that can retrieve
// or manipulate resource version on objects derived from core API
// metadata concepts.
func NewAccessor() MetadataAccessor {
	return resourceAccessor{}
}

// resourceAccessor implements ResourceVersioner and SelfLinker.
type resourceAccessor struct{}

func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Kind(), nil
}

func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetKind(kind)
	return nil
}

func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.APIVersion(), nil
}

func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetAPIVersion(version)
	return nil
}

func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Namespace(), nil
}

func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetNamespace(namespace)
	return nil
}

func (resourceAccessor) Name(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.Name(), nil
}

func (resourceAccessor) SetName(obj runtime.Object, name string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetName(name)
	return nil
}

func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.UID(), nil
}

func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetUID(uid)
	return nil
}

func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.SelfLink(), nil
}

func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetSelfLink(selfLink)
	return nil
}

func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.Labels(), nil
}

func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetLabels(labels)
	return nil
}

func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return nil, err
	}
	return accessor.Annotations(), nil
}

func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetAnnotations(annotations)
	return nil
}

func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
	accessor, err := Accessor(obj)
	if err != nil {
		return "", err
	}
	return accessor.ResourceVersion(), nil
}

func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
	accessor, err := Accessor(obj)
	if err != nil {
		return err
	}
	accessor.SetResourceVersion(version)
	return nil
}

// genericAccessor contains pointers to strings that can modify an arbitrary
// struct and implements the Accessor interface.
type genericAccessor struct {
	namespace       *string
	name            *string
	uid             *types.UID
	apiVersion      *string
	kind            *string
	resourceVersion *string
	selfLink        *string
	labels          *map[string]string
	annotations     *map[string]string
}

func (a genericAccessor) Namespace() string {
	if a.namespace == nil {
		return ""
	}
	return *a.namespace
}

func (a genericAccessor) SetNamespace(namespace string) {
	if a.namespace == nil {
		return
	}
	*a.namespace = namespace
}

func (a genericAccessor) Name() string {
	if a.name == nil {
		return ""
	}
	return *a.name
}

func (a genericAccessor) SetName(name string) {
	if a.name == nil {
		return
	}
	*a.name = name
}

func (a genericAccessor) UID() types.UID {
	if a.uid == nil {
		return ""
	}
	return *a.uid
}

func (a genericAccessor) SetUID(uid types.UID) {
	if a.uid == nil {
		return
	}
	*a.uid = uid
}

func (a genericAccessor) APIVersion() string {
	return *a.apiVersion
}

func (a genericAccessor) SetAPIVersion(version string) {
	*a.apiVersion = version
}

func (a genericAccessor) Kind() string {
	return *a.kind
}

func (a genericAccessor) SetKind(kind string) {
	*a.kind = kind
}

func (a genericAccessor) ResourceVersion() string {
	return *a.resourceVersion
}

func (a genericAccessor) SetResourceVersion(version string) {
	*a.resourceVersion = version
}

func (a genericAccessor) SelfLink() string {
	return *a.selfLink
}

func (a genericAccessor) SetSelfLink(selfLink string) {
	*a.selfLink = selfLink
}

func (a genericAccessor) Labels() map[string]string {
	if a.labels == nil {
		return nil
	}
	return *a.labels
}

func (a genericAccessor) SetLabels(labels map[string]string) {
	*a.labels = labels
}

func (a genericAccessor) Annotations() map[string]string {
	if a.annotations == nil {
		return nil
	}
	return *a.annotations
}

func (a genericAccessor) SetAnnotations(annotations map[string]string) {
	*a.annotations = annotations
}

// extractFromTypeMeta extracts pointers to version and kind fields from an object
func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
		return err
	}
	return nil
}

// extractFromObjectMeta extracts pointers to metadata fields from an object
func extractFromObjectMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "Namespace", &a.namespace); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Name", &a.name); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "UID", &a.uid); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "ResourceVersion", &a.resourceVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "SelfLink", &a.selfLink); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Labels", &a.labels); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "Annotations", &a.annotations); err != nil {
		return err
	}
	return nil
}

// extractFromObjectMeta extracts pointers to metadata fields from a list object
func extractFromListMeta(v reflect.Value, a *genericAccessor) error {
	if err := runtime.FieldPtr(v, "ResourceVersion", &a.resourceVersion); err != nil {
		return err
	}
	if err := runtime.FieldPtr(v, "SelfLink", &a.selfLink); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package handler

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/m-lab/annotation-service/metrics"
	"github.com/m-lab/etl/schema"
)

// A mutex to make sure that we are not reading from the dataset while
// trying to update it
var currentDataMutex = &sync.RWMutex{}

// A function to set up any handlers that are needed, including url
// handlers and pubsub handlers
func SetupHandlers() {
	http.HandleFunc("/annotate", Annotate)
	go waitForDownloaderMessages()
}

// Annotate is a URL handler that looks up IP address and puts
// metadata out to the response encoded in json format.
func Annotate(w http.ResponseWriter, r *http.Request) {
	// Setup timers and counters for prometheus metrics.
	timerStart := time.Now()
	defer func(tStart time.Time) {
		metrics.Metrics_requestTimes.Observe(float64(time.Since(tStart).Nanoseconds()))
	}(timerStart)
	metrics.Metrics_activeRequests.Inc()
	defer metrics.Metrics_activeRequests.Dec()

	_, err := ValidateAndParse(r)
	if err != nil {
		fmt.Fprintf(w, "Invalid request")
	} else {
		// Fake response
		currentDataMutex.RLock()
		defer currentDataMutex.RUnlock()
		fmt.Fprintf(w, `{"Geo":{"city": "%s", "postal_code":"10583"},"ASN":{}}`, "Not A Real City")
		// TODO: Figure out which table to use
		// TODO: Handle request
	}
}

// ValidateAndParse takes a request and validates the URL parameters,
// verifying that it has a valid ip address and time. Then, it uses
// that to construct a RequestData struct and returns the pointer.
func ValidateAndParse(r *http.Request) (*schema.RequestData, error) {
	query := r.URL.Query()

	time_milli, err := strconv.ParseInt(query.Get("since_epoch"), 10, 64)
	if err != nil {
		return nil, errors.New("Invalid time")
	}

	ip := query.Get("ip_addr")

	newIP := net.ParseIP(ip)
	if newIP == nil {
		return nil, errors.New("Invalid IP address")
	}
	if newIP.To4() != nil {
		return &schema.RequestData{ip, 4, time.Unix(time_milli, 0)}, nil
	}
	return &schema.RequestData{ip, 6, time.Unix(time_milli, 0)}, nil
}

func BatchAnnotate(w http.ResponseWriter, r *http.Request) {

}

func BatchValidateAndParse(source io.Reader) ([]schema.RequestData, error) {
	return nil, nil
}

func GetMetadataForSingleIP(request *schema.RequestData) *schema.MetaData {
	return nil
}
<commit_msg>Added back in BatchValidateAndParse.<commit_after>package handler

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"strconv"
	"sync"
	"time"

	"github.com/m-lab/annotation-service/metrics"
	"github.com/m-lab/etl/schema"
)

// A mutex to make sure that we are not reading from the dataset while
// trying to update it
var currentDataMutex = &sync.RWMutex{}

// A function to set up any handlers that are needed, including url
// handlers and pubsub handlers
func SetupHandlers() {
	http.HandleFunc("/annotate", Annotate)
	go waitForDownloaderMessages()
}

// Annotate is a URL handler that looks up IP address and puts
// metadata out to the response encoded in json format.
func Annotate(w http.ResponseWriter, r *http.Request) {
	// Setup timers and counters for prometheus metrics.
	timerStart := time.Now()
	defer func(tStart time.Time) {
		metrics.Metrics_requestTimes.Observe(float64(time.Since(tStart).Nanoseconds()))
	}(timerStart)
	metrics.Metrics_activeRequests.Inc()
	defer metrics.Metrics_activeRequests.Dec()

	_, err := ValidateAndParse(r)
	if err != nil {
		fmt.Fprintf(w, "Invalid request")
	} else {
		// Fake response
		currentDataMutex.RLock()
		defer currentDataMutex.RUnlock()
		fmt.Fprintf(w, `{"Geo":{"city": "%s", "postal_code":"10583"},"ASN":{}}`, "Not A Real City")
		// TODO: Figure out which table to use
		// TODO: Handle request
	}
}

// ValidateAndParse takes a request and validates the URL parameters,
// verifying that it has a valid ip address and time. Then, it uses
// that to construct a RequestData struct and returns the pointer.
func ValidateAndParse(r *http.Request) (*schema.RequestData, error) {
	query := r.URL.Query()

	time_milli, err := strconv.ParseInt(query.Get("since_epoch"), 10, 64)
	if err != nil {
		return nil, errors.New("Invalid time")
	}

	ip := query.Get("ip_addr")

	newIP := net.ParseIP(ip)
	if newIP == nil {
		return nil, errors.New("Invalid IP address")
	}
	if newIP.To4() != nil {
		return &schema.RequestData{ip, 4, time.Unix(time_milli, 0)}, nil
	}
	return &schema.RequestData{ip, 6, time.Unix(time_milli, 0)}, nil
}

func BatchAnnotate(w http.ResponseWriter, r *http.Request) {

}

func BatchValidateAndParse(source io.Reader) ([]RequestData, error) {
	jsonBuffer, err := ioutil.ReadAll(source)
	validatedData := []RequestData{}
	if err != nil {
		return nil, err
	}
	uncheckedData := []struct {
		ip      string
		unix_ts int64
	}{}

	err = json.Unmarshal(jsonBuffer, &uncheckedData)
	if err != nil {
		return nil, err
	}
	for _, data := range uncheckedData {
		newIP := net.ParseIP(data.ip)
		if newIP == nil {
			return nil, errors.New("Invalid IP address.")
		}
		ipType := 6
		if newIP.To4() != nil {
			ipType = 4
		}
		validatedData = append(validatedData, RequestData{data.ip, ipType, time.Unix(data.unix_ts, 0)})
	}
	return validatedData, nil
}

func GetMetadataForSingleIP(request *schema.RequestData) *schema.MetaData {
	return nil
}
<|endoftext|>