<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type gitRunner struct {
	// Original git repo path, which should be current working directory
	originalGitPath string
	// A temporary path for worktree
	worktreePath string
	// Does this have worktree
	hasWorktree bool
}

func newGitRunner(worktree bool) (gitRunner, error) {
	gr := gitRunner{}
	pwd, err := os.Getwd()
	if err != nil {
		return gr, err
	}
	gr.originalGitPath = pwd
	gr.hasWorktree = worktree
	if worktree {
		err = gr.CreateWorktreeDir()
		if err != nil {
			return gr, err
		}
	}
	return gr, nil
}

func (gr *gitRunner) Close() error {
	if !gr.hasWorktree {
		return nil
	}
	err := gr.DeleteWorktreeDir()
	if err != nil {
		return err
	}
	err = gr.PruneWorktree()
	if err != nil {
		return err
	}
	return nil
}

func (gr *gitRunner) DeleteWorktreeDir() error {
	logDebug("Deleting git worktree dir: %s", gr.worktreePath)
	err := os.RemoveAll(gr.worktreePath)
	if err != nil {
		return err
	}
	logDebug("Deleting done")
	return nil
}

func (gr *gitRunner) WorktreePath() (string, error) {
	if gr.worktreePath == "" {
		return "", fmt.Errorf("Empty worktree path")
	}
	return gr.worktreePath, nil
}

func (gr *gitRunner) OriginalGitPath() (string, error) {
	if gr.originalGitPath == "" {
		return "", fmt.Errorf("Empty git path")
	}
	return gr.originalGitPath, nil
}

func (gr *gitRunner) CreateWorktreeDir() error {
	// Create temporary directory
	temp, err := ioutil.TempDir("", "kustomize-releases")
	if err != nil {
		return err
	}
	gr.worktreePath = filepath.Join(temp, "sigs.k8s.io/kustomize")
	err = os.MkdirAll(gr.worktreePath, 0700)
	logDebug("Created git worktree dir: %s", gr.worktreePath)
	if err != nil {
		return err
	}
	return nil
}

func (gr *gitRunner) CheckRemoteExistence(remote string) error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	logDebug("Checking remote %s in %s", remote, path)
	cmd := exec.Command("git", "remote")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Remotes:\n%s", string(stdoutStderr))

	regString := fmt.Sprintf("(?m)^\\s*%s\\s*$", remote)
	reg := regexp.MustCompile(regString)
	if !reg.MatchString(string(stdoutStderr)) {
		return fmt.Errorf("Cannot find remote named %s", remote)
	}
	logDebug("Remote %s exists", remote)
	return nil
}

func (gr *gitRunner) FetchTags(remote string) error {
	logDebug("Fetching latest tags")
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "fetch", "-t", remote)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished fetching")
	return nil
}

func (gr *gitRunner) GetTags() (string, error) {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return "", err
	}
	logDebug("Getting latest tag in repo %s", path)
	cmd := exec.Command("git", "tag", "-l")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished getting tags")
	return string(stdoutStderr), nil
}

func (gr *gitRunner) CheckBranchExistence(name string) (bool, error) {
	logDebug("Checking branch %s existence", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return false, err
	}
	cmd := exec.Command("git", "branch", "-a")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return false, fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	branches := strings.Split(string(stdoutStderr), "\n")
	for _, branch := range branches {
		if strings.Trim(branch, " ") == "remotes/"+name {
			return true, nil
		}
	}
	return false, nil
}

func (gr *gitRunner) NewBranch(name string) error {
	logInfo("Creating new branch %s", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	upstreamBranch := "upstream/" + name
	cmd := exec.Command("git", "branch", name, upstreamBranch)
	exist, err := gr.CheckBranchExistence(upstreamBranch)
	if err != nil {
		return err
	}
	if !exist {
		logInfo("Remote branch %s doesn't exist", upstreamBranch)
		cmd = exec.Command("git", "branch", name)
	}
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) DeleteBranch(name string) error {
	logDebug("Deleting branch %s", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "branch", "-D", name)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished deleting branch")
	return nil
}

func (gr *gitRunner) AddWorktree(branch string) error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	tempDir, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	logInfo("Adding worktree %s for branch %s", tempDir, branch)
	cmd := exec.Command("git", "worktree", "add", tempDir, branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) PruneWorktree() error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	logDebug("Pruning worktree for repo %s", path)
	cmd := exec.Command("git", "worktree", "prune")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished pruning worktree")
	return nil
}

func (gr *gitRunner) Merge(branch string) error {
	logInfo("Merging %s", branch)
	path, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	logDebug("Working dir: %s", path)
	cmd := exec.Command("git", "merge", branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) PushRelease(branch string, mod module) error {
	logInfo("Pushing branch %s", branch)
	path, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "push", "upstream", branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}

	logInfo("Creating tag %s", mod.Tag())
	cmd = exec.Command(
		"git", "tag",
		"-a", mod.Tag(),
		"-m", fmt.Sprintf("Release %s on branch %s", mod.Tag(), branch),
	)
	cmd.Dir = path
	stdoutStderr, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}

	logInfo("Pushing tag %s", mod.Tag())
	cmd = exec.Command("git", "push", "upstream", mod.Tag())
	cmd.Dir = path
	stdoutStderr, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}
<commit_msg>force branch fetches in gitrunner<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)

type gitRunner struct {
	// Original git repo path, which should be current working directory
	originalGitPath string
	// A temporary path for worktree
	worktreePath string
	// Does this have worktree
	hasWorktree bool
}

func newGitRunner(worktree bool) (gitRunner, error) {
	gr := gitRunner{}
	pwd, err := os.Getwd()
	if err != nil {
		return gr, err
	}
	gr.originalGitPath = pwd
	gr.hasWorktree = worktree
	if worktree {
		err = gr.CreateWorktreeDir()
		if err != nil {
			return gr, err
		}
	}
	return gr, nil
}

func (gr *gitRunner) Close() error {
	if !gr.hasWorktree {
		return nil
	}
	err := gr.DeleteWorktreeDir()
	if err != nil {
		return err
	}
	err = gr.PruneWorktree()
	if err != nil {
		return err
	}
	return nil
}

func (gr *gitRunner) DeleteWorktreeDir() error {
	logDebug("Deleting git worktree dir: %s", gr.worktreePath)
	err := os.RemoveAll(gr.worktreePath)
	if err != nil {
		return err
	}
	logDebug("Deleting done")
	return nil
}

func (gr *gitRunner) WorktreePath() (string, error) {
	if gr.worktreePath == "" {
		return "", fmt.Errorf("Empty worktree path")
	}
	return gr.worktreePath, nil
}

func (gr *gitRunner) OriginalGitPath() (string, error) {
	if gr.originalGitPath == "" {
		return "", fmt.Errorf("Empty git path")
	}
	return gr.originalGitPath, nil
}

func (gr *gitRunner) CreateWorktreeDir() error {
	// Create temporary directory
	temp, err := ioutil.TempDir("", "kustomize-releases")
	if err != nil {
		return err
	}
	gr.worktreePath = filepath.Join(temp, "sigs.k8s.io/kustomize")
	err = os.MkdirAll(gr.worktreePath, 0700)
	logDebug("Created git worktree dir: %s", gr.worktreePath)
	if err != nil {
		return err
	}
	return nil
}

func (gr *gitRunner) CheckRemoteExistence(remote string) error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	logDebug("Checking remote %s in %s", remote, path)
	cmd := exec.Command("git", "remote")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Remotes:\n%s", string(stdoutStderr))

	regString := fmt.Sprintf("(?m)^\\s*%s\\s*$", remote)
	reg := regexp.MustCompile(regString)
	if !reg.MatchString(string(stdoutStderr)) {
		return fmt.Errorf("Cannot find remote named %s", remote)
	}
	logDebug("Remote %s exists", remote)
	return nil
}

func (gr *gitRunner) FetchTags(remote string) error {
	logDebug("Fetching latest tags")
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "fetch", "-t", remote, "-f")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished fetching")
	return nil
}

func (gr *gitRunner) GetTags() (string, error) {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return "", err
	}
	logDebug("Getting latest tag in repo %s", path)
	cmd := exec.Command("git", "tag", "-l")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished getting tags")
	return string(stdoutStderr), nil
}

func (gr *gitRunner) CheckBranchExistence(name string) (bool, error) {
	logDebug("Checking branch %s existence", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return false, err
	}
	cmd := exec.Command("git", "branch", "-a")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return false, fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	branches := strings.Split(string(stdoutStderr), "\n")
	for _, branch := range branches {
		if strings.Trim(branch, " ") == "remotes/"+name {
			return true, nil
		}
	}
	return false, nil
}

func (gr *gitRunner) NewBranch(name string) error {
	logInfo("Creating new branch %s", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	upstreamBranch := "upstream/" + name
	cmd := exec.Command("git", "branch", name, upstreamBranch)
	exist, err := gr.CheckBranchExistence(upstreamBranch)
	if err != nil {
		return err
	}
	if !exist {
		logInfo("Remote branch %s doesn't exist", upstreamBranch)
		cmd = exec.Command("git", "branch", name)
	}
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) DeleteBranch(name string) error {
	logDebug("Deleting branch %s", name)
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "branch", "-D", name)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished deleting branch")
	return nil
}

func (gr *gitRunner) AddWorktree(branch string) error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	tempDir, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	logInfo("Adding worktree %s for branch %s", tempDir, branch)
	cmd := exec.Command("git", "worktree", "add", tempDir, branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) PruneWorktree() error {
	path, err := gr.OriginalGitPath()
	if err != nil {
		return err
	}
	logDebug("Pruning worktree for repo %s", path)
	cmd := exec.Command("git", "worktree", "prune")
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	logDebug("Finished pruning worktree")
	return nil
}

func (gr *gitRunner) Merge(branch string) error {
	logInfo("Merging %s", branch)
	path, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	logDebug("Working dir: %s", path)
	cmd := exec.Command("git", "merge", branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}

func (gr *gitRunner) PushRelease(branch string, mod module) error {
	logInfo("Pushing branch %s", branch)
	path, err := gr.WorktreePath()
	if err != nil {
		return err
	}
	cmd := exec.Command("git", "push", "upstream", branch)
	cmd.Dir = path
	stdoutStderr, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}

	logInfo("Creating tag %s", mod.Tag())
	cmd = exec.Command(
		"git", "tag",
		"-a", mod.Tag(),
		"-m", fmt.Sprintf("Release %s on branch %s", mod.Tag(), branch),
	)
	cmd.Dir = path
	stdoutStderr, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}

	logInfo("Pushing tag %s", mod.Tag())
	cmd = exec.Command("git", "push", "upstream", mod.Tag())
	cmd.Dir = path
	stdoutStderr, err = cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s %s", err.Error(), stdoutStderr)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Aerospike, 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 types

import (
	. "github.com/aerospike/aerospike-client-go/types/atomic"
)

// BufferPool implements a specialized buffer pool.
// Pool size will be limited, and each buffer size will be
// constrained to the init and max buffer sizes.
type BufferPool struct {
	pool     *AtomicQueue
	poolSize int

	maxBufSize  int
	initBufSize int
}

// NewBufferPool creates a new buffer pool.
// New buffers will be created with size and capacity of initBufferSize.
// If  cap(buffer) is larger than maxBufferSize when it is put back in the buffer,
// it will be thrown away. This will prevent unwanted memory bloat and
// set a deterministic maximum-size for the pool which will not be exceeded.
func NewBufferPool(poolSize, initBufferSize, maxBufferSize int) *BufferPool {
	return &BufferPool{
		pool:        NewAtomicQueue(poolSize),
		poolSize:    poolSize,
		maxBufSize:  maxBufferSize,
		initBufSize: initBufferSize,
	}
}

// Get returns a buffer from the pool. If pool is empty, a new buffer of
// size initBufSize will be created and returned.
func (bp *BufferPool) Get() []byte {
	res := bp.pool.Poll()
	if res == nil {
		return make([]byte, bp.initBufSize, bp.initBufSize)
	}

	return res.([]byte)
}

// Put will put the buffer back in the pool, unless cap(buf) is bigger than
// initBufSize, in which case it will be thrown away
func (bp *BufferPool) Put(buf []byte) {
	if cap(buf) <= bp.maxBufSize {
		bp.pool.Offer(buf)
	}
}
<commit_msg>use LIFO pool to optimize for CPU local cache<commit_after>// Copyright 2013-2014 Aerospike, 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 types

import "sync"

// BufferPool implements a specialized buffer pool.
// Pool size will be limited, and each buffer size will be
// constrained to the init and max buffer sizes.
type BufferPool struct {
	pool     [][]byte
	poolSize int

	pos int64

	maxBufSize  int
	initBufSize int

	mutex sync.Mutex
}

// NewBufferPool creates a new buffer pool.
// New buffers will be created with size and capacity of initBufferSize.
// If  cap(buffer) is larger than maxBufferSize when it is put back in the buffer,
// it will be thrown away. This will prevent unwanted memory bloat and
// set a deterministic maximum-size for the pool which will not be exceeded.
func NewBufferPool(poolSize, initBufferSize, maxBufferSize int) *BufferPool {
	return &BufferPool{
		pool:        make([][]byte, poolSize),
		pos:         -1,
		poolSize:    poolSize,
		maxBufSize:  maxBufferSize,
		initBufSize: initBufferSize,
	}
}

// Get returns a buffer from the pool. If pool is empty, a new buffer of
// size initBufSize will be created and returned.
func (bp *BufferPool) Get() (res []byte) {
	bp.mutex.Lock()
	if bp.pos >= 0 {
		res = bp.pool[bp.pos]
		bp.pos--
	} else {
		res = make([]byte, bp.initBufSize, bp.initBufSize)
	}

	bp.mutex.Unlock()
	return res
}

// Put will put the buffer back in the pool, unless cap(buf) is bigger than
// initBufSize, in which case it will be thrown away
func (bp *BufferPool) Put(buf []byte) {
	if len(buf) <= bp.maxBufSize {
		bp.mutex.Lock()
		if bp.pos < int64(bp.poolSize-1) {
			bp.pos++
			bp.pool[bp.pos] = buf
		}
		bp.mutex.Unlock()
	}
}
<|endoftext|>


<commit_before>// +build windows

package logger

import (
	"os"
	"strings"
	"syscall"
	"unsafe"
)

const SupportsColorEscapes = true

var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var getConsoleMode = kernel32.NewProc("GetConsoleMode")
var setConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
var getConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")

type consoleScreenBufferInfo struct {
	dwSizeX              int16
	dwSizeY              int16
	dwCursorPositionX    int16
	dwCursorPositionY    int16
	wAttributes          uint16
	srWindowLeft         int16
	srWindowTop          int16
	srWindowRight        int16
	srWindowBottom       int16
	dwMaximumWindowSizeX int16
	dwMaximumWindowSizeY int16
}

func GetTerminalInfo(file *os.File) TerminalInfo {
	fd := file.Fd()

	// Is this file descriptor a terminal?
	var unused uint32
	isTTY, _, _ := syscall.Syscall(getConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&unused)), 0)

	// Get the width of the window
	var info consoleScreenBufferInfo
	syscall.Syscall(getConsoleScreenBufferInfo.Addr(), 2, fd, uintptr(unsafe.Pointer(&info)), 0)

	return TerminalInfo{
		IsTTY:           isTTY != 0,
		Width:           int(info.dwSizeX) - 1,
		Height:          int(info.dwSizeY) - 1,
		UseColorEscapes: true,
	}
}

func writeStringWithColor(file *os.File, text string) {
	const FOREGROUND_BLUE = 1
	const FOREGROUND_GREEN = 2
	const FOREGROUND_RED = 4
	const FOREGROUND_INTENSITY = 8

	fd := file.Fd()
	i := 0

	for i < len(text) {
		var attributes uintptr
		end := i

		switch {
		case text[i] != 033:
			i++
			continue

		case strings.HasPrefix(text[i:], terminalColors.Reset):
			i += len(terminalColors.Reset)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], terminalColors.Red):
			i += len(terminalColors.Red)
			attributes = FOREGROUND_RED

		case strings.HasPrefix(text[i:], terminalColors.Green):
			i += len(terminalColors.Green)
			attributes = FOREGROUND_GREEN

		case strings.HasPrefix(text[i:], terminalColors.Blue):
			i += len(terminalColors.Blue)
			attributes = FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], terminalColors.Cyan):
			i += len(terminalColors.Cyan)
			attributes = FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], terminalColors.Magenta):
			i += len(terminalColors.Magenta)
			attributes = FOREGROUND_RED | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], terminalColors.Yellow):
			i += len(terminalColors.Yellow)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN

		case strings.HasPrefix(text[i:], terminalColors.Dim):
			i += len(terminalColors.Dim)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], terminalColors.Bold):
			i += len(terminalColors.Bold)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY

		// Apparently underlines only work with the CJK locale on Windows :(
		case strings.HasPrefix(text[i:], terminalColors.Underline):
			i += len(terminalColors.Underline)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		default:
			i++
			continue
		}

		file.WriteString(text[:end])
		text = text[i:]
		i = 0
		setConsoleTextAttribute.Call(fd, attributes)
	}

	file.WriteString(text)
}
<commit_msg>Fix variable name for terminal colors used in Windows logger (#1074)<commit_after>// +build windows

package logger

import (
	"os"
	"strings"
	"syscall"
	"unsafe"
)

const SupportsColorEscapes = true

var kernel32 = syscall.NewLazyDLL("kernel32.dll")
var getConsoleMode = kernel32.NewProc("GetConsoleMode")
var setConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute")
var getConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")

type consoleScreenBufferInfo struct {
	dwSizeX              int16
	dwSizeY              int16
	dwCursorPositionX    int16
	dwCursorPositionY    int16
	wAttributes          uint16
	srWindowLeft         int16
	srWindowTop          int16
	srWindowRight        int16
	srWindowBottom       int16
	dwMaximumWindowSizeX int16
	dwMaximumWindowSizeY int16
}

func GetTerminalInfo(file *os.File) TerminalInfo {
	fd := file.Fd()

	// Is this file descriptor a terminal?
	var unused uint32
	isTTY, _, _ := syscall.Syscall(getConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&unused)), 0)

	// Get the width of the window
	var info consoleScreenBufferInfo
	syscall.Syscall(getConsoleScreenBufferInfo.Addr(), 2, fd, uintptr(unsafe.Pointer(&info)), 0)

	return TerminalInfo{
		IsTTY:           isTTY != 0,
		Width:           int(info.dwSizeX) - 1,
		Height:          int(info.dwSizeY) - 1,
		UseColorEscapes: true,
	}
}

func writeStringWithColor(file *os.File, text string) {
	const FOREGROUND_BLUE = 1
	const FOREGROUND_GREEN = 2
	const FOREGROUND_RED = 4
	const FOREGROUND_INTENSITY = 8

	fd := file.Fd()
	i := 0

	for i < len(text) {
		var attributes uintptr
		end := i

		switch {
		case text[i] != 033:
			i++
			continue

		case strings.HasPrefix(text[i:], TerminalColors.Reset):
			i += len(TerminalColors.Reset)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], TerminalColors.Red):
			i += len(TerminalColors.Red)
			attributes = FOREGROUND_RED

		case strings.HasPrefix(text[i:], TerminalColors.Green):
			i += len(TerminalColors.Green)
			attributes = FOREGROUND_GREEN

		case strings.HasPrefix(text[i:], TerminalColors.Blue):
			i += len(TerminalColors.Blue)
			attributes = FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], TerminalColors.Cyan):
			i += len(TerminalColors.Cyan)
			attributes = FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], TerminalColors.Magenta):
			i += len(TerminalColors.Magenta)
			attributes = FOREGROUND_RED | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], TerminalColors.Yellow):
			i += len(TerminalColors.Yellow)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN

		case strings.HasPrefix(text[i:], TerminalColors.Dim):
			i += len(TerminalColors.Dim)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		case strings.HasPrefix(text[i:], TerminalColors.Bold):
			i += len(TerminalColors.Bold)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY

		// Apparently underlines only work with the CJK locale on Windows :(
		case strings.HasPrefix(text[i:], TerminalColors.Underline):
			i += len(TerminalColors.Underline)
			attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE

		default:
			i++
			continue
		}

		file.WriteString(text[:end])
		text = text[i:]
		i = 0
		setConsoleTextAttribute.Call(fd, attributes)
	}

	file.WriteString(text)
}
<|endoftext|>


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

package graphicsutil

import (
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

var (
	theVerticesBackend = &verticesBackend{}
)

type verticesBackend struct {
	backend []float32
	head    int
}

func (v *verticesBackend) sliceForOneQuad() []float32 {
	const num = 256
	size := 4 * graphics.VertexSizeInBytes() / opengl.Float.SizeInBytes()
	if v.backend == nil {
		v.backend = make([]float32, size*num)
	}
	s := v.backend[v.head : v.head+size]
	v.head += size
	if v.head+size > len(v.backend) {
		v.backend = nil
		v.head = 0
	}
	return s
}

func isPowerOf2(x int) bool {
	return (x & (x - 1)) == 0
}

func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	if sx0 >= sx1 || sy0 >= sy1 {
		return nil
	}
	if sx1 <= 0 || sy1 <= 0 {
		return nil
	}

	wf := float32(width)
	hf := float32(height)
	u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
	return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca)
}

func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca float32) []float32 {
	// Specifying a range explicitly here is redundant but this helps optimization
	// to eliminate boundry checks.
	vs := theVerticesBackend.sliceForOneQuad()[0:40]

	ax, by, cx, dy := a*x, b*y, c*x, d*y

	// Vertex coordinates
	vs[0] = tx
	vs[1] = ty

	// Texture coordinates: first 2 values indicates the actual coodinate, and
	// the second indicates diagonally opposite coodinates.
	// The second is needed to calculate source rectangle size in shader programs.
	vs[2] = u0
	vs[3] = v0
	vs[4] = u1
	vs[5] = v1
	vs[6] = cr
	vs[7] = cg
	vs[8] = cb
	vs[9] = ca

	// and the same for the other three coordinates
	vs[10] = ax + tx
	vs[11] = cx + ty
	vs[12] = u1
	vs[13] = v0
	vs[14] = u0
	vs[15] = v1
	vs[16] = cr
	vs[17] = cg
	vs[18] = cb
	vs[19] = ca

	vs[20] = by + tx
	vs[21] = dy + ty
	vs[22] = u0
	vs[23] = v1
	vs[24] = u1
	vs[25] = v0
	vs[26] = cr
	vs[27] = cg
	vs[28] = cb
	vs[29] = ca

	vs[30] = ax + by + tx
	vs[31] = cx + dy + ty
	vs[32] = u1
	vs[33] = v1
	vs[34] = u0
	vs[35] = v0
	vs[36] = cr
	vs[37] = cg
	vs[38] = cb
	vs[39] = ca

	return vs
}

var (
	quadIndices = []uint16{0, 1, 2, 1, 2, 3}
)

func QuadIndices() []uint16 {
	return quadIndices
}

func Vertex(width, height int, dx, dy, sx, sy float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	wf := float32(width)
	hf := float32(height)

	// Specifying a range explicitly here is redundant but this helps optimization
	// to eliminate boundry checks.
	vs := theVerticesBackend.sliceForOneQuad()[0:10]
	vs[0] = dx
	vs[1] = dy
	vs[2] = sx / wf
	vs[3] = sy / hf
	vs[4] = -1
	vs[5] = -1
	vs[6] = cr
	vs[7] = cg
	vs[8] = cb
	vs[9] = ca

	return vs
}
<commit_msg>graphicsutil: Fix comments<commit_after>// Copyright 2017 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package graphicsutil

import (
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/opengl"
)

var (
	theVerticesBackend = &verticesBackend{}
)

type verticesBackend struct {
	backend []float32
	head    int
}

func (v *verticesBackend) sliceForOneQuad() []float32 {
	const num = 256
	size := 4 * graphics.VertexSizeInBytes() / opengl.Float.SizeInBytes()
	if v.backend == nil {
		v.backend = make([]float32, size*num)
	}
	s := v.backend[v.head : v.head+size]
	v.head += size
	if v.head+size > len(v.backend) {
		v.backend = nil
		v.head = 0
	}
	return s
}

func isPowerOf2(x int) bool {
	return (x & (x - 1)) == 0
}

func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	if sx0 >= sx1 || sy0 >= sy1 {
		return nil
	}
	if sx1 <= 0 || sy1 <= 0 {
		return nil
	}

	wf := float32(width)
	hf := float32(height)
	u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
	return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca)
}

func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty, cr, cg, cb, ca float32) []float32 {
	// Specifying a range explicitly here is redundant but this helps optimization
	// to eliminate boundry checks.
	vs := theVerticesBackend.sliceForOneQuad()[0:40]

	ax, by, cx, dy := a*x, b*y, c*x, d*y

	// Vertex coordinates
	vs[0] = tx
	vs[1] = ty

	// Texture coordinates: first 2 values indicates the actual coodinate, and
	// the second indicates diagonally opposite coodinates.
	// The second is needed to calculate source rectangle size in shader programs.
	vs[2] = u0
	vs[3] = v0
	vs[4] = u1
	vs[5] = v1
	vs[6] = cr
	vs[7] = cg
	vs[8] = cb
	vs[9] = ca

	// and the same for the other three coordinates
	vs[10] = ax + tx
	vs[11] = cx + ty
	vs[12] = u1
	vs[13] = v0
	vs[14] = u0
	vs[15] = v1
	vs[16] = cr
	vs[17] = cg
	vs[18] = cb
	vs[19] = ca

	vs[20] = by + tx
	vs[21] = dy + ty
	vs[22] = u0
	vs[23] = v1
	vs[24] = u1
	vs[25] = v0
	vs[26] = cr
	vs[27] = cg
	vs[28] = cb
	vs[29] = ca

	vs[30] = ax + by + tx
	vs[31] = cx + dy + ty
	vs[32] = u1
	vs[33] = v1
	vs[34] = u0
	vs[35] = v0
	vs[36] = cr
	vs[37] = cg
	vs[38] = cb
	vs[39] = ca

	return vs
}

var (
	quadIndices = []uint16{0, 1, 2, 1, 2, 3}
)

func QuadIndices() []uint16 {
	return quadIndices
}

func Vertex(width, height int, dx, dy, sx, sy float32, cr, cg, cb, ca float32) []float32 {
	if !isPowerOf2(width) {
		panic("not reached")
	}
	if !isPowerOf2(height) {
		panic("not reached")
	}

	wf := float32(width)
	hf := float32(height)

	// Specify -1 for the source region, which means the source region is ignored.
	//
	// NaN would make more sense to represent an invalid state, but vertices including NaN values doesn't work on
	// some machines (#696). Let's use negative numbers to represent such state.
	vs := theVerticesBackend.sliceForOneQuad()[0:10]
	vs[0] = dx
	vs[1] = dy
	vs[2] = sx / wf
	vs[3] = sy / hf
	vs[4] = -1
	vs[5] = -1
	vs[6] = cr
	vs[7] = cg
	vs[8] = cb
	vs[9] = ca

	return vs
}
<|endoftext|>


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

// For now, we are not writing the unit test, which requires multiple
// version of same object. As this is not supported by fake-storage-server.
// Although API is exposed to enable the object versioning for a bucket,
// but it returns "method not allowed" when we call it.

package storage

import (
	"fmt"
	"io"

	"cloud.google.com/go/storage"
	"github.com/jacobsa/gcloud/gcs"
	"golang.org/x/net/context"
)

type bucketHandle struct {
	gcs.Bucket
	bucket *storage.BucketHandle
}

func (bh *bucketHandle) NewReader(
		ctx context.Context,
		req *gcs.ReadObjectRequest) (rc io.ReadCloser, err error) {
	// Initialising the starting offset and the length to be read by the reader.
	start := int64((*req.Range).Start)
	end := int64((*req.Range).Limit)
	length := int64(end - start)

	obj := bh.bucket.Object(req.Name)

	// Switching to the requested generation of object.
	if req.Generation != 0 {
		obj = obj.Generation(req.Generation)
	}

	// Creating a NewRangeReader instance.
	r, err := obj.NewRangeReader(ctx, start, length)
	if err != nil {
		err = fmt.Errorf("error in creating a NewRangeReader instance: %v", err)
		return
	}

	// Converting io.Reader to io.ReadCloser by adding a no-op closer method
	// to match the return type interface.
	rc = io.NopCloser(r)
	return
}
func (b *bucketHandle) DeleteObject(ctx context.Context, req *gcs.DeleteObjectRequest) (err error) {
	obj := b.bucket.Object(req.Name)

	// Switching to the requested generation of the object.
	if req.Generation != 0 {
		obj = obj.Generation(req.Generation)
	}
	// Putting condition that the object's MetaGeneration should match the requested MetaGeneration for deletion to occur.
	if req.MetaGenerationPrecondition != nil && *req.MetaGenerationPrecondition != 0 {
		obj = obj.If(storage.Conditions{MetagenerationMatch: *req.MetaGenerationPrecondition})
	}

	// Deleting object through Go Storage Client.
	err = obj.Delete(ctx)
	if err != nil {
		return
	}

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

// For now, we are not writing the unit test, which requires multiple
// version of same object. As this is not supported by fake-storage-server.
// Although API is exposed to enable the object versioning for a bucket,
// but it returns "method not allowed" when we call it.

package storage

import (
	"fmt"
	"io"

	"cloud.google.com/go/storage"
	"github.com/jacobsa/gcloud/gcs"
	"golang.org/x/net/context"
)

type bucketHandle struct {
	gcs.Bucket
	bucket *storage.BucketHandle
}

func (bh *bucketHandle) NewReader(
	ctx context.Context,
	req *gcs.ReadObjectRequest) (rc io.ReadCloser, err error) {
	// Initialising the starting offset and the length to be read by the reader.
	start := int64((*req.Range).Start)
	end := int64((*req.Range).Limit)
	length := int64(end - start)

	obj := bh.bucket.Object(req.Name)

	// Switching to the requested generation of object.
	if req.Generation != 0 {
		obj = obj.Generation(req.Generation)
	}

	// Creating a NewRangeReader instance.
	r, err := obj.NewRangeReader(ctx, start, length)
	if err != nil {
		err = fmt.Errorf("error in creating a NewRangeReader instance: %v", err)
		return
	}

	// Converting io.Reader to io.ReadCloser by adding a no-op closer method
	// to match the return type interface.
	rc = io.NopCloser(r)
	return
}
func (b *bucketHandle) DeleteObject(ctx context.Context, req *gcs.DeleteObjectRequest) (err error) {
	obj := b.bucket.Object(req.Name)

	// Switching to the requested generation of the object.
	if req.Generation != 0 {
		obj = obj.Generation(req.Generation)
	}
	// Putting condition that the object's MetaGeneration should match the requested MetaGeneration for deletion to occur.
	if req.MetaGenerationPrecondition != nil && *req.MetaGenerationPrecondition != 0 {
		obj = obj.If(storage.Conditions{MetagenerationMatch: *req.MetaGenerationPrecondition})
	}

	// Deleting object through Go Storage Client.
	err = obj.Delete(ctx)
	return
}
<|endoftext|>


<commit_before>// declaration of the basic alu
package standard

import (
	"encoding/binary"
	"fmt"
	"github.com/DrItanium/cores"
	"github.com/DrItanium/cores/iris2"
	"github.com/DrItanium/cores/manip"
)

const (
	tagByte = iota
	tagInt16
	tagInt32
	tagInt64
	tagEnd

	registerCount = 8
)

func init() {
	if tagEnd > 4 {
		panic(fmt.Errorf("ALU INTERNAL ERROR: %d tags are defined when the max is 4", tagEnd))
	}
}

type aluValue struct {
	dataType byte
	data     iris2.Word
}

func (this *aluValue) slice() ([]byte, error) {
	var out []byte
	switch this.dataType {
	case tagByte:
		out = make([]byte, 1)
		out[0] = byte(this.data)
	case tagInt16:
		out = make([]byte, 2)
		binary.LittleEndian.PutUint16(out, uint16(this.data))
	case tagInt32:
		out = make([]byte, 4)
		binary.LittleEndian.PutUint32(out, uint32(this.data))
	case tagInt64:
		out = make([]byte, 8)
		binary.LittleEndian.PutUint64(out, uint64(this.data))
	default:
		return nil, fmt.Errorf("Illegal data type code in alu register!")
	}
	return out, nil
}

type Alu struct {
	input     chan cores.Packet
	output    chan cores.Packet
	terminate bool
	regs      [registerCount]aluValue
}
type argument struct {
	dataType  byte
	unsigned  bool
	immediate bool
	register  byte
	data      []byte
}

var argSizeTable = []byte{1, 2, 4, 8}

func newArgument(value []byte) (*argument, int, error) {
	if len(value) == 0 {
		return nil, 0, fmt.Errorf("No bytes to parse for argument!")
	}
	count := 1
	first := value[0]
	a := argument{
		dataType:  byte(manip.Mask8(first, 0x03, 0)),
		unsigned:  manip.BitsSet8(first, 0x04, 2),
		immediate: manip.BitsSet8(first, 0x08, 3),
		register:  byte(manip.Mask8(first, 0xE0, 5)),
	}

	if a.immediate {
		if int(a.dataType) < len(argSizeTable) {
			return nil, 0, fmt.Errorf("dataType set as %d", a.dataType)
		}
		num := argSizeTable[a.dataType]
		a.data = make([]byte, num)
		copy(a.data, value[1:1+num])
		count += int(num)
	}

	return &a, count, nil
}

type instruction struct {
	op   byte
	args []*argument
}

func (this *instruction) hasArgs() bool {
	return len(this.args) != 0
}
func newInstruction(value []byte) (*instruction, error) {
	if len(value) == 0 {
		return nil, fmt.Errorf("No bytes to parse!")
	} else {
		var i instruction
		i.op = value[0]
		rest := value[1:]
		for len(rest) > 0 {
			arg, count, err := newArgument(rest)
			if err != nil {
				return nil, err
			}
			i.args = append(i.args, arg)
			rest = rest[count:]
		}
		return &i, nil
	}
}

func New() *Alu {
	var a Alu
	a.output = make(chan cores.Packet)
	a.input = make(chan cores.Packet)
	go a.parseInput()
	return &a
}

func (this *Alu) Terminate() {
	if !this.terminate {
		close(this.input)
		close(this.output)
		this.terminate = true
	}
}

const (
	nop = iota
	add
	sub
	mul
	div
	mod
	shl
	shr
	and
	or
	not
	xor
	set
	get
	lastAluOp
)

func init() {
	// make sure that we aren't going to barf on too many operations!
	if lastAluOp > 256 {
		panic(fmt.Errorf("%d alu operations defined, max is 256", lastAluOp))
	}
}

type aluOperation func(*Alu, *instruction) ([]byte, error)

func (fn aluOperation) Invoke(alu *Alu, inst *instruction) ([]byte, error) {
	return fn(alu, inst)
}

func (this *Alu) opset(inst *instruction) ([]byte, error) {
	if !inst.hasArgs() {
		return nil, fmt.Errorf("No arguments provided for the alu set operation!")
	}
	if len(inst.args) < 2 {
		return nil, fmt.Errorf("Too few arguments provided to the alu set operation!")
	} else if len(inst.args) > 2 {
		return nil, fmt.Errorf("Too many arguments provided to the alu set operation!")
	}
	first := inst.args[0]
	if first.immediate {
		return nil, fmt.Errorf("The first argument provided to the alu set operation must be a register!")
	}
	second := inst.args[1]
	if !second.immediate {
		return nil, fmt.Errorf("The second argument provided to the alu set operation must be an immediate!")
	}
	reg := &(this.regs[first.register])
	reg.dataType = second.dataType
	switch reg.dataType {
	case tagByte:
		reg.data = iris2.Word(second.data[0])
	case tagInt16:
		reg.data = iris2.Word(binary.LittleEndian.Uint16(second.data))
	case tagInt32:
		reg.data = iris2.Word(binary.LittleEndian.Uint32(second.data))
	case tagInt64:
		reg.data = iris2.Word(binary.LittleEndian.Uint64(second.data))
	default:
		return nil, fmt.Errorf("Got an illegal alu tag type during set: %d", reg.dataType)
	}
	return []byte{}, nil
}
func (this *Alu) opget(inst *instruction) ([]byte, error) {
	if !inst.hasArgs() {
		return nil, fmt.Errorf("No arguments provided for the alu get operation!")
	}
	if inst.args[0].immediate {
		return nil, fmt.Errorf("Getting an immediate does not make sense!")
	}

	if result, err1 := this.regs[inst.args[0].register].slice(); err1 != nil {
		return nil, err1
	} else {
		return result, nil
	}
}
func (this *Alu) opnop(inst *instruction) ([]byte, error) {
	if inst.hasArgs() {
		return nil, fmt.Errorf("alu nop should have no arguments!")
	} else {
		return []byte{}, nil
	}
}

//func (this *Alu) opadd(inst *instruction) ([]byte,

var lookupTable = []aluOperation{
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opnop,
	(*Alu).opset,
	(*Alu).opget,
}

func (this *Alu) parseInput() {
	for !this.terminate {
		var out cores.Packet
		input := <-this.input
		if !input.HasData() {
			out.Error = fmt.Errorf("alu: Command stream is empty")
		} else {
			if inst, err := newInstruction(input.Value); err != nil {
				out.Error = err
			} else {
				if inst.op >= lastAluOp {
					out.Error = fmt.Errorf("Illegal operation %d", inst.op)
				} else {
					out.Value, out.Error = lookupTable[inst.op].Invoke(this, inst)
				}
			}
		}
		this.output <- out
	}
}
<commit_msg>Finished reimplementing the alu for iris2<commit_after>// declaration of the basic alu
package standard

import (
	"encoding/binary"
	"fmt"
	"github.com/DrItanium/cores"
	"github.com/DrItanium/cores/iris2"
	"github.com/DrItanium/cores/manip"
)

const (
	tagByte = iota
	tagInt16
	tagInt32
	tagInt64
	tagEnd

	registerCount = 8
)

func init() {
	if tagEnd > 4 {
		panic(fmt.Errorf("ALU INTERNAL ERROR: %d tags are defined when the max is 4", tagEnd))
	}
}

type aluValue struct {
	dataType byte
	data     iris2.Word
}

func (this *aluValue) slice() ([]byte, error) {
	var out []byte
	switch this.dataType {
	case tagByte:
		out = make([]byte, 1)
		out[0] = byte(this.data)
	case tagInt16:
		out = make([]byte, 2)
		binary.LittleEndian.PutUint16(out, uint16(this.data))
	case tagInt32:
		out = make([]byte, 4)
		binary.LittleEndian.PutUint32(out, uint32(this.data))
	case tagInt64:
		out = make([]byte, 8)
		binary.LittleEndian.PutUint64(out, uint64(this.data))
	default:
		return nil, fmt.Errorf("Illegal data type code in alu register!")
	}
	return out, nil
}

type Alu struct {
	input     chan cores.Packet
	output    chan cores.Packet
	terminate bool
	regs      [registerCount]aluValue
}

func (this *Alu) setRegister(index int, value iris2.Word) error {
	if index >= registerCount {
		return fmt.Errorf("Register at index %d is not a real register (alu has %d registers)!", index, registerCount)
	} else {
		switch this.regs[index].dataType {
		case tagByte:
			this.regs[index].data = iris2.Word(byte(value))
		case tagInt16:
			this.regs[index].data = iris2.Word(int16(value))
		case tagInt32:
			this.regs[index].data = iris2.Word(int32(value))
		case tagInt64:
			this.regs[index].data = value
		}
		return nil
	}
}
func (this *Alu) getRegister(index int) ([]byte, error) {
	if index >= registerCount {
		return nil, fmt.Errorf("Register at index %d is not a real register (alu has %d registers)!", index, registerCount)
	} else {
		return this.regs[index].slice()
	}
}

type argument struct {
	dataType  byte
	unsigned  bool
	immediate bool
	register  byte
	data      []byte
}

var argSizeTable = []byte{1, 2, 4, 8}

func newArgument(value []byte) (*argument, int, error) {
	if len(value) == 0 {
		return nil, 0, fmt.Errorf("No bytes to parse for argument!")
	}
	count := 1
	first := value[0]
	a := argument{
		dataType:  byte(manip.Mask8(first, 0x03, 0)),
		unsigned:  manip.BitsSet8(first, 0x04, 2),
		immediate: manip.BitsSet8(first, 0x08, 3),
		register:  byte(manip.Mask8(first, 0xE0, 5)),
	}

	if a.immediate {
		if int(a.dataType) < len(argSizeTable) {
			return nil, 0, fmt.Errorf("dataType set as %d", a.dataType)
		}
		num := argSizeTable[a.dataType]
		a.data = make([]byte, num)
		copy(a.data, value[1:1+num])
		count += int(num)
	}

	return &a, count, nil
}

type instruction struct {
	op   byte
	args []*argument
}

func (this *instruction) hasArgs() bool {
	return len(this.args) != 0
}
func newInstruction(value []byte) (*instruction, error) {
	if len(value) == 0 {
		return nil, fmt.Errorf("No bytes to parse!")
	} else {
		var i instruction
		i.op = value[0]
		rest := value[1:]
		for len(rest) > 0 {
			arg, count, err := newArgument(rest)
			if err != nil {
				return nil, err
			}
			i.args = append(i.args, arg)
			rest = rest[count:]
		}
		return &i, nil
	}
}

func New() *Alu {
	var a Alu
	a.output = make(chan cores.Packet)
	a.input = make(chan cores.Packet)
	go a.parseInput()
	return &a
}

func (this *Alu) Terminate() {
	if !this.terminate {
		close(this.input)
		close(this.output)
		this.terminate = true
	}
}

const (
	add = iota
	sub
	mul
	div
	mod
	shl
	shr
	and
	or
	not
	xor
	nop
	set
	get
	lastAluOp
)

func init() {
	// make sure that we aren't going to barf on too many operations!
	if lastAluOp > 256 {
		panic(fmt.Errorf("%d alu operations defined, max is 256", lastAluOp))
	}
}

func (this *Alu) opset(inst *instruction) ([]byte, error) {
	first := inst.args[0]
	if first.immediate {
		return nil, fmt.Errorf("The first argument provided to the alu set operation must be a register!")
	}
	second := inst.args[1]
	if !second.immediate {
		return nil, fmt.Errorf("The second argument provided to the alu set operation must be an immediate!")
	}
	reg := &(this.regs[first.register])
	reg.dataType = second.dataType
	switch reg.dataType {
	case tagByte:
		reg.data = iris2.Word(second.data[0])
	case tagInt16:
		reg.data = iris2.Word(binary.LittleEndian.Uint16(second.data))
	case tagInt32:
		reg.data = iris2.Word(binary.LittleEndian.Uint32(second.data))
	case tagInt64:
		reg.data = iris2.Word(binary.LittleEndian.Uint64(second.data))
	}
	return []byte{}, nil
}
func (this *Alu) opget(inst *instruction) ([]byte, error) {
	first := inst.args[0]
	if first.immediate {
		return nil, fmt.Errorf("Getting an immediate does not make sense!")
	}

	if result, err1 := this.getRegister(int(first.register)); err1 != nil {
		return nil, err1
	} else {
		return result, nil
	}
}
func (this *Alu) opnop(inst *instruction) ([]byte, error) {
	return []byte{}, nil
}

type aluOperation struct {
	name                string
	requiresArguments   bool
	numberOfArguments   int
	customOperation     bool
	secondArgCantBeZero bool
	fn                  func(*Alu, *instruction) ([]byte, error)
	binaryOp            binaryOperation
}

func (this *aluOperation) invoke(alu *Alu, inst *instruction) ([]byte, error) {
	if this.requiresArguments {
		if !inst.hasArgs() {
			return nil, fmt.Errorf("Alu op %s requires arguments but none are given!", this.name)
		} else if len(inst.args) != this.numberOfArguments {
			return nil, fmt.Errorf("Alu op %s requires exactly %d arguments but %d are given!", this.name, this.numberOfArguments, len(inst.args))
		}
	} else {
		if inst.hasArgs() {
			return nil, fmt.Errorf("Alu op %s does not accept arguments but %d are given!", this.name, len(inst.args))
		}
	}
	if this.customOperation {
		return this.fn(alu, inst)
	} else {
		if this.numberOfArguments == 3 {
			destination, src0, src1 := inst.args[0], inst.args[1], inst.args[2]
			if destination.immediate {
				return nil, fmt.Errorf("Destination is tagged as an immediate!")
			} else if src0.immediate {
				return nil, fmt.Errorf("Source0 is tagged as an immediate!")
			} else if src1.immediate {
				return nil, fmt.Errorf("Source1 is tagged as an immediate!")
			} else if destination.register >= registerCount {
				return nil, fmt.Errorf("destination's associated register index (%d) is greater than %d", destination.register, registerCount)
			} else if src0.register >= registerCount {
				return nil, fmt.Errorf("src0's associated register index (%d) is greater than %d", src0.register, registerCount)
			} else if src1.register >= registerCount {
				return nil, fmt.Errorf("src1's associated register index (%d) is greater than %d", src1.register, registerCount)
			} else {
				alu.regs[destination.register].dataType = destination.dataType
				if d, s0, s1 := int(destination.register), alu.regs[src0.register].data, alu.regs[src1.register].data; this.secondArgCantBeZero && s1 == 0 {
					return nil, fmt.Errorf("Attempted to divide by zero, op is %s", this.name)
				} else if err0 := alu.setRegister(d, this.binaryOp(s0, s1)); err0 != nil {
					return nil, err0
				} else {
					return []byte{}, nil
				}
			}
		} else {
			return nil, fmt.Errorf("non three argument operations must have a custom implementation!")
		}
	}
}

func (this *Alu) unpack2(inst *instruction) (int, iris2.Word, error) {
	destination, src0 := inst.args[0], inst.args[1]
	if destination.immediate {
		return 0, 0, fmt.Errorf("Destination is tagged as an immediate!")
	} else if src0.immediate {
		return 0, 0, fmt.Errorf("Source0 is tagged as an immediate!")
	} else if destination.register >= registerCount {
		return 0, 0, fmt.Errorf("destination's associated register index (%d) is greater than %d", destination.register, registerCount)
	} else if src0.register >= registerCount {
		return 0, 0, fmt.Errorf("src0's associated register index (%d) is greater than %d", src0.register, registerCount)
	} else {
		this.regs[destination.register].dataType = destination.dataType
		return int(destination.register), this.regs[src0.register].data, nil
	}

}

type binaryOperation func(iris2.Word, iris2.Word) iris2.Word

func (fn binaryOperation) invoke(x, y iris2.Word) iris2.Word {
	return fn(x, y)
}

func (this *Alu) opnot(inst *instruction) ([]byte, error) {
	if destination, src0, err := this.unpack2(inst); err != nil {
		return nil, err
	} else {
		if err0 := this.setRegister(destination, ^src0); err0 != nil {
			return nil, err0
		} else {
			return []byte{}, nil
		}
	}
}

var lookupTable = map[int]*aluOperation{
	add: &aluOperation{"add", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x + y }},
	sub: &aluOperation{"sub", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x - y }},
	mul: &aluOperation{"mul", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x * y }},
	shl: &aluOperation{"shl", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x << y }},
	shr: &aluOperation{"shr", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x >> y }},
	and: &aluOperation{"and", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x & y }},
	or:  &aluOperation{"or", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x | y }},
	xor: &aluOperation{"xor", true, 3, false, false, nil, func(x, y iris2.Word) iris2.Word { return x ^ y }},
	div: &aluOperation{"div", true, 3, false, true, nil, func(x, y iris2.Word) iris2.Word { return x / y }},
	mod: &aluOperation{"mod", true, 3, false, true, nil, func(x, y iris2.Word) iris2.Word { return x % y }},
	nop: &aluOperation{"nop", false, 0, true, false, (*Alu).opnop, nil},
	not: &aluOperation{"not", true, 2, true, false, (*Alu).opnot, nil},
	set: &aluOperation{"set", true, 1, true, false, (*Alu).opset, nil},
	get: &aluOperation{"get", true, 2, true, false, (*Alu).opget, nil},
}

func init() {
	if len(lookupTable) != lastAluOp {
		panic(fmt.Errorf("Number of operations in dispatch table (%d) does not match number of defined operations (%d)", len(lookupTable), lastAluOp))
	}
}

func (this *Alu) parseInput() {
	for !this.terminate {
		var out cores.Packet
		input := <-this.input
		if !input.HasData() {
			out.Error = fmt.Errorf("alu: Command stream is empty")
		} else {
			if inst, err := newInstruction(input.Value); err != nil {
				out.Error = err
			} else {
				if inst.op >= lastAluOp {
					out.Error = fmt.Errorf("Illegal operation %d", inst.op)
				} else {
					out.Value, out.Error = lookupTable[int(inst.op)].invoke(this, inst)
				}
			}
		}
		this.output <- out
	}
}
<|endoftext|>


<commit_before>package application

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/disintegration/imaging"
	"github.com/getsentry/raven-go"
	"github.com/gorilla/mux"
	"github.com/jmoiron/jsonq"
	"github.com/lizdeika/gostorages"
	"github.com/lizdeika/picfit/engines"
	"github.com/lizdeika/picfit/extractors"
	"github.com/lizdeika/picfit/hash"
	"github.com/lizdeika/picfit/image"
	"github.com/lizdeika/picfit/middleware"
	"github.com/meatballhat/negroni-logrus"
	"github.com/rs/cors"
	"github.com/thoas/gokvstores"
	"github.com/thoas/muxer"
	"github.com/thoas/stats"
)

var Extractors = map[string]extractors.Extractor{
	"op":   extractors.Operation,
	"url":  extractors.URL,
	"path": extractors.Path,
}

type Shard struct {
	Depth int
	Width int
}

type Application struct {
	EnableUpload  bool
	Prefix        string
	SecretKey     string
	KVStore       gokvstores.KVStore
	SourceStorage gostorages.Storage
	DestStorage   gostorages.Storage
	Shard         Shard
	Raven         *raven.Client
	Logger        *logrus.Logger
	Engine        engines.Engine
	Jq            *jsonq.JsonQuery
}

func NewApplication() *Application {
	return &Application{
		Logger:       logrus.New(),
		EnableUpload: false,
	}
}

func NewFromConfigPath(path string) (*Application, error) {
	content, err := ioutil.ReadFile(path)

	if err != nil {
		return nil, fmt.Errorf("Your config file %s cannot be loaded: %s", path, err)
	}

	return NewFromConfig(string(content))
}

func NewFromConfig(content string) (*Application, error) {
	data := map[string]interface{}{}
	dec := json.NewDecoder(strings.NewReader(content))
	err := dec.Decode(&data)

	if err != nil {
		return nil, fmt.Errorf("Your config file %s cannot be parsed: %s", content, err)
	}

	jq := jsonq.NewQuery(data)

	return NewFromJsonQuery(jq)
}

func NewFromJsonQuery(jq *jsonq.JsonQuery) (*Application, error) {
	app := NewApplication()
	app.Jq = jq

	for _, initializer := range Initializers {
		err := initializer(jq, app)

		if err != nil {
			return nil, fmt.Errorf("An error occured during init: %s", err)
		}
	}

	return app, nil
}

func (app *Application) ServeHTTP(h Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		con := app.KVStore.Connection()
		defer con.Close()

		res := muxer.NewResponse(w)

		request, err := NewRequest(req, con, app.Jq)

		if err != nil {
			app.Logger.Error(err)

			res.BadRequest()

			return
		}

		if app.SecretKey != "" && !request.IsAuthorized(app.SecretKey) {
			res.Unauthorized()

			return
		}

		h(res, request, app)
	})
}

func (a *Application) InitRouter() *negroni.Negroni {
	router := mux.NewRouter()
	router.NotFoundHandler = NotFoundHandler()

	methods := map[string]Handler{
		"redirect": RedirectHandler,
		"display":  ImageHandler,
		"get":      GetHandler,
	}

	for name, handler := range methods {
		handlerFunc := a.ServeHTTP(handler)

		router.Handle(fmt.Sprintf("/%s", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/x{h:[\\d]+}/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/{w:[\\d]+}x/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/x{h:[\\d]+}/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/{w:[\\d]+}x/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/.]+}", name), handlerFunc)

		router.Handle(fmt.Sprintf("/%s/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/.]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{path:[\\w\\-/.]+}", name), handlerFunc)
	}

	// router.Handle("/upload", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
	// 	res := muxer.NewResponse(w)
	//
	// 	UploadHandler(res, req, a)
	// }))

	allowedOrigins, err := a.Jq.ArrayOfStrings("allowed_origins")
	allowedMethods, err := a.Jq.ArrayOfStrings("allowed_methods")

	s := stats.New()

	router.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		stats := s.Data()

		b, _ := json.Marshal(stats)

		w.Write(b)
	})

	debug, err := a.Jq.Bool("debug")

	if err != nil {
		debug = false
	}

	n := negroni.New(&middleware.Recovery{
		Raven:      a.Raven,
		Logger:     a.Logger,
		PrintStack: debug,
		StackAll:   false,
		StackSize:  1024 * 8,
	}, &middleware.Logger{a.Logger})
	n.Use(cors.New(cors.Options{
		AllowedOrigins: allowedOrigins,
		AllowedMethods: allowedMethods,
	}))
	n.Use(negronilogrus.NewMiddleware())
	n.UseHandler(router)

	return n
}

func (a *Application) Port() int {
	port, err := a.Jq.Int("port")

	if err != nil {
		port = DefaultPort
	}

	return port
}

func (a *Application) ShardFilename(filename string) string {
	results := hash.Shard(filename, a.Shard.Width, a.Shard.Depth, true)

	return strings.Join(results, "/")
}

func (a *Application) Store(i *image.ImageFile, args ...string) error {
	con := a.KVStore.Connection()
	defer con.Close()

	err := i.Save()

	if err != nil {
		a.Logger.Fatal(err)
		return err
	}

	tipe := "thumbnail"
	if len(args) > 0 {
		tipe = args[0]
	}

	a.Logger.Infof("Save %s %s to storage", tipe, i.Filepath)

	key := a.WithPrefix(i.Key)

	err = con.Set(key, i.Filepath)

	if err != nil {
		a.Logger.Fatal(err)

		return err
	}

	a.Logger.Infof("Save key %s => %s to kvstore", key, i.Filepath)

	return nil
}

func (a *Application) WithPrefix(str string) string {
	return a.Prefix + str
}

func (a *Application) ImageFileFromRequest(req *Request, async bool, load bool) (*image.ImageFile, error) {
	var file *image.ImageFile = &image.ImageFile{
		Key:     req.Key,
		Storage: a.DestStorage,
		Headers: map[string]string{},
	}
	var err error

	key := a.WithPrefix(req.Key)

	// Image from the KVStore found
	stored, _ := gokvstores.String(req.Connection.Get(key))

	file.Filepath = stored

	if stored != "" {
		a.Logger.Infof("Key %s found in kvstore: %s", key, stored)

		if load {
			file, err = image.FromStorage(a.DestStorage, stored)

			if file == nil || err != nil {
				stored = ""
				err = nil
			}

			// if err != nil {
			// 	return nil, err
			// }
		}
	}

	if stored == "" {
		a.Logger.Infof("Key %s not found in kvstore OR file not found in dst", key)

		// Image not found from the KVStore, we need to process it
		// URL or Path available in Query String
		cacheOriginal := false
		fileKey := ""
		kvKey := ""
		if req.URL != nil {
			return nil, errors.New("404")
		} else {
			// URL provided we use http protocol to retrieve it
			fileKey = hash.Tokey(hash.Serialize(req.Filepath))
			kvKey = a.WithPrefix(fileKey)
			fileStored, err := gokvstores.String(req.Connection.Get(kvKey))
			if fileStored != "" {
				a.Logger.Infof("Key %s for original found in kvstore: %s", kvKey, fileStored)

				if load {
					file, err = image.FromStorage(a.DestStorage, fileStored)
					// not found in dest storage? Try getting from src storage
					if file == nil || err != nil {
						a.Logger.Infof("File %s for key %s not found in dst, try reget from src", fileStored, kvKey)
						file, err = image.FromStorage(a.SourceStorage, req.Filepath)
						if file == nil {
							return nil, errors.New("404")
						}
						cacheOriginal = true
					}
				}
			} else {
				file, err = image.FromStorage(a.SourceStorage, req.Filepath)
				if file == nil {
					return nil, errors.New("404")
				}
				cacheOriginal = true
			}
		}

		if err != nil {
			return nil, err
		}

		if cacheOriginal == true && fileKey != "" {
			file.Key = fileKey
			file.Storage = a.DestStorage
			file.Filepath = fmt.Sprintf("%s.%s", a.ShardFilename(fileKey), file.Format())
			if async == true {
				go a.Store(file, "original")
			} else {
				err = a.Store(file, "original")
			}
		}

		if err != nil {
			return nil, err
		}

		imageOrig, err := imaging.Decode(bytes.NewReader(file.Source))
		if err != nil {
			return nil, err
		}
		width, height := engines.ImageSize(imageOrig)
		rw, err := strconv.Atoi(req.QueryString["w"])
		if err != nil {
			return nil, err
		}
		rh, err := strconv.Atoi(req.QueryString["h"])
		if err != nil {
			return nil, err
		}
		// if rw < width && rh < height {
		// 	file, err = a.Engine.Transform(file, req.Operation, req.QueryString)
		// } else {
		// 	stored = "do not store"
		// }
		if rw > width {
			req.QueryString["w"] = strconv.Itoa(width)
		}
		if rh > height {
			req.QueryString["h"] = strconv.Itoa(height)
		}
		file, err = a.Engine.Transform(file, req.Operation, req.QueryString)

		if err != nil {
			return nil, err
		}
	}

	file.Headers["Content-Type"] = file.ContentType()
	file.Headers["ETag"] = req.Key

	if stored == "" {
		file.Filepath = fmt.Sprintf("%s.%s", a.ShardFilename(req.Key), file.Format())
		file.Key = req.Key
		file.Storage = a.DestStorage
		if async == true {
			go a.Store(file)
		} else {
			err = a.Store(file)
		}
	}

	return file, err
}
<commit_msg>handle spaces<commit_after>package application

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/negroni"
	"github.com/disintegration/imaging"
	"github.com/getsentry/raven-go"
	"github.com/gorilla/mux"
	"github.com/jmoiron/jsonq"
	"github.com/lizdeika/gostorages"
	"github.com/lizdeika/picfit/engines"
	"github.com/lizdeika/picfit/extractors"
	"github.com/lizdeika/picfit/hash"
	"github.com/lizdeika/picfit/image"
	"github.com/lizdeika/picfit/middleware"
	"github.com/meatballhat/negroni-logrus"
	"github.com/rs/cors"
	"github.com/thoas/gokvstores"
	"github.com/thoas/muxer"
	"github.com/thoas/stats"
)

var Extractors = map[string]extractors.Extractor{
	"op":   extractors.Operation,
	"url":  extractors.URL,
	"path": extractors.Path,
}

type Shard struct {
	Depth int
	Width int
}

type Application struct {
	EnableUpload  bool
	Prefix        string
	SecretKey     string
	KVStore       gokvstores.KVStore
	SourceStorage gostorages.Storage
	DestStorage   gostorages.Storage
	Shard         Shard
	Raven         *raven.Client
	Logger        *logrus.Logger
	Engine        engines.Engine
	Jq            *jsonq.JsonQuery
}

func NewApplication() *Application {
	return &Application{
		Logger:       logrus.New(),
		EnableUpload: false,
	}
}

func NewFromConfigPath(path string) (*Application, error) {
	content, err := ioutil.ReadFile(path)

	if err != nil {
		return nil, fmt.Errorf("Your config file %s cannot be loaded: %s", path, err)
	}

	return NewFromConfig(string(content))
}

func NewFromConfig(content string) (*Application, error) {
	data := map[string]interface{}{}
	dec := json.NewDecoder(strings.NewReader(content))
	err := dec.Decode(&data)

	if err != nil {
		return nil, fmt.Errorf("Your config file %s cannot be parsed: %s", content, err)
	}

	jq := jsonq.NewQuery(data)

	return NewFromJsonQuery(jq)
}

func NewFromJsonQuery(jq *jsonq.JsonQuery) (*Application, error) {
	app := NewApplication()
	app.Jq = jq

	for _, initializer := range Initializers {
		err := initializer(jq, app)

		if err != nil {
			return nil, fmt.Errorf("An error occured during init: %s", err)
		}
	}

	return app, nil
}

func (app *Application) ServeHTTP(h Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		con := app.KVStore.Connection()
		defer con.Close()

		res := muxer.NewResponse(w)

		request, err := NewRequest(req, con, app.Jq)

		if err != nil {
			app.Logger.Error(err)

			res.BadRequest()

			return
		}

		if app.SecretKey != "" && !request.IsAuthorized(app.SecretKey) {
			res.Unauthorized()

			return
		}

		h(res, request, app)
	})
}

func (a *Application) InitRouter() *negroni.Negroni {
	router := mux.NewRouter()
	router.NotFoundHandler = NotFoundHandler()

	methods := map[string]Handler{
		"redirect": RedirectHandler,
		"display":  ImageHandler,
		"get":      GetHandler,
	}

	for name, handler := range methods {
		handlerFunc := a.ServeHTTP(handler)

		router.Handle(fmt.Sprintf("/%s", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/x{h:[\\d]+}/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/{w:[\\d]+}x/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{sig}/{op}/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/x{h:[\\d]+}/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/{w:[\\d]+}x/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{op}/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/. ]+}", name), handlerFunc)

		router.Handle(fmt.Sprintf("/%s/{w:[\\d]+}x{h:[\\d]+}/{path:[\\w\\-/. ]+}", name), handlerFunc)
		router.Handle(fmt.Sprintf("/%s/{path:[\\w\\-/. ]+}", name), handlerFunc)
	}

	// router.Handle("/upload", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
	// 	res := muxer.NewResponse(w)
	//
	// 	UploadHandler(res, req, a)
	// }))

	allowedOrigins, err := a.Jq.ArrayOfStrings("allowed_origins")
	allowedMethods, err := a.Jq.ArrayOfStrings("allowed_methods")

	s := stats.New()

	router.HandleFunc("/stats", func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")

		stats := s.Data()

		b, _ := json.Marshal(stats)

		w.Write(b)
	})

	debug, err := a.Jq.Bool("debug")

	if err != nil {
		debug = false
	}

	n := negroni.New(&middleware.Recovery{
		Raven:      a.Raven,
		Logger:     a.Logger,
		PrintStack: debug,
		StackAll:   false,
		StackSize:  1024 * 8,
	}, &middleware.Logger{a.Logger})
	n.Use(cors.New(cors.Options{
		AllowedOrigins: allowedOrigins,
		AllowedMethods: allowedMethods,
	}))
	n.Use(negronilogrus.NewMiddleware())
	n.UseHandler(router)

	return n
}

func (a *Application) Port() int {
	port, err := a.Jq.Int("port")

	if err != nil {
		port = DefaultPort
	}

	return port
}

func (a *Application) ShardFilename(filename string) string {
	results := hash.Shard(filename, a.Shard.Width, a.Shard.Depth, true)

	return strings.Join(results, "/")
}

func (a *Application) Store(i *image.ImageFile, args ...string) error {
	con := a.KVStore.Connection()
	defer con.Close()

	err := i.Save()

	if err != nil {
		a.Logger.Fatal(err)
		return err
	}

	tipe := "thumbnail"
	if len(args) > 0 {
		tipe = args[0]
	}

	a.Logger.Infof("Save %s %s to storage", tipe, i.Filepath)

	key := a.WithPrefix(i.Key)

	err = con.Set(key, i.Filepath)

	if err != nil {
		a.Logger.Fatal(err)

		return err
	}

	a.Logger.Infof("Save key %s => %s to kvstore", key, i.Filepath)

	return nil
}

func (a *Application) WithPrefix(str string) string {
	return a.Prefix + str
}

func (a *Application) ImageFileFromRequest(req *Request, async bool, load bool) (*image.ImageFile, error) {
	var file *image.ImageFile = &image.ImageFile{
		Key:     req.Key,
		Storage: a.DestStorage,
		Headers: map[string]string{},
	}
	var err error

	key := a.WithPrefix(req.Key)

	// Image from the KVStore found
	stored, _ := gokvstores.String(req.Connection.Get(key))

	file.Filepath = stored

	if stored != "" {
		a.Logger.Infof("Key %s found in kvstore: %s", key, stored)

		if load {
			file, err = image.FromStorage(a.DestStorage, stored)

			if file == nil || err != nil {
				stored = ""
				err = nil
			}

			// if err != nil {
			// 	return nil, err
			// }
		}
	}

	if stored == "" {
		a.Logger.Infof("Key %s not found in kvstore OR file not found in dst", key)

		// Image not found from the KVStore, we need to process it
		// URL or Path available in Query String
		cacheOriginal := false
		fileKey := ""
		kvKey := ""
		if req.URL != nil {
			return nil, errors.New("404")
		} else {
			// URL provided we use http protocol to retrieve it
			fileKey = hash.Tokey(hash.Serialize(req.Filepath))
			kvKey = a.WithPrefix(fileKey)
			fileStored, err := gokvstores.String(req.Connection.Get(kvKey))
			if fileStored != "" {
				a.Logger.Infof("Key %s for original found in kvstore: %s", kvKey, fileStored)

				if load {
					file, err = image.FromStorage(a.DestStorage, fileStored)
					// not found in dest storage? Try getting from src storage
					if file == nil || err != nil {
						a.Logger.Infof("File %s for key %s not found in dst, try reget from src", fileStored, kvKey)
						file, err = image.FromStorage(a.SourceStorage, req.Filepath)
						if file == nil {
							return nil, errors.New("404")
						}
						cacheOriginal = true
					}
				}
			} else {
				file, err = image.FromStorage(a.SourceStorage, req.Filepath)
				if file == nil {
					return nil, errors.New("404")
				}
				cacheOriginal = true
			}
		}

		if err != nil {
			return nil, err
		}

		if cacheOriginal == true && fileKey != "" {
			file.Key = fileKey
			file.Storage = a.DestStorage
			file.Filepath = fmt.Sprintf("%s.%s", a.ShardFilename(fileKey), file.Format())
			if async == true {
				go a.Store(file, "original")
			} else {
				err = a.Store(file, "original")
			}
		}

		if err != nil {
			return nil, err
		}

		imageOrig, err := imaging.Decode(bytes.NewReader(file.Source))
		if err != nil {
			return nil, err
		}
		width, height := engines.ImageSize(imageOrig)
		rw, err := strconv.Atoi(req.QueryString["w"])
		if err != nil {
			return nil, err
		}
		rh, err := strconv.Atoi(req.QueryString["h"])
		if err != nil {
			return nil, err
		}
		// if rw < width && rh < height {
		// 	file, err = a.Engine.Transform(file, req.Operation, req.QueryString)
		// } else {
		// 	stored = "do not store"
		// }
		if rw > width {
			req.QueryString["w"] = strconv.Itoa(width)
		}
		if rh > height {
			req.QueryString["h"] = strconv.Itoa(height)
		}
		file, err = a.Engine.Transform(file, req.Operation, req.QueryString)

		if err != nil {
			return nil, err
		}
	}

	file.Headers["Content-Type"] = file.ContentType()
	file.Headers["ETag"] = req.Key

	if stored == "" {
		file.Filepath = fmt.Sprintf("%s.%s", a.ShardFilename(req.Key), file.Format())
		file.Key = req.Key
		file.Storage = a.DestStorage
		if async == true {
			go a.Store(file)
		} else {
			err = a.Store(file)
		}
	}

	return file, err
}
<|endoftext|>


<commit_before>package utils

import (
	"net/url"
)

type Redirect struct {
	Id      uint
	Referer string
	Url     string
	Link    string
}

// Redirect to the correct imageboard after post
func (r *Redirect) Link() (err error) {

	// Get Database handle
	db, err := u.GetDb()
	if err != nil {
		return
	}

	// Get the url of the imageboard from the database
	err = db.QueryRow("SELECT ib_domain FROM imageboards WHERE ib_id = ?", r.Id).Scan(&r.Url)
	if err != nil {
		return
	}

	// Get the scheme from the referer
	parsed, err := url.Parse(r.Referer)
	if err != nil {
		return
	}

	// Create url
	redir := &url.URL{
		Scheme: parsed.Scheme,
		Host:   r.Url,
	}

	// set the link
	r.Link = redir.String()

	return

}
<commit_msg>new redirect links<commit_after>package utils

import (
	"net/url"
)

type Redirect struct {
	Id      uint
	Referer string
	Host    string
	Url     string
}

// Redirect to the correct imageboard after post
func (r *Redirect) Link() (err error) {

	// Get Database handle
	db, err := GetDb()
	if err != nil {
		return
	}

	// Get the url of the imageboard from the database
	err = db.QueryRow("SELECT ib_domain FROM imageboards WHERE ib_id = ?", r.Id).Scan(&r.Host)
	if err != nil {
		return
	}

	// Get the scheme from the referer
	parsed, err := url.Parse(r.Referer)
	if err != nil {
		return
	}

	// Create url
	redir := &url.URL{
		Scheme: parsed.Scheme,
		Host:   r.Host,
	}

	// set the link
	r.Url = redir.String()

	return

}
<|endoftext|>


<commit_before>package utils

// TSTNode represents the ternary search trie node
type TSTNode struct {
	Value               interface{}
	Cb                  byte
	Left, Middle, Right *TSTNode
}

type TernarySearchTrie struct {
	Root *TSTNode
}

func NewTST() *TernarySearchTrie {
	return &TernarySearchTrie{
		Root: &TSTNode{},
	}
}

func (t *TernarySearchTrie) Put(key string, val interface{}) {
	t.Root = put(t.Root, key, val, 0)
}

func put(node *TSTNode, key string, val interface{}, d int) *TSTNode {
	c := key[d]
	if node == nil {
		node = &TSTNode{
			Cb: c,
		}
	}
	if c < node.Cb {
		//fmt.Printf("node.Cb: %c, and c: %c,go to left\n", node.Cb, c)
		node.Left = put(node.Left, key, val, d)
	} else if c > node.Cb {
		//fmt.Printf("node.Cb: %c, and c: %c,go to right\n", node.Cb, c)
		node.Right = put(node.Right, key, val, d)
	} else if d < len(key)-1 {
		//fmt.Printf("node.Cb: %c, and c: %c,go to Middle\n", node.Cb, c)
		node.Middle = put(node.Middle, key, val, d+1)
	} else {
		//fmt.Printf("node.c: %c, d=%d, len(key):%d\n", node.Cb, d, len(key))
		node.Value = val
	}
	return node
}

func (t *TernarySearchTrie) LongestPrefixOf(query string) string {
	length := search(t.Root, query, 0, 0)
	return query[:length]
}

func search(node *TSTNode, query string, d, length int) int {
	if node == nil {
		return length
	}
	if node.Value != nil {
		length = d + 1 // d+1 means the actually length
	}
	if d == len(query) {
		return length
	}
	c := query[d]
	if c < node.Cb {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Left\n", node.Cb, c)
		return search(node.Left, query, d, length)
	} else if c > node.Cb {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Right\n", node.Cb, c)
		return search(node.Right, query, d, length)
	} else if d < len(query) {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Middle with d:%d, and query:%d\n", node.Cb, c, d, len(query))
		return search(node.Middle, query, d+1, length)
	}
	return length
}

func (t *TernarySearchTrie) Contains(key string) bool {
	return t.Get(key) != nil
}

func (t *TernarySearchTrie) Get(key string) interface{} {
	x := get(t.Root, key, 0)
	if x == nil {
		return nil
	}
	return x.Value
}

func get(node *TSTNode, key string, d int) *TSTNode {
	if node == nil {
		return nil
	}
	c := key[d]
	if c < node.Cb {
		return get(node.Left, key, d)
	} else if c > node.Cb {
		return get(node.Right, key, d)
	} else if d < len(key)-1 {
		return get(node.Middle, key, d+1)
	} else {
		return node
	}
}
<commit_msg>fix: ternary search trie is not a R-way trie, root is not empty<commit_after>package utils

// TSTNode represents the ternary search trie node
type TSTNode struct {
	Value               interface{}
	Cb                  byte
	Left, Middle, Right *TSTNode
}

type TernarySearchTrie struct {
	Root *TSTNode
}

func NewTST() *TernarySearchTrie {
	return &TernarySearchTrie{
		//	Root: &TSTNode{}, not a R-way trie, root is not empty
	}
}

func (t *TernarySearchTrie) Put(key string, val interface{}) {
	t.Root = put(t.Root, key, val, 0)
}

func put(node *TSTNode, key string, val interface{}, d int) *TSTNode {
	c := key[d]
	if node == nil {
		node = &TSTNode{
			Cb: c,
		}
	}
	if c < node.Cb {
		//fmt.Printf("node.Cb: %c, and c: %c,go to left\n", node.Cb, c)
		node.Left = put(node.Left, key, val, d)
	} else if c > node.Cb {
		//fmt.Printf("node.Cb: %c, and c: %c,go to right\n", node.Cb, c)
		node.Right = put(node.Right, key, val, d)
	} else if d < len(key)-1 {
		//fmt.Printf("node.Cb: %c, and c: %c,go to Middle\n", node.Cb, c)
		node.Middle = put(node.Middle, key, val, d+1)
	} else {
		//fmt.Printf("node.c: %c, d=%d, len(key):%d\n", node.Cb, d, len(key))
		node.Value = val
	}
	return node
}

func (t *TernarySearchTrie) LongestPrefixOf(query string) string {
	length := search(t.Root, query, 0, 0)
	return query[:length]
}

func search(node *TSTNode, query string, d, length int) int {
	if node == nil {
		return length
	}
	if node.Value != nil {
		length = d + 1 // d+1 means the actually length
	}
	if d == len(query) {
		return length
	}
	c := query[d]
	if c < node.Cb {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Left\n", node.Cb, c)
		return search(node.Left, query, d, length)
	} else if c > node.Cb {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Right\n", node.Cb, c)
		return search(node.Right, query, d, length)
	} else if d < len(query) {
		// fmt.Printf("node.Cb: %c, and c: %c,go to Middle with d:%d, and query:%d\n", node.Cb, c, d, len(query))
		return search(node.Middle, query, d+1, length)
	}
	return length
}

func (t *TernarySearchTrie) Contains(key string) bool {
	return t.Get(key) != nil
}

func (t *TernarySearchTrie) Get(key string) interface{} {
	x := get(t.Root, key, 0)
	if x == nil {
		return nil
	}
	return x.Value
}

func get(node *TSTNode, key string, d int) *TSTNode {
	if node == nil {
		return nil
	}
	c := key[d]
	if c < node.Cb {
		return get(node.Left, key, d)
	} else if c > node.Cb {
		return get(node.Right, key, d)
	} else if d < len(key)-1 {
		return get(node.Middle, key, d+1)
	} else {
		return node
	}
}
<|endoftext|>


<commit_before>package utils

import (
	"database/sql"
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-post/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	ErrUserNotExist     error = errors.New("User does not exist")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	send    chan *User
	receive chan *User
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
	err             error  `json:"-"`
}

func UserInit() {
	// make worker channel
	userdataWorker = &userWorker{
		send:    make(chan *User, 64),
		receive: make(chan *User, 64),
	}

	go func() {

		// Get Database handle
		db, err := GetDb()
		if err != nil {
			fmt.Println(err)
			return
		}

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			fmt.Println(err)
			return
		}

		// range through tasks channel
		for u := range userdataWorker.send {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				u.err = err
			}

			// send back data
			userdataWorker.receive <- u

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	// send to worker
	userdataWorker.send <- u

	// block until done
	<-userdataWorker.receive

	// check error
	if u.err == sql.ErrNoRows {
		return ErrUserNotExist
	} else if u.err != nil {
		return e.ErrInternalError
	}

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<commit_msg>add manual init for userinfo worker<commit_after>package utils

import (
	"database/sql"
	"errors"
	"fmt"

	e "github.com/techjanitor/pram-post/errors"
)

var (
	ErrUserNotConfirmed error = errors.New("Account not confirmed")
	ErrUserBanned       error = errors.New("Account banned")
	ErrUserLocked       error = errors.New("Account locked")
	ErrUserNotExist     error = errors.New("User does not exist")
	userdataWorker      *userWorker
)

// struct for database insert worker
type userWorker struct {
	send    chan *User
	receive chan *User
}

// user struct
type User struct {
	Id              uint   `json:"id"`
	Name            string `json:"name"`
	Email           string `json:"email"`
	Group           uint   `json:"group"`
	IsConfirmed     bool   `json:"-"`
	IsLocked        bool   `json:"-"`
	IsBanned        bool   `json:"-"`
	IsAuthenticated bool   `json:"-"`
	err             error  `json:"-"`
}

func UserInit() {

	fmt.Println("Initializing User Info Worker...")

	// make worker channel
	userdataWorker = &userWorker{
		send:    make(chan *User, 64),
		receive: make(chan *User, 64),
	}

	go func() {

		// Get Database handle
		db, err := GetDb()
		if err != nil {
			fmt.Println(err)
			return
		}

		// prepare query for users table
		ps1, err := db.Prepare("SELECT usergroup_id,user_name,user_email,user_confirmed,user_locked,user_banned FROM users WHERE user_id = ?")
		if err != nil {
			fmt.Println(err)
			return
		}

		// range through tasks channel
		for u := range userdataWorker.send {

			// input data
			err = ps1.QueryRow(u.Id).Scan(&u.Group, &u.Name, &u.Email, &u.IsConfirmed, &u.IsLocked, &u.IsBanned)
			if err != nil {
				u.err = err
			}

			// send back data
			userdataWorker.receive <- u

		}

	}()

}

// get the user info from id
func (u *User) Info() (err error) {

	// this needs an id
	if u.Id == 0 || u.Id == 1 {
		return e.ErrInvalidParam
	}

	// send to worker
	userdataWorker.send <- u

	// block until done
	<-userdataWorker.receive

	// check error
	if u.err == sql.ErrNoRows {
		return ErrUserNotExist
	} else if u.err != nil {
		return e.ErrInternalError
	}

	// if account is not confirmed
	if !u.IsConfirmed {
		return ErrUserNotConfirmed
	}

	// if locked
	if u.IsLocked {
		return ErrUserLocked
	}

	// if banned
	if u.IsBanned {
		return ErrUserBanned
	}

	// mark authenticated
	u.IsAuthenticated = true

	return

}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Apcera Inc. All rights reserved.

package test

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/apcera/nats"
)

func TestServerRestartReSliceIssue(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// msg to send..
	msg := []byte("Hello World")

	servers := []string{urlA, urlB}

	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000

	reconnects := int32(0)
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		atomic.AddInt32(&reconnects, 1)
		reconnectsDone <- true
	}

	// Create 20 random clients.
	// Half connected to A and half to B..
	numClients := 20
	for i := 0; i < numClients; i++ {
		opts.Url = servers[i%2]
		nc, err := opts.Connect()
		defer nc.Close()

		if err != nil {
			t.Fatalf("Failed to create connection: %v\n", err)
		}
		// Create 10 subscriptions each..
		for x := 0; x < 10; x++ {
			subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
			nc.Subscribe(subject, func(m *nats.Msg) {
				// Just eat it..
			})
		}
		// Pick one subject to send to..
		subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
		go func() {
			time.Sleep(10 * time.Millisecond)
			for i := 1; 1 <= 100; i++ {
				nc.Publish(subject, msg)
				if i%10 == 0 {
					time.Sleep(time.Millisecond)
				}
			}
		}()
	}

	// Wait for a short bit..
	time.Sleep(20 * time.Millisecond)

	// Restart SrvB
	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	select {
	case <-reconnectsDone:
		break
	case <-time.After(2 * time.Second):
		t.Fatalf("Expected %d reconnects, got %d\n", numClients/2, reconnects)
	}
}

// This will test queue subscriber semantics across a cluster in the presence
// of server restarts.
func TestServerRestartAndQueueSubs(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// Client options
	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000
	opts.NoRandomize = true

	// Allow us to block on a reconnect completion.
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		reconnectsDone <- true
	}

	// Helper to wait on a reconnect.
	waitOnReconnect := func() {
		var rcs int64
		for {
			select {
			case <-reconnectsDone:
				atomic.AddInt64(&rcs, 1)
				if rcs >= 2 {
					return
				}
			case <-time.After(2 * time.Second):
				t.Fatalf("Expected a reconnect, timedout!\n")
			}
		}
	}

	// Create two clients..
	opts.Servers = []string{urlA}
	nc1, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	opts.Servers = []string{urlB}
	nc2, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}

	c1, _ := nats.NewEncodedConn(nc1, "json")
	defer c1.Close()
	c2, _ := nats.NewEncodedConn(nc2, "json")
	defer c2.Close()

	// Flusher helper function.
	flush := func() {
		// Wait for processing.
		c1.Flush()
		c2.Flush()
		// Wait for a short bit for cluster propogation.
		time.Sleep(50 * time.Millisecond)
	}

	// To hold queue results.
	results := make(map[int]int)
	var mu sync.Mutex

	// This corresponds to the subsriptions below.
	const ExpectedMsgCount = 3

	// Make sure we got what we needed, 1 msg only and all seqnos accounted for..
	checkResults := func(numSent int) {
		mu.Lock()
		defer mu.Unlock()

		for i := 0; i < numSent; i++ {
			if results[i] != ExpectedMsgCount {
				t.Fatalf("Received incorrect number of messages, [%d] for seq: %d\n", results[i], i)
			}
		}

		// Auto reset results map
		results = make(map[int]int)
	}

	subj := "foo.bar"
	qgroup := "workers"

	cb := func(seqno int) {
		mu.Lock()
		defer mu.Unlock()
		results[seqno] = results[seqno] + 1
	}

	// Create queue subscribers
	c1.QueueSubscribe(subj, qgroup, cb)
	c2.QueueSubscribe(subj, qgroup, cb)

	// Do a wildcard subscription.
	c1.Subscribe("foo.*", cb)
	c2.Subscribe("foo.*", cb)

	// Wait for processing.
	flush()

	sendAndCheckMsgs := func(numToSend int) {
		for i := 0; i < numToSend; i++ {
			if i%2 == 0 {
				c1.Publish(subj, i)
			} else {
				c2.Publish(subj, i)
			}
		}
		// Wait for processing.
		flush()
		// Check Results
		checkResults(numToSend)
	}

	////////////////////////////////////////////////////////////////////////////
	// Base Test
	////////////////////////////////////////////////////////////////////////////

	// Now send 10 messages, from each client..
	sendAndCheckMsgs(10)

	////////////////////////////////////////////////////////////////////////////
	// Now restart SrvA and srvB, re-run test
	////////////////////////////////////////////////////////////////////////////

	srvA.Shutdown()
	srvA = RunServer(optsA)
	defer srvA.Shutdown()

	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	waitOnReconnect()

	time.Sleep(50 * time.Millisecond)

	// Now send another 10 messages, from each client..
	sendAndCheckMsgs(10)
}

// This will test request semantics across a route
func TestRequestsAcrossRoutes(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect responder to srvA
	nc1.Subscribe("foo-req", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}

// This will test request semantics across a route to queues
func TestRequestsAcrossRoutesToQueues(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	ec1, _ := nats.NewEncodedConn(nc1, nats.JSON_ENCODER)
	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect one responder to srvA
	nc1.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	// Connect the other responder to srvB
	nc2.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc2.Publish(m.Reply, response)
	})

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}

	for i := 0; i < 100; i++ {
		if err := ec1.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}
<commit_msg>close connections for test, return on err for pub<commit_after>// Copyright 2013-2014 Apcera Inc. All rights reserved.

package test

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/apcera/nats"
)

func TestServerRestartReSliceIssue(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// msg to send..
	msg := []byte("Hello World")

	servers := []string{urlA, urlB}

	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000

	reconnects := int32(0)
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		atomic.AddInt32(&reconnects, 1)
		reconnectsDone <- true
	}

	// Create 20 random clients.
	// Half connected to A and half to B..
	numClients := 20
	for i := 0; i < numClients; i++ {
		opts.Url = servers[i%2]
		nc, err := opts.Connect()
		defer nc.Close()

		if err != nil {
			t.Fatalf("Failed to create connection: %v\n", err)
		}
		// Create 10 subscriptions each..
		for x := 0; x < 10; x++ {
			subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
			nc.Subscribe(subject, func(m *nats.Msg) {
				// Just eat it..
			})
		}
		// Pick one subject to send to..
		subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
		go func() {
			time.Sleep(10 * time.Millisecond)
			for i := 1; 1 <= 100; i++ {
				if err := nc.Publish(subject, msg); err != nil {
					return
				}
				if i%10 == 0 {
					time.Sleep(time.Millisecond)
				}
			}
		}()
	}

	// Wait for a short bit..
	time.Sleep(20 * time.Millisecond)

	// Restart SrvB
	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	select {
	case <-reconnectsDone:
		break
	case <-time.After(2 * time.Second):
		t.Fatalf("Expected %d reconnects, got %d\n", numClients/2, reconnects)
	}
}

// This will test queue subscriber semantics across a cluster in the presence
// of server restarts.
func TestServerRestartAndQueueSubs(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// Client options
	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000
	opts.NoRandomize = true

	// Allow us to block on a reconnect completion.
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		reconnectsDone <- true
	}

	// Helper to wait on a reconnect.
	waitOnReconnect := func() {
		var rcs int64
		for {
			select {
			case <-reconnectsDone:
				atomic.AddInt64(&rcs, 1)
				if rcs >= 2 {
					return
				}
			case <-time.After(2 * time.Second):
				t.Fatalf("Expected a reconnect, timedout!\n")
			}
		}
	}

	// Create two clients..
	opts.Servers = []string{urlA}
	nc1, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	opts.Servers = []string{urlB}
	nc2, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}

	c1, _ := nats.NewEncodedConn(nc1, "json")
	defer c1.Close()
	c2, _ := nats.NewEncodedConn(nc2, "json")
	defer c2.Close()

	// Flusher helper function.
	flush := func() {
		// Wait for processing.
		c1.Flush()
		c2.Flush()
		// Wait for a short bit for cluster propogation.
		time.Sleep(50 * time.Millisecond)
	}

	// To hold queue results.
	results := make(map[int]int)
	var mu sync.Mutex

	// This corresponds to the subsriptions below.
	const ExpectedMsgCount = 3

	// Make sure we got what we needed, 1 msg only and all seqnos accounted for..
	checkResults := func(numSent int) {
		mu.Lock()
		defer mu.Unlock()

		for i := 0; i < numSent; i++ {
			if results[i] != ExpectedMsgCount {
				t.Fatalf("Received incorrect number of messages, [%d] for seq: %d\n", results[i], i)
			}
		}

		// Auto reset results map
		results = make(map[int]int)
	}

	subj := "foo.bar"
	qgroup := "workers"

	cb := func(seqno int) {
		mu.Lock()
		defer mu.Unlock()
		results[seqno] = results[seqno] + 1
	}

	// Create queue subscribers
	c1.QueueSubscribe(subj, qgroup, cb)
	c2.QueueSubscribe(subj, qgroup, cb)

	// Do a wildcard subscription.
	c1.Subscribe("foo.*", cb)
	c2.Subscribe("foo.*", cb)

	// Wait for processing.
	flush()

	sendAndCheckMsgs := func(numToSend int) {
		for i := 0; i < numToSend; i++ {
			if i%2 == 0 {
				c1.Publish(subj, i)
			} else {
				c2.Publish(subj, i)
			}
		}
		// Wait for processing.
		flush()
		// Check Results
		checkResults(numToSend)
	}

	////////////////////////////////////////////////////////////////////////////
	// Base Test
	////////////////////////////////////////////////////////////////////////////

	// Now send 10 messages, from each client..
	sendAndCheckMsgs(10)

	////////////////////////////////////////////////////////////////////////////
	// Now restart SrvA and srvB, re-run test
	////////////////////////////////////////////////////////////////////////////

	srvA.Shutdown()
	srvA = RunServer(optsA)
	defer srvA.Shutdown()

	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	waitOnReconnect()

	time.Sleep(50 * time.Millisecond)

	// Now send another 10 messages, from each client..
	sendAndCheckMsgs(10)
}

// This will test request semantics across a route
func TestRequestsAcrossRoutes(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect responder to srvA
	nc1.Subscribe("foo-req", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}

// This will test request semantics across a route to queues
func TestRequestsAcrossRoutesToQueues(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec1, _ := nats.NewEncodedConn(nc1, nats.JSON_ENCODER)
	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect one responder to srvA
	nc1.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	// Connect the other responder to srvB
	nc2.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc2.Publish(m.Reply, response)
	})

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}

	for i := 0; i < 100; i++ {
		if err := ec1.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}
<|endoftext|>