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

package kvscheduler

import (
	"net/http"
	"time"
	"fmt"
	"errors"

	"github.com/unrolled/render"
	"github.com/ligato/cn-infra/rpc/rest"
)

const (
	// prefix used for REST urls of the scheduler.
	urlPrefix = "/scheduler/"

	// txnHistoryURL is URL used to obtain the transaction history.
	txnHistoryURL = urlPrefix + "txn-history"

	// verboseArg is the name of the argument used to enable/disable verbose
	// output for transaction history.
	verboseArg = "verbose"

	// sinceArg is the name of the argument used to define the start of the time
	// window for the transaction history to display.
	sinceArg = "since"

	// untilArg is the name of the argument used to define the end of the time
	// window for the transaction history to display.
	untilArg = "until"

	// keyTimelineURL is URL used to obtain timeline of value changes for a given key.
	keyTimelineURL = urlPrefix + "key-timeline"

	// keyArg is the name of the argument used to define key for "key-timeline" API.
	keyArg = "key"

	// graphSnapshotURL is URL used to obtain graph snapshot from a given point in time.
	graphSnapshotURL = urlPrefix + "graph-snapshot"

	// time is the name of the argument used to define point in time for a graph snapshot
	// to retrieve.
	timeArg = "time"
)

// registerHandlers registers all supported REST APIs.
func (scheduler *Scheduler) registerHandlers(http rest.HTTPHandlers) {
	if http == nil {
		scheduler.Log.Warn("No http handler provided, skipping registration of KVScheduler REST handlers")
		return
	}
	http.RegisterHTTPHandler(txnHistoryURL, scheduler.txnHistoryGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", txnHistoryURL)
	http.RegisterHTTPHandler(keyTimelineURL, scheduler.keyTimelineGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", keyTimelineURL)
	http.RegisterHTTPHandler(graphSnapshotURL, scheduler.graphSnapshotGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", graphSnapshotURL)
}

// txnHistoryGetHandler is the GET handler for "txn-history" API.
func (scheduler *Scheduler) txnHistoryGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		var since, until time.Time
		var verbose bool
		args := req.URL.Query()
		fmt.Println(args)

		// parse "verbose" argument
		if verboseStr, withVerbose := args[verboseArg]; withVerbose && len(verboseStr) == 1 {
			verboseVal := verboseStr[0]
			if verboseVal == "true" || verboseVal == "1" {
				verbose = true
			}
		}

		// parse *until* argument
		if untilStr, withUntil := args[untilArg]; withUntil && len(untilStr) == 1 {
			var err error
			until, err = stringToTime(untilStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		// parse *since* argument
		if sinceStr, withSince := args[sinceArg]; withSince && len(sinceStr) == 1 {
			var err error
			since, err = stringToTime(sinceStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		txnHistory := scheduler.getTransactionHistory(since, until)
		formatter.Text(w, http.StatusOK, txnHistory.StringWithOpts(false, 0, verbose))
	}
}

// keyTimelineGetHandler is the GET handler for "key-timeline" API.
func (scheduler *Scheduler) keyTimelineGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()
		fmt.Println(args)

		if keys, withKey := args[keyArg]; withKey && len(keys) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			timeline := graphR.GetNodeTimeline(keys[0])
			formatter.JSON(w, http.StatusOK, timeline)
			return
		}

		err := errors.New("missing key argument")
		formatter.JSON(w, http.StatusInternalServerError, err)
		return
	}
}

// graphSnapshotGetHandler is the GET handler for "graph-snapshot" API.
func (scheduler *Scheduler) graphSnapshotGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		timeVal := time.Now()
		args := req.URL.Query()
		fmt.Println(args)

		// parse *time* argument
		if timeStr, withTime := args[timeArg]; withTime && len(timeStr) == 1 {
			var err error
			timeVal, err = stringToTime(timeStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		snapshot := graphR.GetSnapshot(timeVal)
		formatter.JSON(w, http.StatusOK, snapshot)
	}
}<commit_msg>REST API for flag stats.<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package kvscheduler

import (
	"net/http"
	"time"
	"errors"

	"github.com/unrolled/render"
	"github.com/ligato/cn-infra/rpc/rest"
	"strings"
)

const (
	// prefix used for REST urls of the scheduler.
	urlPrefix = "/scheduler/"

	// txnHistoryURL is URL used to obtain the transaction history.
	txnHistoryURL = urlPrefix + "txn-history"

	// verboseArg is the name of the argument used to enable/disable verbose
	// output for transaction history.
	verboseArg = "verbose"

	// sinceArg is the name of the argument used to define the start of the time
	// window for the transaction history to display.
	sinceArg = "since"

	// untilArg is the name of the argument used to define the end of the time
	// window for the transaction history to display.
	untilArg = "until"

	// keyTimelineURL is URL used to obtain timeline of value changes for a given key.
	keyTimelineURL = urlPrefix + "key-timeline"

	// keyArg is the name of the argument used to define key for "key-timeline" API.
	keyArg = "key"

	// graphSnapshotURL is URL used to obtain graph snapshot from a given point in time.
	graphSnapshotURL = urlPrefix + "graph-snapshot"

	// flagStatsURL is URL used to obtain flag statistics.
	flagStatsURL = urlPrefix + "flag-stats"

	// flagArg is the name of the argument used to define flag for "flag-stats" API.
	flagArg = "flag"

	// prefixArg is the name of the argument used to define prefix to filter keys
	// for "flag-stats" API.
	prefixArg = "prefix"

	// time is the name of the argument used to define point in time for a graph snapshot
	// to retrieve.
	timeArg = "time"
)

// registerHandlers registers all supported REST APIs.
func (scheduler *Scheduler) registerHandlers(http rest.HTTPHandlers) {
	if http == nil {
		scheduler.Log.Warn("No http handler provided, skipping registration of KVScheduler REST handlers")
		return
	}
	http.RegisterHTTPHandler(txnHistoryURL, scheduler.txnHistoryGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", txnHistoryURL)
	http.RegisterHTTPHandler(keyTimelineURL, scheduler.keyTimelineGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", keyTimelineURL)
	http.RegisterHTTPHandler(graphSnapshotURL, scheduler.graphSnapshotGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", graphSnapshotURL)
	http.RegisterHTTPHandler(flagStatsURL, scheduler.flagStatsGetHandler, "GET")
	scheduler.Log.Infof("KVScheduler REST handler registered: GET %v", flagStatsURL)
}

// txnHistoryGetHandler is the GET handler for "txn-history" API.
func (scheduler *Scheduler) txnHistoryGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		var since, until time.Time
		var verbose bool
		args := req.URL.Query()

		// parse optional *verbose* argument
		if verboseStr, withVerbose := args[verboseArg]; withVerbose && len(verboseStr) == 1 {
			verboseVal := verboseStr[0]
			if verboseVal == "true" || verboseVal == "1" {
				verbose = true
			}
		}

		// parse optional *until* argument
		if untilStr, withUntil := args[untilArg]; withUntil && len(untilStr) == 1 {
			var err error
			until, err = stringToTime(untilStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		// parse optional *since* argument
		if sinceStr, withSince := args[sinceArg]; withSince && len(sinceStr) == 1 {
			var err error
			since, err = stringToTime(sinceStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		txnHistory := scheduler.getTransactionHistory(since, until)
		formatter.Text(w, http.StatusOK, txnHistory.StringWithOpts(false, 0, verbose))
	}
}

// keyTimelineGetHandler is the GET handler for "key-timeline" API.
func (scheduler *Scheduler) keyTimelineGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()

		// parse mandatory *key* argument
		if keys, withKey := args[keyArg]; withKey && len(keys) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			timeline := graphR.GetNodeTimeline(keys[0])
			formatter.JSON(w, http.StatusOK, timeline)
			return
		}

		err := errors.New("missing key argument")
		formatter.JSON(w, http.StatusInternalServerError, err)
		return
	}
}

// graphSnapshotGetHandler is the GET handler for "graph-snapshot" API.
func (scheduler *Scheduler) graphSnapshotGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		timeVal := time.Now()
		args := req.URL.Query()

		// parse optional *time* argument
		if timeStr, withTime := args[timeArg]; withTime && len(timeStr) == 1 {
			var err error
			timeVal, err = stringToTime(timeStr[0])
			if err != nil {
				formatter.JSON(w, http.StatusInternalServerError, err)
				return
			}
		}

		graphR := scheduler.graph.Read()
		defer graphR.Release()

		snapshot := graphR.GetSnapshot(timeVal)
		formatter.JSON(w, http.StatusOK, snapshot)
	}
}

// flagStatsGetHandler is the GET handler for "flag-stats" API.
func (scheduler *Scheduler) flagStatsGetHandler(formatter *render.Render) http.HandlerFunc {
	return func(w http.ResponseWriter, req *http.Request) {
		args := req.URL.Query()
		var prefixes []string

		// parse repeated *prefix* argument
		prefixes, _ = args[prefixArg]

		if flags, withFlag := args[flagArg]; withFlag && len(flags) == 1 {
			graphR := scheduler.graph.Read()
			defer graphR.Release()

			stats := graphR.GetFlagStats(flags[0], func(key string) bool {
				if len(prefixes) == 0 {
					return true
				}
				for _, prefix := range prefixes {
					if strings.HasPrefix(key, prefix) {
						return true
					}
				}
				return false
			})
			formatter.JSON(w, http.StatusOK, stats)
			return
		}

		err := errors.New("missing flag argument")
		formatter.JSON(w, http.StatusInternalServerError, err)
		return
	}
}
<|endoftext|>


<commit_before>package adm

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

	"gopkg.in/resty.v0"
)

// Exported functions

// DELETE
func DeleteReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Delete(p))
}

func DeleteReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Delete(p))
}

// GET
func GetReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Get(p))
}

// PATCH
func PatchReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Patch(p))
}

// POST
func PostReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Post(p))
}

// PUT
func PutReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Put(p))
}

func PutReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Put(p))
}

// Private functions

func handleRequestOptions(resp *resty.Response, err error) (*resty.Response, error) {
	if err != nil {
		return nil, err
	}

	if resp.StatusCode() >= 300 {
		return resp, fmt.Errorf("Request error: %s", resp.Status())
	}

	if !(async || jobSave) {
		return resp, nil
	}

	var result *proto.Result
	if result, err = decodeResponse(resp); err != nil {
		return nil, err
	}

	if jobSave {
		if result.StatusCode == 202 && result.JobId != "" {
			cache.SaveJob(result.JobId, result.JobType)
		}
	}

	if async {
		asyncWait(result)
	}
	return resp, nil
}

func asyncWait(result *proto.Result) {
	if !async {
		return
	}

	if result.StatusCode == 202 && result.JobId != "" {
		fmt.Fprintf(os.Stderr, "Waiting for job: %s\n", result.JobId)
		_, err := PutReq(fmt.Sprintf("/jobs/%s", result.JobId))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Wait error: %s\n", err.Error())
		}
	}
}

func decodeResponse(resp *resty.Response) (*proto.Result, error) {
	result := proto.Result{}
	decoder := json.NewDecoder(bytes.NewReader(resp.Body()))
	err := decoder.Decode(&result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>Do not print EOF errors<commit_after>package adm

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

	"gopkg.in/resty.v0"
)

// Exported functions

// DELETE
func DeleteReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Delete(p))
}

func DeleteReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Delete(p))
}

// GET
func GetReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Get(p))
}

// PATCH
func PatchReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Patch(p))
}

// POST
func PostReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Post(p))
}

// PUT
func PutReq(p string) (*resty.Response, error) {
	return handleRequestOptions(client.R().Put(p))
}

func PutReqBody(body interface{}, p string) (*resty.Response, error) {
	return handleRequestOptions(
		client.R().SetBody(body).SetContentLength(true).Put(p))
}

// Private functions

func handleRequestOptions(resp *resty.Response, err error) (*resty.Response, error) {
	if err != nil {
		return nil, err
	}

	if resp.StatusCode() >= 300 {
		return resp, fmt.Errorf("Request error: %s", resp.Status())
	}

	if !(async || jobSave) {
		return resp, nil
	}

	var result *proto.Result
	if result, err = decodeResponse(resp); err != nil {
		return nil, err
	}

	if jobSave {
		if result.StatusCode == 202 && result.JobId != "" {
			cache.SaveJob(result.JobId, result.JobType)
		}
	}

	if async {
		asyncWait(result)
	}
	return resp, nil
}

func asyncWait(result *proto.Result) {
	if !async {
		return
	}

	if result.StatusCode == 202 && result.JobId != "" {
		fmt.Fprintf(os.Stderr, "Waiting for job: %s\n", result.JobId)
		_, err := PutReq(fmt.Sprintf("/jobs/%s", result.JobId))
		if err != nil && err != io.EOF {
			fmt.Fprintf(os.Stderr, "Wait error: %s\n", err.Error())
		}
	}
}

func decodeResponse(resp *resty.Response) (*proto.Result, error) {
	result := proto.Result{}
	decoder := json.NewDecoder(bytes.NewReader(resp.Body()))
	err := decoder.Decode(&result)
	if err != nil {
		return nil, err
	}

	return &result, nil
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>/*
Package lumber implements a simple logger that supports log levels and rotation.
*/
package lumber

import (
	"strings"
	"time"
)

const (
	TRACE = iota
	DEBUG
	INFO
	WARN
	ERROR
	FATAL

	TIMEFORMAT = "2006-01-02 15:04:05"
)

var (
	stdLog     = NewConsoleLogger(INFO)
	levels     = []string{"TRACE", "DEBUG", "INFO ", "WARN ", "ERROR", "FATAL", "*LOG*"}
	timeFormat = TIMEFORMAT
)

type Logger interface {
	Fatal(string, ...interface{})
	Error(string, ...interface{})
	Warn(string, ...interface{})
	Info(string, ...interface{})
	Debug(string, ...interface{})
	Trace(string, ...interface{})

	IsFatal() bool
	IsError() bool
	IsWarn() bool
	IsInfo() bool
	IsDebug() bool
	IsTrace() bool
	GetLevel() int

	Print(int, ...interface{})
	Printf(int, string, ...interface{})
	Level(int)
	Prefix(string)
	TimeFormat(string)
	Close()
	output(msg *Message)
}

type Message struct {
	level int
	m     string
	time  time.Time
}

// Returns the string representation of the level
func LvlStr(l int) string {
	if l >= 0 && l <= len(levels)-1 {
		return levels[l]
	}
	return ""
}

// Returns the int value of the level
func LvlInt(s string) int {
	for i, str := range levels {
		if strings.TrimSpace(str) == strings.ToUpper(s) {
			return i
		}
	}
	return 0
}

// Sets the output level for the default logger
func Level(o int) {
	stdLog.Level(o)
}

// Sets the time format for the default logger
func TimeFormat(f string) {
	stdLog.TimeFormat(f)
}

// Close the default logger
func Close() {
	stdLog.Close()
}

// Logging functions
func Fatal(format string, v ...interface{}) {
	stdLog.Fatal(format, v...)
}

func Error(format string, v ...interface{}) {
	stdLog.Error(format, v...)
}

func Warn(format string, v ...interface{}) {
	stdLog.Warn(format, v...)
}

func Info(format string, v ...interface{}) {
	stdLog.Info(format, v...)
}

func Debug(format string, v ...interface{}) {
	stdLog.Debug(format, v...)
}

func Trace(format string, v ...interface{}) {
	stdLog.Trace(format, v...)
}

func Print(lvl int, v ...interface{}) {
	stdLog.Print(lvl, v...)
}

func Printf(lvl int, format string, v ...interface{}) {
	stdLog.Printf(lvl, format, v...)
}

func GetLevel() int {
	return stdLog.GetLevel()
}

func IsFatal() bool {
	return stdLog.IsFatal()
}

func IsError() bool {
	return stdLog.IsError()
}

func IsWarn() bool {
	return stdLog.IsWarn()
}

func IsInfo() bool {
	return stdLog.IsInfo()
}

func IsDebug() bool {
	return stdLog.IsDebug()
}

func IsTrace() bool {
	return stdLog.IsTrace()
}
<commit_msg>ability to change the default logger<commit_after>/*
Package lumber implements a simple logger that supports log levels and rotation.
*/
package lumber

import (
	"strings"
	"time"
)

const (
	TRACE = iota
	DEBUG
	INFO
	WARN
	ERROR
	FATAL

	TIMEFORMAT = "2006-01-02 15:04:05"
)

var (
	stdLog     Logger = NewConsoleLogger(INFO)
	levels            = []string{"TRACE", "DEBUG", "INFO ", "WARN ", "ERROR", "FATAL", "*LOG*"}
	timeFormat        = TIMEFORMAT
)

type Logger interface {
	Fatal(string, ...interface{})
	Error(string, ...interface{})
	Warn(string, ...interface{})
	Info(string, ...interface{})
	Debug(string, ...interface{})
	Trace(string, ...interface{})

	IsFatal() bool
	IsError() bool
	IsWarn() bool
	IsInfo() bool
	IsDebug() bool
	IsTrace() bool
	GetLevel() int

	Print(int, ...interface{})
	Printf(int, string, ...interface{})
	Level(int)
	Prefix(string)
	TimeFormat(string)
	Close()
	output(msg *Message)
}

type Message struct {
	level int
	m     string
	time  time.Time
}

// SetLogger sets a new default logger
func SetLogger(l Logger) {
	stdLog = l
}

// Returns the string representation of the level
func LvlStr(l int) string {
	if l >= 0 && l <= len(levels)-1 {
		return levels[l]
	}
	return ""
}

// Returns the int value of the level
func LvlInt(s string) int {
	for i, str := range levels {
		if strings.TrimSpace(str) == strings.ToUpper(s) {
			return i
		}
	}
	return 0
}

// Sets the output level for the default logger
func Level(o int) {
	stdLog.Level(o)
}

// Sets the time format for the default logger
func TimeFormat(f string) {
	stdLog.TimeFormat(f)
}

// Close the default logger
func Close() {
	stdLog.Close()
}

// Logging functions
func Fatal(format string, v ...interface{}) {
	stdLog.Fatal(format, v...)
}

func Error(format string, v ...interface{}) {
	stdLog.Error(format, v...)
}

func Warn(format string, v ...interface{}) {
	stdLog.Warn(format, v...)
}

func Info(format string, v ...interface{}) {
	stdLog.Info(format, v...)
}

func Debug(format string, v ...interface{}) {
	stdLog.Debug(format, v...)
}

func Trace(format string, v ...interface{}) {
	stdLog.Trace(format, v...)
}

func Print(lvl int, v ...interface{}) {
	stdLog.Print(lvl, v...)
}

func Printf(lvl int, format string, v ...interface{}) {
	stdLog.Printf(lvl, format, v...)
}

func GetLevel() int {
	return stdLog.GetLevel()
}

func IsFatal() bool {
	return stdLog.IsFatal()
}

func IsError() bool {
	return stdLog.IsError()
}

func IsWarn() bool {
	return stdLog.IsWarn()
}

func IsInfo() bool {
	return stdLog.IsInfo()
}

func IsDebug() bool {
	return stdLog.IsDebug()
}

func IsTrace() bool {
	return stdLog.IsTrace()
}
<|endoftext|>


<commit_before>package game

import (
	"sync"
	"time"
	"runtime"

	"buildblast/lib/coords"
	"buildblast/lib/mapgen"
)

type ChunkGenerator struct {
	// Chunks are sent to this channel as they are generated
	Generated chan ChunkGenerationResult

	chunks    map[coords.Chunk]ChunkStatus
	mutex     sync.Mutex
	goPool    chan bool
	generator mapgen.Generator
}

type ChunkGenerationResult struct {
	cc    coords.Chunk
	chunk *mapgen.Chunk
}

type ChunkStatus struct {
	generating bool
	generated  bool
	priority   int
}

func NewChunkGenerator(generator mapgen.Generator) *ChunkGenerator {
	cm := new(ChunkGenerator)
	cm.chunks = make(map[coords.Chunk]ChunkStatus, 10)
	cm.Generated = make(chan ChunkGenerationResult, 10)
	// Only cores - 1 chunks can be generated at a time.
	maxActiveThreads := runtime.NumCPU() - 1
	if maxActiveThreads < 1 {
		maxActiveThreads = 1
	}
	cm.goPool = make(chan bool, maxActiveThreads)
	for i := 0; i < maxActiveThreads; i++ {
		cm.goPool <- true
	}
	cm.generator = generator
	return cm
}

// cm.Lock() MUST BE HELD by the caller, or else calling
// this function is unsafe.
func (cm *ChunkGenerator) queue(cc coords.Chunk, priority int) {
	status := cm.chunks[cc]
	if status.generated || status.generating {
		return
	}
	status.priority += priority
	cm.chunks[cc] = status
}

func (cm *ChunkGenerator) QueueChunksNearby(wc coords.World) {
	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	queue := func(cc coords.Chunk, priority int) {
		cm.queue(cc, priority)
	}

	EachChunkNearby(wc, queue)
}

func (cm *ChunkGenerator) Top() (cc coords.Chunk, valid bool) {
	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	highest := -1
	for key, val := range cm.chunks {
		if val.priority > highest && !val.generated && !val.generating {
			highest = val.priority
			cc = key
		}
	}
	if highest != -1 {
		return cc, true
	}
	return cc, false
}

func (cm *ChunkGenerator) Run() {
	for {
		cc, valid := cm.Top()
		if !valid {
			<-time.After(time.Second / 60)
			continue
		}

		cm.mutex.Lock()
		status := cm.chunks[cc]
		status.generating = true
		cm.chunks[cc] = status
		cm.mutex.Unlock()

		go cm.generate(cc)
	}
}

func (cm *ChunkGenerator) generate(cc coords.Chunk) {
	// Attempt to use a slot
	<- cm.goPool
	chunk := cm.generator.Chunk(cc)

	cm.Generated <- ChunkGenerationResult{
		cc:    cc,
		chunk: chunk,
	}

	cm.mutex.Lock()
	status := cm.chunks[cc]
	status.generating = false
	status.generated = true
	cm.chunks[cc] = status
	cm.mutex.Unlock()
	// Free our slot
	cm.goPool <- true
}

func EachChunkNearby(wc coords.World, cb func(cc coords.Chunk, priority int)) {
	occ := func(cc coords.Chunk, x, y, z int) coords.Chunk {
		return coords.Chunk{
			X: cc.X + x,
			Y: cc.Y + y,
			Z: cc.Z + z,
		}
	}

	eachWithin := func(cc coords.Chunk, xdist, ydist, zdist int, cb func(newCC coords.Chunk, dist int)) {
		abs := func(n int) int {
			if n < 0 {
				return -n
			}
			return n
		}
		dist := func(x, y, z int) int {
			return abs(x) + abs(y) + abs(z)
		}

		cb(cc, 0)
		for x := -xdist; x <= xdist; x++ {
			for y := -ydist; y <= ydist; y++ {
				for z := -zdist; z <= zdist; z++ {
					cb(occ(cc, x, y, z), dist(x, y, z))
				}
			}
		}
	}

	cc := wc.Chunk()
	eachWithin(cc, 2, 0, 2, func(newCC coords.Chunk, dist int) {
		// We want to prioritize further away chunks lower, but the
		// priority must be a positive integer.
		cb(newCC, 10-dist)
	})

	oc := wc.Offset()
	if oc.Y <= 4 {
		cb(occ(cc, 0, -1, 0), 1)
	} else if oc.Y >= 28 {
		cb(occ(cc, 0, 1, 0), 1)
	}
}
<commit_msg>go fmt ./...<commit_after>package game

import (
	"runtime"
	"sync"
	"time"

	"buildblast/lib/coords"
	"buildblast/lib/mapgen"
)

type ChunkGenerator struct {
	// Chunks are sent to this channel as they are generated
	Generated chan ChunkGenerationResult

	chunks    map[coords.Chunk]ChunkStatus
	mutex     sync.Mutex
	goPool    chan bool
	generator mapgen.Generator
}

type ChunkGenerationResult struct {
	cc    coords.Chunk
	chunk *mapgen.Chunk
}

type ChunkStatus struct {
	generating bool
	generated  bool
	priority   int
}

func NewChunkGenerator(generator mapgen.Generator) *ChunkGenerator {
	cm := new(ChunkGenerator)
	cm.chunks = make(map[coords.Chunk]ChunkStatus, 10)
	cm.Generated = make(chan ChunkGenerationResult, 10)
	// Only cores - 1 chunks can be generated at a time.
	maxActiveThreads := runtime.NumCPU() - 1
	if maxActiveThreads < 1 {
		maxActiveThreads = 1
	}
	cm.goPool = make(chan bool, maxActiveThreads)
	for i := 0; i < maxActiveThreads; i++ {
		cm.goPool <- true
	}
	cm.generator = generator
	return cm
}

// cm.Lock() MUST BE HELD by the caller, or else calling
// this function is unsafe.
func (cm *ChunkGenerator) queue(cc coords.Chunk, priority int) {
	status := cm.chunks[cc]
	if status.generated || status.generating {
		return
	}
	status.priority += priority
	cm.chunks[cc] = status
}

func (cm *ChunkGenerator) QueueChunksNearby(wc coords.World) {
	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	queue := func(cc coords.Chunk, priority int) {
		cm.queue(cc, priority)
	}

	EachChunkNearby(wc, queue)
}

func (cm *ChunkGenerator) Top() (cc coords.Chunk, valid bool) {
	cm.mutex.Lock()
	defer cm.mutex.Unlock()

	highest := -1
	for key, val := range cm.chunks {
		if val.priority > highest && !val.generated && !val.generating {
			highest = val.priority
			cc = key
		}
	}
	if highest != -1 {
		return cc, true
	}
	return cc, false
}

func (cm *ChunkGenerator) Run() {
	for {
		cc, valid := cm.Top()
		if !valid {
			<-time.After(time.Second / 60)
			continue
		}

		cm.mutex.Lock()
		status := cm.chunks[cc]
		status.generating = true
		cm.chunks[cc] = status
		cm.mutex.Unlock()

		go cm.generate(cc)
	}
}

func (cm *ChunkGenerator) generate(cc coords.Chunk) {
	// Attempt to use a slot
	<-cm.goPool
	chunk := cm.generator.Chunk(cc)

	cm.Generated <- ChunkGenerationResult{
		cc:    cc,
		chunk: chunk,
	}

	cm.mutex.Lock()
	status := cm.chunks[cc]
	status.generating = false
	status.generated = true
	cm.chunks[cc] = status
	cm.mutex.Unlock()
	// Free our slot
	cm.goPool <- true
}

func EachChunkNearby(wc coords.World, cb func(cc coords.Chunk, priority int)) {
	occ := func(cc coords.Chunk, x, y, z int) coords.Chunk {
		return coords.Chunk{
			X: cc.X + x,
			Y: cc.Y + y,
			Z: cc.Z + z,
		}
	}

	eachWithin := func(cc coords.Chunk, xdist, ydist, zdist int, cb func(newCC coords.Chunk, dist int)) {
		abs := func(n int) int {
			if n < 0 {
				return -n
			}
			return n
		}
		dist := func(x, y, z int) int {
			return abs(x) + abs(y) + abs(z)
		}

		cb(cc, 0)
		for x := -xdist; x <= xdist; x++ {
			for y := -ydist; y <= ydist; y++ {
				for z := -zdist; z <= zdist; z++ {
					cb(occ(cc, x, y, z), dist(x, y, z))
				}
			}
		}
	}

	cc := wc.Chunk()
	eachWithin(cc, 2, 0, 2, func(newCC coords.Chunk, dist int) {
		// We want to prioritize further away chunks lower, but the
		// priority must be a positive integer.
		cb(newCC, 10-dist)
	})

	oc := wc.Offset()
	if oc.Y <= 4 {
		cb(occ(cc, 0, -1, 0), 1)
	} else if oc.Y >= 28 {
		cb(occ(cc, 0, 1, 0), 1)
	}
}
<|endoftext|>


<commit_before>package vmwpatch

const VERSION = "4.2.1"
const COPYRIGHT = "© 2014-2022 David Parsons"
<commit_msg>4.2.2: Bump version to prepare for new version<commit_after>package vmwpatch

const VERSION = "4.2.2"
const COPYRIGHT = "© 2014-2022 David Parsons"
<|endoftext|>


<commit_before>package optshttp

import (
  "net/http"
  "time"
  //"github.com/gorilla/mux"
  "fmt"
  "strconv"
  "reflect"
  "unsafe"
)

type optsError struct{
  optType string
  optKey string
  optVal string
}

func (e *optsError) Error() string {
  return fmt.Sprintf("Invalid %s %s: %s", e.optType, e.optKey, e.optVal)
}

func UnmarshalForm(req *http.Request, v interface{}) error {
  vv := reflect.ValueOf(v).Elem()
  vt := vv.Type()
  numField := vt.NumField()
  for i := 0; i < numField; i++ {
    field := vt.Field(i)
    if formKey, ok := field.Tag.Lookup("form"); ok {
      formStr := req.FormValue(formKey)
      if (len(formStr) == 0) {
        continue
      }
      if err := setValue(vv.Field(i), formKey, formStr); err != nil {
        return err
      }
    }
  }
  return nil
}

var pStrType = reflect.TypeOf((*string)(nil))
var pIntType = reflect.TypeOf((*int)(nil))
var timeType = reflect.TypeOf(time.Time{})
var pTimeType = reflect.PtrTo(timeType)

func setValue(v reflect.Value, formKey string, formStr string) error {
  switch v.Kind() {
    case reflect.String:
      v.SetString(formStr)
    case reflect.Int:
      if val, err := strconv.ParseInt(formStr, 10, 0); err != nil{
        return &optsError{"integer", formKey, formStr}
      } else {
        v.SetInt(val)
      }
    case reflect.Struct:
      if v.Type() == timeType {
        t := (*time.Time)(unsafe.Pointer(v.UnsafeAddr()))
        if err := t.UnmarshalText([]byte(formStr)); err != nil {
          return &optsError{"time in RFC3339 format", formKey, formStr}
        }
      }
    case reflect.Ptr:
      if ! v.IsNil() {
        return setValue(v.Elem(), formKey, formStr)
      }
      switch v.Type() {
        case pStrType:
          p := (**string)(unsafe.Pointer(v.UnsafeAddr()))
          *p = &formStr
        case pIntType:
          if val, err := strconv.Atoi(formStr); err != nil{
            return &optsError{"integer", formKey, formStr}
          } else {
            p := (**int)(unsafe.Pointer(v.UnsafeAddr()))
            *p = &val
          }
        case pTimeType:
          if val, err := time.Parse(time.RFC3339Nano, formStr); err != nil{
            return &optsError{"time in RFC3339 format", formKey, formStr}
          } else {
            p := (**time.Time)(unsafe.Pointer(v.UnsafeAddr()))
            *p = &val
          }
      }
  }
  return nil
}
<commit_msg>Parses gorilla path of request form<commit_after>package optshttp

import (
  "net/http"
  "time"
  "github.com/gorilla/mux"
  "fmt"
  "strconv"
  "reflect"
  "unsafe"
)

type optsError struct{
  optType string
  optKey string
  optVal string
}

func (e *optsError) Error() string {
  return fmt.Sprintf("Invalid %s %s: %s", e.optType, e.optKey, e.optVal)
}

func UnmarshalForm(req *http.Request, v interface{}) error {
  return unmarshal(v, func(s string) string {return req.FormValue(s)})
}

func UnmarshalPath(req *http.Request, v interface{}) error {
  vars := mux.Vars(req)
  return unmarshal(v, func(s string) string {return vars[s]})
}

func unmarshal(v interface{}, varLookup func(string) string) error {
  vv := reflect.ValueOf(v).Elem()
  vt := vv.Type()
  numField := vt.NumField()
  for i := 0; i < numField; i++ {
    field := vt.Field(i)
    if formKey, ok := field.Tag.Lookup("form"); ok {
      formStr := varLookup(formKey)
      if (len(formStr) == 0) {
        continue
      }
      if err := setValue(vv.Field(i), formKey, formStr); err != nil {
        return err
      }
    }
  }
  return nil
}

var pStrType = reflect.TypeOf((*string)(nil))
var pIntType = reflect.TypeOf((*int)(nil))
var timeType = reflect.TypeOf(time.Time{})
var pTimeType = reflect.PtrTo(timeType)

func setValue(v reflect.Value, formKey string, formStr string) error {
  switch v.Kind() {
    case reflect.String:
      v.SetString(formStr)
    case reflect.Int:
      if val, err := strconv.ParseInt(formStr, 10, 0); err != nil{
        return &optsError{"integer", formKey, formStr}
      } else {
        v.SetInt(val)
      }
    case reflect.Struct:
      if v.Type() == timeType {
        t := (*time.Time)(unsafe.Pointer(v.UnsafeAddr()))
        if err := t.UnmarshalText([]byte(formStr)); err != nil {
          return &optsError{"time in RFC3339 format", formKey, formStr}
        }
      }
    case reflect.Ptr:
      if ! v.IsNil() {
        return setValue(v.Elem(), formKey, formStr)
      }
      switch v.Type() {
        case pStrType:
          p := (**string)(unsafe.Pointer(v.UnsafeAddr()))
          *p = &formStr
        case pIntType:
          if val, err := strconv.Atoi(formStr); err != nil{
            return &optsError{"integer", formKey, formStr}
          } else {
            p := (**int)(unsafe.Pointer(v.UnsafeAddr()))
            *p = &val
          }
        case pTimeType:
          if val, err := time.Parse(time.RFC3339Nano, formStr); err != nil{
            return &optsError{"time in RFC3339 format", formKey, formStr}
          } else {
            p := (**time.Time)(unsafe.Pointer(v.UnsafeAddr()))
            *p = &val
          }
      }
  }
  return nil
}
<|endoftext|>


<commit_before>package mantle

import (
        "string"
        "./backends/redis"
        "./backends/memcache"
)

type Mantle interface{
        Connect()
        Get(key interface{}) interface{}
        Set(key interface{}, value interface{}) bool
        MGet(key ...interface{}) map[interface{}]interface{}
        MSet(k_v_map map[interface{}]interface{}) bool
        Expire(keys ...interface{}) bool
}

type Orm struct{
        driver string
        host string
        port string
}

func (o *Orm) Get() interface{}{
        if o.driver == "memcache" {
                return &Mantle{&Memcache{o.host, o.port}}
        }else{
                return &Mantle{&Redis{o.host, o.port}}
        }
}

func main(){
        driver := &Orm{}
        driver.Get()
        /*
        connection = driver.Connect()
        connection.Get("key") //returns value
        connection.Set("key", "value") //returns true or false
        connection.MGet(["key1", "key2", "key3"]) // returns map of k v
        connection.MSet(["key"]"value") //returns true or false
        */
}

<commit_msg>fixing mantle.go<commit_after>package main

import (
        "./backends/redis"
        //"./backends/memcache"
        "fmt"
)

type Mantle interface{
        Connect()
        Get(key string) string
        Set(key string, value interface{}) bool
        //MGet(key ...interface{}) map[interface{}]interface{}
        //MSet(k_v_map map[interface{}]interface{}) bool
        //Expire(keys ...interface{}) bool
}

type Orm struct{
        driver string
        Host string
        Port string
}

func (o *Orm) Get() Mantle{
        if o.driver == "" {
                return Mantle(&mantle.Redis{Host : "", Port : ""})
        }else{
                return Mantle(&mantle.Redis{Host : "", Port : ""})
        }
}

func main(){
        orm := &Orm{Host: "", Port: ""}
        driver := orm.Get()
        driver.Connect()
        driver.Set("key", "value")
        fmt.Println(driver.Get("key"))
        driver.Set("key", "value1")
        fmt.Println(driver.Get("key"))
/*
        connection = driver.Connect()
        connection.Get("key") //returns value
        connection.Set("key", "value") //returns true or false
        connection.MGet(["key1", "key2", "key3"]) // returns map of k v
        connection.MSet(["key"]"value") //returns true or false
*/
}
<|endoftext|>


<commit_before>package opts

import (
	"fmt"
	"net"
	"net/url"
	"strconv"
	"strings"
)

var (
	// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp://
	// These are the IANA registered port numbers for use with Docker
	// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
	DefaultHTTPPort = 2375 // Default HTTP Port
	// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
	DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
	// DefaultUnixSocket Path for the unix socket.
	// Docker daemon by default always listens on the default unix socket
	DefaultUnixSocket = "/var/run/docker.sock"
	// DefaultTCPHost constant defines the default host string used by docker on Windows
	DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
	// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
	DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
	// DefaultNamedPipe defines the default named pipe used by docker on Windows
	DefaultNamedPipe = `//./pipe/docker_engine`
)

// ValidateHost validates that the specified string is a valid host and returns it.
func ValidateHost(val string) (string, error) {
	host := strings.TrimSpace(val)
	// The empty string means default and is not handled by parseDockerDaemonHost
	if host != "" {
		_, err := parseDockerDaemonHost(host)
		if err != nil {
			return val, err
		}
	}
	// Note: unlike most flag validators, we don't return the mutated value here
	//       we need to know what the user entered later (using ParseHost) to adjust for tls
	return val, nil
}

// ParseHost and set defaults for a Daemon host string
func ParseHost(defaultToTLS bool, val string) (string, error) {
	host := strings.TrimSpace(val)
	if host == "" {
		if defaultToTLS {
			host = DefaultTLSHost
		} else {
			host = DefaultHost
		}
	} else {
		var err error
		host, err = parseDockerDaemonHost(host)
		if err != nil {
			return val, err
		}
	}
	return host, nil
}

// parseDockerDaemonHost parses the specified address and returns an address that will be used as the host.
// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go.
func parseDockerDaemonHost(addr string) (string, error) {
	addrParts := strings.SplitN(addr, "://", 2)
	if len(addrParts) == 1 && addrParts[0] != "" {
		addrParts = []string{"tcp", addrParts[0]}
	}

	switch addrParts[0] {
	case "tcp":
		return ParseTCPAddr(addrParts[1], DefaultTCPHost)
	case "unix":
		return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
	case "npipe":
		return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
	case "fd":
		return addr, nil
	default:
		return "", fmt.Errorf("Invalid bind address format: %s", addr)
	}
}

// parseSimpleProtoAddr parses and validates that the specified address is a valid
// socket address for simple protocols like unix and npipe. It returns a formatted
// socket address, either using the address parsed from addr, or the contents of
// defaultAddr if addr is a blank string.
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
	addr = strings.TrimPrefix(addr, proto+"://")
	if strings.Contains(addr, "://") {
		return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr)
	}
	if addr == "" {
		addr = defaultAddr
	}
	return fmt.Sprintf("%s://%s", proto, addr), nil
}

// ParseTCPAddr parses and validates that the specified address is a valid TCP
// address. It returns a formatted TCP address, either using the address parsed
// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
// tryAddr is expected to have already been Trim()'d
// defaultAddr must be in the full `tcp://host:port` form
func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
	if tryAddr == "" || tryAddr == "tcp://" {
		return defaultAddr, nil
	}
	addr := strings.TrimPrefix(tryAddr, "tcp://")
	if strings.Contains(addr, "://") || addr == "" {
		return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
	}

	defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
	defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
	if err != nil {
		return "", err
	}
	// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
	// not 1.4. See https://github.com/golang/go/issues/12200 and
	// https://github.com/golang/go/issues/6530.
	if strings.HasSuffix(addr, "]:") {
		addr += defaultPort
	}

	u, err := url.Parse("tcp://" + addr)
	if err != nil {
		return "", err
	}
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		// try port addition once
		host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort))
	}
	if err != nil {
		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
	}

	if host == "" {
		host = defaultHost
	}
	if port == "" {
		port = defaultPort
	}
	p, err := strconv.Atoi(port)
	if err != nil && p == 0 {
		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
	}

	return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
}
<commit_msg>Change tls to TLS<commit_after>package opts

import (
	"fmt"
	"net"
	"net/url"
	"strconv"
	"strings"
)

var (
	// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp://
	// These are the IANA registered port numbers for use with Docker
	// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
	DefaultHTTPPort = 2375 // Default HTTP Port
	// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
	DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
	// DefaultUnixSocket Path for the unix socket.
	// Docker daemon by default always listens on the default unix socket
	DefaultUnixSocket = "/var/run/docker.sock"
	// DefaultTCPHost constant defines the default host string used by docker on Windows
	DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
	// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
	DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
	// DefaultNamedPipe defines the default named pipe used by docker on Windows
	DefaultNamedPipe = `//./pipe/docker_engine`
)

// ValidateHost validates that the specified string is a valid host and returns it.
func ValidateHost(val string) (string, error) {
	host := strings.TrimSpace(val)
	// The empty string means default and is not handled by parseDockerDaemonHost
	if host != "" {
		_, err := parseDockerDaemonHost(host)
		if err != nil {
			return val, err
		}
	}
	// Note: unlike most flag validators, we don't return the mutated value here
	//       we need to know what the user entered later (using ParseHost) to adjust for TLS
	return val, nil
}

// ParseHost and set defaults for a Daemon host string
func ParseHost(defaultToTLS bool, val string) (string, error) {
	host := strings.TrimSpace(val)
	if host == "" {
		if defaultToTLS {
			host = DefaultTLSHost
		} else {
			host = DefaultHost
		}
	} else {
		var err error
		host, err = parseDockerDaemonHost(host)
		if err != nil {
			return val, err
		}
	}
	return host, nil
}

// parseDockerDaemonHost parses the specified address and returns an address that will be used as the host.
// Depending of the address specified, this may return one of the global Default* strings defined in hosts.go.
func parseDockerDaemonHost(addr string) (string, error) {
	addrParts := strings.SplitN(addr, "://", 2)
	if len(addrParts) == 1 && addrParts[0] != "" {
		addrParts = []string{"tcp", addrParts[0]}
	}

	switch addrParts[0] {
	case "tcp":
		return ParseTCPAddr(addrParts[1], DefaultTCPHost)
	case "unix":
		return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
	case "npipe":
		return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
	case "fd":
		return addr, nil
	default:
		return "", fmt.Errorf("Invalid bind address format: %s", addr)
	}
}

// parseSimpleProtoAddr parses and validates that the specified address is a valid
// socket address for simple protocols like unix and npipe. It returns a formatted
// socket address, either using the address parsed from addr, or the contents of
// defaultAddr if addr is a blank string.
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
	addr = strings.TrimPrefix(addr, proto+"://")
	if strings.Contains(addr, "://") {
		return "", fmt.Errorf("Invalid proto, expected %s: %s", proto, addr)
	}
	if addr == "" {
		addr = defaultAddr
	}
	return fmt.Sprintf("%s://%s", proto, addr), nil
}

// ParseTCPAddr parses and validates that the specified address is a valid TCP
// address. It returns a formatted TCP address, either using the address parsed
// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
// tryAddr is expected to have already been Trim()'d
// defaultAddr must be in the full `tcp://host:port` form
func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
	if tryAddr == "" || tryAddr == "tcp://" {
		return defaultAddr, nil
	}
	addr := strings.TrimPrefix(tryAddr, "tcp://")
	if strings.Contains(addr, "://") || addr == "" {
		return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
	}

	defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
	defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
	if err != nil {
		return "", err
	}
	// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
	// not 1.4. See https://github.com/golang/go/issues/12200 and
	// https://github.com/golang/go/issues/6530.
	if strings.HasSuffix(addr, "]:") {
		addr += defaultPort
	}

	u, err := url.Parse("tcp://" + addr)
	if err != nil {
		return "", err
	}
	host, port, err := net.SplitHostPort(u.Host)
	if err != nil {
		// try port addition once
		host, port, err = net.SplitHostPort(net.JoinHostPort(u.Host, defaultPort))
	}
	if err != nil {
		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
	}

	if host == "" {
		host = defaultHost
	}
	if port == "" {
		port = defaultPort
	}
	p, err := strconv.Atoi(port)
	if err != nil && p == 0 {
		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
	}

	return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
}
<|endoftext|>


<commit_before>package dataProcess

import (
	"../autils"
	"bytes"
	"database/sql"
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Tac struct {
	Key   string
	Value int
}

type tcRs struct {
	Name  string `json:"name"`
	Value int    `json:"value"`
}

type Tc []Tac

func (p Tc) Len() int           { return len(p) }
func (p Tc) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Tc) Less(i, j int) bool { return p[i].Value < p[j].Value }

var (
	tcMax    = 10
	tcOthers = "others"
)

// 组件被引用数统计
func GetBarCountData(c *gin.Context, db *sql.DB, q interface{}, d interface{}) {
	tr := tcRs{}
	finalRs := []tcRs{}
	var name, count string

	customDate := c.Query("date")
	ml := c.Query("max")
	if ml != "" {
		tcMax, _ = strconv.Atoi(ml)
	}

	t := time.Now()
	t = t.AddDate(0, 0, -2)
	yesterday := autils.GetCurrentData(t)

	if customDate != "" {
		yesterday = customDate
	}

	var bf bytes.Buffer
	bf.WriteString("select tag_name,tag_count from tags where ana_date = '")
	valStr := autils.CheckSql(yesterday)
	bf.WriteString(valStr)
	bf.WriteString("' ")

	tn := autils.AnaDrillDowns(d)
	match, err := regexp.MatchString("mip-", tn)

	if match && err == nil {
		bf.WriteString(" and tag_name = '")
		bf.WriteString(tn)
		bf.WriteString("' ")
	}

	sqlStr := bf.String()

	rows, err := db.Query(sqlStr)
	autils.ErrHadle(err)

	for rows.Next() {
		noble := map[string]int{}
		err := rows.Scan(&name, &count)
		autils.ErrHadle(err)

		// tag count 处理
		tArr := strings.Split(count, ",")
		for _, v := range tArr {
			kvArr := strings.Split(v, "=")
			if len(kvArr) == 2 {
				noble[kvArr[0]], err = strconv.Atoi(kvArr[1])
			}
		}

		p := make(Tc, len(noble))
		i := 0
		for k, v := range noble {
			p[i] = Tac{k, v}
			i++
		}
		sort.Sort(sort.Reverse(p))

		c := 0
		for k, v := range p {
			if k >= tcMax {
				c += v.Value
			} else {
				tr.Name = v.Key
				tr.Value = v.Value
				finalRs = append(finalRs, tr)
			}
		}
		tr.Name = tcOthers
		tr.Value = c
		finalRs = append(finalRs, tr)
	}

	err = rows.Err()
	autils.ErrHadle(err)

	defer rows.Close()

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "ok",
		"data":   finalRs,
	})
}
<commit_msg>fixed other bugs.<commit_after>package dataProcess

import (
	"../autils"
	"bytes"
	"database/sql"
	"github.com/gin-gonic/gin"
	"net/http"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type Tac struct {
	Key   string
	Value int
}

type tcRs struct {
	Name  string `json:"name"`
	Value int    `json:"value"`
}

type Tc []Tac

func (p Tc) Len() int           { return len(p) }
func (p Tc) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Tc) Less(i, j int) bool { return p[i].Value < p[j].Value }

var (
	tcMax    = 10
	tcOthers = "others"
)

// 组件被引用数统计
func GetBarCountData(c *gin.Context, db *sql.DB, q interface{}, d interface{}) {
	tr := tcRs{}
	finalRs := []tcRs{}
	var name, count string

	customDate := c.Query("date")
	ml := c.Query("max")
	if ml != "" {
		tcMax, _ = strconv.Atoi(ml)
	}

	t := time.Now()
	t = t.AddDate(0, 0, -2)
	yesterday := autils.GetCurrentData(t)

	if customDate != "" {
		yesterday = customDate
	}

	var bf bytes.Buffer
	bf.WriteString("select tag_name,tag_count from tags where ana_date = '")
	valStr := autils.CheckSql(yesterday)
	bf.WriteString(valStr)
	bf.WriteString("' ")

	tn := autils.AnaDrillDowns(d)
	match, err := regexp.MatchString("mip-", tn)

	if match && err == nil {
		bf.WriteString(" and tag_name = '")
		bf.WriteString(tn)
		bf.WriteString("' ")
	}

	sqlStr := bf.String()

	rows, err := db.Query(sqlStr)
	autils.ErrHadle(err)

	ct := 0
	for rows.Next() {
		noble := map[string]int{}
		err := rows.Scan(&name, &count)
		autils.ErrHadle(err)

		// tag count 处理
		tArr := strings.Split(count, ",")
		for _, v := range tArr {
			kvArr := strings.Split(v, "=")
			if len(kvArr) == 2 {
				noble[kvArr[0]], err = strconv.Atoi(kvArr[1])
			}
		}

		p := make(Tc, len(noble))
		i := 0
		for k, v := range noble {
			p[i] = Tac{k, v}
			i++
		}
		sort.Sort(sort.Reverse(p))

		for k, v := range p {
			if k >= tcMax {
				ct += v.Value
			} else {
				tr.Name = v.Key
				tr.Value = v.Value
				finalRs = append(finalRs, tr)
			}
		}
	}

	tr.Name = tcOthers
	tr.Value = ct
	finalRs = append(finalRs, tr)

	err = rows.Err()
	autils.ErrHadle(err)

	defer rows.Close()

	c.JSON(http.StatusOK, gin.H{
		"status": 0,
		"msg":    "ok",
		"data":   finalRs,
	})
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Miquel Sabaté Solà <mikisabate@gmail.com>
// This file is licensed under the MIT license.
// See the LICENSE file.

package lib

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/mssola/dym"
)

type Topic struct {
	Id         string    `json:"id,omitempty"`
	Name       string    `json:"name,omitempty"`
	Contents   string    `json:"contents,omitempty"`
	Created_at time.Time `json:"created_at,omitempty"`
	Markdown   string    `json:"markdown,omitempty"`
}

func unknownTopic(name string) {
	var topics []Topic
	var names []string

	readTopics(&topics)
	for _, v := range topics {
		names = append(names, v.Name)
	}

	msg := fmt.Sprintf("td: the topic '%v' does not exist.", name)
	similars := dym.Similar(names, name)
	if len(similars) == 0 {
		fmt.Printf(msg)
	} else {
		msg += "\n\nDid you mean one of these?\n"
		for _, v := range similars {
			msg += "\t" + v + "\n"
		}
		fmt.Printf(msg)
	}
}

func Edit() error {
	cmd := exec.Command(editor())
	cmd.Dir = filepath.Join(home(), dirName, newDir)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func Diff() error {
	// TODO
	return nil
}

func Fetch() error {
	// Perform the HTTP request.
	res, err := getResponse("GET", "/topics", nil)
	if err != nil {
		return fromError(err)
	}

	// Parse the given topics.
	var topics []Topic
	body, _ := ioutil.ReadAll(res.Body)
	if err := json.Unmarshal(body, &topics); err != nil {
		return fromError(err)
	}

	// And save the results.
	save(topics)
	fmt.Printf("Topics updated.\n")
	return nil
}

func List() error {
	var topics []Topic
	readTopics(&topics)
	for _, v := range topics {
		fmt.Printf("%v\n", v.Name)
	}
	return nil
}

func Push() error {
	var success, fails []string
	var topics []Topic
	readTopics(&topics)

	total := len(topics)
	for k, v := range topics {
		// Print the status.
		fmt.Printf("\rPushing... %v/%v\r", k+1, total)

		// Get the contents.
		file := filepath.Join(home(), dirName, newDir, v.Name+".md")
		body, _ := ioutil.ReadFile(file)
		t := &Topic{Contents: string(body)}
		if t.Contents == "" {
			success = append(success, v.Name)
			continue
		}

		// Perform the request.
		body, _ = json.Marshal(t)
		path := "/topics/" + v.Id
		_, err := getResponse("PUT", path, bytes.NewReader(body))
		if err == nil {
			success = append(success, v.Name)
		} else {
			fails = append(fails, v.Name)
		}
	}

	// And finally update the file system.
	update(success, fails)
	return nil
}

func Status() error {
	// TODO
	return nil
}

func Create(name string) error {
	// Perform the HTTP request.
	t := &Topic{Name: name}
	body, _ := json.Marshal(t)
	res, err := getResponse("POST", "/topics", bytes.NewReader(body))
	if err != nil {
		return fromError(err)
	}

	// Parse the newly created topic and add it to the list.
	body, _ = ioutil.ReadAll(res.Body)
	if err := json.Unmarshal(body, &t); err != nil {
		return fromError(err)
	}
	addTopic(t)
	return nil
}

func Delete(name string) error {
	var topics, actual []Topic
	var id string

	// Get the list of topics straight.
	readTopics(&topics)
	for _, v := range topics {
		if v.Name == name {
			id = v.Id
		} else {
			actual = append(actual, v)
		}
	}
	if id == "" {
		unknownTopic(name)
		os.Exit(1)
	}

	// Perform the HTTP request.
	_, err := getResponse("DELETE", "/topics/"+id, nil)
	if err != nil {
		return fromError(err)
	}

	// On the system.
	writeTopics(actual)
	file := filepath.Join(home(), dirName, oldDir, name+".md")
	os.RemoveAll(file)
	file = filepath.Join(home(), dirName, newDir, name+".md")
	os.RemoveAll(file)
	return nil
}

func Rename(oldName, newName string) error {
	var topics []Topic
	var id, name string

	readTopics(&topics)
	for k, v := range topics {
		if v.Name == oldName {
			id = v.Id
			topics[k].Name = newName
		}
	}
	if id == "" {
		unknownTopic(name)
		os.Exit(1)
	}

	// Perform the HTTP Request.
	t := &Topic{Name: newName}
	body, _ := json.Marshal(t)
	_, err := getResponse("PUT", "/topics/"+id, bytes.NewReader(body))
	if err != nil {
		return fromError(err)
	}

	// Update the system.
	writeTopics(topics)
	file := filepath.Join(home(), dirName, oldDir)
	os.Rename(filepath.Join(file, oldName), filepath.Join(file, newName))
	file = filepath.Join(home(), dirName, newDir)
	os.Rename(filepath.Join(file, oldName), filepath.Join(file, newName))
	return nil
}
<commit_msg>lib: check the error of failing to set a new name for a topic.<commit_after>// Copyright (C) 2014 Miquel Sabaté Solà <mikisabate@gmail.com>
// This file is licensed under the MIT license.
// See the LICENSE file.

package lib

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/mssola/dym"
)

type Topic struct {
	Id         string    `json:"id,omitempty"`
	Name       string    `json:"name,omitempty"`
	Contents   string    `json:"contents,omitempty"`
	Created_at time.Time `json:"created_at,omitempty"`
	Markdown   string    `json:"markdown,omitempty"`
	Error      string    `json:"error,omitempty"`
}

func unknownTopic(name string) {
	var topics []Topic
	var names []string

	readTopics(&topics)
	for _, v := range topics {
		names = append(names, v.Name)
	}

	msg := fmt.Sprintf("td: the topic '%v' does not exist.", name)
	similars := dym.Similar(names, name)
	if len(similars) == 0 {
		fmt.Printf(msg)
	} else {
		msg += "\n\nDid you mean one of these?\n"
		for _, v := range similars {
			msg += "\t" + v + "\n"
		}
		fmt.Printf(msg)
	}
}

func Edit() error {
	cmd := exec.Command(editor())
	cmd.Dir = filepath.Join(home(), dirName, newDir)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func Diff() error {
	// TODO
	return nil
}

func Fetch() error {
	// Perform the HTTP request.
	res, err := getResponse("GET", "/topics", nil)
	if err != nil {
		return fromError(err)
	}

	// Parse the given topics.
	var topics []Topic
	body, _ := ioutil.ReadAll(res.Body)
	if err := json.Unmarshal(body, &topics); err != nil {
		return fromError(err)
	}

	// And save the results.
	save(topics)
	fmt.Printf("Topics updated.\n")
	return nil
}

func List() error {
	var topics []Topic
	readTopics(&topics)
	for _, v := range topics {
		fmt.Printf("%v\n", v.Name)
	}
	return nil
}

func Push() error {
	var success, fails []string
	var topics []Topic
	readTopics(&topics)

	total := len(topics)
	for k, v := range topics {
		// Print the status.
		fmt.Printf("\rPushing... %v/%v\r", k+1, total)

		// Get the contents.
		file := filepath.Join(home(), dirName, newDir, v.Name+".md")
		body, _ := ioutil.ReadFile(file)
		t := &Topic{Contents: string(body)}
		if t.Contents == "" {
			success = append(success, v.Name)
			continue
		}

		// Perform the request.
		body, _ = json.Marshal(t)
		path := "/topics/" + v.Id
		_, err := getResponse("PUT", path, bytes.NewReader(body))
		if err == nil {
			success = append(success, v.Name)
		} else {
			fails = append(fails, v.Name)
		}
	}

	// And finally update the file system.
	update(success, fails)
	return nil
}

func Status() error {
	// TODO
	return nil
}

func topicResponse(t *Topic, res *http.Response) bool {
	body, _ := ioutil.ReadAll(res.Body)
	if err := json.Unmarshal(body, t); err != nil {
		return false
	}
	if t.Error != "" {
		return false
	}
	return true
}

func Create(name string) error {
	// Perform the HTTP request.
	t := &Topic{Name: name}
	body, _ := json.Marshal(t)
	res, err := getResponse("POST", "/topics", bytes.NewReader(body))
	if err != nil {
		return fromError(err)
	}

	// Parse the newly created topic and add it to the list.
	if !topicResponse(t, res) {
		return newError("could not create this topic")
	}
	addTopic(t)
	return nil
}

func Delete(name string) error {
	var topics, actual []Topic
	var id string

	// Get the list of topics straight.
	readTopics(&topics)
	for _, v := range topics {
		if v.Name == name {
			id = v.Id
		} else {
			actual = append(actual, v)
		}
	}
	if id == "" {
		unknownTopic(name)
		os.Exit(1)
	}

	// Perform the HTTP request.
	_, err := getResponse("DELETE", "/topics/"+id, nil)
	if err != nil {
		return fromError(err)
	}

	// On the system.
	writeTopics(actual)
	file := filepath.Join(home(), dirName, oldDir, name+".md")
	os.RemoveAll(file)
	file = filepath.Join(home(), dirName, newDir, name+".md")
	os.RemoveAll(file)
	return nil
}

func Rename(oldName, newName string) error {
	var topics []Topic
	var id, name string

	readTopics(&topics)
	for k, v := range topics {
		if v.Name == oldName {
			id = v.Id
			topics[k].Name = newName
		}
	}
	if id == "" {
		unknownTopic(name)
		os.Exit(1)
	}

	// Perform the HTTP Request.
	t := &Topic{Name: newName}
	body, _ := json.Marshal(t)
	res, _ := getResponse("PUT", "/topics/"+id, bytes.NewReader(body))
	if !topicResponse(t, res) {
		return newError("could not rename this topic")
	}

	// Update the system.
	writeTopics(topics)
	file := filepath.Join(home(), dirName, oldDir)
	os.Rename(filepath.Join(file, oldName), filepath.Join(file, newName))
	file = filepath.Join(home(), dirName, newDir)
	os.Rename(filepath.Join(file, oldName), filepath.Join(file, newName))
	return nil
}
<|endoftext|>


<commit_before>package srvproxy

import (
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/streadway/handy/breaker"
	proxypkg "github.com/streadway/handy/proxy"
)

var (
	// ErrNoTransportAvailable is returned by the choosing
	// transport when no underlying transport will allow the request.
	ErrNoTransportAvailable = errors.New("no successful transport available")
)

// retryTransport forwards the request to each next RoundTripper in random
// sequence. It will return the first validated response it receives. It will
// abort when it exceeds the max attempt count, or the cutoff deadline, or it
// exhausts the next RoundTrippers, whichever occurs first.
type retryTransport struct {
	next     []http.RoundTripper
	validate breaker.ResponseValidator
	cutoff   time.Duration
	max      int
}

func (t retryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	deadline := time.Now().Add(t.cutoff)
	errs := []string{}
	for attempt, index := range rand.Perm(len(t.next)) {
		if attempt >= t.max {
			errs = append(errs, "too many attempts")
			break
		}
		if time.Now().After(deadline) {
			errs = append(errs, "deadline exceeded")
			break
		}
		resp, err := t.next[index].RoundTrip(req)
		if err != nil {
			errs = append(errs, err.Error())
			continue
		}
		if resp == nil {
			errs = append(errs, "nil response")
			continue
		}
		if !t.validate(resp) {
			errs = append(errs, "response failed validation")
			continue
		}
		return resp, err
	}
	return nil, fmt.Errorf("request failed (%s)", strings.Join(errs, "; "))
}

// updatingTransport uses a generator function to make and cache a new
// RoundTripper from Endpoints that arrive via a StreamingProxy.
type updatingTransport struct {
	requests chan http.RoundTripper
}

func newUpdatingTransport(proxy StreamingProxy, generator func([]Endpoint) http.RoundTripper) *updatingTransport {
	t := &updatingTransport{
		requests: make(chan http.RoundTripper),
	}
	go t.run(proxy, generator, generator(<-proxy.Stream())) // get one set before returning
	return t
}

func (t *updatingTransport) run(proxy StreamingProxy, generator func([]Endpoint) http.RoundTripper, next http.RoundTripper) {
	for {
		select {
		case t.requests <- next:
		case endpoints := <-proxy.Stream():
			next = generator(endpoints)
		}
	}
}

func (t *updatingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	return (<-t.requests).RoundTrip(req)
}

// makeResilientTransportGenerator returns a generator function that creates a
// retrying, round-robining, circuit-breaking http.RoundTripper around a slice
// of endpoints. All of the caveats described by NewResilientTransport apply
// here.
func makeResilientTransportGenerator(
	readTimeout time.Duration,
	retryValidator breaker.ResponseValidator,
	retryCutoff time.Duration,
	maxRetries int,
	breakerFailureRatio float64,
	maxIdleConnsPerEndpoint int,
) func([]Endpoint) http.RoundTripper {
	return func(endpoints []Endpoint) http.RoundTripper {
		candidates := make([]http.RoundTripper, len(endpoints))
		for i, endpoint := range endpoints {
			baseTransport := &http.Transport{
				ResponseHeaderTimeout: readTimeout,
				MaxIdleConnsPerHost:   maxIdleConnsPerEndpoint,
			}
			proxyHost := fmt.Sprintf("%s:%d", endpoint.IP, endpoint.Port) // capture
			rewritingTransport := proxypkg.Transport{
				Proxy: func(req *http.Request) (*url.URL, error) {
					return &url.URL{
						Scheme:   req.URL.Scheme,
						Opaque:   req.URL.Opaque,
						User:     req.URL.User,
						Host:     proxyHost,
						Path:     req.URL.Path,
						RawQuery: req.URL.RawQuery,
						Fragment: req.URL.Fragment,
					}, nil
				},
				Next: baseTransport,
			}
			candidates[i] = breaker.Transport(
				breaker.NewBreaker(breakerFailureRatio),
				breaker.DefaultResponseValidator,
				rewritingTransport,
			)
		}
		return retryTransport{
			next:     candidates,
			validate: retryValidator,
			cutoff:   retryCutoff,
			max:      maxRetries + 1, // attempts = retries + 1
		}
	}
}

// NewResilientTransport creates an http.RoundTripper that acts as a resilient
// round-robining proxy over endpoints yielded by the proxy. Resiliency is
// achieved by combining a circuit breaker per endpoint with introspective
// retry logic over all endpoints. Endpoints are assumed to be functionally
// identical. Requests are assumed to be idempotent.
//
// Retry validator determines if a given non-error response is valid and can
// be returned to the client, or should be retried. Retry cutoff is a hard
// deadline after which no more retries will be attempted, and the most recent
// error will be returned to the client. Max retries is the maximum number of
// retries that will be attempted within the deadline. Breaker failure ratio
// sets how many failures per success are required to trigger the circuit
// breaker and open the circuit.
func NewResilientTransport(
	proxy StreamingProxy,
	readTimeout time.Duration,
	retryValidator breaker.ResponseValidator,
	retryCutoff time.Duration,
	maxRetries int,
	breakerFailureRatio float64,
	maxIdleConnsPerEndpoint int,
) http.RoundTripper {
	return newUpdatingTransport(
		proxy,
		makeResilientTransportGenerator(
			readTimeout,
			retryValidator,
			retryCutoff,
			maxRetries,
			breakerFailureRatio,
			maxIdleConnsPerEndpoint,
		),
	)
}
<commit_msg>Remove dead code in resilient transport<commit_after>package srvproxy

import (
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/streadway/handy/breaker"
	proxypkg "github.com/streadway/handy/proxy"
)

// retryTransport forwards the request to each next RoundTripper in random
// sequence. It will return the first validated response it receives. It will
// abort when it exceeds the max attempt count, or the cutoff deadline, or it
// exhausts the next RoundTrippers, whichever occurs first.
type retryTransport struct {
	next     []http.RoundTripper
	validate breaker.ResponseValidator
	cutoff   time.Duration
	max      int
}

func (t retryTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	deadline := time.Now().Add(t.cutoff)
	errs := []string{}
	for attempt, index := range rand.Perm(len(t.next)) {
		if attempt >= t.max {
			errs = append(errs, "too many attempts")
			break
		}
		if time.Now().After(deadline) {
			errs = append(errs, "deadline exceeded")
			break
		}
		resp, err := t.next[index].RoundTrip(req)
		if err != nil {
			errs = append(errs, err.Error())
			continue
		}
		if resp == nil {
			errs = append(errs, "nil response")
			continue
		}
		if !t.validate(resp) {
			errs = append(errs, "response failed validation")
			continue
		}
		return resp, err
	}
	return nil, fmt.Errorf("request failed (%s)", strings.Join(errs, "; "))
}

// updatingTransport uses a generator function to make and cache a new
// RoundTripper from Endpoints that arrive via a StreamingProxy.
type updatingTransport struct {
	requests chan http.RoundTripper
}

func newUpdatingTransport(proxy StreamingProxy, generator func([]Endpoint) http.RoundTripper) *updatingTransport {
	t := &updatingTransport{
		requests: make(chan http.RoundTripper),
	}
	go t.run(proxy, generator, generator(<-proxy.Stream())) // get one set before returning
	return t
}

func (t *updatingTransport) run(proxy StreamingProxy, generator func([]Endpoint) http.RoundTripper, next http.RoundTripper) {
	for {
		select {
		case t.requests <- next:
		case endpoints := <-proxy.Stream():
			next = generator(endpoints)
		}
	}
}

func (t *updatingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	return (<-t.requests).RoundTrip(req)
}

// makeResilientTransportGenerator returns a generator function that creates a
// retrying, round-robining, circuit-breaking http.RoundTripper around a slice
// of endpoints. All of the caveats described by NewResilientTransport apply
// here.
func makeResilientTransportGenerator(
	readTimeout time.Duration,
	retryValidator breaker.ResponseValidator,
	retryCutoff time.Duration,
	maxRetries int,
	breakerFailureRatio float64,
	maxIdleConnsPerEndpoint int,
) func([]Endpoint) http.RoundTripper {
	return func(endpoints []Endpoint) http.RoundTripper {
		candidates := make([]http.RoundTripper, len(endpoints))
		for i, endpoint := range endpoints {
			baseTransport := &http.Transport{
				ResponseHeaderTimeout: readTimeout,
				MaxIdleConnsPerHost:   maxIdleConnsPerEndpoint,
			}
			proxyHost := fmt.Sprintf("%s:%d", endpoint.IP, endpoint.Port) // capture
			rewritingTransport := proxypkg.Transport{
				Proxy: func(req *http.Request) (*url.URL, error) {
					return &url.URL{
						Scheme:   req.URL.Scheme,
						Opaque:   req.URL.Opaque,
						User:     req.URL.User,
						Host:     proxyHost,
						Path:     req.URL.Path,
						RawQuery: req.URL.RawQuery,
						Fragment: req.URL.Fragment,
					}, nil
				},
				Next: baseTransport,
			}
			candidates[i] = breaker.Transport(
				breaker.NewBreaker(breakerFailureRatio),
				breaker.DefaultResponseValidator,
				rewritingTransport,
			)
		}
		return retryTransport{
			next:     candidates,
			validate: retryValidator,
			cutoff:   retryCutoff,
			max:      maxRetries + 1, // attempts = retries + 1
		}
	}
}

// NewResilientTransport creates an http.RoundTripper that acts as a resilient
// round-robining proxy over endpoints yielded by the proxy. Resiliency is
// achieved by combining a circuit breaker per endpoint with introspective
// retry logic over all endpoints. Endpoints are assumed to be functionally
// identical. Requests are assumed to be idempotent.
//
// Retry validator determines if a given non-error response is valid and can
// be returned to the client, or should be retried. Retry cutoff is a hard
// deadline after which no more retries will be attempted, and the most recent
// error will be returned to the client. Max retries is the maximum number of
// retries that will be attempted within the deadline. Breaker failure ratio
// sets how many failures per success are required to trigger the circuit
// breaker and open the circuit.
func NewResilientTransport(
	proxy StreamingProxy,
	readTimeout time.Duration,
	retryValidator breaker.ResponseValidator,
	retryCutoff time.Duration,
	maxRetries int,
	breakerFailureRatio float64,
	maxIdleConnsPerEndpoint int,
) http.RoundTripper {
	return newUpdatingTransport(
		proxy,
		makeResilientTransportGenerator(
			readTimeout,
			retryValidator,
			retryCutoff,
			maxRetries,
			breakerFailureRatio,
			maxIdleConnsPerEndpoint,
		),
	)
}
<|endoftext|>


<commit_before>package resource

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

	"github.com/cloudfoundry-incubator/garden"
	"github.com/tedsuo/ifrit"
)

var ErrAborted = errors.New("script aborted")

const resourceProcessIDPropertyName = "resource-process"
const resourceResultPropertyName = "resource-result"

type ErrResourceScriptFailed struct {
	Path       string
	Args       []string
	Stdout     string
	Stderr     string
	ExitStatus int
}

func (err ErrResourceScriptFailed) Error() string {
	return fmt.Sprintf(
		"resource script '%s %v' failed: exit status %d\n\nstdout:\n\n%s\n\nstderr:\n\n%s",
		err.Path,
		err.Args,
		err.ExitStatus,
		err.Stdout,
		err.Stderr,
	)
}

func (resource *resource) runScript(
	path string,
	args []string,
	input interface{},
	output interface{},
	logDest io.Writer,
	inputSource ArtifactSource,
	inputDestination ArtifactDestination,
	recoverable bool,
) ifrit.Runner {
	return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error {
		request, err := json.Marshal(input)
		if err != nil {
			return err
		}

		if recoverable {
			result, err := resource.container.GetProperty(resourceResultPropertyName)
			if err == nil {
				return json.Unmarshal([]byte(result), &output)
			}
		}

		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		var stderrW io.Writer
		if logDest != nil {
			stderrW = io.MultiWriter(logDest, stderr)
		} else {
			stderrW = stderr
		}

		processIO := garden.ProcessIO{
			Stdin:  bytes.NewBuffer(request),
			Stderr: stderrW,
			Stdout: stdout,
		}

		var process garden.Process

		processIDProp, err := resource.container.GetProperty(resourceProcessIDPropertyName)
		if recoverable && err == nil {
			var processID uint32
			_, err = fmt.Sscanf(processIDProp, "%d", &processID)
			if err != nil {
				return err
			}

			process, err = resource.container.Attach(processID, processIO)
			if err != nil {
				return err
			}
		} else {
			if inputSource != nil {
				err := inputSource.StreamTo(inputDestination)
				if err != nil {
					return err
				}
			}

			process, err = resource.container.Run(garden.ProcessSpec{
				Path:       path,
				Args:       args,
				Privileged: true,
			}, processIO)
			if err != nil {
				return err
			}

			if recoverable {
				processIDValue := fmt.Sprintf("%d", process.ID())

				err := resource.container.SetProperty(resourceProcessIDPropertyName, processIDValue)
				if err != nil {
					return err
				}
			}
		}

		close(ready)

		statusCh := make(chan int, 1)
		errCh := make(chan error, 1)

		go func() {
			status, err := process.Wait()
			if err != nil {
				errCh <- err
			} else {
				statusCh <- status
			}
		}()

		select {
		case status := <-statusCh:
			if status != 0 {
				return ErrResourceScriptFailed{
					Path:       path,
					Args:       args,
					Stdout:     stdout.String(),
					Stderr:     stderr.String(),
					ExitStatus: status,
				}
			}

			if recoverable {
				err := resource.container.SetProperty(resourceResultPropertyName, stdout.String())
				if err != nil {
					return err
				}
			}

			return json.Unmarshal(stdout.Bytes(), output)

		case err := <-errCh:
			return err

		case <-signals:
			resource.container.Stop(false)
			return ErrAborted
		}
	})
}
<commit_msg>only get process ID property when recoverable<commit_after>package resource

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

	"github.com/cloudfoundry-incubator/garden"
	"github.com/tedsuo/ifrit"
)

var ErrAborted = errors.New("script aborted")

const resourceProcessIDPropertyName = "resource-process"
const resourceResultPropertyName = "resource-result"

type ErrResourceScriptFailed struct {
	Path       string
	Args       []string
	Stdout     string
	Stderr     string
	ExitStatus int
}

func (err ErrResourceScriptFailed) Error() string {
	return fmt.Sprintf(
		"resource script '%s %v' failed: exit status %d\n\nstdout:\n\n%s\n\nstderr:\n\n%s",
		err.Path,
		err.Args,
		err.ExitStatus,
		err.Stdout,
		err.Stderr,
	)
}

func (resource *resource) runScript(
	path string,
	args []string,
	input interface{},
	output interface{},
	logDest io.Writer,
	inputSource ArtifactSource,
	inputDestination ArtifactDestination,
	recoverable bool,
) ifrit.Runner {
	return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error {
		request, err := json.Marshal(input)
		if err != nil {
			return err
		}

		if recoverable {
			result, err := resource.container.GetProperty(resourceResultPropertyName)
			if err == nil {
				return json.Unmarshal([]byte(result), &output)
			}
		}

		stdout := new(bytes.Buffer)
		stderr := new(bytes.Buffer)

		var stderrW io.Writer
		if logDest != nil {
			stderrW = io.MultiWriter(logDest, stderr)
		} else {
			stderrW = stderr
		}

		processIO := garden.ProcessIO{
			Stdin:  bytes.NewBuffer(request),
			Stderr: stderrW,
			Stdout: stdout,
		}

		var process garden.Process

		var processIDProp string
		if recoverable {
			processIDProp, err = resource.container.GetProperty(resourceProcessIDPropertyName)
			if err != nil {
				processIDProp = ""
			}
		}

		if processIDProp != "" {
			var processID uint32
			_, err = fmt.Sscanf(processIDProp, "%d", &processID)
			if err != nil {
				return err
			}

			process, err = resource.container.Attach(processID, processIO)
			if err != nil {
				return err
			}
		} else {
			if inputSource != nil {
				err := inputSource.StreamTo(inputDestination)
				if err != nil {
					return err
				}
			}

			process, err = resource.container.Run(garden.ProcessSpec{
				Path:       path,
				Args:       args,
				Privileged: true,
			}, processIO)
			if err != nil {
				return err
			}

			if recoverable {
				processIDValue := fmt.Sprintf("%d", process.ID())

				err := resource.container.SetProperty(resourceProcessIDPropertyName, processIDValue)
				if err != nil {
					return err
				}
			}
		}

		close(ready)

		statusCh := make(chan int, 1)
		errCh := make(chan error, 1)

		go func() {
			status, err := process.Wait()
			if err != nil {
				errCh <- err
			} else {
				statusCh <- status
			}
		}()

		select {
		case status := <-statusCh:
			if status != 0 {
				return ErrResourceScriptFailed{
					Path:       path,
					Args:       args,
					Stdout:     stdout.String(),
					Stderr:     stderr.String(),
					ExitStatus: status,
				}
			}

			if recoverable {
				err := resource.container.SetProperty(resourceResultPropertyName, stdout.String())
				if err != nil {
					return err
				}
			}

			return json.Unmarshal(stdout.Bytes(), output)

		case err := <-errCh:
			return err

		case <-signals:
			resource.container.Stop(false)
			return ErrAborted
		}
	})
}
<|endoftext|>


<commit_before>package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

import (
	"image"
	"image/color"
	"unsafe"
)

type Surface struct {
	s *C.SDL_Surface
}

// BEGIN Pixel Info {{{1

// The following helpers are modified directly from SDL 2.0 source code:
// include/SDL_pixels.h

type PixelType uint32

const (
	PixelTypeUnknown PixelType = iota
	PixelTypeIndex1
	PixelTypeIndex4
	PixelTypeIndex8
	PixelTypePacked8
	PixelTypePacked16
	PixelTypePacked32
	PixelTypeArrayU8
	PixelTypeArrayU16
	PixelTypeArrayU32
	PixelTypeArrayF16
	PixelTypeArrayF32
)

type PixelOrder uint32

// Bitmap pixel order, high bit -> low bit.
const (
	BitmapOrderNone PixelOrder = iota
	BitmapOrder4321
	BitmapOrder1234
)

// Packed component order, high bit -> low bit.
const (
	PackedOrderNone PixelOrder = iota
	PackedOrderXRGB
	PackedOrderRGBX
	PackedOrderARGB
	PackedOrderRGBA
	PackedOrderXBGR
	PackedOrderBGRX
	PackedOrderABGR
	PackedOrderBGRA
)

// Array component order, low byte -> high byte.
const (
	ArrayOrderNone PixelOrder = iota
	ArrayOrderRGB
	ArrayOrderRGBA
	ArrayOrderARGB
	ArrayOrderBGR
	ArrayOrderBGRA
	ArrayOrderABGR
)

type PackedLayout uint32

// Packed component layout.
const (
	PackedLayoutNone PackedLayout = iota
	PackedLayout332
	PackedLayout4444
	PackedLayout1555
	PackedLayout5551
	PackedLayout565
	PackedLayout8888
	PackedLayout2101010
	PackedLayout1010102
)

func DEFINE_PIXELFOURCC(A, B, C, D uint32) PixelFormat {
	return PixelFormat((A << 0) | (B << 8) | (C << 16) | (D << 24))
}

func DEFINE_PIXELFORMAT(typ PixelType, order PixelOrder, layout PackedLayout, bits, bytes uint32) PixelFormat {
	return PixelFormat((1 << 28) | uint32(typ<<24) | uint32(order<<20) | uint32(layout<<16) | uint32(bits<<8) | uint32(bytes<<0))
}

func PIXELFLAG(X PixelFormat) PixelFormat {
	return (X >> 28) & 0x0F
}

func PIXELTYPE(X PixelFormat) PixelType {
	return PixelType((X >> 24) & 0x0F)
}

func PIXELORDER(X PixelFormat) PixelOrder {
	return PixelOrder((X >> 20) & 0x0F)
}

func PIXELLAYOUT(X PixelFormat) PackedLayout {
	return PackedLayout((X >> 16) & 0x0F)
}

func BITSPERPIXEL(X PixelFormat) uint32 {
	return uint32(X>>8) & 0xFF
}

func BYTESPERPIXEL(X PixelFormat) PixelFormat {
	if ISPIXELFORMAT_FOURCC(X) {
		if X == PixelFormatYUY2 || X == PixelFormatUYVY || X == PixelFormatYVYU {
			return 2
		}
		return 1
	}
	return (X >> 0) & 0xFF
}

func ISPIXELFORMAT_INDEXED(format PixelFormat) bool {
	pixelType := PIXELTYPE(format)
	return !ISPIXELFORMAT_FOURCC(format) &&
		((pixelType == PixelTypeIndex1) ||
			(pixelType == PixelTypeIndex4) ||
			(pixelType == PixelTypeIndex8))
}

func ISPIXELFORMAT_ALPHA(format PixelFormat) bool {
	pixelOrder := PIXELORDER(format)
	return !ISPIXELFORMAT_FOURCC(format) &&
		((pixelOrder == PackedOrderARGB) ||
			(pixelOrder == PackedOrderRGBA) ||
			(pixelOrder == PackedOrderABGR) ||
			(pixelOrder == PackedOrderBGRA))
}

// The flag is set to 1 because 0x1? is not in the printable ASCII range
func ISPIXELFORMAT_FOURCC(format PixelFormat) bool {
	return format != 0 && PIXELFLAG(format) != 1
}

type PixelFormat uint32

const (
	PixelFormatUnknown     PixelFormat = PixelFormat(C.SDL_PIXELFORMAT_UNKNOWN)
	PixelFormatIndex1LSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX1LSB)
	PixelFormatIndex1MSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX1MSB)
	PixelFormatIndex4LSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX4LSB)
	PixelFormatIndex4MSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX4MSB)
	PixelFormatIndex8                  = PixelFormat(C.SDL_PIXELFORMAT_INDEX8)
	PixelFormatRGB332                  = PixelFormat(C.SDL_PIXELFORMAT_RGB332)
	PixelFormatRGB444                  = PixelFormat(C.SDL_PIXELFORMAT_RGB444)
	PixelFormatRGB555                  = PixelFormat(C.SDL_PIXELFORMAT_RGB555)
	PixelFormatBGR555                  = PixelFormat(C.SDL_PIXELFORMAT_BGR555)
	PixelFormatARGB4444                = PixelFormat(C.SDL_PIXELFORMAT_ARGB4444)
	PixelFormatRGBA4444                = PixelFormat(C.SDL_PIXELFORMAT_RGBA4444)
	PixelFormatABGR4444                = PixelFormat(C.SDL_PIXELFORMAT_ABGR4444)
	PixelFormatBGRA4444                = PixelFormat(C.SDL_PIXELFORMAT_BGRA4444)
	PixelFormatARGB1555                = PixelFormat(C.SDL_PIXELFORMAT_ARGB1555)
	PixelFormatRGBA5551                = PixelFormat(C.SDL_PIXELFORMAT_RGBA5551)
	PixelFormatABGR1555                = PixelFormat(C.SDL_PIXELFORMAT_ABGR1555)
	PixelFormatBGRA5551                = PixelFormat(C.SDL_PIXELFORMAT_BGRA5551)
	PixelFormatRGB565                  = PixelFormat(C.SDL_PIXELFORMAT_RGB565)
	PixelFormatBGR565                  = PixelFormat(C.SDL_PIXELFORMAT_BGR565)
	PixelFormatRGB24                   = PixelFormat(C.SDL_PIXELFORMAT_RGB24)
	PixelFormatBGR24                   = PixelFormat(C.SDL_PIXELFORMAT_BGR24)
	PixelFormatRGB888                  = PixelFormat(C.SDL_PIXELFORMAT_RGB888)
	PixelFormatRGBX8888                = PixelFormat(C.SDL_PIXELFORMAT_RGBX8888)
	PixelFormatBGR888                  = PixelFormat(C.SDL_PIXELFORMAT_BGR888)
	PixelFormatBGRX8888                = PixelFormat(C.SDL_PIXELFORMAT_BGRX8888)
	PixelFormatARGB8888                = PixelFormat(C.SDL_PIXELFORMAT_ARGB8888)
	PixelFormatRGBA8888                = PixelFormat(C.SDL_PIXELFORMAT_RGBA8888)
	PixelFormatABGR8888                = PixelFormat(C.SDL_PIXELFORMAT_ABGR8888)
	PixelFormatBGRA8888                = PixelFormat(C.SDL_PIXELFORMAT_BGRA8888)
	PixelFormatARGB2101010             = PixelFormat(C.SDL_PIXELFORMAT_ARGB2101010)
	PixelFormatYV12                    = PixelFormat(C.SDL_PIXELFORMAT_YV12)
	PixelFormatIYUV                    = PixelFormat(C.SDL_PIXELFORMAT_IYUV)
	PixelFormatYUY2                    = PixelFormat(C.SDL_PIXELFORMAT_YUY2)
	PixelFormatUYVY                    = PixelFormat(C.SDL_PIXELFORMAT_UYVY)
	PixelFormatYVYU                    = PixelFormat(C.SDL_PIXELFORMAT_YVYU)
)

// END Pixel Info }}}1

func (surface Surface) PixelData() (PixelData, error) {
	if result := C.SDL_LockSurface(surface.s); result < 0 {
		return PixelData{}, getError()
	}
	return PixelData{s: surface.s}, nil
}

// Implements the image.Image and draw.Image interfaces
// See: http://golang.org/pkg/image/#Image http://golang.org/pkg/image/draw/#Image
type PixelData struct {
	s *C.SDL_Surface
}

// Expand out a component of a color from a pixel representing the color.
// TODO unit tests
func expandColor(pixel uint32, mask C.Uint32, shift, loss C.Uint8) uint8 {
	temp := pixel & uint32(mask)
	temp = temp >> uint8(shift)
	return uint8(temp << uint8(loss))
}

// Takes a uintptr to the pixel data from an SDL Surface and returns a pointer to the particular
// pixel referenced by parameters.
// Pitch is the number of bytes that make up one horizontal row (same as the field in SDL_Surface)
func getPixelPointer(pixels uintptr, x, y, bytesPerPixel, pitch int) unsafe.Pointer {
	offset := x*bytesPerPixel + y*pitch
	return unsafe.Pointer(pixels + uintptr(offset))
}

func (pix PixelData) At(x, y int) color.Color {
	format := pix.s.format
	bytesPerPixel := int(format.BytesPerPixel)

	ptr := getPixelPointer(uintptr(pix.s.pixels), x, y, bytesPerPixel, int(pix.s.pitch))
	pixel := *(*uint32)(ptr)

	// TODO not necesarily NRGBA (which would be an entirely different codepath)
	col := color.NRGBA{}

	switch bytesPerPixel {
	case 1:
		// TODO look up the color in color palette
	case 2, 3, 4:
		col.R = expandColor(pixel, format.Rmask, format.Rshift, format.Rloss)
		col.G = expandColor(pixel, format.Gmask, format.Gshift, format.Gloss)
		col.B = expandColor(pixel, format.Bmask, format.Bshift, format.Bloss)
		// If the alpha mask is 0, there's no alpha component, so set it to 1
		if format.Amask == 0 {
			col.A = 1
		} else {
			col.A = expandColor(pixel, format.Amask, format.Ashift, format.Aloss)
		}
	}

	return col
}

func (pix PixelData) ColorModel() color.Model {
	// TODO this is a guess
	return color.NRGBAModel
}

// PixelData doesn't actually know where it is on the screen, so return (0,0) => (w,h)
func (pix PixelData) Bounds() image.Rectangle {
	return image.Rectangle{image.Point{0, 0}, image.Point{int(pix.s.w), int(pix.s.h)}}
}

// Collapse a component of the color into a pointer at a pixel representing the color.
// TODO unit tests
func collapseColor(pixel *uint32, color uint8, shift, loss C.Uint8) {
	temp := uint32(color >> uint8(loss))
	temp = temp << uint8(shift)
	*pixel = *pixel & temp
}

// Set the color at an x, y position in the PixelData to a given color.
func (pix PixelData) Set(x, y int, c color.Color) {
	format := pix.s.format
	bytesPerPixel := int(format.BytesPerPixel)

	switch bytesPerPixel {
	case 1:
		// TODO look up the color in color palette
	case 2, 3, 4:
		// if necessary, convert color model to NRGBA
		col := pix.ColorModel().Convert(c).(color.NRGBA)

		// put that in a uint32 that I can slap into the void* of pixel data (also helper function?)
		var pixel *uint32
		collapseColor(pixel, col.R, format.Rshift, format.Rloss)
		collapseColor(pixel, col.G, format.Gshift, format.Gloss)
		collapseColor(pixel, col.B, format.Bshift, format.Bloss)
		// If the alpha mask is 0, there's no alpha component, so set it to 1
		if format.Amask == 0 {
			col.A = 1
		}
		collapseColor(pixel, col.A, format.Ashift, format.Aloss)

		// get pixel offset that's (x, y)
		ptr := getPixelPointer(uintptr(pix.s.pixels), x, y, bytesPerPixel, int(pix.s.pitch))

		// slap it in
		*(*uint32)(ptr) = *pixel
	}
}

func (pix PixelData) Close() error {
	C.SDL_UnlockSurface(pix.s)
	return nil
}
<commit_msg>Sufrace: add ToTexture() and Free()<commit_after>package sdl

// #cgo pkg-config: sdl2
// #cgo LDFLAGS: -lSDL2_image
//
// #include "SDL.h"
import "C"

import (
	"image"
	"image/color"
	"unsafe"
)

type Surface struct {
	s *C.SDL_Surface
}

// BEGIN Pixel Info {{{1

// The following helpers are modified directly from SDL 2.0 source code:
// include/SDL_pixels.h

type PixelType uint32

const (
	PixelTypeUnknown PixelType = iota
	PixelTypeIndex1
	PixelTypeIndex4
	PixelTypeIndex8
	PixelTypePacked8
	PixelTypePacked16
	PixelTypePacked32
	PixelTypeArrayU8
	PixelTypeArrayU16
	PixelTypeArrayU32
	PixelTypeArrayF16
	PixelTypeArrayF32
)

type PixelOrder uint32

// Bitmap pixel order, high bit -> low bit.
const (
	BitmapOrderNone PixelOrder = iota
	BitmapOrder4321
	BitmapOrder1234
)

// Packed component order, high bit -> low bit.
const (
	PackedOrderNone PixelOrder = iota
	PackedOrderXRGB
	PackedOrderRGBX
	PackedOrderARGB
	PackedOrderRGBA
	PackedOrderXBGR
	PackedOrderBGRX
	PackedOrderABGR
	PackedOrderBGRA
)

// Array component order, low byte -> high byte.
const (
	ArrayOrderNone PixelOrder = iota
	ArrayOrderRGB
	ArrayOrderRGBA
	ArrayOrderARGB
	ArrayOrderBGR
	ArrayOrderBGRA
	ArrayOrderABGR
)

type PackedLayout uint32

// Packed component layout.
const (
	PackedLayoutNone PackedLayout = iota
	PackedLayout332
	PackedLayout4444
	PackedLayout1555
	PackedLayout5551
	PackedLayout565
	PackedLayout8888
	PackedLayout2101010
	PackedLayout1010102
)

func DEFINE_PIXELFOURCC(A, B, C, D uint32) PixelFormat {
	return PixelFormat((A << 0) | (B << 8) | (C << 16) | (D << 24))
}

func DEFINE_PIXELFORMAT(typ PixelType, order PixelOrder, layout PackedLayout, bits, bytes uint32) PixelFormat {
	return PixelFormat((1 << 28) | uint32(typ<<24) | uint32(order<<20) | uint32(layout<<16) | uint32(bits<<8) | uint32(bytes<<0))
}

func PIXELFLAG(X PixelFormat) PixelFormat {
	return (X >> 28) & 0x0F
}

func PIXELTYPE(X PixelFormat) PixelType {
	return PixelType((X >> 24) & 0x0F)
}

func PIXELORDER(X PixelFormat) PixelOrder {
	return PixelOrder((X >> 20) & 0x0F)
}

func PIXELLAYOUT(X PixelFormat) PackedLayout {
	return PackedLayout((X >> 16) & 0x0F)
}

func BITSPERPIXEL(X PixelFormat) uint32 {
	return uint32(X>>8) & 0xFF
}

func BYTESPERPIXEL(X PixelFormat) PixelFormat {
	if ISPIXELFORMAT_FOURCC(X) {
		if X == PixelFormatYUY2 || X == PixelFormatUYVY || X == PixelFormatYVYU {
			return 2
		}
		return 1
	}
	return (X >> 0) & 0xFF
}

func ISPIXELFORMAT_INDEXED(format PixelFormat) bool {
	pixelType := PIXELTYPE(format)
	return !ISPIXELFORMAT_FOURCC(format) &&
		((pixelType == PixelTypeIndex1) ||
			(pixelType == PixelTypeIndex4) ||
			(pixelType == PixelTypeIndex8))
}

func ISPIXELFORMAT_ALPHA(format PixelFormat) bool {
	pixelOrder := PIXELORDER(format)
	return !ISPIXELFORMAT_FOURCC(format) &&
		((pixelOrder == PackedOrderARGB) ||
			(pixelOrder == PackedOrderRGBA) ||
			(pixelOrder == PackedOrderABGR) ||
			(pixelOrder == PackedOrderBGRA))
}

// The flag is set to 1 because 0x1? is not in the printable ASCII range
func ISPIXELFORMAT_FOURCC(format PixelFormat) bool {
	return format != 0 && PIXELFLAG(format) != 1
}

type PixelFormat uint32

const (
	PixelFormatUnknown     PixelFormat = PixelFormat(C.SDL_PIXELFORMAT_UNKNOWN)
	PixelFormatIndex1LSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX1LSB)
	PixelFormatIndex1MSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX1MSB)
	PixelFormatIndex4LSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX4LSB)
	PixelFormatIndex4MSB               = PixelFormat(C.SDL_PIXELFORMAT_INDEX4MSB)
	PixelFormatIndex8                  = PixelFormat(C.SDL_PIXELFORMAT_INDEX8)
	PixelFormatRGB332                  = PixelFormat(C.SDL_PIXELFORMAT_RGB332)
	PixelFormatRGB444                  = PixelFormat(C.SDL_PIXELFORMAT_RGB444)
	PixelFormatRGB555                  = PixelFormat(C.SDL_PIXELFORMAT_RGB555)
	PixelFormatBGR555                  = PixelFormat(C.SDL_PIXELFORMAT_BGR555)
	PixelFormatARGB4444                = PixelFormat(C.SDL_PIXELFORMAT_ARGB4444)
	PixelFormatRGBA4444                = PixelFormat(C.SDL_PIXELFORMAT_RGBA4444)
	PixelFormatABGR4444                = PixelFormat(C.SDL_PIXELFORMAT_ABGR4444)
	PixelFormatBGRA4444                = PixelFormat(C.SDL_PIXELFORMAT_BGRA4444)
	PixelFormatARGB1555                = PixelFormat(C.SDL_PIXELFORMAT_ARGB1555)
	PixelFormatRGBA5551                = PixelFormat(C.SDL_PIXELFORMAT_RGBA5551)
	PixelFormatABGR1555                = PixelFormat(C.SDL_PIXELFORMAT_ABGR1555)
	PixelFormatBGRA5551                = PixelFormat(C.SDL_PIXELFORMAT_BGRA5551)
	PixelFormatRGB565                  = PixelFormat(C.SDL_PIXELFORMAT_RGB565)
	PixelFormatBGR565                  = PixelFormat(C.SDL_PIXELFORMAT_BGR565)
	PixelFormatRGB24                   = PixelFormat(C.SDL_PIXELFORMAT_RGB24)
	PixelFormatBGR24                   = PixelFormat(C.SDL_PIXELFORMAT_BGR24)
	PixelFormatRGB888                  = PixelFormat(C.SDL_PIXELFORMAT_RGB888)
	PixelFormatRGBX8888                = PixelFormat(C.SDL_PIXELFORMAT_RGBX8888)
	PixelFormatBGR888                  = PixelFormat(C.SDL_PIXELFORMAT_BGR888)
	PixelFormatBGRX8888                = PixelFormat(C.SDL_PIXELFORMAT_BGRX8888)
	PixelFormatARGB8888                = PixelFormat(C.SDL_PIXELFORMAT_ARGB8888)
	PixelFormatRGBA8888                = PixelFormat(C.SDL_PIXELFORMAT_RGBA8888)
	PixelFormatABGR8888                = PixelFormat(C.SDL_PIXELFORMAT_ABGR8888)
	PixelFormatBGRA8888                = PixelFormat(C.SDL_PIXELFORMAT_BGRA8888)
	PixelFormatARGB2101010             = PixelFormat(C.SDL_PIXELFORMAT_ARGB2101010)
	PixelFormatYV12                    = PixelFormat(C.SDL_PIXELFORMAT_YV12)
	PixelFormatIYUV                    = PixelFormat(C.SDL_PIXELFORMAT_IYUV)
	PixelFormatYUY2                    = PixelFormat(C.SDL_PIXELFORMAT_YUY2)
	PixelFormatUYVY                    = PixelFormat(C.SDL_PIXELFORMAT_UYVY)
	PixelFormatYVYU                    = PixelFormat(C.SDL_PIXELFORMAT_YVYU)
)

// END Pixel Info }}}1

func (surface Surface) PixelData() (PixelData, error) {
	if result := C.SDL_LockSurface(surface.s); result < 0 {
		return PixelData{}, getError()
	}
	return PixelData{s: surface.s}, nil
}

// SDL_CreateTextureFromSurface
func (surface Surface) ToTexture(renderer Renderer) (Texture, error) {
	txt := C.SDL_CreateTextureFromSurface(renderer.r, surface.s)
	if txt == nil {
		return Texture{}, getError()
	}
	return Texture{txt}, nil
}

func (surface Surface) Free() {
	C.SDL_FreeSurface(surface.s)
}

// Implements the image.Image and draw.Image interfaces
// See: http://golang.org/pkg/image/#Image http://golang.org/pkg/image/draw/#Image
type PixelData struct {
	s *C.SDL_Surface
}

// Expand out a component of a color from a pixel representing the color.
// TODO unit tests
func expandColor(pixel uint32, mask C.Uint32, shift, loss C.Uint8) uint8 {
	temp := pixel & uint32(mask)
	temp = temp >> uint8(shift)
	return uint8(temp << uint8(loss))
}

// Takes a uintptr to the pixel data from an SDL Surface and returns a pointer to the particular
// pixel referenced by parameters.
// Pitch is the number of bytes that make up one horizontal row (same as the field in SDL_Surface)
func getPixelPointer(pixels uintptr, x, y, bytesPerPixel, pitch int) unsafe.Pointer {
	offset := x*bytesPerPixel + y*pitch
	return unsafe.Pointer(pixels + uintptr(offset))
}

func (pix PixelData) At(x, y int) color.Color {
	format := pix.s.format
	bytesPerPixel := int(format.BytesPerPixel)

	ptr := getPixelPointer(uintptr(pix.s.pixels), x, y, bytesPerPixel, int(pix.s.pitch))
	pixel := *(*uint32)(ptr)

	// TODO not necesarily NRGBA (which would be an entirely different codepath)
	col := color.NRGBA{}

	switch bytesPerPixel {
	case 1:
		// TODO look up the color in color palette
	case 2, 3, 4:
		col.R = expandColor(pixel, format.Rmask, format.Rshift, format.Rloss)
		col.G = expandColor(pixel, format.Gmask, format.Gshift, format.Gloss)
		col.B = expandColor(pixel, format.Bmask, format.Bshift, format.Bloss)
		// If the alpha mask is 0, there's no alpha component, so set it to 1
		if format.Amask == 0 {
			col.A = 1
		} else {
			col.A = expandColor(pixel, format.Amask, format.Ashift, format.Aloss)
		}
	}

	return col
}

func (pix PixelData) ColorModel() color.Model {
	// TODO this is a guess
	return color.NRGBAModel
}

// PixelData doesn't actually know where it is on the screen, so return (0,0) => (w,h)
func (pix PixelData) Bounds() image.Rectangle {
	return image.Rectangle{image.Point{0, 0}, image.Point{int(pix.s.w), int(pix.s.h)}}
}

// Collapse a component of the color into a pointer at a pixel representing the color.
// TODO unit tests
func collapseColor(pixel *uint32, color uint8, shift, loss C.Uint8) {
	temp := uint32(color >> uint8(loss))
	temp = temp << uint8(shift)
	*pixel = *pixel & temp
}

// Set the color at an x, y position in the PixelData to a given color.
func (pix PixelData) Set(x, y int, c color.Color) {
	format := pix.s.format
	bytesPerPixel := int(format.BytesPerPixel)

	switch bytesPerPixel {
	case 1:
		// TODO look up the color in color palette
	case 2, 3, 4:
		// if necessary, convert color model to NRGBA
		col := pix.ColorModel().Convert(c).(color.NRGBA)

		// put that in a uint32 that I can slap into the void* of pixel data (also helper function?)
		var pixel *uint32
		collapseColor(pixel, col.R, format.Rshift, format.Rloss)
		collapseColor(pixel, col.G, format.Gshift, format.Gloss)
		collapseColor(pixel, col.B, format.Bshift, format.Bloss)
		// If the alpha mask is 0, there's no alpha component, so set it to 1
		if format.Amask == 0 {
			col.A = 1
		}
		collapseColor(pixel, col.A, format.Ashift, format.Aloss)

		// get pixel offset that's (x, y)
		ptr := getPixelPointer(uintptr(pix.s.pixels), x, y, bytesPerPixel, int(pix.s.pitch))

		// slap it in
		*(*uint32)(ptr) = *pixel
	}
}

func (pix PixelData) Close() error {
	C.SDL_UnlockSurface(pix.s)
	return nil
}
<|endoftext|>


<commit_before>package goselect

import (
	"fmt"
	"io"
	"os"
	"testing"
	"time"
)

type fder interface {
	Fd() uintptr
}

func TestReadWriteSync(t *testing.T) {
	const count = 500
	rrs := []io.Reader{}
	wws := []io.Writer{}
	rFDSet := &FDSet{}
	for i := 0; i < count; i++ {
		rr, ww, err := os.Pipe()
		if err != nil {
			t.Fatal(err)
		}
		rrs = append(rrs, rr)
		wws = append(wws, ww)
	}

	go func() {
		time.Sleep(time.Second)
		for i := 0; i < count; i++ {
			fmt.Fprintf(wws[i], "hello %d", i)
			time.Sleep(time.Millisecond)
		}
	}()

	buf := make([]byte, 1024)
	for i := 0; i < count; i++ {
		rFDSet.Zero()
		for i := 0; i < count; i++ {
			rFDSet.Set(rrs[i].(fder).Fd())
		}

		if err := RetrySelect(1024, rFDSet, nil, nil, -1, 10, 10*time.Millisecond); err != nil {
			t.Fatalf("select call failed: %s", err)
		}
		for j := 0; j < count; j++ {
			if rFDSet.IsSet(rrs[j].(fder).Fd()) {
				//				println(i, j)
				if i != j {
					t.Fatalf("unexpected fd ready: %d,expected: %d", j, i)
				}
				_, err := rrs[j].Read(buf)
				if err != nil {
					t.Fatalf("read call failed: %s", err)
				}
			}
		}
	}
}
<commit_msg>Reduce open fds in tests to avoid changing ulimit<commit_after>package goselect

import (
	"fmt"
	"io"
	"os"
	"testing"
	"time"
)

type fder interface {
	Fd() uintptr
}

func TestReadWriteSync(t *testing.T) {
	const count = 50
	rrs := []io.Reader{}
	wws := []io.Writer{}
	rFDSet := &FDSet{}
	for i := 0; i < count; i++ {
		rr, ww, err := os.Pipe()
		if err != nil {
			t.Fatal(err)
		}
		rrs = append(rrs, rr)
		wws = append(wws, ww)
	}

	go func() {
		time.Sleep(time.Second)
		for i := 0; i < count; i++ {
			fmt.Fprintf(wws[i], "hello %d", i)
			time.Sleep(time.Millisecond)
		}
	}()

	buf := make([]byte, 1024)
	for i := 0; i < count; i++ {
		rFDSet.Zero()
		for i := 0; i < count; i++ {
			rFDSet.Set(rrs[i].(fder).Fd())
		}

		if err := RetrySelect(1024, rFDSet, nil, nil, -1, 10, 10*time.Millisecond); err != nil {
			t.Fatalf("select call failed: %s", err)
		}
		for j := 0; j < count; j++ {
			if rFDSet.IsSet(rrs[j].(fder).Fd()) {
				//				println(i, j)
				if i != j {
					t.Fatalf("unexpected fd ready: %d,expected: %d", j, i)
				}
				_, err := rrs[j].Read(buf)
				if err != nil {
					t.Fatalf("read call failed: %s", err)
				}
			}
		}
	}
}
<|endoftext|>