<commit_before>package pixel

import (
	"image/color"

	"runtime"

	"github.com/faiface/mainthread"
	"github.com/faiface/pixel/pixelgl"
	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/pkg/errors"
)

// WindowConfig is a structure for specifying all possible properties of a window. Properties are
// chosen in such a way, that you usually only need to set a few of them - defaults (zeros) should
// usually be sensible.
//
// Note that you always need to set the width and the height of a window.
type WindowConfig struct {
	// Title at the top of a window.
	Title string

	// Width of a window in pixels.
	Width float64

	// Height of a window in pixels.
	Height float64

	// If set to nil, a window will be windowed. Otherwise it will be fullscreen on the
	// specified monitor.
	Fullscreen *Monitor

	// Whether a window is resizable.
	Resizable bool

	// If set to true, the window will be initially invisible.
	Hidden bool

	// Undecorated window ommits the borders and decorations (close button, etc.).
	Undecorated bool

	// If set to true, a window will not get focused upon showing up.
	Unfocused bool

	// Whether a window is maximized.
	Maximized bool

	// VSync (vertical synchronization) synchronizes window's framerate with the framerate
	// of the monitor.
	VSync bool

	// Number of samples for multi-sample anti-aliasing (edge-smoothing).  Usual values
	// are 0, 2, 4, 8 (powers of 2 and not much more than this).
	MSAASamples int
}

// Window is a window handler. Use this type to manipulate a window (input, drawing, ...).
type Window struct {
	enabled bool
	window  *glfw.Window
	config  WindowConfig

	canvas   *Canvas
	canvasVs *pixelgl.VertexSlice
	shader   *pixelgl.Shader

	// need to save these to correctly restore a fullscreen window
	restore struct {
		xpos, ypos, width, height int
	}

	prevInp, tempInp, currInp struct {
		buttons [KeyLast + 1]bool
		scroll  Vec
	}
}

var currentWindow *Window

// NewWindow creates a new window with it's properties specified in the provided config.
//
// If window creation fails, an error is returned.
func NewWindow(config WindowConfig) (*Window, error) {
	bool2int := map[bool]int{
		true:  glfw.True,
		false: glfw.False,
	}

	w := &Window{config: config}

	err := mainthread.CallErr(func() error {
		err := glfw.Init()
		if err != nil {
			return err
		}

		glfw.WindowHint(glfw.ContextVersionMajor, 3)
		glfw.WindowHint(glfw.ContextVersionMinor, 3)
		glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
		glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

		glfw.WindowHint(glfw.Resizable, bool2int[config.Resizable])
		glfw.WindowHint(glfw.Visible, bool2int[!config.Hidden])
		glfw.WindowHint(glfw.Decorated, bool2int[!config.Undecorated])
		glfw.WindowHint(glfw.Focused, bool2int[!config.Unfocused])
		glfw.WindowHint(glfw.Maximized, bool2int[config.Maximized])
		glfw.WindowHint(glfw.Samples, config.MSAASamples)

		var share *glfw.Window
		if currentWindow != nil {
			share = currentWindow.window
		}
		w.window, err = glfw.CreateWindow(
			int(config.Width),
			int(config.Height),
			config.Title,
			nil,
			share,
		)
		if err != nil {
			return err
		}

		// enter the OpenGL context
		w.begin()
		w.end()

		w.shader, err = pixelgl.NewShader(
			windowVertexFormat,
			windowUniformFormat,
			windowVertexShader,
			windowFragmentShader,
		)
		if err != nil {
			return err
		}

		w.canvasVs = pixelgl.MakeVertexSlice(w.shader, 6, 6)
		w.canvasVs.Begin()
		w.canvasVs.SetVertexData([]float32{
			-1, -1, 0, 0,
			1, -1, 1, 0,
			1, 1, 1, 1,
			-1, -1, 0, 0,
			1, 1, 1, 1,
			-1, 1, 0, 1,
		})
		w.canvasVs.End()

		return nil
	})
	if err != nil {
		return nil, errors.Wrap(err, "creating window failed")
	}

	w.initInput()
	w.SetFullscreen(config.Fullscreen)
	w.Update()

	runtime.SetFinalizer(w, (*Window).Destroy)

	return w, nil
}

// Destroy destroys a window. The window can't be used any further.
func (w *Window) Destroy() {
	mainthread.Call(func() {
		w.window.Destroy()
	})
}

// Clear clears the window with a color.
func (w *Window) Clear(c color.Color) {
	w.canvas.Clear(c)
}

// Update swaps buffers and polls events.
func (w *Window) Update() {
	width, height := w.Size()
	if w.canvas == nil || V(w.canvas.Size()) != V(width, height) {
		oldCanvas := w.canvas
		w.canvas = NewCanvas(width, height, false)
		if oldCanvas != nil {
			td := TrianglesDrawer{Triangles: &TrianglesData{
				{Position: V(-1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 0)},
				{Position: V(1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 0)},
				{Position: V(1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 1)},
				{Position: V(-1, -1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 0)},
				{Position: V(1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(1, 1)},
				{Position: V(-1, 1), Color: NRGBA{1, 1, 1, 1}, Texture: V(0, 1)},
			}}
			w.canvas.SetPicture(oldCanvas.Content())
			td.Draw(w.canvas)
		}
	}

	mainthread.Call(func() {
		w.begin()

		pixelgl.Clear(0, 0, 0, 0)
		w.shader.Begin()
		w.canvas.f.Texture().Begin()
		w.canvasVs.Begin()
		w.canvasVs.Draw()
		w.canvasVs.End()
		w.canvas.f.Texture().End()
		w.shader.End()

		if w.config.VSync {
			glfw.SwapInterval(1)
		}
		w.window.SwapBuffers()
		w.end()
	})

	w.updateInput()
}

// SetClosed sets the closed flag of a window.
//
// This is usefull when overriding the user's attempt to close a window, or just to close a
// window from within a program.
func (w *Window) SetClosed(closed bool) {
	mainthread.Call(func() {
		w.window.SetShouldClose(closed)
	})
}

// Closed returns the closed flag of a window, which reports whether the window should be closed.
//
// The closed flag is automatically set when a user attempts to close a window.
func (w *Window) Closed() bool {
	return mainthread.CallVal(func() interface{} {
		return w.window.ShouldClose()
	}).(bool)
}

// SetTitle changes the title of a window.
func (w *Window) SetTitle(title string) {
	mainthread.Call(func() {
		w.window.SetTitle(title)
	})
}

// SetSize resizes a window to the specified size in pixels.  In case of a fullscreen window,
// it changes the resolution of that window.
func (w *Window) SetSize(width, height float64) {
	mainthread.Call(func() {
		w.window.SetSize(int(width), int(height))
	})
}

// Size returns the size of the client area of a window (the part you can draw on).
func (w *Window) Size() (width, height float64) {
	mainthread.Call(func() {
		wi, hi := w.window.GetSize()
		width = float64(wi)
		height = float64(hi)
	})
	return width, height
}

// Show makes a window visible if it was hidden.
func (w *Window) Show() {
	mainthread.Call(func() {
		w.window.Show()
	})
}

// Hide hides a window if it was visible.
func (w *Window) Hide() {
	mainthread.Call(func() {
		w.window.Hide()
	})
}

// SetFullscreen sets a window fullscreen on a given monitor. If the monitor is nil, the window
// will be resored to windowed instead.
//
// Note, that there is nothing about the resolution of the fullscreen window. The window is
// automatically set to the monitor's resolution. If you want a different resolution, you need
// to set it manually with SetSize method.
func (w *Window) SetFullscreen(monitor *Monitor) {
	if w.Monitor() != monitor {
		if monitor == nil {
			mainthread.Call(func() {
				w.window.SetMonitor(
					nil,
					w.restore.xpos,
					w.restore.ypos,
					w.restore.width,
					w.restore.height,
					0,
				)
			})
		} else {
			mainthread.Call(func() {
				w.restore.xpos, w.restore.ypos = w.window.GetPos()
				w.restore.width, w.restore.height = w.window.GetSize()

				width, height := monitor.Size()
				refreshRate := monitor.RefreshRate()
				w.window.SetMonitor(
					monitor.monitor,
					0,
					0,
					int(width),
					int(height),
					int(refreshRate),
				)
			})
		}
	}
}

// IsFullscreen returns true if the window is in the fullscreen mode.
func (w *Window) IsFullscreen() bool {
	return w.Monitor() != nil
}

// Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this
// function returns nil.
func (w *Window) Monitor() *Monitor {
	monitor := mainthread.CallVal(func() interface{} {
		return w.window.GetMonitor()
	}).(*glfw.Monitor)
	if monitor == nil {
		return nil
	}
	return &Monitor{
		monitor: monitor,
	}
}

// Focus brings a window to the front and sets input focus.
func (w *Window) Focus() {
	mainthread.Call(func() {
		w.window.Focus()
	})
}

// Focused returns true if a window has input focus.
func (w *Window) Focused() bool {
	return mainthread.CallVal(func() interface{} {
		return w.window.GetAttrib(glfw.Focused) == glfw.True
	}).(bool)
}

// Maximize puts a windowed window to a maximized state.
func (w *Window) Maximize() {
	mainthread.Call(func() {
		w.window.Maximize()
	})
}

// Restore restores a windowed window from a maximized state.
func (w *Window) Restore() {
	mainthread.Call(func() {
		w.window.Restore()
	})
}

// Note: must be called inside the main thread.
func (w *Window) begin() {
	if currentWindow != w {
		w.window.MakeContextCurrent()
		pixelgl.Init()
		currentWindow = w
	}
}

// Note: must be called inside the main thread.
func (w *Window) end() {
	// nothing really
}

// MakeTriangles generates a specialized copy of the supplied triangles that will draw onto this
// Window.
//
// Window supports TrianglesPosition, TrianglesColor and TrianglesTexture.
func (w *Window) MakeTriangles(t Triangles) Triangles {
	return w.canvas.MakeTriangles(t)
}

// SetPicture sets a Picture that will be used in subsequent drawings onto the window.
func (w *Window) SetPicture(p *Picture) {
	w.canvas.SetPicture(p)
}

// SetTransform sets a global transformation matrix for the Window.
//
// Transforms are applied right-to-left.
func (w *Window) SetTransform(t ...Transform) {
	w.canvas.SetTransform(t...)
}

// SetMaskColor sets a global mask color for the Window.
func (w *Window) SetMaskColor(c color.Color) {
	w.canvas.SetMaskColor(c)
}

const (
	windowPositionVec2 = iota
	windowTextureVec2
)

var windowVertexFormat = pixelgl.AttrFormat{
	windowPositionVec2: {Name: "position", Type: pixelgl.Vec2},
	windowTextureVec2:  {Name: "texture", Type: pixelgl.Vec2},
}

var windowUniformFormat = pixelgl.AttrFormat{}

var windowVertexShader = `
#version 330 core

in vec2 position;
in vec2 texture;

out vec2 Texture;

void main() {
	gl_Position = vec4(position, 0.0, 1.0);
	Texture = texture;
}
`

var windowFragmentShader = `
#version 330 core

in vec2 Texture;

out vec4 color;

uniform sampler2D tex;

void main() {
	color = texture(tex, Texture);
}
`
<commit_msg>fix window resizing<commit_after>package pixel

import (
	"image/color"

	"runtime"

	"github.com/faiface/mainthread"
	"github.com/faiface/pixel/pixelgl"
	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/pkg/errors"
)

// WindowConfig is a structure for specifying all possible properties of a window. Properties are
// chosen in such a way, that you usually only need to set a few of them - defaults (zeros) should
// usually be sensible.
//
// Note that you always need to set the width and the height of a window.
type WindowConfig struct {
	// Title at the top of a window.
	Title string

	// Width of a window in pixels.
	Width float64

	// Height of a window in pixels.
	Height float64

	// If set to nil, a window will be windowed. Otherwise it will be fullscreen on the
	// specified monitor.
	Fullscreen *Monitor

	// Whether a window is resizable.
	Resizable bool

	// If set to true, the window will be initially invisible.
	Hidden bool

	// Undecorated window ommits the borders and decorations (close button, etc.).
	Undecorated bool

	// If set to true, a window will not get focused upon showing up.
	Unfocused bool

	// Whether a window is maximized.
	Maximized bool

	// VSync (vertical synchronization) synchronizes window's framerate with the framerate
	// of the monitor.
	VSync bool

	// Number of samples for multi-sample anti-aliasing (edge-smoothing).  Usual values
	// are 0, 2, 4, 8 (powers of 2 and not much more than this).
	MSAASamples int
}

// Window is a window handler. Use this type to manipulate a window (input, drawing, ...).
type Window struct {
	enabled bool
	window  *glfw.Window
	config  WindowConfig

	canvas   *Canvas
	canvasVs *pixelgl.VertexSlice
	shader   *pixelgl.Shader

	// need to save these to correctly restore a fullscreen window
	restore struct {
		xpos, ypos, width, height int
	}

	prevInp, tempInp, currInp struct {
		buttons [KeyLast + 1]bool
		scroll  Vec
	}
}

var currentWindow *Window

// NewWindow creates a new window with it's properties specified in the provided config.
//
// If window creation fails, an error is returned.
func NewWindow(config WindowConfig) (*Window, error) {
	bool2int := map[bool]int{
		true:  glfw.True,
		false: glfw.False,
	}

	w := &Window{config: config}

	err := mainthread.CallErr(func() error {
		err := glfw.Init()
		if err != nil {
			return err
		}

		glfw.WindowHint(glfw.ContextVersionMajor, 3)
		glfw.WindowHint(glfw.ContextVersionMinor, 3)
		glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
		glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

		glfw.WindowHint(glfw.Resizable, bool2int[config.Resizable])
		glfw.WindowHint(glfw.Visible, bool2int[!config.Hidden])
		glfw.WindowHint(glfw.Decorated, bool2int[!config.Undecorated])
		glfw.WindowHint(glfw.Focused, bool2int[!config.Unfocused])
		glfw.WindowHint(glfw.Maximized, bool2int[config.Maximized])
		glfw.WindowHint(glfw.Samples, config.MSAASamples)

		var share *glfw.Window
		if currentWindow != nil {
			share = currentWindow.window
		}
		w.window, err = glfw.CreateWindow(
			int(config.Width),
			int(config.Height),
			config.Title,
			nil,
			share,
		)
		if err != nil {
			return err
		}

		// enter the OpenGL context
		w.begin()
		w.end()

		w.shader, err = pixelgl.NewShader(
			windowVertexFormat,
			windowUniformFormat,
			windowVertexShader,
			windowFragmentShader,
		)
		if err != nil {
			return err
		}

		w.canvasVs = pixelgl.MakeVertexSlice(w.shader, 6, 6)
		w.canvasVs.Begin()
		w.canvasVs.SetVertexData([]float32{
			-1, -1, 0, 0,
			1, -1, 1, 0,
			1, 1, 1, 1,
			-1, -1, 0, 0,
			1, 1, 1, 1,
			-1, 1, 0, 1,
		})
		w.canvasVs.End()

		return nil
	})
	if err != nil {
		return nil, errors.Wrap(err, "creating window failed")
	}

	w.initInput()
	w.SetFullscreen(config.Fullscreen)

	w.canvas = NewCanvas(config.Width, config.Height, false)
	w.Update()

	runtime.SetFinalizer(w, (*Window).Destroy)

	return w, nil
}

// Destroy destroys a window. The window can't be used any further.
func (w *Window) Destroy() {
	mainthread.Call(func() {
		w.window.Destroy()
	})
}

// Clear clears the window with a color.
func (w *Window) Clear(c color.Color) {
	w.canvas.Clear(c)
}

// Update swaps buffers and polls events.
func (w *Window) Update() {
	w.canvas.SetSize(w.Size())

	mainthread.Call(func() {
		w.begin()

		pixelgl.Clear(0, 0, 0, 0)
		w.shader.Begin()
		w.canvas.f.Texture().Begin()
		w.canvasVs.Begin()
		w.canvasVs.Draw()
		w.canvasVs.End()
		w.canvas.f.Texture().End()
		w.shader.End()

		if w.config.VSync {
			glfw.SwapInterval(1)
		}
		w.window.SwapBuffers()
		w.end()
	})

	w.updateInput()
}

// SetClosed sets the closed flag of a window.
//
// This is usefull when overriding the user's attempt to close a window, or just to close a
// window from within a program.
func (w *Window) SetClosed(closed bool) {
	mainthread.Call(func() {
		w.window.SetShouldClose(closed)
	})
}

// Closed returns the closed flag of a window, which reports whether the window should be closed.
//
// The closed flag is automatically set when a user attempts to close a window.
func (w *Window) Closed() bool {
	return mainthread.CallVal(func() interface{} {
		return w.window.ShouldClose()
	}).(bool)
}

// SetTitle changes the title of a window.
func (w *Window) SetTitle(title string) {
	mainthread.Call(func() {
		w.window.SetTitle(title)
	})
}

// SetSize resizes a window to the specified size in pixels.  In case of a fullscreen window,
// it changes the resolution of that window.
func (w *Window) SetSize(width, height float64) {
	mainthread.Call(func() {
		w.window.SetSize(int(width), int(height))
	})
}

// Size returns the size of the client area of a window (the part you can draw on).
func (w *Window) Size() (width, height float64) {
	mainthread.Call(func() {
		wi, hi := w.window.GetSize()
		width = float64(wi)
		height = float64(hi)
	})
	return width, height
}

// Show makes a window visible if it was hidden.
func (w *Window) Show() {
	mainthread.Call(func() {
		w.window.Show()
	})
}

// Hide hides a window if it was visible.
func (w *Window) Hide() {
	mainthread.Call(func() {
		w.window.Hide()
	})
}

// SetFullscreen sets a window fullscreen on a given monitor. If the monitor is nil, the window
// will be resored to windowed instead.
//
// Note, that there is nothing about the resolution of the fullscreen window. The window is
// automatically set to the monitor's resolution. If you want a different resolution, you need
// to set it manually with SetSize method.
func (w *Window) SetFullscreen(monitor *Monitor) {
	if w.Monitor() != monitor {
		if monitor == nil {
			mainthread.Call(func() {
				w.window.SetMonitor(
					nil,
					w.restore.xpos,
					w.restore.ypos,
					w.restore.width,
					w.restore.height,
					0,
				)
			})
		} else {
			mainthread.Call(func() {
				w.restore.xpos, w.restore.ypos = w.window.GetPos()
				w.restore.width, w.restore.height = w.window.GetSize()

				width, height := monitor.Size()
				refreshRate := monitor.RefreshRate()
				w.window.SetMonitor(
					monitor.monitor,
					0,
					0,
					int(width),
					int(height),
					int(refreshRate),
				)
			})
		}
	}
}

// IsFullscreen returns true if the window is in the fullscreen mode.
func (w *Window) IsFullscreen() bool {
	return w.Monitor() != nil
}

// Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this
// function returns nil.
func (w *Window) Monitor() *Monitor {
	monitor := mainthread.CallVal(func() interface{} {
		return w.window.GetMonitor()
	}).(*glfw.Monitor)
	if monitor == nil {
		return nil
	}
	return &Monitor{
		monitor: monitor,
	}
}

// Focus brings a window to the front and sets input focus.
func (w *Window) Focus() {
	mainthread.Call(func() {
		w.window.Focus()
	})
}

// Focused returns true if a window has input focus.
func (w *Window) Focused() bool {
	return mainthread.CallVal(func() interface{} {
		return w.window.GetAttrib(glfw.Focused) == glfw.True
	}).(bool)
}

// Maximize puts a windowed window to a maximized state.
func (w *Window) Maximize() {
	mainthread.Call(func() {
		w.window.Maximize()
	})
}

// Restore restores a windowed window from a maximized state.
func (w *Window) Restore() {
	mainthread.Call(func() {
		w.window.Restore()
	})
}

// Note: must be called inside the main thread.
func (w *Window) begin() {
	if currentWindow != w {
		w.window.MakeContextCurrent()
		pixelgl.Init()
		currentWindow = w
	}
}

// Note: must be called inside the main thread.
func (w *Window) end() {
	// nothing really
}

// MakeTriangles generates a specialized copy of the supplied triangles that will draw onto this
// Window.
//
// Window supports TrianglesPosition, TrianglesColor and TrianglesTexture.
func (w *Window) MakeTriangles(t Triangles) Triangles {
	return w.canvas.MakeTriangles(t)
}

// SetPicture sets a Picture that will be used in subsequent drawings onto the window.
func (w *Window) SetPicture(p *Picture) {
	w.canvas.SetPicture(p)
}

// SetTransform sets a global transformation matrix for the Window.
//
// Transforms are applied right-to-left.
func (w *Window) SetTransform(t ...Transform) {
	w.canvas.SetTransform(t...)
}

// SetMaskColor sets a global mask color for the Window.
func (w *Window) SetMaskColor(c color.Color) {
	w.canvas.SetMaskColor(c)
}

const (
	windowPositionVec2 = iota
	windowTextureVec2
)

var windowVertexFormat = pixelgl.AttrFormat{
	windowPositionVec2: {Name: "position", Type: pixelgl.Vec2},
	windowTextureVec2:  {Name: "texture", Type: pixelgl.Vec2},
}

var windowUniformFormat = pixelgl.AttrFormat{}

var windowVertexShader = `
#version 330 core

in vec2 position;
in vec2 texture;

out vec2 Texture;

void main() {
	gl_Position = vec4(position, 0.0, 1.0);
	Texture = texture;
}
`

var windowFragmentShader = `
#version 330 core

in vec2 Texture;

out vec4 color;

uniform sampler2D tex;

void main() {
	color = texture(tex, Texture);
}
`
<|endoftext|>


<commit_before>/* Copyright 2017 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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 interpreter

import (
	"encoding/json"
	"fmt"

	"CodeCity/server/interpreter/data"
)

// A NativeImpl encapsulates information about a Go-language function
// which can be used as the implementation of a JS function.
type NativeImpl struct {
	// Tag is a string used to refer to the NativeImpl when creating
	// the corresponding JS function object (and when serializing
	// interpreter state to disk).  It must be unique amongst
	// (registered) NativeImpls, and can be any arbitrary value but is
	// normally the same as the Javascript name of the function this
	// NativeImpl implements (for example:
	// "Object.prototype.toString")
	Tag string

	// Impl is the Go language function that is the actual
	// implementation of a native function.  It takes a pointer to the
	// enclosing interpreter, a 'this' value, and a slice arguments.
	//
	// It returns a JS value (ret) and boolean flag (throw).  If throw
	// is true it indicates that ret is a thrown exception rather than
	// a normal return value.
	//
	// Note that this function is (mostly) responsible for checking
	// that the arguments are correct in number and type.
	Impl func(intrp *Interpreter, this data.Value, args []data.Value) (ret data.Value, throw bool)

	// Length specifies the value to be used for the associated (JS)
	// function object's .length property; this is neither a minimum
	// nor maximum number of parameters, but a somewhat arbitrary
	// 'usual' number of parameters as specified by the ES5.1 spec.
	//
	// If length > 0, the []args parameter to impl will be padded out
	// to this length (by adding JS undefined values as required)
	// before impl is called.
	Length int
}

// A nativeFunc is an object that when called / applied invokes a
// Go-language function.
//
// In order to be serializable using flatpack and encoding/json (which
// cannot serialise function values) it does not contain the
// NativeImpl directly but rather an index into the package variable
// nativeImpls.
type nativeFunc struct {
	data.Object
	idx natImplIdx
}

// *nativeFunc must satisfy function (and in turn data.Object):
var _ function = (*nativeFunc)(nil)

func (nativeFunc) Typeof() string {
	return "function"
}

// Class always returns "Function" for function objects.
func (nativeFunc) Class() string {
	return "Function"
}

// ToString is repeated here to catch the changed definition of Class.
//
// BUG(cpcallen): as with object.ToString, nativeFunc.ToString should
// call a user-code toString() method if present.
func (nf nativeFunc) ToString() data.String {
	return data.String("[object " + nf.Class() + "]")
}

// call prepares the arguments and then calls the NativeImpl.impl,
// after which it converts the return values into a cval which it
// sends to the parent of the call expression that initiated the call.
func (nf nativeFunc) call(st *stateCallExpression, intrp *Interpreter, this data.Value, args []data.Value) (state, *cval) {
	ni := nativeImpls[nf.idx]
	// Extend args list to length:
	for len(args) < ni.Length {
		args = append(args, data.Undefined{})
	}
	r, throw := ni.Impl(intrp, this, args)
	if throw {
		return st.parent, &cval{THROW, r, ""}
	}
	return st.parent, pval(r)
}

// newNativeFunc returns a new native function object with the
// specified owner, prototype, tag and length.
//
// The owner and proto params are as for data.NewObject().
//
// The tag param specifies which nativeImpl (from nativeImpls) should
// be used; this will also be used when serialising; a deserialised
// NativeFunc will be reconnected to a nativeImpl with the same name.
func newNativeFunc(owner *data.Owner, proto data.Object, tag string) *nativeFunc {
	idx, ok := nativeImplsByTag[tag]
	if !ok {
		panic(fmt.Errorf("No NativeImpl tagged '%s' registered", tag))
	}
	o := data.NewObject(owner, proto)
	// FIXME: make not writeable? (check spec for this an other attributes)
	err := o.Set("length", data.Number(nativeImpls[idx].Length))
	if err != nil {
		panic(err)
	}
	return &nativeFunc{
		Object: o,
		idx:    idx,
	}
}

// nativeImpls is a table mapping nativeFunc.idx values to NativeImpl
// values.
var nativeImpls []NativeImpl

// nativeImplsByTag is a map indexing nativeImpls by tag value.
var nativeImplsByTag = make(map[string]natImplIdx)

// registerNativeImpl adds its argument to nativeImpls (and indexes it
// by tag in nativeImplsByTag).
func registerNativeImpl(ni NativeImpl) {
	if _, exists := nativeImplsByTag[ni.Tag]; exists {
		panic(fmt.Errorf("A NativeImpl tagged '%s' already registered", ni.Tag))
	}
	nativeImplsByTag[ni.Tag] = natImplIdx(len(nativeImpls))
	nativeImpls = append(nativeImpls, ni)
}

// natImplIdx is just an integer index into nativeImpls which is
// serialised in a special way: using the corresponding tag value.
type natImplIdx int

// natImplIdx must satisfy json.Marshaler and json.Unmarshaler.
var _ json.Marshaler = natImplIdx(0)
var _ json.Unmarshaler = &[]natImplIdx{0}[0]

func (idx natImplIdx) MarshalJSON() ([]byte, error) {
	if n := len(nativeImpls); int(idx) >= n {
		return nil, fmt.Errorf("natImplIdx %d out of range [0:%d]", idx, n)
	}
	return json.Marshal(nativeImpls[idx].Tag)
}

func (idx *natImplIdx) UnmarshalJSON(data []byte) error {
	var tag string
	err := json.Unmarshal(data, &tag)
	if err != nil {
		return err
	}
	var ok bool
	*idx, ok = nativeImplsByTag[tag]
	if !ok {
		return fmt.Errorf("No NativeImpl tagged '%s' registered", tag)
	}
	return nil
}
<commit_msg>'err' -> 'nErr' when it's actually a NativeError<commit_after>/* Copyright 2017 Google Inc.
 * https://github.com/NeilFraser/CodeCity
 *
 * 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 interpreter

import (
	"encoding/json"
	"fmt"

	"CodeCity/server/interpreter/data"
)

// A NativeImpl encapsulates information about a Go-language function
// which can be used as the implementation of a JS function.
type NativeImpl struct {
	// Tag is a string used to refer to the NativeImpl when creating
	// the corresponding JS function object (and when serializing
	// interpreter state to disk).  It must be unique amongst
	// (registered) NativeImpls, and can be any arbitrary value but is
	// normally the same as the Javascript name of the function this
	// NativeImpl implements (for example:
	// "Object.prototype.toString")
	Tag string

	// Impl is the Go language function that is the actual
	// implementation of a native function.  It takes a pointer to the
	// enclosing interpreter, a 'this' value, and a slice arguments.
	//
	// It returns a JS value (ret) and boolean flag (throw).  If throw
	// is true it indicates that ret is a thrown exception rather than
	// a normal return value.
	//
	// Note that this function is (mostly) responsible for checking
	// that the arguments are correct in number and type.
	Impl func(intrp *Interpreter, this data.Value, args []data.Value) (ret data.Value, throw bool)

	// Length specifies the value to be used for the associated (JS)
	// function object's .length property; this is neither a minimum
	// nor maximum number of parameters, but a somewhat arbitrary
	// 'usual' number of parameters as specified by the ES5.1 spec.
	//
	// If length > 0, the []args parameter to impl will be padded out
	// to this length (by adding JS undefined values as required)
	// before impl is called.
	Length int
}

// A nativeFunc is an object that when called / applied invokes a
// Go-language function.
//
// In order to be serializable using flatpack and encoding/json (which
// cannot serialise function values) it does not contain the
// NativeImpl directly but rather an index into the package variable
// nativeImpls.
type nativeFunc struct {
	data.Object
	idx natImplIdx
}

// *nativeFunc must satisfy function (and in turn data.Object):
var _ function = (*nativeFunc)(nil)

func (nativeFunc) Typeof() string {
	return "function"
}

// Class always returns "Function" for function objects.
func (nativeFunc) Class() string {
	return "Function"
}

// ToString is repeated here to catch the changed definition of Class.
//
// BUG(cpcallen): as with object.ToString, nativeFunc.ToString should
// call a user-code toString() method if present.
func (nf nativeFunc) ToString() data.String {
	return data.String("[object " + nf.Class() + "]")
}

// call prepares the arguments and then calls the NativeImpl.impl,
// after which it converts the return values into a cval which it
// sends to the parent of the call expression that initiated the call.
func (nf nativeFunc) call(st *stateCallExpression, intrp *Interpreter, this data.Value, args []data.Value) (state, *cval) {
	ni := nativeImpls[nf.idx]
	// Extend args list to length:
	for len(args) < ni.Length {
		args = append(args, data.Undefined{})
	}
	r, throw := ni.Impl(intrp, this, args)
	if throw {
		return st.parent, &cval{THROW, r, ""}
	}
	return st.parent, pval(r)
}

// newNativeFunc returns a new native function object with the
// specified owner, prototype, tag and length.
//
// The owner and proto params are as for data.NewObject().
//
// The tag param specifies which nativeImpl (from nativeImpls) should
// be used; this will also be used when serialising; a deserialised
// NativeFunc will be reconnected to a nativeImpl with the same name.
func newNativeFunc(owner *data.Owner, proto data.Object, tag string) *nativeFunc {
	idx, ok := nativeImplsByTag[tag]
	if !ok {
		panic(fmt.Errorf("No NativeImpl tagged '%s' registered", tag))
	}
	o := data.NewObject(owner, proto)
	// FIXME: make not writeable? (check spec for this an other attributes)
	nErr := o.Set("length", data.Number(nativeImpls[idx].Length))
	if nErr != nil {
		panic(nErr)
	}
	return &nativeFunc{
		Object: o,
		idx:    idx,
	}
}

// nativeImpls is a table mapping nativeFunc.idx values to NativeImpl
// values.
var nativeImpls []NativeImpl

// nativeImplsByTag is a map indexing nativeImpls by tag value.
var nativeImplsByTag = make(map[string]natImplIdx)

// registerNativeImpl adds its argument to nativeImpls (and indexes it
// by tag in nativeImplsByTag).
func registerNativeImpl(ni NativeImpl) {
	if _, exists := nativeImplsByTag[ni.Tag]; exists {
		panic(fmt.Errorf("A NativeImpl tagged '%s' already registered", ni.Tag))
	}
	nativeImplsByTag[ni.Tag] = natImplIdx(len(nativeImpls))
	nativeImpls = append(nativeImpls, ni)
}

// natImplIdx is just an integer index into nativeImpls which is
// serialised in a special way: using the corresponding tag value.
type natImplIdx int

// natImplIdx must satisfy json.Marshaler and json.Unmarshaler.
var _ json.Marshaler = natImplIdx(0)
var _ json.Unmarshaler = &[]natImplIdx{0}[0]

func (idx natImplIdx) MarshalJSON() ([]byte, error) {
	if n := len(nativeImpls); int(idx) >= n {
		return nil, fmt.Errorf("natImplIdx %d out of range [0:%d]", idx, n)
	}
	return json.Marshal(nativeImpls[idx].Tag)
}

func (idx *natImplIdx) UnmarshalJSON(data []byte) error {
	var tag string
	err := json.Unmarshal(data, &tag)
	if err != nil {
		return err
	}
	var ok bool
	*idx, ok = nativeImplsByTag[tag]
	if !ok {
		return fmt.Errorf("No NativeImpl tagged '%s' registered", tag)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"syscall"
	"time"
)

func main() {

	var token = flag.String("token", "400", "The Pollendina provisioning token.")
	var endpoint = flag.String("host", ":33004", "Default port for Pollendina CA.")
	var cn = flag.String("cn", "Tommy", "Default common name.")
	var caFile = flag.String("cacert", "", "File path for a custom CA certificate.")
	var keyFileOut = flag.String("keyout", "/etc/secret/client-key.pem", "The locattion where the client private key will be written.")
	var crtFileOut = flag.String("certout", "/etc/secret/client-cert.pem", "The locattion where the client certificate will be written.")
	var keysize = flag.Int("size", 4096, "The size of the private key e.g. 1024, 2048, 4096 (default).")
	flag.Parse()

	// Load the CA certificate from the specified file
	var pool *x509.CertPool
	if len(*caFile) > 0 {
		cacert, err := ioutil.ReadFile(*caFile)
		if err != nil {
			log.Fatal(err)
		}
		pool = x509.NewCertPool()
		pool.AppendCertsFromPEM(cacert)
	}

	// Generate the private key
	pkTimeStart := time.Now()
	key, err := rsa.GenerateKey(rand.Reader, *keysize)
	log.Printf("[TIMER] [%s] Generated PK\n", time.Since(pkTimeStart))
	if err != nil {
		log.Fatal("Unable to generate a private key.", err)
		os.Exit(1)
	}
	err = installKey(key, *keyFileOut)
	if err != nil {
		log.Fatal("Unable to install the private key.", err)
		os.Exit(4)
	}

	// Generate a CSR
	t := x509.CertificateRequest{
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
			CommonName:   *cn,
		},
		SignatureAlgorithm: x509.SHA256WithRSA,
	}
	csrTimeStart := time.Now()
	csr, err := x509.CreateCertificateRequest(rand.Reader, &t, key)
	log.Printf("[TIMER] [%s] Generated CSR\n", time.Since(csrTimeStart))
	if err != nil {
		log.Fatal("Unable to generate a CSR.", err)
		os.Exit(2)
	}

	// PEM encode the CSR
	pemCSR := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csr})

	// Fetch a signed certificate
	crt, err := shipCSR(pemCSR, token, endpoint, pool)
	if err != nil {
		log.Fatal("Unable to retrieve a signed CRT.", err)
		os.Exit(3)
	}

	err = installCrt(crt, *crtFileOut)
	if err != nil {
		log.Fatal("Unable to install the CRT.", err)
		os.Exit(5)
	}
}

func shipCSR(csr []byte, token *string, endpoint *string, pool *x509.CertPool) ([]byte, error) {
	if csr == nil {
		return nil, errors.New("csr is nil")
	}
	if token == nil {
		return nil, errors.New("token is nil")
	}
	if endpoint == nil {
		return nil, errors.New("endpoint is nil")
	}

	// Create an HTTPS client. If the pool has not been set, then use the default
	// CA trust store, otherwise add the configured pool into the tls config.
	var client *http.Client
	if pool != nil {
		tr := &http.Transport{
			TLSClientConfig:    &tls.Config{RootCAs: pool},
			DisableCompression: true,
		}
		client = &http.Client{
			Transport: tr,
		}
	} else {
		client = &http.Client{}
	}

	// Execute a PUT request to upload the provided CSR
	//req, err := http.NewRequest("PUT", fmt.Sprintf("https://%s/v1/sign/%s", *endpoint, *token), bytes.NewReader(csr))
	req, err := http.NewRequest("PUT", fmt.Sprintf("http://%s/v1/sign/%s", *endpoint, *token), bytes.NewReader(csr))
	if err != nil {
		log.Fatal("Unable to form the HTTPS request.", err)
		return nil, err
	}
	signTimeStart := time.Now()
	res, err := client.Do(req)
	log.Printf("[TIMER] [%s] Uploaded CSR and retrieved CRT.", time.Since(signTimeStart))
	if err != nil {
		log.Fatal("A problem occurred during communication with the Pollendina CA.", err)
		return nil, err
	}

	// TODO: validation of response content type and content length is within some reasonable limit

	// read the response body and get it into certificate form
	var rawCert []byte
	rawCert = make([]byte, req.ContentLength, req.ContentLength)
	_, err = res.Body.Read(rawCert)
	if err != nil {
		log.Fatal("A problem occurred while reading the certificate from the Pollendina CA.", err)
		return nil, err
	}
	// TODO: validate that the number of bytes read matches the reported content length

	// parse the CRT and validate form
	//_, err = x509.ParseCertificate(rawCert)
	// TODO: assign the cert to a variable and actually validate some of the fields
	//if err != nil {
	//	log.Fatal("A problem occurred while validating the generated certificate.", err)
	//	return nil, err
	//}
	defer res.Body.Close()
	return rawCert, nil
}

// TODO: install functions should be defined on an interface. Composed implementations
// would persist to various stores. This implementation will use mounted tmpfs, but others
// might include some vault.
func installKey(key *rsa.PrivateKey, location string) error {

	pkDirPrepTimeStart := time.Now()
	dir := path.Dir(location)
	// Create destination directory
	if err := syscall.Mkdir(dir, 0600); err != nil {
		if err != syscall.EEXIST {
			return err
		}
		// The directory already exists
		log.Printf("The key destination directory already exists.")
	}

	// with CAP_SYS_ADMIN we could create a tmpfs mount
	if err := syscall.Mount("tmpfs", dir, "tmpfs", 0600, "size=1M"); err != nil {
		log.Printf("Unable to create tmpfs mount. Do you have CAP_SYS_ADMIN? Error: %s", err)
	}
	log.Printf("[TIMER] [%s] Prepared PK storage\n", time.Since(pkDirPrepTimeStart))

	keyOut, err := os.OpenFile(location, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	defer keyOut.Close()

	if err != nil {
		log.Print("failed to open key.pem for writing:", err)
		return nil
	}
	pkFileWriteTimeStart := time.Now()
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
	log.Printf("[TIMER] [%s] Wrote PK\n", time.Since(pkFileWriteTimeStart))
	return nil
}

func installCrt(crt []byte, location string) error {

	crtFileWriteTimeStart := time.Now()
	err := ioutil.WriteFile(location, crt, 0600)
	log.Printf("[TIMER] [%s] Wrote CRT\n", time.Since(crtFileWriteTimeStart))
	return err
}
<commit_msg>Previously committed and Closes #2, Closes #3.<commit_after>/*
*  Pollendina Native Client
*  Author: Jeff Nickoloff
*/
package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"syscall"
	"time"
)

func main() {

	var token = flag.String("token", "400", "The Pollendina provisioning token.")
	var endpoint = flag.String("host", ":33004", "Default port for Pollendina CA.")
	var cn = flag.String("cn", "Tommy", "Default common name.")
	var caFile = flag.String("cacert", "", "File path for a custom CA certificate.")
	var keyFileOut = flag.String("keyout", "/etc/secret/client-key.pem", "The locattion where the client private key will be written.")
	var crtFileOut = flag.String("certout", "/etc/secret/client-cert.pem", "The locattion where the client certificate will be written.")
	var keysize = flag.Int("size", 4096, "The size of the private key e.g. 1024, 2048, 4096 (default).")
	flag.Parse()

	// Load the CA certificate from the specified file
	var pool *x509.CertPool
	if len(*caFile) > 0 {
		cacert, err := ioutil.ReadFile(*caFile)
		if err != nil {
			log.Fatal(err)
		}
		pool = x509.NewCertPool()
		pool.AppendCertsFromPEM(cacert)
	}

	// Generate the private key
	pkTimeStart := time.Now()
	key, err := rsa.GenerateKey(rand.Reader, *keysize)
	log.Printf("[TIMER] [%s] Generated PK\n", time.Since(pkTimeStart))
	if err != nil {
		log.Fatal("Unable to generate a private key.", err)
		os.Exit(1)
	}
	err = installKey(key, *keyFileOut)
	if err != nil {
		log.Fatal("Unable to install the private key.", err)
		os.Exit(4)
	}

	// Generate a CSR
	t := x509.CertificateRequest{
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
			CommonName:   *cn,
		},
		SignatureAlgorithm: x509.SHA256WithRSA,
	}
	csrTimeStart := time.Now()
	csr, err := x509.CreateCertificateRequest(rand.Reader, &t, key)
	log.Printf("[TIMER] [%s] Generated CSR\n", time.Since(csrTimeStart))
	if err != nil {
		log.Fatal("Unable to generate a CSR.", err)
		os.Exit(2)
	}

	// PEM encode the CSR
	pemCSR := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: csr})

	// Fetch a signed certificate
	crt, err := shipCSR(pemCSR, token, endpoint, pool)
	if err != nil {
		log.Fatal("Unable to retrieve a signed CRT.", err)
		os.Exit(3)
	}

	err = installCrt(crt, *crtFileOut)
	if err != nil {
		log.Fatal("Unable to install the CRT.", err)
		os.Exit(5)
	}
}

func shipCSR(csr []byte, token *string, endpoint *string, pool *x509.CertPool) ([]byte, error) {
	if csr == nil {
		return nil, errors.New("csr is nil")
	}
	if token == nil {
		return nil, errors.New("token is nil")
	}
	if endpoint == nil {
		return nil, errors.New("endpoint is nil")
	}

	// Create an HTTPS client. If the pool has not been set, then use the default
	// CA trust store, otherwise add the configured pool into the tls config.
	var client *http.Client
	if pool != nil {
		tr := &http.Transport{
			TLSClientConfig:    &tls.Config{RootCAs: pool},
			DisableCompression: true,
		}
		client = &http.Client{
			Transport: tr,
		}
	} else {
		client = &http.Client{}
	}

	// Execute a PUT request to upload the provided CSR
	//req, err := http.NewRequest("PUT", fmt.Sprintf("https://%s/v1/sign/%s", *endpoint, *token), bytes.NewReader(csr))
	req, err := http.NewRequest("PUT", fmt.Sprintf("http://%s/v1/sign/%s", *endpoint, *token), bytes.NewReader(csr))
	if err != nil {
		log.Fatal("Unable to form the HTTPS request.", err)
		return nil, err
	}
	signTimeStart := time.Now()
	res, err := client.Do(req)
	log.Printf("[TIMER] [%s] Uploaded CSR and retrieved CRT.", time.Since(signTimeStart))
	if err != nil {
		log.Fatal("A problem occurred during communication with the Pollendina CA.", err)
		return nil, err
	}

	// TODO: validation of response content type and content length is within some reasonable limit

	// read the response body and get it into certificate form
	var rawCert []byte
	rawCert = make([]byte, req.ContentLength, req.ContentLength)
	_, err = res.Body.Read(rawCert)
	if err != nil {
		log.Fatal("A problem occurred while reading the certificate from the Pollendina CA.", err)
		return nil, err
	}
	// TODO: validate that the number of bytes read matches the reported content length

	// parse the CRT and validate form
	//_, err = x509.ParseCertificate(rawCert)
	// TODO: assign the cert to a variable and actually validate some of the fields
	//if err != nil {
	//	log.Fatal("A problem occurred while validating the generated certificate.", err)
	//	return nil, err
	//}
	defer res.Body.Close()
	return rawCert, nil
}

// TODO: install functions should be defined on an interface. Composed implementations
// would persist to various stores. This implementation will use mounted tmpfs, but others
// might include some vault.
func installKey(key *rsa.PrivateKey, location string) error {

	pkDirPrepTimeStart := time.Now()
	dir := path.Dir(location)
	// Create destination directory
	if err := syscall.Mkdir(dir, 0600); err != nil {
		if err != syscall.EEXIST {
			return err
		}
		// The directory already exists
		log.Printf("The key destination directory already exists.")
	}

	// with CAP_SYS_ADMIN we could create a tmpfs mount
	if err := syscall.Mount("tmpfs", dir, "tmpfs", 0600, "size=1M"); err != nil {
		log.Printf("Unable to create tmpfs mount. Do you have CAP_SYS_ADMIN? Error: %s", err)
	}
	log.Printf("[TIMER] [%s] Prepared PK storage\n", time.Since(pkDirPrepTimeStart))

	keyOut, err := os.OpenFile(location, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	defer keyOut.Close()

	if err != nil {
		log.Print("failed to open key.pem for writing:", err)
		return nil
	}
	pkFileWriteTimeStart := time.Now()
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
	log.Printf("[TIMER] [%s] Wrote PK\n", time.Since(pkFileWriteTimeStart))
	return nil
}

func installCrt(crt []byte, location string) error {

	crtFileWriteTimeStart := time.Now()
	err := ioutil.WriteFile(location, crt, 0600)
	log.Printf("[TIMER] [%s] Wrote CRT\n", time.Since(crtFileWriteTimeStart))
	return err
}
<|endoftext|>


<commit_before>// Copyright 2020 Asim Aslam
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Original source: github.com/micro/go-micro/v3/client/grpc/grpc_test.go

package grpc

import (
	"context"
	"net"
	"testing"

	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/errors"
	"github.com/micro/micro/v3/service/registry"
	"github.com/micro/micro/v3/service/registry/memory"
	"github.com/micro/micro/v3/service/router"
	regRouter "github.com/micro/micro/v3/service/router/registry"
	pgrpc "google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

// server is used to implement helloworld.GreeterServer.
type greeterServer struct{}

// SayHello implements helloworld.GreeterServer
func (g *greeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	if in.Name == "Error" {
		return nil, &errors.Error{Id: "1", Code: 99, Detail: "detail"}
	}
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func TestGRPCClient(t *testing.T) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatalf("failed to listen: %v", err)
	}
	defer l.Close()

	s := pgrpc.NewServer()
	pb.RegisterGreeterServer(s, &greeterServer{})

	go s.Serve(l)
	defer s.Stop()

	// create mock registry
	r := memory.NewRegistry()

	// register service
	r.Register(&registry.Service{
		Name:    "helloworld",
		Version: "test",
		Nodes: []*registry.Node{
			{
				Id:      "test-1",
				Address: l.Addr().String(),
				Metadata: map[string]string{
					"protocol": "grpc",
				},
			},
		},
	})

	// create router
	rtr := regRouter.NewRouter(router.Registry(r))

	// create client
	c := NewClient(client.Router(rtr))

	testMethods := []string{
		"/helloworld.Greeter/SayHello",
		"Greeter.SayHello",
	}

	for _, method := range testMethods {
		req := c.NewRequest("helloworld", method, &pb.HelloRequest{
			Name: "John",
		})

		rsp := pb.HelloReply{}

		err = c.Call(context.TODO(), req, &rsp)
		if err != nil {
			t.Fatal(err)
		}

		if rsp.Message != "Hello John" {
			t.Fatalf("Got unexpected response %v", rsp.Message)
		}
	}

	req := c.NewRequest("helloworld", "/helloworld.Greeter/SayHello", &pb.HelloRequest{
		Name: "Error",
	})

	rsp := pb.HelloReply{}

	err = c.Call(context.TODO(), req, &rsp)
	if err == nil {
		t.Fatal("nil error received")
	}

	verr, ok := err.(*errors.Error)
	if !ok {
		t.Fatalf("invalid error received %#+v\n", err)
	}

	if verr.Code != 99 && verr.Id != "1" && verr.Detail != "detail" {
		t.Fatalf("invalid error received %#+v\n", verr)
	}

}
<commit_msg>fix grpc test case to  forward compatible implementations (#1570)<commit_after>// Copyright 2020 Asim Aslam
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Original source: github.com/micro/go-micro/v3/client/grpc/grpc_test.go

package grpc

import (
	"context"
	"net"
	"testing"

	"github.com/micro/micro/v3/service/client"
	"github.com/micro/micro/v3/service/errors"
	"github.com/micro/micro/v3/service/registry"
	"github.com/micro/micro/v3/service/registry/memory"
	"github.com/micro/micro/v3/service/router"
	regRouter "github.com/micro/micro/v3/service/router/registry"
	pgrpc "google.golang.org/grpc"
	pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

// server is used to implement helloworld.GreeterServer.
type greeterServer struct {
	pb.UnimplementedGreeterServer
}

// SayHello implements helloworld.GreeterServer
func (g *greeterServer) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	if in.Name == "Error" {
		return nil, &errors.Error{Id: "1", Code: 99, Detail: "detail"}
	}
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func TestGRPCClient(t *testing.T) {
	l, err := net.Listen("tcp", ":0")
	if err != nil {
		t.Fatalf("failed to listen: %v", err)
	}
	defer l.Close()

	s := pgrpc.NewServer()
	pb.RegisterGreeterServer(s, &greeterServer{})

	go s.Serve(l)
	defer s.Stop()

	// create mock registry
	r := memory.NewRegistry()

	// register service
	r.Register(&registry.Service{
		Name:    "helloworld",
		Version: "test",
		Nodes: []*registry.Node{
			{
				Id:      "test-1",
				Address: l.Addr().String(),
				Metadata: map[string]string{
					"protocol": "grpc",
				},
			},
		},
	})

	// create router
	rtr := regRouter.NewRouter(router.Registry(r))

	// create client
	c := NewClient(client.Router(rtr))

	testMethods := []string{
		"/helloworld.Greeter/SayHello",
		"Greeter.SayHello",
	}

	for _, method := range testMethods {
		req := c.NewRequest("helloworld", method, &pb.HelloRequest{
			Name: "John",
		})

		rsp := pb.HelloReply{}

		err = c.Call(context.TODO(), req, &rsp)
		if err != nil {
			t.Fatal(err)
		}

		if rsp.Message != "Hello John" {
			t.Fatalf("Got unexpected response %v", rsp.Message)
		}
	}

	req := c.NewRequest("helloworld", "/helloworld.Greeter/SayHello", &pb.HelloRequest{
		Name: "Error",
	})

	rsp := pb.HelloReply{}

	err = c.Call(context.TODO(), req, &rsp)
	if err == nil {
		t.Fatal("nil error received")
	}

	verr, ok := err.(*errors.Error)
	if !ok {
		t.Fatalf("invalid error received %#+v\n", err)
	}

	if verr.Code != 99 && verr.Id != "1" && verr.Detail != "detail" {
		t.Fatalf("invalid error received %#+v\n", verr)
	}

}
<|endoftext|>


<commit_before>package controllers

import (
	"fmt"
	"log"
	"net/http"

	"encoding/json"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/api"
	"github.com/nuveo/prest/statements"
)

// GetTables list all (or filter) tables
func GetTables(w http.ResponseWriter, r *http.Request) {
	requestWhere, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	sqlTables := statements.Tables
	if requestWhere != "" {
		sqlTables = fmt.Sprint(
			statements.TablesSelect,
			statements.TablesWhere,
			" AND ",
			requestWhere,
			statements.TablesOrderBy)
	}

	object, err := postgres.Query(sqlTables, values...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// GetTablesByDatabaseAndSchema list all (or filter) tables based on database and schema
func GetTablesByDatabaseAndSchema(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	requestWhere, values, err := postgres.WhereByRequest(r, 3)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	sqlSchemaTables := statements.SchemaTables
	if requestWhere != "" {
		sqlSchemaTables = fmt.Sprint(
			statements.SchemaTablesSelect,
			statements.SchemaTablesWhere,
			" AND ",
			requestWhere,
			statements.SchemaTablesOrderBy)
	}

	page, err := postgres.PaginateIfPossible(r)
	if err != nil {
		http.Error(w, "Paging error", http.StatusBadRequest)
		return
	}

	sqlSchemaTables = fmt.Sprint(sqlSchemaTables, " ", page)

	valuesAux := make([]interface{}, 0)
	valuesAux = append(valuesAux, database)
	valuesAux = append(valuesAux, schema)
	valuesAux = append(valuesAux, values...)

	object, err := postgres.Query(sqlSchemaTables, valuesAux...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// SelectFromTables perform select in database
func SelectFromTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	query := fmt.Sprintf("%s %s.%s.%s", statements.SelectInTable, database, schema, table)
	requestWhere, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	sqlSelect := query
	if requestWhere != "" {
		sqlSelect = fmt.Sprint(
			query,
			" WHERE ",
			requestWhere)
	}

	page, err := postgres.PaginateIfPossible(r)
	if err != nil {
		http.Error(w, "Paging error", http.StatusBadRequest)
		return
	}
	sqlSelect = fmt.Sprint(sqlSelect, " ", page)

	object, err := postgres.Query(sqlSelect, values...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// InsertInTables perform insert in specific table
func InsertInTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}
	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	object, err := postgres.Insert(database, schema, table, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// DeleteFromTable perform delete sql
func DeleteFromTable(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	where, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	object, err := postgres.Delete(database, schema, table, where, values)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// UpdateTable perform update table
func UpdateTable(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	where, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	object, err := postgres.Update(database, schema, table, where, values, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}
<commit_msg>add return to http.Error<commit_after>package controllers

import (
	"fmt"
	"log"
	"net/http"

	"encoding/json"

	"github.com/gorilla/mux"
	"github.com/nuveo/prest/adapters/postgres"
	"github.com/nuveo/prest/api"
	"github.com/nuveo/prest/statements"
)

// GetTables list all (or filter) tables
func GetTables(w http.ResponseWriter, r *http.Request) {
	requestWhere, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	sqlTables := statements.Tables
	if requestWhere != "" {
		sqlTables = fmt.Sprint(
			statements.TablesSelect,
			statements.TablesWhere,
			" AND ",
			requestWhere,
			statements.TablesOrderBy)
	}

	object, err := postgres.Query(sqlTables, values...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// GetTablesByDatabaseAndSchema list all (or filter) tables based on database and schema
func GetTablesByDatabaseAndSchema(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	requestWhere, values, err := postgres.WhereByRequest(r, 3)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	sqlSchemaTables := statements.SchemaTables
	if requestWhere != "" {
		sqlSchemaTables = fmt.Sprint(
			statements.SchemaTablesSelect,
			statements.SchemaTablesWhere,
			" AND ",
			requestWhere,
			statements.SchemaTablesOrderBy)
	}

	page, err := postgres.PaginateIfPossible(r)
	if err != nil {
		http.Error(w, "Paging error", http.StatusBadRequest)
		return
	}

	sqlSchemaTables = fmt.Sprint(sqlSchemaTables, " ", page)

	valuesAux := make([]interface{}, 0)
	valuesAux = append(valuesAux, database)
	valuesAux = append(valuesAux, schema)
	valuesAux = append(valuesAux, values...)

	object, err := postgres.Query(sqlSchemaTables, valuesAux...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// SelectFromTables perform select in database
func SelectFromTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	query := fmt.Sprintf("%s %s.%s.%s", statements.SelectInTable, database, schema, table)
	requestWhere, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	sqlSelect := query
	if requestWhere != "" {
		sqlSelect = fmt.Sprint(
			query,
			" WHERE ",
			requestWhere)
	}

	page, err := postgres.PaginateIfPossible(r)
	if err != nil {
		http.Error(w, "Paging error", http.StatusBadRequest)
		return
	}
	sqlSelect = fmt.Sprint(sqlSelect, " ", page)

	object, err := postgres.Query(sqlSelect, values...)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// InsertInTables perform insert in specific table
func InsertInTables(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}
	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	object, err := postgres.Insert(database, schema, table, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// DeleteFromTable perform delete sql
func DeleteFromTable(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	where, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	object, err := postgres.Delete(database, schema, table, where, values)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}

// UpdateTable perform update table
func UpdateTable(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	database, ok := vars["database"]
	if !ok {
		log.Println("Unable to parse database in URI")
		http.Error(w, "Unable to parse database in URI", http.StatusInternalServerError)
		return
	}
	schema, ok := vars["schema"]
	if !ok {
		log.Println("Unable to parse schema in URI")
		http.Error(w, "Unable to parse schema in URI", http.StatusInternalServerError)
		return
	}
	table, ok := vars["table"]
	if !ok {
		log.Println("Unable to parse table in URI")
		http.Error(w, "Unable to parse table in URI", http.StatusInternalServerError)
		return
	}

	req := api.Request{}
	err := json.NewDecoder(r.Body).Decode(&req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	where, values, err := postgres.WhereByRequest(r, 1)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
	}

	object, err := postgres.Update(database, schema, table, where, values, req)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(object)
}
<|endoftext|>


<commit_before>/*
 * Minio Cloud Storage, (C) 2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     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 cmd

import (
	"context"
	"io"

	"github.com/minio/minio/cmd/logger"
)

// Reads in parallel from readers.
type parallelReader struct {
	readers       []io.ReaderAt
	dataBlocks    int
	offset        int64
	shardSize     int64
	shardFileSize int64
	buf           [][]byte
}

// newParallelReader returns parallelReader.
func newParallelReader(readers []io.ReaderAt, e Erasure, offset, totalLength int64) *parallelReader {
	return &parallelReader{
		readers,
		e.dataBlocks,
		(offset / e.blockSize) * e.ShardSize(),
		e.ShardSize(),
		e.ShardFileSize(totalLength),
		make([][]byte, len(readers)),
	}
}

// Returns if buf can be erasure decoded.
func (p *parallelReader) canDecode(buf [][]byte) bool {
	bufCount := 0
	for _, b := range buf {
		if b != nil {
			bufCount++
		}
	}
	return bufCount >= p.dataBlocks
}

// Read reads from readers in parallel. Returns p.dataBlocks number of bufs.
func (p *parallelReader) Read() ([][]byte, error) {
	type errIdx struct {
		idx int
		buf []byte
		err error
	}

	errCh := make(chan errIdx)
	currReaderIndex := 0
	newBuf := make([][]byte, len(p.readers))

	if p.offset+p.shardSize > p.shardFileSize {
		p.shardSize = p.shardFileSize - p.offset
	}

	read := func(currReaderIndex int) {
		if p.buf[currReaderIndex] == nil {
			p.buf[currReaderIndex] = make([]byte, p.shardSize)
		}
		p.buf[currReaderIndex] = p.buf[currReaderIndex][:p.shardSize]
		_, err := p.readers[currReaderIndex].ReadAt(p.buf[currReaderIndex], p.offset)
		errCh <- errIdx{currReaderIndex, p.buf[currReaderIndex], err}
	}

	readerCount := 0
	for _, r := range p.readers {
		if r != nil {
			readerCount++
		}
	}
	if readerCount < p.dataBlocks {
		return nil, errXLReadQuorum
	}

	readerCount = 0
	for i, r := range p.readers {
		if r == nil {
			continue
		}
		go read(i)
		readerCount++
		if readerCount == p.dataBlocks {
			currReaderIndex = i + 1
			break
		}
	}

	for errVal := range errCh {
		if errVal.err == nil {
			newBuf[errVal.idx] = errVal.buf
			if p.canDecode(newBuf) {
				p.offset += int64(p.shardSize)
				return newBuf, nil
			}
			continue
		}
		p.readers[errVal.idx] = nil
		for currReaderIndex < len(p.readers) {
			if p.readers[currReaderIndex] != nil {
				break
			}
			currReaderIndex++
		}

		if currReaderIndex == len(p.readers) {
			break
		}
		go read(currReaderIndex)
		currReaderIndex++
	}

	return nil, errXLReadQuorum
}

// Decode reads from readers, reconstructs data if needed and writes the data to the writer.
func (e Erasure) Decode(ctx context.Context, writer io.Writer, readers []io.ReaderAt, offset, length, totalLength int64) error {
	if offset < 0 || length < 0 {
		logger.LogIf(ctx, errInvalidArgument)
		return errInvalidArgument
	}
	if offset+length > totalLength {
		logger.LogIf(ctx, errInvalidArgument)
		return errInvalidArgument
	}
	if length == 0 {
		return nil
	}

	reader := newParallelReader(readers, e, offset, totalLength)

	startBlock := offset / e.blockSize
	endBlock := (offset + length) / e.blockSize

	var bytesWritten int64
	for block := startBlock; block <= endBlock; block++ {
		var blockOffset, blockLength int64
		switch {
		case startBlock == endBlock:
			blockOffset = offset % e.blockSize
			blockLength = length
		case block == startBlock:
			blockOffset = offset % e.blockSize
			blockLength = e.blockSize - blockOffset
		case block == endBlock:
			blockOffset = 0
			blockLength = (offset + length) % e.blockSize
		default:
			blockOffset = 0
			blockLength = e.blockSize
		}
		if blockLength == 0 {
			break
		}
		bufs, err := reader.Read()
		if err != nil {
			return err
		}
		if err = e.DecodeDataBlocks(bufs); err != nil {
			logger.LogIf(ctx, err)
			return err
		}
		n, err := writeDataBlocks(ctx, writer, bufs, e.dataBlocks, blockOffset, blockLength)
		if err != nil {
			return err
		}
		bytesWritten += n
	}
	if bytesWritten != length {
		logger.LogIf(ctx, errLessData)
		return errLessData
	}
	return nil
}
<commit_msg>Simplify parallelReader.Read() (#7109)<commit_after>/*
 * Minio Cloud Storage, (C) 2016 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     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 cmd

import (
	"context"
	"io"
	"sync"

	"github.com/minio/minio/cmd/logger"
)

// Reads in parallel from readers.
type parallelReader struct {
	readers       []io.ReaderAt
	dataBlocks    int
	offset        int64
	shardSize     int64
	shardFileSize int64
	buf           [][]byte
}

// newParallelReader returns parallelReader.
func newParallelReader(readers []io.ReaderAt, e Erasure, offset, totalLength int64) *parallelReader {
	return &parallelReader{
		readers,
		e.dataBlocks,
		(offset / e.blockSize) * e.ShardSize(),
		e.ShardSize(),
		e.ShardFileSize(totalLength),
		make([][]byte, len(readers)),
	}
}

// Returns if buf can be erasure decoded.
func (p *parallelReader) canDecode(buf [][]byte) bool {
	bufCount := 0
	for _, b := range buf {
		if b != nil {
			bufCount++
		}
	}
	return bufCount >= p.dataBlocks
}

// Read reads from readers in parallel. Returns p.dataBlocks number of bufs.
func (p *parallelReader) Read() ([][]byte, error) {
	newBuf := make([][]byte, len(p.readers))
	var newBufLK sync.RWMutex

	if p.offset+p.shardSize > p.shardFileSize {
		p.shardSize = p.shardFileSize - p.offset
	}

	readTriggerCh := make(chan bool, len(p.readers))
	for i := 0; i < p.dataBlocks; i++ {
		// Setup read triggers for p.dataBlocks number of reads so that it reads in parallel.
		readTriggerCh <- true
	}

	readerIndex := 0
	var wg sync.WaitGroup
	// if readTrigger is true, it implies next disk.ReadAt() should be tried
	// if readTrigger is false, it implies previous disk.ReadAt() was successful and there is no need
	// to try reading the next disk.
	for readTrigger := range readTriggerCh {
		newBufLK.RLock()
		canDecode := p.canDecode(newBuf)
		newBufLK.RUnlock()
		if canDecode {
			break
		}
		if readerIndex == len(p.readers) {
			break
		}
		if !readTrigger {
			continue
		}
		wg.Add(1)
		go func(i int) {
			defer wg.Done()
			disk := p.readers[i]
			if disk == nil {
				// Since disk is nil, trigger another read.
				readTriggerCh <- true
				return
			}
			if p.buf[i] == nil {
				// Reading first time on this disk, hence the buffer needs to be allocated.
				// Subsequent reads will re-use this buffer.
				p.buf[i] = make([]byte, p.shardSize)
			}
			// For the last shard, the shardsize might be less than previous shard sizes.
			// Hence the following statement ensures that the buffer size is reset to the right size.
			p.buf[i] = p.buf[i][:p.shardSize]
			_, err := disk.ReadAt(p.buf[i], p.offset)
			if err != nil {
				p.readers[i] = nil
				// Since ReadAt returned error, trigger another read.
				readTriggerCh <- true
				return
			}
			newBufLK.Lock()
			newBuf[i] = p.buf[i]
			newBufLK.Unlock()
			// Since ReadAt returned success, there is no need to trigger another read.
			readTriggerCh <- false
		}(readerIndex)
		readerIndex++
	}
	wg.Wait()

	if p.canDecode(newBuf) {
		p.offset += p.shardSize
		return newBuf, nil
	}

	return nil, errXLReadQuorum
}

// Decode reads from readers, reconstructs data if needed and writes the data to the writer.
func (e Erasure) Decode(ctx context.Context, writer io.Writer, readers []io.ReaderAt, offset, length, totalLength int64) error {
	if offset < 0 || length < 0 {
		logger.LogIf(ctx, errInvalidArgument)
		return errInvalidArgument
	}
	if offset+length > totalLength {
		logger.LogIf(ctx, errInvalidArgument)
		return errInvalidArgument
	}
	if length == 0 {
		return nil
	}

	reader := newParallelReader(readers, e, offset, totalLength)

	startBlock := offset / e.blockSize
	endBlock := (offset + length) / e.blockSize

	var bytesWritten int64
	for block := startBlock; block <= endBlock; block++ {
		var blockOffset, blockLength int64
		switch {
		case startBlock == endBlock:
			blockOffset = offset % e.blockSize
			blockLength = length
		case block == startBlock:
			blockOffset = offset % e.blockSize
			blockLength = e.blockSize - blockOffset
		case block == endBlock:
			blockOffset = 0
			blockLength = (offset + length) % e.blockSize
		default:
			blockOffset = 0
			blockLength = e.blockSize
		}
		if blockLength == 0 {
			break
		}
		bufs, err := reader.Read()
		if err != nil {
			return err
		}
		if err = e.DecodeDataBlocks(bufs); err != nil {
			logger.LogIf(ctx, err)
			return err
		}
		n, err := writeDataBlocks(ctx, writer, bufs, e.dataBlocks, blockOffset, blockLength)
		if err != nil {
			return err
		}
		bytesWritten += n
	}
	if bytesWritten != length {
		logger.LogIf(ctx, errLessData)
		return errLessData
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/heroku/log-iss/Godeps/_workspace/src/github.com/heroku/authenticater"
	"github.com/heroku/log-iss/Godeps/_workspace/src/github.com/heroku/slog"
)

type ShutdownCh chan int

var Config *IssConfig

func Logf(format string, a ...interface{}) {
	orig := fmt.Sprintf(format, a...)
	fmt.Printf("app=log-iss source=%s %s\n", Config.Deploy, orig)
}

func LogContext(ctx slog.Context) {
	ctx["app"] = "log-iss"
	ctx["source"] = Config.Deploy
	fmt.Println(ctx)
}

func awaitShutdownSignals(chs []ShutdownCh) {
	sigCh := make(chan os.Signal)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
	sig := <-sigCh
	Logf("ns=main at=shutdown-signal signal=%q", sig)
	for _, ch := range chs {
		ch <- 1
	}
}

func main() {
	Config, err := NewIssConfig()
	if err != nil {
		log.Fatalln(err)
	}

	auth, err := authenticater.NewBasicAuthFromString(Config.Tokens)
	if err != nil {
		log.Fatalln(err)
	}

	forwarderSet := NewForwarderSet(Config)
	forwarderSet.Start()

	shutdownCh := make(ShutdownCh)

	httpServer := NewHttpServer(Config, auth, Fix, forwarderSet.Inbox)

	go awaitShutdownSignals([]ShutdownCh{httpServer.ShutdownCh, shutdownCh})

	go func() {
		if err := httpServer.Run(); err != nil {
			log.Fatalln("Unable to start HTTP server:", err)
		}
	}()

	Logf("ns=main at=start")
	<-shutdownCh
	Logf("ns=main at=drain")
	httpServer.InFlightWg.Wait()
	Logf("ns=main at=exit")
}
<commit_msg>Oh yeah<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/heroku/log-iss/Godeps/_workspace/src/github.com/heroku/authenticater"
	"github.com/heroku/log-iss/Godeps/_workspace/src/github.com/heroku/slog"
)

type ShutdownCh chan int

var Config *IssConfig

func Logf(format string, a ...interface{}) {
	orig := fmt.Sprintf(format, a...)
	fmt.Printf("app=log-iss source=%s %s\n", Config.Deploy, orig)
}

func LogContext(ctx slog.Context) {
	ctx["app"] = "log-iss"
	ctx["source"] = Config.Deploy
	fmt.Println(ctx)
}

func awaitShutdownSignals(chs []ShutdownCh) {
	sigCh := make(chan os.Signal)
	signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
	sig := <-sigCh
	Logf("ns=main at=shutdown-signal signal=%q", sig)
	for _, ch := range chs {
		ch <- 1
	}
}

func main() {
	config, err := NewIssConfig()
	if err != nil {
		log.Fatalln(err)
	}

	Config = config

	auth, err := authenticater.NewBasicAuthFromString(Config.Tokens)
	if err != nil {
		log.Fatalln(err)
	}

	forwarderSet := NewForwarderSet(Config)
	forwarderSet.Start()

	shutdownCh := make(ShutdownCh)

	httpServer := NewHttpServer(Config, auth, Fix, forwarderSet.Inbox)

	go awaitShutdownSignals([]ShutdownCh{httpServer.ShutdownCh, shutdownCh})

	go func() {
		if err := httpServer.Run(); err != nil {
			log.Fatalln("Unable to start HTTP server:", err)
		}
	}()

	Logf("ns=main at=start")
	<-shutdownCh
	Logf("ns=main at=drain")
	httpServer.InFlightWg.Wait()
	Logf("ns=main at=exit")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/shifr/imgwizard"
)

const VERSION = 1.5

func init() {
	log.SetOutput(os.Stdout)

	flag.BoolVar(&imgwizard.Version, "v", false, "Check imgwizard version")
	flag.StringVar(&imgwizard.ListenAddr, "l", "127.0.0.1:8070", "Address to listen on")
	flag.StringVar(&imgwizard.AllowedMedia, "m", "", "comma separated list of allowed media server hosts")
	flag.StringVar(&imgwizard.AllowedSizes, "s", "", "comma separated list of allowed sizes")
	flag.StringVar(&imgwizard.CacheDir, "c", "/tmp/imgwizard", "directory for cached files")
	flag.StringVar(&imgwizard.S3BucketName, "s3-b", "", "AWS S3 cache bucket name")
	flag.StringVar(&imgwizard.AzureContainerName, "az", "", "Microsoft Azure Storage container name")
	flag.StringVar(&imgwizard.Default404, "thumb", "", "path to default image if original not found")
	flag.StringVar(&imgwizard.DirsToSearch, "d", "", "comma separated list of directories to search requested file")
	flag.StringVar(&imgwizard.Mark, "mark", "images", "Mark for nginx")
	flag.StringVar(&imgwizard.NoCacheKey, "no-cache-key", "", "Secret key that must be equal X-No-Cache value from request header")
	flag.StringVar(&imgwizard.Nodes, "nodes", "", "Other imgwizard nodes to ask before process image")
	flag.IntVar(&imgwizard.Quality, "q", 0, "image quality after resize")
}

func main() {
	flag.Parse()

	if imgwizard.Version {
		log.Println("Version:", VERSION)
		return
	}

	imgwizard.GlobalSettings.Load()

	r := new(imgwizard.RegexpHandler)
	r.HandleFunc(imgwizard.GlobalSettings.UrlExp, imgwizard.FetchImage)

	log.Printf("ImgWizard started on http://%s", imgwizard.ListenAddr)
	http.ListenAndServe(imgwizard.ListenAddr, r)
}
<commit_msg>Updated version<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"

	"github.com/shifr/imgwizard"
)

const VERSION = 1.6

func init() {
	log.SetOutput(os.Stdout)

	flag.BoolVar(&imgwizard.Version, "v", false, "Check imgwizard version")
	flag.StringVar(&imgwizard.ListenAddr, "l", "127.0.0.1:8070", "Address to listen on")
	flag.StringVar(&imgwizard.AllowedMedia, "m", "", "comma separated list of allowed media server hosts")
	flag.StringVar(&imgwizard.AllowedSizes, "s", "", "comma separated list of allowed sizes")
	flag.StringVar(&imgwizard.CacheDir, "c", "/tmp/imgwizard", "directory for cached files")
	flag.StringVar(&imgwizard.S3BucketName, "s3-b", "", "AWS S3 cache bucket name")
	flag.StringVar(&imgwizard.AzureContainerName, "az", "", "Microsoft Azure Storage container name")
	flag.StringVar(&imgwizard.Default404, "thumb", "", "path to default image if original not found")
	flag.StringVar(&imgwizard.DirsToSearch, "d", "", "comma separated list of directories to search requested file")
	flag.StringVar(&imgwizard.Mark, "mark", "images", "Mark for nginx")
	flag.StringVar(&imgwizard.NoCacheKey, "no-cache-key", "", "Secret key that must be equal X-No-Cache value from request header")
	flag.StringVar(&imgwizard.Nodes, "nodes", "", "Other imgwizard nodes to ask before process image")
	flag.IntVar(&imgwizard.Quality, "q", 0, "image quality after resize")
}

func main() {
	flag.Parse()

	if imgwizard.Version {
		log.Println("Version:", VERSION)
		return
	}

	imgwizard.GlobalSettings.Load()

	r := new(imgwizard.RegexpHandler)
	r.HandleFunc(imgwizard.GlobalSettings.UrlExp, imgwizard.FetchImage)

	log.Printf("ImgWizard started on http://%s", imgwizard.ListenAddr)
	http.ListenAndServe(imgwizard.ListenAddr, r)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/datawire/teleproxy/pkg/kubeapply"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

func envBool(name string) bool {
	val, _ := strconv.ParseBool(name)
	return val
}

// Version holds the version of the code. This is intended to be overridden at build time.
var Version = "(unknown version)"

func main() {
	var ka = &cobra.Command{
		Use:           "kubeapply",
		Short:         "kubeapply",
		Long:          "kubeapply - the way kubectl aught to work",
		SilenceErrors: true,
		SilenceUsage:  true,
	}

	debug := ka.Flags().Bool("debug", envBool("KUBEAPPLY_DEBUG"), "enable debug mode")
	dryRun := ka.Flags().Bool("dry-run", envBool("KUBEAPPLY_DRYRUN"), "enable dry-run mode")
	timeout := ka.Flags().DurationP("timeout", "t", 60*time.Second, "timeout to wait for applied yaml to be ready")
	showVersion := ka.Flags().Bool("version", false, "output version information and exit")
	files := ka.Flags().StringArrayP("", "f", nil, "files to apply")

	ka.RunE = func(cmd *cobra.Command, args []string) error {
		if *showVersion {
			fmt.Println(Version)
			return nil
		}
		if len(args) > 0 {
			return errors.Errorf("extra args: %v", args)
		}
		if len(*files) == 0 {
			return errors.Errorf("at least one file argument is required")
		}
		return kubeapply.Kubeapply(nil, *timeout, *debug, *dryRun, *files...)
	}

	err := ka.Execute()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}
<commit_msg>added standard kubeinfo args to kubeapply<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/datawire/teleproxy/pkg/k8s"
	"github.com/datawire/teleproxy/pkg/kubeapply"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

func envBool(name string) bool {
	val, _ := strconv.ParseBool(name)
	return val
}

// Version holds the version of the code. This is intended to be overridden at build time.
var Version = "(unknown version)"

func main() {
	var ka = &cobra.Command{
		Use:           "kubeapply",
		Short:         "kubeapply",
		Long:          "kubeapply - the way kubectl aught to work",
		SilenceErrors: true,
		SilenceUsage:  true,
	}

	kubeconfig := ka.Flags().String("kubeconfig", "", "kubernetes config file")
	context := ka.Flags().String("context", "", "kubernetes context")
	namespace := ka.Flags().StringP("namespace", "n", "", "kubernetes namespace")
	debug := ka.Flags().Bool("debug", envBool("KUBEAPPLY_DEBUG"), "enable debug mode")
	dryRun := ka.Flags().Bool("dry-run", envBool("KUBEAPPLY_DRYRUN"), "enable dry-run mode")
	timeout := ka.Flags().DurationP("timeout", "t", 60*time.Second, "timeout to wait for applied yaml to be ready")
	showVersion := ka.Flags().Bool("version", false, "output version information and exit")
	files := ka.Flags().StringArrayP("", "f", nil, "files to apply")

	ka.RunE = func(cmd *cobra.Command, args []string) error {
		if *showVersion {
			fmt.Println(Version)
			return nil
		}
		if len(args) > 0 {
			return errors.Errorf("extra args: %v", args)
		}
		if len(*files) == 0 {
			return errors.Errorf("at least one file argument is required")
		}
		return kubeapply.Kubeapply(k8s.NewKubeInfo(*kubeconfig, *context, *namespace), *timeout,
			*debug, *dryRun, *files...)
	}

	err := ka.Execute()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {
	// TODO: compile this binary for a docker container
	fmt.Printf("Hello: this is the primary Plumber command.\n")
	// TODO: start injector API
	// TODO: start election process
	// TODO: start coupler-container interface
}
<commit_msg>Stubbing out more plumber logic<commit_after>package main

import (
	"container/heap"
	"fmt"

	"bitbucket.org/bign8/pipelines/shared"
)

func main() {
	// TODO: compile this binary for a docker container
	fmt.Printf("Hello: this is the primary Plumber command.\n")
	// TODO: start injector API
	// TODO: start election process
	// TODO: start coupler-container interface

	h := Handler{}
	h.balancer = Balancer{}

}

// NodeType is the possible type of nodes in the system
type NodeType string

// KeyType is the type of key in the system
type KeyType string

// NodeLookup is a simple lookup map for nodes to workers
type NodeLookup map[KeyType]Worker

// Handler is the base type of inbound manager requests
type Handler struct {
	index    map[NodeType]NodeLookup
	balancer Balancer
	queue    chan<- Request
}

// NewHandler creates a new handler for inboud requests
func NewHandler() *Handler {
	h := &Handler{}
	queue := make(chan Request)
	h.queue = queue
	h.balancer = Balancer{}
	h.balancer.balance(queue)
	return h
}

// TODO: make NATS handler
func (h *Handler) handle(req shared.RouteRequest) {
	request := Request{}

	// Handling based on node type
	// TODO: lookup destination based on source
	nodeType := NodeType(req.Source)
	lookup, ok := h.index[nodeType]
	if !ok {
		h.queue <- request
	}

	// Handling based on mined keys
	dataKey := KeyType(req.Key)
	worker, ok := lookup[dataKey]
	if !ok {
		h.queue <- request
	}

	// Direct route of handling requsts
	worker.requests <- request
	worker.pending++
	heap.Fix(&h.balancer.pool, worker.index)
}
<|endoftext|>