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

package storage

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/util/tracing"
)

func BenchmarkReplicaSnapshot(b *testing.B) {
	defer tracing.Disable()()
	sCtx := TestStoreContext()
	sCtx.TestingKnobs.DisableSplitQueue = true
	store, _, stopper := createTestStoreWithContext(b, &sCtx)
	defer stopper.Stop()
	// We want to manually control the size of the raft log.
	store.SetRaftLogQueueActive(false)

	rep, err := store.GetReplica(rangeID)
	if err != nil {
		b.Fatal(err)
	}

	fillTestRange(b, rep, snapSize)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := rep.GetSnapshot(context.Background()); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>storage: always snapshot *full* ranges in BenchmarkReplicaSnapshot<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tamir Duberstein (tamird@gmail.com)

package storage

import (
	"testing"

	"golang.org/x/net/context"

	"github.com/cockroachdb/cockroach/util/tracing"
)

func BenchmarkReplicaSnapshot(b *testing.B) {
	defer tracing.Disable()()
	sCtx := TestStoreContext()
	sCtx.TestingKnobs.DisableSplitQueue = true
	store, _, stopper := createTestStoreWithContext(b, &sCtx)
	defer stopper.Stop()
	// We want to manually control the size of the raft log.
	store.SetRaftLogQueueActive(false)

	rep, err := store.GetReplica(rangeID)
	if err != nil {
		b.Fatal(err)
	}

	snapSize := rep.GetMaxBytes()
	fillTestRange(b, rep, int(snapSize))
	b.SetBytes(snapSize)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if _, err := rep.GetSnapshot(context.Background()); err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"syscall"
)

var (
	help    = flag.Bool("help", false, "help")
	command = flag.String("c", "", "command to run when files change in given directories")
	ignore  = flag.String("i", "", "comma separated list of files to ignore")
)

func usage() {
	fmt.Fprintf(os.Stderr, "justrun -c 'SOME BASH COMMAND' [FILEPATH...]\n")
	os.Exit(1)
}

func main() {
	flag.Parse()
	if *help {
		usage()
	}
	ignoreNames := strings.Split(*ignore, ",")
	ignored := make(map[string]bool)
	for _, in := range ignoreNames {
		a, err := filepath.Abs(in)
		if err != nil {
			log.Fatalf("unable to get current working dir")
		}
		ignored[a] = true
	}
	cmdCh := make(chan time.Time)
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		for {
			select {
			case ev := <-w.Event:
				en, err := filepath.Abs(ev.Name)
				if err != nil {
					log.Fatalf("unable to get current working dir")
				}
				if ignored[en] {
					continue
				}
				//				log.Printf("event %s: file %s", ev, ev.Name)
				cmdCh <- time.Now()
			case err := <-w.Error:
				log.Println("error:", err)
			}
		}
	}()

	if len(flag.Args()) == 0 {
		usage()
	}
	for _, path := range flag.Args() {
		err = w.Watch(path)
		if err != nil {
			log.Fatalf("unable to watch: %s", err)
		}
	}
	lastStartTime := time.Unix(0, 0)
	var proc *os.Process
	done := make(chan error)
	for t := range cmdCh {
		log.Printf("event at %d", t)
		if t.After(lastStartTime.Add(30 * time.Millisecond)) {
			if proc != nil {
				shutdownCommand(proc, done)
			}
			lastStartTime = time.Now()
			proc = runCommand(proc, done)
		}
	}
}

func runCommand(oldProc *os.Process, done chan error) *os.Process {
	log.Println("running")
	cmd := exec.Command("bash", "-c", *command)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		log.Printf("error process %d", cmd.Process)
		log.Printf("command failed: %s", err)
		return oldProc
	}
	log.Printf("got process %d", cmd.Process.Pid)

	go func() {
		err := cmd.Wait()
		log.Printf("exiting process %d", cmd.Process.Pid)
		done <- err
	}()
	return cmd.Process
}

func shutdownCommand(proc *os.Process, done chan error) {
	err := syscall.Kill(proc.Pid, syscall.SIGKILL)
	if err != nil {
		log.Printf("returning after first kill")
		return
	}
	select {
	case <-done:
		break
	case <-time.After(300 * time.Millisecond):
		err := syscall.Kill(proc.Pid, syscall.SIGKILL)
		log.Printf("kill error?: %#v", err)
		if err != nil {
			log.Printf("returning after kill")
			return
		}
	}
	log.Printf("Shutdown cleanly, i guess? %d", proc.Pid)
}
<commit_msg>children of the bash processes can now be killed<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/howeyc/fsnotify"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"
	"syscall"
)

var (
	help    = flag.Bool("help", false, "help")
	command = flag.String("c", "", "command to run when files change in given directories")
	ignore  = flag.String("i", "", "comma separated list of files to ignore")
)

func usage() {
	fmt.Fprintf(os.Stderr, "justrun -c 'SOME BASH COMMAND' [FILEPATH...]\n")
	os.Exit(1)
}

func main() {
	flag.Parse()
	if *help {
		usage()
	}
	ignoreNames := strings.Split(*ignore, ",")
	ignored := make(map[string]bool)
	for _, in := range ignoreNames {
		a, err := filepath.Abs(in)
		if err != nil {
			log.Fatalf("unable to get current working dir")
		}
		ignored[a] = true
	}
	cmdCh := make(chan time.Time)
	w, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		for {
			select {
			case ev := <-w.Event:
				en, err := filepath.Abs(ev.Name)
				if err != nil {
					log.Fatalf("unable to get current working dir")
				}
				if ignored[en] {
					continue
				}
				//				log.Printf("event %s: file %s", ev, ev.Name)
				cmdCh <- time.Now()
			case err := <-w.Error:
				log.Println("error:", err)
			}
		}
	}()

	if len(flag.Args()) == 0 {
		usage()
	}
	for _, path := range flag.Args() {
		err = w.Watch(path)
		if err != nil {
			log.Fatalf("unable to watch: %s", err)
		}
	}
	lastStartTime := time.Unix(0, 0)
	var proc *os.Process
	done := make(chan error)
	for t := range cmdCh {
		log.Printf("event at %d", t)
		if t.After(lastStartTime.Add(30 * time.Millisecond)) {
			if proc != nil {
				shutdownCommand(proc, done)
			}
			lastStartTime = time.Now()
			proc = runCommand(proc, done)
		}
	}
}

func runCommand(oldProc *os.Process, done chan error) *os.Process {
	log.Println("running")
	cmd := exec.Command("bash", "-c", *command)
	// Necessary so that SIGTERM's will traverse down to the the child
	// processes in the bash command below.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err := cmd.Start()
	if err != nil {
		log.Printf("error process %d", cmd.Process)
		log.Printf("command failed: %s", err)
		return oldProc
	}
	log.Printf("got process %d", cmd.Process.Pid)

	go func() {
		err := cmd.Wait()
		log.Printf("exiting process %d", cmd.Process.Pid)
		done <- err
	}()
	return cmd.Process
}

func shutdownCommand(proc *os.Process, done chan error) {
	// the negation here means to kill not just the parent pid (which is the
	// bash shell), but also its children. This means long-lived servers can
	// be killed as well quickly exiting processes. e.g. "go build &&
	// ./myserver -http=:6000". fswatch and others won't do this.
	err = syscall.Kill(-proc.Pid, syscall.SIGTERM)
	if err != nil {
		log.Printf("returning after first kill")
		return
	}

	for {
		select {
		case <-done:
			goto done
		case <-time.After(300 * time.Millisecond):
			err := syscall.Kill(-proc.Pid, syscall.SIGTERM)
			log.Printf("kill error?: %#v", err)
			if err != nil {
				log.Printf("returning after kill")
				return
			}
		}
	}
done:
	log.Printf("Shutdown cleanly, i guess? %d", proc.Pid)
}
<|endoftext|>


<commit_before>package sqldecoder

import (
	"database/sql"
	"io"
	"reflect"
)

type fieldMap struct {
	columnName string
}
type Decoder struct {
	rows      *sql.Rows
	columnMap map[string]int
}

type unmarshalTypeError struct {
	rt reflect.Type
}

func (e unmarshalTypeError) Error() string {
	return "Cannot unmarshal into value of type " + e.rt.String()
}

// NewDecoder returns a new decoder that reads from rows.
func NewDecoder(rows *sql.Rows) (*Decoder, error) {
	d := &Decoder{rows, make(map[string]int)}
	if rows != nil {
		cols, err := rows.Columns()
		if err != nil {
			return nil, err
		}
		for i, key := range cols {
			d.columnMap[key] = i
		}
	}
	return d, nil
}

// unmarshal gets the data from the row and stores it in the value pointed to by v.
func (d *Decoder) unmarshal(v interface{}) error {
	var e error

	shimmer := reflect.ValueOf(v)
	if shimmer.Type().Kind() != reflect.Ptr {
		return unmarshalTypeError{rt: shimmer.Type()}
	}
	dst := shimmer.Elem()

	switch dst.Kind() {
	case reflect.Struct:
		fields := make([]interface{}, len(d.columnMap))
		for i := 0; i < dst.NumField(); i++ {
			fv := dst.Field(i)
			if ok := fv.CanSet(); ok {
				ft := dst.Type().Field(i)
				if colName := ft.Tag.Get("sql"); colName != "" {
					if idx, ok := d.columnMap[colName]; ok {
						fields[idx] = fv.Addr().Interface()
					}
				}
			}
		}
		if e = d.rows.Scan(fields...); e != nil {
			return e
		}
	default:
		return unmarshalTypeError{rt: dst.Type()}
	}
	return nil
}

// Decode the next row into v. v is expected to a struct.
// Returns io.EOF if there are no rows to decode.
func (d *Decoder) Decode(v interface{}) error {
	if d.rows == nil {
		return io.EOF
	}

	if ok := d.rows.Next(); ok {
		if err := d.unmarshal(v); err != nil {
			return err
		}
	} else {
		return io.EOF
	}
	return nil
}
<commit_msg>cache field and column mappings by type<commit_after>package sqldecoder

import (
	"database/sql"
	"io"
	"reflect"
)

type typeMap map[reflect.Type]map[string]int
type Decoder struct {
	rows *sql.Rows
	tm   typeMap
}

type unmarshalTypeError struct {
	rt reflect.Type
}

func (e unmarshalTypeError) Error() string {
	return "Cannot unmarshal into value of type " + e.rt.String()
}

// NewDecoder returns a new decoder that reads from rows.
func NewDecoder(rows *sql.Rows) (*Decoder, error) {
	d := &Decoder{rows: rows, tm: make(typeMap)}
	return d, nil
}

// fieldMap provides a map whose keys are a column name and whose values are
// the field index. The column name for a given exported field is (in priority
// order):
// 		the value of a sql tag on on the field
//		the field name
func fieldMap(t reflect.Type) (map[string]int) {
	if t.Kind() != reflect.Struct {
		return nil
	}

	fm := make(map[string]int)
	tagged := make(map[string]bool)
	for i := 0; i < t.NumField(); i++ {
		ft := t.Field(i)
		colName := ft.Tag.Get("sql")
		if colName != "" {
			fm[colName] = i
			tagged[colName] = true
			continue
		}

		colName = ft.Name
		if _, ok := tagged[colName]; !ok {
			fm[colName] = i
			tagged[colName] = false
		}
	}

	return fm
}

// unmarshal gets the data from the row and stores it in the value pointed to by v.
func (d *Decoder) unmarshal(v interface{}) error {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return unmarshalTypeError{rt: rv.Type()}
	}
	dst := rv.Elem()

	switch dst.Kind() {
	case reflect.Struct:
		fm, ok := d.tm[dst.Type()]
		if !ok {
			fm = fieldMap(dst.Type())
			d.tm[dst.Type()] = fm
		}

		cols, err := d.rows.Columns()
		if err != nil {
			return err
		}

		fields := make([]interface{}, len(cols))
		for ci, v := range cols {
			if fi, ok := fm[v]; ok {
				if fv := dst.Field(fi); fv.CanSet() {
					fields[ci] = fv.Addr().Interface()
					continue
				}
			}
		}

		if err := d.rows.Scan(fields...); err != nil {
			return err
		}
	default:
		return unmarshalTypeError{rt: dst.Type()}
	}
	return nil
}

// Decode the next row into v. v is expected to be a struct.
// Returns io.EOF if there are no more rows to decode.
func (d *Decoder) Decode(v interface{}) error {
	if d.rows == nil {
		return io.EOF
	}

	if ok := d.rows.Next(); ok {
		if err := d.unmarshal(v); err != nil {
			return err
		}
	} else {
		return io.EOF
	}
	return nil
}
<|endoftext|>


<commit_before>package krpc

import (
	crand "crypto/rand"
	"encoding"
	"encoding/hex"
	"fmt"

	"github.com/anacrolix/torrent/bencode"

	"github.com/anacrolix/dht/v2/int160"
)

func RandomNodeID() (id ID) {
	crand.Read(id[:])
	return
}

type ID [20]byte

var (
	_ interface {
		bencode.Unmarshaler
		encoding.TextUnmarshaler
	} = (*ID)(nil)
	_ bencode.Marshaler = ID{}
	_ fmt.Formatter     = ID{}
)

func (h ID) Format(f fmt.State, c rune) {
	// See metainfo.Hash.
	f.Write([]byte(h.String()))
}

func IdFromString(s string) (id ID) {
	if n := copy(id[:], s); n != 20 {
		panic(n)
	}
	return
}

func (id ID) MarshalBencode() ([]byte, error) {
	return []byte("20:" + string(id[:])), nil
}

func (id *ID) UnmarshalBencode(b []byte) error {
	var s string
	if err := bencode.Unmarshal(b, &s); err != nil {
		return err
	}
	if n := copy(id[:], s); n != 20 {
		return fmt.Errorf("string has wrong length: %d", n)
	}
	return nil
}

func (id *ID) UnmarshalText(b []byte) (err error) {
	n, err := hex.Decode(id[:], b)
	if err != nil {
		return
	}
	if n != len(*id) {
		err = fmt.Errorf("expected %v bytes, only got %v", len(*id), n)
	}
	return
}

func (id ID) String() string {
	return hex.EncodeToString(id[:])
}

func (id ID) Int160() int160.T {
	return int160.FromByteArray(id)
}
<commit_msg>Add krpc.ID.IsZero<commit_after>package krpc

import (
	crand "crypto/rand"
	"encoding"
	"encoding/hex"
	"fmt"

	"github.com/anacrolix/torrent/bencode"

	"github.com/anacrolix/dht/v2/int160"
)

func RandomNodeID() (id ID) {
	crand.Read(id[:])
	return
}

type ID [20]byte

var (
	_ interface {
		bencode.Unmarshaler
		encoding.TextUnmarshaler
	} = (*ID)(nil)
	_ bencode.Marshaler = ID{}
	_ fmt.Formatter     = ID{}
)

func (h ID) Format(f fmt.State, c rune) {
	// See metainfo.Hash.
	f.Write([]byte(h.String()))
}

func IdFromString(s string) (id ID) {
	if n := copy(id[:], s); n != 20 {
		panic(n)
	}
	return
}

func (id ID) MarshalBencode() ([]byte, error) {
	return []byte("20:" + string(id[:])), nil
}

func (id *ID) UnmarshalBencode(b []byte) error {
	var s string
	if err := bencode.Unmarshal(b, &s); err != nil {
		return err
	}
	if n := copy(id[:], s); n != 20 {
		return fmt.Errorf("string has wrong length: %d", n)
	}
	return nil
}

func (id *ID) UnmarshalText(b []byte) (err error) {
	n, err := hex.Decode(id[:], b)
	if err != nil {
		return
	}
	if n != len(*id) {
		err = fmt.Errorf("expected %v bytes, only got %v", len(*id), n)
	}
	return
}

func (id ID) String() string {
	return hex.EncodeToString(id[:])
}

func (id ID) Int160() int160.T {
	return int160.FromByteArray(id)
}

func (id ID) IsZero() bool {
	return id == [20]byte{}
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"errors"
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/avalanchego/api"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/perms"
	"github.com/ava-labs/avalanchego/utils/profiler"

	cjson "github.com/ava-labs/avalanchego/utils/json"
)

const (
	maxAliasLength = 512

	// Name of file that stacktraces are written to
	stacktraceFile = "stacktrace.txt"
)

var errAliasTooLong = errors.New("alias length is too long")

type Config struct {
	Log          logging.Logger
	ProfileDir   string
	LogFactory   logging.Factory
	NodeConfig   interface{}
	ChainManager chains.Manager
	HTTPServer   *server.Server
}

// Admin is the API service for node admin management
type Admin struct {
	Config
	profiler profiler.Profiler
}

// NewService returns a new admin API service.
// All of the fields in [config] must be set.
func NewService(config Config) (*common.HTTPHandler, error) {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	if err := newServer.RegisterService(&Admin{
		Config:   config,
		profiler: profiler.New(config.ProfileDir),
	}, "admin"); err != nil {
		return nil, err
	}
	return &common.HTTPHandler{Handler: newServer}, nil
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.profiler.StartCPUProfiler()
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.profiler.StopCPUProfiler()
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: MemoryProfile called")

	reply.Success = true
	return service.profiler.MemoryProfile()
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: LockProfile called")

	reply.Success = true
	return service.profiler.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}

	reply.Success = true
	return service.HTTPServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}
	chainID, err := service.ChainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.ChainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.HTTPServer.AddAliasesWithReadLock(constants.ChainAliasPrefix+chainID.String(), constants.ChainAliasPrefix+args.Alias)
}

// GetChainAliasesArgs are the arguments for calling GetChainAliases
type GetChainAliasesArgs struct {
	Chain string `json:"chain"`
}

// GetChainAliasesReply are the aliases of the given chain
type GetChainAliasesReply struct {
	Aliases []string `json:"aliases"`
}

// GetChainAliases returns the aliases of the chain
func (service *Admin) GetChainAliases(_ *http.Request, args *GetChainAliasesArgs, reply *GetChainAliasesReply) error {
	service.Log.Debug("Admin: GetChainAliases called with Chain: %s", args.Chain)

	id, err := ids.FromString(args.Chain)
	if err != nil {
		return err
	}

	reply.Aliases = service.ChainManager.Aliases(id)
	return nil
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: Stacktrace called")

	reply.Success = true
	stacktrace := []byte(logging.Stacktrace{Global: true}.String())
	return perms.WriteFile(stacktraceFile, stacktrace, perms.ReadWrite)
}

// See SetLoggerLevel
type SetLoggerLevelArgs struct {
	LoggerName   string         `json:"loggerName"`
	LogLevel     *logging.Level `json:"logLevel"`
	DisplayLevel *logging.Level `json:"displayLevel"`
}

// SetLoggerLevel sets the log level and/or display level for loggers.
// If len([args.LoggerName]) == 0, sets the log/display level of all loggers.
// Otherwise, sets the log/display level of the loggers named in that argument.
// Sets the log level of these loggers to args.LogLevel.
// If args.LogLevel == nil, doesn't set the log level of these loggers.
// If args.LogLevel != nil, must be a valid string representation of a log level.
// Sets the display level of these loggers to args.LogLevel.
// If args.DisplayLevel == nil, doesn't set the display level of these loggers.
// If args.DisplayLevel != nil, must be a valid string representation of a log level.
func (service *Admin) SetLoggerLevel(_ *http.Request, args *SetLoggerLevelArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: SetLogLevels called with LoggerName: %q, LogLevel: %q, DisplayLevel: %q", args.LoggerName, args.LogLevel, args.DisplayLevel)

	if args.LogLevel == nil && args.DisplayLevel == nil {
		return errors.New("need to specify either displayLevel or logLevel")
	}

	var loggerNames []string
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		// Empty name means all loggers
		loggerNames = service.LogFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		if args.LogLevel != nil {
			if err := service.LogFactory.SetLogLevel(name, *args.LogLevel); err != nil {
				return err
			}
		}
		if args.DisplayLevel != nil {
			if err := service.LogFactory.SetDisplayLevel(name, *args.DisplayLevel); err != nil {
				return err
			}
		}
	}
	reply.Success = true
	return nil
}

type LogAndDisplayLevels struct {
	LogLevel     logging.Level `json:"logLevel"`
	DisplayLevel logging.Level `json:"displayLevel"`
}

// See GetLoggerLevel
type GetLoggerLevelArgs struct {
	LoggerName string `json:"loggerName"`
}

// See GetLoggerLevel
type GetLoggerLevelReply struct {
	LoggerLevels map[string]LogAndDisplayLevels `json:"loggerLevels"`
}

// GetLogLevel returns the log level and display level of all loggers.
func (service *Admin) GetLoggerLevel(_ *http.Request, args *GetLoggerLevelArgs, reply *GetLoggerLevelReply) error {
	service.Log.Debug("Admin: GetLoggerLevels called with LoggerName: %q", args.LoggerName)
	reply.LoggerLevels = make(map[string]LogAndDisplayLevels)
	var loggerNames []string
	// Empty name means all loggers
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		loggerNames = service.LogFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		logLevel, err := service.LogFactory.GetLogLevel(name)
		if err != nil {
			return err
		}
		displayLevel, err := service.LogFactory.GetDisplayLevel(name)
		if err != nil {
			return err
		}
		reply.LoggerLevels[name] = LogAndDisplayLevels{
			LogLevel:     logLevel,
			DisplayLevel: displayLevel,
		}
	}
	return nil
}

// GetConfig returns the config that the node was started with.
func (service *Admin) GetConfig(_ *http.Request, args *struct{}, reply *interface{}) error {
	*reply = service.NodeConfig
	return nil
}
<commit_msg>add debug log for admin.getConfig<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"errors"
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/avalanchego/api"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/perms"
	"github.com/ava-labs/avalanchego/utils/profiler"

	cjson "github.com/ava-labs/avalanchego/utils/json"
)

const (
	maxAliasLength = 512

	// Name of file that stacktraces are written to
	stacktraceFile = "stacktrace.txt"
)

var errAliasTooLong = errors.New("alias length is too long")

type Config struct {
	Log          logging.Logger
	ProfileDir   string
	LogFactory   logging.Factory
	NodeConfig   interface{}
	ChainManager chains.Manager
	HTTPServer   *server.Server
}

// Admin is the API service for node admin management
type Admin struct {
	Config
	profiler profiler.Profiler
}

// NewService returns a new admin API service.
// All of the fields in [config] must be set.
func NewService(config Config) (*common.HTTPHandler, error) {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	if err := newServer.RegisterService(&Admin{
		Config:   config,
		profiler: profiler.New(config.ProfileDir),
	}, "admin"); err != nil {
		return nil, err
	}
	return &common.HTTPHandler{Handler: newServer}, nil
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.profiler.StartCPUProfiler()
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.profiler.StopCPUProfiler()
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: MemoryProfile called")

	reply.Success = true
	return service.profiler.MemoryProfile()
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: LockProfile called")

	reply.Success = true
	return service.profiler.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}

	reply.Success = true
	return service.HTTPServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}
	chainID, err := service.ChainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.ChainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.HTTPServer.AddAliasesWithReadLock(constants.ChainAliasPrefix+chainID.String(), constants.ChainAliasPrefix+args.Alias)
}

// GetChainAliasesArgs are the arguments for calling GetChainAliases
type GetChainAliasesArgs struct {
	Chain string `json:"chain"`
}

// GetChainAliasesReply are the aliases of the given chain
type GetChainAliasesReply struct {
	Aliases []string `json:"aliases"`
}

// GetChainAliases returns the aliases of the chain
func (service *Admin) GetChainAliases(_ *http.Request, args *GetChainAliasesArgs, reply *GetChainAliasesReply) error {
	service.Log.Debug("Admin: GetChainAliases called with Chain: %s", args.Chain)

	id, err := ids.FromString(args.Chain)
	if err != nil {
		return err
	}

	reply.Aliases = service.ChainManager.Aliases(id)
	return nil
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: Stacktrace called")

	reply.Success = true
	stacktrace := []byte(logging.Stacktrace{Global: true}.String())
	return perms.WriteFile(stacktraceFile, stacktrace, perms.ReadWrite)
}

// See SetLoggerLevel
type SetLoggerLevelArgs struct {
	LoggerName   string         `json:"loggerName"`
	LogLevel     *logging.Level `json:"logLevel"`
	DisplayLevel *logging.Level `json:"displayLevel"`
}

// SetLoggerLevel sets the log level and/or display level for loggers.
// If len([args.LoggerName]) == 0, sets the log/display level of all loggers.
// Otherwise, sets the log/display level of the loggers named in that argument.
// Sets the log level of these loggers to args.LogLevel.
// If args.LogLevel == nil, doesn't set the log level of these loggers.
// If args.LogLevel != nil, must be a valid string representation of a log level.
// Sets the display level of these loggers to args.LogLevel.
// If args.DisplayLevel == nil, doesn't set the display level of these loggers.
// If args.DisplayLevel != nil, must be a valid string representation of a log level.
func (service *Admin) SetLoggerLevel(_ *http.Request, args *SetLoggerLevelArgs, reply *api.SuccessResponse) error {
	service.Log.Debug("Admin: SetLogLevels called with LoggerName: %q, LogLevel: %q, DisplayLevel: %q", args.LoggerName, args.LogLevel, args.DisplayLevel)

	if args.LogLevel == nil && args.DisplayLevel == nil {
		return errors.New("need to specify either displayLevel or logLevel")
	}

	var loggerNames []string
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		// Empty name means all loggers
		loggerNames = service.LogFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		if args.LogLevel != nil {
			if err := service.LogFactory.SetLogLevel(name, *args.LogLevel); err != nil {
				return err
			}
		}
		if args.DisplayLevel != nil {
			if err := service.LogFactory.SetDisplayLevel(name, *args.DisplayLevel); err != nil {
				return err
			}
		}
	}
	reply.Success = true
	return nil
}

type LogAndDisplayLevels struct {
	LogLevel     logging.Level `json:"logLevel"`
	DisplayLevel logging.Level `json:"displayLevel"`
}

// See GetLoggerLevel
type GetLoggerLevelArgs struct {
	LoggerName string `json:"loggerName"`
}

// See GetLoggerLevel
type GetLoggerLevelReply struct {
	LoggerLevels map[string]LogAndDisplayLevels `json:"loggerLevels"`
}

// GetLogLevel returns the log level and display level of all loggers.
func (service *Admin) GetLoggerLevel(_ *http.Request, args *GetLoggerLevelArgs, reply *GetLoggerLevelReply) error {
	service.Log.Debug("Admin: GetLoggerLevels called with LoggerName: %q", args.LoggerName)
	reply.LoggerLevels = make(map[string]LogAndDisplayLevels)
	var loggerNames []string
	// Empty name means all loggers
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		loggerNames = service.LogFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		logLevel, err := service.LogFactory.GetLogLevel(name)
		if err != nil {
			return err
		}
		displayLevel, err := service.LogFactory.GetDisplayLevel(name)
		if err != nil {
			return err
		}
		reply.LoggerLevels[name] = LogAndDisplayLevels{
			LogLevel:     logLevel,
			DisplayLevel: displayLevel,
		}
	}
	return nil
}

// GetConfig returns the config that the node was started with.
func (service *Admin) GetConfig(_ *http.Request, args *struct{}, reply *interface{}) error {
	service.Log.Debug("Admin: GetConfig called")
	*reply = service.NodeConfig
	return nil
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/gecko/api"
	"github.com/ava-labs/gecko/chains"
	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/utils/logging"

	cjson "github.com/ava-labs/gecko/utils/json"
)

// Admin is the API service for node admin management
type Admin struct {
	log          logging.Logger
	performance  Performance
	chainManager chains.Manager
	httpServer   *api.Server
}

// NewService returns a new admin API service
func NewService(log logging.Logger, chainManager chains.Manager, httpServer *api.Server) *common.HTTPHandler {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	newServer.RegisterService(&Admin{
		log:          log,
		chainManager: chainManager,
		httpServer:   httpServer,
	}, "admin")
	return &common.HTTPHandler{Handler: newServer}
}

// StartCPUProfilerReply are the results from calling StartCPUProfiler
type StartCPUProfilerReply struct {
	Success bool `json:"success"`
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *StartCPUProfilerReply) error {
	service.log.Info("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.performance.StartCPUProfiler()
}

// StopCPUProfilerReply are the results from calling StopCPUProfiler
type StopCPUProfilerReply struct {
	Success bool `json:"success"`
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *StopCPUProfilerReply) error {
	service.log.Info("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.performance.StopCPUProfiler()
}

// MemoryProfileReply are the results from calling MemoryProfile
type MemoryProfileReply struct {
	Success bool `json:"success"`
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *MemoryProfileReply) error {
	service.log.Info("Admin: MemoryProfile called")

	reply.Success = true
	return service.performance.MemoryProfile()
}

// LockProfileReply are the results from calling LockProfile
type LockProfileReply struct {
	Success bool `json:"success"`
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *LockProfileReply) error {
	service.log.Info("Admin: LockProfile called")

	reply.Success = true
	return service.performance.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// AliasReply are the results from calling Alias
type AliasReply struct {
	Success bool `json:"success"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *AliasReply) error {
	service.log.Info("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChainReply are the results from calling AliasChain
type AliasChainReply struct {
	Success bool `json:"success"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *AliasChainReply) error {
	service.log.Info("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	chainID, err := service.chainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.chainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock("bc/"+chainID.String(), "bc/"+args.Alias)
}

// StacktraceReply are the results from calling Stacktrace
type StacktraceReply struct {
	Stacktrace string `json:"stacktrace"`
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *StacktraceReply) error {
	service.log.Info("Admin: Stacktrace called")

	reply.Stacktrace = logging.Stacktrace{Global: true}.String()
	return nil
}
<commit_msg>Enforce maximum alias length in admin API<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"errors"
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/gecko/api"
	"github.com/ava-labs/gecko/chains"
	"github.com/ava-labs/gecko/snow/engine/common"
	"github.com/ava-labs/gecko/utils/logging"

	cjson "github.com/ava-labs/gecko/utils/json"
)

const (
	maxAliasLength = 512
)

var (
	errAliasTooLong = errors.New("alias length is too long")
)

// Admin is the API service for node admin management
type Admin struct {
	log          logging.Logger
	performance  Performance
	chainManager chains.Manager
	httpServer   *api.Server
}

// NewService returns a new admin API service
func NewService(log logging.Logger, chainManager chains.Manager, httpServer *api.Server) *common.HTTPHandler {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	newServer.RegisterService(&Admin{
		log:          log,
		chainManager: chainManager,
		httpServer:   httpServer,
	}, "admin")
	return &common.HTTPHandler{Handler: newServer}
}

// StartCPUProfilerReply are the results from calling StartCPUProfiler
type StartCPUProfilerReply struct {
	Success bool `json:"success"`
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *StartCPUProfilerReply) error {
	service.log.Info("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.performance.StartCPUProfiler()
}

// StopCPUProfilerReply are the results from calling StopCPUProfiler
type StopCPUProfilerReply struct {
	Success bool `json:"success"`
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *StopCPUProfilerReply) error {
	service.log.Info("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.performance.StopCPUProfiler()
}

// MemoryProfileReply are the results from calling MemoryProfile
type MemoryProfileReply struct {
	Success bool `json:"success"`
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *MemoryProfileReply) error {
	service.log.Info("Admin: MemoryProfile called")

	reply.Success = true
	return service.performance.MemoryProfile()
}

// LockProfileReply are the results from calling LockProfile
type LockProfileReply struct {
	Success bool `json:"success"`
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *LockProfileReply) error {
	service.log.Info("Admin: LockProfile called")

	reply.Success = true
	return service.performance.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// AliasReply are the results from calling Alias
type AliasReply struct {
	Success bool `json:"success"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *AliasReply) error {
	service.log.Info("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChainReply are the results from calling AliasChain
type AliasChainReply struct {
	Success bool `json:"success"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *AliasChainReply) error {
	service.log.Info("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}
	chainID, err := service.chainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.chainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock("bc/"+chainID.String(), "bc/"+args.Alias)
}

// StacktraceReply are the results from calling Stacktrace
type StacktraceReply struct {
	Stacktrace string `json:"stacktrace"`
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *StacktraceReply) error {
	service.log.Info("Admin: Stacktrace called")

	reply.Stacktrace = logging.Stacktrace{Global: true}.String()
	return nil
}
<|endoftext|>


<commit_before>package app_test

import (
	"github.com/timeredbull/tsuru/api/app"
	"github.com/timeredbull/tsuru/api/bind"
	"reflect"
	"testing"
)

func TestAppIsABinderApp(t *testing.T) {
	var a bind.App
	iface := reflect.ValueOf(&a)
	obj := reflect.ValueOf(&app.App{})
	if !obj.Type().Implements(iface.Elem().Type()) {
		t.Errorf("app.App should implement bind.App")
	}
}
<commit_msg>api/app: added failing test for issue #51<commit_after>package app_test

import (
	"github.com/timeredbull/tsuru/api/app"
	"github.com/timeredbull/tsuru/api/bind"
	"github.com/timeredbull/tsuru/api/service"
	"github.com/timeredbull/tsuru/db"
	"labix.org/v2/mgo/bson"
	"reflect"
	"testing"
)

func TestAppIsABinderApp(t *testing.T) {
	var a bind.App
	iface := reflect.ValueOf(&a)
	obj := reflect.ValueOf(&app.App{})
	if !obj.Type().Implements(iface.Elem().Type()) {
		t.Errorf("app.App should implement bind.App")
	}
}

func TestDestroyShouldUnbindAppFromInstance(t *testing.T) {
	db.Session, _ = db.Open("127.0.0.1:27017", "tsuru_app_bind_test")
	defer func() {
		db.Session.Apps().Database.DropDatabase()
		db.Session.Close()
	}()
	instance := service.ServiceInstance{
		Name: "MyInstance",
		Apps: []string{"myApp"},
	}
	err := instance.Create()
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
	defer db.Session.ServiceInstances().Remove(bson.M{"_id": instance.Name})
	a := app.App{
		Name: "myApp",
	}
	err = a.Create()
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
	defer db.Session.Apps().Remove(bson.M{"name": a.Name})
	err = a.Destroy()
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
	n, _ := db.Session.ServiceInstances().Find(bson.M{"apps": bson.M{"$in": []string{a.Name}}}).Count()
	if n != 0 {
		t.Errorf("Should unbind apps when destroying them, but did not.\nExpected 0 apps to be binded to the instance %s, got %d.", instance.Name, n)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
//	"github.com/streadway/amqp"
	"labix.org/v2/mgo"
	"log/syslog"
	"math/rand"
	"time"
)

func dequeue(syslogLog *syslog.Writer, mongoHref string, mongoDatabaseName string, mongoCollectionName string) {

	//DEBUG
	syslogLog.Notice("[dequeue] BEGIN")
	syslogLog.Notice(  fmt.Sprintf("    [dequeue] mongoHref = [%v]", mongoHref)  )

	// Deal with parameters.
		if "" == mongoHref {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoHref. Received: [%v].", mongoHref)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

		if "" == mongoDatabaseName {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoDatabaseName. Received: [%v].", mongoDatabaseName)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

		if "" == mongoCollectionName {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoCollectionName. Received: [%v].", mongoCollectionName)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

	// Connect to MongoDB
		session, err := mgo.Dial(mongoHref)
		if err != nil {
			syslogLog.Err( fmt.Sprintf("    [dequeue] Could NOT connect to MongoDB at [%v], received err = [%v]", mongoHref, err) )
			panic(err)
/////////////////////// RETURN
			return
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

	// Forever
		for {

			//DEBUG
			syslogLog.Notice("    [dequeue] =-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=")
			syslogLog.Notice("    [dequeue] loop")

			// Check MongoDB for items that are ready.

			// Sleep for a while before checking again.
				sleepTime := time.Duration(5 + rand.Intn(7)) * time.Second

				//DEBUG
				syslogLog.Notice( fmt.Sprintf("    [dequeue] sleep for %v", sleepTime) )

				time.Sleep(sleepTime)
		} // for

	//DEBUG
	syslogLog.Notice("[dequeue] END")

}
<commit_msg>dev work. still work in progress<commit_after>package main

import (
	"fmt"
//	"github.com/streadway/amqp"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"log/syslog"
	"math/rand"
	"time"
)

func dequeue(syslogLog *syslog.Writer, mongoHref string, mongoDatabaseName string, mongoCollectionName string) {

	//DEBUG
	syslogLog.Notice("[dequeue] BEGIN")
	syslogLog.Notice(  fmt.Sprintf("    [dequeue] mongoHref = [%v]", mongoHref)  )

	// Deal with parameters.
		if "" == mongoHref {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoHref. Received: [%v].", mongoHref)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

		if "" == mongoDatabaseName {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoDatabaseName. Received: [%v].", mongoDatabaseName)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

		if "" == mongoCollectionName {
			errMsg := fmt.Sprintf("    [dequeue] Bad mongoCollectionName. Received: [%v].", mongoCollectionName)
			syslogLog.Err(errMsg)
			panic(errMsg)
/////////////////////// RETURN
			return
		}

	// Connect to MongoDB
		session, err := mgo.Dial(mongoHref)
		if err != nil {
			syslogLog.Err( fmt.Sprintf("    [dequeue] Could NOT connect to MongoDB at [%v], received err = [%v]", mongoHref, err) )
			panic(err)
/////////////////////// RETURN
			return
		}
		defer session.Close()

		// Optional. Switch the session to a monotonic behavior.
		session.SetMode(mgo.Monotonic, true)

		mongoCollection := session.DB(mongoDatabaseName).C(mongoCollectionName)

	// Forever
		for {

			//DEBUG
			syslogLog.Notice("    [dequeue] =-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=-<>-=")
			syslogLog.Notice("    [dequeue] loop")

			// Check MongoDB for items that are ready.
				mongoCriteria := bson.M{  "when":bson.M{"$lte": bson.Now()}  }

				mongoQuery := mongoCollection.Find(mongoCriteria)

				//DEBUG
				syslogLog.Notice( fmt.Sprintf("    [dequeue] mongoQuery = [%v]", mongoQuery) )

//				if nil != err {
//					syslogLog.Err( fmt.Sprintf("    [dequeue] Error querying MongoDB with mongoCriteria = [%v] received err = [%v]", mongoCriteria, err) )
//				} else {
//
//				}

			// Sleep for a while before checking again.
				sleepTime := time.Duration(5 + rand.Intn(7)) * time.Second

				//DEBUG
				syslogLog.Notice( fmt.Sprintf("    [dequeue] sleep for %v", sleepTime) )

				time.Sleep(sleepTime)
		} // for

	//DEBUG
	syslogLog.Notice("[dequeue] END")

}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"flag"
	"reflect"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
)

// Data holds all of polly's app settings
type Data struct {
	API struct {
		BaseURL         string
		PathPrefix      string
		Bind            string
		SwaggerAPIPath  string
		SwaggerPath     string
		SwaggerFilePath string
	}

	Connections struct {
		Email                EmailConfig
		PostgreSQLConnection PostgreSQLConnection
		Logging              struct {
			IrcHost       string
			IrcChannel    string
			IrcImpChannel string
		}
	}

	Web struct {
		BaseURL string
	}

	App struct {
		CryptPepper string

		Proposals struct {
			SmallGrantThreshold uint
		}

		Templates Templates
	}
}

// PostgreSQLConnection contains all of the db configuration values
type PostgreSQLConnection struct {
	User     string
	Password string
	Host     string
	DbName   string
	SslMode  string
}

// EmailConfig contains all email settings
type EmailConfig struct {
	AdminEmail string
	ReplyTo    string
	SMTP       struct {
		User     string
		Password string
		Server   string
		Port     int
	}
	IMAP struct {
		User        string
		Password    string
		Server      string
		Port        int
		LastMessage string
		LastSeen    int64
	}
}

// EmailTemplate holds all values of one email template
type EmailTemplate struct {
	Subject string
	Text    string
	HTML    string
}

// Templates holds all email templates
type Templates struct {
	Invitation         EmailTemplate
	ModerationProposal EmailTemplate
}

var (
	// Settings contains the parsed configuration values
	Settings *Data
)

// ParseSettings parses the config file
func ParseSettings() {
	logLevelStr := flag.String("loglevel", "info", "Log level")
	configFile := flag.String("configfile", "config.json", "config file in the JSON format")
	flag.Parse()

	logLevel, err := log.ParseLevel(*logLevelStr)
	if err != nil {
		log.Fatal(err)
	}
	log.SetLevel(logLevel)

	if configFile == nil || len(*configFile) == 0 {
		log.Panic(errors.New("Did not get a config file passed in"))
	}
	log.WithField("File", *configFile).Info("Using config file")

	// Parse config file
	configData := Data{}
	handler := NewHandler(*configFile, &configData, nil)
	if handler == nil {
		log.Fatal(errors.New("Config handler is nil, cannot continue"))
	}
	if !handler.LastReadValid() {
		log.WithField(
			"File",
			*configFile,
		).Fatal(errors.New("Did not get a valid config file"))
	}

	Settings = handler.CurrentData().(*Data)
	//FIXME catch empty conf fields
}

// Marshal returns a "Connection String" with escaped values of all non-empty
// fields as described at http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
func (c *PostgreSQLConnection) Marshal() string {
	val := reflect.ValueOf(c).Elem()
	var out string
	l := val.NumField()

	r := strings.NewReplacer(`'`, `\'`, `\`, `\\`)

	for i := 0; i < l; i++ {
		var fieldValue string

		switch f := val.Field(i).Interface().(type) {
		case string:
			fieldValue = f
		case int:
			fieldValue = strconv.Itoa(f)
		}
		fieldType := val.Type().Field(i).Name

		if len(fieldValue) > 0 {
			out += strings.ToLower(fieldType) + "='" + r.Replace(fieldValue) + "'"
			if i < l {
				out += " "
			}
		}
	}

	return out
}
<commit_msg>Added config values for down-voting threshold and minimum voting-time<commit_after>package config

import (
	"errors"
	"flag"
	"reflect"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
)

// Data holds all of polly's app settings
type Data struct {
	API struct {
		BaseURL         string
		PathPrefix      string
		Bind            string
		SwaggerAPIPath  string
		SwaggerPath     string
		SwaggerFilePath string
	}

	Connections struct {
		Email                EmailConfig
		PostgreSQLConnection PostgreSQLConnection
		Logging              struct {
			IrcHost       string
			IrcChannel    string
			IrcImpChannel string
		}
	}

	Web struct {
		BaseURL string
	}

	App struct {
		CryptPepper string

		Proposals struct {
			SmallGrantValueThreshold uint
			SmallGrantVoteThreshold  uint
			SmallGrantVoteMinDays    uint
		}

		Templates Templates
	}
}

// PostgreSQLConnection contains all of the db configuration values
type PostgreSQLConnection struct {
	User     string
	Password string
	Host     string
	DbName   string
	SslMode  string
}

// EmailConfig contains all email settings
type EmailConfig struct {
	AdminEmail string
	ReplyTo    string
	SMTP       struct {
		User     string
		Password string
		Server   string
		Port     int
	}
	IMAP struct {
		User        string
		Password    string
		Server      string
		Port        int
		LastMessage string
		LastSeen    int64
	}
}

// EmailTemplate holds all values of one email template
type EmailTemplate struct {
	Subject string
	Text    string
	HTML    string
}

// Templates holds all email templates
type Templates struct {
	Invitation         EmailTemplate
	ModerationProposal EmailTemplate
}

var (
	// Settings contains the parsed configuration values
	Settings *Data
)

// ParseSettings parses the config file
func ParseSettings() {
	logLevelStr := flag.String("loglevel", "info", "Log level")
	configFile := flag.String("configfile", "config.json", "config file in the JSON format")
	flag.Parse()

	logLevel, err := log.ParseLevel(*logLevelStr)
	if err != nil {
		log.Fatal(err)
	}
	log.SetLevel(logLevel)

	if configFile == nil || len(*configFile) == 0 {
		log.Panic(errors.New("Did not get a config file passed in"))
	}
	log.WithField("File", *configFile).Info("Using config file")

	// Parse config file
	configData := Data{}
	handler := NewHandler(*configFile, &configData, nil)
	if handler == nil {
		log.Fatal(errors.New("Config handler is nil, cannot continue"))
	}
	if !handler.LastReadValid() {
		log.WithField(
			"File",
			*configFile,
		).Fatal(errors.New("Did not get a valid config file"))
	}

	Settings = handler.CurrentData().(*Data)
	//FIXME catch empty conf fields
}

// Marshal returns a "Connection String" with escaped values of all non-empty
// fields as described at http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
func (c *PostgreSQLConnection) Marshal() string {
	val := reflect.ValueOf(c).Elem()
	var out string
	l := val.NumField()

	r := strings.NewReplacer(`'`, `\'`, `\`, `\\`)

	for i := 0; i < l; i++ {
		var fieldValue string

		switch f := val.Field(i).Interface().(type) {
		case string:
			fieldValue = f
		case int:
			fieldValue = strconv.Itoa(f)
		}
		fieldType := val.Type().Field(i).Name

		if len(fieldValue) > 0 {
			out += strings.ToLower(fieldType) + "='" + r.Replace(fieldValue) + "'"
			if i < l {
				out += " "
			}
		}
	}

	return out
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/btcsuite/go-flags"
	"os"
	"strconv"
	"strings"
)

type EditorOptions struct {
	Input  flags.Filename `short:"i" long:"input" description:"Input file" default:"-"`
	Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"`
}

type Point struct {
	X, Y int
}

func (p *Point) UnmarshalFlag(value string) error {
	parts := strings.Split(value, ",")

	if len(parts) != 2 {
		return errors.New("expected two numbers separated by a ,")
	}

	x, err := strconv.ParseInt(parts[0], 10, 32)

	if err != nil {
		return err
	}

	y, err := strconv.ParseInt(parts[1], 10, 32)

	if err != nil {
		return err
	}

	p.X = int(x)
	p.Y = int(y)

	return nil
}

func (p Point) MarshalFlag() (string, error) {
	return fmt.Sprintf("%d,%d", p.X, p.Y), nil
}

type Options struct {
	// Example of verbosity with level
	Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`

	// Example of optional value
	User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"`

	// Example of map with multiple default values
	Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"`

	// Example of option group
	Editor EditorOptions `group:"Editor Options"`

	// Example of custom type Marshal/Unmarshal
	Point Point `long:"point" description:"A x,y point" default:"1,2"`
}

var options Options

var parser = flags.NewParser(&options, flags.Default)

func main() {
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<commit_msg>remap to FactomProject<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/FactomProject/go-flags"
	"os"
	"strconv"
	"strings"
)

type EditorOptions struct {
	Input  flags.Filename `short:"i" long:"input" description:"Input file" default:"-"`
	Output flags.Filename `short:"o" long:"output" description:"Output file" default:"-"`
}

type Point struct {
	X, Y int
}

func (p *Point) UnmarshalFlag(value string) error {
	parts := strings.Split(value, ",")

	if len(parts) != 2 {
		return errors.New("expected two numbers separated by a ,")
	}

	x, err := strconv.ParseInt(parts[0], 10, 32)

	if err != nil {
		return err
	}

	y, err := strconv.ParseInt(parts[1], 10, 32)

	if err != nil {
		return err
	}

	p.X = int(x)
	p.Y = int(y)

	return nil
}

func (p Point) MarshalFlag() (string, error) {
	return fmt.Sprintf("%d,%d", p.X, p.Y), nil
}

type Options struct {
	// Example of verbosity with level
	Verbose []bool `short:"v" long:"verbose" description:"Verbose output"`

	// Example of optional value
	User string `short:"u" long:"user" description:"User name" optional:"yes" optional-value:"pancake"`

	// Example of map with multiple default values
	Users map[string]string `long:"users" description:"User e-mail map" default:"system:system@example.org" default:"admin:admin@example.org"`

	// Example of option group
	Editor EditorOptions `group:"Editor Options"`

	// Example of custom type Marshal/Unmarshal
	Point Point `long:"point" description:"A x,y point" default:"1,2"`
}

var options Options

var parser = flags.NewParser(&options, flags.Default)

func main() {
	if _, err := parser.Parse(); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
        "log"
        "time"

	"../../goble"
)

func main() {
	ble := goble.NewBLE()

        log.Println("Init...")
	ble.Init()

        time.Sleep(1 * time.Second)
        log.Println("Start Advertising...")
        ble.StartAdvertising("gobble", []goble.UUID{})

        time.Sleep(5 * time.Second)
        log.Println("Stop Advertising...")
        ble.StopAdvertising()

        time.Sleep(1 * time.Second)
        log.Println("Start Scanning...")
        ble.StartScanning([]goble.UUID{}, true)

        time.Sleep(10 * time.Second)
        log.Println("Stop Scanning...")
        ble.StopScanning()

        time.Sleep(2 * time.Second)
        log.Println("Goodbye!")
}
<commit_msg>Added options to enable/disable phases and/or change the phase duration<commit_after>package main

import (
	"flag"
	"log"
	"time"

	"../../goble"
)

func main() {
	advertise := flag.Int("advertise", 5, "Duration of advertising")
	scan := flag.Int("scan", 10, "Duration of scanning")

	flag.Parse()

	ble := goble.NewBLE()

	log.Println("Init...")
	ble.Init()

	if *advertise > 0 {
		time.Sleep(1 * time.Second)
		log.Println("Start Advertising...")
		ble.StartAdvertising("gobble", []goble.UUID{})

		time.Sleep(time.Duration(*advertise) * time.Second)
		log.Println("Stop Advertising...")
		ble.StopAdvertising()
	}

	if *scan > 0 {
		time.Sleep(1 * time.Second)
		log.Println("Start Scanning...")
		ble.StartScanning([]goble.UUID{}, true)

		time.Sleep(time.Duration(*scan) * time.Second)
		log.Println("Stop Scanning...")
		ble.StopScanning()
	}

	time.Sleep(2 * time.Second)
	log.Println("Goodbye!")
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"strings"
	"time"
)

type DbType string

type Uri struct {
	DbType  DbType
	Proto   string
	Host    string
	Port    string
	DbName  string
	User    string
	Passwd  string
	Charset string
	Laddr   string
	Raddr   string
	Timeout time.Duration
}

// a dialect is a driver's wrapper
type Dialect interface {
	Init(*Uri, string, string) error
	URI() *Uri
	DBType() DbType
	SqlType(t *Column) string
	SupportInsertMany() bool
	QuoteStr() string
	AndStr() string
	EqStr() string
	RollBackStr() string
	DropTableSql(tableName string) string
	AutoIncrStr() string
	SupportEngine() bool
	SupportCharset() bool
	IndexOnTable() bool
	ShowCreateNull() bool

	IndexCheckSql(tableName, idxName string) (string, []interface{})
	TableCheckSql(tableName string) (string, []interface{})
	ColumnCheckSql(tableName, colName string) (string, []interface{})

	GetColumns(tableName string) ([]string, map[string]*Column, error)
	GetTables() ([]*Table, error)
	GetIndexes(tableName string) (map[string]*Index, error)

	CreateTableSql(table *Table, tableName, storeEngine, charset string) string
	Filters() []Filter

	DriverName() string
	DataSourceName() string
}

type Base struct {
	dialect        Dialect
	driverName     string
	dataSourceName string
	*Uri
}

func (b *Base) Init(dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
	b.dialect = dialect
	b.driverName, b.dataSourceName = drivername, dataSourceName
	b.Uri = uri
	return nil
}

func (b *Base) URI() *Uri {
	return b.Uri
}

func (b *Base) DBType() DbType {
	return b.Uri.DbType
}

func (b *Base) DriverName() string {
	return b.driverName
}

func (b *Base) ShowCreateNull() bool {
	return true
}

func (b *Base) DataSourceName() string {
	return b.dataSourceName
}

func (b *Base) Quote(c string) string {
	return b.dialect.QuoteStr() + c + b.dialect.QuoteStr()
}

func (b *Base) AndStr() string {
	return "AND"
}

func (b *Base) EqStr() string {
	return "="
}

func (db *Base) RollBackStr() string {
	return "ROLL BACK"
}

func (db *Base) DropTableSql(tableName string) string {
	return fmt.Sprintf("DROP TABLE IF EXISTS `%s`", tableName)
}

func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
	var sql string
	sql = "CREATE TABLE IF NOT EXISTS "
	if tableName == "" {
		tableName = table.Name
	}

	sql += b.Quote(tableName) + " ("

	pkList := table.PrimaryKeys

	for _, colName := range table.ColumnsSeq() {
		col := table.GetColumn(colName)
		if col.IsPrimaryKey && len(pkList) == 1 {
			sql += col.String(b.dialect)
		} else {
			sql += col.StringNoPk(b.dialect)
		}
		sql = strings.TrimSpace(sql)
		sql += ", "
	}

	if len(pkList) > 1 {
		sql += "PRIMARY KEY ( "
		sql += b.Quote(strings.Join(pkList, b.Quote(",")))
		sql += " ), "
	}

	sql = sql[:len(sql)-2] + ")"
	if b.dialect.SupportEngine() && storeEngine != "" {
		sql += " ENGINE=" + storeEngine
	}
	if b.dialect.SupportCharset() {
		if charset == "" {
			charset = b.dialect.URI().Charset
		}
		sql += " DEFAULT CHARSET " + charset
	}
	sql += ";"
	return sql
}

var (
	dialects = map[DbType]Dialect{}
)

func RegisterDialect(dbName DbType, dialect Dialect) {
	if dialect == nil {
		panic("core: Register dialect is nil")
	}
	dialects[dbName] = dialect // !nashtsai! allow override dialect
}

func QueryDialect(dbName DbType) Dialect {
	return dialects[dbName]
}
<commit_msg>add OpenDialect<commit_after>package core

import (
	"fmt"
	"strings"
	"time"
)

type DbType string

type Uri struct {
	DbType  DbType
	Proto   string
	Host    string
	Port    string
	DbName  string
	User    string
	Passwd  string
	Charset string
	Laddr   string
	Raddr   string
	Timeout time.Duration
}

// a dialect is a driver's wrapper
type Dialect interface {
	Init(*Uri, string, string) error
	URI() *Uri
	DBType() DbType
	SqlType(t *Column) string
	SupportInsertMany() bool
	QuoteStr() string
	AndStr() string
	EqStr() string
	RollBackStr() string
	DropTableSql(tableName string) string
	AutoIncrStr() string
	SupportEngine() bool
	SupportCharset() bool
	IndexOnTable() bool
	ShowCreateNull() bool

	IndexCheckSql(tableName, idxName string) (string, []interface{})
	TableCheckSql(tableName string) (string, []interface{})
	ColumnCheckSql(tableName, colName string) (string, []interface{})

	GetColumns(tableName string) ([]string, map[string]*Column, error)
	GetTables() ([]*Table, error)
	GetIndexes(tableName string) (map[string]*Index, error)

	CreateTableSql(table *Table, tableName, storeEngine, charset string) string
	Filters() []Filter

	DriverName() string
	DataSourceName() string
}

func OpenDialect(dialect Dialect) (*DB, error) {
	return Open(dialect.DriverName(), dialect.DataSourceName())
}

type Base struct {
	dialect        Dialect
	driverName     string
	dataSourceName string
	*Uri
}

func (b *Base) Init(dialect Dialect, uri *Uri, drivername, dataSourceName string) error {
	b.dialect = dialect
	b.driverName, b.dataSourceName = drivername, dataSourceName
	b.Uri = uri
	return nil
}

func (b *Base) URI() *Uri {
	return b.Uri
}

func (b *Base) DBType() DbType {
	return b.Uri.DbType
}

func (b *Base) DriverName() string {
	return b.driverName
}

func (b *Base) ShowCreateNull() bool {
	return true
}

func (b *Base) DataSourceName() string {
	return b.dataSourceName
}

func (b *Base) Quote(c string) string {
	return b.dialect.QuoteStr() + c + b.dialect.QuoteStr()
}

func (b *Base) AndStr() string {
	return "AND"
}

func (b *Base) EqStr() string {
	return "="
}

func (db *Base) RollBackStr() string {
	return "ROLL BACK"
}

func (db *Base) DropTableSql(tableName string) string {
	return fmt.Sprintf("DROP TABLE IF EXISTS `%s`", tableName)
}

func (b *Base) CreateTableSql(table *Table, tableName, storeEngine, charset string) string {
	var sql string
	sql = "CREATE TABLE IF NOT EXISTS "
	if tableName == "" {
		tableName = table.Name
	}

	sql += b.Quote(tableName) + " ("

	pkList := table.PrimaryKeys

	for _, colName := range table.ColumnsSeq() {
		col := table.GetColumn(colName)
		if col.IsPrimaryKey && len(pkList) == 1 {
			sql += col.String(b.dialect)
		} else {
			sql += col.StringNoPk(b.dialect)
		}
		sql = strings.TrimSpace(sql)
		sql += ", "
	}

	if len(pkList) > 1 {
		sql += "PRIMARY KEY ( "
		sql += b.Quote(strings.Join(pkList, b.Quote(",")))
		sql += " ), "
	}

	sql = sql[:len(sql)-2] + ")"
	if b.dialect.SupportEngine() && storeEngine != "" {
		sql += " ENGINE=" + storeEngine
	}
	if b.dialect.SupportCharset() {
		if charset == "" {
			charset = b.dialect.URI().Charset
		}
		sql += " DEFAULT CHARSET " + charset
	}
	sql += ";"
	return sql
}

var (
	dialects = map[DbType]Dialect{}
)

func RegisterDialect(dbName DbType, dialect Dialect) {
	if dialect == nil {
		panic("core: Register dialect is nil")
	}
	dialects[dbName] = dialect // !nashtsai! allow override dialect
}

func QueryDialect(dbName DbType) Dialect {
	return dialects[dbName]
}
<|endoftext|>


<commit_before>package dig

import (
	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/diglet/geo/osm"
	"github.com/buckhx/diglet/util"
	"sync"
)

func Excavate(q *Quarry, pbf, postcodes string) (err error) {
	util.Info("Excavating...")
	//wg := &sync.WaitGroup{}
	//wg.Add(1)
	//wg.Add(2)
	//go survey(q, postcodes, wg)
	//excavate(q, pbf, 8, wg)
	//wg.Wait()
	subregions := loadSubregions(q)
	//util.Info("%s", subregions)
	printGeojson(subregions)
	util.Info("%d", len(subregions))
	return
}

func loadSubregions(q *Quarry) map[int64]*geo.Feature {
	subregions := make(map[int64]*geo.Feature) //, 88)
	for rel := range q.Relations() {
		if rel.ID != 1837989 {
			continue
		}
		feature := relationFeature(q, rel)
		/*
			feature := geo.NewPolygonFeature()
			feature.Properties = make(map[string]interface{}, len(rel.Tags))
			for k, v := range rel.Tags {
				feature.Properties[k] = v
			}
			cur := geo.NewShape()
			shapes := make([]*geo.Shape, len(rel.Members))
			shapes := relationShapes(rel)
			for i, m := range rel.Members {
				if m.Type != osm.WayType {
					// not going to deal with rel->rel & rel->node
					shapes[i] = geo.NewShape()
					continue
				}
				shapes[i] = wayShape(q, m.ID)
					if shp.Length() == 0 {
						util.Info("%d length 0, skipping", m.ID)
					} else if cur.Length() == 0 || cur.Tail() == shp.Head() {
						cur.Append(shp)
					} else if cur.Tail() == shp.Tail() {
						shp.Reverse()
						cur.Append(shp)
					} else {
						if cur.IsClosed() {
							switch m.Role {
							// outer rings -> clockwise
							// inner rings -> anti-clockwise
							case osm.RoleOuter:
								if !cur.IsClockwise() {
									cur.Reverse()
								}
							case osm.RoleInner:
								if cur.IsClockwise() {
									cur.Reverse()
								}
							}
						} else {
							//util.Info("Warning: Relation %d %q is not closed", rel.ID, rel.Tags["name"])
						}
						cur = shp
						feature.AddShape(cur)
					}
			}
			//TODO find bug in winding/reversing
			// Get the start and end shapes that have coordinates
			s := 0
			for i := 0; shapes[s].Length() == 0 && i < len(shapes); i++ {
				s = i
			}
			e := len(shapes) - 1
			for i := e; shapes[e].Length() == 0 && i > 0; i-- {
				e = i
			}
			// Flip the start if incorrectly wound
			if shapes[s].Tail() == shapes[e].Tail() || shapes[s].Tail() == shapes[e].Head() {
				shapes[s].Reverse()
			}
			cur = shapes[s]
			for i, shp := range shapes[s+1 : e+1] {
				c := s + i
				_ = c
				if shp.Length() == 0 {
					continue
				}
				if cur.Tail() == shp.Head() {
					cur.Add(shp.Coordinates[1:]...)
				} else if cur.Tail() == shp.Tail() {
					shp.Reverse()
					cur.Add(shp.Coordinates[1:]...)
				} else if shp.IsClosed() {
					feature.AddShape(cur)
					cur = shp
				} else {
					// there's a whole
					//util.Info("\tRelation %d has hole at %d", rel.ID, rel.Members[c].ID)
					cur.Add(shp.Coordinates[1:]...)
				}
			}
			feature.AddShape(cur)
			util.Info("Relation %d Geometry - %s", rel.ID, feature.Tags("wikipedia"))
			for i, shp := range feature.Geometry {
				if !shp.IsClosed() {
					util.Info("\tRelation %d not closed, explicitly closing", rel.ID)
					//shp.Add(shp.Head())
				}
				util.Info("\t%d - %d - %t", i, shp.Length(), shp.IsClosed())
			}
				if len(feature.Geometry) == 0 {
					util.Info("Relation %d has nil geometry", rel.ID)
				} else {
					util.Info("%q IsClosed() -> %t", feature.Tags["name"], feature.Geometry[0].IsClosed())
				}
				if !feature.Geometry[len(feature.Geometry)-1].IsClosed() {
					util.Info("feature is not closed", feature.Tags["name"])
				}
		*/
		subregions[rel.ID] = feature
	}
	return subregions
}

func survey(q *Quarry, postcodes string, wg *sync.WaitGroup) {
	defer wg.Done()
	q.Survey(postcodes)
}

func excavate(q *Quarry, pbf string, workers int, wg *sync.WaitGroup) {
	defer wg.Done()
	ex, err := osm.NewExcavator(pbf)
	util.Check(err)
	addrFilter := NewOsmFilter(1 << 27)
	ex.RelationCourier = func(feed <-chan *osm.Relation) {
		rels := make(chan QuarryRecord)
		go func() {
			defer close(rels)
			for rel := range feed {
				if rel.IsSubregionBoundary() {
					for _, m := range rel.Members {
						if m.Type == osm.WayType {
							addrFilter.AddInt64(m.ID)
						}
						rels <- rel
					}
				}
			}
		}()
		q.addRecords(RelationBucket, rels)
	}
	err = ex.Start(workers)
	util.Check(err)
	ex, err = osm.NewExcavator(pbf)
	util.Check(err)
	ex.WayCourier = func(feed <-chan *osm.Way) {
		ways := make(chan QuarryRecord)
		go func() {
			defer close(ways)
			for way := range feed {
				if way.IsAddressable() {
					//addrFilter.AddInt64(way.ID)
					//addrFilter.AddInt64(way.NodeIDs[0])
				}
				if addrFilter.HasInt64(way.ID) {
					for _, nid := range way.NodeIDs {
						addrFilter.AddInt64(nid)
					}
					ways <- way
				}
			}
		}()
		q.addRecords(WayBucket, ways)
	}
	ex.NodeCourier = func(feed <-chan *osm.Node) {
		for node := range feed {
			if node.IsAddressable() {
				//addrFilter.AddInt64(node.ID)
			}
		}
	}
	err = ex.Start(workers)
	util.Check(err)
	ex, err = osm.NewExcavator(pbf)
	util.Check(err)
	ex.NodeCourier = func(feed <-chan *osm.Node) {
		nodes := make(chan QuarryRecord)
		go func() {
			defer close(nodes)
			for node := range feed {
				if addrFilter.HasInt64(node.ID) {
					nodes <- node
				}
			}
		}()
		q.addRecords(NodeBucket, nodes)
	}
	err = ex.Start(1)
	util.Check(err)
}

/*
	var wayc uint64 = 0
	var nidc uint64 = 0
	rels := cmap.New()
	ways := cmap.New()
	nods := cmap.New()
	addrFilter := NewOsmFilter(1 << 27)
	collectRelations := func(feed <-chan *Relation) {
		for rel := range feed {
			if rel.IsSubregionBoundary() {
				rels.Set(rel.Key(), rel)
			}
		}
	}
	collectWays := func(feed <-chan *Way) {
		for way := range feed {
			if way.IsSubregionBoundary() {
				ways.Set(way.Key(), way)
				for _, nid := range way.NodeIDs {
					nods.Set(strconv.FormatInt(nid, 10), nil)
				}
				nids := uint64(len(way.NodeIDs))
				atomic.AddUint64(&nidc, nids)
			}
			if way.IsAddressable() {
				atomic.AddUint64(&wayc, 1)
				addrFilter.AddInt64(way.ID)
				addrFilter.AddInt64(way.NodeIDs[0])
			}
		}
	}

func wayShape(q *Quarry, wid int64) (shp *geo.Shape) {
	nodes, warns := q.WayNodes(wid)
	shp = geo.NewShape()
	util.Info("\t%d", wid)
	for {
		select {
		case node, ok := <-nodes:
			if ok {
				c := geo.Coordinate{Lat: node.Lat, Lon: node.Lon}
				util.Info("\t\t%d\t%s", node.ID, c)
				shp.Add(c)
			} else {
				return
			}
		case warn, ok := <-warns:
			if ok {
				_ = warn
					msg := "Incomplete relation %d %q, missing %d "
					if warn == m.ID {
						msg += "way"
					}
					util.Info(msg, rel.ID, rel.Tags["name"], warn)
			} else {
				//break nodeLoop
			}
		}
	}
	return
}
*/

func relationFeature(q *Quarry, rel *osm.Relation) (feature *geo.Feature) {
	feature = geo.NewPolygonFeature()
	feature.Properties = make(map[string]interface{}, len(rel.Tags))
	for k, v := range rel.Tags {
		feature.Properties[k] = v
	}
	ways := make(map[int64]*osm.Way, len(rel.Members))
	heads := make(map[int64]int64, len(rel.Members))
	tails := make(map[int64]int64, len(rel.Members))
	nodes := make(map[int64]geo.Coordinate, 3*len(rel.Members))
	for _, m := range rel.Members {
		if m.Type != osm.WayType {
			continue
		}
		way, nds := q.WayNodes(m.ID)
		if way == nil || len(nds) == 0 {
			util.Info("Missing member %d", m.ID)
			continue
		}
		ways[way.ID] = way
		h := way.NodeIDs[0]
		t := way.NodeIDs[len(way.NodeIDs)-1]
		if heads[h] != 0 || tails[t] != 0 {
			// head or tail already exists, let's flip
			reverse(way.NodeIDs)
			h, t = t, h
		}
		heads[h] = way.ID
		tails[t] = way.ID
		for _, node := range nds {
			c := geo.Coordinate{Lat: node.Lat, Lon: node.Lon}
			nodes[node.ID] = c
		}
	}
	popWay := func(ways map[int64]*osm.Way) (way *osm.Way) {
		for _, m := range rel.Members {
			mid := m.ID
			way = ways[mid]
			if way != nil {
				delete(ways, way.ID)
				return
			}
		}
		return
	}
	wayShape := func(way *osm.Way) (shp *geo.Shape) {
		shp = geo.NewShape()
		for _, nid := range way.NodeIDs {
			shp.Add(nodes[nid])
		}
		return
	}
	extendShape := func(shp *geo.Shape, tid int64) int64 {
		if wid, ok := heads[tid]; ok && ways[wid] != nil {
			way := ways[wid]
			delete(ways, way.ID)
			shp.Append(wayShape(way))
			util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[0], way.NodeIDs[len(way.NodeIDs)-1])
			return way.NodeIDs[len(way.NodeIDs)-1]
		}
		if wid, ok := tails[tid]; ok && ways[wid] != nil {
			way := ways[wid]
			delete(ways, way.ID)
			nxt := wayShape(way)
			nxt.Reverse()
			shp.Append(nxt)
			util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[len(way.NodeIDs)-1], way.NodeIDs[0])
			return way.NodeIDs[0]
		}
		return 0
	}
	/*
		for _, way := range ways {
			util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[0], way.NodeIDs[len(way.NodeIDs)-1])
		}
	*/
	for len(ways) > 0 {
		way := popWay(ways)
		shp := wayShape(way)
		feature.AddShape(shp)
		tid := way.NodeIDs[len(way.NodeIDs)-1]
		util.Info("----- New Shape -----")
		if _, ok := heads[tid]; !ok {
			util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[len(way.NodeIDs)-1], way.NodeIDs[0])
			// first way needs to be flipped
			shp.Reverse()
			tid = way.NodeIDs[0]
		} else {
			util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[0], way.NodeIDs[len(way.NodeIDs)-1])
		}
		for tid > 0 {
			//util.Info("tid: %d", tid)
			tid = extendShape(shp, tid)
		}
		/*
			if !shp.IsClosed() {
				shp.Add(shp.Head())
			}
		*/
	}
	util.Info("geom len: %d", len(feature.Geometry))
	return
}
<commit_msg>county polygons built<commit_after>package dig

import (
	"github.com/buckhx/diglet/geo"
	"github.com/buckhx/diglet/geo/osm"
	"github.com/buckhx/diglet/util"
	"sync"
)

func Excavate(q *Quarry, pbf, postcodes string) (err error) {
	util.Info("Excavating...")
	//wg := &sync.WaitGroup{}
	//wg.Add(1)
	//wg.Add(2)
	//go survey(q, postcodes, wg)
	//excavate(q, pbf, 8, wg)
	//wg.Wait()
	subregions := loadSubregions(q)
	//util.Info("%s", subregions)
	printGeojson(subregions)
	util.Info("%d", len(subregions))
	return
}

func loadSubregions(q *Quarry) map[int64]*geo.Feature {
	subregions := make(map[int64]*geo.Feature) //, 88)
	for rel := range q.Relations() {
		/*
			if rel.ID != 1427734 {
				continue
			}
		*/
		if feature := relationFeature(q, rel); feature != nil {
			subregions[rel.ID] = feature
		}
	}
	return subregions
}

func survey(q *Quarry, postcodes string, wg *sync.WaitGroup) {
	defer wg.Done()
	q.Survey(postcodes)
}

func excavate(q *Quarry, pbf string, workers int, wg *sync.WaitGroup) {
	defer wg.Done()
	ex, err := osm.NewExcavator(pbf)
	util.Check(err)
	addrFilter := NewOsmFilter(1 << 27)
	ex.RelationCourier = func(feed <-chan *osm.Relation) {
		rels := make(chan QuarryRecord)
		go func() {
			defer close(rels)
			for rel := range feed {
				if rel.IsSubregionBoundary() {
					for _, m := range rel.Members {
						if m.Type == osm.WayType {
							addrFilter.AddInt64(m.ID)
						}
						rels <- rel
					}
				}
			}
		}()
		q.addRecords(RelationBucket, rels)
	}
	err = ex.Start(workers)
	util.Check(err)
	ex, err = osm.NewExcavator(pbf)
	util.Check(err)
	ex.WayCourier = func(feed <-chan *osm.Way) {
		ways := make(chan QuarryRecord)
		go func() {
			defer close(ways)
			for way := range feed {
				if way.IsAddressable() {
					//addrFilter.AddInt64(way.ID)
					//addrFilter.AddInt64(way.NodeIDs[0])
				}
				if addrFilter.HasInt64(way.ID) {
					for _, nid := range way.NodeIDs {
						addrFilter.AddInt64(nid)
					}
					ways <- way
				}
			}
		}()
		q.addRecords(WayBucket, ways)
	}
	ex.NodeCourier = func(feed <-chan *osm.Node) {
		for node := range feed {
			if node.IsAddressable() {
				//addrFilter.AddInt64(node.ID)
			}
		}
	}
	err = ex.Start(workers)
	util.Check(err)
	ex, err = osm.NewExcavator(pbf)
	util.Check(err)
	ex.NodeCourier = func(feed <-chan *osm.Node) {
		nodes := make(chan QuarryRecord)
		go func() {
			defer close(nodes)
			for node := range feed {
				if addrFilter.HasInt64(node.ID) {
					nodes <- node
				}
			}
		}()
		q.addRecords(NodeBucket, nodes)
	}
	err = ex.Start(1)
	util.Check(err)
}

/*
	var wayc uint64 = 0
	var nidc uint64 = 0
	rels := cmap.New()
	ways := cmap.New()
	nods := cmap.New()
	addrFilter := NewOsmFilter(1 << 27)
	collectRelations := func(feed <-chan *Relation) {
		for rel := range feed {
			if rel.IsSubregionBoundary() {
				rels.Set(rel.Key(), rel)
			}
		}
	}
	collectWays := func(feed <-chan *Way) {
		for way := range feed {
			if way.IsSubregionBoundary() {
				ways.Set(way.Key(), way)
				for _, nid := range way.NodeIDs {
					nods.Set(strconv.FormatInt(nid, 10), nil)
				}
				nids := uint64(len(way.NodeIDs))
				atomic.AddUint64(&nidc, nids)
			}
			if way.IsAddressable() {
				atomic.AddUint64(&wayc, 1)
				addrFilter.AddInt64(way.ID)
				addrFilter.AddInt64(way.NodeIDs[0])
			}
		}
	}

func wayShape(q *Quarry, wid int64) (shp *geo.Shape) {
	nodes, warns := q.WayNodes(wid)
	shp = geo.NewShape()
	util.Info("\t%d", wid)
	for {
		select {
		case node, ok := <-nodes:
			if ok {
				c := geo.Coordinate{Lat: node.Lat, Lon: node.Lon}
				util.Info("\t\t%d\t%s", node.ID, c)
				shp.Add(c)
			} else {
				return
			}
		case warn, ok := <-warns:
			if ok {
				_ = warn
					msg := "Incomplete relation %d %q, missing %d "
					if warn == m.ID {
						msg += "way"
					}
					util.Info(msg, rel.ID, rel.Tags["name"], warn)
			} else {
				//break nodeLoop
			}
		}
	}
	return
}
*/

func relationFeature(q *Quarry, rel *osm.Relation) (feature *geo.Feature) {
	feature = geo.NewPolygonFeature()
	feature.Properties = make(map[string]interface{}, len(rel.Tags))
	for k, v := range rel.Tags {
		feature.Properties[k] = v
	}
	ways := make(map[int64]*osm.Way, len(rel.Members))
	nodes := make(map[int64]geo.Coordinate, 3*len(rel.Members))
	for _, m := range rel.Members {
		if m.Type != osm.WayType {
			continue
		}
		way, nds := q.WayNodes(m.ID)
		if way == nil || len(nds) == 0 {
			util.Info("Missing member %d", m.ID)
			continue
		}
		ways[way.ID] = way
		for _, node := range nds {
			c := geo.Coordinate{Lat: node.Lat, Lon: node.Lon}
			nodes[node.ID] = c
		}
	}
	mems := rel.Members
	w0 := ways[mems[0].ID]
	w1 := ways[mems[1].ID]
	if w0 != nil && w1 != nil && w0.NodeIDs[0] == w1.NodeIDs[len(w1.NodeIDs)-1] {
		// hint at winding by reversing members
		for i, j := 0, len(mems)-1; i < j; i, j = i+1, j-1 {
			mems[i], mems[j] = mems[j], mems[i]
		}
	}
	popWay := func(ways map[int64]*osm.Way) (way *osm.Way) {
		for _, m := range rel.Members {
			way = ways[m.ID]
			if way != nil {
				delete(ways, way.ID)
				return
			}
		}
		return
	}
	wayShape := func(way *osm.Way) (shp *geo.Shape) {
		shp = geo.NewShape()
		for _, nid := range way.NodeIDs {
			shp.Add(nodes[nid])
		}
		return
	}
	nextWay := func(cur *osm.Way) *osm.Way {
		//head := way.NodeIDs[0]
		tail := cur.NodeIDs[len(cur.NodeIDs)-1]
		for _, way := range ways {
			if tail == way.NodeIDs[0] {
				delete(ways, way.ID)
				return way
			} else if tail == way.NodeIDs[len(way.NodeIDs)-1] {
				reverse(way.NodeIDs)
				delete(ways, way.ID)
				return way
			}
		}
		return nil
	}
	var shp *geo.Shape
	for len(ways) > 0 {
		way := popWay(ways)
		if shp == nil || shp.IsClosed() {
			//util.Info("----- New Shape -----")
			shp = geo.NewShape()
			feature.AddShape(shp)
		}
		for way != nil {
			//util.Info("%d:\t%v\t-> %v", way.ID, way.NodeIDs[0], way.NodeIDs[len(way.NodeIDs)-1])
			shp.Append(wayShape(way))
			way = nextWay(way)
		}
	}
	if !shp.IsClosed() {
		//return nil
		shp.Add(shp.Head())
	}
	return
}
<|endoftext|>


<commit_before><commit_msg>passphrase parent command<commit_after><|endoftext|>


<commit_before>package display

/*
#include "display.h"
#include <stdlib.h>

#cgo darwin  LDFLAGS: -framework GLUT -framework OpenGL
#cgo linux   LDFLAGS: -lGL -lSDL2
#cgo windows LDFLAGS: -lopengl32 -lSDL2
*/
import "C"

import (
	"errors"
	"log"
	"runtime"
	"sync"
	"time"
	"unsafe"
)

var initialize sync.Once

func init() {
	runtime.LockOSThread()
}

// A Config is used to choose the settings of a
// window display. Different systems may support
// different configurations.
type Config map[string]string

//export goProcessEvent
func goProcessEvent(winP unsafe.Pointer, t C.EventType, p unsafe.Pointer) {
	win := (*Buffer)(winP)
	switch t {
	case C.EMouse:
		e := (*C.MouseEvent)(p)
		win.enqueue(Mouse{
			Btn:  Button(e.Down),
			Mod:  Modifier(e.Mod),
			When: time.Now(),
		})
	case C.ECursor:
		e := (*C.CursorEvent)(p)
		win.enqueue(Cursor{
			X:    int(e.X),
			Y:    int(e.Y),
			When: time.Now(),
		})
	case C.EText:
		e := (*C.TextEvent)(p)
		win.enqueue(Text{
			Text: C.GoString((*C.char)(*e)),
			When: time.Now(),
		})
	case C.EEdit:
		e := (*C.EditEvent)(p)
		win.enqueue(Text{
			Text: C.GoString((*C.char)(e.Text)),
			When: time.Now(),
		})
	case C.EKeyPress:
		e := (*C.KeyEvent)(p)
		win.enqueue(KeyPress{
			Mod:  Modifier(e.Mod),
			Code: Key(e.Code),
			Down: e.Down == 1,
			When: time.Now(),
		})
	case C.EResize:
		e := (*C.ResizeEvent)(p)
		win.enqueue(Resize{
			Width:  int(e.Width),
			Height: int(e.Height),
			When:   time.Now(),
		})
	case C.EFocus:
		e := (*C.FocusEvent)(p)
		win.enqueue(Focus{
			Focused: C.int(*e) == 1,
			When:    time.Now(),
		})
	case C.EScroll:
		e := (*C.ScrollEvent)(p)
		win.enqueue(Scroll{
			X:    int(e.X),
			Y:    int(e.Y),
			When: time.Now(),
		})
	case C.ERefresh:
		win.enqueue(Damage{When: time.Now()})
	case C.EClose:
		// May make a callback here
		win.Close()
	}
}

// This could be more sophisticated; some events are
// more important than others and should not be dropped
func (w Buffer) enqueue(e Event) {
	select {
	case w.event <- e:
	default:
	}
}

// A Buffer is an OpenGL canvas that can be displayed
// within an OS window. Buffers can receive user input,
// which can be accessed with the Subscribe() method.
type Buffer struct {
	ds    unsafe.Pointer
	Event <-chan Event
	event chan Event
	sync.Mutex
}

// Helper functions for pulling values from our C shim
func val(x C.RC) error {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return err
}

func valP(x C.RP) (unsafe.Pointer, error) {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return x.rp, err
}

func val2(x C.R2) (int, int, error) {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return int(x.X), int(x.Y), err
}

// Close() closes a window and releases any resources associated with it.
func (w *Buffer) Close() {
	if w == nil {
		return
	}
	if err := val(C.dsWinClose(w.ds)); err != nil {
		log.Print(err)
	}
	close(w.event)
}

// Title retrieves the current title of a window
func (w *Buffer) Title() string {
	if w == nil {
		return ""
	}
	w.Lock()
	defer w.Unlock()
	if s, err := valP(C.dsWinGetTitle(w.ds)); err != nil {
		return ""
	} else {
		return C.GoString((*C.char)(s))
	}
}

// SetTitle changes a window's title string to a new value. The maximum
// length of a window title is an unspecified value over 255 characters.
func (w *Buffer) SetTitle(title string) {
	if w == nil {
		return
	}
	w.Lock()
	defer w.Unlock()
	s := C.CString(title)
	if err := val(C.dsWinSetTitle(w.ds, s)); err != nil {
		log.Print(err)
	}
}

// Size returns the window's width and height in pixels
func (w *Buffer) Size() (width, height int) {
	var err error
	if w == nil {
		return -1, -1
	}
	width, height, err = val2(C.dsWinSize(w.ds))
	if err != nil {
		log.Print(err)
	}
	return width, height
}

// Resize changes the width and height of a window to the specified
// dimensions in pixels. Note that height and width are only suggestions;
// especially in fullscreen mode, window system or hardware restrictions
// may prevent the desired height and width from being set. The actual
// screen size may be retrieved with the Size() method.
func (w *Buffer) Resize(width, height int) error {
	return val(C.dsWinResize(
		w.ds,
		C.int(width),
		C.int(height)))
}

// Flip swaps the background buffer with the foregroud buffer.
// All drawing is done to the background buffer. The window's context
// must be set in the calling goroutine with TakeContext() before
// SwapBuffers, or any GL drawing functions, are called. By default,
// SwapBuffers will block until the screen is refreshed.
func (w *Buffer) Flip() {
	C.dsWinSwap(w.ds)
}

func buildArgv(cfg Config) ([]*C.char, error) {
	var argv []*C.char

	for key, val := range cfg {
		argv = append(argv, C.CString(key))
		argv = append(argv, C.CString(val))
	}

	argv = append(argv, nil)
	return argv, nil
}

func freeArgv(argv []*C.char) {
	for _, s := range argv {
		if s != nil {
			C.free(unsafe.Pointer(s))
		}
	}
}

// Open creates a new window.
func Open(c Config) (*Buffer, error) {
	var argv []*C.char
	var err error

	initialize.Do(func() {
		err = val(C.dsInit(0, nil))
	})
	if err != nil {
		return nil, err
	}

	buf := new(Buffer)
	buf.event = make(chan Event, 20)
	buf.Event = buf.event

	if argv, err = buildArgv(c); err != nil {
		return nil, err
	}

	buf.ds, err = valP(C.dsWinOpen(unsafe.Pointer(buf), C.int(len(argv)-1), &argv[0]))
	freeArgv(argv)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

func (w *Buffer) CheckEvent() error {
	return val(C.dsWinCheckEvent(w.ds))
}

func (w *Buffer) WaitEvent() error {
	return val(C.dsWinWaitEvent(w.ds))
}
<commit_msg>Make Buffer lock private<commit_after>package display

/*
#include "display.h"
#include <stdlib.h>

#cgo darwin  LDFLAGS: -framework GLUT -framework OpenGL
#cgo linux   LDFLAGS: -lGL -lSDL2
#cgo windows LDFLAGS: -lopengl32 -lSDL2
*/
import "C"

import (
	"errors"
	"log"
	"runtime"
	"sync"
	"time"
	"unsafe"
)

var initialize sync.Once

func init() {
	runtime.LockOSThread()
}

// A Config is used to choose the settings of a
// window display. Different systems may support
// different configurations.
type Config map[string]string

//export goProcessEvent
func goProcessEvent(winP unsafe.Pointer, t C.EventType, p unsafe.Pointer) {
	win := (*Buffer)(winP)
	switch t {
	case C.EMouse:
		e := (*C.MouseEvent)(p)
		win.enqueue(Mouse{
			Btn:  Button(e.Down),
			Mod:  Modifier(e.Mod),
			When: time.Now(),
		})
	case C.ECursor:
		e := (*C.CursorEvent)(p)
		win.enqueue(Cursor{
			X:    int(e.X),
			Y:    int(e.Y),
			When: time.Now(),
		})
	case C.EText:
		e := (*C.TextEvent)(p)
		win.enqueue(Text{
			Text: C.GoString((*C.char)(*e)),
			When: time.Now(),
		})
	case C.EEdit:
		e := (*C.EditEvent)(p)
		win.enqueue(Text{
			Text: C.GoString((*C.char)(e.Text)),
			When: time.Now(),
		})
	case C.EKeyPress:
		e := (*C.KeyEvent)(p)
		win.enqueue(KeyPress{
			Mod:  Modifier(e.Mod),
			Code: Key(e.Code),
			Down: e.Down == 1,
			When: time.Now(),
		})
	case C.EResize:
		e := (*C.ResizeEvent)(p)
		win.enqueue(Resize{
			Width:  int(e.Width),
			Height: int(e.Height),
			When:   time.Now(),
		})
	case C.EFocus:
		e := (*C.FocusEvent)(p)
		win.enqueue(Focus{
			Focused: C.int(*e) == 1,
			When:    time.Now(),
		})
	case C.EScroll:
		e := (*C.ScrollEvent)(p)
		win.enqueue(Scroll{
			X:    int(e.X),
			Y:    int(e.Y),
			When: time.Now(),
		})
	case C.ERefresh:
		win.enqueue(Damage{When: time.Now()})
	case C.EClose:
		// May make a callback here
		win.Close()
	}
}

// This could be more sophisticated; some events are
// more important than others and should not be dropped
func (w Buffer) enqueue(e Event) {
	select {
	case w.event <- e:
	default:
	}
}

// A Buffer is an OpenGL canvas that can be displayed
// within an OS window. Buffers can receive user input,
// which can be accessed with the Subscribe() method.
type Buffer struct {
	ds    unsafe.Pointer
	Event <-chan Event
	event chan Event
	lck sync.Mutex
}

// Helper functions for pulling values from our C shim
func val(x C.RC) error {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return err
}

func valP(x C.RP) (unsafe.Pointer, error) {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return x.rp, err
}

func val2(x C.R2) (int, int, error) {
	var err error
	if x.err != nil {
		err = errors.New(C.GoString(x.err))
		C.free(unsafe.Pointer(x.err))
	}
	return int(x.X), int(x.Y), err
}

// Close() closes a window and releases any resources associated with it.
func (w *Buffer) Close() {
	if w == nil {
		return
	}
	if err := val(C.dsWinClose(w.ds)); err != nil {
		log.Print(err)
	}
	close(w.event)
}

// Title retrieves the current title of a window
func (w *Buffer) Title() string {
	if w == nil {
		return ""
	}
	w.lck.Lock()
	defer w.lck.Unlock()
	if s, err := valP(C.dsWinGetTitle(w.ds)); err != nil {
		return ""
	} else {
		return C.GoString((*C.char)(s))
	}
}

// SetTitle changes a window's title string to a new value. The maximum
// length of a window title is an unspecified value over 255 characters.
func (w *Buffer) SetTitle(title string) {
	if w == nil {
		return
	}
	w.lck.Lock()
	defer w.lck.Unlock()
	s := C.CString(title)
	if err := val(C.dsWinSetTitle(w.ds, s)); err != nil {
		log.Print(err)
	}
}

// Size returns the window's width and height in pixels
func (w *Buffer) Size() (width, height int) {
	var err error
	if w == nil {
		return -1, -1
	}
	width, height, err = val2(C.dsWinSize(w.ds))
	if err != nil {
		log.Print(err)
	}
	return width, height
}

// Resize changes the width and height of a window to the specified
// dimensions in pixels. Note that height and width are only suggestions;
// especially in fullscreen mode, window system or hardware restrictions
// may prevent the desired height and width from being set. The actual
// screen size may be retrieved with the Size() method.
func (w *Buffer) Resize(width, height int) error {
	return val(C.dsWinResize(
		w.ds,
		C.int(width),
		C.int(height)))
}

// Flip swaps the background buffer with the foregroud buffer.
// All drawing is done to the background buffer. The window's context
// must be set in the calling goroutine with TakeContext() before
// SwapBuffers, or any GL drawing functions, are called. By default,
// SwapBuffers will block until the screen is refreshed.
func (w *Buffer) Flip() {
	C.dsWinSwap(w.ds)
}

func buildArgv(cfg Config) ([]*C.char, error) {
	var argv []*C.char

	for key, val := range cfg {
		argv = append(argv, C.CString(key))
		argv = append(argv, C.CString(val))
	}

	argv = append(argv, nil)
	return argv, nil
}

func freeArgv(argv []*C.char) {
	for _, s := range argv {
		if s != nil {
			C.free(unsafe.Pointer(s))
		}
	}
}

// Open creates a new window.
func Open(c Config) (*Buffer, error) {
	var argv []*C.char
	var err error

	initialize.Do(func() {
		err = val(C.dsInit(0, nil))
	})
	if err != nil {
		return nil, err
	}

	buf := new(Buffer)
	buf.event = make(chan Event, 20)
	buf.Event = buf.event

	if argv, err = buildArgv(c); err != nil {
		return nil, err
	}

	buf.ds, err = valP(C.dsWinOpen(unsafe.Pointer(buf), C.int(len(argv)-1), &argv[0]))
	freeArgv(argv)
	if err != nil {
		return nil, err
	}
	return buf, nil
}

func (w *Buffer) CheckEvent() error {
	return val(C.dsWinCheckEvent(w.ds))
}

func (w *Buffer) WaitEvent() error {
	return val(C.dsWinWaitEvent(w.ds))
}
<|endoftext|>