<commit_before>package md3

import (
	"bytes"
	"fmt"
	"io"
	"log"
)

const (
	maxQPath       = 64
	maxFrameLength = 16

	md3HeaderIdent  = "IDP3"
	md3SurfaceIdent = md3HeaderIdent
	md3MaxVersion   = 15
	md3VertexSize   = 8
)

type surfaceHeader struct {
	name string

	flags int32 // Unused.

	num_frames    int32
	num_shaders   int32
	num_verts     int32
	num_triangles int32

	ofs_triangles int32
	ofs_shaders   int32
	ofs_st        int32
	ofs_xyznormal int32
	ofs_end       int32
}

type fileHeader struct {
	name string

	version int32
	flags   int32 // Unused.

	num_frames   int32
	num_tags     int32
	num_surfaces int32
	num_skins    int32 // Unused.

	ofs_frames   int32
	ofs_tags     int32
	ofs_surfaces int32
	ofs_eof      int32
}

func Read(data []byte) (*Model, error) {
	var (
		header *fileHeader
		err    error
	)

	r := bytes.NewReader(data)
	header, err = readMD3Header(r)
	if err != nil {
		log.Println("Error reading header:", err)
		return nil, err
	}

	model := new(Model)
	surfaces := make([]*Surface, 0, 1)

	model.name = header.name

	surfaceOutput := readSurfaceList(data[header.ofs_surfaces:], int(header.num_surfaces))
	tagOutput := readTagList(data[header.ofs_tags:], int(header.num_tags), int(header.num_frames))
	frameOutput := readFrameList(data[header.ofs_frames:], int(header.num_frames))

	for completions := header.num_surfaces + 1; completions > 0; completions-- {
		select {
		case surface := <-surfaceOutput:
			if surface != nil {
				surfaces = append(surfaces, surface)
			}
		case tags := <-tagOutput:
			model.tags = tags
		case frames := <-frameOutput:
			model.frames = frames
		}
	}

	model.surfaces = surfaces

	return model, nil
}

func readTagList(data []byte, count int, numFrames int) <-chan []*Tag {
	output := make(chan []*Tag)

	go func(output chan<- []*Tag) {
		// defer close(output)

		r := bytes.NewReader(data)
		tagMap := make(map[string]*Tag)
		tags := make([]*Tag, 0, count)
		var ok bool
		var tag *Tag
		var frame TagFrame
		var name string
		var err error
		var numTagsToRead = count * numFrames

		for i := 0; i < numTagsToRead; i++ {
			name, frame, err = readTag(r)

			if err != nil {
				log.Println("Error reading tag list:", err)
				break
			}

			if tag, ok = tagMap[name]; !ok {
				tag = new(Tag)
				tag.name = name
				tags = append(tags, tag)
				tagMap[name] = tag
			}

			tag.frames = append(tag.frames, frame)
		}

		output <- tags
	}(output)

	return output
}

func readTag(r io.Reader) (string, TagFrame, error) {
	var err error
	var name string
	var frame TagFrame

	name, err = readNulString(r, maxQPath)
	if err != nil {
		return name, frame, err
	}

	vecPointers := [...]*Vec3{
		&frame.Origin,
		&frame.XOrientation,
		&frame.YOrientation,
		&frame.ZOrientation,
	}

	for _, ptr := range vecPointers {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return name, frame, err
		}
	}

	return name, frame, nil
}

func readMD3Header(r io.Reader) (*fileHeader, error) {
	header := new(fileHeader)
	var ident string
	var err error

	ident, err = readFixedString(r, 4)
	switch {
	case err != nil:
		log.Println("Error reading header identifier", err)
		return nil, err
	case ident != md3HeaderIdent:
		return nil, fmt.Errorf("MD3 header identifier is %q, should be %q", ident, md3HeaderIdent)
	}

	header.version, err = readS32(r)
	switch {
	case err != nil:
		log.Println("Error reading header version", err)
		return nil, err
	case header.version > md3MaxVersion:
		return nil, fmt.Errorf("MD3 header version (%d) exceeds max version (%d)", header.version, md3MaxVersion)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		log.Println("Error reading header model name", err)
		return nil, err
	}

	s32Fields := [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_tags,
		&header.num_surfaces,
		&header.num_skins,
		&header.ofs_frames,
		&header.ofs_tags,
		&header.ofs_surfaces,
		&header.ofs_eof,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readSurfaceHeader(r io.Reader) (*surfaceHeader, error) {
	var err error
	var ident string

	header := new(surfaceHeader)

	ident, err = readFixedString(r, 4)
	if err != nil {
		return nil, err
	} else if ident != md3SurfaceIdent {
		return nil, fmt.Errorf("Surface header identifier is %q, should be %q", ident, md3SurfaceIdent)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		return nil, err
	}

	s32Fields := [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_shaders,
		&header.num_verts,
		&header.num_triangles,
		&header.ofs_triangles,
		&header.ofs_shaders,
		&header.ofs_st,
		&header.ofs_xyznormal,
		&header.ofs_end,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readVertex(r io.Reader) (Vertex, error) {
	var result Vertex
	var err error

	result.Origin, err = readF16Vec3(r)
	if err != nil {
		return result, err
	}

	result.Normal, err = readSphereNormal(r)

	return result, err
}

func readXYZNormals(r io.Reader, count int) ([]Vertex, error) {
	vertices := make([]Vertex, count)
	for index := range vertices {
		var err error
		vertices[index], err = readVertex(r)
		if err != nil {
			return nil, err
		}
	}
	return vertices, nil
}

func readTriangle(r io.Reader) (Triangle, error) {
	var err error
	var tri Triangle

	for _, ptr := range []*int32{&tri.A, &tri.B, &tri.C} {
		if *ptr, err = readS32(r); err != nil {
			break
		}
	}

	return tri, err
}

func readTriangleList(data []byte, count int) <-chan []Triangle {
	output := make(chan []Triangle)
	go func(output chan<- []Triangle) {
		var err error
		tris := make([]Triangle, count)
		r := bytes.NewReader(data)
		for index := range tris {
			tris[index], err = readTriangle(r)

			if err != nil {
				output <- nil
				log.Println("Error reading triangles:", err)
				return
			}
		}

		output <- tris
	}(output)
	return output
}

func readTexCoordList(data []byte, count int) <-chan []TexCoord {
	output := make(chan []TexCoord)
	go func(output chan<- []TexCoord) {
		var err error
		tcs := make([]TexCoord, count)
		r := bytes.NewReader(data)
		for index := range tcs {
			tc := TexCoord{}

			tc.S, err = readF32(r)
			if err != nil {
				break
			}

			tc.T, err = readF32(r)
			if err != nil {
				break
			}

			tcs[index] = tc
		}

		if err != nil {
			log.Println("Error reading texcoords:", err)
		}

		output <- tcs
	}()
	return output
}

func readShaderList(data []byte, count int) <-chan []Shader {
	output := make(chan []Shader)
	go func() {
		var err error
		shaders := make([]Shader, count)
		r := bytes.NewReader(data)
		for index := range shaders {
			shader := Shader{}

			shader.Name, err = readNulString(r, maxQPath)
			if err != nil {
				break
			}

			shader.Index, err = readS32(r)
			if err != nil {
				break
			}

			shaders[index] = shader
		}

		if err != nil {
			log.Println("Error reading shaders:", err)
		}

		output <- shaders
	}()
	return output
}

func readSurfaceList(data []byte, count int) <-chan *Surface {
	output := make(chan *Surface)
	go func(data []byte, output chan<- *Surface) {
		for index := 0; index < count; index++ {
			reader := bytes.NewReader(data[:])
			header, err := readSurfaceHeader(reader)
			if err != nil {
				log.Println("Error reading surface header:", err)
				break
			}

			go func(data []byte) {
				surf, err := readSurface(header, data)
				if err != nil {
					log.Printf("Error reading surface %q: %s\n", header.name, err)
				}

				surf.name = header.name
				surf.numFrames = int(header.num_frames)

				output <- surf
			}(data)

			data = data[header.ofs_end:]
		}
	}(data, output)
	return output
}

func readSurface(h *surfaceHeader, data []byte) (*Surface, error) {
	surface := new(Surface)

	triangleOutput := readTriangleList(data[h.ofs_triangles:], int(h.num_triangles))
	shaderOutput := readShaderList(data[h.ofs_shaders:], int(h.num_shaders))
	texcoordOutput := readTexCoordList(data[h.ofs_st:], int(h.num_verts))
	verticesOutput := readVertexFrames(data[h.ofs_xyznormal:], int(h.num_frames), int(h.num_verts))

	surface.vertices = <-verticesOutput
	surface.triangles = <-triangleOutput
	surface.texcoords = <-texcoordOutput
	surface.shaders = <-shaderOutput

	return surface, nil
}

type frameAndVertices struct {
	index    int
	vertices []Vertex
}

func readVertexFrames(data []byte, numVertices, numFrames int) <-chan [][]Vertex {
	output := make(chan [][]Vertex)

	go func(data []byte, output chan<- [][]Vertex) {
		var (
			frameVertices = make([][]Vertex, numFrames)
			frameReceiver = make(chan frameAndVertices)
			frameSize     = numVertices * md3VertexSize
		)

		for frame := range frameVertices {
			go func(frame int, data []byte) {
				reader := bytes.NewReader(data)
				vertices, err := readXYZNormals(reader, numVertices)
				if err != nil {
					log.Println("Error reading vertices:", err)
				}
				frameReceiver <- frameAndVertices{frame, vertices}
			}(frame, data[:frameSize])
			data = data[frameSize:]
		}

		for _ = range frameVertices {
			pack := <-frameReceiver
			frameVertices[pack.index] = pack.vertices
		}

		output <- frameVertices
	}(data, output)

	return output
}

func readFrame(r io.Reader) (*Frame, error) {
	var err error
	frame := new(Frame)

	frame.name, err = readNulString(r, maxFrameLength)
	if err != nil {
		return nil, err
	}

	for _, ptr := range []*Vec3{&frame.min, &frame.max, &frame.origin} {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return nil, err
		}
	}

	frame.radius, err = readF32(r)
	if err != nil {
		return nil, err
	}

	return frame, nil
}

func readFrameList(data []byte, count int) <-chan []*Frame {
	output := make(chan []*Frame)

	go func(output chan<- []*Frame) {
		// defer close(output)

		var err error
		reader := bytes.NewReader(data)
		frames := make([]*Frame, count)

		for index := range frames {
			frames[index], err = readFrame(reader)

			if err != nil {
				log.Println("Error reading frame list:", err)
				frames = nil
				break
			}
		}

		output <- frames
	}(output)

	return output
}
<commit_msg>Pass outputs as arguments to goroutines.<commit_after>package md3

import (
	"bytes"
	"fmt"
	"io"
	"log"
)

const (
	maxQPath       = 64
	maxFrameLength = 16

	md3HeaderIdent  = "IDP3"
	md3SurfaceIdent = md3HeaderIdent
	md3MaxVersion   = 15
	md3VertexSize   = 8
)

type surfaceHeader struct {
	name string

	flags int32 // Unused.

	num_frames    int32
	num_shaders   int32
	num_verts     int32
	num_triangles int32

	ofs_triangles int32
	ofs_shaders   int32
	ofs_st        int32
	ofs_xyznormal int32
	ofs_end       int32
}

type fileHeader struct {
	name string

	version int32
	flags   int32 // Unused.

	num_frames   int32
	num_tags     int32
	num_surfaces int32
	num_skins    int32 // Unused.

	ofs_frames   int32
	ofs_tags     int32
	ofs_surfaces int32
	ofs_eof      int32
}

func Read(data []byte) (*Model, error) {
	var (
		header *fileHeader
		err    error
	)

	r := bytes.NewReader(data)
	header, err = readMD3Header(r)
	if err != nil {
		log.Println("Error reading header:", err)
		return nil, err
	}

	model := new(Model)
	surfaces := make([]*Surface, 0, 1)

	model.name = header.name

	surfaceOutput := readSurfaceList(data[header.ofs_surfaces:], int(header.num_surfaces))
	tagOutput := readTagList(data[header.ofs_tags:], int(header.num_tags), int(header.num_frames))
	frameOutput := readFrameList(data[header.ofs_frames:], int(header.num_frames))

	for completions := header.num_surfaces + 1; completions > 0; completions-- {
		select {
		case surface := <-surfaceOutput:
			if surface != nil {
				surfaces = append(surfaces, surface)
			}
		case tags := <-tagOutput:
			model.tags = tags
		case frames := <-frameOutput:
			model.frames = frames
		}
	}

	model.surfaces = surfaces

	return model, nil
}

func readTagList(data []byte, count int, numFrames int) <-chan []*Tag {
	output := make(chan []*Tag)

	go func(output chan<- []*Tag) {
		// defer close(output)

		r := bytes.NewReader(data)
		tagMap := make(map[string]*Tag)
		tags := make([]*Tag, 0, count)
		var ok bool
		var tag *Tag
		var frame TagFrame
		var name string
		var err error
		var numTagsToRead = count * numFrames

		for i := 0; i < numTagsToRead; i++ {
			name, frame, err = readTag(r)

			if err != nil {
				log.Println("Error reading tag list:", err)
				break
			}

			if tag, ok = tagMap[name]; !ok {
				tag = new(Tag)
				tag.name = name
				tags = append(tags, tag)
				tagMap[name] = tag
			}

			tag.frames = append(tag.frames, frame)
		}

		output <- tags
	}(output)

	return output
}

func readTag(r io.Reader) (string, TagFrame, error) {
	var err error
	var name string
	var frame TagFrame

	name, err = readNulString(r, maxQPath)
	if err != nil {
		return name, frame, err
	}

	vecPointers := [...]*Vec3{
		&frame.Origin,
		&frame.XOrientation,
		&frame.YOrientation,
		&frame.ZOrientation,
	}

	for _, ptr := range vecPointers {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return name, frame, err
		}
	}

	return name, frame, nil
}

func readMD3Header(r io.Reader) (*fileHeader, error) {
	header := new(fileHeader)
	var ident string
	var err error

	ident, err = readFixedString(r, 4)
	switch {
	case err != nil:
		log.Println("Error reading header identifier", err)
		return nil, err
	case ident != md3HeaderIdent:
		return nil, fmt.Errorf("MD3 header identifier is %q, should be %q", ident, md3HeaderIdent)
	}

	header.version, err = readS32(r)
	switch {
	case err != nil:
		log.Println("Error reading header version", err)
		return nil, err
	case header.version > md3MaxVersion:
		return nil, fmt.Errorf("MD3 header version (%d) exceeds max version (%d)", header.version, md3MaxVersion)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		log.Println("Error reading header model name", err)
		return nil, err
	}

	s32Fields := [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_tags,
		&header.num_surfaces,
		&header.num_skins,
		&header.ofs_frames,
		&header.ofs_tags,
		&header.ofs_surfaces,
		&header.ofs_eof,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readSurfaceHeader(r io.Reader) (*surfaceHeader, error) {
	var err error
	var ident string

	header := new(surfaceHeader)

	ident, err = readFixedString(r, 4)
	if err != nil {
		return nil, err
	} else if ident != md3SurfaceIdent {
		return nil, fmt.Errorf("Surface header identifier is %q, should be %q", ident, md3SurfaceIdent)
	}

	header.name, err = readNulString(r, maxQPath)
	if err != nil {
		return nil, err
	}

	s32Fields := [...]*int32{
		&header.flags,
		&header.num_frames,
		&header.num_shaders,
		&header.num_verts,
		&header.num_triangles,
		&header.ofs_triangles,
		&header.ofs_shaders,
		&header.ofs_st,
		&header.ofs_xyznormal,
		&header.ofs_end,
	}

	for _, x := range s32Fields {
		*x, err = readS32(r)
		if err != nil {
			return nil, err
		}
	}

	return header, nil
}

func readVertex(r io.Reader) (Vertex, error) {
	var result Vertex
	var err error

	result.Origin, err = readF16Vec3(r)
	if err != nil {
		return result, err
	}

	result.Normal, err = readSphereNormal(r)

	return result, err
}

func readXYZNormals(r io.Reader, count int) ([]Vertex, error) {
	vertices := make([]Vertex, count)
	for index := range vertices {
		var err error
		vertices[index], err = readVertex(r)
		if err != nil {
			return nil, err
		}
	}
	return vertices, nil
}

func readTriangle(r io.Reader) (Triangle, error) {
	var err error
	var tri Triangle

	for _, ptr := range []*int32{&tri.A, &tri.B, &tri.C} {
		if *ptr, err = readS32(r); err != nil {
			break
		}
	}

	return tri, err
}

func readTriangleList(data []byte, count int) <-chan []Triangle {
	output := make(chan []Triangle)
	go func(output chan<- []Triangle) {
		var err error
		tris := make([]Triangle, count)
		r := bytes.NewReader(data)
		for index := range tris {
			tris[index], err = readTriangle(r)

			if err != nil {
				output <- nil
				log.Println("Error reading triangles:", err)
				return
			}
		}

		output <- tris
	}(output)
	return output
}

func readTexCoordList(data []byte, count int) <-chan []TexCoord {
	output := make(chan []TexCoord)
	go func(output chan<- []TexCoord) {
		var err error
		tcs := make([]TexCoord, count)
		r := bytes.NewReader(data)
		for index := range tcs {
			tc := TexCoord{}

			tc.S, err = readF32(r)
			if err != nil {
				break
			}

			tc.T, err = readF32(r)
			if err != nil {
				break
			}

			tcs[index] = tc
		}

		if err != nil {
			log.Println("Error reading texcoords:", err)
		}

		output <- tcs
	}(output)
	return output
}

func readShaderList(data []byte, count int) <-chan []Shader {
	output := make(chan []Shader)
	go func(output chan<- []Shader) {
		var err error
		shaders := make([]Shader, count)
		r := bytes.NewReader(data)
		for index := range shaders {
			shader := Shader{}

			shader.Name, err = readNulString(r, maxQPath)
			if err != nil {
				break
			}

			shader.Index, err = readS32(r)
			if err != nil {
				break
			}

			shaders[index] = shader
		}

		if err != nil {
			log.Println("Error reading shaders:", err)
		}

		output <- shaders
	}(output)
	return output
}

func readSurfaceList(data []byte, count int) <-chan *Surface {
	output := make(chan *Surface)
	go func(data []byte, output chan<- *Surface) {
		for index := 0; index < count; index++ {
			reader := bytes.NewReader(data[:])
			header, err := readSurfaceHeader(reader)
			if err != nil {
				log.Println("Error reading surface header:", err)
				break
			}

			go func(data []byte) {
				surf, err := readSurface(header, data)
				if err != nil {
					log.Printf("Error reading surface %q: %s\n", header.name, err)
				}

				surf.name = header.name
				surf.numFrames = int(header.num_frames)

				output <- surf
			}(data)

			data = data[header.ofs_end:]
		}
	}(data, output)
	return output
}

func readSurface(h *surfaceHeader, data []byte) (*Surface, error) {
	surface := new(Surface)

	triangleOutput := readTriangleList(data[h.ofs_triangles:], int(h.num_triangles))
	shaderOutput := readShaderList(data[h.ofs_shaders:], int(h.num_shaders))
	texcoordOutput := readTexCoordList(data[h.ofs_st:], int(h.num_verts))
	verticesOutput := readVertexFrames(data[h.ofs_xyznormal:], int(h.num_frames), int(h.num_verts))

	surface.vertices = <-verticesOutput
	surface.triangles = <-triangleOutput
	surface.texcoords = <-texcoordOutput
	surface.shaders = <-shaderOutput

	return surface, nil
}

type frameAndVertices struct {
	index    int
	vertices []Vertex
}

func readVertexFrames(data []byte, numVertices, numFrames int) <-chan [][]Vertex {
	output := make(chan [][]Vertex)

	go func(data []byte, output chan<- [][]Vertex) {
		var (
			frameVertices = make([][]Vertex, numFrames)
			frameReceiver = make(chan frameAndVertices)
			frameSize     = numVertices * md3VertexSize
		)

		for frame := range frameVertices {
			go func(frame int, data []byte) {
				reader := bytes.NewReader(data)
				vertices, err := readXYZNormals(reader, numVertices)
				if err != nil {
					log.Println("Error reading vertices:", err)
				}
				frameReceiver <- frameAndVertices{frame, vertices}
			}(frame, data[:frameSize])
			data = data[frameSize:]
		}

		for _ = range frameVertices {
			pack := <-frameReceiver
			frameVertices[pack.index] = pack.vertices
		}

		output <- frameVertices
	}(data, output)

	return output
}

func readFrame(r io.Reader) (*Frame, error) {
	var err error
	frame := new(Frame)

	frame.name, err = readNulString(r, maxFrameLength)
	if err != nil {
		return nil, err
	}

	for _, ptr := range []*Vec3{&frame.min, &frame.max, &frame.origin} {
		*ptr, err = readF32Vec3(r)
		if err != nil {
			return nil, err
		}
	}

	frame.radius, err = readF32(r)
	if err != nil {
		return nil, err
	}

	return frame, nil
}

func readFrameList(data []byte, count int) <-chan []*Frame {
	output := make(chan []*Frame)

	go func(output chan<- []*Frame) {
		// defer close(output)

		var err error
		reader := bytes.NewReader(data)
		frames := make([]*Frame, count)

		for index := range frames {
			frames[index], err = readFrame(reader)

			if err != nil {
				log.Println("Error reading frame list:", err)
				frames = nil
				break
			}
		}

		output <- frames
	}(output)

	return output
}
<|endoftext|>


<commit_before>package atlas

import (
	"encoding/json"
	"fmt"
	"github.com/sendgrid/rest"
)

var (
	allTypes = []string{
		"dns",
		"http",
		"ntp",
		"ping",
		"sslcert",
		"traceroute",
		"wifi",
	}
)

// -- private

// checkType verify that the type is valid
func checkType(d Definition) (valid bool) {
	valid = false
	for _, t := range allTypes {
		if d.Type == t {
			valid = true
			break
		}
	}
	return
}

// checkTypeAs is a shortcut
func checkTypeAs(d Definition, t string) bool {
	valid := checkType(d)
	return valid && d.Type == t
}

// checkAllTypesAs is a generalization of checkTypeAs
func checkAllTypesAs(dl []Definition, t string) (valid bool) {
	valid = true
	for _, d := range dl {
		if d.Type != t {
			valid = false
			break
		}
	}
	return
}

// measurementList is our main answer
type measurementList struct {
	Count    int
	Next     string
	Previous string
	Results  []Measurement
}

// fetch the given resource
func fetchOneMeasurementPage(MeasurementEP string, opts map[string]string) (raw *measurementList, err error) {
	hdrs := make(map[string]string)
	req := rest.Request{
		BaseURL:     MeasurementEP,
		Method:      rest.Get,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req=%s qp=%#v", MeasurementEP, opts)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
		return
	}

	raw = &measurementList{}
	err = json.Unmarshal([]byte(r.Body), raw)
	//log.Printf("Count=%d raw=%v", raw.Count, r)
	//log.Printf(">> rawlist=%+v r=%+v Next=|%s|", rawlist, r, rawlist.Next)
	return
}

// -- public

// GetMeasurement gets info for a single one
func GetMeasurement(id int) (m *Measurement, err error) {
	measurementEP := apiEndpoint + "/measurements"

	key, ok := HasAPIKey()

	// Add at least one option, the APIkey if present
	hdrs := make(map[string]string)
	opts := make(map[string]string)

	if ok {
		opts["key"] = key
	}

	req := rest.Request{
		BaseURL:     measurementEP + fmt.Sprintf("/%d", id),
		Method:      rest.Get,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req: %#v", req)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
		return
	}

	m = &Measurement{}
	err = json.Unmarshal([]byte(r.Body), m)
	//log.Printf("json: %#v\n", m)
	return
}

// DeleteMeasurement stops (not really deletes) a given measurement
func DeleteMeasurement(id int) (err error) {
	measurementEP := apiEndpoint + "/measurements"

	key, ok := HasAPIKey()

	// Add at least one option, the APIkey if present
	hdrs := make(map[string]string)
	opts := make(map[string]string)

	if ok {
		opts["key"] = key
	}

	req := rest.Request{
		BaseURL:     measurementEP + fmt.Sprintf("/%d", id),
		Method:      rest.Delete,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req: %#v", req)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
	}
	return
}

// GetMeasurements gets info for a set
func GetMeasurements(opts map[string]string) (m []Measurement, err error) {
	measurementEP := apiEndpoint + "/measurements/"

	key, ok := HasAPIKey()

	// Add APIKey if set
	if ok {
		opts["key"] = key
	}

	// First call
	rawlist, err := fetchOneMeasurementPage(measurementEP, opts)

	// Empty answer
	if rawlist.Count == 0 {
		return nil, fmt.Errorf("empty measurement list")
	}

	var res []Measurement

	res = append(res, rawlist.Results...)
	if rawlist.Next != "" {
		// We have pagination
		for pn := getPageNum(rawlist.Next); rawlist.Next != ""; pn = getPageNum(rawlist.Next) {
			opts["page"] = pn

			rawlist, err = fetchOneMeasurementPage(measurementEP, opts)
			if err != nil {
				return
			}

			res = append(res, rawlist.Results...)
		}
	}
	m = res
	return
}

// Measurement-related methods

// Start is for starting a given measurement
func (m *Measurement) Start(id int) (err error) {
	return nil
}
<commit_msg>Use a map[] instead of an array, should be faster.<commit_after>package atlas

import (
	"encoding/json"
	"fmt"
	"github.com/sendgrid/rest"
)

var (
	allTypes = map[string]bool{
		"dns":        true,
		"http":       true,
		"ntp":        true,
		"ping":       true,
		"SSL":        true,
		"traceroute": true,
		"wifi":       true,
	}
)

// -- private

// checkType verify that the type is valid
func checkType(d Definition) (valid bool) {
	_, ok := allTypes[d.Type]
	return ok
}

// checkTypeAs is a shortcut
func checkTypeAs(d Definition, t string) bool {
	valid := checkType(d)
	return valid && d.Type == t
}

// checkAllTypesAs is a generalization of checkTypeAs
func checkAllTypesAs(dl []Definition, t string) (valid bool) {
	valid = true
	for _, d := range dl {
		if d.Type != t {
			valid = false
			break
		}
	}
	return
}

// measurementList is our main answer
type measurementList struct {
	Count    int
	Next     string
	Previous string
	Results  []Measurement
}

// fetch the given resource
func fetchOneMeasurementPage(MeasurementEP string, opts map[string]string) (raw *measurementList, err error) {
	hdrs := make(map[string]string)
	req := rest.Request{
		BaseURL:     MeasurementEP,
		Method:      rest.Get,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req=%s qp=%#v", MeasurementEP, opts)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
		return
	}

	raw = &measurementList{}
	err = json.Unmarshal([]byte(r.Body), raw)
	//log.Printf("Count=%d raw=%v", raw.Count, r)
	//log.Printf(">> rawlist=%+v r=%+v Next=|%s|", rawlist, r, rawlist.Next)
	return
}

// -- public

// GetMeasurement gets info for a single one
func GetMeasurement(id int) (m *Measurement, err error) {
	measurementEP := apiEndpoint + "/measurements"

	key, ok := HasAPIKey()

	// Add at least one option, the APIkey if present
	hdrs := make(map[string]string)
	opts := make(map[string]string)

	if ok {
		opts["key"] = key
	}

	req := rest.Request{
		BaseURL:     measurementEP + fmt.Sprintf("/%d", id),
		Method:      rest.Get,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req: %#v", req)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
		return
	}

	m = &Measurement{}
	err = json.Unmarshal([]byte(r.Body), m)
	//log.Printf("json: %#v\n", m)
	return
}

// DeleteMeasurement stops (not really deletes) a given measurement
func DeleteMeasurement(id int) (err error) {
	measurementEP := apiEndpoint + "/measurements"

	key, ok := HasAPIKey()

	// Add at least one option, the APIkey if present
	hdrs := make(map[string]string)
	opts := make(map[string]string)

	if ok {
		opts["key"] = key
	}

	req := rest.Request{
		BaseURL:     measurementEP + fmt.Sprintf("/%d", id),
		Method:      rest.Delete,
		Headers:     hdrs,
		QueryParams: opts,
	}

	//log.Printf("req: %#v", req)
	r, err := rest.API(req)
	if err != nil {
		err = fmt.Errorf("err: %v - r:%v\n", err, r)
	}
	return
}

// GetMeasurements gets info for a set
func GetMeasurements(opts map[string]string) (m []Measurement, err error) {
	measurementEP := apiEndpoint + "/measurements/"

	key, ok := HasAPIKey()

	// Add APIKey if set
	if ok {
		opts["key"] = key
	}

	// First call
	rawlist, err := fetchOneMeasurementPage(measurementEP, opts)

	// Empty answer
	if rawlist.Count == 0 {
		return nil, fmt.Errorf("empty measurement list")
	}

	var res []Measurement

	res = append(res, rawlist.Results...)
	if rawlist.Next != "" {
		// We have pagination
		for pn := getPageNum(rawlist.Next); rawlist.Next != ""; pn = getPageNum(rawlist.Next) {
			opts["page"] = pn

			rawlist, err = fetchOneMeasurementPage(measurementEP, opts)
			if err != nil {
				return
			}

			res = append(res, rawlist.Results...)
		}
	}
	m = res
	return
}

// Measurement-related methods

// Start is for starting a given measurement
func (m *Measurement) Start(id int) (err error) {
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"encoding/json"
	"testing"
)

func TestTermQuery(t *testing.T) {
	q := NewTermQuery("user", "ki")
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"term":{"user":"ki"}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}

func TestTermQueryWithOptions(t *testing.T) {
	q := NewTermQuery("user", "ki")
	q = q.Boost(2.79)
	q = q.QueryName("my_tq")
	q = q.CaseInsensitive(true)
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"term":{"user":{"_name":"my_tq","boost":2.79,"case_insensitive":true,"value":"ki"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}
<commit_msg>Add another test for TermQuery<commit_after>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"encoding/json"
	"testing"
)

func TestTermQuery(t *testing.T) {
	q := NewTermQuery("user", "ki")
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"term":{"user":"ki"}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}

func TestTermQueryWithCaseInsensitive(t *testing.T) {
	q := NewTermQuery("user", "ki").CaseInsensitive(true)
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"term":{"user":{"case_insensitive":true,"value":"ki"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}

func TestTermQueryWithOptions(t *testing.T) {
	q := NewTermQuery("user", "ki")
	q = q.Boost(2.79)
	q = q.QueryName("my_tq")
	q = q.CaseInsensitive(true)
	src, err := q.Source()
	if err != nil {
		t.Fatal(err)
	}
	data, err := json.Marshal(src)
	if err != nil {
		t.Fatalf("marshaling to JSON failed: %v", err)
	}
	got := string(data)
	expected := `{"term":{"user":{"_name":"my_tq","boost":2.79,"case_insensitive":true,"value":"ki"}}}`
	if got != expected {
		t.Errorf("expected\n%s\n,got:\n%s", expected, got)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/vpp-agent/clientv1/linux/localclient"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	linux_intf "github.com/ligato/vpp-agent/plugins/linuxplugin/model/interfaces"

	"github.com/contiv/vpp/plugins/kvdbproxy"
	"github.com/gogo/protobuf/proto"
	"github.com/ligato/cn-infra/datasync"
	"github.com/prometheus/common/log"
	"golang.org/x/net/context"
	"strconv"
	"sync"
)

type remoteCNIserver struct {
	logging.Logger
	sync.Mutex

	proxy *kvdbproxy.Plugin

	// bdCreated is true if the bridge domain on the vpp for apackets is configured
	bdCreated bool
	// counter of connected containers. It is used for generating afpacket names
	// and assigned ip addresses.
	counter int
	// created afPacket that are in the bridge domain
	// map is used to support quick removal
	afPackets map[string]interface{}
}

const (
	resultOk           uint32 = 0
	resultErr          uint32 = 1
	vethNameMaxLen            = 15
	bdName                    = "bd1"
	bviName                   = "loop1"
	ipMask                    = "24"
	ipPrefix                  = "10.0.0"
	bviIP                     = ipPrefix + ".254/" + ipMask
	afPacketNamePrefix        = "afpacket"
)

func newRemoteCNIServer(logger logging.Logger, proxy *kvdbproxy.Plugin) *remoteCNIserver {
	return &remoteCNIserver{Logger: logger, afPackets: map[string]interface{}{}, proxy: proxy}
}

// Add connects the container to the network.
func (s *remoteCNIserver) Add(ctx context.Context, request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Info("Add request received ", *request)
	return s.configureContainerConnectivity(request)
}

func (s *remoteCNIserver) Delete(ctx context.Context, request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Info("Delete request received ", *request)
	return s.unconfigureContainerConnectivity(request)
}

// configureContainerConnectivity creates veth pair where
// one end is ns1 namespace, the other is in default namespace.
// the end in default namespace is connected to VPP using afpacket.
func (s *remoteCNIserver) configureContainerConnectivity(request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Lock()
	defer s.Unlock()

	changes := map[string]proto.Message{}
	s.counter++

	veth1 := s.veth1FromRequest(request)
	veth2 := s.veth2FromRequest(request)
	afpacket := s.afpacketFromRequest(request)

	log.Info("veth1", veth1)
	log.Info("veth2", veth2)
	log.Info("afpacket", afpacket)

	// create entry in the afpacket map => add afpacket into bridge domain
	s.afPackets[afpacket.Name] = nil

	bd := s.bridgeDomain()

	log.Info("Bridge domain", *bd)

	txn := localclient.DataChangeRequest("CNI").
		Put().
		LinuxInterface(veth1).
		LinuxInterface(veth2).
		VppInterface(afpacket)

	if !s.bdCreated {
		bvi := s.bviInterface()
		txn.VppInterface(bvi)
		changes[vpp_intf.InterfaceKey(bvi.Name)] = bvi
	}

	err := txn.BD(bd).
		Send().ReceiveReply()

	res := resultOk
	errMsg := ""
	if err == nil {
		s.bdCreated = true

		changes[linux_intf.InterfaceKey(veth1.Name)] = veth1
		changes[linux_intf.InterfaceKey(veth2.Name)] = veth2
		changes[vpp_intf.InterfaceKey(afpacket.Name)] = afpacket
		changes[l2.BridgeDomainKey(bd.Name)] = bd
		s.persistPutChanges(changes)

	} else {
		res = resultErr
		errMsg = err.Error()
		delete(s.afPackets, afpacket.Name)
	}

	reply := &cni.CNIReply{
		Result: res,
		Error:  errMsg,
		Interfaces: []*cni.CNIReply_Interface{
			{
				Name:    veth1.Name,
				Sandbox: veth1.Namespace.Name,
				IpAddresses: []*cni.CNIReply_Interface_IP{
					{
						Version: cni.CNIReply_Interface_IP_IPV4,
						Address: veth1.IpAddresses[0],
						Gateway: bviIP,
					},
				},
			},
		},
		Routes: []*cni.CNIReply_Route{
			{
				Dst: "0.0.0.0/0",
				Gw:  bviIP,
			},
		},
	}
	return reply, err
}

func (s *remoteCNIserver) unconfigureContainerConnectivity(request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Lock()
	defer s.Unlock()

	veth1 := s.veth1NameFromRequest(request)
	veth2 := s.veth2NameFromRequest(request)
	afpacket := s.afpacketNameFromRequest(request)
	s.Info("Removing", []string{veth1, veth2, afpacket})
	// remove afpacket from bridge domain
	delete(s.afPackets, afpacket)

	bd := s.bridgeDomain()

	log.Info("Bridge domain", *bd)

	err := localclient.DataChangeRequest("CNI").
		Delete().
		LinuxInterface(veth1).
		LinuxInterface(veth2).
		VppInterface(afpacket).
		Put().BD(bd).
		Send().ReceiveReply()

	res := resultOk
	errMsg := ""
	if err == nil {
		s.persistDeleteChanges([]string{veth1, veth2, afpacket})
		s.persistPutChanges(map[string]proto.Message{bd.Name: bd})
	} else {
		res = resultErr
		errMsg = err.Error()
	}

	reply := &cni.CNIReply{
		Result: res,
		Error:  errMsg,
	}
	return reply, err
}

func (s *remoteCNIserver) persistPutChanges(changes map[string]proto.Message) {
	for k, v := range changes {
		s.proxy.AddIgnoreEntry(k, datasync.Put)
		s.proxy.Put(k, v)
	}
}

func (s *remoteCNIserver) persistDeleteChanges(removedKeys []string) {
	for _, k := range removedKeys {
		s.proxy.AddIgnoreEntry(k, datasync.Delete)
		s.proxy.Delete(k)
	}
}

//
// +-------------------------------------------------+
// |                                                 |
// |                         +----------------+      |
// |                         |     Loop1      |      |
// |      Bridge domain      |     BVI        |      |
// |                         +----------------+      |
// |    +------+       +------+                      |
// |    |  AF1 |       | AFn  |                      |
// |    |      |  ...  |      |                      |
// |    +------+       +------+                      |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        v
// +------------+
// |            |
// | Veth2      |
// |            |
// +------------+
//        ^
//        |
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Veth1      |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+

func (s *remoteCNIserver) veth1NameFromRequest(request *cni.CNIRequest) string {
	return request.InterfaceName + request.ContainerId
}

func (s *remoteCNIserver) veth1HostIfNameFromRequest(request *cni.CNIRequest) string {
	return request.InterfaceName
}

func (s *remoteCNIserver) veth2NameFromRequest(request *cni.CNIRequest) string {
	if len(request.ContainerId) > vethNameMaxLen {
		return request.ContainerId[:vethNameMaxLen]
	}
	return request.ContainerId
}

func (s *remoteCNIserver) afpacketNameFromRequest(request *cni.CNIRequest) string {
	return afPacketNamePrefix + s.veth2NameFromRequest(request)
}

func (s *remoteCNIserver) ipAddrForContainer() string {
	return ipPrefix + "." + strconv.Itoa(s.counter) + "/" + ipMask
}

func (s *remoteCNIserver) veth1FromRequest(request *cni.CNIRequest) *linux_intf.LinuxInterfaces_Interface {
	return &linux_intf.LinuxInterfaces_Interface{
		Name:       s.veth1NameFromRequest(request),
		Type:       linux_intf.LinuxInterfaces_VETH,
		Enabled:    true,
		HostIfName: s.veth1HostIfNameFromRequest(request),
		Veth: &linux_intf.LinuxInterfaces_Interface_Veth{
			PeerIfName: s.veth2NameFromRequest(request),
		},
		IpAddresses: []string{s.ipAddrForContainer()},
		Namespace: &linux_intf.LinuxInterfaces_Interface_Namespace{
			Type:     linux_intf.LinuxInterfaces_Interface_Namespace_FILE_REF_NS,
			Filepath: request.NetworkNamespace,
		},
	}
}

func (s *remoteCNIserver) veth2FromRequest(request *cni.CNIRequest) *linux_intf.LinuxInterfaces_Interface {
	return &linux_intf.LinuxInterfaces_Interface{
		Name:       s.veth2NameFromRequest(request),
		Type:       linux_intf.LinuxInterfaces_VETH,
		Enabled:    true,
		HostIfName: s.veth2NameFromRequest(request),
		Veth: &linux_intf.LinuxInterfaces_Interface_Veth{
			PeerIfName: s.veth1NameFromRequest(request),
		},
	}
}

func (s *remoteCNIserver) afpacketFromRequest(request *cni.CNIRequest) *vpp_intf.Interfaces_Interface {
	return &vpp_intf.Interfaces_Interface{
		Name:    s.afpacketNameFromRequest(request),
		Type:    vpp_intf.InterfaceType_AF_PACKET_INTERFACE,
		Enabled: true,
		Afpacket: &vpp_intf.Interfaces_Interface_Afpacket{
			HostIfName: s.veth2NameFromRequest(request),
		},
	}
}

func (s *remoteCNIserver) bridgeDomain() *l2.BridgeDomains_BridgeDomain {
	var ifs = []*l2.BridgeDomains_BridgeDomain_Interfaces{
		{
			Name: bviName,
			BridgedVirtualInterface: true,
		}}

	for af := range s.afPackets {
		ifs = append(ifs, &l2.BridgeDomains_BridgeDomain_Interfaces{
			Name: af,
			BridgedVirtualInterface: false,
		})
	}

	return &l2.BridgeDomains_BridgeDomain{
		Name:                bdName,
		Flood:               true,
		UnknownUnicastFlood: true,
		Forward:             true,
		Learn:               true,
		ArpTermination:      false,
		MacAge:              0, /* means disable aging */
		Interfaces:          ifs,
	}
}

func (s *remoteCNIserver) bviInterface() *vpp_intf.Interfaces_Interface {
	return &vpp_intf.Interfaces_Interface{
		Name:        bviName,
		Enabled:     true,
		IpAddresses: []string{bviIP},
		Type:        vpp_intf.InterfaceType_SOFTWARE_LOOPBACK,
	}
}
<commit_msg>contiv plugin cleanup<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 contiv

import (
	"github.com/contiv/vpp/plugins/contiv/model/cni"
	"github.com/ligato/cn-infra/logging"
	"github.com/ligato/vpp-agent/clientv1/linux/localclient"
	vpp_intf "github.com/ligato/vpp-agent/plugins/defaultplugins/ifplugin/model/interfaces"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/l2plugin/model/l2"
	linux_intf "github.com/ligato/vpp-agent/plugins/linuxplugin/model/interfaces"

	"github.com/contiv/vpp/plugins/kvdbproxy"
	"github.com/gogo/protobuf/proto"
	"github.com/ligato/cn-infra/datasync"
	"golang.org/x/net/context"
	"strconv"
	"sync"
)

type remoteCNIserver struct {
	logging.Logger
	sync.Mutex

	proxy *kvdbproxy.Plugin

	// bdCreated is true if the bridge domain on the vpp for apackets is configured
	bdCreated bool
	// counter of connected containers. It is used for generating afpacket names
	// and assigned ip addresses.
	counter int
	// created afPacket that are in the bridge domain
	// map is used to support quick removal
	afPackets map[string]interface{}
}

const (
	resultOk           uint32 = 0
	resultErr          uint32 = 1
	vethNameMaxLen            = 15
	bdName                    = "bd1"
	bviName                   = "loop1"
	ipMask                    = "24"
	ipPrefix                  = "10.0.0"
	bviIP                     = ipPrefix + ".254/" + ipMask
	afPacketNamePrefix        = "afpacket"
)

func newRemoteCNIServer(logger logging.Logger, proxy *kvdbproxy.Plugin) *remoteCNIserver {
	return &remoteCNIserver{Logger: logger, afPackets: map[string]interface{}{}, proxy: proxy}
}

// Add connects the container to the network.
func (s *remoteCNIserver) Add(ctx context.Context, request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Info("Add request received ", *request)
	return s.configureContainerConnectivity(request)
}

func (s *remoteCNIserver) Delete(ctx context.Context, request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Info("Delete request received ", *request)
	return s.unconfigureContainerConnectivity(request)
}

// configureContainerConnectivity creates veth pair where
// one end is ns1 namespace, the other is in default namespace.
// the end in default namespace is connected to VPP using afpacket.
func (s *remoteCNIserver) configureContainerConnectivity(request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Lock()
	defer s.Unlock()

	var (
		res        = resultOk
		errMsg     = ""
		createdIfs []*cni.CNIReply_Interface
	)

	changes := map[string]proto.Message{}
	s.counter++

	veth1 := s.veth1FromRequest(request)
	veth2 := s.veth2FromRequest(request)
	afpacket := s.afpacketFromRequest(request)

	// create entry in the afpacket map => add afpacket into bridge domain
	s.afPackets[afpacket.Name] = nil

	bd := s.bridgeDomain()

	s.WithFields(logging.Fields{"veth1": veth1, "veth2": veth2, "afpacket": afpacket, "bd": bd}).Info("Configuring")

	txn := localclient.DataChangeRequest("CNI").
		Put().
		LinuxInterface(veth1).
		LinuxInterface(veth2).
		VppInterface(afpacket)

	if !s.bdCreated {
		bvi := s.bviInterface()
		txn.VppInterface(bvi)
		changes[vpp_intf.InterfaceKey(bvi.Name)] = bvi
	}

	err := txn.BD(bd).
		Send().ReceiveReply()

	if err == nil {
		s.bdCreated = true

		changes[linux_intf.InterfaceKey(veth1.Name)] = veth1
		changes[linux_intf.InterfaceKey(veth2.Name)] = veth2
		changes[vpp_intf.InterfaceKey(afpacket.Name)] = afpacket
		changes[l2.BridgeDomainKey(bd.Name)] = bd
		s.persistPutChanges(changes)

		createdIfs = s.createdInterfaces(veth1)

	} else {
		res = resultErr
		errMsg = err.Error()
		delete(s.afPackets, afpacket.Name)
	}

	reply := &cni.CNIReply{
		Result:     res,
		Error:      errMsg,
		Interfaces: createdIfs,
		Routes: []*cni.CNIReply_Route{
			{
				Dst: "0.0.0.0/0",
				Gw:  bviIP,
			},
		},
	}
	return reply, err
}

func (s *remoteCNIserver) unconfigureContainerConnectivity(request *cni.CNIRequest) (*cni.CNIReply, error) {
	s.Lock()
	defer s.Unlock()

	var (
		res    = resultOk
		errMsg = ""
	)

	veth1 := s.veth1NameFromRequest(request)
	veth2 := s.veth2NameFromRequest(request)
	afpacket := s.afpacketNameFromRequest(request)
	s.Info("Removing", []string{veth1, veth2, afpacket})
	// remove afpacket from bridge domain
	delete(s.afPackets, afpacket)

	bd := s.bridgeDomain()

	err := localclient.DataChangeRequest("CNI").
		Delete().
		LinuxInterface(veth1).
		LinuxInterface(veth2).
		VppInterface(afpacket).
		Put().BD(bd).
		Send().ReceiveReply()

	if err == nil {
		s.persistDeleteChanges([]string{linux_intf.InterfaceKey(veth1),
			linux_intf.InterfaceKey(veth2),
			vpp_intf.InterfaceKey(afpacket),
		})
		s.persistPutChanges(map[string]proto.Message{l2.BridgeDomainKey(bd.Name): bd})
	} else {
		res = resultErr
		errMsg = err.Error()
	}

	reply := &cni.CNIReply{
		Result: res,
		Error:  errMsg,
	}
	return reply, err
}

func (s *remoteCNIserver) persistPutChanges(changes map[string]proto.Message) {
	for k, v := range changes {
		s.proxy.AddIgnoreEntry(k, datasync.Put)
		s.proxy.Put(k, v)
	}
}

func (s *remoteCNIserver) persistDeleteChanges(removedKeys []string) {
	for _, key := range removedKeys {
		s.proxy.AddIgnoreEntry(key, datasync.Delete)
		s.proxy.Delete(key)
	}
}

// createdInterfaces fills the structure containing data of created interfaces
// that is a part of reply to Add request
func (s *remoteCNIserver) createdInterfaces(veth *linux_intf.LinuxInterfaces_Interface) []*cni.CNIReply_Interface {
	return []*cni.CNIReply_Interface{
		{
			Name:    veth.Name,
			Sandbox: veth.Namespace.Name,
			IpAddresses: []*cni.CNIReply_Interface_IP{
				{
					Version: cni.CNIReply_Interface_IP_IPV4,
					Address: veth.IpAddresses[0],
					Gateway: bviIP,
				},
			},
		},
	}
}

//
// +-------------------------------------------------+
// |                                                 |
// |                         +----------------+      |
// |                         |     Loop1      |      |
// |      Bridge domain      |     BVI        |      |
// |                         +----------------+      |
// |    +------+       +------+                      |
// |    |  AF1 |       | AFn  |                      |
// |    |      |  ...  |      |                      |
// |    +------+       +------+                      |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        v
// +------------+
// |            |
// | Veth2      |
// |            |
// +------------+
//        ^
//        |
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Veth1      |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+

func (s *remoteCNIserver) veth1NameFromRequest(request *cni.CNIRequest) string {
	return request.InterfaceName + request.ContainerId
}

func (s *remoteCNIserver) veth1HostIfNameFromRequest(request *cni.CNIRequest) string {
	return request.InterfaceName
}

func (s *remoteCNIserver) veth2NameFromRequest(request *cni.CNIRequest) string {
	if len(request.ContainerId) > vethNameMaxLen {
		return request.ContainerId[:vethNameMaxLen]
	}
	return request.ContainerId
}

func (s *remoteCNIserver) afpacketNameFromRequest(request *cni.CNIRequest) string {
	return afPacketNamePrefix + s.veth2NameFromRequest(request)
}

func (s *remoteCNIserver) ipAddrForContainer() string {
	return ipPrefix + "." + strconv.Itoa(s.counter) + "/" + ipMask
}

func (s *remoteCNIserver) veth1FromRequest(request *cni.CNIRequest) *linux_intf.LinuxInterfaces_Interface {
	return &linux_intf.LinuxInterfaces_Interface{
		Name:       s.veth1NameFromRequest(request),
		Type:       linux_intf.LinuxInterfaces_VETH,
		Enabled:    true,
		HostIfName: s.veth1HostIfNameFromRequest(request),
		Veth: &linux_intf.LinuxInterfaces_Interface_Veth{
			PeerIfName: s.veth2NameFromRequest(request),
		},
		IpAddresses: []string{s.ipAddrForContainer()},
		Namespace: &linux_intf.LinuxInterfaces_Interface_Namespace{
			Type:     linux_intf.LinuxInterfaces_Interface_Namespace_FILE_REF_NS,
			Filepath: request.NetworkNamespace,
		},
	}
}

func (s *remoteCNIserver) veth2FromRequest(request *cni.CNIRequest) *linux_intf.LinuxInterfaces_Interface {
	return &linux_intf.LinuxInterfaces_Interface{
		Name:       s.veth2NameFromRequest(request),
		Type:       linux_intf.LinuxInterfaces_VETH,
		Enabled:    true,
		HostIfName: s.veth2NameFromRequest(request),
		Veth: &linux_intf.LinuxInterfaces_Interface_Veth{
			PeerIfName: s.veth1NameFromRequest(request),
		},
	}
}

func (s *remoteCNIserver) afpacketFromRequest(request *cni.CNIRequest) *vpp_intf.Interfaces_Interface {
	return &vpp_intf.Interfaces_Interface{
		Name:    s.afpacketNameFromRequest(request),
		Type:    vpp_intf.InterfaceType_AF_PACKET_INTERFACE,
		Enabled: true,
		Afpacket: &vpp_intf.Interfaces_Interface_Afpacket{
			HostIfName: s.veth2NameFromRequest(request),
		},
	}
}

func (s *remoteCNIserver) bridgeDomain() *l2.BridgeDomains_BridgeDomain {
	var ifs = []*l2.BridgeDomains_BridgeDomain_Interfaces{
		{
			Name: bviName,
			BridgedVirtualInterface: true,
		}}

	for af := range s.afPackets {
		ifs = append(ifs, &l2.BridgeDomains_BridgeDomain_Interfaces{
			Name: af,
			BridgedVirtualInterface: false,
		})
	}

	return &l2.BridgeDomains_BridgeDomain{
		Name:                bdName,
		Flood:               true,
		UnknownUnicastFlood: true,
		Forward:             true,
		Learn:               true,
		ArpTermination:      false,
		MacAge:              0, /* means disable aging */
		Interfaces:          ifs,
	}
}

func (s *remoteCNIserver) bviInterface() *vpp_intf.Interfaces_Interface {
	return &vpp_intf.Interfaces_Interface{
		Name:        bviName,
		Enabled:     true,
		IpAddresses: []string{bviIP},
		Type:        vpp_intf.InterfaceType_SOFTWARE_LOOPBACK,
	}
}
<|endoftext|>


<commit_before>package goftp

import "testing"
import "os"

//import "strings"

//import "strings"

import "fmt"

var goodServer string
var uglyServer string
var badServer string

func init() {
	//ProFTPD 1.3.5 Server (Debian)
	goodServer = "bo.mirror.garr.it:21"

	//Symantec EMEA FTP Server
	badServer = "ftp.packardbell.com:21"

	//Unknown server
	uglyServer = "ftp.musicbrainz.org:21"
}

func active(host string) (msg string) {
	var err error
	var connection *FTP

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}
	code, response := connection.RawPassiveCmd("LIST .")
	if code < 0 || code > 299 {
		return fmt.Sprintf("Can't list -> %d", code)
	}
	fmt.Println(response)
	connection.Close()
	return ""

}

func standard(host string) (msg string) {
	var err error
	var connection *FTP

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}
	code, str := connection.RawCmd("FEAT")
	if code < 0 || code > 299 {
		return fmt.Sprintf("Can't FEAT -> %d", code)
	} else {
		fmt.Println(str)
	}

	connection.Close()
	return ""
}

func walk(host string) (msg string) {
	var err error
	var connection *FTP
	deep := 5

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}

	err = connection.Walk("/", func(path string, info os.FileMode, err error) error {
		fmt.Print("--->")
		fmt.Println(path)
		return nil

	}, deep)
	//if err != nil && !strings.HasPrefix(err.Error(), "550") {
	if err != nil {
		return "Can't walk ->" + err.Error()
	}
	connection.Close()
	return ""

}

func TestLogin_good(t *testing.T) {
	str := standard(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestLogin_bad(t *testing.T) {
	str := standard(badServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestLogin_ugly(t *testing.T) {
	str := standard(uglyServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

//

func TestWalk_good(t *testing.T) {
	str := walk(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestWalk_bad(t *testing.T) {
	str := walk(badServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestWalk_ugly(t *testing.T) {
	str := walk(uglyServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestActiveCommand(t *testing.T) {
	str := active(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestGetFilesListOnGoodServer(t *testing.T) {
	var err error
	var connection *FTP
	host := uglyServer

	if connection, err = Connect(host); err != nil {
		t.Error("Can't connect ->" + err.Error())
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		t.Error("Can't login ->" + err.Error())
	}
	files, dirs, links, err := connection.GetFilesList("")

	if err != nil {
		t.Error("Can't parse file list ->" + err.Error())
	}

	fmt.Println(files)
	fmt.Println("---")
	fmt.Println(dirs)
	fmt.Println("---")
	fmt.Println(links)

	connection.Close()
}

type getCodeResult struct {
	code           int
	beginMultiline bool
	err            error
}

func TestGetCode(t *testing.T) {
	var tests = []struct {
		input string
		want  getCodeResult
	}{
		{"220 test", getCodeResult{220, false, nil}},
		{"220     test", getCodeResult{220, false, nil}},
		{"  220     test", getCodeResult{220, false, nil}},
		{"220- test", getCodeResult{220, true, nil}},
		{"220asdf test", getCodeResult{0, false, errNoCode}},
		{"", getCodeResult{0, false, errNoCode}},
		{"\r\n", getCodeResult{0, false, errNoCode}},
		{"123-Firstline", getCodeResult{123, true, nil}},
		{"123-First line", getCodeResult{123, true, nil}},
	}
	ftp := &FTP{}
	for _, test := range tests {
		code, beginMultiline, err := ftp.getCode(test.input)
		res := getCodeResult{code, beginMultiline, err}
		if res != test.want {
			t.Errorf("want: %#v, expected: %#v", test.want, res)
		}
	}
}

func TestHasCode(t *testing.T) {
	var tests = []struct {
		input string
		code  int
		want  bool
	}{
		{"220 test", 220, true},
		{"220     test", 220, true},
		{"  220     test", 220, true},
		{"220- test", 220, true},
		{"123-Firstline", 123, true},
		{"123-First line", 123, true},

		{"220asdf test", 220, false},
		{"", 220, false},
		{"\r\n", 220, false},
		{"220 test", 550, false},
		{"220     test", 550, false},
	}
	ftp := &FTP{}
	for _, test := range tests {
		hasCode := ftp.HasCode(test.input, test.code)
		if hasCode != test.want {
			t.Errorf("input %q, code: %d, want: %#v, expected: %#v", test.input,
				test.code, test.want, hasCode)
		}
	}
}
<commit_msg>decreased deep limit in test<commit_after>package goftp

import "testing"
import "os"

//import "strings"

//import "strings"

import "fmt"

var goodServer string
var uglyServer string
var badServer string

func init() {
	//ProFTPD 1.3.5 Server (Debian)
	//goodServer = "bo.mirror.garr.it:21"
	goodServer = "ftp.fu-berlin.de:21"

	//Symantec EMEA FTP Server
	badServer = "ftp.packardbell.com:21"

	//Unknown server
	uglyServer = "ftp.musicbrainz.org:21"
}

func active(host string) (msg string) {
	var err error
	var connection *FTP

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}
	code, response := connection.RawPassiveCmd("LIST .")
	if code < 0 || code > 299 {
		return fmt.Sprintf("Can't list -> %d", code)
	}
	fmt.Println(response)
	connection.Close()
	return ""

}

func standard(host string) (msg string) {
	var err error
	var connection *FTP

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}
	code, str := connection.RawCmd("FEAT")
	if code < 0 || code > 299 {
		return fmt.Sprintf("Can't FEAT -> %d", code)
	} else {
		fmt.Println(str)
	}

	connection.Close()
	return ""
}

func walk(host string) (msg string) {
	var err error
	var connection *FTP
	deep := 2
	filehit := 0

	if connection, err = Connect(host); err != nil {
		return "Can't connect ->" + err.Error()
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		return "Can't login ->" + err.Error()
	}

	err = connection.Walk("/", func(path string, info os.FileMode, err error) error {
		fmt.Print("--->")
		filehit = filehit + 1
		fmt.Println(path)
		return nil

	}, deep)
	//if err != nil && !strings.HasPrefix(err.Error(), "550") {
	if err != nil {
		return "Can't walk " + host + " ->" + err.Error()
	}
	if filehit < 1 {
		return "Can't walk " + host + " -> No file found"
	}

	connection.Close()
	return ""

}

func TestLogin_good(t *testing.T) {
	str := standard(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestLogin_bad(t *testing.T) {
	str := standard(badServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestLogin_ugly(t *testing.T) {
	str := standard(uglyServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

//

func TestWalk_good(t *testing.T) {
	str := walk(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestWalk_bad(t *testing.T) {
	str := walk(badServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestWalk_ugly(t *testing.T) {
	str := walk(uglyServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestActiveCommand(t *testing.T) {
	str := active(goodServer)
	if len(str) > 0 {
		t.Error(str)
	}
}

func TestGetFilesListOnGoodServer(t *testing.T) {
	var err error
	var connection *FTP
	host := uglyServer

	if connection, err = Connect(host); err != nil {
		t.Error("Can't connect ->" + err.Error())
	}
	if err = connection.Login("anonymous", "anonymous"); err != nil {
		t.Error("Can't login ->" + err.Error())
	}
	files, dirs, links, err := connection.GetFilesList("")

	if err != nil {
		t.Error("Can't parse file list ->" + err.Error())
	}

	fmt.Println(files)
	fmt.Println("---")
	fmt.Println(dirs)
	fmt.Println("---")
	fmt.Println(links)

	connection.Close()
}

type getCodeResult struct {
	code           int
	beginMultiline bool
	err            error
}

func TestGetCode(t *testing.T) {
	var tests = []struct {
		input string
		want  getCodeResult
	}{
		{"220 test", getCodeResult{220, false, nil}},
		{"220     test", getCodeResult{220, false, nil}},
		{"  220     test", getCodeResult{220, false, nil}},
		{"220- test", getCodeResult{220, true, nil}},
		{"220asdf test", getCodeResult{0, false, errNoCode}},
		{"", getCodeResult{0, false, errNoCode}},
		{"\r\n", getCodeResult{0, false, errNoCode}},
		{"123-Firstline", getCodeResult{123, true, nil}},
		{"123-First line", getCodeResult{123, true, nil}},
	}
	ftp := &FTP{}
	for _, test := range tests {
		code, beginMultiline, err := ftp.getCode(test.input)
		res := getCodeResult{code, beginMultiline, err}
		if res != test.want {
			t.Errorf("want: %#v, expected: %#v", test.want, res)
		}
	}
}

func TestHasCode(t *testing.T) {
	var tests = []struct {
		input string
		code  int
		want  bool
	}{
		{"220 test", 220, true},
		{"220     test", 220, true},
		{"  220     test", 220, true},
		{"220- test", 220, true},
		{"123-Firstline", 123, true},
		{"123-First line", 123, true},

		{"220asdf test", 220, false},
		{"", 220, false},
		{"\r\n", 220, false},
		{"220 test", 550, false},
		{"220     test", 550, false},
	}
	ftp := &FTP{}
	for _, test := range tests {
		hasCode := ftp.HasCode(test.input, test.code)
		if hasCode != test.want {
			t.Errorf("input %q, code: %d, want: %#v, expected: %#v", test.input,
				test.code, test.want, hasCode)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 server

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	genericapiserver "k8s.io/apiserver/pkg/server"
	"k8s.io/apiserver/pkg/server/filters"
	genericoptions "k8s.io/apiserver/pkg/server/options"
	kubeclientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	restclient "k8s.io/client-go/rest"
	"k8s.io/kube-aggregator/pkg/apiserver"

	"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1alpha1"
)

const defaultEtcdPathPrefix = "/registry/kube-aggregator.kubernetes.io/"

type AggregatorOptions struct {
	RecommendedOptions *genericoptions.RecommendedOptions

	// ProxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	ProxyClientCertFile string
	ProxyClientKeyFile  string

	StdOut io.Writer
	StdErr io.Writer
}

// NewCommandStartMaster provides a CLI handler for 'start master' command
func NewCommandStartAggregator(out, err io.Writer) *cobra.Command {
	o := &AggregatorOptions{
		RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, api.Scheme, api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)),

		StdOut: out,
		StdErr: err,
	}
	o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443

	cmd := &cobra.Command{
		Short: "Launch a API aggregator and proxy server",
		Long:  "Launch a API aggregator and proxy server",
		RunE: func(c *cobra.Command, args []string) error {
			if err := o.Complete(); err != nil {
				return err
			}
			if err := o.Validate(args); err != nil {
				return err
			}
			if err := o.RunAggregator(); err != nil {
				return err
			}
			return nil
		},
	}

	flags := cmd.Flags()
	o.RecommendedOptions.AddFlags(flags)
	flags.StringVar(&o.ProxyClientCertFile, "proxy-client-cert-file", o.ProxyClientCertFile, "client certificate used identify the proxy to the API server")
	flags.StringVar(&o.ProxyClientKeyFile, "proxy-client-key-file", o.ProxyClientKeyFile, "client certificate key used identify the proxy to the API server")

	return cmd
}

func (o AggregatorOptions) Validate(args []string) error {
	return nil
}

func (o *AggregatorOptions) Complete() error {
	return nil
}

func (o AggregatorOptions) RunAggregator() error {
	// TODO have a "real" external address
	if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil {
		return fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	serverConfig := genericapiserver.NewConfig().
		WithSerializer(api.Codecs)

	if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
		return err
	}
	serverConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
		sets.NewString("watch", "proxy"),
		sets.NewString("attach", "exec", "proxy", "log", "portforward"),
	)

	kubeconfig, err := restclient.InClusterConfig()
	if err != nil {
		return err
	}
	coreAPIServerClient, err := kubeclientset.NewForConfig(kubeconfig)
	if err != nil {
		return err
	}

	config := apiserver.Config{
		GenericConfig:       serverConfig,
		CoreAPIServerClient: coreAPIServerClient,
	}

	config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile)
	if err != nil {
		return err
	}
	config.ProxyClientKey, err = ioutil.ReadFile(o.ProxyClientKeyFile)
	if err != nil {
		return err
	}

	server, err := config.Complete().New()
	if err != nil {
		return err
	}
	server.GenericAPIServer.PrepareRun().Run(wait.NeverStop)

	return nil
}
<commit_msg>allow specification of core kubeconfig in aggregator<commit_after>/*
Copyright 2016 The Kubernetes 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 server

import (
	"fmt"
	"io"
	"io/ioutil"

	"github.com/spf13/cobra"

	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/wait"
	genericapiserver "k8s.io/apiserver/pkg/server"
	"k8s.io/apiserver/pkg/server/filters"
	genericoptions "k8s.io/apiserver/pkg/server/options"
	kubeclientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"k8s.io/kube-aggregator/pkg/apiserver"

	"k8s.io/kube-aggregator/pkg/apis/apiregistration/v1alpha1"
)

const defaultEtcdPathPrefix = "/registry/kube-aggregator.kubernetes.io/"

type AggregatorOptions struct {
	RecommendedOptions *genericoptions.RecommendedOptions

	// ProxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
	// this to confirm the proxy's identity
	ProxyClientCertFile string
	ProxyClientKeyFile  string

	// CoreAPIKubeconfig is a filename for a kubeconfig file to contact the core API server wtih
	// If it is not set, the in cluster config is used
	CoreAPIKubeconfig string

	StdOut io.Writer
	StdErr io.Writer
}

// NewCommandStartMaster provides a CLI handler for 'start master' command
func NewCommandStartAggregator(out, err io.Writer) *cobra.Command {
	o := &AggregatorOptions{
		RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, api.Scheme, api.Codecs.LegacyCodec(v1alpha1.SchemeGroupVersion)),

		StdOut: out,
		StdErr: err,
	}
	o.RecommendedOptions.SecureServing.ServingOptions.BindPort = 443

	cmd := &cobra.Command{
		Short: "Launch a API aggregator and proxy server",
		Long:  "Launch a API aggregator and proxy server",
		RunE: func(c *cobra.Command, args []string) error {
			if err := o.Complete(); err != nil {
				return err
			}
			if err := o.Validate(args); err != nil {
				return err
			}
			if err := o.RunAggregator(); err != nil {
				return err
			}
			return nil
		},
	}

	flags := cmd.Flags()
	o.RecommendedOptions.AddFlags(flags)
	flags.StringVar(&o.ProxyClientCertFile, "proxy-client-cert-file", o.ProxyClientCertFile, "client certificate used identify the proxy to the API server")
	flags.StringVar(&o.ProxyClientKeyFile, "proxy-client-key-file", o.ProxyClientKeyFile, "client certificate key used identify the proxy to the API server")
	flags.StringVar(&o.CoreAPIKubeconfig, "core-kubeconfig", o.CoreAPIKubeconfig, ""+
		"kubeconfig file pointing at the 'core' kubernetes server with enough rights to get,list,watch "+
		" services,endpoints.  If not set, the in-cluster config is used")
	return cmd
}

func (o AggregatorOptions) Validate(args []string) error {
	return nil
}

func (o *AggregatorOptions) Complete() error {
	return nil
}

func (o AggregatorOptions) RunAggregator() error {
	// TODO have a "real" external address
	if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost"); err != nil {
		return fmt.Errorf("error creating self-signed certificates: %v", err)
	}

	serverConfig := genericapiserver.NewConfig().
		WithSerializer(api.Codecs)

	if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil {
		return err
	}
	serverConfig.LongRunningFunc = filters.BasicLongRunningRequestCheck(
		sets.NewString("watch", "proxy"),
		sets.NewString("attach", "exec", "proxy", "log", "portforward"),
	)

	var kubeconfig *rest.Config
	var err error
	if len(o.CoreAPIKubeconfig) > 0 {
		loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: o.CoreAPIKubeconfig}
		loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})

		kubeconfig, err = loader.ClientConfig()

	} else {
		kubeconfig, err = rest.InClusterConfig()
	}
	if err != nil {
		return err
	}

	coreAPIServerClient, err := kubeclientset.NewForConfig(kubeconfig)
	if err != nil {
		return err
	}

	config := apiserver.Config{
		GenericConfig:       serverConfig,
		CoreAPIServerClient: coreAPIServerClient,
	}

	config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile)
	if err != nil {
		return err
	}
	config.ProxyClientKey, err = ioutil.ReadFile(o.ProxyClientKeyFile)
	if err != nil {
		return err
	}

	server, err := config.Complete().New()
	if err != nil {
		return err
	}
	server.GenericAPIServer.PrepareRun().Run(wait.NeverStop)

	return nil
}
<|endoftext|>


<commit_before>package dsdk

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	_path "path"
	"strings"
	"time"

	uuid "github.com/google/uuid"
)

const (
	LogInterval = int(time.Hour * 1)
	LastFile    = "last"
	LogFiltered = "dlogs.tar.gz"
)

var (
	EndLogging = make(chan bool)
)

type LogsUpload struct {
	Path string `json:"path,omitempty"`
}

type LogsUploadRequest struct {
	Ctxt  context.Context
	Files []string
}

func newLogsUpload(path string) *LogsUpload {
	return &LogsUpload{
		Path: _path.Join(path, "logs_upload"),
	}
}

func logsUpload(ctxt context.Context, file string) error {
	conn := GetConn(ctxt)
	tid, ok := ctxt.Value("tid").(string)
	if !ok {
		tid = "nil"
	}
	reqId := uuid.Must(uuid.NewRandom()).String()
	var err error
	if conn.apikey == "" {
		if _, err = conn.Login(ctxt); err != nil {
			return err
		}
	}
	key := conn.apikey
	conn.baseUrl.Path = _path.Join(conn.baseUrl.Path, "logs_upload")
	url := conn.baseUrl.String()

	var b bytes.Buffer
	w := multipart.NewWriter(&b)

	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()
	err = w.WriteField("ecosystem", "kubernetes")
	if err != nil {
		return err
	}

	fw, err := w.CreateFormFile("logs.tar.gz", file)
	if err != nil {
		return err
	}
	if _, err = io.Copy(fw, f); err != nil {
		return err
	}
	// Don't forget to close the multipart writer.
	// If you don't close it, your request will be missing the terminating boundary.
	w.Close()

	// Now that you have a form, you can submit it to your handler.
	req, err := http.NewRequest(http.MethodPut, url, &b)
	if err != nil {
		return err
	}
	// Don't forget to set the content type, this will contain the boundary.
	req.Header.Set("Content-Type", w.FormDataContentType())
	req.Header.Set("Auth-Token", key)

	// Submit the request
	client := &http.Client{}
	sheaders, err := json.Marshal(req.Header)
	if err != nil {
		Log().Errorf("Couldn't stringify headers, %s", req.Header)
	}
	Log().Debugf(strings.Join([]string{"\nDatera Trace ID: %s",
		"Datera Request ID: %s",
		"Datera Request URL: %s",
		"Datera Request Method: %s",
		"Datera Request Payload: %s",
		"Datera Request Headers: %s\n"}, "\n"),
		tid, reqId, url, http.MethodPut, req.Body, sheaders)
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	Log().Debugf("Status Code: %d", res.StatusCode)
	// Check the response
	if res.StatusCode != http.StatusOK {
		err = fmt.Errorf("bad status: %s", res.Status)
		bodyBytes, _ := ioutil.ReadAll(res.Body)
		Log().Error(err)
		Log().Error(string(bodyBytes))
		return err
	}
	return nil
}

func rotateLogs(rule string) error {
	if _, err := RunCmd("logrotate", rule); err != nil {
		return err
	}
	return nil
}

// For finer grained sleeping, interval is specified in seconds
func logSleeper(interval int) {
	for {
		if interval <= 0 {
			break
		}
		time.Sleep(time.Second * 1)
		interval--
	}
}

func (e *LogsUpload) Upload(ro *LogsUploadRequest) (*LogsUpload, *ApiErrorResponse, error) {
	return nil, nil, logsUpload(ro.Ctxt, ro.Files[0])
}

func (e *LogsUpload) LogUploadDaemon(rule, rotated string, interval int) error {
	for {
		if err := rotateLogs(rule); err != nil {
			return err
		}

		// Determine if filtered logs exist
		lf, err := os.Open(rotated)
		if err != nil {
			return err
		}
		defer os.Remove(rotated)
		defer lf.Close()
		fstat, err := lf.Stat()
		if err != nil {
			return err
		}
		// Even a single line of logs will be greater than 100 bytes
		if fstat.Size() > 100 {
			Log().Debug("Uploading logs")
			go func() {
				_, apierr, err := e.Upload(&LogsUploadRequest{Files: []string{rotated}})
				if apierr != nil {
					Log().Errorf("%s\n", Pretty(apierr))
				}
				if err != nil {
					Log().Error(err)
				}
			}()
		} else {
			Log().Debugf("No new filtered logs detected.  Size: %d\n", fstat.Size())
		}
		Log().Debugf("Logpush sleeping %d", interval)
		logSleeper(interval)
	}
}
<commit_msg>Modifications to log_upload to match driver interface<commit_after>package dsdk

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	_path "path"
	"strings"

	uuid "github.com/google/uuid"
)

var (
	EndLogging = make(chan bool)
)

type LogsUpload struct {
	Path string `json:"path,omitempty"`
}

type LogsUploadRequest struct {
	Ctxt  context.Context
	Files []string
}

func newLogsUpload(path string) *LogsUpload {
	return &LogsUpload{
		Path: _path.Join(path, "logs_upload"),
	}
}

func logsUpload(ctxt context.Context, file string) error {
	conn := GetConn(ctxt)
	tid, ok := ctxt.Value("tid").(string)
	if !ok {
		tid = "nil"
	}
	reqId := uuid.Must(uuid.NewRandom()).String()
	var err error
	if conn.apikey == "" {
		if _, err = conn.Login(ctxt); err != nil {
			return err
		}
	}
	key := conn.apikey
	conn.baseUrl.Path = _path.Join(conn.baseUrl.Path, "logs_upload")
	url := conn.baseUrl.String()

	var b bytes.Buffer
	w := multipart.NewWriter(&b)

	f, err := os.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()
	err = w.WriteField("ecosystem", "kubernetes")
	if err != nil {
		return err
	}

	fw, err := w.CreateFormFile("logs.tar.gz", file)
	if err != nil {
		return err
	}
	if _, err = io.Copy(fw, f); err != nil {
		return err
	}
	// Don't forget to close the multipart writer.
	// If you don't close it, your request will be missing the terminating boundary.
	w.Close()

	// Now that you have a form, you can submit it to your handler.
	req, err := http.NewRequest(http.MethodPut, url, &b)
	if err != nil {
		return err
	}
	// Don't forget to set the content type, this will contain the boundary.
	req.Header.Set("Content-Type", w.FormDataContentType())
	req.Header.Set("Auth-Token", key)

	// Submit the request
	client := &http.Client{}
	sheaders, err := json.Marshal(req.Header)
	if err != nil {
		Log().Errorf("Couldn't stringify headers, %s", req.Header)
	}
	Log().Debugf(strings.Join([]string{"\nDatera Trace ID: %s",
		"Datera Request ID: %s",
		"Datera Request URL: %s",
		"Datera Request Method: %s",
		"Datera Request Payload: %s",
		"Datera Request Headers: %s\n"}, "\n"),
		tid, reqId, url, http.MethodPut, req.Body, sheaders)
	res, err := client.Do(req)
	if err != nil {
		return err
	}
	Log().Debugf("Status Code: %d", res.StatusCode)
	// Check the response
	if res.StatusCode != http.StatusOK {
		err = fmt.Errorf("bad status: %s", res.Status)
		bodyBytes, _ := ioutil.ReadAll(res.Body)
		Log().Error(err)
		Log().Error(string(bodyBytes))
		return err
	}
	return nil
}

func rotateLogs(rule string) error {
	if _, err := RunCmd("logrotate", rule); err != nil {
		return err
	}
	return nil
}

func (e *LogsUpload) Upload(ro *LogsUploadRequest) (*LogsUpload, *ApiErrorResponse, error) {
	return nil, nil, logsUpload(ro.Ctxt, ro.Files[0])
}

func (e *LogsUpload) RotateUploadRemove(ctxt context.Context, rule, rotated string) error {
	if err := rotateLogs(rule); err != nil {
		return err
	}

	// Determine if filtered logs exist
	lf, err := os.Open(rotated)
	if err != nil {
		return err
	}
	defer os.Remove(rotated)
	defer lf.Close()
	fstat, err := lf.Stat()
	if err != nil {
		return err
	}
	// Even a single line of logs will be greater than 100 bytes
	if fstat.Size() > 100 {
		Log().Debug("Uploading logs")
		go func() {
			_, apierr, err := e.Upload(&LogsUploadRequest{
				Ctxt:  ctxt,
				Files: []string{rotated},
			})
			if apierr != nil {
				Log().Errorf("%s\n", Pretty(apierr))
			}
			if err != nil {
				Log().Error(err)
			}
		}()
	} else {
		Log().Debugf("No new filtered logs detected.  Size: %d\n", fstat.Size())
	}
	return nil
}
<|endoftext|>


<commit_before>package book

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

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
)

// BookAction represents a new/update or removal for a book entry.
type BookAction byte

const (
	//BookEntry represents a new or updated book entry.
	BookEntry BookAction = 0
	//BookRemoveEntry represents a removal of a book entry.
	BookRemoveEntry BookAction = 1
)

// Book represents an order book price update.
type Book struct {
	Symbol      string // book symbol
	ID          int64  // the book update ID, optional
	Count       int64  // updated count, optional
	Period      int64
	Price       float64 // updated price
	Amount      float64 // updated amount
	Rate        float64
	PriceJsNum  json.Number      // update price as json.Number
	AmountJsNum json.Number      // update amount as json.Number
	Side        common.OrderSide // side
	Action      BookAction       // action (add/remove)
}

type Snapshot struct {
	Snapshot []*Book
}

func SnapshotFromRaw(symbol, precision string, raw [][]interface{}, rawNumbers interface{}) (*Snapshot, error) {
	if len(raw) <= 0 {
		return nil, fmt.Errorf("data slice too short for book snapshot: %#v", raw)
	}

	snap := make([]*Book, len(raw))
	for i, v := range raw {
		b, err := FromRaw(symbol, precision, v, rawNumbers.([]interface{})[i])
		if err != nil {
			return nil, err
		}
		snap[i] = b
	}

	return &Snapshot{Snapshot: snap}, nil
}

func IsRawBook(precision string) bool {
	return precision == "R0"
}

// FromRaw creates a new book object from raw data. Precision determines how
// to interpret the side (baked into Count versus Amount)
// raw book updates [ID, price, qty], aggregated book updates [price, amount, count]
func FromRaw(symbol, precision string, raw []interface{}, rawNumbers interface{}) (b *Book, err error) {
	if len(raw) < 3 {
		return b, fmt.Errorf("raw slice too short for book update, expected %d got %d: %#v", 3, len(raw), raw)
	}

	rawBook := IsRawBook(precision)

	if len(raw) == 3 && rawBook {
		b = rawTradingPairsBook(raw, rawNumbers)
	}

	if len(raw) == 3 && !rawBook {
		b = tradingPairsBook(raw, rawNumbers)
	}

	if len(raw) >= 4 && rawBook {
		b = rawFundingPairsBook(raw, rawNumbers)
	}

	if len(raw) >= 4 && !rawBook {
		b = fundingPairsBook(raw, rawNumbers)
	}

	b.Symbol = symbol

	return
}

// FromWSRaw - based on condition will return snapshot of books or single book
func FromWSRaw(symbol, precision string, data []interface{}) (interface{}, error) {
	if len(data) == 0 {
		return nil, errors.New("empty data slice")
	}

	_, isSnapshot := data[0].([]interface{})
	if isSnapshot {
		return SnapshotFromRaw(symbol, precision, convert.ToInterfaceArray(data), data)
	}

	return FromRaw(symbol, precision, data, data)
}

func rawTradingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ ORDER_ID, PRICE, AMOUNT ] - raw trading pairs signature
	var (
		side   common.OrderSide
		action BookAction
	)

	rawNumSlice := rawNumbers.([]interface{})
	amount := convert.F64ValOrZero(raw[2])
	price := convert.F64ValOrZero(raw[1])

	if amount > 0 {
		side = common.Bid
	} else {
		side = common.Ask
	}

	if price <= 0 {
		action = BookRemoveEntry
	} else {
		action = BookEntry
	}

	return &Book{
		Price:       math.Abs(price),
		PriceJsNum:  convert.FloatToJsonNumber(rawNumSlice[1]),
		Amount:      math.Abs(amount),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[2]),
		Side:        side,
		Action:      action,
		ID:          convert.I64ValOrZero(raw[0]),
	}
}

func tradingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ PRICE, COUNT, AMOUNT ] - trading pairs signature
	var (
		price, actionCtrl float64
		count             int64
		priceNum          json.Number
		side              common.OrderSide
		action            BookAction
	)

	rawNumSlice := rawNumbers.([]interface{})
	amount := convert.F64ValOrZero(raw[2])
	amountNum := convert.FloatToJsonNumber(rawNumSlice[2])

	price = convert.F64ValOrZero(raw[0])
	priceNum = convert.FloatToJsonNumber(rawNumSlice[0])
	count = convert.I64ValOrZero(raw[1])
	actionCtrl = float64(count)

	if amount > 0 {
		side = common.Bid
	} else {
		side = common.Ask
	}

	if actionCtrl <= 0 {
		action = BookRemoveEntry
	} else {
		action = BookEntry
	}

	return &Book{
		Price:       math.Abs(price),
		PriceJsNum:  priceNum,
		Count:       count,
		Amount:      math.Abs(amount),
		AmountJsNum: amountNum,
		Side:        side,
		Action:      action,
	}
}

func rawFundingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ ORDER_ID, PERIOD, RATE, AMOUNT ] - raw funding pairs signature
	rawNumSlice := rawNumbers.([]interface{})

	return &Book{
		ID:          convert.I64ValOrZero(raw[0]),
		Period:      convert.I64ValOrZero(raw[1]),
		Rate:        convert.F64ValOrZero(raw[2]),
		Amount:      convert.F64ValOrZero(raw[3]),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[3]),
	}
}

func fundingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ RATE, PERIOD, COUNT, AMOUNT ], - funding pairs signature
	rawNumSlice := rawNumbers.([]interface{})

	return &Book{
		Rate:        convert.F64ValOrZero(raw[0]),
		Period:      convert.I64ValOrZero(raw[1]),
		Count:       convert.I64ValOrZero(raw[2]),
		Amount:      convert.F64ValOrZero(raw[3]),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[3]),
	}
}
<commit_msg>not relaying on raw data slice length to determin trading/funding pair type book<commit_after>package book

import (
	"encoding/json"
	"errors"
	"fmt"
	"math"
	"strings"

	"github.com/bitfinexcom/bitfinex-api-go/pkg/convert"
	"github.com/bitfinexcom/bitfinex-api-go/pkg/models/common"
)

// BookAction represents a new/update or removal for a book entry.
type BookAction byte

const (
	//BookEntry represents a new or updated book entry.
	BookEntry BookAction = 0
	//BookRemoveEntry represents a removal of a book entry.
	BookRemoveEntry BookAction = 1
)

// Book represents an order book price update.
type Book struct {
	Symbol      string // book symbol
	ID          int64  // the book update ID, optional
	Count       int64  // updated count, optional
	Period      int64
	Price       float64 // updated price
	Amount      float64 // updated amount
	Rate        float64
	PriceJsNum  json.Number      // update price as json.Number
	AmountJsNum json.Number      // update amount as json.Number
	Side        common.OrderSide // side
	Action      BookAction       // action (add/remove)
}

type Snapshot struct {
	Snapshot []*Book
}

func SnapshotFromRaw(symbol, precision string, raw [][]interface{}, rawNumbers interface{}) (*Snapshot, error) {
	if len(raw) <= 0 {
		return nil, fmt.Errorf("data slice too short for book snapshot: %#v", raw)
	}

	snap := make([]*Book, len(raw))
	for i, v := range raw {
		b, err := FromRaw(symbol, precision, v, rawNumbers.([]interface{})[i])
		if err != nil {
			return nil, err
		}
		snap[i] = b
	}

	return &Snapshot{Snapshot: snap}, nil
}

func IsRawBook(precision string) bool {
	return precision == "R0"
}

// FromRaw creates a new book object from raw data. Precision determines how
// to interpret the side (baked into Count versus Amount)
// raw book updates [ID, price, qty], aggregated book updates [price, amount, count]
func FromRaw(symbol, precision string, raw []interface{}, rawNumbers interface{}) (b *Book, err error) {
	isRaw := IsRawBook(precision)
	isFunding := strings.HasPrefix(symbol, "f")
	isTrading := strings.HasPrefix(symbol, "t")

	if len(raw) < 3 && isTrading {
		err = fmt.Errorf("raw slice too short for trading pair book, got len %d: %#v", len(raw), raw)
		return
	}

	if len(raw) < 4 && isFunding {
		err = fmt.Errorf("raw slice too short for funding pair book, got len %d: %#v", len(raw), raw)
		return
	}

	if isTrading && isRaw {
		b = rawTradingPairsBook(raw, rawNumbers)
		b.Symbol = symbol
		return
	}

	if isTrading && !isRaw {
		b = tradingPairsBook(raw, rawNumbers)
		b.Symbol = symbol
		return
	}

	if isFunding && isRaw {
		b = rawFundingPairsBook(raw, rawNumbers)
		b.Symbol = symbol
		return
	}

	if isFunding && !isRaw {
		b = fundingPairsBook(raw, rawNumbers)
		b.Symbol = symbol
		return
	}

	err = fmt.Errorf("unrecognized data slice: %#v", raw)
	return
}

// FromWSRaw - based on condition will return snapshot of books or single book
func FromWSRaw(symbol, precision string, data []interface{}) (interface{}, error) {
	if len(data) == 0 {
		return nil, errors.New("empty data slice")
	}

	_, isSnapshot := data[0].([]interface{})
	if isSnapshot {
		return SnapshotFromRaw(symbol, precision, convert.ToInterfaceArray(data), data)
	}

	return FromRaw(symbol, precision, data, data)
}

func rawTradingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ ORDER_ID, PRICE, AMOUNT ] - raw trading pairs signature
	var (
		side   common.OrderSide
		action BookAction
	)

	rawNumSlice := rawNumbers.([]interface{})
	price := convert.F64ValOrZero(raw[1])
	amount := convert.F64ValOrZero(raw[2])

	if amount > 0 {
		side = common.Bid
	} else {
		side = common.Ask
	}

	if price <= 0 {
		action = BookRemoveEntry
	} else {
		action = BookEntry
	}

	return &Book{
		Price:       math.Abs(price),
		PriceJsNum:  convert.FloatToJsonNumber(rawNumSlice[1]),
		Amount:      math.Abs(amount),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[2]),
		Side:        side,
		Action:      action,
		ID:          convert.I64ValOrZero(raw[0]),
	}
}

func tradingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ PRICE, COUNT, AMOUNT ] - trading pairs signature
	var (
		price    float64
		count    int64
		priceNum json.Number
		side     common.OrderSide
		action   BookAction
	)

	rawNumSlice := rawNumbers.([]interface{})
	amount := convert.F64ValOrZero(raw[2])
	amountNum := convert.FloatToJsonNumber(rawNumSlice[2])

	price = convert.F64ValOrZero(raw[0])
	priceNum = convert.FloatToJsonNumber(rawNumSlice[0])
	count = convert.I64ValOrZero(raw[1])

	if amount > 0 {
		side = common.Bid
	} else {
		side = common.Ask
	}

	if count <= 0 {
		action = BookRemoveEntry
	} else {
		action = BookEntry
	}

	return &Book{
		Price:       math.Abs(price),
		PriceJsNum:  priceNum,
		Count:       count,
		Amount:      math.Abs(amount),
		AmountJsNum: amountNum,
		Side:        side,
		Action:      action,
	}
}

func rawFundingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ ORDER_ID, PERIOD, RATE, AMOUNT ] - raw funding pairs signature
	rawNumSlice := rawNumbers.([]interface{})

	return &Book{
		ID:          convert.I64ValOrZero(raw[0]),
		Period:      convert.I64ValOrZero(raw[1]),
		Rate:        convert.F64ValOrZero(raw[2]),
		Amount:      convert.F64ValOrZero(raw[3]),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[3]),
	}
}

func fundingPairsBook(raw []interface{}, rawNumbers interface{}) *Book {
	// [ RATE, PERIOD, COUNT, AMOUNT ], - funding pairs signature
	rawNumSlice := rawNumbers.([]interface{})

	return &Book{
		Rate:        convert.F64ValOrZero(raw[0]),
		Period:      convert.I64ValOrZero(raw[1]),
		Count:       convert.I64ValOrZero(raw[2]),
		Amount:      convert.F64ValOrZero(raw[3]),
		AmountJsNum: convert.FloatToJsonNumber(rawNumSlice[3]),
	}
}
<|endoftext|>