<commit_before>
package core

import ("fmt"
	"os"
	"strconv"
	"runtime"
	"math"
	"bytes"
	"time"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	orientation ogre.Quaternion // current orientation
}

func InitCore() {
	var gameThreadParams GameThreadParams
	gameThreadParams.start = time.Now() // There's an small time before this variable is initalized,
	// it probably doesn't matter... Someone timed Go initalization at 1.94us on Linux.

	sdl.Init(sdl.INIT_EVERYTHING)
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	var version sdl.Version
	sdl.GetVersion(&version)

	fmt.Printf("Sdl Major Version: %d\n", version.Major)
	fmt.Printf("Sdl Minor Version: %d\n", version.Minor)
	fmt.Printf("Sdl Patch level: %d\n", version.Patch)
	fmt.Printf("Sdl Subsystem: %s\n", getSubsystemString(info))
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
		root.LoadPlugin(wd  + "/RenderSystem_GL3Plus")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL3Plus")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	if runtime.GOOS == "windows" {
		windowsInfo := info.GetWindowsInfo()
		windowString := strconv.FormatUint(uint64(*(*uint32)(windowsInfo.Window)), 10)
		params.AddPair("parentWindowHandle", windowString)
	}
	if runtime.GOOS == "darwin" {
		params.AddPair("macAPI", "cocoa")
		cocoaInfo := info.GetCocoaInfo()
		windowString := strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10)
		params.AddPair("parentWindowHandle", windowString)
	}

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread(gameThreadParams)
	var renderThreadParams RenderThreadParams
	renderThreadParams.start = gameThreadParams.start
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.ogreWindow = renderWindow

	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	for !shutdownRequested /* && SDL_GetTicks() < MAX_RUN_TIME */ {
		// We wait here.
		b, err := nnInputPull.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		s, _, err := capn.ReadFromMemoryZeroCopy(b)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		state := ReadRootState(s)
		fmt.Printf("Game push received:\n")
		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		var event sdl.Event
		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent {
			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					// Todo
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			case *sdl.MouseMotionEvent:
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.yaw += is.orientationFactor * is.yawSens * float32(t.XRel)
				if is.yaw >= 0.0 {
					is.yaw = float32(math.Mod(float64(is.yaw) + 180.0, 360.0) - 180.0)
				} else {
					is.yaw = float32(math.Mod(float64(is.yaw) - 180.0, 360.0) + 180.0)
				}
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.pitch += is.orientationFactor * is.pitchSens * float32(t.YRel)
				if is.pitch > 90.0 {
					is.pitch = 90.0
				} else if ( is.pitch < -90.0 ) {
					is.pitch = -90.0
				}
				// build a quaternion of the current orientation
				var r ogre.Matrix3
				r.FromEulerAnglesYXZ( deg2Rad(is.yaw), deg2Rad(is.pitch), deg2Rad(is.roll))
				is.orientation.FromRotationMatrix(r)
			case *sdl.MouseButtonEvent:
				fmt.Printf("SDL mouse button event:\n")
			case *sdl.QuitEvent:
			    // push a shutdown on the control socket, game and render will pick it up later
				// NOTE: if the message patterns change we may still have to deal with hangs here
				sendShutdown(nnRenderSocket, nnGameSocket)

				shutdownRequested = true
			default:
				fmt.Printf("SDL_Event %T\n", event);
			}
		}
		switch {
		// we are ready to process the request now
		case state.Mouse():
			buttons := sdl.GetMouseState(nil, nil)
			fmt.Printf("buttons: %d\n", buttons)
			s := capn.NewBuffer(nil)
			ms := NewRootInputMouse(s)
			ms.SetW(is.orientation.W())
			ms.SetX(is.orientation.X())
			ms.SetY(is.orientation.Y())
			ms.SetZ(is.orientation.Z())
			ms.SetButtons(buttons)
			buf := bytes.Buffer{}
			s.WriteTo(&buf)
			nnInputPub.Send(append([]byte("input.mouse:"), buf.Bytes()...), 0)
			fmt.Printf("Mouse input sent.\n")

		case state.Kb():
		// looking at a few hardcoded keys for now
		// NOTE: I suspect it would be perfectly safe to grab that pointer once, and read it from a different thread?
			state := sdl.GetKeyboardState(nil)
			t := capn.NewBuffer(nil)
			kbs := NewRootInputKb(t)
			kbs.SetW(state[sdl.SCANCODE_W] != 0)
			kbs.SetA(state[sdl.SCANCODE_A] != 0)
			kbs.SetS(state[sdl.SCANCODE_S] != 0)
			kbs.SetD(state[sdl.SCANCODE_D] != 0)
			kbs.SetSpace(state[sdl.SCANCODE_SPACE] != 0)
			kbs.SetLalt(state[sdl.SCANCODE_LALT] != 0)
			b := bytes.Buffer{}
			t.WriteTo(&b)
			nnInputPub.Send(append([]byte("input.kb:"), b.Bytes()...), 0)
			fmt.Printf("Keyboard input sent.\n")

		case state.MouseReset():
			var q ogre.Quaternion;
			is.orientation = q.FromValues(state.Quaternion().W(), state.Quaternion().X(),
				state.Quaternion().Y(), state.Quaternion().Z())
			var r ogre.Matrix3
			is.orientation.ToRotationMatrix(&r)
			var rfYAngle, rfPAngle, rfRAngle float32
			r.ToEulerAnglesYXZ(&rfYAngle, &rfPAngle, &rfRAngle)
			is.yaw = rad2Deg(rfYAngle)
			is.pitch = rad2Deg(rfPAngle)
			is.roll = rad2Deg(rfRAngle)
		case state.ConfigLookAround():
			if state.LookAround().ManipulateObject() {
				fmt.Printf("Input configuration: manipulate object\n");
				is.orientationFactor = 1.0;
			} else {
				fmt.Printf("Input configuration: look around\n");
				is.orientationFactor = -1.0
			}
		}
	}
	if !shutdownRequested {
      sendShutdown(nnRenderSocket, nnGameSocket)
      shutdownRequested = true
    }
    waitShutdown(nnInputPull, &gameThreadParams)
}

func deg2Rad(deg float32) float32 {
	return deg * math.Pi / 180
}

func rad2Deg (rad float32) float32 {
	return rad * 180 / math.Pi
}

func sendShutdown(nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	s := capn.NewBuffer(nil)
	stop := NewRootStop(s)
	stop.SetStop(true)
	buf := bytes.Buffer{}
	s.WriteTo(&buf)
	fmt.Printf("Render socket shutdown.\n")
	nnRenderSocket.Send(buf.Bytes(), 0)
	fmt.Printf("Game socket shutdown.\n")
	nnGameSocket.Send(buf.Bytes(), 0)
}

func waitShutdown(nnInputPull *nanomsg.Socket, params *GameThreadParams) {
	// For now, loop the input thread for a bit to flush out any events
	continueTime := time.Since(params.start) + 500 * time.Millisecond  // An eternity.
	for time.Since(params.start) < continueTime {
		msg, _ := nnInputPull.Recv(nanomsg.DontWait)
		if msg == nil {
			sdl.Delay(10)
		}
	}
}

func getSubsystemString(info sdl.SysWMInfo) string {
	switch info.Subsystem {
	case 0:
	    return "Unknown"
	case 1:
		return "Windows"
	case 2:
		return "X11"
	case 3:
		return "DirectFB"
	case 4:
		return "Cocoa"
	case 5:
		return "UiKit"
	}
	return "Unknown"
}
<commit_msg>Cleanup.<commit_after>
package core

import ("fmt"
	"os"
	"strconv"
	"runtime"
	"math"
	"bytes"
	"time"
	"github.com/jackyb/go-sdl2/sdl"
	"github.com/op/go-nanomsg"
	"github.com/fire/go-ogre3d"
	"github.com/jmckaskill/go-capnproto")

type InputState struct {
	yawSens float32
	pitchSens float32
	orientationFactor float32 // +1/-1 easy switch between look around and manipulate something
	yaw float32 // degrees, modulo [-180,180] range
	pitch float32 // degrees, clamped [-90,90] range
	roll float32
	orientation ogre.Quaternion // current orientation
}

func InitCore() {
	var gameThreadParams GameThreadParams
	gameThreadParams.start = time.Now() // There's an small time before this variable is initalized,
	// it probably doesn't matter... Someone timed Go initalization at 1.94us on Linux.

	sdl.Init(sdl.INIT_EVERYTHING)
	var event sdl.Event
	window := sdl.CreateWindow("es_core::SDL",
		sdl.WINDOWPOS_UNDEFINED,
		sdl.WINDOWPOS_UNDEFINED,
		800,
		600,
		sdl.WINDOW_SHOWN)
	if window == nil {
		panic(fmt.Sprintf("sdl.CreateWindow failed: %s\n", sdl.GetError()))
	}
	defer sdl.Quit()
	var info sdl.SysWMInfo
	if !window.GetWMInfo(&info) {
		panic(fmt.Sprintf("window.GetWMInfo failed.\n"))
	}
	var version sdl.Version
	sdl.GetVersion(&version)

	fmt.Printf("Sdl Major Version: %d\n", version.Major)
	fmt.Printf("Sdl Minor Version: %d\n", version.Minor)
	fmt.Printf("Sdl Patch level: %d\n", version.Patch)
	fmt.Printf("Sdl Subsystem: %s\n", getSubsystemString(info))
	root := ogre.NewRoot("", "", "ogre.log")
	defer root.Destroy()
	wd, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	if runtime.GOOS == "windows" {
		root.LoadPlugin(wd  + "/RenderSystem_GL3Plus")
		}
	if runtime.GOOS == "darwin" {
		root.LoadPlugin(wd  + "/../frameworks/RenderSystem_GL3Plus")
	}

	renderers := root.GetAvailableRenderers()
	if renderers.RenderSystemListSize() != 1 {

		panic(fmt.Sprintf("Failed to initalize RendererRenderSystem_GL"))
	}
	root.SetRenderSystem(renderers.RenderSystemListGet(0))
	root.Initialise(false, "es_core::ogre")
	params := ogre.CreateNameValuePairList()
	if runtime.GOOS == "windows" {
		windowsInfo := info.GetWindowsInfo()
		windowString := strconv.FormatUint(uint64(*(*uint32)(windowsInfo.Window)), 10)
		params.AddPair("parentWindowHandle", windowString)
	}
	if runtime.GOOS == "darwin" {
		params.AddPair("macAPI", "cocoa")
		cocoaInfo := info.GetCocoaInfo()
		windowString := strconv.FormatUint(uint64(*(*uint32)(cocoaInfo.Window)), 10)
		params.AddPair("parentWindowHandle", windowString)
	}

	renderWindow := root.CreateRenderWindow("es_core::ogre", 800, 600, false, params)
	renderWindow.SetVisible(true)

	nnGameSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
        if err != nil {
                panic(err)
        }
        _, err = nnGameSocket.Bind("tcp://127.0.0.1:60206")
        if err != nil {
                panic(err)
        }

	nnRenderSocket, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.BUS)
	if err != nil {
                panic(err)
        }
        _, err = nnRenderSocket.Bind("tcp://127.0.0.1:60207")
        if err != nil {
                panic(err)
        }

	nnInputPub, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PUB)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPub.Bind("tcp://127.0.0.1:60208")
        if err != nil {
                panic(err)
        }

	nnInputPull, err := nanomsg.NewSocket(nanomsg.AF_SP, nanomsg.PULL)
        if err != nil {
                panic(err)
        }
        _, err = nnInputPull.Bind("tcp://127.0.0.1:60209")
        if err != nil {
                panic(err)
        }
	go gameThread(gameThreadParams)
	var renderThreadParams RenderThreadParams
	renderThreadParams.start = gameThreadParams.start
	renderThreadParams.root = root
	renderThreadParams.window = window
	renderThreadParams.ogreWindow = renderWindow

	go renderThread(renderThreadParams)

	window.SetGrab(true)
	sdl.SetRelativeMouseMode(true)

	shutdownRequested := false
	var is InputState
	is.yawSens = 0.1
	is.yaw = 0.0
	is.pitchSens = 0.1
	is.pitch = 0.0
	is.roll = 0.0
	is.orientationFactor = -1.0 // Look around config

	for !shutdownRequested /* && SDL_GetTicks() < MAX_RUN_TIME */ {
		// We wait here.
		b, err := nnInputPull.Recv(0)
		if err != nil {
			fmt.Printf("%s\n", err)
		}
		s, _, err := capn.ReadFromMemoryZeroCopy(b)
		if err != nil {
			fmt.Printf("Read error %v\n", err)
			return
		}
		state := ReadRootState(s)
		fmt.Printf("Game push received:\n")
		// poll for events before processing the request
		// NOTE: this is how SDL builds the internal mouse and keyboard state
		// TODO: done this way does not meet the objectives of smooth, frame independent mouse view control,
		// Plus it throws some latency into the calling thread

		for event = sdl.PollEvent(); event != nil; event = sdl.PollEvent {
			switch t := event.(type) {
			case *sdl.KeyDownEvent:
				fmt.Printf("SDL keyboard event:\n")
			case *sdl.KeyUpEvent:
				fmt.Printf("SDL keyboard event:\n")
				if t.Keysym.Scancode == sdl.SCANCODE_ESCAPE {
					sendShutdown(nnRenderSocket, nnGameSocket)
					shutdownRequested = true
				}
			case *sdl.MouseMotionEvent:
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.yaw += is.orientationFactor * is.yawSens * float32(t.XRel)
				if is.yaw >= 0.0 {
					is.yaw = float32(math.Mod(float64(is.yaw) + 180.0, 360.0) - 180.0)
				} else {
					is.yaw = float32(math.Mod(float64(is.yaw) - 180.0, 360.0) + 180.0)
				}
				// + when manipulating an object, - when doing a first person view .. needs to be configurable?
				is.pitch += is.orientationFactor * is.pitchSens * float32(t.YRel)
				if is.pitch > 90.0 {
					is.pitch = 90.0
				} else if ( is.pitch < -90.0 ) {
					is.pitch = -90.0
				}
				// build a quaternion of the current orientation
				var r ogre.Matrix3
				r.FromEulerAnglesYXZ( deg2Rad(is.yaw), deg2Rad(is.pitch), deg2Rad(is.roll))
				is.orientation.FromRotationMatrix(r)
			case *sdl.MouseButtonEvent:
				fmt.Printf("SDL mouse button event:\n")
			case *sdl.QuitEvent:
			    // push a shutdown on the control socket, game and render will pick it up later
				// NOTE: if the message patterns change we may still have to deal with hangs here
				sendShutdown(nnRenderSocket, nnGameSocket)
				shutdownRequested = true
			default:
				fmt.Printf("SDL_Event: %T\n", t);

			}
		}
		switch {
		// we are ready to process the request now
		case state.Mouse():
			buttons := sdl.GetMouseState(nil, nil)
			fmt.Printf("buttons: %d\n", buttons)
			s := capn.NewBuffer(nil)
			ms := NewRootInputMouse(s)
			ms.SetW(is.orientation.W())
			ms.SetX(is.orientation.X())
			ms.SetY(is.orientation.Y())
			ms.SetZ(is.orientation.Z())
			ms.SetButtons(buttons)
			buf := bytes.Buffer{}
			s.WriteTo(&buf)
			nnInputPub.Send(append([]byte("input.mouse:"), buf.Bytes()...), 0)
			fmt.Printf("Mouse input sent.\n")

		case state.Kb():
		// looking at a few hardcoded keys for now
		// NOTE: I suspect it would be perfectly safe to grab that pointer once, and read it from a different thread?
			state := sdl.GetKeyboardState()
			t := capn.NewBuffer(nil)
			kbs := NewRootInputKb(t)
			kbs.SetW(state[sdl.SCANCODE_W] != 0)
			kbs.SetA(state[sdl.SCANCODE_A] != 0)
			kbs.SetS(state[sdl.SCANCODE_S] != 0)
			kbs.SetD(state[sdl.SCANCODE_D] != 0)
			kbs.SetSpace(state[sdl.SCANCODE_SPACE] != 0)
			kbs.SetLalt(state[sdl.SCANCODE_LALT] != 0)
			b := bytes.Buffer{}
			t.WriteTo(&b)
			nnInputPub.Send(append([]byte("input.kb:"), b.Bytes()...), 0)
			fmt.Printf("Keyboard input sent.\n")

		case state.MouseReset():
			var q ogre.Quaternion;
			is.orientation = q.FromValues(state.Quaternion().W(), state.Quaternion().X(),
				state.Quaternion().Y(), state.Quaternion().Z())
			var r ogre.Matrix3
			is.orientation.ToRotationMatrix(&r)
			var rfYAngle, rfPAngle, rfRAngle float32
			r.ToEulerAnglesYXZ(&rfYAngle, &rfPAngle, &rfRAngle)
			is.yaw = rad2Deg(rfYAngle)
			is.pitch = rad2Deg(rfPAngle)
			is.roll = rad2Deg(rfRAngle)
		case state.ConfigLookAround():
			if state.LookAround().ManipulateObject() {
				fmt.Printf("Input configuration: manipulate object\n");
				is.orientationFactor = 1.0;
			} else {
				fmt.Printf("Input configuration: look around\n");
				is.orientationFactor = -1.0
			}
		}
	}
	if !shutdownRequested {
      sendShutdown(nnRenderSocket, nnGameSocket)
      shutdownRequested = true
    }
    waitShutdown(nnInputPull, &gameThreadParams)
}

func deg2Rad(deg float32) float32 {
	return deg * math.Pi / 180
}

func rad2Deg (rad float32) float32 {
	return rad * 180 / math.Pi
}

func sendShutdown(nnRenderSocket *nanomsg.Socket, nnGameSocket *nanomsg.Socket) {
	s := capn.NewBuffer(nil)
	stop := NewRootStop(s)
	stop.SetStop(true)
	buf := bytes.Buffer{}
	s.WriteTo(&buf)
	fmt.Printf("Render socket shutdown.\n")
	nnRenderSocket.Send(buf.Bytes(), 0)
	fmt.Printf("Game socket shutdown.\n")
	nnGameSocket.Send(buf.Bytes(), 0)
}

func waitShutdown(nnInputPull *nanomsg.Socket, params *GameThreadParams) {
	// For now, loop the input thread for a bit to flush out any events
	continueTime := time.Since(params.start) + 500 * time.Millisecond  // An eternity.
	for time.Since(params.start) < continueTime {
		msg, _ := nnInputPull.Recv(nanomsg.DontWait)
		if msg == nil {
			sdl.Delay(10)
		}
	}
}

func getSubsystemString(info sdl.SysWMInfo) string {
	switch info.Subsystem {
	case 0:
	    return "Unknown"
	case 1:
		return "Windows"
	case 2:
		return "X11"
	case 3:
		return "DirectFB"
	case 4:
		return "Cocoa"
	case 5:
		return "UiKit"
	}
	return "Unknown"
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

var (
	TS_MODULE     string
	TS_CUR_MODULE string
	TS_EX_TYPE    bool
	TS_OBJECTS    map[string]*Object
	EXTENS_PKG    map[string]string
)

func Typescript(dir string, name string, module string, types []Type, propPre []Type) {
	var buffer bytes.Buffer

	PROP_PRE = propPre
	TS_MODULE = module
	TS_OBJECTS = ObjectMap(types, TS_MODULE == "")

	var pkgTypes map[string][]Type
	var sortedPkgs []string
	if TS_MODULE == "" {
		pkgTypes = PkgTypeMap(types)
		for pkg, _ := range pkgTypes {
			sortedPkgs = append(sortedPkgs, pkg)
		}
		sort.Strings(sortedPkgs)
	} else {
		pkgTypes = map[string][]Type{module: types}
		sortedPkgs = []string{module}
	}

	var modules []string
	for _, pkg := range sortedPkgs {
		ts := pkgTypes[pkg]
		TS_CUR_MODULE = pkg
		TS_EX_TYPE = false

		var codes []string
		for _, t := range ts {
			codes = append(codes, t.Typescript())
		}

		exType := ""
		if TS_EX_TYPE {
			exType = `
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}`
		}

		modules = append(modules, fmt.Sprintf(`
declare module %s {%s%s
}
`, strings.Replace(pkg, "/", ".", -1), exType, strings.Join(codes, "")))
	}

	PROP_PRE = nil
	TS_OBJECTS = nil
	TS_EX_TYPE = false
	TS_MODULE = ""
	TS_CUR_MODULE = ""

	buffer.Write([]byte(fmt.Sprintf(`// Generated for tyts by tygo.  DO NOT EDIT!
%s`, strings.Join(modules, ""))))

	if name == "" {
		name = module
	}
	ioutil.WriteFile(path.Join(dir, name+".d.ts"), buffer.Bytes(), 0666)
	Javascript(dir, name, module, types, propPre)
}

func (t *Enum) Typescript() string {
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
		%s = %d`, name, t.Values[name]))
	}
	return fmt.Sprintf(`

	const enum %s {%s
	}`, t.Name, strings.Join(enums, ","))
}

func typeListTypescript(name string, typ string, ts []Type) string {
	var items []string
	for i, t := range ts {
		items = append(items, fmt.Sprintf("a%d: %s", i, t.Typescript()))
	}
	return fmt.Sprintf(`
		static S_%s%s(%s): Uint8Array;
		static D_%s%s(data: Uint8Array): any;`, name, typ, strings.Join(items, ", "), name, typ)
}

func (t *Object) Typescript() string {
	var parent string
	if t.HasParent() {
		parent = fmt.Sprintf(" extends %s", t.Parent.Typescript())
	}
	var members []string
	for _, field := range t.VisibleFields() {
		members = append(members, fmt.Sprintf(`
		%s: %s;`, field.Name, field.Typescript()))
	}

	if PROP_PRE != nil {
		for _, field := range t.VisibleFields() {
			members = append(members, typeListTypescript(field.Name, "", []Type{field}))
		}
	}

	for _, method := range t.Methods {
		if len(method.Params) > 0 {
			members = append(members, typeListTypescript(method.Name, "Param", method.Params))
		}
		if len(method.Results) > 0 {
			members = append(members, typeListTypescript(method.Name, "Result", method.Results))
		}
	}

	return fmt.Sprintf(`

	class %s%s {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
%s
	}

	namespace %s {
		function Deserialize(data: Uint8Array): %s;
	}`, t.Name, parent, strings.Join(members, ""), t.Name, t.Name)
}

func (t UnknownType) Typescript() string {
	return ""
}

func (t SimpleType) Typescript() string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		fallthrough
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "number"
	case SimpleType_BYTES:
		return "Uint8Array"
	case SimpleType_SYMBOL:
		fallthrough
	case SimpleType_STRING:
		return "string"
	case SimpleType_BOOL:
		return "boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typescript: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typescript() string {
	return t.Name
}

func (t *InstanceType) Typescript() string {
	fullName := t.Name
	if t.Object != nil {
		fullName = t.Object.FullName()
	} else if TS_MODULE == "" && t.PkgPath != "" {
		fullName = t.PkgPath + "/" + t.Name
	} else if EXTENS_PKG != nil {
		if pkg, ok := EXTENS_PKG[t.Name]; ok {
			if TS_CUR_MODULE == pkg {
				return t.Name
			} else {
				return strings.Replace(pkg, "/", ".", -1) + "." + t.Name
			}
		}
	}
	if _, ok := TS_OBJECTS[fullName]; ok {
		if TS_CUR_MODULE == t.PkgPath || t.Object != nil {
			return t.Name
		}
		return strings.Replace(fullName, "/", ".", -1)
	} else {
		TS_EX_TYPE = true
		return "Type"
	}
}

func (t *FixedPointType) Typescript() string {
	return "number"
}

func (t *ListType) Typescript() string {
	return fmt.Sprintf("%s[]", t.E.Typescript())
}

func (t *DictType) Typescript() string {
	return fmt.Sprintf("{[index: %s]: %s}", t.K.Typescript(), t.V.Typescript())
}

func (t *VariantType) Typescript() string {
	return "any"
}
<commit_msg>fix type bug<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"bytes"
	"fmt"
	"log"
	"path"
	"sort"
	"strings"

	"io/ioutil"
)

var (
	TS_MODULE     string
	TS_CUR_MODULE string
	TS_EX_TYPE    bool
	TS_OBJECTS    map[string]*Object
	EXTENS_PKG    map[string]string
)

func Typescript(dir string, name string, module string, types []Type, propPre []Type) {
	var buffer bytes.Buffer

	PROP_PRE = propPre
	TS_MODULE = module
	TS_OBJECTS = ObjectMap(types, TS_MODULE == "")

	var pkgTypes map[string][]Type
	var sortedPkgs []string
	if TS_MODULE == "" {
		pkgTypes = PkgTypeMap(types)
		for pkg, _ := range pkgTypes {
			sortedPkgs = append(sortedPkgs, pkg)
		}
		sort.Strings(sortedPkgs)
	} else {
		pkgTypes = map[string][]Type{module: types}
		sortedPkgs = []string{module}
	}

	var modules []string
	for _, pkg := range sortedPkgs {
		ts := pkgTypes[pkg]
		TS_CUR_MODULE = pkg
		TS_EX_TYPE = false

		var codes []string
		for _, t := range ts {
			codes = append(codes, t.Typescript())
		}

		exType := ""
		if TS_EX_TYPE {
			exType = `
	interface Type {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
	}`
		}

		modules = append(modules, fmt.Sprintf(`
declare module %s {%s%s
}
`, strings.Replace(pkg, "/", ".", -1), exType, strings.Join(codes, "")))
	}

	PROP_PRE = nil
	TS_OBJECTS = nil
	TS_EX_TYPE = false
	TS_MODULE = ""
	TS_CUR_MODULE = ""

	buffer.Write([]byte(fmt.Sprintf(`// Generated for tyts by tygo.  DO NOT EDIT!
%s`, strings.Join(modules, ""))))

	if name == "" {
		name = module
	}
	ioutil.WriteFile(path.Join(dir, name+".d.ts"), buffer.Bytes(), 0666)
	Javascript(dir, name, module, types, propPre)
}

func (t *Enum) Typescript() string {
	var enums []string
	for _, name := range t.Sorted() {
		enums = append(enums, fmt.Sprintf(`
		%s = %d`, name, t.Values[name]))
	}
	return fmt.Sprintf(`

	const enum %s {%s
	}`, t.Name, strings.Join(enums, ","))
}

func typeListTypescript(name string, typ string, ts []Type) string {
	var items []string
	for i, t := range ts {
		items = append(items, fmt.Sprintf("a%d: %s", i, t.Typescript()))
	}
	return fmt.Sprintf(`
		static S_%s%s(%s): Uint8Array;
		static D_%s%s(data: Uint8Array): any;`, name, typ, strings.Join(items, ", "), name, typ)
}

func (t *Object) Typescript() string {
	var parent string
	if t.HasParent() {
		parent = fmt.Sprintf(" extends %s", t.Parent.Typescript())
	}
	var members []string
	for _, field := range t.VisibleFields() {
		members = append(members, fmt.Sprintf(`
		%s: %s;`, field.Name, field.Typescript()))
	}

	if PROP_PRE != nil {
		for _, field := range t.VisibleFields() {
			members = append(members, typeListTypescript(field.Name, "", []Type{field}))
		}
	}

	for _, method := range t.Methods {
		if len(method.Params) > 0 {
			members = append(members, typeListTypescript(method.Name, "Param", method.Params))
		}
		if len(method.Results) > 0 {
			members = append(members, typeListTypescript(method.Name, "Result", method.Results))
		}
	}

	return fmt.Sprintf(`

	class %s%s {
		__class__: string;
		ByteSize(): number;
		Serialize(): Uint8Array;
		Deserialize(data: Uint8Array): void;
%s
	}

	namespace %s {
		function Deserialize(data: Uint8Array): %s;
	}`, t.Name, parent, strings.Join(members, ""), t.Name, t.Name)
}

func (t UnknownType) Typescript() string {
	return ""
}

func (t SimpleType) Typescript() string {
	switch t {
	case SimpleType_INT32:
		fallthrough
	case SimpleType_INT64:
		fallthrough
	case SimpleType_UINT32:
		fallthrough
	case SimpleType_UINT64:
		fallthrough
	case SimpleType_FLOAT32:
		fallthrough
	case SimpleType_FLOAT64:
		return "number"
	case SimpleType_BYTES:
		return "Uint8Array"
	case SimpleType_SYMBOL:
		fallthrough
	case SimpleType_STRING:
		return "string"
	case SimpleType_BOOL:
		return "boolean"
	default:
		log.Fatalf("[Tygo][SimpleType] Unexpect enum value for Typescript: %d", t)
		return "unknown"
	}
}

func (t *EnumType) Typescript() string {
	return t.Name
}

func (t *InstanceType) Typescript() string {
	fullName := t.Name
	if TS_MODULE == "" && t.Object != nil {
		fullName = t.Object.FullName()
	} else if TS_MODULE == "" && t.PkgPath != "" {
		fullName = t.PkgPath + "/" + t.Name
	} else if EXTENS_PKG != nil {
		if pkg, ok := EXTENS_PKG[t.Name]; ok {
			if TS_CUR_MODULE == pkg {
				return t.Name
			} else {
				return strings.Replace(pkg, "/", ".", -1) + "." + t.Name
			}
		}
	}
	if _, ok := TS_OBJECTS[fullName]; ok {
		if TS_CUR_MODULE == t.PkgPath || t.Object != nil {
			return t.Name
		}
		return strings.Replace(fullName, "/", ".", -1)
	} else {
		TS_EX_TYPE = true
		return "Type"
	}
}

func (t *FixedPointType) Typescript() string {
	return "number"
}

func (t *ListType) Typescript() string {
	return fmt.Sprintf("%s[]", t.E.Typescript())
}

func (t *DictType) Typescript() string {
	return fmt.Sprintf("{[index: %s]: %s}", t.K.Typescript(), t.V.Typescript())
}

func (t *VariantType) Typescript() string {
	return "any"
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package jaeger

const (
	// JaegerClientVersionTagKey is the name of the tag used to report client version.
	JaegerClientVersionTagKey = "jaeger.version"

	// TracerHostnameTagKey used to report host name of the process.
	TracerHostnameTagKey = "jaeger.hostname"

	// SamplerTypeTagKey reports which sampler was used on the root span.
	SamplerTypeTagKey = "sampler.type"

	// SamplerParamTagKey reports the parameter of the sampler, like sampling probability.
	SamplerParamTagKey = "sampler.param"

	// JaegerGoVersion is the version of the client library reported as Span tag.
	JaegerGoVersion = "Golang-1.2"

	// TracerStateHeaderName is the http header name used to propagate tracing context.
	// This must be in lower-case to avoid mismatches when decoding incoming headers.
	TracerStateHeaderName = "uber-trace-id"

	// TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage.
	// This must be in lower-case to avoid mismatches when decoding incoming headers.
	TraceBaggageHeaderPrefix = "uberctx-"

	defaultSamplingServerHostPort = "localhost:5778"

	// SamplerTypeConst is the type of sampler that always makes the same decision.
	SamplerTypeConst = "const"

	// SamplerTypeRemote is the type of sampler that polls Jaeger agent for sampling strategy.
	SamplerTypeRemote = "remote"

	// SamplerTypeProbabilistic is the type of sampler that samples traces
	// with a certain fixed probability.
	SamplerTypeProbabilistic = "probabilistic"

	// SamplerTypeRateLimiting is the type of sampler that samples
	// only up to a fixed number of traces per second.
	SamplerTypeRateLimiting = "ratelimiting"
)
<commit_msg>Preparing release 1.3.1<commit_after>// Copyright (c) 2016 Uber Technologies, Inc.

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package jaeger

const (
	// JaegerClientVersionTagKey is the name of the tag used to report client version.
	JaegerClientVersionTagKey = "jaeger.version"

	// TracerHostnameTagKey used to report host name of the process.
	TracerHostnameTagKey = "jaeger.hostname"

	// SamplerTypeTagKey reports which sampler was used on the root span.
	SamplerTypeTagKey = "sampler.type"

	// SamplerParamTagKey reports the parameter of the sampler, like sampling probability.
	SamplerParamTagKey = "sampler.param"

	// JaegerGoVersion is the version of the client library reported as Span tag.
	JaegerGoVersion = "Golang-1.3"

	// TracerStateHeaderName is the http header name used to propagate tracing context.
	// This must be in lower-case to avoid mismatches when decoding incoming headers.
	TracerStateHeaderName = "uber-trace-id"

	// TraceBaggageHeaderPrefix is the prefix for http headers used to propagate baggage.
	// This must be in lower-case to avoid mismatches when decoding incoming headers.
	TraceBaggageHeaderPrefix = "uberctx-"

	defaultSamplingServerHostPort = "localhost:5778"

	// SamplerTypeConst is the type of sampler that always makes the same decision.
	SamplerTypeConst = "const"

	// SamplerTypeRemote is the type of sampler that polls Jaeger agent for sampling strategy.
	SamplerTypeRemote = "remote"

	// SamplerTypeProbabilistic is the type of sampler that samples traces
	// with a certain fixed probability.
	SamplerTypeProbabilistic = "probabilistic"

	// SamplerTypeRateLimiting is the type of sampler that samples
	// only up to a fixed number of traces per second.
	SamplerTypeRateLimiting = "ratelimiting"
)
<|endoftext|>


<commit_before>package plugin

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

	"github.com/docker/cli/internal/test"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"

	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
	"gotest.tools/golden"
)

func TestListErrors(t *testing.T) {
	testCases := []struct {
		description   string
		args          []string
		flags         map[string]string
		expectedError string
		listFunc      func(filter filters.Args) (types.PluginsListResponse, error)
	}{
		{
			description:   "too many arguments",
			args:          []string{"foo"},
			expectedError: "accepts no arguments",
		},
		{
			description:   "error listing plugins",
			args:          []string{},
			expectedError: "error listing plugins",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{}, fmt.Errorf("error listing plugins")
			},
		},
		{
			description: "invalid format",
			args:        []string{},
			flags: map[string]string{
				"format": "{{invalid format}}",
			},
			expectedError: "Template parsing error",
		},
	}

	for _, tc := range testCases {
		cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
		cmd := newListCommand(cli)
		cmd.SetArgs(tc.args)
		for key, value := range tc.flags {
			cmd.Flags().Set(key, value)
		}
		cmd.SetOutput(ioutil.Discard)
		assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
	}
}

func TestList(t *testing.T) {
	singlePluginListFunc := func(filter filters.Args) (types.PluginsListResponse, error) {
		return types.PluginsListResponse{
			{
				ID:      "id-foo",
				Name:    "name-foo",
				Enabled: true,
				Config: types.PluginConfig{
					Description: "desc-bar",
				},
			},
		}, nil
	}

	testCases := []struct {
		description string
		args        []string
		flags       map[string]string
		golden      string
		listFunc    func(filter filters.Args) (types.PluginsListResponse, error)
	}{
		{
			description: "list with no additional flags",
			args:        []string{},
			golden:      "plugin-list-without-format.golden",
			listFunc:    singlePluginListFunc,
		},
		{
			description: "list with filters",
			args:        []string{},
			flags: map[string]string{
				"filter": "foo=bar",
			},
			golden: "plugin-list-without-format.golden",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				assert.Check(t, is.Equal("bar", filter.Get("foo")[0]))
				return singlePluginListFunc(filter)
			},
		},
		{
			description: "list with quiet option",
			args:        []string{},
			flags: map[string]string{
				"quiet": "true",
			},
			golden:   "plugin-list-with-quiet-option.golden",
			listFunc: singlePluginListFunc,
		},
		{
			description: "list with no-trunc option",
			args:        []string{},
			flags: map[string]string{
				"no-trunc": "true",
				"format":   "{{ .ID }}",
			},
			golden: "plugin-list-with-no-trunc-option.golden",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{
					{
						ID:      "xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd",
						Name:    "name-foo",
						Enabled: true,
						Config: types.PluginConfig{
							Description: "desc-bar",
						},
					},
				}, nil
			},
		},
		{
			description: "list with format",
			args:        []string{},
			flags: map[string]string{
				"format": "{{ .Name }}",
			},
			golden:   "plugin-list-with-format.golden",
			listFunc: singlePluginListFunc,
		},
		{
			description: "list output is sorted based on plugin name",
			args:        []string{},
			flags: map[string]string{
				"format": "{{ .Name }}",
			},
			golden: "plugin-list-sort.golden",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{
					{
						ID:   "id-1",
						Name: "plugin-1-foo",
					},
					{
						ID:   "id-2",
						Name: "plugin-10-foo",
					},
					{
						ID:   "id-3",
						Name: "plugin-2-foo",
					},
				}, nil
			},
		},
	}

	for _, tc := range testCases {
		cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
		cmd := newListCommand(cli)
		cmd.SetArgs(tc.args)
		for key, value := range tc.flags {
			cmd.Flags().Set(key, value)
		}
		assert.NilError(t, cmd.Execute())
		golden.Assert(t, cli.OutBuffer().String(), tc.golden)
	}
}
<commit_msg>cli/command/plugin/list_test.go:61:31: `TestList$1` - `filter` is unused (unparam)<commit_after>package plugin

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

	"github.com/docker/cli/internal/test"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"

	"gotest.tools/assert"
	is "gotest.tools/assert/cmp"
	"gotest.tools/golden"
)

func TestListErrors(t *testing.T) {
	testCases := []struct {
		description   string
		args          []string
		flags         map[string]string
		expectedError string
		listFunc      func(filter filters.Args) (types.PluginsListResponse, error)
	}{
		{
			description:   "too many arguments",
			args:          []string{"foo"},
			expectedError: "accepts no arguments",
		},
		{
			description:   "error listing plugins",
			args:          []string{},
			expectedError: "error listing plugins",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{}, fmt.Errorf("error listing plugins")
			},
		},
		{
			description: "invalid format",
			args:        []string{},
			flags: map[string]string{
				"format": "{{invalid format}}",
			},
			expectedError: "Template parsing error",
		},
	}

	for _, tc := range testCases {
		cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
		cmd := newListCommand(cli)
		cmd.SetArgs(tc.args)
		for key, value := range tc.flags {
			cmd.Flags().Set(key, value)
		}
		cmd.SetOutput(ioutil.Discard)
		assert.ErrorContains(t, cmd.Execute(), tc.expectedError)
	}
}

func TestList(t *testing.T) {
	singlePluginListFunc := func(_ filters.Args) (types.PluginsListResponse, error) {
		return types.PluginsListResponse{
			{
				ID:      "id-foo",
				Name:    "name-foo",
				Enabled: true,
				Config: types.PluginConfig{
					Description: "desc-bar",
				},
			},
		}, nil
	}

	testCases := []struct {
		description string
		args        []string
		flags       map[string]string
		golden      string
		listFunc    func(filter filters.Args) (types.PluginsListResponse, error)
	}{
		{
			description: "list with no additional flags",
			args:        []string{},
			golden:      "plugin-list-without-format.golden",
			listFunc:    singlePluginListFunc,
		},
		{
			description: "list with filters",
			args:        []string{},
			flags: map[string]string{
				"filter": "foo=bar",
			},
			golden: "plugin-list-without-format.golden",
			listFunc: func(filter filters.Args) (types.PluginsListResponse, error) {
				assert.Check(t, is.Equal("bar", filter.Get("foo")[0]))
				return singlePluginListFunc(filter)
			},
		},
		{
			description: "list with quiet option",
			args:        []string{},
			flags: map[string]string{
				"quiet": "true",
			},
			golden:   "plugin-list-with-quiet-option.golden",
			listFunc: singlePluginListFunc,
		},
		{
			description: "list with no-trunc option",
			args:        []string{},
			flags: map[string]string{
				"no-trunc": "true",
				"format":   "{{ .ID }}",
			},
			golden: "plugin-list-with-no-trunc-option.golden",
			listFunc: func(_ filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{
					{
						ID:      "xyg4z2hiSLO5yTnBJfg4OYia9gKA6Qjd",
						Name:    "name-foo",
						Enabled: true,
						Config: types.PluginConfig{
							Description: "desc-bar",
						},
					},
				}, nil
			},
		},
		{
			description: "list with format",
			args:        []string{},
			flags: map[string]string{
				"format": "{{ .Name }}",
			},
			golden:   "plugin-list-with-format.golden",
			listFunc: singlePluginListFunc,
		},
		{
			description: "list output is sorted based on plugin name",
			args:        []string{},
			flags: map[string]string{
				"format": "{{ .Name }}",
			},
			golden: "plugin-list-sort.golden",
			listFunc: func(_ filters.Args) (types.PluginsListResponse, error) {
				return types.PluginsListResponse{
					{
						ID:   "id-1",
						Name: "plugin-1-foo",
					},
					{
						ID:   "id-2",
						Name: "plugin-10-foo",
					},
					{
						ID:   "id-3",
						Name: "plugin-2-foo",
					},
				}, nil
			},
		},
	}

	for _, tc := range testCases {
		cli := test.NewFakeCli(&fakeClient{pluginListFunc: tc.listFunc})
		cmd := newListCommand(cli)
		cmd.SetArgs(tc.args)
		for key, value := range tc.flags {
			cmd.Flags().Set(key, value)
		}
		assert.NilError(t, cmd.Execute())
		golden.Assert(t, cli.OutBuffer().String(), tc.golden)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Janoš Guljaš <janos@resenje.org>
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httpClient

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func TestDefaultClient(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer ts.Close()

	r, err := Default.Get(ts.URL)
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestClientRetry(t *testing.T) {
	l, err := net.Listen("tcp", "")
	if err != nil {
		t.Error(err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()

	go func() {
		time.Sleep(2 * time.Second)

		l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
		if err != nil {
			t.Error(err)
		}
		defer l.Close()
		server := http.Server{
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
		}
		if err := server.Serve(l); err != nil {
			t.Error(err)
		}
	}()

	r, err := New(&Options{RetryTimeMax: 10 * time.Second}).Get(fmt.Sprintf("http://localhost:%d", port))
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestClientRetryFailure(t *testing.T) {
	l, err := net.Listen("tcp", "")
	if err != nil {
		t.Error(err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()

	go func() {
		time.Sleep(1 * time.Second)

		l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
		if err != nil {
			t.Error(err)
		}
		defer l.Close()
		server := http.Server{
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
		}
		if err := server.Serve(l); err != nil {
			t.Error(err)
		}
	}()

	r, err := New(&Options{RetryTimeMax: 1 * time.Second}).Get(fmt.Sprintf("http://localhost:%d", port))
	if err == nil || !strings.Contains(err.Error(), "getsockopt: connection refused") {
		t.Errorf("expected connection refused error, got $#v", err)
	}
	if r != nil {
		t.Error("unexpected not-nil response")
	}
}

func TestClientRedirectHeaders(t *testing.T) {
	want := "test httputils"
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/redirect" {
			http.Redirect(w, r, "/", http.StatusFound)
		}
		got := r.Header.Get("X-Test")
		if got != want {
			t.Errorf("expected X-Test header %q, got %q", want, got)
		}
	}))
	defer ts.Close()

	req, err := http.NewRequest("GET", ts.URL+"/redirect", nil)
	if err != nil {
		t.Error(err)
	}
	req.Header.Set("X-Test", want)
	r, err := Default.Do(req)
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestOptionsMarshalJSON(t *testing.T) {
	o := Options{
		Timeout:             30 * time.Second,
		KeepAlive:           3 * time.Minute,
		TLSHandshakeTimeout: 100 * time.Millisecond,
		TLSSkipVerify:       true,
		RetryTimeMax:        1 * time.Hour,
		RetrySleepMax:       10 * time.Second,
		RetrySleepBase:      10 * time.Microsecond,
	}

	b, err := o.MarshalJSON()
	if err != nil {
		t.Error(err.Error())
	}
	got := string(b)
	want := "{\"timeout\":\"30s\",\"keep-alive\":\"3m0s\",\"tls-handshake-timeout\":\"100ms\",\"tls-skip-verify\":true,\"retry-time-max\":\"1h0m0s\",\"retry-sleep-max\":\"10s\",\"retry-sleep-base\":\"10µs\"}"
	if got != want {
		t.Errorf("expected json %q, got %q", want, got)
	}
}

func TestOptionsUnmarshalJSON(t *testing.T) {
	o := &Options{}
	if err := o.UnmarshalJSON([]byte("{\"timeout\":\"30s\",\"keep-alive\":\"3m0s\",\"tls-handshake-timeout\":\"100ms\",\"tls-skip-verify\":true,\"retry-time-max\":\"1h0m0s\",\"retry-sleep-max\":\"10s\",\"retry-sleep-base\":\"10µs\"}")); err != nil {
		t.Error(err.Error())
	}

	Timeout := 30 * time.Second
	if o.Timeout != Timeout {
		t.Errorf("expected Timeout %v, got %v", Timeout, o.Timeout)
	}
	KeepAlive := 3 * time.Minute
	if o.KeepAlive != KeepAlive {
		t.Errorf("expected KeepAlive %v, got %v", KeepAlive, o.KeepAlive)
	}
	TLSHandshakeTimeout := 100 * time.Millisecond
	if o.TLSHandshakeTimeout != TLSHandshakeTimeout {
		t.Errorf("expected TLSHandshakeTimeout %v, got %v", TLSHandshakeTimeout, o.TLSHandshakeTimeout)
	}
	TLSSkipVerify := true
	if o.TLSSkipVerify != TLSSkipVerify {
		t.Errorf("expected TLSSkipVerify %v, got %v", TLSSkipVerify, o.TLSSkipVerify)
	}
	RetryTimeMax := 1 * time.Hour
	if o.RetryTimeMax != RetryTimeMax {
		t.Errorf("expected RetryTimeMax %v, got %v", RetryTimeMax, o.RetryTimeMax)
	}
	RetrySleepMax := 10 * time.Second
	if o.RetrySleepMax != RetrySleepMax {
		t.Errorf("expected RetrySleepMax %v, got %v", RetrySleepMax, o.RetrySleepMax)
	}
	RetrySleepBase := 10 * time.Microsecond
	if o.RetrySleepBase != RetrySleepBase {
		t.Errorf("expected RetrySleepBase %v, got %v", RetrySleepBase, o.RetrySleepBase)
	}
}

func TestOptionsUnmarshalJSONError(t *testing.T) {
	o := &Options{}
	e := "invalid character '1' looking for beginning of object key string"
	if err := o.UnmarshalJSON([]byte("{1}")); err == nil || err.Error() != e {
		t.Errorf("expected error %q, got %v", e, err)
	}
}
<commit_msg>Fix fmt mesage in test<commit_after>// Copyright (c) 2016, Janoš Guljaš <janos@resenje.org>
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package httpClient

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
	"time"
)

func TestDefaultClient(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer ts.Close()

	r, err := Default.Get(ts.URL)
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestClientRetry(t *testing.T) {
	l, err := net.Listen("tcp", "")
	if err != nil {
		t.Error(err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()

	go func() {
		time.Sleep(2 * time.Second)

		l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
		if err != nil {
			t.Error(err)
		}
		defer l.Close()
		server := http.Server{
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
		}
		if err := server.Serve(l); err != nil {
			t.Error(err)
		}
	}()

	r, err := New(&Options{RetryTimeMax: 10 * time.Second}).Get(fmt.Sprintf("http://localhost:%d", port))
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestClientRetryFailure(t *testing.T) {
	l, err := net.Listen("tcp", "")
	if err != nil {
		t.Error(err)
	}
	port := l.Addr().(*net.TCPAddr).Port
	l.Close()

	go func() {
		time.Sleep(1 * time.Second)

		l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
		if err != nil {
			t.Error(err)
		}
		defer l.Close()
		server := http.Server{
			Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}),
		}
		if err := server.Serve(l); err != nil {
			t.Error(err)
		}
	}()

	r, err := New(&Options{RetryTimeMax: 1 * time.Second}).Get(fmt.Sprintf("http://localhost:%d", port))
	if err == nil || !strings.Contains(err.Error(), "getsockopt: connection refused") {
		t.Errorf("expected connection refused error, got %#v", err)
	}
	if r != nil {
		t.Error("unexpected not-nil response")
	}
}

func TestClientRedirectHeaders(t *testing.T) {
	want := "test httputils"
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/redirect" {
			http.Redirect(w, r, "/", http.StatusFound)
		}
		got := r.Header.Get("X-Test")
		if got != want {
			t.Errorf("expected X-Test header %q, got %q", want, got)
		}
	}))
	defer ts.Close()

	req, err := http.NewRequest("GET", ts.URL+"/redirect", nil)
	if err != nil {
		t.Error(err)
	}
	req.Header.Set("X-Test", want)
	r, err := Default.Do(req)
	if err != nil {
		t.Error(err)
	}
	if r == nil {
		t.Error("unexpected nil response")
	}
}

func TestOptionsMarshalJSON(t *testing.T) {
	o := Options{
		Timeout:             30 * time.Second,
		KeepAlive:           3 * time.Minute,
		TLSHandshakeTimeout: 100 * time.Millisecond,
		TLSSkipVerify:       true,
		RetryTimeMax:        1 * time.Hour,
		RetrySleepMax:       10 * time.Second,
		RetrySleepBase:      10 * time.Microsecond,
	}

	b, err := o.MarshalJSON()
	if err != nil {
		t.Error(err.Error())
	}
	got := string(b)
	want := "{\"timeout\":\"30s\",\"keep-alive\":\"3m0s\",\"tls-handshake-timeout\":\"100ms\",\"tls-skip-verify\":true,\"retry-time-max\":\"1h0m0s\",\"retry-sleep-max\":\"10s\",\"retry-sleep-base\":\"10µs\"}"
	if got != want {
		t.Errorf("expected json %q, got %q", want, got)
	}
}

func TestOptionsUnmarshalJSON(t *testing.T) {
	o := &Options{}
	if err := o.UnmarshalJSON([]byte("{\"timeout\":\"30s\",\"keep-alive\":\"3m0s\",\"tls-handshake-timeout\":\"100ms\",\"tls-skip-verify\":true,\"retry-time-max\":\"1h0m0s\",\"retry-sleep-max\":\"10s\",\"retry-sleep-base\":\"10µs\"}")); err != nil {
		t.Error(err.Error())
	}

	Timeout := 30 * time.Second
	if o.Timeout != Timeout {
		t.Errorf("expected Timeout %v, got %v", Timeout, o.Timeout)
	}
	KeepAlive := 3 * time.Minute
	if o.KeepAlive != KeepAlive {
		t.Errorf("expected KeepAlive %v, got %v", KeepAlive, o.KeepAlive)
	}
	TLSHandshakeTimeout := 100 * time.Millisecond
	if o.TLSHandshakeTimeout != TLSHandshakeTimeout {
		t.Errorf("expected TLSHandshakeTimeout %v, got %v", TLSHandshakeTimeout, o.TLSHandshakeTimeout)
	}
	TLSSkipVerify := true
	if o.TLSSkipVerify != TLSSkipVerify {
		t.Errorf("expected TLSSkipVerify %v, got %v", TLSSkipVerify, o.TLSSkipVerify)
	}
	RetryTimeMax := 1 * time.Hour
	if o.RetryTimeMax != RetryTimeMax {
		t.Errorf("expected RetryTimeMax %v, got %v", RetryTimeMax, o.RetryTimeMax)
	}
	RetrySleepMax := 10 * time.Second
	if o.RetrySleepMax != RetrySleepMax {
		t.Errorf("expected RetrySleepMax %v, got %v", RetrySleepMax, o.RetrySleepMax)
	}
	RetrySleepBase := 10 * time.Microsecond
	if o.RetrySleepBase != RetrySleepBase {
		t.Errorf("expected RetrySleepBase %v, got %v", RetrySleepBase, o.RetrySleepBase)
	}
}

func TestOptionsUnmarshalJSONError(t *testing.T) {
	o := &Options{}
	e := "invalid character '1' looking for beginning of object key string"
	if err := o.UnmarshalJSON([]byte("{1}")); err == nil || err.Error() != e {
		t.Errorf("expected error %q, got %v", e, err)
	}
}
<|endoftext|>


<commit_before>package fire

import "net/http"

// Compose is a short-hand for chaining the specified middlewares and handler
// together.
func Compose(chain ...interface{}) http.Handler {
	// check length
	if len(chain) < 2 {
		panic("expected chain to have at least two items")
	}

	// get handler
	h, ok := chain[len(chain)-1].(http.Handler)
	if !ok {
		panic(`expected last chain item to be a "http.Handler"`)
	}

	// chain all middlewares
	for i := len(chain) - 2; i >= 0; i-- {
		// get middleware
		m, ok := chain[i].(func(http.Handler) http.Handler)
		if !ok {
			panic(`expected chain item to be a "func(http.handler) http.Handler"`)
		}

		// chain
		h = m(h)
	}

	return h
}
<commit_msg>make message case consistent<commit_after>package fire

import "net/http"

// Compose is a short-hand for chaining the specified middlewares and handler
// together.
func Compose(chain ...interface{}) http.Handler {
	// check length
	if len(chain) < 2 {
		panic("Expected chain to have at least two items")
	}

	// get handler
	h, ok := chain[len(chain)-1].(http.Handler)
	if !ok {
		panic(`Expected last chain item to be a "http.Handler"`)
	}

	// chain all middlewares
	for i := len(chain) - 2; i >= 0; i-- {
		// get middleware
		m, ok := chain[i].(func(http.Handler) http.Handler)
		if !ok {
			panic(`Expected chain item to be a "func(http.handler) http.Handler"`)
		}

		// chain
		h = m(h)
	}

	return h
}
<|endoftext|>


<commit_before>package stun

import (
	"crypto/md5" // #nosec
	"crypto/sha1"
	"errors"
	"fmt"
	"strings"

	"github.com/gortc/stun/internal/hmac"
)

// separator for credentials.
const credentialsSep = ":"

// NewLongTermIntegrity returns new MessageIntegrity with key for long-term
// credentials. Password, username, and realm must be SASL-prepared.
func NewLongTermIntegrity(username, realm, password string) MessageIntegrity {
	k := strings.Join(
		[]string{
			username,
			realm,
			password,
		},
		credentialsSep,
	)
	// #nosec
	h := md5.New()
	fmt.Fprint(h, k)
	return MessageIntegrity(h.Sum(nil))
}

// NewShortTermIntegrity returns new MessageIntegrity with key for short-term
// credentials. Password must be SASL-prepared.
func NewShortTermIntegrity(password string) MessageIntegrity {
	return MessageIntegrity(password)
}

// MessageIntegrity represents MESSAGE-INTEGRITY attribute.
//
// AddTo and GetFrom methods are using zero-allocation version of hmac, see
// internal/hmac/pool.go.
//
// RFC 5389 Section 15.4
type MessageIntegrity []byte

// ErrFingerprintBeforeIntegrity means that FINGEPRINT attribute is already in
// message, so MESSAGE-INTEGRITY attribute cannot be added.
var ErrFingerprintBeforeIntegrity = errors.New(
	"FINGERPRINT before MESSAGE-INTEGRITY attribute",
)

func (i MessageIntegrity) String() string {
	return fmt.Sprintf("KEY: 0x%x", []byte(i))
}

const messageIntegritySize = 20

// AddTo adds MESSAGE-INTEGRITY attribute to message. Be advised, CPU
// and allocations costly, can be cause of DOS.
func (i MessageIntegrity) AddTo(m *Message) error {
	for _, a := range m.Attributes {
		// Message should not contain FINGERPRINT attribute
		// before MESSAGE-INTEGRITY.
		if a.Type == AttrFingerprint {
			return ErrFingerprintBeforeIntegrity
		}
	}
	// The text used as input to HMAC is the STUN message,
	// including the header, up to and including the attribute preceding the
	// MESSAGE-INTEGRITY attribute.
	length := m.Length
	// Adjusting m.Length to contain MESSAGE-INTEGRITY TLV.
	m.Length += messageIntegritySize + attributeHeaderSize
	m.WriteLength()                            // writing length to m.Raw
	v := newHMAC(i, m.Raw, m.Raw[len(m.Raw):]) // calculating HMAC for adjusted m.Raw
	m.Length = length                          // changing m.Length back

	// Copy hmac value to temporary variable to protect it from resetting
	// while processing m.Add call.
	vBuf := make([]byte, sha1.Size)
	copy(vBuf, v)

	m.Add(AttrMessageIntegrity, vBuf)
	return nil
}

// ErrIntegrityMismatch means that computed HMAC differs from expected.
var ErrIntegrityMismatch = errors.New("integrity check failed")

func newHMAC(key, message, buf []byte) []byte {
	mac := hmac.AcquireSHA1(key)
	writeOrPanic(mac, message)
	defer hmac.PutSHA1(mac)
	return mac.Sum(buf)
}

// Check checks MESSAGE-INTEGRITY attribute. Be advised, CPU and allocations
// costly, can be cause of DOS.
func (i MessageIntegrity) Check(m *Message) error {
	v, err := m.Get(AttrMessageIntegrity)
	if err != nil {
		return err
	}

	// Adjusting length in header to match m.Raw that was
	// used when computing HMAC.
	var (
		length         = m.Length
		afterIntegrity = false
		sizeReduced    int
	)
	for _, a := range m.Attributes {
		if afterIntegrity {
			sizeReduced += nearestPaddedValueLength(int(a.Length))
			sizeReduced += attributeHeaderSize
		}
		if a.Type == AttrMessageIntegrity {
			afterIntegrity = true
		}
	}
	m.Length -= uint32(sizeReduced)
	m.WriteLength()
	// startOfHMAC should be first byte of integrity attribute.
	startOfHMAC := messageHeaderSize + m.Length - (attributeHeaderSize + messageIntegritySize)
	b := m.Raw[:startOfHMAC] // data before integrity attribute
	expected := newHMAC(i, b, m.Raw[len(m.Raw):])
	m.Length = length
	m.WriteLength() // writing length back
	return checkHMAC(v, expected)
}
<commit_msg>a:integrity: remove unnecessary multiline declaration and fix comment<commit_after>package stun

import (
	"crypto/md5" // #nosec
	"crypto/sha1"
	"errors"
	"fmt"
	"strings"

	"github.com/gortc/stun/internal/hmac"
)

// separator for credentials.
const credentialsSep = ":"

// NewLongTermIntegrity returns new MessageIntegrity with key for long-term
// credentials. Password, username, and realm must be SASL-prepared.
func NewLongTermIntegrity(username, realm, password string) MessageIntegrity {
	k := strings.Join(
		[]string{
			username,
			realm,
			password,
		},
		credentialsSep,
	)
	// #nosec
	h := md5.New()
	fmt.Fprint(h, k)
	return MessageIntegrity(h.Sum(nil))
}

// NewShortTermIntegrity returns new MessageIntegrity with key for short-term
// credentials. Password must be SASL-prepared.
func NewShortTermIntegrity(password string) MessageIntegrity {
	return MessageIntegrity(password)
}

// MessageIntegrity represents MESSAGE-INTEGRITY attribute.
//
// AddTo and GetFrom methods are using zero-allocation version of hmac, see
// internal/hmac/pool.go.
//
// RFC 5389 Section 15.4
type MessageIntegrity []byte

// ErrFingerprintBeforeIntegrity means that FINGERPRINT attribute is already in
// message, so MESSAGE-INTEGRITY attribute cannot be added.
var ErrFingerprintBeforeIntegrity = errors.New("FINGERPRINT before MESSAGE-INTEGRITY attribute")

func (i MessageIntegrity) String() string {
	return fmt.Sprintf("KEY: 0x%x", []byte(i))
}

const messageIntegritySize = 20

// AddTo adds MESSAGE-INTEGRITY attribute to message. Be advised, CPU
// and allocations costly, can be cause of DOS.
func (i MessageIntegrity) AddTo(m *Message) error {
	for _, a := range m.Attributes {
		// Message should not contain FINGERPRINT attribute
		// before MESSAGE-INTEGRITY.
		if a.Type == AttrFingerprint {
			return ErrFingerprintBeforeIntegrity
		}
	}
	// The text used as input to HMAC is the STUN message,
	// including the header, up to and including the attribute preceding the
	// MESSAGE-INTEGRITY attribute.
	length := m.Length
	// Adjusting m.Length to contain MESSAGE-INTEGRITY TLV.
	m.Length += messageIntegritySize + attributeHeaderSize
	m.WriteLength()                            // writing length to m.Raw
	v := newHMAC(i, m.Raw, m.Raw[len(m.Raw):]) // calculating HMAC for adjusted m.Raw
	m.Length = length                          // changing m.Length back

	// Copy hmac value to temporary variable to protect it from resetting
	// while processing m.Add call.
	vBuf := make([]byte, sha1.Size)
	copy(vBuf, v)

	m.Add(AttrMessageIntegrity, vBuf)
	return nil
}

// ErrIntegrityMismatch means that computed HMAC differs from expected.
var ErrIntegrityMismatch = errors.New("integrity check failed")

func newHMAC(key, message, buf []byte) []byte {
	mac := hmac.AcquireSHA1(key)
	writeOrPanic(mac, message)
	defer hmac.PutSHA1(mac)
	return mac.Sum(buf)
}

// Check checks MESSAGE-INTEGRITY attribute. Be advised, CPU and allocations
// costly, can be cause of DOS.
func (i MessageIntegrity) Check(m *Message) error {
	v, err := m.Get(AttrMessageIntegrity)
	if err != nil {
		return err
	}

	// Adjusting length in header to match m.Raw that was
	// used when computing HMAC.
	var (
		length         = m.Length
		afterIntegrity = false
		sizeReduced    int
	)
	for _, a := range m.Attributes {
		if afterIntegrity {
			sizeReduced += nearestPaddedValueLength(int(a.Length))
			sizeReduced += attributeHeaderSize
		}
		if a.Type == AttrMessageIntegrity {
			afterIntegrity = true
		}
	}
	m.Length -= uint32(sizeReduced)
	m.WriteLength()
	// startOfHMAC should be first byte of integrity attribute.
	startOfHMAC := messageHeaderSize + m.Length - (attributeHeaderSize + messageIntegritySize)
	b := m.Raw[:startOfHMAC] // data before integrity attribute
	expected := newHMAC(i, b, m.Raw[len(m.Raw):])
	m.Length = length
	m.WriteLength() // writing length back
	return checkHMAC(v, expected)
}
<|endoftext|>


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

// Generic JSON representation.

package json

import (
	"array";
	"fmt";
	"math";
	"json";
	"strconv";
	"strings";
)

export const (
	StringKind = iota;
	NumberKind;
	MapKind;		// JSON term is "Object", but in Go, it's a map
	ArrayKind;
	BoolKind;
	NullKind;
)

export type Json interface {
	Kind() int;
	String() string;
	Number() float64;
	Bool() bool;
	Get(s string) Json;
	Elem(i int) Json;
	Len() int;
}

export func JsonToString(j Json) string {
	if j == nil {
		return "null"
	}
	if j.Kind() == StringKind {
		return Quote(j.String())
	}
	return j.String()
}

type Null struct { }
export var null Json = &Null{}
func (*Null) Kind() int { return NullKind }
func (*Null) String() string { return "null" }
func (*Null) Number() float64 { return 0 }
func (*Null) Bool() bool { return false }
func (*Null) Get(s string) Json { return null }
func (*Null) Elem(int) Json { return null }
func (*Null) Len() int { return 0 }

type String struct { s string; Null }
func (j *String) Kind() int { return StringKind }
func (j *String) String() string { return j.s }

type Number struct { f float64; Null }
func (j *Number) Kind() int { return NumberKind }
func (j *Number) Number() float64 { return j.f }
func (j *Number) String() string {
	if math.Floor(j.f) == j.f {
		return fmt.sprintf("%.0f", j.f);
	}
	return fmt.sprintf("%g", j.f);
}

type Array struct { a *array.Array; Null }
func (j *Array) Kind() int { return ArrayKind }
func (j *Array) Len() int { return j.a.Len() }
func (j *Array) Elem(i int) Json {
	if i < 0 || i >= j.a.Len() {
		return null
	}
	return j.a.At(i)
}
func (j *Array) String() string {
	s := "[";
	for i := 0; i < j.a.Len(); i++ {
		if i > 0 {
			s += ",";
		}
		s += JsonToString(j.a.At(i).(Json));
	}
	s += "]";
	return s;
}

type Bool struct { b bool; Null }
func (j *Bool) Kind() int { return BoolKind }
func (j *Bool) Bool() bool { return j.b }
func (j *Bool) String() string {
	if j.b {
		return "true"
	}
	return "false"
}

type Map struct { m *map[string]Json; Null }
func (j *Map) Kind() int { return MapKind }
func (j *Map) Get(s string) Json {
	if j.m == nil {
		return null
	}
	v, ok := j.m[s];
	if !ok {
		return null
	}
	return v;
}
func (j *Map) String() string {
	s := "{";
	first := true;
	for k,v range j.m {
		if first {
			first = false;
		} else {
			s += ",";
		}
		s += Quote(k);
		s += ":";
		s += JsonToString(v);
	}
	s += "}";
	return s;
}

export func Walk(j Json, path string) Json {
	for len(path) > 0 {
		var elem string;
		if i := strings.index(path, '/'); i >= 0 {
			elem = path[0:i];
			path = path[i+1:len(path)];
		} else {
			elem = path;
			path = "";
		}
		switch j.Kind() {
		case ArrayKind:
			indx, err := strconv.atoi(elem);
			if err != nil {
				return null
			}
			j = j.Elem(indx);
		case MapKind:
			j = j.Get(elem);
		default:
			return null
		}
	}
	return j
}

export func Equal(a, b Json) bool {
	switch {
	case a == nil && b == nil:
		return true;
	case a == nil || b == nil:
		return false;
	case a.Kind() != b.Kind():
		return false;
	}

	switch a.Kind() {
	case NullKind:
		return true;
	case StringKind:
		return a.String() == b.String();
	case NumberKind:
		return a.Number() == b.Number();
	case BoolKind:
		return a.Bool() == b.Bool();
	case ArrayKind:
		if a.Len() != b.Len() {
			return false;
		}
		for i := 0; i < a.Len(); i++ {
			if !Equal(a.Elem(i), b.Elem(i)) {
				return false;
			}
		}
		return true;
	case MapKind:
		m := a.(*Map).m;
		if len(m) != len(b.(*Map).m) {
			return false;
		}
		for k,v range m {
			if !Equal(v, b.Get(k)) {
				return false;
			}
		}
		return true;
	}

	// invalid kind
	return false;
}

// Parse builder for Json objects.

type JsonBuilder struct {
	// either writing to *ptr
	ptr *Json;

	// or to a[i] (can't set ptr = &a[i])
	a *array.Array;
	i int;

	// or to m[k] (can't set ptr = &m[k])
	m *map[string] Json;
	k string;
}

func (b *JsonBuilder) Put(j Json) {
	switch {
	case b.ptr != nil:
		*b.ptr = j;
	case b.a != nil:
		b.a.Set(b.i, j);
	case b.m != nil:
		b.m[b.k] = j;
	}
}

func (b *JsonBuilder) Get() Json {
	switch {
	case b.ptr != nil:
		return *b.ptr;
	case b.a != nil:
		return b.a.At(b.i);
	case b.m != nil:
		return b.m[b.k];
	}
	return nil
}

func (b *JsonBuilder) Float64(f float64) {
	b.Put(&Number{f, Null{}})
}

func (b *JsonBuilder) Int64(i int64) {
	b.Float64(float64(i))
}

func (b *JsonBuilder) Uint64(i uint64) {
	b.Float64(float64(i))
}

func (b *JsonBuilder) Bool(tf bool) {
	b.Put(&Bool{tf, Null{}})
}

func (b *JsonBuilder) Null() {
	b.Put(null)
}

func (b *JsonBuilder) String(s string) {
	b.Put(&String{s, Null{}})
}

func (b *JsonBuilder) Array() {
	b.Put(&Array{array.New(0), Null{}})
}

func (b *JsonBuilder) Map() {
	b.Put(&Map{new(map[string]Json), Null{}})
}

func (b *JsonBuilder) Elem(i int) Builder {
	bb := new(JsonBuilder);
	bb.a = b.Get().(*Array).a;
	bb.i = i;
	for i >= bb.a.Len() {
		bb.a.Push(null)
	}
	return bb
}

func (b *JsonBuilder) Key(k string) Builder {
	bb := new(JsonBuilder);
	bb.m = b.Get().(*Map).m;
	bb.k = k;
	bb.m[k] = null;
	return bb
}

export func StringToJson(s string) (json Json, ok bool, errtok string) {
	var errindx int;
	var j Json;
	b := new(JsonBuilder);
	b.ptr = &j;
	ok, errindx, errtok = Parse(s, b);
	if !ok {
		return nil, false, errtok
	}
	return j, true, ""
}
<commit_msg>remove implicit int -> string<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Generic JSON representation.

package json

import (
	"array";
	"fmt";
	"math";
	"json";
	"strconv";
	"strings";
)

export const (
	StringKind = iota;
	NumberKind;
	MapKind;		// JSON term is "Object", but in Go, it's a map
	ArrayKind;
	BoolKind;
	NullKind;
)

export type Json interface {
	Kind() int;
	String() string;
	Number() float64;
	Bool() bool;
	Get(s string) Json;
	Elem(i int) Json;
	Len() int;
}

export func JsonToString(j Json) string {
	if j == nil {
		return "null"
	}
	if j.Kind() == StringKind {
		return Quote(j.String())
	}
	return j.String()
}

type Null struct { }
export var null Json = &Null{}
func (*Null) Kind() int { return NullKind }
func (*Null) String() string { return "null" }
func (*Null) Number() float64 { return 0 }
func (*Null) Bool() bool { return false }
func (*Null) Get(s string) Json { return null }
func (*Null) Elem(int) Json { return null }
func (*Null) Len() int { return 0 }

type String struct { s string; Null }
func (j *String) Kind() int { return StringKind }
func (j *String) String() string { return j.s }

type Number struct { f float64; Null }
func (j *Number) Kind() int { return NumberKind }
func (j *Number) Number() float64 { return j.f }
func (j *Number) String() string {
	if math.Floor(j.f) == j.f {
		return fmt.sprintf("%.0f", j.f);
	}
	return fmt.sprintf("%g", j.f);
}

type Array struct { a *array.Array; Null }
func (j *Array) Kind() int { return ArrayKind }
func (j *Array) Len() int { return j.a.Len() }
func (j *Array) Elem(i int) Json {
	if i < 0 || i >= j.a.Len() {
		return null
	}
	return j.a.At(i)
}
func (j *Array) String() string {
	s := "[";
	for i := 0; i < j.a.Len(); i++ {
		if i > 0 {
			s += ",";
		}
		s += JsonToString(j.a.At(i).(Json));
	}
	s += "]";
	return s;
}

type Bool struct { b bool; Null }
func (j *Bool) Kind() int { return BoolKind }
func (j *Bool) Bool() bool { return j.b }
func (j *Bool) String() string {
	if j.b {
		return "true"
	}
	return "false"
}

type Map struct { m *map[string]Json; Null }
func (j *Map) Kind() int { return MapKind }
func (j *Map) Get(s string) Json {
	if j.m == nil {
		return null
	}
	v, ok := j.m[s];
	if !ok {
		return null
	}
	return v;
}
func (j *Map) String() string {
	s := "{";
	first := true;
	for k,v range j.m {
		if first {
			first = false;
		} else {
			s += ",";
		}
		s += Quote(k);
		s += ":";
		s += JsonToString(v);
	}
	s += "}";
	return s;
}

export func Walk(j Json, path string) Json {
	for len(path) > 0 {
		var elem string;
		if i := strings.index(path, "/"); i >= 0 {
			elem = path[0:i];
			path = path[i+1:len(path)];
		} else {
			elem = path;
			path = "";
		}
		switch j.Kind() {
		case ArrayKind:
			indx, err := strconv.atoi(elem);
			if err != nil {
				return null
			}
			j = j.Elem(indx);
		case MapKind:
			j = j.Get(elem);
		default:
			return null
		}
	}
	return j
}

export func Equal(a, b Json) bool {
	switch {
	case a == nil && b == nil:
		return true;
	case a == nil || b == nil:
		return false;
	case a.Kind() != b.Kind():
		return false;
	}

	switch a.Kind() {
	case NullKind:
		return true;
	case StringKind:
		return a.String() == b.String();
	case NumberKind:
		return a.Number() == b.Number();
	case BoolKind:
		return a.Bool() == b.Bool();
	case ArrayKind:
		if a.Len() != b.Len() {
			return false;
		}
		for i := 0; i < a.Len(); i++ {
			if !Equal(a.Elem(i), b.Elem(i)) {
				return false;
			}
		}
		return true;
	case MapKind:
		m := a.(*Map).m;
		if len(m) != len(b.(*Map).m) {
			return false;
		}
		for k,v range m {
			if !Equal(v, b.Get(k)) {
				return false;
			}
		}
		return true;
	}

	// invalid kind
	return false;
}

// Parse builder for Json objects.

type JsonBuilder struct {
	// either writing to *ptr
	ptr *Json;

	// or to a[i] (can't set ptr = &a[i])
	a *array.Array;
	i int;

	// or to m[k] (can't set ptr = &m[k])
	m *map[string] Json;
	k string;
}

func (b *JsonBuilder) Put(j Json) {
	switch {
	case b.ptr != nil:
		*b.ptr = j;
	case b.a != nil:
		b.a.Set(b.i, j);
	case b.m != nil:
		b.m[b.k] = j;
	}
}

func (b *JsonBuilder) Get() Json {
	switch {
	case b.ptr != nil:
		return *b.ptr;
	case b.a != nil:
		return b.a.At(b.i);
	case b.m != nil:
		return b.m[b.k];
	}
	return nil
}

func (b *JsonBuilder) Float64(f float64) {
	b.Put(&Number{f, Null{}})
}

func (b *JsonBuilder) Int64(i int64) {
	b.Float64(float64(i))
}

func (b *JsonBuilder) Uint64(i uint64) {
	b.Float64(float64(i))
}

func (b *JsonBuilder) Bool(tf bool) {
	b.Put(&Bool{tf, Null{}})
}

func (b *JsonBuilder) Null() {
	b.Put(null)
}

func (b *JsonBuilder) String(s string) {
	b.Put(&String{s, Null{}})
}

func (b *JsonBuilder) Array() {
	b.Put(&Array{array.New(0), Null{}})
}

func (b *JsonBuilder) Map() {
	b.Put(&Map{new(map[string]Json), Null{}})
}

func (b *JsonBuilder) Elem(i int) Builder {
	bb := new(JsonBuilder);
	bb.a = b.Get().(*Array).a;
	bb.i = i;
	for i >= bb.a.Len() {
		bb.a.Push(null)
	}
	return bb
}

func (b *JsonBuilder) Key(k string) Builder {
	bb := new(JsonBuilder);
	bb.m = b.Get().(*Map).m;
	bb.k = k;
	bb.m[k] = null;
	return bb
}

export func StringToJson(s string) (json Json, ok bool, errtok string) {
	var errindx int;
	var j Json;
	b := new(JsonBuilder);
	b.ptr = &j;
	ok, errindx, errtok = Parse(s, b);
	if !ok {
		return nil, false, errtok
	}
	return j, true, ""
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/gob"
	"io"
	"time"

	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/filegenerator"
	"github.com/Symantec/tricorder/go/tricorder"
	"github.com/Symantec/tricorder/go/tricorder/units"
)

func newManager(objSrv objectserver.ObjectServer, logger log.Logger) *Manager {
	sourceReconnectChannel := make(chan string)
	m := &Manager{
		sourceMap:              make(map[string]*sourceType),
		objectServer:           objSrv,
		machineMap:             make(map[string]*machineType),
		addMachineChannel:      make(chan *machineType),
		removeMachineChannel:   make(chan string),
		updateMachineChannel:   make(chan *machineType),
		serverMessageChannel:   make(chan *serverMessageType),
		sourceReconnectChannel: sourceReconnectChannel,
		objectWaiters:          make(map[hash.Hash][]chan<- hash.Hash),
		logger:                 logger}
	tricorder.RegisterMetric("filegen/client/num-object-waiters",
		&m.numObjectWaiters.value, units.None,
		"number of goroutines waiting for objects")
	go m.manage(sourceReconnectChannel)
	return m
}

func (m *Manager) manage(sourceConnectChannel <-chan string) {
	for {
		select {
		case machine := <-m.addMachineChannel:
			m.addMachine(machine)
		case hostname := <-m.removeMachineChannel:
			m.removeMachine(hostname)
		case machine := <-m.updateMachineChannel:
			m.updateMachine(machine)
		case serverMessage := <-m.serverMessageChannel:
			m.processMessage(serverMessage)
		case sourceName := <-sourceConnectChannel:
			m.processSourceConnect(sourceName)
		}
	}
}

func (m *Manager) processMessage(serverMessage *serverMessageType) {
	if msg := serverMessage.serverMessage.GetObjectResponse; msg != nil {
		if _, _, err := m.objectServer.AddObject(
			bytes.NewReader(msg.Data), 0, &msg.Hash); err != nil {
			m.logger.Println(err)
		} else {
			if waiters, ok := m.objectWaiters[msg.Hash]; ok {
				for _, channel := range waiters {
					channel <- msg.Hash
				}
				delete(m.objectWaiters, msg.Hash)
			}
		}
	}
	if msg := serverMessage.serverMessage.YieldResponse; msg != nil {
		if machine, ok := m.machineMap[msg.Hostname]; ok {
			m.handleYieldResponse(machine, msg.Files)
		} // else machine no longer known. Drop the message.
	}
}

func (m *Manager) processSourceConnect(sourceName string) {
	source := m.sourceMap[sourceName]
	for _, machine := range m.machineMap {
		if pathnames, ok := machine.sourceToPaths[sourceName]; ok {
			request := &proto.ClientRequest{
				YieldRequest: &proto.YieldRequest{machine.machine, pathnames}}
			source.sendChannel <- request
		}
	}
}

func (m *Manager) getSource(sourceName string) *sourceType {
	source, ok := m.sourceMap[sourceName]
	if ok {
		return source
	}
	source = new(sourceType)
	sendChannel := make(chan *proto.ClientRequest, 4096)
	source.sendChannel = sendChannel
	m.sourceMap[sourceName] = source
	go manageSource(sourceName, m.sourceReconnectChannel, sendChannel,
		m.serverMessageChannel, m.logger)
	return source
}

func manageSource(sourceName string, sourceReconnectChannel chan<- string,
	clientRequestChannel <-chan *proto.ClientRequest,
	serverMessageChannel chan<- *serverMessageType, logger log.Logger) {
	closeNotifyChannel := make(chan struct{})
	initialRetryTimeout := time.Millisecond * 100
	retryTimeout := initialRetryTimeout
	reconnect := false
	for ; ; time.Sleep(retryTimeout) {
		if retryTimeout < time.Minute {
			retryTimeout *= 2
		}
		client, err := srpc.DialHTTP("tcp", sourceName, time.Second*15)
		if err != nil {
			logger.Printf("error connecting to: %s: %s\n", sourceName, err)
			continue
		}
		conn, err := client.Call("FileGenerator.Connect")
		if err != nil {
			client.Close()
			logger.Println(err)
			continue
		}
		retryTimeout = initialRetryTimeout
		// The server keeps the same encoder/decoder pair over the lifetime of
		// the connection, so we must do the same.
		go handleServerMessages(sourceName, gob.NewDecoder(conn),
			serverMessageChannel, closeNotifyChannel, logger)
		if reconnect {
			sourceReconnectChannel <- sourceName
		} else {
			reconnect = true
		}
		sendClientRequests(conn, clientRequestChannel, closeNotifyChannel,
			logger)
		conn.Close()
		client.Close()
	}
}

func sendClientRequests(conn *srpc.Conn,
	clientRequestChannel <-chan *proto.ClientRequest,
	closeNotifyChannel <-chan struct{}, logger log.Logger) {
	encoder := gob.NewEncoder(conn)
	for {
		select {
		case clientRequest := <-clientRequestChannel:
			if err := encoder.Encode(clientRequest); err != nil {
				logger.Printf("error encoding client request: %s\n", err)
				return
			}
			if len(clientRequestChannel) < 1 {
				if err := conn.Flush(); err != nil {
					logger.Printf("error flushing: %s\n", err)
					return
				}
			}
		case <-closeNotifyChannel:
			return
		}
	}
}

func handleServerMessages(sourceName string, decoder *gob.Decoder,
	serverMessageChannel chan<- *serverMessageType,
	closeNotifyChannel chan<- struct{}, logger log.Logger) {
	for {
		var message proto.ServerMessage
		if err := decoder.Decode(&message); err != nil {
			if err == io.EOF {
				logger.Printf("connection to source: %s closed\n", sourceName)
			} else {
				logger.Println(err)
			}
			closeNotifyChannel <- struct{}{}
			return
		}
		serverMessageChannel <- &serverMessageType{sourceName, message}
	}
}
<commit_msg>Switch lib/filegen/client to use connection Decode and Encode methods.<commit_after>package client

import (
	"bytes"
	"io"
	"time"

	"github.com/Symantec/Dominator/lib/hash"
	"github.com/Symantec/Dominator/lib/log"
	"github.com/Symantec/Dominator/lib/objectserver"
	"github.com/Symantec/Dominator/lib/srpc"
	proto "github.com/Symantec/Dominator/proto/filegenerator"
	"github.com/Symantec/tricorder/go/tricorder"
	"github.com/Symantec/tricorder/go/tricorder/units"
)

func newManager(objSrv objectserver.ObjectServer, logger log.Logger) *Manager {
	sourceReconnectChannel := make(chan string)
	m := &Manager{
		sourceMap:              make(map[string]*sourceType),
		objectServer:           objSrv,
		machineMap:             make(map[string]*machineType),
		addMachineChannel:      make(chan *machineType),
		removeMachineChannel:   make(chan string),
		updateMachineChannel:   make(chan *machineType),
		serverMessageChannel:   make(chan *serverMessageType),
		sourceReconnectChannel: sourceReconnectChannel,
		objectWaiters:          make(map[hash.Hash][]chan<- hash.Hash),
		logger:                 logger}
	tricorder.RegisterMetric("filegen/client/num-object-waiters",
		&m.numObjectWaiters.value, units.None,
		"number of goroutines waiting for objects")
	go m.manage(sourceReconnectChannel)
	return m
}

func (m *Manager) manage(sourceConnectChannel <-chan string) {
	for {
		select {
		case machine := <-m.addMachineChannel:
			m.addMachine(machine)
		case hostname := <-m.removeMachineChannel:
			m.removeMachine(hostname)
		case machine := <-m.updateMachineChannel:
			m.updateMachine(machine)
		case serverMessage := <-m.serverMessageChannel:
			m.processMessage(serverMessage)
		case sourceName := <-sourceConnectChannel:
			m.processSourceConnect(sourceName)
		}
	}
}

func (m *Manager) processMessage(serverMessage *serverMessageType) {
	if msg := serverMessage.serverMessage.GetObjectResponse; msg != nil {
		if _, _, err := m.objectServer.AddObject(
			bytes.NewReader(msg.Data), 0, &msg.Hash); err != nil {
			m.logger.Println(err)
		} else {
			if waiters, ok := m.objectWaiters[msg.Hash]; ok {
				for _, channel := range waiters {
					channel <- msg.Hash
				}
				delete(m.objectWaiters, msg.Hash)
			}
		}
	}
	if msg := serverMessage.serverMessage.YieldResponse; msg != nil {
		if machine, ok := m.machineMap[msg.Hostname]; ok {
			m.handleYieldResponse(machine, msg.Files)
		} // else machine no longer known. Drop the message.
	}
}

func (m *Manager) processSourceConnect(sourceName string) {
	source := m.sourceMap[sourceName]
	for _, machine := range m.machineMap {
		if pathnames, ok := machine.sourceToPaths[sourceName]; ok {
			request := &proto.ClientRequest{
				YieldRequest: &proto.YieldRequest{machine.machine, pathnames}}
			source.sendChannel <- request
		}
	}
}

func (m *Manager) getSource(sourceName string) *sourceType {
	source, ok := m.sourceMap[sourceName]
	if ok {
		return source
	}
	source = new(sourceType)
	sendChannel := make(chan *proto.ClientRequest, 4096)
	source.sendChannel = sendChannel
	m.sourceMap[sourceName] = source
	go manageSource(sourceName, m.sourceReconnectChannel, sendChannel,
		m.serverMessageChannel, m.logger)
	return source
}

func manageSource(sourceName string, sourceReconnectChannel chan<- string,
	clientRequestChannel <-chan *proto.ClientRequest,
	serverMessageChannel chan<- *serverMessageType, logger log.Logger) {
	closeNotifyChannel := make(chan struct{})
	initialRetryTimeout := time.Millisecond * 100
	retryTimeout := initialRetryTimeout
	reconnect := false
	for ; ; time.Sleep(retryTimeout) {
		if retryTimeout < time.Minute {
			retryTimeout *= 2
		}
		client, err := srpc.DialHTTP("tcp", sourceName, time.Second*15)
		if err != nil {
			logger.Printf("error connecting to: %s: %s\n", sourceName, err)
			continue
		}
		conn, err := client.Call("FileGenerator.Connect")
		if err != nil {
			client.Close()
			logger.Println(err)
			continue
		}
		retryTimeout = initialRetryTimeout
		go handleServerMessages(sourceName, conn, serverMessageChannel,
			closeNotifyChannel, logger)
		if reconnect {
			sourceReconnectChannel <- sourceName
		} else {
			reconnect = true
		}
		sendClientRequests(conn, clientRequestChannel, closeNotifyChannel,
			logger)
		conn.Close()
		client.Close()
	}
}

func sendClientRequests(conn *srpc.Conn,
	clientRequestChannel <-chan *proto.ClientRequest,
	closeNotifyChannel <-chan struct{}, logger log.Logger) {
	for {
		select {
		case clientRequest := <-clientRequestChannel:
			if err := conn.Encode(clientRequest); err != nil {
				logger.Printf("error encoding client request: %s\n", err)
				return
			}
			if len(clientRequestChannel) < 1 {
				if err := conn.Flush(); err != nil {
					logger.Printf("error flushing: %s\n", err)
					return
				}
			}
		case <-closeNotifyChannel:
			return
		}
	}
}

func handleServerMessages(sourceName string, decoder srpc.Decoder,
	serverMessageChannel chan<- *serverMessageType,
	closeNotifyChannel chan<- struct{}, logger log.Logger) {
	for {
		var message proto.ServerMessage
		if err := decoder.Decode(&message); err != nil {
			if err == io.EOF {
				logger.Printf("connection to source: %s closed\n", sourceName)
			} else {
				logger.Println(err)
			}
			closeNotifyChannel <- struct{}{}
			return
		}
		serverMessageChannel <- &serverMessageType{sourceName, message}
	}
}
<|endoftext|>


<commit_before>package fragbag

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"

	"github.com/TuftsBCB/seq"
	"github.com/TuftsBCB/structure"
)

type Library interface {
	// Save should save the fragment library to the writer provided.
	// No particular format is specified by the public API.
	Save(w io.Writer) error

	// Size returns the number of fragments in the library.
	Size() int

	// FragmentSize returns the size of every fragment in the library.
	// All fragments in a library must have the same size.
	FragmentSize() int

	// String returns a custom string representation of the library.
	// This may be anything.
	String() string

	// Name returns a canonical name for this fragment library.
	Name() string
}

type StructureLibrary interface {
	Library
	Best([]structure.Coords) int
	Fragment(i int) StructureFragment
}

type StructureFragment interface {
	Number() int
	String() string
	Atoms() []structure.Coords
}

type SequenceLibrary interface {
	Library
	Best(seq.Sequence) int
	Fragment(i int) SequenceFragment
}

type SequenceFragment interface {
	Number() int
	String() string
	AlignmentProb(seq.Sequence) seq.Prob
}

type libKind string

const (
	kindStructureAtoms  libKind = "structure-atoms"
	kindSequenceProfile         = "sequence-profile"
	kindSequenceHMM             = "sequence-hmm"
)

func (k libKind) String() string {
	return string(k)
}

type jsonLibrary struct {
	Kind    libKind
	Library json.RawMessage
}

// Open reads a library from the reader provided. If there is a problem
// reading or parsing the data as a library, an error is returned.
// If no error is returned, the Library returned is guarnateed to be one
// of the following types of fragment libraries:
// StructureLibrary, SequenceLibrary.
func Open(r io.Reader) (Library, error) {
	var jsonlib jsonLibrary
	dec := json.NewDecoder(r)
	if err := dec.Decode(&jsonlib); err != nil {
		return nil, err
	}

	bytesr := bytes.NewReader(jsonlib.Library)
	switch jsonlib.Kind {
	case kindStructureAtoms:
		return openStructureAtoms(bytesr)
	case kindSequenceProfile:
		return openSequenceProfile(bytesr)
	case kindSequenceHMM:
		return openSequenceHMM(bytesr)
	}
	return nil, fmt.Errorf("Unknown fragment library type: %s", jsonlib.Kind)
}

// saveLibrary writes any library with the given kind as JSON data to w.
func saveLibrary(w io.Writer, kind libKind, library interface{}) error {
	jsonlib := map[string]interface{}{
		"Kind":    kind,
		"Library": library,
	}
	return niceJson(w, jsonlib)
}

// niceJson is a convenience function for encoding a JSON value and writing
// it with `json.Indent`.
func niceJson(w io.Writer, v interface{}) error {
	raw, dst := new(bytes.Buffer), new(bytes.Buffer)

	enc := json.NewEncoder(raw)
	if err := enc.Encode(v); err != nil {
		return err
	}
	if err := json.Indent(dst, raw.Bytes(), "", "\t"); err != nil {
		return err
	}
	_, err := io.Copy(w, dst)
	return err
}
<commit_msg>Convenient functions to tell whether a fragment library is sequence or structure based. Probably not a good idea. (Why use these when you have type switching?)<commit_after>package fragbag

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"

	"github.com/TuftsBCB/seq"
	"github.com/TuftsBCB/structure"
)

type Library interface {
	// Save should save the fragment library to the writer provided.
	// No particular format is specified by the public API.
	Save(w io.Writer) error

	// Size returns the number of fragments in the library.
	Size() int

	// FragmentSize returns the size of every fragment in the library.
	// All fragments in a library must have the same size.
	FragmentSize() int

	// String returns a custom string representation of the library.
	// This may be anything.
	String() string

	// Name returns a canonical name for this fragment library.
	Name() string
}

type StructureLibrary interface {
	Library
	Best([]structure.Coords) int
	Fragment(i int) StructureFragment
}

type StructureFragment interface {
	Number() int
	String() string
	Atoms() []structure.Coords
}

type SequenceLibrary interface {
	Library
	Best(seq.Sequence) int
	Fragment(i int) SequenceFragment
}

type SequenceFragment interface {
	Number() int
	String() string
	AlignmentProb(seq.Sequence) seq.Prob
}

type libKind string

const (
	kindStructureAtoms  libKind = "structure-atoms"
	kindSequenceProfile         = "sequence-profile"
	kindSequenceHMM             = "sequence-hmm"
)

func (k libKind) String() string {
	return string(k)
}

type jsonLibrary struct {
	Kind    libKind
	Library json.RawMessage
}

// Open reads a library from the reader provided. If there is a problem
// reading or parsing the data as a library, an error is returned.
// If no error is returned, the Library returned is guarnateed to be one
// of the following types of fragment libraries:
// StructureLibrary, SequenceLibrary.
func Open(r io.Reader) (Library, error) {
	var jsonlib jsonLibrary
	dec := json.NewDecoder(r)
	if err := dec.Decode(&jsonlib); err != nil {
		return nil, err
	}

	bytesr := bytes.NewReader(jsonlib.Library)
	switch jsonlib.Kind {
	case kindStructureAtoms:
		return openStructureAtoms(bytesr)
	case kindSequenceProfile:
		return openSequenceProfile(bytesr)
	case kindSequenceHMM:
		return openSequenceHMM(bytesr)
	}
	return nil, fmt.Errorf("Unknown fragment library type: %s", jsonlib.Kind)
}

// IsSequence returns true if the given library is a sequence fragment library.
// Returns false otherwise.
func IsSequence(lib Library) bool {
	_, ok := lib.(SequenceLibrary)
	return ok
}

// IsStructure returns true if the given library is a structure fragment
// library. Returns false otherwise.
func IsStructure(lib Library) bool {
	_, ok := lib.(StructureLibrary)
	return ok
}

// saveLibrary writes any library with the given kind as JSON data to w.
func saveLibrary(w io.Writer, kind libKind, library interface{}) error {
	jsonlib := map[string]interface{}{
		"Kind":    kind,
		"Library": library,
	}
	return niceJson(w, jsonlib)
}

// niceJson is a convenience function for encoding a JSON value and writing
// it with `json.Indent`.
func niceJson(w io.Writer, v interface{}) error {
	raw, dst := new(bytes.Buffer), new(bytes.Buffer)

	enc := json.NewEncoder(raw)
	if err := enc.Encode(v); err != nil {
		return err
	}
	if err := json.Indent(dst, raw.Bytes(), "", "\t"); err != nil {
		return err
	}
	_, err := io.Copy(w, dst)
	return err
}
<|endoftext|>