<commit_before>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"math"
	"sort"
	"strings"

	"github.com/go-gl/mathgl/mgl32"
	"github.com/thinkofdeath/steven/render/gl"
	"github.com/thinkofdeath/steven/type/direction"
	"github.com/thinkofdeath/steven/type/vmath"
)

var (
	chunkProgram  gl.Program
	shaderChunk   *chunkShader
	chunkProgramT gl.Program
	shaderChunkT  *chunkShader
	lineProgram   gl.Program
	shaderLine    *lineShader

	FOV, lastFOV          int = 90, 90
	lastWidth, lastHeight int = -1, -1
	perspectiveMatrix         = mgl32.Mat4{}
	cameraMatrix              = mgl32.Mat4{}

	syncChan = make(chan func(), 500)

	glTexture       gl.Texture
	textureDepth    int
	texturesCreated bool

	MultiSample bool
)

// Start starts the renderer
func Start() {
	gl.ClearColor(122.0/255.0, 165.0/255.0, 247.0/255.0, 1.0)
	gl.Enable(gl.DepthTest)
	gl.Enable(gl.CullFaceFlag)
	gl.CullFace(gl.Back)
	gl.FrontFace(gl.ClockWise)

	chunkProgram = CreateProgram(vertex, fragment)
	shaderChunk = &chunkShader{}
	InitStruct(shaderChunk, chunkProgram)

	chunkProgramT = CreateProgram(vertex, strings.Replace(fragment, "#version 150", "#version 150\n#define alpha", 1))
	shaderChunkT = &chunkShader{}
	InitStruct(shaderChunkT, chunkProgramT)

	textureLock.Lock()
	glTexture = gl.CreateTexture()
	glTexture.Bind(gl.Texture2DArray)
	textureDepth = len(textures)
	glTexture.Image3D(0, AtlasSize, AtlasSize, len(textures), gl.RGBA, gl.UnsignedByte, make([]byte, AtlasSize*AtlasSize*len(textures)*4))
	glTexture.Parameter(gl.TextureMagFilter, gl.Nearest)
	glTexture.Parameter(gl.TextureMinFilter, gl.Nearest)
	glTexture.Parameter(gl.TextureWrapS, gl.ClampToEdge)
	glTexture.Parameter(gl.TextureWrapT, gl.ClampToEdge)
	for i, tex := range textures {
		glTexture.SubImage3D(0, 0, 0, i, AtlasSize, AtlasSize, 1, gl.RGBA, gl.UnsignedByte, tex.Buffer)
		textures[i] = nil
	}
	texturesCreated = true
	textureLock.Unlock()

	initUI()
	initLineDraw()

	gl.BlendFunc(gl.SrcAlpha, gl.OneMinusSrcAlpha)

	elementBuffer = gl.CreateBuffer()
}

var (
	textureIds    []int
	frameID       uint
	nearestBuffer *ChunkBuffer
	viewVector    vmath.Vector3
)

// Draw draws a single frame
func Draw(width, height int, delta float64) {
	tickAnimatedTextures(delta)
	frameID++
sync:
	for {
		select {
		case f := <-syncChan:
			f()
		default:
			break sync
		}
	}

	// Only update the viewport if the window was resized
	if lastHeight != height || lastWidth != width || lastFOV != FOV {
		lastWidth = width
		lastHeight = height
		lastFOV = FOV

		perspectiveMatrix = mgl32.Perspective(
			(math.Pi/180)*float32(FOV),
			float32(width)/float32(height),
			0.1,
			10000.0,
		)
		gl.Viewport(0, 0, width, height)
	}

	if MultiSample {
		gl.Enable(gl.Multisample)
	}

	glTexture.Bind(gl.Texture2DArray)
	gl.ActiveTexture(0)

	gl.Clear(gl.ColorBufferBit | gl.DepthBufferBit)

	chunkProgram.Use()

	cameraMatrix = mgl32.Ident4()
	// +1.62 for the players height.
	// TODO(Think) Change this?
	cameraMatrix = cameraMatrix.Mul4(mgl32.Rotate3DX(-float32(Camera.Pitch)).Mat4())
	cameraMatrix = cameraMatrix.Mul4(mgl32.Rotate3DY(float32(Camera.Yaw)).Mat4())
	cameraMatrix = cameraMatrix.Mul4(mgl32.Translate3D(float32(Camera.X), float32(Camera.Y), float32(-Camera.Z)))
	cameraMatrix = cameraMatrix.Mul4(mgl32.Scale3D(-1.0, 1.0, 1.0))

	shaderChunk.PerspectiveMatrix.Matrix4(&perspectiveMatrix)
	shaderChunk.CameraMatrix.Matrix4(&cameraMatrix)
	shaderChunk.Texture.Int(0)

	chunkPos := position{
		X: int(Camera.X) >> 4,
		Y: int(Camera.Y) >> 4,
		Z: int(Camera.Z) >> 4,
	}
	nearestBuffer = buffers[chunkPos]

	viewVector.X = math.Cos(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)
	viewVector.Z = -math.Sin(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)
	viewVector.Y = -math.Sin(Camera.Pitch)

	for _, dir := range direction.Values {
		validDirs[dir] = viewVector.Dot(dir.AsVector()) > -0.8
	}

	renderOrder = renderOrder[:0]
	renderBuffer(nearestBuffer, chunkPos, direction.Invalid)

	drawLines()

	chunkProgramT.Use()
	shaderChunkT.PerspectiveMatrix.Matrix4(&perspectiveMatrix)
	shaderChunkT.CameraMatrix.Matrix4(&cameraMatrix)
	shaderChunkT.Texture.Int(0)

	gl.Enable(gl.Blend)
	for i := range renderOrder {
		chunk := renderOrder[len(renderOrder)-1-i]
		if chunk.countT > 0 && chunk.bufferT.IsValid() {
			shaderChunkT.Offset.Int3(chunk.X, chunk.Y, chunk.Z)

			chunk.arrayT.Bind()
			chunk.bufferTI.Bind(gl.ElementArrayBuffer)
			offset := 0
			sort.Sort(chunk.transInfo)
			data := chunk.bufferTI.Map(gl.WriteOnly, len(chunk.transData))
			m := 2
			if chunk.bufferTIType == gl.UnsignedInt {
				m = 4
			}
			for _, i := range chunk.transInfo {
				offset += copy(data[offset:], chunk.transData[i.Offset*m:(i.Offset+i.Count)*m])
			}
			chunk.bufferTI.Unmap()
			gl.DrawElements(gl.Triangles, chunk.countT, chunk.bufferTIType)
		}
	}
	gl.Disable(gl.Blend)
	if MultiSample {
		gl.Disable(gl.Multisample)
	}

	drawUI()
}

var (
	renderOrder []*ChunkBuffer
	validDirs   = make([]bool, len(direction.Values))
)

type renderRequest struct {
	chunk *ChunkBuffer
	pos   position
	from  direction.Type
}

const (
	renderQueueSize = 5000
)

var rQueue renderQueue

func renderBuffer(chunk *ChunkBuffer, pos position, from direction.Type) {
	rQueue.Append(renderRequest{chunk, pos, from})
itQueue:
	for !rQueue.Empty() {
		req := rQueue.Take()
		chunk, pos, from = req.chunk, req.pos, req.from
		v := vmath.Vector3{
			float64((pos.X<<4)+8) - Camera.X,
			float64((pos.Y<<4)+8) - Camera.Y,
			float64((pos.Z<<4)+8) - Camera.Z,
		}
		if v.LengthSquared() > 40*40 && v.Dot(viewVector) < 0 {
			continue itQueue
		}
		if chunk == nil || chunk.renderedOn == frameID {
			continue itQueue
		}
		chunk.renderedOn = frameID
		renderOrder = append(renderOrder, chunk)

		if chunk.count > 0 && chunk.buffer.IsValid() {
			shaderChunk.Offset.Int3(chunk.X, chunk.Y, chunk.Z)

			chunk.array.Bind()
			gl.DrawElements(gl.Triangles, chunk.count, elementBufferType)
		}

		for _, dir := range direction.Values {
			c := chunk.neighborChunks[dir]
			if dir != from && c != nil && c.renderedOn != frameID &&
				(from == direction.Invalid || (chunk.IsVisible(from, dir) && validDirs[dir])) {
				ox, oy, oz := dir.Offset()
				pos := position{pos.X + ox, pos.Y + oy, pos.Z + oz}
				rQueue.Append(renderRequest{c, pos, dir.Opposite()})
			}
		}
	}
}

// Sync runs the passed function on the next frame on the same goroutine
// as the renderer.
func Sync(f func()) {
	syncChan <- f
}
<commit_msg>render: remove old comment<commit_after>// Copyright 2015 Matthew Collins
//
// 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 render

import (
	"math"
	"sort"
	"strings"

	"github.com/go-gl/mathgl/mgl32"
	"github.com/thinkofdeath/steven/render/gl"
	"github.com/thinkofdeath/steven/type/direction"
	"github.com/thinkofdeath/steven/type/vmath"
)

var (
	chunkProgram  gl.Program
	shaderChunk   *chunkShader
	chunkProgramT gl.Program
	shaderChunkT  *chunkShader
	lineProgram   gl.Program
	shaderLine    *lineShader

	FOV, lastFOV          int = 90, 90
	lastWidth, lastHeight int = -1, -1
	perspectiveMatrix         = mgl32.Mat4{}
	cameraMatrix              = mgl32.Mat4{}

	syncChan = make(chan func(), 500)

	glTexture       gl.Texture
	textureDepth    int
	texturesCreated bool

	MultiSample bool
)

// Start starts the renderer
func Start() {
	gl.ClearColor(122.0/255.0, 165.0/255.0, 247.0/255.0, 1.0)
	gl.Enable(gl.DepthTest)
	gl.Enable(gl.CullFaceFlag)
	gl.CullFace(gl.Back)
	gl.FrontFace(gl.ClockWise)

	chunkProgram = CreateProgram(vertex, fragment)
	shaderChunk = &chunkShader{}
	InitStruct(shaderChunk, chunkProgram)

	chunkProgramT = CreateProgram(vertex, strings.Replace(fragment, "#version 150", "#version 150\n#define alpha", 1))
	shaderChunkT = &chunkShader{}
	InitStruct(shaderChunkT, chunkProgramT)

	textureLock.Lock()
	glTexture = gl.CreateTexture()
	glTexture.Bind(gl.Texture2DArray)
	textureDepth = len(textures)
	glTexture.Image3D(0, AtlasSize, AtlasSize, len(textures), gl.RGBA, gl.UnsignedByte, make([]byte, AtlasSize*AtlasSize*len(textures)*4))
	glTexture.Parameter(gl.TextureMagFilter, gl.Nearest)
	glTexture.Parameter(gl.TextureMinFilter, gl.Nearest)
	glTexture.Parameter(gl.TextureWrapS, gl.ClampToEdge)
	glTexture.Parameter(gl.TextureWrapT, gl.ClampToEdge)
	for i, tex := range textures {
		glTexture.SubImage3D(0, 0, 0, i, AtlasSize, AtlasSize, 1, gl.RGBA, gl.UnsignedByte, tex.Buffer)
		textures[i] = nil
	}
	texturesCreated = true
	textureLock.Unlock()

	initUI()
	initLineDraw()

	gl.BlendFunc(gl.SrcAlpha, gl.OneMinusSrcAlpha)

	elementBuffer = gl.CreateBuffer()
}

var (
	textureIds    []int
	frameID       uint
	nearestBuffer *ChunkBuffer
	viewVector    vmath.Vector3
)

// Draw draws a single frame
func Draw(width, height int, delta float64) {
	tickAnimatedTextures(delta)
	frameID++
sync:
	for {
		select {
		case f := <-syncChan:
			f()
		default:
			break sync
		}
	}

	// Only update the viewport if the window was resized
	if lastHeight != height || lastWidth != width || lastFOV != FOV {
		lastWidth = width
		lastHeight = height
		lastFOV = FOV

		perspectiveMatrix = mgl32.Perspective(
			(math.Pi/180)*float32(FOV),
			float32(width)/float32(height),
			0.1,
			10000.0,
		)
		gl.Viewport(0, 0, width, height)
	}

	if MultiSample {
		gl.Enable(gl.Multisample)
	}

	glTexture.Bind(gl.Texture2DArray)
	gl.ActiveTexture(0)

	gl.Clear(gl.ColorBufferBit | gl.DepthBufferBit)

	chunkProgram.Use()

	cameraMatrix = mgl32.Ident4()
	cameraMatrix = cameraMatrix.Mul4(mgl32.Rotate3DX(-float32(Camera.Pitch)).Mat4())
	cameraMatrix = cameraMatrix.Mul4(mgl32.Rotate3DY(float32(Camera.Yaw)).Mat4())
	cameraMatrix = cameraMatrix.Mul4(mgl32.Translate3D(float32(Camera.X), float32(Camera.Y), float32(-Camera.Z)))
	cameraMatrix = cameraMatrix.Mul4(mgl32.Scale3D(-1.0, 1.0, 1.0))

	shaderChunk.PerspectiveMatrix.Matrix4(&perspectiveMatrix)
	shaderChunk.CameraMatrix.Matrix4(&cameraMatrix)
	shaderChunk.Texture.Int(0)

	chunkPos := position{
		X: int(Camera.X) >> 4,
		Y: int(Camera.Y) >> 4,
		Z: int(Camera.Z) >> 4,
	}
	nearestBuffer = buffers[chunkPos]

	viewVector.X = math.Cos(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)
	viewVector.Z = -math.Sin(Camera.Yaw-math.Pi/2) * -math.Cos(Camera.Pitch)
	viewVector.Y = -math.Sin(Camera.Pitch)

	for _, dir := range direction.Values {
		validDirs[dir] = viewVector.Dot(dir.AsVector()) > -0.8
	}

	renderOrder = renderOrder[:0]
	renderBuffer(nearestBuffer, chunkPos, direction.Invalid)

	drawLines()

	chunkProgramT.Use()
	shaderChunkT.PerspectiveMatrix.Matrix4(&perspectiveMatrix)
	shaderChunkT.CameraMatrix.Matrix4(&cameraMatrix)
	shaderChunkT.Texture.Int(0)

	gl.Enable(gl.Blend)
	for i := range renderOrder {
		chunk := renderOrder[len(renderOrder)-1-i]
		if chunk.countT > 0 && chunk.bufferT.IsValid() {
			shaderChunkT.Offset.Int3(chunk.X, chunk.Y, chunk.Z)

			chunk.arrayT.Bind()
			chunk.bufferTI.Bind(gl.ElementArrayBuffer)
			offset := 0
			sort.Sort(chunk.transInfo)
			data := chunk.bufferTI.Map(gl.WriteOnly, len(chunk.transData))
			m := 2
			if chunk.bufferTIType == gl.UnsignedInt {
				m = 4
			}
			for _, i := range chunk.transInfo {
				offset += copy(data[offset:], chunk.transData[i.Offset*m:(i.Offset+i.Count)*m])
			}
			chunk.bufferTI.Unmap()
			gl.DrawElements(gl.Triangles, chunk.countT, chunk.bufferTIType)
		}
	}
	gl.Disable(gl.Blend)
	if MultiSample {
		gl.Disable(gl.Multisample)
	}

	drawUI()
}

var (
	renderOrder []*ChunkBuffer
	validDirs   = make([]bool, len(direction.Values))
)

type renderRequest struct {
	chunk *ChunkBuffer
	pos   position
	from  direction.Type
}

const (
	renderQueueSize = 5000
)

var rQueue renderQueue

func renderBuffer(chunk *ChunkBuffer, pos position, from direction.Type) {
	rQueue.Append(renderRequest{chunk, pos, from})
itQueue:
	for !rQueue.Empty() {
		req := rQueue.Take()
		chunk, pos, from = req.chunk, req.pos, req.from
		v := vmath.Vector3{
			float64((pos.X<<4)+8) - Camera.X,
			float64((pos.Y<<4)+8) - Camera.Y,
			float64((pos.Z<<4)+8) - Camera.Z,
		}
		if v.LengthSquared() > 40*40 && v.Dot(viewVector) < 0 {
			continue itQueue
		}
		if chunk == nil || chunk.renderedOn == frameID {
			continue itQueue
		}
		chunk.renderedOn = frameID
		renderOrder = append(renderOrder, chunk)

		if chunk.count > 0 && chunk.buffer.IsValid() {
			shaderChunk.Offset.Int3(chunk.X, chunk.Y, chunk.Z)

			chunk.array.Bind()
			gl.DrawElements(gl.Triangles, chunk.count, elementBufferType)
		}

		for _, dir := range direction.Values {
			c := chunk.neighborChunks[dir]
			if dir != from && c != nil && c.renderedOn != frameID &&
				(from == direction.Invalid || (chunk.IsVisible(from, dir) && validDirs[dir])) {
				ox, oy, oz := dir.Offset()
				pos := position{pos.X + ox, pos.Y + oy, pos.Z + oz}
				rQueue.Append(renderRequest{c, pos, dir.Opposite()})
			}
		}
	}
}

// Sync runs the passed function on the next frame on the same goroutine
// as the renderer.
func Sync(f func()) {
	syncChan <- f
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"

	"github.com/romana/core/common"

	"github.com/go-resty/resty"
	log "github.com/romana/rlog"
	cli "github.com/spf13/cobra"
	config "github.com/spf13/viper"
)

// Variables used for configuration and flags.
var (
	cfgFile  string
	rootURL  string
	rootPort string
	version  bool
	verbose  bool
	format   string
	platform string
)

// type Error contains information for
// json formatted output in cli.
type Error struct {
	Code    int32
	Message string
	Fields  string
}

func (e Error) Error() string {
	return fmt.Sprintf("%d: %v: %v", e.Code, e.Message, e.Fields)
}

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cli.Command{
	Use:   "romana",
	Short: "Command line tools for romana services.",
	Long: `Command line tools for romana services.

For more information, please check http://romana.io
`,
}

// Execute adds all child commands to the root command and sets
// flags appropriately. This is called by main.main(). It only
// needs to happen once to the rootCmd. Here commands/subcommand
// mapping is added where control is passed around from main()
// to commands/subcommands evoked.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		log.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cli.OnInitialize(initConfig)

	RootCmd.AddCommand(hostCmd)
	RootCmd.AddCommand(policyCmd)
	RootCmd.AddCommand(networkCmd)
	RootCmd.AddCommand(blockCmd)
	RootCmd.AddCommand(topologyCmd)

	RootCmd.Flags().BoolVarP(&version, "version", "",
		false, "Build and Versioning Information.")

	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config",
		"c", "", "config file (default $HOME/.romana.yaml | /etc/romana/cli.yml)")
	RootCmd.PersistentFlags().StringVarP(&rootURL, "rootURL",
		"r", "", "root service url, e.g. http://192.168.0.1")
	RootCmd.PersistentFlags().StringVarP(&rootPort, "rootPort",
		"p", "", "root service port, e.g. 9600")
	RootCmd.PersistentFlags().StringVarP(&format, "format",
		"f", "", "enable formatting options like [json|table], etc.")
	RootCmd.PersistentFlags().StringVarP(&platform, "platform",
		"P", "", "Use platforms like [openstack|kubernetes], etc.")
	RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose",
		"v", false, "Verbose output.")

	RootCmd.PersistentPreRun = preConfig
	RootCmd.Run = versionInfo
}

// preConfig sanitizes URLs and sets up config with URLs.
func preConfig(cmd *cli.Command, args []string) {
	var baseURL string

	// Add port details to rootURL else try localhost
	// if nothing is given on command line or config.
	if rootURL == "" {
		rootURL = config.GetString("RootURL")
	}
	if rootPort == "" {
		rootPort = config.GetString("RootPort")
	}
	if rootPort == "" {
		re, _ := regexp.Compile(`:\d+/?`)
		port := re.FindString(rootURL)
		port = strings.TrimPrefix(port, ":")
		port = strings.TrimSuffix(port, "/")
		if port != "" {
			rootPort = port
		} else {
			rootPort = "9600"
		}
	}
	config.Set("RootPort", rootPort)
	if rootURL != "" {
		baseURL = strings.TrimSuffix(rootURL, "/")
		baseURL = strings.TrimSuffix(baseURL, ":9600")
		baseURL = strings.TrimSuffix(baseURL, ":"+rootPort)
	} else {
		baseURL = "http://localhost"
	}
	config.Set("BaseURL", baseURL)
	rootURL = baseURL + ":" + rootPort
	config.Set("RootURL", rootURL)

	// Give command line options higher priority then
	// the corresponding config options.
	if format == "" {
		format = config.GetString("Format")
	}
	// if format is still not found just default to tabular format.
	if format == "" {
		format = "table"
	}
	config.Set("Format", format)

	if platform == "" {
		platform = config.GetString("Platform")
	}
	if platform == "" {
		platform = "kubernetes"
	}
	config.Set("Platform", platform)
}

// versionInfo displays the build and versioning information.
func versionInfo(cmd *cli.Command, args []string) {
	if version {
		fmt.Println(common.BuildInfo())
		os.Exit(0)
	}
	cmd.Help()
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	// https://github.com/spf13/viper/commit/5619c0 changes the behaviour
	// of SetConfigFile and SetConfigName, thus SetConfigName should come
	// before SetConfigFile.
	config.SetConfigName(".romana") // name of config file (without extension)
	config.AddConfigPath("$HOME")   // adding home directory as first search path

	if cfgFile != "" { // enable ability to specify config file via flag
		config.SetConfigFile(cfgFile)
	}

	config.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	err := config.ReadInConfig()
	if err != nil {
		// retry other location if error is received for first
		// default location for config file.
		config.SetConfigFile("/etc/romana/cli.yml")
		err = config.ReadInConfig()
	}
	setLogOutput()
	if err != nil {
		log.Printf("Error using config file(%s): %s", config.ConfigFileUsed(), err)
	} else {
		log.Println("Using config file:", config.ConfigFileUsed())
	}
}

// setLogOutput sets the log output to a file of /dev/null
// depending on the configuration set during initialization.
func setLogOutput() {
	logFileName := config.GetString("LogFile")
	if logFileName == "" {
		logFileName = "/var/tmp/romana-cli.log"
	}
	logFile, err := os.OpenFile(logFileName,
		os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err == nil {
		if verbose || config.GetBool("Verbose") {
			// If output is verbose send it to log file
			// stdout simultaneously.
			config.Set("Verbose", true)
			resty.SetDebug(true)
			resty.SetLogger(io.MultiWriter(logFile, os.Stdout))
			log.SetOutput(io.MultiWriter(logFile, os.Stdout))
		} else {
			// Redirect log output to the log file.
			log.SetOutput(logFile)
		}
	} else {
		if verbose || config.GetBool("Verbose") {
			config.Set("Verbose", true)
			log.SetOutput(os.Stdout)
			resty.SetDebug(true)
			resty.SetLogger(os.Stdout)
		} else {
			// Silently fail and discard log output
			log.SetOutput(ioutil.Discard)
		}
	}
}

// JSONFormat indents input json b and writes it to
// output writer w.
func JSONFormat(b []byte, w io.Writer) {
	var out bytes.Buffer
	if err := json.Indent(&out, b, "", "\t"); err != nil {
		// reset out since it may have partial output from above.
		out.Reset()
		// indentation failed, so write the original string as is.
		out.Write(b)
		out.Write([]byte("\n"))
		out.WriteTo(w)
		return
	}
	out.Write([]byte("\n"))
	out.WriteTo(w)
}
<commit_msg>cli: use yaml instead of yml as extension.<commit_after>// Copyright (c) 2016 Pani Networks
// All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package commands

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"regexp"
	"strings"

	"github.com/romana/core/common"

	"github.com/go-resty/resty"
	log "github.com/romana/rlog"
	cli "github.com/spf13/cobra"
	config "github.com/spf13/viper"
)

// Variables used for configuration and flags.
var (
	cfgFile  string
	rootURL  string
	rootPort string
	version  bool
	verbose  bool
	format   string
	platform string
)

// type Error contains information for
// json formatted output in cli.
type Error struct {
	Code    int32
	Message string
	Fields  string
}

func (e Error) Error() string {
	return fmt.Sprintf("%d: %v: %v", e.Code, e.Message, e.Fields)
}

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cli.Command{
	Use:   "romana",
	Short: "Command line tools for romana services.",
	Long: `Command line tools for romana services.

For more information, please check http://romana.io
`,
}

// Execute adds all child commands to the root command and sets
// flags appropriately. This is called by main.main(). It only
// needs to happen once to the rootCmd. Here commands/subcommand
// mapping is added where control is passed around from main()
// to commands/subcommands evoked.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		log.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cli.OnInitialize(initConfig)

	RootCmd.AddCommand(hostCmd)
	RootCmd.AddCommand(policyCmd)
	RootCmd.AddCommand(networkCmd)
	RootCmd.AddCommand(blockCmd)
	RootCmd.AddCommand(topologyCmd)

	RootCmd.Flags().BoolVarP(&version, "version", "",
		false, "Build and Versioning Information.")

	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config",
		"c", "", "config file (default $HOME/.romana.yaml | /etc/romana/cli.yaml)")
	RootCmd.PersistentFlags().StringVarP(&rootURL, "rootURL",
		"r", "", "root service url, e.g. http://192.168.0.1")
	RootCmd.PersistentFlags().StringVarP(&rootPort, "rootPort",
		"p", "", "root service port, e.g. 9600")
	RootCmd.PersistentFlags().StringVarP(&format, "format",
		"f", "", "enable formatting options like [json|table], etc.")
	RootCmd.PersistentFlags().StringVarP(&platform, "platform",
		"P", "", "Use platforms like [openstack|kubernetes], etc.")
	RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose",
		"v", false, "Verbose output.")

	RootCmd.PersistentPreRun = preConfig
	RootCmd.Run = versionInfo
}

// preConfig sanitizes URLs and sets up config with URLs.
func preConfig(cmd *cli.Command, args []string) {
	var baseURL string

	// Add port details to rootURL else try localhost
	// if nothing is given on command line or config.
	if rootURL == "" {
		rootURL = config.GetString("RootURL")
	}
	if rootPort == "" {
		rootPort = config.GetString("RootPort")
	}
	if rootPort == "" {
		re, _ := regexp.Compile(`:\d+/?`)
		port := re.FindString(rootURL)
		port = strings.TrimPrefix(port, ":")
		port = strings.TrimSuffix(port, "/")
		if port != "" {
			rootPort = port
		} else {
			rootPort = "9600"
		}
	}
	config.Set("RootPort", rootPort)
	if rootURL != "" {
		baseURL = strings.TrimSuffix(rootURL, "/")
		baseURL = strings.TrimSuffix(baseURL, ":9600")
		baseURL = strings.TrimSuffix(baseURL, ":"+rootPort)
	} else {
		baseURL = "http://localhost"
	}
	config.Set("BaseURL", baseURL)
	rootURL = baseURL + ":" + rootPort
	config.Set("RootURL", rootURL)

	// Give command line options higher priority then
	// the corresponding config options.
	if format == "" {
		format = config.GetString("Format")
	}
	// if format is still not found just default to tabular format.
	if format == "" {
		format = "table"
	}
	config.Set("Format", format)

	if platform == "" {
		platform = config.GetString("Platform")
	}
	if platform == "" {
		platform = "kubernetes"
	}
	config.Set("Platform", platform)
}

// versionInfo displays the build and versioning information.
func versionInfo(cmd *cli.Command, args []string) {
	if version {
		fmt.Println(common.BuildInfo())
		os.Exit(0)
	}
	cmd.Help()
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	// https://github.com/spf13/viper/commit/5619c0 changes the behaviour
	// of SetConfigFile and SetConfigName, thus SetConfigName should come
	// before SetConfigFile.
	config.SetConfigName(".romana") // name of config file (without extension)
	config.AddConfigPath("$HOME")   // adding home directory as first search path

	if cfgFile != "" { // enable ability to specify config file via flag
		config.SetConfigFile(cfgFile)
	}

	config.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	err := config.ReadInConfig()
	if err != nil {
		// retry other location if error is received for first
		// default location for config file.
		config.SetConfigFile("/etc/romana/cli.yaml")
		err = config.ReadInConfig()
	}
	setLogOutput()
	if err != nil {
		log.Printf("Error using config file(%s): %s", config.ConfigFileUsed(), err)
	} else {
		log.Println("Using config file:", config.ConfigFileUsed())
	}
}

// setLogOutput sets the log output to a file of /dev/null
// depending on the configuration set during initialization.
func setLogOutput() {
	logFileName := config.GetString("LogFile")
	if logFileName == "" {
		logFileName = "/var/tmp/romana-cli.log"
	}
	logFile, err := os.OpenFile(logFileName,
		os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err == nil {
		if verbose || config.GetBool("Verbose") {
			// If output is verbose send it to log file
			// stdout simultaneously.
			config.Set("Verbose", true)
			resty.SetDebug(true)
			resty.SetLogger(io.MultiWriter(logFile, os.Stdout))
			log.SetOutput(io.MultiWriter(logFile, os.Stdout))
		} else {
			// Redirect log output to the log file.
			log.SetOutput(logFile)
		}
	} else {
		if verbose || config.GetBool("Verbose") {
			config.Set("Verbose", true)
			log.SetOutput(os.Stdout)
			resty.SetDebug(true)
			resty.SetLogger(os.Stdout)
		} else {
			// Silently fail and discard log output
			log.SetOutput(ioutil.Discard)
		}
	}
}

// JSONFormat indents input json b and writes it to
// output writer w.
func JSONFormat(b []byte, w io.Writer) {
	var out bytes.Buffer
	if err := json.Indent(&out, b, "", "\t"); err != nil {
		// reset out since it may have partial output from above.
		out.Reset()
		// indentation failed, so write the original string as is.
		out.Write(b)
		out.Write([]byte("\n"))
		out.WriteTo(w)
		return
	}
	out.Write([]byte("\n"))
	out.WriteTo(w)
}
<|endoftext|>


<commit_before>// Copyright © 2015 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// Package remote integrates the remote features of Viper.
package remote

import (
	"bytes"
	"io"
	"os"

	crypt "github.com/sagikazarmark/crypt/config"

	"github.com/spf13/viper"
)

type remoteConfigProvider struct{}

func (rc remoteConfigProvider) Get(rp viper.RemoteProvider) (io.Reader, error) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, err
	}
	b, err := cm.Get(rp.Path())
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(b), nil
}

func (rc remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, err
	}
	resp, err := cm.Get(rp.Path())
	if err != nil {
		return nil, err
	}

	return bytes.NewReader(resp), nil
}

func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, nil
	}
	quit := make(chan bool)
	quitwc := make(chan bool)
	viperResponsCh := make(chan *viper.RemoteResponse)
	cryptoResponseCh := cm.Watch(rp.Path(), quit)
	// need this function to convert the Channel response form crypt.Response to viper.Response
	go func(cr <-chan *crypt.Response, vr chan<- *viper.RemoteResponse, quitwc <-chan bool, quit chan<- bool) {
		for {
			select {
			case <-quitwc:
				quit <- true
				return
			case resp := <-cr:
				vr <- &viper.RemoteResponse{
					Error: resp.Error,
					Value: resp.Value,
				}
			}
		}
	}(cryptoResponseCh, viperResponsCh, quitwc, quit)

	return viperResponsCh, quitwc
}

func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
	var cm crypt.ConfigManager
	var err error

	if rp.SecretKeyring() != "" {
		var kr *os.File
		kr, err = os.Open(rp.SecretKeyring())
		if err != nil {
			return nil, err
		}
		defer kr.Close()
		switch rp.Provider() {
		case "etcd":
			cm, err = crypt.NewEtcdConfigManager([]string{rp.Endpoint()}, kr)
		case "firestore":
			cm, err = crypt.NewFirestoreConfigManager([]string{rp.Endpoint()}, kr)
		default:
			cm, err = crypt.NewConsulConfigManager([]string{rp.Endpoint()}, kr)
		}
	} else {
		switch rp.Provider() {
		case "etcd":
			cm, err = crypt.NewStandardEtcdConfigManager([]string{rp.Endpoint()})
		case "firestore":
			cm, err = crypt.NewStandardFirestoreConfigManager([]string{rp.Endpoint()})
		default:
			cm, err = crypt.NewStandardConsulConfigManager([]string{rp.Endpoint()})
		}
	}
	if err != nil {
		return nil, err
	}
	return cm, nil
}

func init() {
	viper.RemoteConfig = &remoteConfigProvider{}
}
<commit_msg>feat: add etcd3 support to remote<commit_after>// Copyright © 2015 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// Package remote integrates the remote features of Viper.
package remote

import (
	"bytes"
	"io"
	"os"

	crypt "github.com/sagikazarmark/crypt/config"

	"github.com/spf13/viper"
)

type remoteConfigProvider struct{}

func (rc remoteConfigProvider) Get(rp viper.RemoteProvider) (io.Reader, error) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, err
	}
	b, err := cm.Get(rp.Path())
	if err != nil {
		return nil, err
	}
	return bytes.NewReader(b), nil
}

func (rc remoteConfigProvider) Watch(rp viper.RemoteProvider) (io.Reader, error) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, err
	}
	resp, err := cm.Get(rp.Path())
	if err != nil {
		return nil, err
	}

	return bytes.NewReader(resp), nil
}

func (rc remoteConfigProvider) WatchChannel(rp viper.RemoteProvider) (<-chan *viper.RemoteResponse, chan bool) {
	cm, err := getConfigManager(rp)
	if err != nil {
		return nil, nil
	}
	quit := make(chan bool)
	quitwc := make(chan bool)
	viperResponsCh := make(chan *viper.RemoteResponse)
	cryptoResponseCh := cm.Watch(rp.Path(), quit)
	// need this function to convert the Channel response form crypt.Response to viper.Response
	go func(cr <-chan *crypt.Response, vr chan<- *viper.RemoteResponse, quitwc <-chan bool, quit chan<- bool) {
		for {
			select {
			case <-quitwc:
				quit <- true
				return
			case resp := <-cr:
				vr <- &viper.RemoteResponse{
					Error: resp.Error,
					Value: resp.Value,
				}
			}
		}
	}(cryptoResponseCh, viperResponsCh, quitwc, quit)

	return viperResponsCh, quitwc
}

func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
	var cm crypt.ConfigManager
	var err error

	if rp.SecretKeyring() != "" {
		var kr *os.File
		kr, err = os.Open(rp.SecretKeyring())
		if err != nil {
			return nil, err
		}
		defer kr.Close()
		switch rp.Provider() {
		case "etcd":
			cm, err = crypt.NewEtcdConfigManager([]string{rp.Endpoint()}, kr)
		case "etcd3":
			cm, err = crypt.NewEtcdV3ConfigManager([]string{rp.Endpoint()}, kr)
		case "firestore":
			cm, err = crypt.NewFirestoreConfigManager([]string{rp.Endpoint()}, kr)
		default:
			cm, err = crypt.NewConsulConfigManager([]string{rp.Endpoint()}, kr)
		}
	} else {
		switch rp.Provider() {
		case "etcd":
			cm, err = crypt.NewStandardEtcdConfigManager([]string{rp.Endpoint()})
		case "etcd3":
			cm, err = crypt.NewStandardEtcdV3ConfigManager([]string{rp.Endpoint()})
		case "firestore":
			cm, err = crypt.NewStandardFirestoreConfigManager([]string{rp.Endpoint()})
		default:
			cm, err = crypt.NewStandardConsulConfigManager([]string{rp.Endpoint()})
		}
	}
	if err != nil {
		return nil, err
	}
	return cm, nil
}

func init() {
	viper.RemoteConfig = &remoteConfigProvider{}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
)

/*
// =============================================
// this is the entry manager for the goNSproxy.
// the design goals are as follows:
//   - list entries and their attributes
//   - add entries
//   - remove entries
//   - modify entries
//
// I would also like to add a listener on a
// different port so we can manage this thing
// while it is deployed. I think we should use
// gorilla/mux and just listen on 8054 or something
// and a simple rest request to manage entries
// =============================================
*/

func main() {
	list := flag.Bool("l", false, "list records")
	addReq := flag.String("add", "", "add record: <domain name> <ipv4 addr>")
	remReq := flag.String("rm", "", "remove a record: <domain name>")
	modReq := flag.String("modify", "", "modify record: <domain name> <ipv4 addr>")

	flag.Parse()

	// first thing to do is make a 'records/' dir
	// if it does not exist
	_, err := os.Stat("records/")
	if err != nil {
		os.Mkdir("records/", 0755)
	}

	if *list {
		listEntries()
	}

	if *addReq != "" {
		dn := *addReq
		// the extra argument is the ip
		ip := flag.Arg(0)
		addEntry(dn, ip)
	}

	if *modReq != "" {
		dn := *modReq
		// the extra argument is the ip
		ip := flag.Arg(0)
		addEntry(dn, ip)
	}

	if *remReq != "" {
		rm := *remReq
		rmEntry(rm)
	}
}

func listEntries() {
	// list records
	println("-------------------------------------------")
	files, _ := ioutil.ReadDir("records/")
	for _, f := range files {
		//print out filename followed by record
		filepath := fmt.Sprintf("records/%s", f.Name())
		cont, _ := ioutil.ReadFile(filepath)
		//strip out trailing '.' from FQDM
		formName := f.Name()[:len(f.Name())-1]
		fmt.Printf("%-25s: %s", formName, cont)
	}
	println("-------------------------------------------")
	return
}

func addEntry(dn, ip string) {
	// add record
	// more useable when the newline is appened to the end
	ip = fmt.Sprintf("%s\n", ip)

	// if the domain is not FQ, FQ it
	if string(dn[len(dn)-1]) != "." {
		//println("not fully qualified")
		dn = fmt.Sprintf("%s.", dn)
	}
	// filepath is 'records/fqdn'
	path := fmt.Sprintf("records/%s", dn)

	// write record
	content := []byte(ip)
	ioutil.WriteFile(path, content, 0644)
}

func rmEntry(rm string) {
	// delete record
	// try to remove it if it exist, otherwise it doesn't
	// filepath is 'records/<rm>.', need to append a .
	path := fmt.Sprintf("records/%s.", rm)

	err := os.Remove(path)
	if err != nil {
		fmt.Println(err)
	}
}
<commit_msg>remote manager working<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/gorilla/mux"
	"github.com/unixvoid/nsproxy/nsmanager"
)

/*
// =============================================
// this is the entry manager for the goNSproxy.
// the design goals are as follows:
//   - list entries and their attributes
//   - add entries
//   - remove entries
//   - modify entries
//
// I would also like to add a listener on a
// different port so we can manage this thing
// while it is deployed. I think we should use
// gorilla/mux and just listen on 8054 or something
// and a simple rest request to manage entries
// =============================================
*/

func main() {
	rawPort := flag.String("p", "8054", "port to listen on")
	flag.Parse()
	port := fmt.Sprint(":", *rawPort)
	// first thing to do is make a 'records/' dir
	// if it does not exist
	_, err := os.Stat("records/")
	if err != nil {
		os.Mkdir("records/", 0755)
	}

	router := mux.NewRouter()
	router.HandleFunc("/!{command}", dynamichandler).Methods("GET")
	println("running on port", *rawPort)
	log.Fatal(http.ListenAndServe(port, router))
}

func dynamichandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	commArr := strings.SplitN(vars["command"], " ", 3)
	command := commArr[0]

	switch command {
	case "list":
		fmt.Fprintln(w, "-------------------------------------------")
		files, _ := ioutil.ReadDir("records/")
		for _, f := range files {
			//print out filename followed by record
			filepath := fmt.Sprintf("records/%s", f.Name())
			cont, _ := ioutil.ReadFile(filepath)
			//strip out trailing '.' from FQDM
			formName := f.Name()[:len(f.Name())-1]
			fmt.Fprintf(w, "%-25s: %s", formName, cont)
		}
		fmt.Fprintf(w, "-------------------------------------------")
		return

	case "add":
		dn, ip := commArr[1], commArr[2]
		nsmanager.AddEntry(dn, ip)
	case "rm":
		rm := commArr[1]
		nsmanager.RmEntry(rm)
	case "modify":
		dn, ip := commArr[1], commArr[2]
		nsmanager.AddEntry(dn, ip)
	default:
		fmt.Fprintf(w, "not a valid command.")
	}
}
<|endoftext|>


<commit_before>package db

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"syscall"
)

type returnChanMessage struct {
	err  error
	json string
}

type readChanMessage struct {
	key        string
	returnChan chan returnChanMessage
}

type DB struct {
	data      []byte
	dataMap   map[string]string
	Log       *Log
	fd        int
	filename  string
	file      *os.File
	writeChan chan map[string]string
	readChan  chan readChanMessage
}

func (db *DB) load() {
	err := json.Unmarshal(db.data, &db.dataMap)
	if err != nil {
		fmt.Println("Error unmarshalling initial data into map: ", err)
	}
	fmt.Println(db.dataMap)
}

func (db *DB) mmap(size int) {
	fmt.Println("mmapping db file: ", size)
	data, err := syscall.Mmap(db.fd, 0, size, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Println("Error mmapping: ", err)
	}
	db.data = data
}

func (db *DB) resize(size int) {
	fmt.Println("Resizing db file: ", size)
	err := syscall.Ftruncate(db.fd, int64(size))
	if err != nil {
		fmt.Println("Error resizing: ", err)
	}
}

func (db *DB) open() {
	fmt.Println("Getting db file descriptor")
	f, err := os.OpenFile(db.filename, os.O_CREATE|os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open file: ", err)
	}
	db.fd = int(f.Fd())
	db.file = f
}

func (db *DB) extend(size int) {
	db.file.Close()
	db.open()
	db.resize(size)
	db.mmap(size)
}

func (db *DB) listener() {
	for {
		select {
		case writeReq := <-db.writeChan:
			key := writeReq["key"]
			value := writeReq["value"]
			db.dataMap[key] = value
			b, err := json.Marshal(db.dataMap)
			if err != nil {
				fmt.Println("Error marshalling db: ", err)
			}
			if len(b) > len(db.data) {
				db.extend(len(b))
			}
			copy(db.data, b)
			s := "SET " + key + ": " + value + "\n"
			b = append(db.Log.data, []byte(s)...)
			if len(b) > len(db.Log.data) {
				db.Log.extend(len(b))
			}
			copy(db.Log.data, b)

		case readReq := <-db.readChan:
			key := readReq.key
			returnChan := readReq.returnChan
			if value, ok := db.dataMap[key]; ok {
				m := &returnChanMessage{nil, value}
				returnChan <- *m
			} else {
				m := &returnChanMessage{errors.New("Invalid Key"), ""}
				returnChan <- *m
			}
		}
	}
}

func Init(dbFilename string, logFilename string) *DB {
	log := initLog(logFilename)
	writeChan := make(chan map[string]string, 250)
	readChan := make(chan readChanMessage)
	dataMap := make(map[string]string)
	var data []byte
	var fd int
	var file *os.File
	db := &DB{data, dataMap, log, fd, dbFilename, file, writeChan, readChan}
	db.open()
	f, err := os.Stat(dbFilename)
	if err != nil {
		fmt.Println("Could not stat file: ", err)
	}

	db.mmap(int(f.Size()))
	db.load()
	go db.listener()
	return db
}
<commit_msg>move db writing code into its own function<commit_after>package db

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"syscall"
)

type returnChanMessage struct {
	err  error
	json string
}

type readChanMessage struct {
	key        string
	returnChan chan returnChanMessage
}

type DB struct {
	data      []byte
	dataMap   map[string]string
	Log       *Log
	fd        int
	filename  string
	file      *os.File
	writeChan chan map[string]string
	readChan  chan readChanMessage
}

func (db *DB) load() {
	err := json.Unmarshal(db.data, &db.dataMap)
	if err != nil {
		fmt.Println("Error unmarshalling initial data into map: ", err)
	}
	fmt.Println(db.dataMap)
}

func (db *DB) mmap(size int) {
	fmt.Println("mmapping db file: ", size)
	data, err := syscall.Mmap(db.fd, 0, size, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
	if err != nil {
		fmt.Println("Error mmapping: ", err)
	}
	db.data = data
}

func (db *DB) resize(size int) {
	fmt.Println("Resizing db file: ", size)
	err := syscall.Ftruncate(db.fd, int64(size))
	if err != nil {
		fmt.Println("Error resizing: ", err)
	}
}

func (db *DB) open() {
	fmt.Println("Getting db file descriptor")
	f, err := os.OpenFile(db.filename, os.O_CREATE|os.O_RDWR, 0)
	if err != nil {
		fmt.Println("Could not open file: ", err)
	}
	db.fd = int(f.Fd())
	db.file = f
}

func (db *DB) extend(size int) {
	db.file.Close()
	db.open()
	db.resize(size)
	db.mmap(size)
}

func (db *DB) write(key string, value string) {
	db.dataMap[key] = value
	b, err := json.Marshal(db.dataMap)
	if err != nil {
		fmt.Println("Error marshalling db: ", err)
	}
	if len(b) > len(db.data) {
		db.extend(len(b))
	}
	copy(db.data, b)
	s := "SET " + key + ": " + value + "\n"
	b = append(db.Log.data, []byte(s)...)
	if len(b) > len(db.Log.data) {
		db.Log.extend(len(b))
	}
	copy(db.Log.data, b)
}

func (db *DB) listener() {
	for {
		select {
		case writeReq := <-db.writeChan:
			key := writeReq["key"]
			value := writeReq["value"]
			db.write(key, value)

		case readReq := <-db.readChan:
			key := readReq.key
			returnChan := readReq.returnChan
			if value, ok := db.dataMap[key]; ok {
				m := &returnChanMessage{nil, value}
				returnChan <- *m
			} else {
				m := &returnChanMessage{errors.New("Invalid Key"), ""}
				returnChan <- *m
			}
		}
	}
}

func Init(dbFilename string, logFilename string) *DB {
	log := initLog(logFilename)
	writeChan := make(chan map[string]string, 250)
	readChan := make(chan readChanMessage)
	dataMap := make(map[string]string)
	var data []byte
	var fd int
	var file *os.File
	db := &DB{data, dataMap, log, fd, dbFilename, file, writeChan, readChan}
	db.open()
	f, err := os.Stat(dbFilename)
	if err != nil {
		fmt.Println("Could not stat file: ", err)
	}

	db.mmap(int(f.Size()))
	db.load()
	go db.listener()
	return db
}
<|endoftext|>


<commit_before>package render

import (
	"bytes"
	"errors"
	"io"
	"net/rpc"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/natefinch/pie"
)

type Mapnik struct {
	client *rpc.Client
}

var mapnikPluginName = "magnacarto-mapnik"

func init() {
	if runtime.GOOS == "windows" {
		mapnikPluginName += ".exe"
	}
}

func NewMapnik() (*Mapnik, error) {
	path, err := exec.LookPath(mapnikPluginName)
	if err != nil {
		path = filepath.Join(filepath.Dir(os.Args[0]), mapnikPluginName)
		path, _ = filepath.Abs(path)
		if _, serr := os.Stat(path); serr != nil {
			return nil, err
		}
	}

	client, err := pie.StartProvider(os.Stderr, path)
	if err != nil {
		return nil, err
	}
	return &Mapnik{client: client}, nil
}

func (m *Mapnik) Is3() (bool, error) {
	if m.client == nil {
		return false, errors.New("mapnik plugin not initialized")
	}
	var is3 bool
	err := m.client.Call("Mapnik.Is3", struct{}{} /* not used */, &is3)
	return is3, err
}

func (m *Mapnik) RegisterFonts(fontDir string) error {
	if m.client == nil {
		return errors.New("mapnik plugin not initialized")
	}
	var tmp interface{}
	err := m.client.Call("Mapnik.RegisterFonts", fontDir, &tmp /* not used */)
	return err
}

func (m *Mapnik) Render(mapfile string, dst io.Writer, mapReq Request) error {
	if m.client == nil {
		return errors.New("mapnik plugin not initialized")
	}
	var buf []byte
	err := m.client.Call("Mapnik.Render", struct {
		Mapfile string
		Req     Request
	}{mapfile, mapReq}, &buf)
	if err != nil {
		return err
	}
	_, err = io.Copy(dst, bytes.NewBuffer(buf))
	return err
}
<commit_msg>allow to close mapnik plugin<commit_after>package render

import (
	"bytes"
	"errors"
	"io"
	"net/rpc"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/natefinch/pie"
)

type Mapnik struct {
	client *rpc.Client
}

var mapnikPluginName = "magnacarto-mapnik"

func init() {
	if runtime.GOOS == "windows" {
		mapnikPluginName += ".exe"
	}
}

func NewMapnik() (*Mapnik, error) {
	path, err := exec.LookPath(mapnikPluginName)
	if err != nil {
		path = filepath.Join(filepath.Dir(os.Args[0]), mapnikPluginName)
		path, _ = filepath.Abs(path)
		if _, serr := os.Stat(path); serr != nil {
			return nil, err
		}
	}

	client, err := pie.StartProvider(os.Stderr, path)
	if err != nil {
		return nil, err
	}
	return &Mapnik{client: client}, nil
}

func (m *Mapnik) Is3() (bool, error) {
	if m.client == nil {
		return false, errors.New("mapnik plugin not initialized")
	}
	var is3 bool
	err := m.client.Call("Mapnik.Is3", struct{}{} /* not used */, &is3)
	return is3, err
}

func (m *Mapnik) RegisterFonts(fontDir string) error {
	if m.client == nil {
		return errors.New("mapnik plugin not initialized")
	}
	var tmp interface{}
	err := m.client.Call("Mapnik.RegisterFonts", fontDir, &tmp /* not used */)
	return err
}

func (m *Mapnik) Close() error {
	if m.client == nil {
		return errors.New("mapnik plugin not initialized")
	}
	return m.client.Close()
}

func (m *Mapnik) Render(mapfile string, dst io.Writer, mapReq Request) error {
	if m.client == nil {
		return errors.New("mapnik plugin not initialized")
	}
	var buf []byte
	err := m.client.Call("Mapnik.Render", struct {
		Mapfile string
		Req     Request
	}{mapfile, mapReq}, &buf)
	if err != nil {
		return err
	}
	_, err = io.Copy(dst, bytes.NewBuffer(buf))
	return err
}
<|endoftext|>


<commit_before>package iradix

import (
	"bytes"

	"github.com/hashicorp/golang-lru/simplelru"
)

const (
	// defaultModifiedCache is the default size of the modified node
	// cache used per transaction. This is used to cache the updates
	// to the nodes near the root, while the leaves do not need to be
	// cached. This is important for very large transactions to prevent
	// the modified cache from growing to be enormous.
	defaultModifiedCache = 8192
)

// Tree implements an immutable radix tree. This can be treated as a
// Dictionary abstract data type. The main advantage over a standard
// hash map is prefix-based lookups and ordered iteration. The immutability
// means that it is safe to concurrently read from a Tree without any
// coordination.
type Tree struct {
	root *Node
	size int
}

// New returns an empty Tree
func New() *Tree {
	t := &Tree{root: &Node{}}
	return t
}

// Len is used to return the number of elements in the tree
func (t *Tree) Len() int {
	return t.size
}

// Txn is a transaction on the tree. This transaction is applied
// atomically and returns a new tree when committed. A transaction
// is not thread safe, and should only be used by a single goroutine.
type Txn struct {
	root     *Node
	size     int
	modified *simplelru.LRU

	mutatedNode  map[*Node]struct{}
	mutatedLeaf  map[*leafNode]struct{}
	notifyMutate bool
}

// Txn starts a new transaction that can be used to mutate the tree
func (t *Tree) Txn() *Txn {
	txn := &Txn{
		root: t.root,
		size: t.size,
	}
	return txn
}

// NotifyMutate can be used to toggle if mutation cause a notification
// to the affected nodes. This must be enabled before any modifications are
// made within the transaction.
func (t *Txn) NotifyMutate(notify bool) error {
	if len(t.modified) > 0 && notify {
		return fmt.Errorf("transaction already in progress")
	}
	t.notifyMutate = notify
	return nil
}

// writeNode returns a node to be modified, if the current
// node as already been modified during the course of
// the transaction, it is used in-place.
func (t *Txn) writeNode(n *Node) *Node {
	// Ensure the modified set exists
	if t.modified == nil {
		lru, err := simplelru.NewLRU(defaultModifiedCache, nil)
		if err != nil {
			panic(err)
		}
		t.modified = lru
	}

	// If this node has already been modified, we can
	// continue to use it during this transaction.
	if _, ok := t.modified.Get(n); ok {
		return n
	}

	// Mark this node as being mutated
	if t.notifyMutate {
		if t.mutatedNode == nil {
			t.mutatedNode = make(map[*Node]struct{})
		}
		t.mutatedNode[n] = struct{}{}
	}

	// Copy the existing node
	nc := new(Node)
	nc.mutateCh = make(chan struct{})
	if n.prefix != nil {
		nc.prefix = make([]byte, len(n.prefix))
		copy(nc.prefix, n.prefix)
	}
	if n.leaf != nil {
		nc.leaf = n.leaf
	}
	if len(n.edges) != 0 {
		nc.edges = make([]edge, len(n.edges))
		copy(nc.edges, n.edges)
	}

	// Mark this node as modified
	t.modified.Add(nc, nil)
	return nc
}

// mutateLeaf is used to mark a leaf as being mutated
// for the purposes of notification.
func (t *Txn) mutateLeaf(leaf *leafNode) {
	if !t.notifyMutate {
		return
	}
	if t.mutatedLeaf == nil {
		t.mutatedLeaf = make(map[*leafNode]struct{})
	}
	t.mutatedLeaf[leaf] = struct{}{}
}

// insert does a recursive insertion
func (t *Txn) insert(n *Node, k, search []byte, v interface{}) (*Node, interface{}, bool) {
	// Handle key exhaution
	if len(search) == 0 {
		nc := t.writeNode(n)
		nc.leaf = &leafNode{
			mutateCh: make(chan struct{}),
			key:      k,
			val:      v,
		}
		if n.isLeaf() {
			t.mutateLeaf(n.leaf)
			return nc, n.leaf.val, true
		} else {
			return nc, nil, false
		}
	}

	// Look for the edge
	idx, child := n.getEdge(search[0])

	// No edge, create one
	if child == nil {
		e := edge{
			label: search[0],
			node: &Node{
				mutateCh: make(chan struct{}),
				leaf: &leafNode{
					mutateCh: make(chan struct{}),
					key:      k,
					val:      v,
				},
				prefix: search,
			},
		}
		nc := t.writeNode(n)
		nc.addEdge(e)
		return nc, nil, false
	}

	// Determine longest prefix of the search key on match
	commonPrefix := longestPrefix(search, child.prefix)
	if commonPrefix == len(child.prefix) {
		search = search[commonPrefix:]
		newChild, oldVal, didUpdate := t.insert(child, k, search, v)
		if newChild != nil {
			nc := t.writeNode(n)
			nc.edges[idx].node = newChild
			return nc, oldVal, didUpdate
		}
		return nil, oldVal, didUpdate
	}

	// Split the node
	nc := t.writeNode(n)
	splitNode := &Node{
		mutateCh: make(chan struct{}),
		prefix:   search[:commonPrefix],
	}
	nc.replaceEdge(edge{
		label: search[0],
		node:  splitNode,
	})

	// Restore the existing child node
	modChild := t.writeNode(child)
	splitNode.addEdge(edge{
		label: modChild.prefix[commonPrefix],
		node:  modChild,
	})
	modChild.prefix = modChild.prefix[commonPrefix:]

	// Create a new leaf node
	leaf := &leafNode{
		mutateCh: make(chan struct{}),
		key:      k,
		val:      v,
	}

	// If the new key is a subset, add to to this node
	search = search[commonPrefix:]
	if len(search) == 0 {
		splitNode.leaf = leaf
		return nc, nil, false
	}

	// Create a new edge for the node
	splitNode.addEdge(edge{
		label: search[0],
		node: &Node{
			mutateCh: make(chan struct{}),
			leaf:     leaf,
			prefix:   search,
		},
	})
	return nc, nil, false
}

// delete does a recursive deletion
func (t *Txn) delete(parent, n *Node, search []byte) (*Node, *leafNode) {
	// Check for key exhaution
	if len(search) == 0 {
		if !n.isLeaf() {
			return nil, nil
		}

		// Remove the leaf node
		nc := t.writeNode(n)
		nc.leaf = nil
		t.mutateLeaf(n.leaf)

		// Check if this node should be merged
		if n != t.root && len(nc.edges) == 1 {
			nc.mergeChild()
		}
		return nc, n.leaf
	}

	// Look for an edge
	label := search[0]
	idx, child := n.getEdge(label)
	if child == nil || !bytes.HasPrefix(search, child.prefix) {
		return nil, nil
	}

	// Consume the search prefix
	search = search[len(child.prefix):]
	newChild, leaf := t.delete(n, child, search)
	if newChild == nil {
		return nil, nil
	}

	// Copy this node
	nc := t.writeNode(n)

	// Delete the edge if the node has no edges
	if newChild.leaf == nil && len(newChild.edges) == 0 {
		nc.delEdge(label)
		if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
			nc.mergeChild()
		}
	} else {
		nc.edges[idx].node = newChild
	}
	return nc, leaf
}

// Insert is used to add or update a given key. The return provides
// the previous value and a bool indicating if any was set.
func (t *Txn) Insert(k []byte, v interface{}) (interface{}, bool) {
	newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v)
	if newRoot != nil {
		t.root = newRoot
	}
	if !didUpdate {
		t.size++
	}
	return oldVal, didUpdate
}

// Delete is used to delete a given key. Returns the old value if any,
// and a bool indicating if the key was set.
func (t *Txn) Delete(k []byte) (interface{}, bool) {
	newRoot, leaf := t.delete(nil, t.root, k)
	if newRoot != nil {
		t.root = newRoot
	}
	if leaf != nil {
		t.size--
		return leaf.val, true
	}
	return nil, false
}

// Root returns the current root of the radix tree within this
// transaction. The root is not safe across insert and delete operations,
// but can be used to read the current state during a transaction.
func (t *Txn) Root() *Node {
	return t.root
}

// Get is used to lookup a specific key, returning
// the value and if it was found
func (t *Txn) Get(k []byte) (interface{}, bool) {
	return t.root.Get(k)
}

// Commit is used to finalize the transaction and return a new tree
func (t *Txn) Commit() *Tree {
	nt := &Tree{t.root, t.size}
	if t.notifyMutate {
		for leaf := range t.mutatedLeaf {
			close(leaf.mutateCh)
		}
		for node := range t.mutatedNode {
			close(node.mutateCh)
		}
	}
	t.modified = nil
	t.mutatedNode = nil
	t.mutatedLeaf = nil
	return nt
}

// Insert is used to add or update a given key. The return provides
// the new tree, previous value and a bool indicating if any was set.
func (t *Tree) Insert(k []byte, v interface{}) (*Tree, interface{}, bool) {
	txn := t.Txn()
	old, ok := txn.Insert(k, v)
	return txn.Commit(), old, ok
}

// Delete is used to delete a given key. Returns the new tree,
// old value if any, and a bool indicating if the key was set.
func (t *Tree) Delete(k []byte) (*Tree, interface{}, bool) {
	txn := t.Txn()
	old, ok := txn.Delete(k)
	return txn.Commit(), old, ok
}

// Root returns the root node of the tree which can be used for richer
// query operations.
func (t *Tree) Root() *Node {
	return t.root
}

// Get is used to lookup a specific key, returning
// the value and if it was found
func (t *Tree) Get(k []byte) (interface{}, bool) {
	return t.root.Get(k)
}

// longestPrefix finds the length of the shared prefix
// of two strings
func longestPrefix(k1, k2 []byte) int {
	max := len(k1)
	if l := len(k2); l < max {
		max = l
	}
	var i int
	for i = 0; i < max; i++ {
		if k1[i] != k2[i] {
			break
		}
	}
	return i
}

// concat two byte slices, returning a third new copy
func concat(a, b []byte) []byte {
	c := make([]byte, len(a)+len(b))
	copy(c, a)
	copy(c[len(a):], b)
	return c
}
<commit_msg>Expose GetWatch on transaction<commit_after>package iradix

import (
	"bytes"

	"github.com/hashicorp/golang-lru/simplelru"
)

const (
	// defaultModifiedCache is the default size of the modified node
	// cache used per transaction. This is used to cache the updates
	// to the nodes near the root, while the leaves do not need to be
	// cached. This is important for very large transactions to prevent
	// the modified cache from growing to be enormous.
	defaultModifiedCache = 8192
)

// Tree implements an immutable radix tree. This can be treated as a
// Dictionary abstract data type. The main advantage over a standard
// hash map is prefix-based lookups and ordered iteration. The immutability
// means that it is safe to concurrently read from a Tree without any
// coordination.
type Tree struct {
	root *Node
	size int
}

// New returns an empty Tree
func New() *Tree {
	t := &Tree{root: &Node{}}
	return t
}

// Len is used to return the number of elements in the tree
func (t *Tree) Len() int {
	return t.size
}

// Txn is a transaction on the tree. This transaction is applied
// atomically and returns a new tree when committed. A transaction
// is not thread safe, and should only be used by a single goroutine.
type Txn struct {
	root     *Node
	size     int
	modified *simplelru.LRU

	mutatedNode  map[*Node]struct{}
	mutatedLeaf  map[*leafNode]struct{}
	notifyMutate bool
}

// Txn starts a new transaction that can be used to mutate the tree
func (t *Tree) Txn() *Txn {
	txn := &Txn{
		root: t.root,
		size: t.size,
	}
	return txn
}

// NotifyMutate can be used to toggle if mutation cause a notification
// to the affected nodes. This must be enabled before any modifications are
// made within the transaction.
func (t *Txn) NotifyMutate(notify bool) error {
	if len(t.modified) > 0 && notify {
		return fmt.Errorf("transaction already in progress")
	}
	t.notifyMutate = notify
	return nil
}

// writeNode returns a node to be modified, if the current
// node as already been modified during the course of
// the transaction, it is used in-place.
func (t *Txn) writeNode(n *Node) *Node {
	// Ensure the modified set exists
	if t.modified == nil {
		lru, err := simplelru.NewLRU(defaultModifiedCache, nil)
		if err != nil {
			panic(err)
		}
		t.modified = lru
	}

	// If this node has already been modified, we can
	// continue to use it during this transaction.
	if _, ok := t.modified.Get(n); ok {
		return n
	}

	// Mark this node as being mutated
	if t.notifyMutate {
		if t.mutatedNode == nil {
			t.mutatedNode = make(map[*Node]struct{})
		}
		t.mutatedNode[n] = struct{}{}
	}

	// Copy the existing node
	nc := new(Node)
	nc.mutateCh = make(chan struct{})
	if n.prefix != nil {
		nc.prefix = make([]byte, len(n.prefix))
		copy(nc.prefix, n.prefix)
	}
	if n.leaf != nil {
		nc.leaf = n.leaf
	}
	if len(n.edges) != 0 {
		nc.edges = make([]edge, len(n.edges))
		copy(nc.edges, n.edges)
	}

	// Mark this node as modified
	t.modified.Add(nc, nil)
	return nc
}

// mutateLeaf is used to mark a leaf as being mutated
// for the purposes of notification.
func (t *Txn) mutateLeaf(leaf *leafNode) {
	if !t.notifyMutate {
		return
	}
	if t.mutatedLeaf == nil {
		t.mutatedLeaf = make(map[*leafNode]struct{})
	}
	t.mutatedLeaf[leaf] = struct{}{}
}

// insert does a recursive insertion
func (t *Txn) insert(n *Node, k, search []byte, v interface{}) (*Node, interface{}, bool) {
	// Handle key exhaution
	if len(search) == 0 {
		nc := t.writeNode(n)
		nc.leaf = &leafNode{
			mutateCh: make(chan struct{}),
			key:      k,
			val:      v,
		}
		if n.isLeaf() {
			t.mutateLeaf(n.leaf)
			return nc, n.leaf.val, true
		} else {
			return nc, nil, false
		}
	}

	// Look for the edge
	idx, child := n.getEdge(search[0])

	// No edge, create one
	if child == nil {
		e := edge{
			label: search[0],
			node: &Node{
				mutateCh: make(chan struct{}),
				leaf: &leafNode{
					mutateCh: make(chan struct{}),
					key:      k,
					val:      v,
				},
				prefix: search,
			},
		}
		nc := t.writeNode(n)
		nc.addEdge(e)
		return nc, nil, false
	}

	// Determine longest prefix of the search key on match
	commonPrefix := longestPrefix(search, child.prefix)
	if commonPrefix == len(child.prefix) {
		search = search[commonPrefix:]
		newChild, oldVal, didUpdate := t.insert(child, k, search, v)
		if newChild != nil {
			nc := t.writeNode(n)
			nc.edges[idx].node = newChild
			return nc, oldVal, didUpdate
		}
		return nil, oldVal, didUpdate
	}

	// Split the node
	nc := t.writeNode(n)
	splitNode := &Node{
		mutateCh: make(chan struct{}),
		prefix:   search[:commonPrefix],
	}
	nc.replaceEdge(edge{
		label: search[0],
		node:  splitNode,
	})

	// Restore the existing child node
	modChild := t.writeNode(child)
	splitNode.addEdge(edge{
		label: modChild.prefix[commonPrefix],
		node:  modChild,
	})
	modChild.prefix = modChild.prefix[commonPrefix:]

	// Create a new leaf node
	leaf := &leafNode{
		mutateCh: make(chan struct{}),
		key:      k,
		val:      v,
	}

	// If the new key is a subset, add to to this node
	search = search[commonPrefix:]
	if len(search) == 0 {
		splitNode.leaf = leaf
		return nc, nil, false
	}

	// Create a new edge for the node
	splitNode.addEdge(edge{
		label: search[0],
		node: &Node{
			mutateCh: make(chan struct{}),
			leaf:     leaf,
			prefix:   search,
		},
	})
	return nc, nil, false
}

// delete does a recursive deletion
func (t *Txn) delete(parent, n *Node, search []byte) (*Node, *leafNode) {
	// Check for key exhaution
	if len(search) == 0 {
		if !n.isLeaf() {
			return nil, nil
		}

		// Remove the leaf node
		nc := t.writeNode(n)
		nc.leaf = nil
		t.mutateLeaf(n.leaf)

		// Check if this node should be merged
		if n != t.root && len(nc.edges) == 1 {
			nc.mergeChild()
		}
		return nc, n.leaf
	}

	// Look for an edge
	label := search[0]
	idx, child := n.getEdge(label)
	if child == nil || !bytes.HasPrefix(search, child.prefix) {
		return nil, nil
	}

	// Consume the search prefix
	search = search[len(child.prefix):]
	newChild, leaf := t.delete(n, child, search)
	if newChild == nil {
		return nil, nil
	}

	// Copy this node
	nc := t.writeNode(n)

	// Delete the edge if the node has no edges
	if newChild.leaf == nil && len(newChild.edges) == 0 {
		nc.delEdge(label)
		if n != t.root && len(nc.edges) == 1 && !nc.isLeaf() {
			nc.mergeChild()
		}
	} else {
		nc.edges[idx].node = newChild
	}
	return nc, leaf
}

// Insert is used to add or update a given key. The return provides
// the previous value and a bool indicating if any was set.
func (t *Txn) Insert(k []byte, v interface{}) (interface{}, bool) {
	newRoot, oldVal, didUpdate := t.insert(t.root, k, k, v)
	if newRoot != nil {
		t.root = newRoot
	}
	if !didUpdate {
		t.size++
	}
	return oldVal, didUpdate
}

// Delete is used to delete a given key. Returns the old value if any,
// and a bool indicating if the key was set.
func (t *Txn) Delete(k []byte) (interface{}, bool) {
	newRoot, leaf := t.delete(nil, t.root, k)
	if newRoot != nil {
		t.root = newRoot
	}
	if leaf != nil {
		t.size--
		return leaf.val, true
	}
	return nil, false
}

// Root returns the current root of the radix tree within this
// transaction. The root is not safe across insert and delete operations,
// but can be used to read the current state during a transaction.
func (t *Txn) Root() *Node {
	return t.root
}

// Get is used to lookup a specific key, returning
// the value and if it was found
func (t *Txn) Get(k []byte) (interface{}, bool) {
	return t.root.Get(k)
}

// GetWatch is used to lookup a specific key, returning
// the watch channel, value and if it was found
func (t *Txn) GetWatch(k []byte) (<-chan struct{}, interface{}, bool) {
	return t.root.GetWatch(k)
}

// Commit is used to finalize the transaction and return a new tree
func (t *Txn) Commit() *Tree {
	nt := &Tree{t.root, t.size}
	if t.notifyMutate {
		for leaf := range t.mutatedLeaf {
			close(leaf.mutateCh)
		}
		for node := range t.mutatedNode {
			close(node.mutateCh)
		}
	}
	t.modified = nil
	t.mutatedNode = nil
	t.mutatedLeaf = nil
	return nt
}

// Insert is used to add or update a given key. The return provides
// the new tree, previous value and a bool indicating if any was set.
func (t *Tree) Insert(k []byte, v interface{}) (*Tree, interface{}, bool) {
	txn := t.Txn()
	old, ok := txn.Insert(k, v)
	return txn.Commit(), old, ok
}

// Delete is used to delete a given key. Returns the new tree,
// old value if any, and a bool indicating if the key was set.
func (t *Tree) Delete(k []byte) (*Tree, interface{}, bool) {
	txn := t.Txn()
	old, ok := txn.Delete(k)
	return txn.Commit(), old, ok
}

// Root returns the root node of the tree which can be used for richer
// query operations.
func (t *Tree) Root() *Node {
	return t.root
}

// Get is used to lookup a specific key, returning
// the value and if it was found
func (t *Tree) Get(k []byte) (interface{}, bool) {
	return t.root.Get(k)
}

// longestPrefix finds the length of the shared prefix
// of two strings
func longestPrefix(k1, k2 []byte) int {
	max := len(k1)
	if l := len(k2); l < max {
		max = l
	}
	var i int
	for i = 0; i < max; i++ {
		if k1[i] != k2[i] {
			break
		}
	}
	return i
}

// concat two byte slices, returning a third new copy
func concat(a, b []byte) []byte {
	c := make([]byte, len(a)+len(b))
	copy(c, a)
	copy(c[len(a):], b)
	return c
}
<|endoftext|>


<commit_before>// +build linux
package tap

import (
	"fmt"
	//"log"
	"net"
	"sync"
	"syscall"
	"unsafe"
)

type route struct {
	gateway  net.IP
	dst      *net.IPNet
	if_index int
}

func find_gateway(ip_mask *net.IPNet) (ip net.IP, dev string, err error) {
	buf, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET)
	if err != nil {
		return
	}
	msgs, err := syscall.ParseNetlinkMessage(buf)
	if err != nil {
		return
	}
	var def route
	var once sync.Once
loop:
	for _, m := range msgs {
		switch m.Header.Type {
		case syscall.NLMSG_DONE:
			break loop
		case syscall.RTM_NEWROUTE:
			// a route enrty
			var r route
			rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
			attrs, err := syscall.ParseNetlinkRouteAttr(&m)
			if err != nil {
				// err is shadowed
				return ip, dev, err
			}
			// parse a route entry
			for _, a := range attrs {
				switch a.Attr.Type {
				case syscall.RTA_DST:
					addr := a.Value
					_, r.dst, err = net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", addr[0], addr[1], addr[2], addr[3], rtmsg.Dst_len))
					if err != nil {
						return ip, dev, err
					}
				case syscall.RTA_GATEWAY:
					addr := a.Value
					r.gateway = net.IPv4(addr[0], addr[1], addr[2], addr[3])
				case syscall.RTA_OIF:
					r.if_index = int(a.Value[0])
				}
			}
			if r.dst == nil {
				once.Do(func() {
					def = r
				})
			}
			if r.dst.Contains(ip_mask.IP) {
				ifce, err := net.InterfaceByIndex(r.if_index)
				if err != nil {
					return ip, dev, err
				}
				return r.gateway, ifce.Name, nil
			}
		}
	}
	err = fmt.Errorf("Route not Found.")
	return
}
<commit_msg>If route entry not found, return default route.<commit_after>// +build linux
package tap

import (
	"fmt"
	"log"
	"net"
	"sync"
	"syscall"
	"unsafe"
)

type route struct {
	gateway  net.IP
	dst      *net.IPNet
	if_index int
}

func find_gateway(ip_mask *net.IPNet) (ip net.IP, dev string, err error) {
	buf, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET)
	if err != nil {
		log.Println("Failed to open netlink:", err)
		return
	}
	msgs, err := syscall.ParseNetlinkMessage(buf)
	if err != nil {
		log.Println("Failed to parse nl msg:", err)
		return
	}
	var def route
	set := false
	var once sync.Once
loop:
	for _, m := range msgs {
		switch m.Header.Type {
		case syscall.NLMSG_DONE:
			break loop
		case syscall.RTM_NEWROUTE:
			// a route enrty
			var r route
			rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
			attrs, err := syscall.ParseNetlinkRouteAttr(&m)
			if err != nil {
				// err is shadowed
				log.Println("Failed to parse nl rtattr:", err)
				return ip, dev, err
			}
			// parse a route entry
			for _, a := range attrs {
				switch a.Attr.Type {
				case syscall.RTA_DST:
					addr := a.Value
					_, r.dst, err = net.ParseCIDR(fmt.Sprintf("%d.%d.%d.%d/%d", addr[0], addr[1], addr[2], addr[3], rtmsg.Dst_len))
					if err != nil {
						log.Println("Failed to parse ip addr:", err)
						return ip, dev, err
					}
				case syscall.RTA_GATEWAY:
					addr := a.Value
					r.gateway = net.IPv4(addr[0], addr[1], addr[2], addr[3])
				case syscall.RTA_OIF:
					r.if_index = int(a.Value[0])
				}
			}
			if r.dst == nil {
				once.Do(func() {
					def = r
					set = true
				})
			} else {
				if r.dst.Contains(ip_mask.IP) {
					ifce, err := net.InterfaceByIndex(r.if_index)
					if err != nil {
						log.Println("Failed to get interface by index:", err)
						return ip, dev, err
					}
					return r.gateway, ifce.Name, nil
				}

			}
		}
	}
	if set {
		ifce, err := net.InterfaceByIndex(def.if_index)
		if err != nil {
			log.Println("Failed to get interface by index:", err)
			return ip, dev, err
		}
		return def.gateway, ifce.Name, nil
	}
	err = fmt.Errorf("Route not found.")
	return
}
<|endoftext|>


<commit_before>package validator_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/go-jstmpl/go-jsvalidator"
	"github.com/gocraft/dbr"
)

func TestNewRequiredValidator(t *testing.T) {
	type Case struct {
		Message    string
		Definition validator.RequiredValidatorDefinition
		Error      error
	}
	cases := []Case{
		{
			Message:    "single element",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo"}},
			Error:      nil,
		},
		{
			Message:    "multi elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "bar"}},
			Error:      nil,
		},
		{
			Message:    "empty slice",
			Definition: validator.RequiredValidatorDefinition{Required: []string{}},
			Error:      validator.RequiredDefinitionEmptyError,
		},
		{
			Message:    "duplicated elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at first and second",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo", "bar"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at first and end",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "bar", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at second end end",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"bar", "foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated all elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
	}
	for _, c := range cases {
		_, err := validator.NewRequiredValidator(c.Definition)
		if err != c.Error {
			t.Errorf("Test with %s: fail to NewPatternValidator with error %v", c.Message, err)
		}
	}
}

func TestValidateOfRequiredValidator(t *testing.T) {
	type Types struct {
		NullableStringValue dbr.NullString
		NullableIntValue    dbr.NullInt64
		NullableFloatValue  dbr.NullFloat64
		NullableBoolValue   dbr.NullBool
		NullableTimeValue   dbr.NullTime
		StringValue         string
		IntValue            int
		FloatValue          float64
		BoolValue           bool
		TimeValue           time.Time
	}

	type Input struct {
		Types      Types
		Definition validator.RequiredValidatorDefinition
	}

	type Case struct {
		Message  string
		Input    Input
		Expected error
	}

	cases := []Case{
		{
			Message: "complete struct against required",
			Input: Input{
				Types: Types{
					NullableStringValue: dbr.NewNullString("value"),
					NullableIntValue:    dbr.NewNullInt64(1),
					NullableFloatValue:  dbr.NewNullFloat64(1.1),
					NullableBoolValue:   dbr.NewNullBool(true),
					NullableTimeValue:   dbr.NewNullTime("2009-11-10 23:00:00"),
					StringValue:         "value",
					IntValue:            1,
					FloatValue:          1.1,
					BoolValue:           true,
					TimeValue:           time.Date(2009, 11, 10, 23, 00, 0, 0, time.UTC),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{
						"NullableStringValue",
						"NullableIntValue",
						"NullableFloatValue",
						"NullableBoolValue",
						"NullableTimeValue",
						"StringValue",
						"IntValue",
						"FloatValue",
						"BoolValue",
						"TimeValue",
					},
				},
			},
			Expected: nil,
		},
		{
			Message: "NullableStringValue is missing",
			Input: Input{
				Types: Types{
					NullableStringValue: dbr.NewNullString(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableStringValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableStringValue: dbr.NewNullString(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableStringValue"},
				},
			},
		},
		{
			Message: "NullableIntValue is missing",
			Input: Input{
				Types: Types{
					NullableIntValue: dbr.NewNullInt64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableIntValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableIntValue: dbr.NewNullInt64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableIntValue"},
				},
			},
		},
		{
			Message: "NullableFloatValue is missing",
			Input: Input{
				Types: Types{
					NullableFloatValue: dbr.NewNullFloat64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableFloatValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableFloatValue: dbr.NewNullFloat64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableFloatValue"},
				},
			},
		},
		{
			Message: "NullableBoolValue is missing",
			Input: Input{
				Types: Types{
					NullableBoolValue: dbr.NewNullBool(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableBoolValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableBoolValue: dbr.NewNullBool(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableBoolValue"},
				},
			},
		},
		{
			Message: "NullableTimeValue is missing",
			Input: Input{
				Types: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
		},

		{
			Message: "NullableTimeValue is missing",
			Input: Input{
				Types: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
		},
	}

	for _, c := range cases {
		definition := c.Input.Definition
		va, err := validator.NewRequiredValidator(definition)
		if err != nil {
			t.Errorf("test with %s: fail to create new required validator: %s", c.Message, err)
			continue
		}

		err = va.Validate(c.Input.Types)
		if !reflect.DeepEqual(err, c.Expected) {
			t.Errorf("test with %s: expected %+v, but actual %+v", c.Message, c.Expected, err)
		}
	}
}

func TestConvertToConcreteValue(t *testing.T) {
	// Output expected is always Kind of non Ptr
	type Case struct {
		Message string
		Input   reflect.Value
	}
	var (
		stringValue = "string"
		intValue    = 1
		floatValue  = 1.1
		boolValue   = true
		structValue = time.Now()
	)

	cases := []Case{
		{
			Message: "kind of string",
			Input:   reflect.ValueOf(stringValue),
		},
		{
			Message: "kind of int",
			Input:   reflect.ValueOf(intValue),
		},
		{
			Message: "kind of float",
			Input:   reflect.ValueOf(floatValue),
		},
		{
			Message: "kind of bool",
			Input:   reflect.ValueOf(boolValue),
		},
		{
			Message: "kind of struct",
			Input:   reflect.ValueOf(structValue),
		},
		{
			Message: "kind of pointer of string",
			Input:   reflect.ValueOf(&stringValue),
		},
		{
			Message: "kind of pointer of int",
			Input:   reflect.ValueOf(&intValue),
		},
		{
			Message: "kind of pointer of float",
			Input:   reflect.ValueOf(&floatValue),
		},
		{
			Message: "kind of pointer of bool",
			Input:   reflect.ValueOf(&boolValue),
		},
		{
			Message: "kind of pointer of struct",
			Input:   reflect.ValueOf(&structValue),
		},
	}

	for _, c := range cases {
		v, ok := validator.ConvertToConcreteValue(c.Input)
		if !ok {
			t.Errorf("test with %s: fail to convert to concrete value %v", c.Message, c.Input)
		}
		if v.Kind() == reflect.Ptr {
			t.Errorf("test with  %s: expected non Ptr but not", c.Message)
		}
	}
}

func TestGetFieldByName(t *testing.T) {
	type Sample struct {
		Hoge string
		Foo  string
		Bar  string
	}

	v, ok := validator.GetFieldByName(
		reflect.ValueOf(
			Sample{
				Hoge: "hoge",
				Foo:  "foo",
				Bar:  "bar",
			},
		),
		"Foo",
	)
	if !ok {
		t.Fatal("test with existing field key: expected true but not")
	}
	i := v.Interface()
	if i.(string) != "foo" {
		t.Errorf("test with existing field: expected `foo` but not")
	}

	_, ok = validator.GetFieldByName(
		reflect.ValueOf(
			Sample{
				Hoge: "hoge",
				Foo:  "foo",
				Bar:  "bar",
			},
		),
		"Piyo",
	)
	if ok {
		t.Errorf("test with not existing field: expected false but not")
	}
}

func TestIsValid(t *testing.T) {
	type Case struct {
		Description     string
		Input           interface{}
		ExpectedIsValid bool
	}

	cases := []Case{
		{
			Description:     "primitive value",
			Input:           "value",
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable string",
			Input:           dbr.NewNullString("value"),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable int",
			Input:           dbr.NewNullInt64(1),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable float",
			Input:           dbr.NewNullFloat64(1.1),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable bool",
			Input:           dbr.NewNullBool(true),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable time",
			Input:           dbr.NewNullTime(time.Now()),
			ExpectedIsValid: true,
		},
		{
			Description:     "invalid nullable string",
			Input:           dbr.NewNullString(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable int",
			Input:           dbr.NewNullInt64(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable float",
			Input:           dbr.NewNullFloat64(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable bool",
			Input:           dbr.NewNullBool(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable time",
			Input:           dbr.NewNullTime(nil),
			ExpectedIsValid: false,
		},
	}

	for _, c := range cases {
		ok := validator.IsValid(c.Input)
		if ok != c.ExpectedIsValid {
			t.Errorf("test with %s: expected %t but not", c.Description, c.ExpectedIsValid)
		}
	}
}
<commit_msg>Add test for isPresentString method<commit_after>package validator_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/go-jstmpl/go-jsvalidator"
	"github.com/gocraft/dbr"
)

func TestNewRequiredValidator(t *testing.T) {
	type Case struct {
		Message    string
		Definition validator.RequiredValidatorDefinition
		Error      error
	}
	cases := []Case{
		{
			Message:    "single element",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo"}},
			Error:      nil,
		},
		{
			Message:    "multi elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "bar"}},
			Error:      nil,
		},
		{
			Message:    "empty slice",
			Definition: validator.RequiredValidatorDefinition{Required: []string{}},
			Error:      validator.RequiredDefinitionEmptyError,
		},
		{
			Message:    "duplicated elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at first and second",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo", "bar"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at first and end",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "bar", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated elements at second end end",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"bar", "foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
		{
			Message:    "duplicated all elements",
			Definition: validator.RequiredValidatorDefinition{Required: []string{"foo", "foo", "foo"}},
			Error:      validator.RequiredDefinitionDuplicationError,
		},
	}
	for _, c := range cases {
		_, err := validator.NewRequiredValidator(c.Definition)
		if err != c.Error {
			t.Errorf("Test with %s: fail to NewPatternValidator with error %v", c.Message, err)
		}
	}
}

func TestValidateOfRequiredValidator(t *testing.T) {
	type Types struct {
		NullableStringValue dbr.NullString
		NullableIntValue    dbr.NullInt64
		NullableFloatValue  dbr.NullFloat64
		NullableBoolValue   dbr.NullBool
		NullableTimeValue   dbr.NullTime
		StringValue         string
		IntValue            int
		FloatValue          float64
		BoolValue           bool
		TimeValue           time.Time
	}

	type Input struct {
		Types      Types
		Definition validator.RequiredValidatorDefinition
	}

	type Case struct {
		Message  string
		Input    Input
		Expected error
	}

	cases := []Case{
		{
			Message: "complete struct against required",
			Input: Input{
				Types: Types{
					NullableStringValue: dbr.NewNullString("value"),
					NullableIntValue:    dbr.NewNullInt64(1),
					NullableFloatValue:  dbr.NewNullFloat64(1.1),
					NullableBoolValue:   dbr.NewNullBool(true),
					NullableTimeValue:   dbr.NewNullTime("2009-11-10 23:00:00"),
					StringValue:         "value",
					IntValue:            1,
					FloatValue:          1.1,
					BoolValue:           true,
					TimeValue:           time.Date(2009, 11, 10, 23, 00, 0, 0, time.UTC),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{
						"NullableStringValue",
						"NullableIntValue",
						"NullableFloatValue",
						"NullableBoolValue",
						"NullableTimeValue",
						"StringValue",
						"IntValue",
						"FloatValue",
						"BoolValue",
						"TimeValue",
					},
				},
			},
			Expected: nil,
		},
		{
			Message: "NullableStringValue is missing",
			Input: Input{
				Types: Types{
					NullableStringValue: dbr.NewNullString(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableStringValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableStringValue: dbr.NewNullString(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableStringValue"},
				},
			},
		},
		{
			Message: "NullableIntValue is missing",
			Input: Input{
				Types: Types{
					NullableIntValue: dbr.NewNullInt64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableIntValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableIntValue: dbr.NewNullInt64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableIntValue"},
				},
			},
		},
		{
			Message: "NullableFloatValue is missing",
			Input: Input{
				Types: Types{
					NullableFloatValue: dbr.NewNullFloat64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableFloatValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableFloatValue: dbr.NewNullFloat64(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableFloatValue"},
				},
			},
		},
		{
			Message: "NullableBoolValue is missing",
			Input: Input{
				Types: Types{
					NullableBoolValue: dbr.NewNullBool(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableBoolValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableBoolValue: dbr.NewNullBool(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableBoolValue"},
				},
			},
		},
		{
			Message: "NullableTimeValue is missing",
			Input: Input{
				Types: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
		},

		{
			Message: "NullableTimeValue is missing",
			Input: Input{
				Types: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
			Expected: &validator.RequiredValidationError{
				Input: Types{
					NullableTimeValue: dbr.NewNullTime(nil),
				},
				Definition: validator.RequiredValidatorDefinition{
					Required: []string{"NullableTimeValue"},
				},
			},
		},
	}

	for _, c := range cases {
		definition := c.Input.Definition
		va, err := validator.NewRequiredValidator(definition)
		if err != nil {
			t.Errorf("test with %s: fail to create new required validator: %s", c.Message, err)
			continue
		}

		err = va.Validate(c.Input.Types)
		if !reflect.DeepEqual(err, c.Expected) {
			t.Errorf("test with %s: expected %+v, but actual %+v", c.Message, c.Expected, err)
		}
	}
}

func TestConvertToConcreteValue(t *testing.T) {
	// Output expected is always Kind of non Ptr
	type Case struct {
		Message string
		Input   reflect.Value
	}
	var (
		stringValue = "string"
		intValue    = 1
		floatValue  = 1.1
		boolValue   = true
		structValue = time.Now()
	)

	cases := []Case{
		{
			Message: "kind of string",
			Input:   reflect.ValueOf(stringValue),
		},
		{
			Message: "kind of int",
			Input:   reflect.ValueOf(intValue),
		},
		{
			Message: "kind of float",
			Input:   reflect.ValueOf(floatValue),
		},
		{
			Message: "kind of bool",
			Input:   reflect.ValueOf(boolValue),
		},
		{
			Message: "kind of struct",
			Input:   reflect.ValueOf(structValue),
		},
		{
			Message: "kind of pointer of string",
			Input:   reflect.ValueOf(&stringValue),
		},
		{
			Message: "kind of pointer of int",
			Input:   reflect.ValueOf(&intValue),
		},
		{
			Message: "kind of pointer of float",
			Input:   reflect.ValueOf(&floatValue),
		},
		{
			Message: "kind of pointer of bool",
			Input:   reflect.ValueOf(&boolValue),
		},
		{
			Message: "kind of pointer of struct",
			Input:   reflect.ValueOf(&structValue),
		},
	}

	for _, c := range cases {
		v, ok := validator.ConvertToConcreteValue(c.Input)
		if !ok {
			t.Errorf("test with %s: fail to convert to concrete value %v", c.Message, c.Input)
		}
		if v.Kind() == reflect.Ptr {
			t.Errorf("test with  %s: expected non Ptr but not", c.Message)
		}
	}
}

func TestGetFieldByName(t *testing.T) {
	type Sample struct {
		Hoge string
		Foo  string
		Bar  string
	}

	v, ok := validator.GetFieldByName(
		reflect.ValueOf(
			Sample{
				Hoge: "hoge",
				Foo:  "foo",
				Bar:  "bar",
			},
		),
		"Foo",
	)
	if !ok {
		t.Fatal("test with existing field key: expected true but not")
	}
	i := v.Interface()
	if i.(string) != "foo" {
		t.Errorf("test with existing field: expected `foo` but not")
	}

	_, ok = validator.GetFieldByName(
		reflect.ValueOf(
			Sample{
				Hoge: "hoge",
				Foo:  "foo",
				Bar:  "bar",
			},
		),
		"Piyo",
	)
	if ok {
		t.Errorf("test with not existing field: expected false but not")
	}
}

func TestIsPresentString(t *testing.T) {
	type Case struct {
		Description       string
		Input             string
		ExpectedIsPresent bool
	}

	cases := []Case{
		{
			Description:       "presented value",
			Input:             "value",
			ExpectedIsPresent: true,
		},
		{
			Description:       "empty",
			Input:             "",
			ExpectedIsPresent: false,
		},
		{
			Description:       "single space",
			Input:             " ",
			ExpectedIsPresent: false,
		},
		{
			Description:       "double space",
			Input:             "  ",
			ExpectedIsPresent: false,
		},
		{
			Description:       "many space",
			Input:             "                         ",
			ExpectedIsPresent: false,
		},
		{
			Description:       "horizontal tab",
			Input:             "\t",
			ExpectedIsPresent: false,
		},
		{
			Description:       "newline",
			Input:             "\n",
			ExpectedIsPresent: false,
		},
		{
			Description:       "vertical tab character",
			Input:             "\v",
			ExpectedIsPresent: false,
		},
		{
			Description:       "form feed",
			Input:             "\f",
			ExpectedIsPresent: false,
		},
		{
			Description:       "carriage return",
			Input:             "\r",
			ExpectedIsPresent: false,
		},
		{
			Description:       "whitespace",
			Input:             "\t\n\v\f\r ",
			ExpectedIsPresent: false,
		},
		{
			Description:       "whitespace with value",
			Input:             "\t\n\v\f\r value",
			ExpectedIsPresent: true,
		},
	}

	for _, c := range cases {
		ok := validator.IsPresentString(c.Input)
		if ok != c.ExpectedIsPresent {
			t.Errorf("test with %s: expected %t but not", c.Description, c.ExpectedIsPresent)
		}
	}
}

func TestIsValid(t *testing.T) {
	type Case struct {
		Description     string
		Input           interface{}
		ExpectedIsValid bool
	}

	cases := []Case{
		{
			Description:     "primitive value",
			Input:           "value",
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable string",
			Input:           dbr.NewNullString("value"),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable int",
			Input:           dbr.NewNullInt64(1),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable float",
			Input:           dbr.NewNullFloat64(1.1),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable bool",
			Input:           dbr.NewNullBool(true),
			ExpectedIsValid: true,
		},
		{
			Description:     "valid nullable time",
			Input:           dbr.NewNullTime(time.Now()),
			ExpectedIsValid: true,
		},
		{
			Description:     "invalid nullable string",
			Input:           dbr.NewNullString(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable int",
			Input:           dbr.NewNullInt64(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable float",
			Input:           dbr.NewNullFloat64(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable bool",
			Input:           dbr.NewNullBool(nil),
			ExpectedIsValid: false,
		},
		{
			Description:     "invalid nullable time",
			Input:           dbr.NewNullTime(nil),
			ExpectedIsValid: false,
		},
	}

	for _, c := range cases {
		ok := validator.IsValid(c.Input)
		if ok != c.ExpectedIsValid {
			t.Errorf("test with %s: expected %t but not", c.Description, c.ExpectedIsValid)
		}
	}
}
<|endoftext|>