<commit_before>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/crypto/scrypt"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

var daemonConfigLock sync.Mutex
var daemonConfig map[string]*daemonConfigKey

type daemonConfigKey struct {
	valueType    string
	defaultValue string
	validValues  []string
	currentValue string
	hiddenValue  bool

	validator func(d *Daemon, key string, value string) error
	setter    func(d *Daemon, key string, value string) (string, error)
	trigger   func(d *Daemon, key string, value string)
}

func (k *daemonConfigKey) name() string {
	name := ""

	// Look for a matching entry in daemonConfig
	daemonConfigLock.Lock()
	for key, value := range daemonConfig {
		if value == k {
			name = key
			break
		}
	}
	daemonConfigLock.Unlock()

	return name
}

func (k *daemonConfigKey) Validate(d *Daemon, value string) error {
	// No need to validate when unsetting
	if value == "" {
		return nil
	}

	// Validate booleans
	if k.valueType == "bool" && !shared.StringInSlice(strings.ToLower(value), []string{"true", "false", "1", "0", "yes", "no"}) {
		return fmt.Errorf("Invalid value for a boolean: %s", value)
	}

	// Validate integers
	if k.valueType == "int" {
		_, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}
	}

	// Check against valid values
	if k.validValues != nil && !shared.StringInSlice(value, k.validValues) {
		return fmt.Errorf("Invalid value, only the following values are allowed: %s", k.validValues)
	}

	// Run external validation function
	if k.validator != nil {
		err := k.validator(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	return nil
}

func (k *daemonConfigKey) Set(d *Daemon, value string) error {
	var name string

	// Check if we are actually changing things
	oldValue := k.currentValue
	if oldValue == value {
		return nil
	}

	// Validate the new value
	err := k.Validate(d, value)
	if err != nil {
		return err
	}

	// Run external setting function
	if k.setter != nil {
		value, err = k.setter(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	// Get the configuration key and make sure daemonConfig is sane
	name = k.name()
	if name == "" {
		return fmt.Errorf("Corrupted configuration cache")
	}

	// Actually apply the change
	daemonConfigLock.Lock()
	k.currentValue = value
	daemonConfigLock.Unlock()

	err = dbConfigValueSet(d.db, name, value)
	if err != nil {
		return err
	}

	return nil
}

func (k *daemonConfigKey) Get() string {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	return value
}

func (k *daemonConfigKey) GetBool() bool {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to boolean
	if shared.StringInSlice(strings.ToLower(value), []string{"true", "1", "yes"}) {
		return true
	}

	return false
}

func (k *daemonConfigKey) GetInt64() int64 {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to int64
	ret, _ := strconv.ParseInt(value, 10, 64)
	return ret
}

func daemonConfigInit(db *sql.DB) error {
	// Set all the keys
	daemonConfig = map[string]*daemonConfigKey{
		"core.https_address":         &daemonConfigKey{valueType: "string", setter: daemonConfigSetAddress},
		"core.https_allowed_headers": &daemonConfigKey{valueType: "string"},
		"core.https_allowed_methods": &daemonConfigKey{valueType: "string"},
		"core.https_allowed_origin":  &daemonConfigKey{valueType: "string"},
		"core.proxy_http":            &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_https":           &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_ignore_hosts":    &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.trust_password":        &daemonConfigKey{valueType: "string", hiddenValue: true, setter: daemonConfigSetPassword},

		"images.auto_update_cached":    &daemonConfigKey{valueType: "bool", defaultValue: "true"},
		"images.auto_update_interval":  &daemonConfigKey{valueType: "int", defaultValue: "6"},
		"images.compression_algorithm": &daemonConfigKey{valueType: "string", validator: daemonConfigValidateCommand, defaultValue: "gzip"},
		"images.remote_cache_expiry":   &daemonConfigKey{valueType: "int", defaultValue: "10", trigger: daemonConfigTriggerExpiry},

		"storage.lvm_fstype":           &daemonConfigKey{valueType: "string", defaultValue: "ext4", validValues: []string{"ext4", "xfs"}},
		"storage.lvm_thinpool_name":    &daemonConfigKey{valueType: "string", defaultValue: "LXDPool", validator: storageLVMValidateThinPoolName},
		"storage.lvm_vg_name":          &daemonConfigKey{valueType: "string", validator: storageLVMValidateVolumeGroupName, setter: daemonConfigSetStorage},
		"storage.lvm_volume_size":      &daemonConfigKey{valueType: "string", defaultValue: "10GiB"},
		"storage.zfs_pool_name":        &daemonConfigKey{valueType: "string", validator: storageZFSValidatePoolName, setter: daemonConfigSetStorage},
		"storage.zfs_remove_snapshots": &daemonConfigKey{valueType: "bool"},
	}

	// Load the values from the DB
	dbValues, err := dbConfigValuesGet(db)
	if err != nil {
		return err
	}

	daemonConfigLock.Lock()
	for k, v := range dbValues {
		_, ok := daemonConfig[k]
		if !ok {
			shared.Log.Error("Found invalid configuration key in database", log.Ctx{"key": k})
		}

		daemonConfig[k].currentValue = v
	}
	daemonConfigLock.Unlock()

	return nil
}

func daemonConfigRender() map[string]interface{} {
	config := map[string]interface{}{}

	// Turn the config into a JSON-compatible map
	for k, v := range daemonConfig {
		value := v.Get()
		if value != v.defaultValue {
			if v.hiddenValue {
				config[k] = true
			} else {
				config[k] = value
			}
		}
	}

	return config
}

func daemonConfigSetPassword(d *Daemon, key string, value string) (string, error) {
	// Nothing to do on unset
	if value == "" {
		return value, nil
	}

	// Hash the password
	buf := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, buf)
	if err != nil {
		return "", err
	}

	hash, err := scrypt.Key([]byte(value), buf, 1<<14, 8, 1, 64)
	if err != nil {
		return "", err
	}

	buf = append(buf, hash...)
	value = hex.EncodeToString(buf)

	return value, nil
}

func daemonConfigSetStorage(d *Daemon, key string, value string) (string, error) {
	// The storage driver looks at daemonConfig so just set it temporarily
	daemonConfigLock.Lock()
	oldValue := daemonConfig[key].Get()
	daemonConfig[key].currentValue = value
	daemonConfigLock.Unlock()

	defer func() {
		daemonConfigLock.Lock()
		daemonConfig[key].currentValue = oldValue
		daemonConfigLock.Unlock()
	}()

	// Update the current storage driver
	err := d.SetupStorageDriver()
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetAddress(d *Daemon, key string, value string) (string, error) {
	// Update the current https address
	err := d.UpdateHTTPsPort(value)
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetProxy(d *Daemon, key string, value string) (string, error) {
	// Get the current config
	config := map[string]string{}
	config["core.proxy_https"] = daemonConfig["core.proxy_https"].Get()
	config["core.proxy_http"] = daemonConfig["core.proxy_http"].Get()
	config["core.proxy_ignore_hosts"] = daemonConfig["core.proxy_ignore_hosts"].Get()

	// Apply the change
	config[key] = value

	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config["core.proxy_https"],
		config["core.proxy_http"],
		config["core.proxy_ignore_hosts"],
	)

	// Clear the simplestreams cache as it's tied to the old proxy config
	imageStreamCacheLock.Lock()
	for k, _ := range imageStreamCache {
		delete(imageStreamCache, k)
	}
	imageStreamCacheLock.Unlock()

	return value, nil
}

func daemonConfigTriggerExpiry(d *Daemon, key string, value string) {
	// Trigger an image pruning run
	d.pruneChan <- true
}

func daemonConfigValidateCommand(d *Daemon, key string, value string) error {
	_, err := exec.LookPath(value)
	return err
}
<commit_msg>Allow on/off as boolean strings<commit_after>package main

import (
	"crypto/rand"
	"database/sql"
	"encoding/hex"
	"fmt"
	"io"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	"golang.org/x/crypto/scrypt"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

var daemonConfigLock sync.Mutex
var daemonConfig map[string]*daemonConfigKey

type daemonConfigKey struct {
	valueType    string
	defaultValue string
	validValues  []string
	currentValue string
	hiddenValue  bool

	validator func(d *Daemon, key string, value string) error
	setter    func(d *Daemon, key string, value string) (string, error)
	trigger   func(d *Daemon, key string, value string)
}

func (k *daemonConfigKey) name() string {
	name := ""

	// Look for a matching entry in daemonConfig
	daemonConfigLock.Lock()
	for key, value := range daemonConfig {
		if value == k {
			name = key
			break
		}
	}
	daemonConfigLock.Unlock()

	return name
}

func (k *daemonConfigKey) Validate(d *Daemon, value string) error {
	// No need to validate when unsetting
	if value == "" {
		return nil
	}

	// Validate booleans
	if k.valueType == "bool" && !shared.StringInSlice(strings.ToLower(value), []string{"true", "false", "1", "0", "yes", "no", "on", "off"}) {
		return fmt.Errorf("Invalid value for a boolean: %s", value)
	}

	// Validate integers
	if k.valueType == "int" {
		_, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return err
		}
	}

	// Check against valid values
	if k.validValues != nil && !shared.StringInSlice(value, k.validValues) {
		return fmt.Errorf("Invalid value, only the following values are allowed: %s", k.validValues)
	}

	// Run external validation function
	if k.validator != nil {
		err := k.validator(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	return nil
}

func (k *daemonConfigKey) Set(d *Daemon, value string) error {
	var name string

	// Check if we are actually changing things
	oldValue := k.currentValue
	if oldValue == value {
		return nil
	}

	// Validate the new value
	err := k.Validate(d, value)
	if err != nil {
		return err
	}

	// Run external setting function
	if k.setter != nil {
		value, err = k.setter(d, k.name(), value)
		if err != nil {
			return err
		}
	}

	// Get the configuration key and make sure daemonConfig is sane
	name = k.name()
	if name == "" {
		return fmt.Errorf("Corrupted configuration cache")
	}

	// Actually apply the change
	daemonConfigLock.Lock()
	k.currentValue = value
	daemonConfigLock.Unlock()

	err = dbConfigValueSet(d.db, name, value)
	if err != nil {
		return err
	}

	return nil
}

func (k *daemonConfigKey) Get() string {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	return value
}

func (k *daemonConfigKey) GetBool() bool {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to boolean
	if shared.StringInSlice(strings.ToLower(value), []string{"true", "1", "yes", "on"}) {
		return true
	}

	return false
}

func (k *daemonConfigKey) GetInt64() int64 {
	value := k.currentValue

	// Get the default value if not set
	if value == "" {
		value = k.defaultValue
	}

	// Convert to int64
	ret, _ := strconv.ParseInt(value, 10, 64)
	return ret
}

func daemonConfigInit(db *sql.DB) error {
	// Set all the keys
	daemonConfig = map[string]*daemonConfigKey{
		"core.https_address":         &daemonConfigKey{valueType: "string", setter: daemonConfigSetAddress},
		"core.https_allowed_headers": &daemonConfigKey{valueType: "string"},
		"core.https_allowed_methods": &daemonConfigKey{valueType: "string"},
		"core.https_allowed_origin":  &daemonConfigKey{valueType: "string"},
		"core.proxy_http":            &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_https":           &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.proxy_ignore_hosts":    &daemonConfigKey{valueType: "string", setter: daemonConfigSetProxy},
		"core.trust_password":        &daemonConfigKey{valueType: "string", hiddenValue: true, setter: daemonConfigSetPassword},

		"images.auto_update_cached":    &daemonConfigKey{valueType: "bool", defaultValue: "true"},
		"images.auto_update_interval":  &daemonConfigKey{valueType: "int", defaultValue: "6"},
		"images.compression_algorithm": &daemonConfigKey{valueType: "string", validator: daemonConfigValidateCommand, defaultValue: "gzip"},
		"images.remote_cache_expiry":   &daemonConfigKey{valueType: "int", defaultValue: "10", trigger: daemonConfigTriggerExpiry},

		"storage.lvm_fstype":           &daemonConfigKey{valueType: "string", defaultValue: "ext4", validValues: []string{"ext4", "xfs"}},
		"storage.lvm_thinpool_name":    &daemonConfigKey{valueType: "string", defaultValue: "LXDPool", validator: storageLVMValidateThinPoolName},
		"storage.lvm_vg_name":          &daemonConfigKey{valueType: "string", validator: storageLVMValidateVolumeGroupName, setter: daemonConfigSetStorage},
		"storage.lvm_volume_size":      &daemonConfigKey{valueType: "string", defaultValue: "10GiB"},
		"storage.zfs_pool_name":        &daemonConfigKey{valueType: "string", validator: storageZFSValidatePoolName, setter: daemonConfigSetStorage},
		"storage.zfs_remove_snapshots": &daemonConfigKey{valueType: "bool"},
	}

	// Load the values from the DB
	dbValues, err := dbConfigValuesGet(db)
	if err != nil {
		return err
	}

	daemonConfigLock.Lock()
	for k, v := range dbValues {
		_, ok := daemonConfig[k]
		if !ok {
			shared.Log.Error("Found invalid configuration key in database", log.Ctx{"key": k})
		}

		daemonConfig[k].currentValue = v
	}
	daemonConfigLock.Unlock()

	return nil
}

func daemonConfigRender() map[string]interface{} {
	config := map[string]interface{}{}

	// Turn the config into a JSON-compatible map
	for k, v := range daemonConfig {
		value := v.Get()
		if value != v.defaultValue {
			if v.hiddenValue {
				config[k] = true
			} else {
				config[k] = value
			}
		}
	}

	return config
}

func daemonConfigSetPassword(d *Daemon, key string, value string) (string, error) {
	// Nothing to do on unset
	if value == "" {
		return value, nil
	}

	// Hash the password
	buf := make([]byte, 32)
	_, err := io.ReadFull(rand.Reader, buf)
	if err != nil {
		return "", err
	}

	hash, err := scrypt.Key([]byte(value), buf, 1<<14, 8, 1, 64)
	if err != nil {
		return "", err
	}

	buf = append(buf, hash...)
	value = hex.EncodeToString(buf)

	return value, nil
}

func daemonConfigSetStorage(d *Daemon, key string, value string) (string, error) {
	// The storage driver looks at daemonConfig so just set it temporarily
	daemonConfigLock.Lock()
	oldValue := daemonConfig[key].Get()
	daemonConfig[key].currentValue = value
	daemonConfigLock.Unlock()

	defer func() {
		daemonConfigLock.Lock()
		daemonConfig[key].currentValue = oldValue
		daemonConfigLock.Unlock()
	}()

	// Update the current storage driver
	err := d.SetupStorageDriver()
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetAddress(d *Daemon, key string, value string) (string, error) {
	// Update the current https address
	err := d.UpdateHTTPsPort(value)
	if err != nil {
		return "", err
	}

	return value, nil
}

func daemonConfigSetProxy(d *Daemon, key string, value string) (string, error) {
	// Get the current config
	config := map[string]string{}
	config["core.proxy_https"] = daemonConfig["core.proxy_https"].Get()
	config["core.proxy_http"] = daemonConfig["core.proxy_http"].Get()
	config["core.proxy_ignore_hosts"] = daemonConfig["core.proxy_ignore_hosts"].Get()

	// Apply the change
	config[key] = value

	// Update the cached proxy function
	d.proxy = shared.ProxyFromConfig(
		config["core.proxy_https"],
		config["core.proxy_http"],
		config["core.proxy_ignore_hosts"],
	)

	// Clear the simplestreams cache as it's tied to the old proxy config
	imageStreamCacheLock.Lock()
	for k, _ := range imageStreamCache {
		delete(imageStreamCache, k)
	}
	imageStreamCacheLock.Unlock()

	return value, nil
}

func daemonConfigTriggerExpiry(d *Daemon, key string, value string) {
	// Trigger an image pruning run
	d.pruneChan <- true
}

func daemonConfigValidateCommand(d *Daemon, key string, value string) error {
	_, err := exec.LookPath(value)
	return err
}
<|endoftext|>


<commit_before>//go:build linux && cgo && !agent
// +build linux,cgo,!agent

package state

import (
	"context"
	"testing"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/firewall"
	"github.com/lxc/lxd/lxd/sys"
)

// NewTestState returns a State object initialized with testable instances of
// the node/cluster databases and of the OS facade.
//
// Return the newly created State object, along with a function that can be
// used for cleaning it up.
func NewTestState(t *testing.T) (*State, func()) {
	node, nodeCleanup := db.NewTestNode(t)
	cluster, clusterCleanup := db.NewTestCluster(t)
	os, osCleanup := sys.NewTestOS(t)

	cleanup := func() {
		nodeCleanup()
		clusterCleanup()
		osCleanup()
	}

	state := NewState(context.TODO(), node, cluster, nil, os, nil, nil, nil, firewall.New(), nil)

	return state, cleanup
}
<commit_msg>lxd/state: Update tests with NewState usage<commit_after>//go:build linux && cgo && !agent
// +build linux,cgo,!agent

package state

import (
	"context"
	"testing"

	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/firewall"
	"github.com/lxc/lxd/lxd/sys"
)

// NewTestState returns a State object initialized with testable instances of
// the node/cluster databases and of the OS facade.
//
// Return the newly created State object, along with a function that can be
// used for cleaning it up.
func NewTestState(t *testing.T) (*State, func()) {
	node, nodeCleanup := db.NewTestNode(t)
	cluster, clusterCleanup := db.NewTestCluster(t)
	os, osCleanup := sys.NewTestOS(t)

	cleanup := func() {
		nodeCleanup()
		clusterCleanup()
		osCleanup()
	}

	state := NewState(context.TODO(), node, cluster, nil, os, nil, nil, nil, firewall.New(), nil, nil, func() {})

	return state, cleanup
}
<|endoftext|>


<commit_before>package locus

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"github.com/dpup/locus/tmpl"
)

// OverrideQueryParam param that when specified in the URL overrides the request
// in the URL.
// e.g. http://localhost:5555/?locus_override=http://sample.locus.xyz
const OverrideQueryParam = "locus_override"

// Locus wraps a fork of golang's httputil.ReverseProxy to provide multi-host
// routing.
type Locus struct {

	// VerboseLogging specifies that additional request details should be logged.
	VerboseLogging bool

	// AccessLog specifies an optional logger for request details. If nil,
	// logging goes to os.Stderr via the log package's standard logger.
	AccessLog *log.Logger

	// ErrorLog specifies an optional logger for exceptional occurances. If nil,
	// logging goes to os.Stderr via the log package's standard logger.
	ErrorLog *log.Logger

	// Port specifies the port for incoming connections.
	Port uint16

	// ReadTimeout is the maximum duration before timing out read of the request.
	ReadTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out write of the
	// response.
	WriteTimeout time.Duration

	// Configs is a list of sites that locus will forward for.
	Configs []*Config

	proxy *reverseProxy
}

// New returns an instance of a Locus server with the following defaults set:
// Port = 5555
// ReadTimeout = 30s
// WriteTimeout = 30s
func New() *Locus {
	return &Locus{
		proxy:        &reverseProxy{},
		Configs:      []*Config{},
		Port:         5555,
		ReadTimeout:  time.Second * 30,
		WriteTimeout: time.Second * 30,
	}
}

// FromConfig creates a new locus server from YAML config.
// See SampleYAMLConfig.
func FromConfig(data []byte) (*Locus, error) {
	cfgs, globals, err := loadConfigFromYAML(data)
	if err != nil {
		return nil, err
	}

	locus := New()

	if globals.Port != 0 {
		locus.Port = globals.Port
	}
	if globals.ReadTimeout != 0 {
		locus.ReadTimeout = globals.ReadTimeout
	}
	if globals.WriteTimeout != 0 {
		locus.WriteTimeout = globals.WriteTimeout
	}

	locus.VerboseLogging = globals.VerboseLogging

	if globals.AccessLog != "" {
		locus.AccessLog, err = newLogger(globals.AccessLog)
		if err != nil {
			return nil, err
		}
	}

	if globals.ErrorLog != "" {
		locus.ErrorLog, err = newLogger(globals.ErrorLog)
		if err != nil {
			return nil, err
		}
	}

	for _, cfg := range cfgs {
		locus.AddConfig(cfg)
	}

	return locus, nil
}

// FromConfigFile creates a new locus server from a YAML config file.
func FromConfigFile(filename string) (*Locus, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return FromConfig(data)
}

// NewConfig creates an empty config, registers it, then returns it.
func (locus *Locus) NewConfig() *Config {
	cfg := &Config{Name: fmt.Sprintf("cfg%d", len(locus.Configs))}
	locus.AddConfig(cfg)
	return cfg
}

// AddConfig adds config to the reverse proxy. Configs will be checked in the
// order they were added, the first matching config being used to route the
// request.
func (locus *Locus) AddConfig(cfg *Config) {
	locus.Configs = append(locus.Configs, cfg)
}

// ListenAndServe listens on locus.Port for incoming connections.
func (locus *Locus) ListenAndServe() error {
	s := http.Server{
		Addr:           fmt.Sprintf(":%d", locus.Port),
		Handler:        locus,
		ReadTimeout:    locus.ReadTimeout,
		WriteTimeout:   locus.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	locus.elogf("Starting Locus on port %d", locus.Port)
	return s.ListenAndServe()
}

func (locus *Locus) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	overrideParam := req.URL.Query().Get(OverrideQueryParam)
	if overrideParam != "" {
		overrideURL, err := url.Parse(overrideParam)
		if err != nil {
			locus.elogf("error parsing override URL, ignoring: ", err)
		} else {
			req.URL = overrideURL
		}
	}

	c := locus.findConfig(req)
	if c != nil {
		// Found matching config so copy req, transform it, and forward it.
		proxyreq := copyRequest(req)

		if err := c.Transform(proxyreq); err != nil { // TODO: Render local error page.
			locus.elogf("error transforming request: %v", err)
			rw.WriteHeader(http.StatusInternalServerError)
			locus.logDefaultReq(http.StatusInternalServerError, req)
			return
		}

		status := http.StatusOK // TODO: extract status code from rw.

		if err := locus.proxy.Proxy(rw, proxyreq); err != nil { // TODO: Render local error page.
			locus.elogf("error proxying request: %v", err)
			rw.WriteHeader(http.StatusInternalServerError)
			status = http.StatusInternalServerError
		}

		var d []byte
		if locus.VerboseLogging {
			d, _ = httputil.DumpRequestOut(proxyreq, false)
		}
		locus.alogf("locus[%s] %d %s %s => %s (%s \"%s\") %s",
			c.Name, status, req.Method, req.URL, proxyreq.URL, req.RemoteAddr,
			req.Header.Get("User-Agent"), string(d))

	} else if req.URL.Path == "/debug/configs" {
		tmpl.DebugTemplate.ExecuteTemplate(rw, "configs", locus)
		locus.logDefaultReq(http.StatusOK, req)
	} else {
		rw.WriteHeader(http.StatusNotImplemented)
		locus.logDefaultReq(http.StatusNotImplemented, req)
	}
}

func (locus *Locus) logDefaultReq(status int, req *http.Request) {
	locus.alogf("locus[-] %d %s %s (%s \"%s\")",
		status, req.Method, req.URL, req.RemoteAddr, req.Header.Get("User-Agent"))
}

func (locus *Locus) findConfig(req *http.Request) *Config {
	for _, c := range locus.Configs {
		if c.Matches(req) {
			return c
		}
	}
	return nil
}

func (locus *Locus) alogf(format string, args ...interface{}) {
	if locus.AccessLog != nil {
		locus.AccessLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func (locus *Locus) elogf(format string, args ...interface{}) {
	if locus.ErrorLog != nil {
		locus.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}
<commit_msg>Add package docs<commit_after>// Package locus provides a multi-host reverse proxy.
package locus

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	"github.com/dpup/locus/tmpl"
)

// OverrideQueryParam param that when specified in the URL overrides the request
// in the URL.
// e.g. http://localhost:5555/?locus_override=http://sample.locus.xyz
const OverrideQueryParam = "locus_override"

// Locus wraps a fork of golang's httputil.ReverseProxy to provide multi-host
// routing.
type Locus struct {

	// VerboseLogging specifies that additional request details should be logged.
	VerboseLogging bool

	// AccessLog specifies an optional logger for request details. If nil,
	// logging goes to os.Stderr via the log package's standard logger.
	AccessLog *log.Logger

	// ErrorLog specifies an optional logger for exceptional occurances. If nil,
	// logging goes to os.Stderr via the log package's standard logger.
	ErrorLog *log.Logger

	// Port specifies the port for incoming connections.
	Port uint16

	// ReadTimeout is the maximum duration before timing out read of the request.
	ReadTimeout time.Duration

	// WriteTimeout is the maximum duration before timing out write of the
	// response.
	WriteTimeout time.Duration

	// Configs is a list of sites that locus will forward for.
	Configs []*Config

	proxy *reverseProxy
}

// New returns an instance of a Locus server with the following defaults set:
// Port = 5555
// ReadTimeout = 30s
// WriteTimeout = 30s
func New() *Locus {
	return &Locus{
		proxy:        &reverseProxy{},
		Configs:      []*Config{},
		Port:         5555,
		ReadTimeout:  time.Second * 30,
		WriteTimeout: time.Second * 30,
	}
}

// FromConfig creates a new locus server from YAML config.
// See SampleYAMLConfig.
func FromConfig(data []byte) (*Locus, error) {
	cfgs, globals, err := loadConfigFromYAML(data)
	if err != nil {
		return nil, err
	}

	locus := New()

	if globals.Port != 0 {
		locus.Port = globals.Port
	}
	if globals.ReadTimeout != 0 {
		locus.ReadTimeout = globals.ReadTimeout
	}
	if globals.WriteTimeout != 0 {
		locus.WriteTimeout = globals.WriteTimeout
	}

	locus.VerboseLogging = globals.VerboseLogging

	if globals.AccessLog != "" {
		locus.AccessLog, err = newLogger(globals.AccessLog)
		if err != nil {
			return nil, err
		}
	}

	if globals.ErrorLog != "" {
		locus.ErrorLog, err = newLogger(globals.ErrorLog)
		if err != nil {
			return nil, err
		}
	}

	for _, cfg := range cfgs {
		locus.AddConfig(cfg)
	}

	return locus, nil
}

// FromConfigFile creates a new locus server from a YAML config file.
func FromConfigFile(filename string) (*Locus, error) {
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	return FromConfig(data)
}

// NewConfig creates an empty config, registers it, then returns it.
func (locus *Locus) NewConfig() *Config {
	cfg := &Config{Name: fmt.Sprintf("cfg%d", len(locus.Configs))}
	locus.AddConfig(cfg)
	return cfg
}

// AddConfig adds config to the reverse proxy. Configs will be checked in the
// order they were added, the first matching config being used to route the
// request.
func (locus *Locus) AddConfig(cfg *Config) {
	locus.Configs = append(locus.Configs, cfg)
}

// ListenAndServe listens on locus.Port for incoming connections.
func (locus *Locus) ListenAndServe() error {
	s := http.Server{
		Addr:           fmt.Sprintf(":%d", locus.Port),
		Handler:        locus,
		ReadTimeout:    locus.ReadTimeout,
		WriteTimeout:   locus.WriteTimeout,
		MaxHeaderBytes: 1 << 20,
	}
	locus.elogf("Starting Locus on port %d", locus.Port)
	return s.ListenAndServe()
}

func (locus *Locus) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	overrideParam := req.URL.Query().Get(OverrideQueryParam)
	if overrideParam != "" {
		overrideURL, err := url.Parse(overrideParam)
		if err != nil {
			locus.elogf("error parsing override URL, ignoring: ", err)
		} else {
			req.URL = overrideURL
		}
	}

	c := locus.findConfig(req)
	if c != nil {
		// Found matching config so copy req, transform it, and forward it.
		proxyreq := copyRequest(req)

		if err := c.Transform(proxyreq); err != nil { // TODO: Render local error page.
			locus.elogf("error transforming request: %v", err)
			rw.WriteHeader(http.StatusInternalServerError)
			locus.logDefaultReq(http.StatusInternalServerError, req)
			return
		}

		status := http.StatusOK // TODO: extract status code from rw.

		if err := locus.proxy.Proxy(rw, proxyreq); err != nil { // TODO: Render local error page.
			locus.elogf("error proxying request: %v", err)
			rw.WriteHeader(http.StatusInternalServerError)
			status = http.StatusInternalServerError
		}

		var d []byte
		if locus.VerboseLogging {
			d, _ = httputil.DumpRequestOut(proxyreq, false)
		}
		locus.alogf("locus[%s] %d %s %s => %s (%s \"%s\") %s",
			c.Name, status, req.Method, req.URL, proxyreq.URL, req.RemoteAddr,
			req.Header.Get("User-Agent"), string(d))

	} else if req.URL.Path == "/debug/configs" {
		tmpl.DebugTemplate.ExecuteTemplate(rw, "configs", locus)
		locus.logDefaultReq(http.StatusOK, req)
	} else {
		rw.WriteHeader(http.StatusNotImplemented)
		locus.logDefaultReq(http.StatusNotImplemented, req)
	}
}

func (locus *Locus) logDefaultReq(status int, req *http.Request) {
	locus.alogf("locus[-] %d %s %s (%s \"%s\")",
		status, req.Method, req.URL, req.RemoteAddr, req.Header.Get("User-Agent"))
}

func (locus *Locus) findConfig(req *http.Request) *Config {
	for _, c := range locus.Configs {
		if c.Matches(req) {
			return c
		}
	}
	return nil
}

func (locus *Locus) alogf(format string, args ...interface{}) {
	if locus.AccessLog != nil {
		locus.AccessLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

func (locus *Locus) elogf(format string, args ...interface{}) {
	if locus.ErrorLog != nil {
		locus.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}
<|endoftext|>


<commit_before>package main

/* The output of this utility is JSON, but not intended to be easily human-readable.
   At this moment it exists to test the rtnetlink/route subsystem */

import "os"
import "netlink/rtnetlink/route"
import "netlink/rtnetlink"
import "log"
import "netlink"

func main(){
  rtmsg := route.NewMessage(0,0,0,0,0,0,0,0,0)
  nlmsg, err := netlink.NewMessage2(rtnetlink.RTM_GETROUTE, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, rtmsg)
  if err != nil {
    log.Exitf("Couldn't construct message: %v", err)
  }
  nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE)
  if err != nil {
    log.Exitf("Couldn't dial netlink: %v", err)
  }
  h := netlink.NewHandler(nlsock)
  ec := make(chan os.Error)
  go h.Start(ec)
  c := make(chan netlink.NetlinkMessage)
  err = h.SendQuery(nlmsg, c)
  if err != nil {
    log.Exitf("Couldn't write netlink: %v", err)
  }
  for i := range( c) {
    switch i.MessageType() {
      case rtnetlink.RTM_NEWROUTE:
        msg := &route.RoutingMessage{}
        err = msg.UnmarshalNetlink(i.Body(), 4)
        if err == nil {
          log.Printf("NLMsg: %v", msg)
        } else {
          log.Printf("Unmarshal error: %v", err)
        }
      default:
          log.Printf("Unknown type: %v", i)
    }
  }
}
<commit_msg>Update syntax<commit_after>package main

/* The output of this utility is JSON, but not intended to be easily human-readable.
   At this moment it exists to test the rtnetlink/route subsystem */

import "os"
import "netlink/rtnetlink/route"
import "netlink/rtnetlink"
import "log"
import "netlink"

func main(){
  rtmsg := route.NewMessage(0,0,0,0,0,0,0,0,0)
  nlmsg, err := netlink.NewMessage2(rtnetlink.RTM_GETROUTE, netlink.NLM_F_DUMP|netlink.NLM_F_REQUEST, rtmsg)
  if err != nil {
    log.Exitf("Couldn't construct message: %v", err)
  }
  nlsock, err := netlink.Dial(netlink.NETLINK_ROUTE)
  if err != nil {
    log.Exitf("Couldn't dial netlink: %v", err)
  }
  h := netlink.NewHandler(nlsock)
  ec := make(chan os.Error)
  go h.Start(ec)
  c := make(chan netlink.NetlinkMessage)
  err = h.SendQuery(nlmsg, c)
  if err != nil {
    log.Exitf("Couldn't write netlink: %v", err)
  }
  for i := range( c) {
    switch i.MessageType() {
      case rtnetlink.RTM_NEWROUTE:
        msg := rtnetlink.NewMessage(&route.Header{}, nil)
        err = msg.UnmarshalNetlink(i.Body(), 4)
        if err == nil {
          log.Printf("NLMsg: %v", msg)
        } else {
          log.Printf("Unmarshal error: %v", err)
        }
      default:
          log.Printf("Unknown type: %v", i)
    }
  }
}
<|endoftext|>


<commit_before>package vjoy

import (
	"errors"
	"github.com/tajtiattila/vjoy/dll"
)

var (
	ErrDeviceAlreadyOwned = errors.New("vJoy Device already open by this application")
	ErrDeviceBusy         = errors.New("vJoy Device is owned by another application")
	ErrDeviceMissing      = errors.New("vJoy Device is missing: either does not exist or the driver is down")
	ErrDeviceUnknown      = errors.New("Unknown vJoy Device error")
	ErrReset              = errors.New("Reset failed")
	ErrUpdate             = errors.New("UpdateVJD failed")
	ErrUnknownName        = errors.New("Unknown name (axis, button or pov)")
)

// Available check if the vjoy.dll was successfully loaded and is enabled.
// Other functions in this library will likely panic if Available returns
// false.
func Available() bool {
	err := dll.Load()
	return err == nil && dll.VJoyEnabled()
}

// Version returns the version number of the installed vJoy.
func Version() uint {
	return uint(dll.GetvJoyVersion())
}

func ProductString() string {
	return dll.GetvJoyProductString()
}

func ManufacturerString() string {
	return dll.GetvJoyManufacturerString()
}

func SerialNumberString() string {
	return dll.GetvJoySerialNumberString()
}

// ResetAll resets all VJD devices
func ResetAll() error {
	if dll.ResetAll() {
		return nil
	}
	return ErrReset
}

type AxisName int

const (
	AxisX AxisName = iota
	AxisY
	AxisZ
	AxisRX
	AxisRY
	AxisRZ
	Slider0
	Slider1
	MaxAxis
)

func axisNumber(a AxisName) uint {
	switch a {
	case AxisX:
		return dll.HID_USAGE_X
	case AxisY:
		return dll.HID_USAGE_Y
	case AxisZ:
		return dll.HID_USAGE_Z
	case AxisRX:
		return dll.HID_USAGE_RX
	case AxisRY:
		return dll.HID_USAGE_RY
	case AxisRZ:
		return dll.HID_USAGE_RZ
	case Slider0:
		return dll.HID_USAGE_SL0
	case Slider1:
		return dll.HID_USAGE_SL1
	}
	return 0
}

type Axis struct {
	p        *int32
	exists   bool
	min, max int32
}

func (a *Axis) Exists() bool { return a.exists }

func (a *Axis) Setu(val int) { *(a.p) = int32(val & 0x7fff) } // 0..0x7fff
func (a *Axis) Seti(val int) { a.Setu(val - 0x4000) }         // -0x4000..0x3fff

// Setc is same as Setu, but truncates values to permitted bounds
func (a *Axis) Setc(val int) {
	switch {
	case val < 0:
		val = 0
	case 0x7fff < val:
		val = 0x7fff
	}
	a.Setu(val)
}

func (a *Axis) Setf(val float32) {
	var v int
	if val < 0 {
		val += 1
		if val < 0 {
			val = 0
		}
		v = int(val * 0x4000)
	} else {
		if val > 1 {
			val = 1
		}
		v = 0x4000 + int(val*0x3fff)
	}
	a.Setu(v)
}

func (a *Axis) Setuf(val float32) { a.Setc(int(val * 0x7fff)) } // 0..1

type Button struct {
	p      *int32
	mask   int32
	exists bool
}

func (b *Button) Exists() bool {
	return b.exists
}

func (b *Button) Set(val bool) {
	if val {
		*(b.p) |= b.mask
	} else {
		*(b.p) &= ^b.mask
	}
}

type HatState int

const (
	HatN   HatState = 0
	HatE   HatState = 1
	HatS   HatState = 2
	HatW   HatState = 3
	HatOff HatState = -1
)

type Hat interface {
	Exists() bool
	SetDiscrete(HatState)
	SetDegp(int) // set value in degree-percents (-1: off, 0-360000: direction)
}

type continuousHat struct {
	p      *uint32
	shift  uint
	exists bool
}

func (h *continuousHat) Exists() bool {
	return h.exists
}

func (h *continuousHat) SetDiscrete(s HatState) {
	mask := uint32(0xffff) << h.shift
	val := int(s)
	if val > 0 {
		val *= 9000
	}
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

func (h *continuousHat) SetDegp(val int) {
	mask := uint32(0xffff) << h.shift
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

type discreteHat struct {
	p      *uint32
	shift  uint
	exists bool
}

func (h *discreteHat) Exists() bool {
	return h.exists
}

func (h *discreteHat) SetDiscrete(val HatState) {
	mask := uint32(0xf) << h.shift
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

func (h *discreteHat) SetDegp(val int) {
	if val > 0 {
		val = ((val + 4500) / 9000) % 4
	}
	mask := uint32(0xffff) << h.shift
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

// Device represents an open vJoy device
type Device struct {
	rid           uint                  // rid Device opened with
	st            dll.JOYSTICK_POSITION // state for Update()
	noi           int32
	nou           uint32
	axes          []*Axis
	buttons       []*Button
	hats          []Hat
	invalidaxis   *Axis
	invalidbutton *Button
	invalidhat    Hat
}

// Acquire opens a Device for use in the application.
func Acquire(rid uint) (*Device, error) {
	d := &Device{rid: rid}
	err := d.init()
	if err != nil {
		return nil, err
	}
	d.Reset()
	d.Update()
	return d, nil
}

// Relinquish closes an acquired device
func (d *Device) Relinquish() {
	dll.RelinquishVJD(d.rid)
}

// reset Device: Axes centered, Buttons and Hats off.
func (d *Device) Reset() {
	const center = 0x4000
	d.st.Throttle = center
	d.st.Rudder = center
	d.st.Aileron = center
	d.st.AxisX = center
	d.st.AxisY = center
	d.st.AxisZ = center
	d.st.AxisXRot = center
	d.st.AxisYRot = center
	d.st.AxisZRot = center
	d.st.Slider = center
	d.st.Dial = center
	d.st.Wheel = center
	d.st.AxisVX = center
	d.st.AxisVY = center
	d.st.AxisVZ = center
	d.st.AxisVBRX = center
	d.st.AxisVBRY = center
	d.st.AxisVBRZ = center
	d.st.Buttons = 0
	const hatoff = 0xffffffff
	d.st.Hats = hatoff
	d.st.HatsEx1 = hatoff
	d.st.HatsEx2 = hatoff
	d.st.HatsEx3 = hatoff
}

// Axis returns the given Axis to update
// cached values for this device, to be submitted
// by Update()
func (d *Device) Axis(n AxisName) *Axis {
	if 0 <= n && int(n) < len(d.axes) {
		return d.axes[n]
	}
	return d.invalidaxis
}

// return Button number n
func (d *Device) Button(n int) *Button {
	if 0 <= n && n < len(d.buttons) {
		return d.buttons[n]
	}
	return d.invalidbutton
}

// return Hat number n
// hats aren't yet supported by vjoy
func (d *Device) not_yet_suppoerted_Hat(n int) Hat {
	if 0 <= n && n < len(d.hats) {
		return d.hats[n]
	}
	return d.invalidhat
}

func (d *Device) Axes() []*Axis                  { return d.axes }
func (d *Device) Buttons() []*Button             { return d.buttons }
func (d *Device) not_yet_suppoerted_Hats() []Hat { return d.hats }

// Update VJD with values changed with in
// Button, Hat and Axis objects.
func (d *Device) Update() error {
	if dll.UpdateVJD(d.rid, &d.st) {
		return nil
	}
	return ErrUpdate
}

func (d *Device) init() error {
	d.st.Device = byte(d.rid)
	var err error
	switch dll.GetVJDStatus(d.rid) {
	case dll.VJD_STAT_OWN:
		return ErrDeviceAlreadyOwned
	case dll.VJD_STAT_FREE:
		// no op
	case dll.VJD_STAT_BUSY:
		err = ErrDeviceBusy
	case dll.VJD_STAT_MISS:
		err = ErrDeviceMissing
	default:
		//case VJD_STAT_UNKN:
		err = ErrDeviceUnknown
	}
	if !dll.AcquireVJD(d.rid) {
		return err
	}

	d.invalidaxis = &Axis{p: &d.noi, exists: false}
	d.invalidbutton = &Button{p: &d.noi, exists: false}
	d.invalidhat = &discreteHat{p: &d.nou, exists: false}

	d.axes = make([]*Axis, MaxAxis)
	for i := AxisName(0); i < MaxAxis; i++ {
		axn := axisNumber(i)
		a := &Axis{exists: dll.GetVJDAxisExist(d.rid, axn)}
		switch i {
		case AxisX:
			a.p = &d.st.AxisX
		case AxisY:
			a.p = &d.st.AxisY
		case AxisZ:
			a.p = &d.st.AxisZ
		case AxisRX:
			a.p = &d.st.AxisXRot
		case AxisRY:
			a.p = &d.st.AxisYRot
		case AxisRZ:
			a.p = &d.st.AxisZRot
		case Slider0:
			a.p = &d.st.Slider
		case Slider1:
			a.p = &d.st.Dial
		default:
			a.p = &d.noi // unused
		}
		if a.exists {
			dll.GetVJDAxisMin(d.rid, axn, &a.min)
			dll.GetVJDAxisMax(d.rid, axn, &a.max)
		}
		d.axes[i] = a
	}
	n := dll.GetVJDButtonNumber(d.rid)
	for i := 0; i < n; i++ {
		p, mask := d.button(i)
		if p != nil {
			d.buttons = append(d.buttons, &Button{p: p, exists: true, mask: mask})
		} else {
			d.buttons = append(d.buttons, d.invalidbutton)
		}
	}

	n = dll.GetVJDDiscPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.hat(i)
		if p != nil {
			d.hats = append(d.hats, &discreteHat{p: p, exists: true, shift: shift})
		}
	}

	n = dll.GetVJDContPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.hat(i)
		if p != nil {
			d.hats = append(d.hats, &continuousHat{p: p, exists: true, shift: shift})
		}
	}

	return nil
}

func (d *Device) button(i int) (p *int32, mask int32) {
	switch i / 32 {
	case 0:
		p = &d.st.Buttons
	case 1:
		p = &d.st.ButtonsEx1
	case 2:
		p = &d.st.ButtonsEx2
	case 3:
		p = &d.st.ButtonsEx3
	}
	mask = 1 << uint(i%32)
	return
}

func (d *Device) hat(i int) (p *uint32, shift uint) {
	shift = uint(i%2) * 16
	switch i / 2 {
	case 0:
		p = &d.st.Hats
	case 1:
		p = &d.st.HatsEx1
	case 2:
		p = &d.st.HatsEx2
	case 3:
		p = &d.st.HatsEx3
	}
	return
}
<commit_msg>fix hat support<commit_after>package vjoy

import (
	"errors"
	"github.com/tajtiattila/vjoy/dll"
)

var (
	ErrDeviceAlreadyOwned = errors.New("vJoy Device already open by this application")
	ErrDeviceBusy         = errors.New("vJoy Device is owned by another application")
	ErrDeviceMissing      = errors.New("vJoy Device is missing: either does not exist or the driver is down")
	ErrDeviceUnknown      = errors.New("Unknown vJoy Device error")
	ErrReset              = errors.New("Reset failed")
	ErrUpdate             = errors.New("UpdateVJD failed")
	ErrUnknownName        = errors.New("Unknown name (axis, button or pov)")
)

// Available check if the vjoy.dll was successfully loaded and is enabled.
// Other functions in this library will likely panic if Available returns
// false.
func Available() bool {
	err := dll.Load()
	return err == nil && dll.VJoyEnabled()
}

// Version returns the version number of the installed vJoy.
func Version() uint {
	return uint(dll.GetvJoyVersion())
}

func ProductString() string {
	return dll.GetvJoyProductString()
}

func ManufacturerString() string {
	return dll.GetvJoyManufacturerString()
}

func SerialNumberString() string {
	return dll.GetvJoySerialNumberString()
}

// ResetAll resets all VJD devices
func ResetAll() error {
	if dll.ResetAll() {
		return nil
	}
	return ErrReset
}

type AxisName uint

const (
	AxisX AxisName = iota
	AxisY
	AxisZ
	AxisRX
	AxisRY
	AxisRZ
	Slider0
	Slider1
	MaxAxis

	MaxButton = 128
)

func axisNumber(a AxisName) uint {
	switch a {
	case AxisX:
		return dll.HID_USAGE_X
	case AxisY:
		return dll.HID_USAGE_Y
	case AxisZ:
		return dll.HID_USAGE_Z
	case AxisRX:
		return dll.HID_USAGE_RX
	case AxisRY:
		return dll.HID_USAGE_RY
	case AxisRZ:
		return dll.HID_USAGE_RZ
	case Slider0:
		return dll.HID_USAGE_SL0
	case Slider1:
		return dll.HID_USAGE_SL1
	}
	return 0
}

type Axis struct {
	p        *int32
	exists   bool
	min, max int32
}

func (a *Axis) Exists() bool { return a.exists }

func (a *Axis) Setu(val int) { *(a.p) = int32(val & 0x7fff) } // 0..0x7fff
func (a *Axis) Seti(val int) { a.Setu(val - 0x4000) }         // -0x4000..0x3fff

// Setc is same as Setu, but truncates values to permitted bounds
func (a *Axis) Setc(val int) {
	switch {
	case val < 0:
		val = 0
	case 0x7fff < val:
		val = 0x7fff
	}
	a.Setu(val)
}

func (a *Axis) Setf(val float32) {
	var v int
	if val < 0 {
		val += 1
		if val < 0 {
			val = 0
		}
		v = int(val * 0x4000)
	} else {
		if val > 1 {
			val = 1
		}
		v = 0x4000 + int(val*0x3fff)
	}
	a.Setu(v)
}

func (a *Axis) Setuf(val float32) { a.Setc(int(val * 0x7fff)) } // 0..1

type Button struct {
	p      *int32
	mask   int32
	exists bool
}

func (b *Button) Exists() bool {
	return b.exists
}

func (b *Button) Set(val bool) {
	if val {
		*(b.p) |= b.mask
	} else {
		*(b.p) &= ^b.mask
	}
}

type HatState int

const (
	HatN   HatState = 0
	HatE   HatState = 1
	HatS   HatState = 2
	HatW   HatState = 3
	HatOff HatState = -1
)

type Hat interface {
	Exists() bool
	SetDiscrete(HatState)
	SetDegp(int) // set value in degree-percents (-1: off, 0-360000: direction)
}

type continuousHat struct {
	p      *uint32
	shift  uint
	exists bool
}

func (h *continuousHat) Exists() bool {
	return h.exists
}

func (h *continuousHat) SetDiscrete(s HatState) {
	mask := uint32(0xffff) << h.shift
	val := int(s)
	if val > 0 {
		val *= 9000
	}
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

func (h *continuousHat) SetDegp(val int) {
	mask := uint32(0xffff) << h.shift
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

type discreteHat struct {
	p      *uint32
	shift  uint
	exists bool
}

func (h *discreteHat) Exists() bool {
	return h.exists
}

func (h *discreteHat) SetDiscrete(val HatState) {
	mask := uint32(0xf) << h.shift
	vsh := (uint32(val) & 0xf) << h.shift
	*(h.p) = (*(h.p) & ^mask) | vsh
}

func (h *discreteHat) SetDegp(val int) {
	if val > 0 {
		val = ((val + 4500) / 9000) % 4
	}
	mask := uint32(0xffff) << h.shift
	*(h.p) = (*(h.p) & mask) | (uint32(val) << h.shift)
}

// Device represents an open vJoy device
type Device struct {
	rid           uint                  // rid Device opened with
	st            dll.JOYSTICK_POSITION // state for Update()
	noi           int32
	nou           uint32
	axes          []*Axis
	buttons       []*Button
	hats          []Hat
	invalidaxis   *Axis
	invalidbutton *Button
	invalidhat    Hat
}

// Acquire opens a Device for use in the application.
func Acquire(rid uint) (*Device, error) {
	d := &Device{rid: rid}
	err := d.init()
	if err != nil {
		return nil, err
	}
	d.Reset()
	d.Update()
	return d, nil
}

// Relinquish closes an acquired device
func (d *Device) Relinquish() {
	dll.RelinquishVJD(d.rid)
}

// reset Device: Axes centered, Buttons and Hats off.
func (d *Device) Reset() {
	const center = 0x4000
	d.st.Throttle = center
	d.st.Rudder = center
	d.st.Aileron = center
	d.st.AxisX = center
	d.st.AxisY = center
	d.st.AxisZ = center
	d.st.AxisXRot = center
	d.st.AxisYRot = center
	d.st.AxisZRot = center
	d.st.Slider = center
	d.st.Dial = center
	d.st.Wheel = center
	d.st.AxisVX = center
	d.st.AxisVY = center
	d.st.AxisVZ = center
	d.st.AxisVBRX = center
	d.st.AxisVBRY = center
	d.st.AxisVBRZ = center
	d.st.Buttons = 0
	const hatoff = 0xffffffff
	d.st.Hats = hatoff
	d.st.HatsEx1 = hatoff
	d.st.HatsEx2 = hatoff
	d.st.HatsEx3 = hatoff
}

// Axis returns the given Axis to update
// cached values for this device, to be submitted
// by Update()
func (d *Device) Axis(n AxisName) *Axis {
	if int(n) < len(d.axes) {
		return d.axes[n]
	}
	return d.invalidaxis
}

// return Button number n
func (d *Device) Button(n uint) *Button {
	if int(n) < len(d.buttons) {
		return d.buttons[n]
	}
	return d.invalidbutton
}

// return Hat number n
// hats aren't yet supported by vjoy
func (d *Device) Hat(n int) Hat {
	if 0 <= n && n < len(d.hats) {
		return d.hats[n]
	}
	return d.invalidhat
}

func (d *Device) Axes() []*Axis      { return d.axes }
func (d *Device) Buttons() []*Button { return d.buttons }
func (d *Device) Hats() []Hat        { return d.hats }

// Update VJD with values changed with in
// Button, Hat and Axis objects.
func (d *Device) Update() error {
	if dll.UpdateVJD(d.rid, &d.st) {
		return nil
	}
	return ErrUpdate
}

func (d *Device) init() error {
	d.st.Device = byte(d.rid)
	var err error
	switch dll.GetVJDStatus(d.rid) {
	case dll.VJD_STAT_OWN:
		return ErrDeviceAlreadyOwned
	case dll.VJD_STAT_FREE:
		// no op
	case dll.VJD_STAT_BUSY:
		err = ErrDeviceBusy
	case dll.VJD_STAT_MISS:
		err = ErrDeviceMissing
	default:
		//case VJD_STAT_UNKN:
		err = ErrDeviceUnknown
	}
	if !dll.AcquireVJD(d.rid) {
		return err
	}

	d.invalidaxis = &Axis{p: &d.noi, exists: false}
	d.invalidbutton = &Button{p: &d.noi, exists: false}
	d.invalidhat = &discreteHat{p: &d.nou, exists: false}

	d.axes = make([]*Axis, MaxAxis)
	for i := AxisName(0); i < MaxAxis; i++ {
		axn := axisNumber(i)
		a := &Axis{exists: dll.GetVJDAxisExist(d.rid, axn)}
		switch i {
		case AxisX:
			a.p = &d.st.AxisX
		case AxisY:
			a.p = &d.st.AxisY
		case AxisZ:
			a.p = &d.st.AxisZ
		case AxisRX:
			a.p = &d.st.AxisXRot
		case AxisRY:
			a.p = &d.st.AxisYRot
		case AxisRZ:
			a.p = &d.st.AxisZRot
		case Slider0:
			a.p = &d.st.Slider
		case Slider1:
			a.p = &d.st.Dial
		default:
			a.p = &d.noi // unused
		}
		if a.exists {
			dll.GetVJDAxisMin(d.rid, axn, &a.min)
			dll.GetVJDAxisMax(d.rid, axn, &a.max)
		}
		d.axes[i] = a
	}
	n := dll.GetVJDButtonNumber(d.rid)
	for i := 0; i < n; i++ {
		p, mask := d.button(i)
		if p != nil {
			d.buttons = append(d.buttons, &Button{p: p, exists: true, mask: mask})
		} else {
			d.buttons = append(d.buttons, d.invalidbutton)
		}
	}

	n = dll.GetVJDDiscPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.dhat(i)
		if p != nil {
			d.hats = append(d.hats, &discreteHat{p: p, exists: true, shift: shift})
		}
	}

	n = dll.GetVJDContPovNumber(d.rid)
	for i := 0; i < n; i++ {
		p, shift := d.chat(i)
		if p != nil {
			d.hats = append(d.hats, &continuousHat{p: p, exists: true, shift: shift})
		}
	}

	return nil
}

func (d *Device) button(i int) (p *int32, mask int32) {
	switch i / 32 {
	case 0:
		p = &d.st.Buttons
	case 1:
		p = &d.st.ButtonsEx1
	case 2:
		p = &d.st.ButtonsEx2
	case 3:
		p = &d.st.ButtonsEx3
	}
	mask = 1 << uint(i%32)
	return
}

func (d *Device) dhat(i int) (p *uint32, shift uint) {
	p = &d.st.Hats
	shift = uint(i) * 4
	return
}

func (d *Device) chat(i int) (p *uint32, shift uint) {
	shift = uint(i%2) * 16
	switch i / 2 {
	case 0:
		p = &d.st.Hats
	case 1:
		p = &d.st.HatsEx1
	case 2:
		p = &d.st.HatsEx2
	case 3:
		p = &d.st.HatsEx3
	}
	return
}
<|endoftext|>


<commit_before>package transaction

import (
	// Stdlib
	"bytes"
	"encoding/binary"
	"io"
	"regexp"
	"strconv"
	"strings"

	// Vendor
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcutil/base58"
	"github.com/pkg/errors"
	"golang.org/x/crypto/ripemd160"
)

//Encoder structure for the converter
type Encoder struct {
	w io.Writer
}

//NewEncoder initializing a new converter
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

//EncodeVarint converting int64 to byte
func (encoder *Encoder) EncodeVarint(i int64) error {
	if i >= 0 {
		return encoder.EncodeUVarint(uint64(i))
	}

	b := make([]byte, binary.MaxVarintLen64)
	n := binary.PutVarint(b, i)
	return encoder.writeBytes(b[:n])
}

//EncodeUVarint converting uint64 to byte
func (encoder *Encoder) EncodeUVarint(i uint64) error {
	b := make([]byte, binary.MaxVarintLen64)
	n := binary.PutUvarint(b, i)
	return encoder.writeBytes(b[:n])
}

//EncodeNumber converting number to byte
func (encoder *Encoder) EncodeNumber(v interface{}) error {
	if err := binary.Write(encoder.w, binary.LittleEndian, v); err != nil {
		return errors.Wrapf(err, "encoder: failed to write number: %v", v)
	}
	return nil
}

//EncodeArrString converting []string to byte
func (encoder *Encoder) EncodeArrString(v []string) error {
	if err := encoder.EncodeUVarint(uint64(len(v))); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", v)
	}
	for _, val := range v {
		if err := encoder.EncodeUVarint(uint64(len(val))); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", val)
		}
		if _, err := io.Copy(encoder.w, strings.NewReader(val)); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", val)
		}
	}
	return nil
}

//Encode function that determines the input values of which converter to use
func (encoder *Encoder) Encode(v interface{}) error {
	if marshaller, ok := v.(TransactionMarshaller); ok {
		return marshaller.MarshalTransaction(encoder)
	}

	switch v := v.(type) {
	case int:
		return encoder.EncodeNumber(v)
	case int8:
		return encoder.EncodeNumber(v)
	case int16:
		return encoder.EncodeNumber(v)
	case int32:
		return encoder.EncodeNumber(v)
	case int64:
		return encoder.EncodeNumber(v)

	case uint:
		return encoder.EncodeNumber(v)
	case uint8:
		return encoder.EncodeNumber(v)
	case uint16:
		return encoder.EncodeNumber(v)
	case uint32:
		return encoder.EncodeNumber(v)
	case uint64:
		return encoder.EncodeNumber(v)

	case string:
		return encoder.EncodeString(v)
	case []byte:
		return encoder.writeBytes(v)
	default:
		return errors.Errorf("encoder: unsupported type encountered")
	}
}

//EncodeString converting string to byte
func (encoder *Encoder) EncodeString(v string) error {
	if err := encoder.EncodeUVarint(uint64(len(v))); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", v)
	}

	return encoder.writeString(v)
}

func (encoder *Encoder) writeBytes(bs []byte) error {
	if _, err := encoder.w.Write(bs); err != nil {
		return errors.Wrapf(err, "encoder: failed to write bytes: %v", bs)
	}
	return nil
}

func (encoder *Encoder) writeString(s string) error {
	if _, err := io.Copy(encoder.w, strings.NewReader(s)); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", s)
	}
	return nil
}

//EncodeBool converting bool to byte
func (encoder *Encoder) EncodeBool(b bool) error {
	if b {
		return encoder.EncodeNumber(byte(1))
	}
	return encoder.EncodeNumber(byte(0))
}

//EncodeMoney converting Asset to byte
func (encoder *Encoder) EncodeMoney(s string) error {
	r, _ := regexp.Compile(`^[0-9]+\\.?[0-9]* [A-Za-z0-9]+$`)
	if r.MatchString(s) {
		asset := strings.Split(s, " ")
		amm, errParsInt := strconv.ParseInt(strings.Replace(asset[0], ".", "", -1), 10, 64)
		if errParsInt != nil {
			return errParsInt
		}
		ind := strings.Index(asset[0], ".")
		var perc int
		if ind == -1 {
			perc = 0
		} else {
			perc = len(asset[0]) - ind - 1
		}
		if err := binary.Write(encoder.w, binary.LittleEndian, amm); err != nil {
			return errors.Wrapf(err, "encoder: failed to write number: %v", amm)
		}
		if err := binary.Write(encoder.w, binary.LittleEndian, byte(perc)); err != nil {
			return errors.Wrapf(err, "encoder: failed to write number: %v", perc)
		}

		if _, err := io.Copy(encoder.w, strings.NewReader(asset[1])); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", asset[1])
		}

		for i := byte(len(asset[1])); i < 7; i++ {
			if err := binary.Write(encoder.w, binary.LittleEndian, byte(0)); err != nil {
				return errors.Wrapf(err, "encoder: failed to write number: %v", 0)
			}
		}
		return nil
	}
	return errors.New("Expecting amount like '99.000 SYMBOL'")
}

//EncodePubKey converting PubKey to byte
func (encoder *Encoder) EncodePubKey(s string) error {
	pkn1 := strings.Join(strings.Split(s, "")[3:], "")
	b58 := base58.Decode(pkn1)
	chs := b58[len(b58)-4:]
	pkn2 := b58[:len(b58)-4]
	chHash := ripemd160.New()
	_, errHash := chHash.Write(pkn2)
	if errHash != nil {
		return errHash
	}
	nchs := chHash.Sum(nil)[:4]
	if bytes.Equal(chs, nchs) {
		if string(pkn2) == string(make([]byte, 33)) {
			return encoder.writeBytes(pkn2)
		}
		pkn3, _ := btcec.ParsePubKey(pkn2, btcec.S256())
		if _, err := encoder.w.Write(pkn3.SerializeCompressed()); err != nil {
			return errors.Wrapf(err, "encoder: failed to write bytes: %v", pkn3.SerializeCompressed())
		}
		return nil
	}
	return errors.New("Public key is incorrect")
}
<commit_msg>Update encoder.go<commit_after>package transaction

import (
	// Stdlib
	"bytes"
	"encoding/binary"
	"io"
	"regexp"
	"strconv"
	"strings"

	// Vendor
	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcutil/base58"
	"github.com/pkg/errors"
	"golang.org/x/crypto/ripemd160"
)

//Encoder structure for the converter
type Encoder struct {
	w io.Writer
}

//NewEncoder initializing a new converter
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w}
}

//EncodeVarint converting int64 to byte
func (encoder *Encoder) EncodeVarint(i int64) error {
	if i >= 0 {
		return encoder.EncodeUVarint(uint64(i))
	}

	b := make([]byte, binary.MaxVarintLen64)
	n := binary.PutVarint(b, i)
	return encoder.writeBytes(b[:n])
}

//EncodeUVarint converting uint64 to byte
func (encoder *Encoder) EncodeUVarint(i uint64) error {
	b := make([]byte, binary.MaxVarintLen64)
	n := binary.PutUvarint(b, i)
	return encoder.writeBytes(b[:n])
}

//EncodeNumber converting number to byte
func (encoder *Encoder) EncodeNumber(v interface{}) error {
	if err := binary.Write(encoder.w, binary.LittleEndian, v); err != nil {
		return errors.Wrapf(err, "encoder: failed to write number: %v", v)
	}
	return nil
}

//EncodeArrString converting []string to byte
func (encoder *Encoder) EncodeArrString(v []string) error {
	if err := encoder.EncodeUVarint(uint64(len(v))); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", v)
	}
	for _, val := range v {
		if err := encoder.EncodeUVarint(uint64(len(val))); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", val)
		}
		if _, err := io.Copy(encoder.w, strings.NewReader(val)); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", val)
		}
	}
	return nil
}

//Encode function that determines the input values of which converter to use
func (encoder *Encoder) Encode(v interface{}) error {
	if marshaller, ok := v.(TransactionMarshaller); ok {
		return marshaller.MarshalTransaction(encoder)
	}

	switch v := v.(type) {
	case int:
		return encoder.EncodeNumber(v)
	case int8:
		return encoder.EncodeNumber(v)
	case int16:
		return encoder.EncodeNumber(v)
	case int32:
		return encoder.EncodeNumber(v)
	case int64:
		return encoder.EncodeNumber(v)

	case uint:
		return encoder.EncodeNumber(v)
	case uint8:
		return encoder.EncodeNumber(v)
	case uint16:
		return encoder.EncodeNumber(v)
	case uint32:
		return encoder.EncodeNumber(v)
	case uint64:
		return encoder.EncodeNumber(v)

	case string:
		return encoder.EncodeString(v)
	case []byte:
		return encoder.writeBytes(v)
	default:
		return errors.Errorf("encoder: unsupported type encountered")
	}
}

//EncodeString converting string to byte
func (encoder *Encoder) EncodeString(v string) error {
	if err := encoder.EncodeUVarint(uint64(len(v))); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", v)
	}

	return encoder.writeString(v)
}

func (encoder *Encoder) writeBytes(bs []byte) error {
	if _, err := encoder.w.Write(bs); err != nil {
		return errors.Wrapf(err, "encoder: failed to write bytes: %v", bs)
	}
	return nil
}

func (encoder *Encoder) writeString(s string) error {
	if _, err := io.Copy(encoder.w, strings.NewReader(s)); err != nil {
		return errors.Wrapf(err, "encoder: failed to write string: %v", s)
	}
	return nil
}

//EncodeBool converting bool to byte
func (encoder *Encoder) EncodeBool(b bool) error {
	if b {
		return encoder.EncodeNumber(byte(1))
	}
	return encoder.EncodeNumber(byte(0))
}

//EncodeMoney converting Asset to byte
func (encoder *Encoder) EncodeMoney(s string) error {
	r, _ := regexp.Compile("^[0-9]+\\.?[0-9]* [A-Za-z0-9]+$")
	if r.MatchString(s) {
		asset := strings.Split(s, " ")
		amm, errParsInt := strconv.ParseInt(strings.Replace(asset[0], ".", "", -1), 10, 64)
		if errParsInt != nil {
			return errParsInt
		}
		ind := strings.Index(asset[0], ".")
		var perc int
		if ind == -1 {
			perc = 0
		} else {
			perc = len(asset[0]) - ind - 1
		}
		if err := binary.Write(encoder.w, binary.LittleEndian, amm); err != nil {
			return errors.Wrapf(err, "encoder: failed to write number: %v", amm)
		}
		if err := binary.Write(encoder.w, binary.LittleEndian, byte(perc)); err != nil {
			return errors.Wrapf(err, "encoder: failed to write number: %v", perc)
		}

		if _, err := io.Copy(encoder.w, strings.NewReader(asset[1])); err != nil {
			return errors.Wrapf(err, "encoder: failed to write string: %v", asset[1])
		}

		for i := byte(len(asset[1])); i < 7; i++ {
			if err := binary.Write(encoder.w, binary.LittleEndian, byte(0)); err != nil {
				return errors.Wrapf(err, "encoder: failed to write number: %v", 0)
			}
		}
		return nil
	}
	return errors.New("Expecting amount like '99.000 SYMBOL'")
}

//EncodePubKey converting PubKey to byte
func (encoder *Encoder) EncodePubKey(s string) error {
	pkn1 := strings.Join(strings.Split(s, "")[3:], "")
	b58 := base58.Decode(pkn1)
	chs := b58[len(b58)-4:]
	pkn2 := b58[:len(b58)-4]
	chHash := ripemd160.New()
	_, errHash := chHash.Write(pkn2)
	if errHash != nil {
		return errHash
	}
	nchs := chHash.Sum(nil)[:4]
	if bytes.Equal(chs, nchs) {
		if string(pkn2) == string(make([]byte, 33)) {
			return encoder.writeBytes(pkn2)
		}
		pkn3, _ := btcec.ParsePubKey(pkn2, btcec.S256())
		if _, err := encoder.w.Write(pkn3.SerializeCompressed()); err != nil {
			return errors.Wrapf(err, "encoder: failed to write bytes: %v", pkn3.SerializeCompressed())
		}
		return nil
	}
	return errors.New("Public key is incorrect")
}
<|endoftext|>


<commit_before>package mirror

import (
	"reflect"
)

// VisitType processes type information.
// It is called by Walk.
// - typ is:
//   - a wrapped type (if len(typ.Index) == 0)
//   - an interface method (type.Index[0] < 0; ignore first value); this is clumsy...
//   - a field of a struct
// - typeIndex is the unique index of this type in the set types enountered during a walk
// - depth counts the number of indirections used to get to this type from the root type
//
// - for a map, the key and the element types are visited
// - for a function, the input argument types and output argument types are visited
// - for an interface, all contained functions are visited
type VisitType func(typ *reflect.StructField, typeIndex, depth int) error

type typeWalker map[reflect.Type]int

func (walker typeWalker) index(t reflect.Type) (int, bool) {
	idx, known := walker[t]
	if !known {
		idx = len(walker)
		walker[t] = idx
	}
	return idx, known
}

func (walker typeWalker) walk(t *reflect.StructField, visit VisitType) error {
	if t == nil || visit == nil {
		return nil
	}
	type stackNode struct {
		field      *reflect.StructField
		currentIdx int
		depth      int
		known      bool
	}
	idx, known := walker.index(t.Type)
	stack := []stackNode{{t, idx, 0, known}}
	var node stackNode
	for lastIdx := 0; lastIdx >= 0; lastIdx = len(stack) - 1 {
		stack, node = stack[:lastIdx], stack[lastIdx]
		err := visit(node.field, node.currentIdx, node.depth)
		if err != nil {
			return err
		}
		if node.known {
			// to prevent endless loops, don't follow known types
			continue
		}
		// follow container types
		depth := node.depth + 1
		switch t := node.field.Type; t.Kind() {
		case reflect.Struct:
			fields := t.NumField()
			for i := fields - 1; i >= 0; i-- {
				// add each field from struct to stack. As this is LIFO, start with the last field.
				field := t.Field(i)
				typeIdx, known := walker.index(field.Type)
				stack = append(stack, stackNode{&field, typeIdx, depth, known})
			}
		case reflect.Ptr, reflect.Array, reflect.Slice, reflect.Chan, reflect.Map:
			// add element to stack
			field := &reflect.StructField{Type: t.Elem()}
			typeIdx, known := walker.index(field.Type)
			stack = append(stack, stackNode{field, typeIdx, depth, known})
			if t.Kind() == reflect.Map {
				// add key to stack
				field := &reflect.StructField{Type: t.Key()}
				typeIdx, known := walker.index(field.Type)
				stack = append(stack, stackNode{field, typeIdx, depth, known})
			}
		case reflect.Interface:
			for i := t.NumMethod() - 1; i >= 0; i-- {
				m := t.Method(i)
				typeIdx, known := walker.index(m.Type)
				stack = append(stack, stackNode{
					&reflect.StructField{
						Name:    m.Name,
						PkgPath: m.PkgPath,
						Type:    m.Type,
						Index:   []int{-1, m.Index},
					},
					typeIdx,
					depth,
					known,
				})
			}
		case reflect.Func:
			for i := t.NumOut() - 1; i >= 0; i-- {
				r := t.Out(i)
				typeIdx, known := walker.index(r)
				stack = append(stack, stackNode{
					&reflect.StructField{Type: r},
					typeIdx,
					depth,
					known,
				})
			}
			for i := t.NumIn() - 1; i >= 0; i-- {
				a := t.In(i)
				typeIdx, known := walker.index(a)
				stack = append(stack, stackNode{
					&reflect.StructField{Type: a},
					typeIdx,
					depth,
					known,
				})
			}
		}
	}
	return nil
}

// Walk will call visit on t and each type in t.
// It will follow struct fields, pointers, arrays, slices, maps and chans
// and call visit on each element.
// Walk will only follow into types at their very first occurence during this walk.
func Walk(t reflect.Type, visit VisitType) error {
	walker := make(typeWalker)
	return walker.walk(&reflect.StructField{Type: t}, visit)
}
<commit_msg>slightly better variable names<commit_after>package mirror

import (
	"reflect"
)

// VisitType processes type information.
// It is called by Walk.
// - typ is:
//   - a wrapped type (if len(typ.Index) == 0)
//   - an interface method (type.Index[0] < 0; ignore first value); this is clumsy...
//   - a field of a struct
// - typeIndex is the unique index of this type in the set types enountered during a walk
// - depth counts the number of indirections used to get to this type from the root type
//
// - for a map, the key and the element types are visited
// - for a function, the input argument types and output argument types are visited
// - for an interface, all contained functions are visited
type VisitType func(typ *reflect.StructField, typeIndex, depth int) error

type typeWalker map[reflect.Type]int

func (walker typeWalker) index(t reflect.Type) (int, bool) {
	idx, known := walker[t]
	if !known {
		idx = len(walker)
		walker[t] = idx
	}
	return idx, known
}

func (walker typeWalker) walk(t *reflect.StructField, visit VisitType) error {
	if t == nil || visit == nil {
		return nil
	}
	type stackNode struct {
		field      *reflect.StructField
		currentIdx int
		depth      int
		known      bool
	}
	idx, known := walker.index(t.Type)
	stack := []stackNode{{t, idx, 0, known}}
	var node stackNode
	for lastIdx := 0; lastIdx >= 0; lastIdx = len(stack) - 1 {
		stack, node = stack[:lastIdx], stack[lastIdx]
		err := visit(node.field, node.currentIdx, node.depth)
		if err != nil {
			return err
		}
		if node.known {
			// to prevent endless loops, don't follow known types
			continue
		}
		// follow container types
		depth := node.depth + 1
		switch t := node.field.Type; t.Kind() {
		case reflect.Struct:
			fields := t.NumField()
			for i := fields - 1; i >= 0; i-- {
				// add each field from struct to stack. As this is LIFO, start with the last field.
				field := t.Field(i)
				typeIdx, known := walker.index(field.Type)
				stack = append(stack, stackNode{&field, typeIdx, depth, known})
			}
		case reflect.Ptr, reflect.Array, reflect.Slice, reflect.Chan, reflect.Map:
			// add element to stack
			field := &reflect.StructField{Type: t.Elem()}
			typeIdx, known := walker.index(field.Type)
			stack = append(stack, stackNode{field, typeIdx, depth, known})
			if t.Kind() == reflect.Map {
				// add key to stack
				field := &reflect.StructField{Type: t.Key()}
				typeIdx, known := walker.index(field.Type)
				stack = append(stack, stackNode{field, typeIdx, depth, known})
			}
		case reflect.Interface:
			for i := t.NumMethod() - 1; i >= 0; i-- {
				m := t.Method(i)
				typeIdx, known := walker.index(m.Type)
				stack = append(stack, stackNode{
					&reflect.StructField{
						Name:    m.Name,
						PkgPath: m.PkgPath,
						Type:    m.Type,
						Index:   []int{-1, m.Index},
					},
					typeIdx,
					depth,
					known,
				})
			}
		case reflect.Func:
			for i := t.NumOut() - 1; i >= 0; i-- {
				ret := t.Out(i)
				typeIdx, known := walker.index(ret)
				stack = append(stack, stackNode{
					&reflect.StructField{Type: ret},
					typeIdx,
					depth,
					known,
				})
			}
			for i := t.NumIn() - 1; i >= 0; i-- {
				arg := t.In(i)
				typeIdx, known := walker.index(arg)
				stack = append(stack, stackNode{
					&reflect.StructField{Type: arg},
					typeIdx,
					depth,
					known,
				})
			}
		}
	}
	return nil
}

// Walk will call visit on t and each type in t.
// It will follow struct fields, pointers, arrays, slices, maps and chans
// and call visit on each element.
// Walk will only follow into types at their very first occurence during this walk.
func Walk(t reflect.Type, visit VisitType) error {
	walker := make(typeWalker)
	return walker.walk(&reflect.StructField{Type: t}, visit)
}
<|endoftext|>


<commit_before>package cloudinit

import (
	"encoding/base64"
	"fmt"
	"launchpad.net/goyaml"
	"launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/upstart"
	"path"
	"strings"
)

// TODO(dfc) duplicated from environs/ec2

const zkPort = 37017

var zkPortSuffix = fmt.Sprintf(":%d", zkPort)

// MachineConfig represents initialization information for a new juju machine.
// Creation of cloudinit data from this struct is largely provider-independent,
// but we'll keep it internal until we need to factor it out.
type MachineConfig struct {
	// Provisioner specifies whether the new machine will run a provisioning agent.
	Provisioner bool

	// StateServer specifies whether the new machine will run a ZooKeeper
	// or MongoDB instance.
	StateServer bool

	// InstanceIdAccessor holds bash code that evaluates to the current instance id.
	InstanceIdAccessor string

	// ProviderType identifies the provider type so the host
	// knows which kind of provider to use.
	ProviderType string

	// StateInfo holds the means for the new instance to communicate with the
	// juju state. Unless the new machine is running a state server (StateServer is
	// set), there must be at least one state server address supplied.
	StateInfo *state.Info

	// Tools is juju tools to be used on the new machine.
	Tools *state.Tools

	// DataDir holds the directory that juju state will be put in the new
	// machine.
	DataDir string

	// MachineId identifies the new machine. It must be non-negative.
	MachineId int

	// AuthorizedKeys specifies the keys that are allowed to
	// connect to the machine (see cloudinit.SSHAddAuthorizedKeys)
	// If no keys are supplied, there can be no ssh access to the node.
	// On a bootstrap machine, that is fatal. On other
	// machines it will mean that the ssh, scp and debug-hooks
	// commands cannot work.
	AuthorizedKeys string

	// Config holds the initial environment configuration.
	Config *config.Config
}

type requiresError string

func (e requiresError) Error() string {
	return "invalid machine configuration: missing " + string(e)
}

func addScripts(c *cloudinit.Config, scripts ...string) {
	for _, s := range scripts {
		c.AddRunCmd(s)
	}
}

func base64yaml(m *config.Config) string {
	data, err := goyaml.Marshal(m.AllAttrs())
	if err != nil {
		// can't happen, these values have been validated a number of times
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(data)
}

func New(cfg *MachineConfig) (*cloudinit.Config, error) {
	if err := verifyConfig(cfg); err != nil {
		return nil, err
	}
	c := cloudinit.New()

	c.AddSSHAuthorizedKeys(cfg.AuthorizedKeys)
	c.AddPackage("git")
	if cfg.StateServer {
	}

	addScripts(c,
		fmt.Sprintf("sudo mkdir -p %s", cfg.DataDir),
		"sudo mkdir -p /var/log/juju")

	// Make a directory for the tools to live in, then fetch the
	// tools and unarchive them into it.
	addScripts(c,
		"bin="+shquote(cfg.jujuTools()),
		"mkdir -p $bin",
		fmt.Sprintf("wget -O - %s | tar xz -C $bin", shquote(cfg.Tools.URL)),
		fmt.Sprintf("echo -n %s > $bin/downloaded-url.txt", shquote(cfg.Tools.URL)),
	)

	debugFlag := ""
	// TODO: disable debug mode by default when the system is stable.
	if true || log.Debug {
		debugFlag = " --debug"
	}

	if cfg.StateServer {
		// TODO The public bucket must come from the environment configuration.
		b := cfg.Tools.Binary
		url := fmt.Sprintf("http://juju-dist.s3.amazonaws.com/tools/mongo-2.2.0-%s-%s.tgz", b.Series, b.Arch)
		addScripts(c,
			"mkdir -p /opt",
			fmt.Sprintf("wget -O - %s | tar xz -C /opt", shquote(url)),
			cfg.jujuTools()+"/jujud bootstrap-state"+
				" --instance-id "+cfg.InstanceIdAccessor+
				" --env-config "+shquote(base64yaml(cfg.Config))+
				" --state-servers localhost"+zkPortSuffix+
				debugFlag,
		)
		if err := addMongoToBoot(c); err != nil {
			return nil, err
		}
		addScripts(c,
			cfg.jujuTools()+"/jujud bootstrap-state"+
				" --instance-id "+cfg.InstanceIdAccessor+
				" --env-config "+shquote(base64yaml(cfg.Config))+
				" --state-servers localhost"+zkPortSuffix+
				debugFlag,
		)
	}

	if err := addAgentToBoot(c, cfg, "machine", fmt.Sprintf("--machine-id %d "+debugFlag, cfg.MachineId)); err != nil {
		return nil, err
	}
	if cfg.Provisioner {
		if err := addAgentToBoot(c, cfg, "provisioning", debugFlag); err != nil {
			return nil, err
		}
	}

	// general options
	c.SetAptUpgrade(true)
	c.SetAptUpdate(true)
	c.SetOutput(cloudinit.OutAll, "| tee -a /var/log/cloud-init-output.log", "")
	return c, nil
}

func addAgentToBoot(c *cloudinit.Config, cfg *MachineConfig, name, args string) error {
	// Make the agent run via a symbolic link to the actual tools
	// directory, so it can upgrade itself without needing to change
	// the upstart script.
	toolsDir := environs.AgentToolsDir(cfg.DataDir, name)
	// TODO(dfc) ln -nfs, so it doesn't fail if for some reason that the target already exists
	addScripts(c, fmt.Sprintf("ln -s %v %s", cfg.Tools.Binary, toolsDir))
	svc := upstart.NewService("jujud-" + name)
	cmd := fmt.Sprintf(
		"%s/jujud %s"+
			" --state-servers '%s'"+
			" --log-file /var/log/juju/%s-agent.log"+
			" --data-dir '%s'"+
			" %s",
		toolsDir, name,
		cfg.zookeeperHostAddrs(),
		name,
		cfg.DataDir,
		args,
	)
	conf := &upstart.Conf{
		Service: *svc,
		Desc:    fmt.Sprintf("juju %s agent", name),
		Cmd:     cmd,
	}
	cmds, err := conf.InstallCommands()
	if err != nil {
		return fmt.Errorf("cannot make cloud-init upstart script for the %s agent: %v", name, err)
	}
	addScripts(c, cmds...)
	return nil
}

func addMongoToBoot(c *cloudinit.Config) error {
	addScripts(c, fmt.Sprintf("mkdir -p /var/lib/juju/db"))
	svc := upstart.NewService("juju-db")
	conf := &upstart.Conf{
		Service: *svc,
		Desc:    "juju state database",
		Cmd:     "/opt/mongo/bin/mongod --port 37017 --bind_ip 0.0.0.0 --dbpath=/var/lib/juju/db",
	}
	cmds, err := conf.InstallCommands()
	if err != nil {
		return fmt.Errorf("cannot make cloud-init upstart script for the state database: %v", err)
	}
	addScripts(c, cmds...)
	return nil
}

// versionDir converts a tools URL into a name
// to use as a directory for storing the tools executables in
// by using the last element stripped of its extension.
func versionDir(toolsURL string) string {
	name := path.Base(toolsURL)
	ext := path.Ext(name)
	return name[:len(name)-len(ext)]
}

func (cfg *MachineConfig) jujuTools() string {
	return environs.ToolsDir(cfg.DataDir, cfg.Tools.Binary)
}

func (cfg *MachineConfig) zookeeperHostAddrs() string {
	var hosts []string
	if cfg.StateServer {
		hosts = append(hosts, "localhost"+zkPortSuffix)
	}
	if cfg.StateInfo != nil {
		hosts = append(hosts, cfg.StateInfo.Addrs...)
	}
	return strings.Join(hosts, ",")
}

// shquote quotes s so that when read by bash, no metacharacters
// within s will be interpreted as such.
func shquote(s string) string {
	// single-quote becomes single-quote, double-quote, single-quote, double-quote, single-quote
	return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'`
}

func verifyConfig(cfg *MachineConfig) error {
	if cfg.MachineId < 0 {
		return fmt.Errorf("invalid machine configuration: negative machine id")
	}
	if cfg.ProviderType == "" {
		return requiresError("provider type")
	}
	if cfg.DataDir == "" {
		return requiresError("var directory")
	}
	if cfg.Tools == nil {
		return requiresError("tools")
	}
	if cfg.Tools.URL == "" {
		return requiresError("tools URL")
	}
	if cfg.StateServer {
		if cfg.InstanceIdAccessor == "" {
			return requiresError("instance id accessor")
		}
		if cfg.Config == nil {
			return requiresError("environment configuration")
		}
	} else {
		if cfg.StateInfo == nil || len(cfg.StateInfo.Addrs) == 0 {
			return requiresError("zookeeper hosts")
		}
	}
	return nil
}
<commit_msg>Removed empty block.<commit_after>package cloudinit

import (
	"encoding/base64"
	"fmt"
	"launchpad.net/goyaml"
	"launchpad.net/juju-core/cloudinit"
	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/state"
	"launchpad.net/juju-core/upstart"
	"path"
	"strings"
)

// TODO(dfc) duplicated from environs/ec2

const zkPort = 37017

var zkPortSuffix = fmt.Sprintf(":%d", zkPort)

// MachineConfig represents initialization information for a new juju machine.
// Creation of cloudinit data from this struct is largely provider-independent,
// but we'll keep it internal until we need to factor it out.
type MachineConfig struct {
	// Provisioner specifies whether the new machine will run a provisioning agent.
	Provisioner bool

	// StateServer specifies whether the new machine will run a ZooKeeper
	// or MongoDB instance.
	StateServer bool

	// InstanceIdAccessor holds bash code that evaluates to the current instance id.
	InstanceIdAccessor string

	// ProviderType identifies the provider type so the host
	// knows which kind of provider to use.
	ProviderType string

	// StateInfo holds the means for the new instance to communicate with the
	// juju state. Unless the new machine is running a state server (StateServer is
	// set), there must be at least one state server address supplied.
	StateInfo *state.Info

	// Tools is juju tools to be used on the new machine.
	Tools *state.Tools

	// DataDir holds the directory that juju state will be put in the new
	// machine.
	DataDir string

	// MachineId identifies the new machine. It must be non-negative.
	MachineId int

	// AuthorizedKeys specifies the keys that are allowed to
	// connect to the machine (see cloudinit.SSHAddAuthorizedKeys)
	// If no keys are supplied, there can be no ssh access to the node.
	// On a bootstrap machine, that is fatal. On other
	// machines it will mean that the ssh, scp and debug-hooks
	// commands cannot work.
	AuthorizedKeys string

	// Config holds the initial environment configuration.
	Config *config.Config
}

type requiresError string

func (e requiresError) Error() string {
	return "invalid machine configuration: missing " + string(e)
}

func addScripts(c *cloudinit.Config, scripts ...string) {
	for _, s := range scripts {
		c.AddRunCmd(s)
	}
}

func base64yaml(m *config.Config) string {
	data, err := goyaml.Marshal(m.AllAttrs())
	if err != nil {
		// can't happen, these values have been validated a number of times
		panic(err)
	}
	return base64.StdEncoding.EncodeToString(data)
}

func New(cfg *MachineConfig) (*cloudinit.Config, error) {
	if err := verifyConfig(cfg); err != nil {
		return nil, err
	}
	c := cloudinit.New()

	c.AddSSHAuthorizedKeys(cfg.AuthorizedKeys)
	c.AddPackage("git")

	addScripts(c,
		fmt.Sprintf("sudo mkdir -p %s", cfg.DataDir),
		"sudo mkdir -p /var/log/juju")

	// Make a directory for the tools to live in, then fetch the
	// tools and unarchive them into it.
	addScripts(c,
		"bin="+shquote(cfg.jujuTools()),
		"mkdir -p $bin",
		fmt.Sprintf("wget -O - %s | tar xz -C $bin", shquote(cfg.Tools.URL)),
		fmt.Sprintf("echo -n %s > $bin/downloaded-url.txt", shquote(cfg.Tools.URL)),
	)

	debugFlag := ""
	// TODO: disable debug mode by default when the system is stable.
	if true || log.Debug {
		debugFlag = " --debug"
	}

	if cfg.StateServer {
		// TODO The public bucket must come from the environment configuration.
		b := cfg.Tools.Binary
		url := fmt.Sprintf("http://juju-dist.s3.amazonaws.com/tools/mongo-2.2.0-%s-%s.tgz", b.Series, b.Arch)
		addScripts(c,
			"mkdir -p /opt",
			fmt.Sprintf("wget -O - %s | tar xz -C /opt", shquote(url)),
			cfg.jujuTools()+"/jujud bootstrap-state"+
				" --instance-id "+cfg.InstanceIdAccessor+
				" --env-config "+shquote(base64yaml(cfg.Config))+
				" --state-servers localhost"+zkPortSuffix+
				debugFlag,
		)
		if err := addMongoToBoot(c); err != nil {
			return nil, err
		}
		addScripts(c,
			cfg.jujuTools()+"/jujud bootstrap-state"+
				" --instance-id "+cfg.InstanceIdAccessor+
				" --env-config "+shquote(base64yaml(cfg.Config))+
				" --state-servers localhost"+zkPortSuffix+
				debugFlag,
		)
	}

	if err := addAgentToBoot(c, cfg, "machine", fmt.Sprintf("--machine-id %d "+debugFlag, cfg.MachineId)); err != nil {
		return nil, err
	}
	if cfg.Provisioner {
		if err := addAgentToBoot(c, cfg, "provisioning", debugFlag); err != nil {
			return nil, err
		}
	}

	// general options
	c.SetAptUpgrade(true)
	c.SetAptUpdate(true)
	c.SetOutput(cloudinit.OutAll, "| tee -a /var/log/cloud-init-output.log", "")
	return c, nil
}

func addAgentToBoot(c *cloudinit.Config, cfg *MachineConfig, name, args string) error {
	// Make the agent run via a symbolic link to the actual tools
	// directory, so it can upgrade itself without needing to change
	// the upstart script.
	toolsDir := environs.AgentToolsDir(cfg.DataDir, name)
	// TODO(dfc) ln -nfs, so it doesn't fail if for some reason that the target already exists
	addScripts(c, fmt.Sprintf("ln -s %v %s", cfg.Tools.Binary, toolsDir))
	svc := upstart.NewService("jujud-" + name)
	cmd := fmt.Sprintf(
		"%s/jujud %s"+
			" --state-servers '%s'"+
			" --log-file /var/log/juju/%s-agent.log"+
			" --data-dir '%s'"+
			" %s",
		toolsDir, name,
		cfg.zookeeperHostAddrs(),
		name,
		cfg.DataDir,
		args,
	)
	conf := &upstart.Conf{
		Service: *svc,
		Desc:    fmt.Sprintf("juju %s agent", name),
		Cmd:     cmd,
	}
	cmds, err := conf.InstallCommands()
	if err != nil {
		return fmt.Errorf("cannot make cloud-init upstart script for the %s agent: %v", name, err)
	}
	addScripts(c, cmds...)
	return nil
}

func addMongoToBoot(c *cloudinit.Config) error {
	addScripts(c, fmt.Sprintf("mkdir -p /var/lib/juju/db"))
	svc := upstart.NewService("juju-db")
	conf := &upstart.Conf{
		Service: *svc,
		Desc:    "juju state database",
		Cmd:     "/opt/mongo/bin/mongod --port 37017 --bind_ip 0.0.0.0 --dbpath=/var/lib/juju/db",
	}
	cmds, err := conf.InstallCommands()
	if err != nil {
		return fmt.Errorf("cannot make cloud-init upstart script for the state database: %v", err)
	}
	addScripts(c, cmds...)
	return nil
}

// versionDir converts a tools URL into a name
// to use as a directory for storing the tools executables in
// by using the last element stripped of its extension.
func versionDir(toolsURL string) string {
	name := path.Base(toolsURL)
	ext := path.Ext(name)
	return name[:len(name)-len(ext)]
}

func (cfg *MachineConfig) jujuTools() string {
	return environs.ToolsDir(cfg.DataDir, cfg.Tools.Binary)
}

func (cfg *MachineConfig) zookeeperHostAddrs() string {
	var hosts []string
	if cfg.StateServer {
		hosts = append(hosts, "localhost"+zkPortSuffix)
	}
	if cfg.StateInfo != nil {
		hosts = append(hosts, cfg.StateInfo.Addrs...)
	}
	return strings.Join(hosts, ",")
}

// shquote quotes s so that when read by bash, no metacharacters
// within s will be interpreted as such.
func shquote(s string) string {
	// single-quote becomes single-quote, double-quote, single-quote, double-quote, single-quote
	return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'`
}

func verifyConfig(cfg *MachineConfig) error {
	if cfg.MachineId < 0 {
		return fmt.Errorf("invalid machine configuration: negative machine id")
	}
	if cfg.ProviderType == "" {
		return requiresError("provider type")
	}
	if cfg.DataDir == "" {
		return requiresError("var directory")
	}
	if cfg.Tools == nil {
		return requiresError("tools")
	}
	if cfg.Tools.URL == "" {
		return requiresError("tools URL")
	}
	if cfg.StateServer {
		if cfg.InstanceIdAccessor == "" {
			return requiresError("instance id accessor")
		}
		if cfg.Config == nil {
			return requiresError("environment configuration")
		}
	} else {
		if cfg.StateInfo == nil || len(cfg.StateInfo.Addrs) == 0 {
			return requiresError("zookeeper hosts")
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package wini

import (
	"bytes"
	"errors"
	"io/ioutil"
	//"fmt"
	"log"
)

// Suppress error if they are not otherwise used.
var _ = log.Printf

type Kvmap map[string]string
type SectionMap map[string]Kvmap

type INI struct {
	sections SectionMap
	linesep  string
	kvsep    string
}

func New() *INI {
	ini := &INI{
		sections: make(SectionMap),
		linesep:  "\n",
		kvsep:    "=",
	}
	return ini
}

// ParseFile reads the INI file named by filename and parse the contents to store the data in the INI
// A successful call returns err == nil
func (ini *INI) ParseFile(filename string) error {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	return ini.parseINI(contents, "\n", "=")
}

// Parse parse the data to store the data in the INI
// A successful call returns err == nil
func (ini *INI) Parse(data []byte, linesep, kvsep string) error {
	return ini.parseINI(data, linesep, kvsep)
}

// Get looks up a value for a key in the default section
// and returns that value, along with a boolean result similar to a map lookup.
func (i INI) Get(key string) (value string, ok bool) {
	return i.SectionGet("", key)
}

// Get looks up a value for a key in a section
// and returns that value, along with a boolean result similar to a map lookup.
func (i INI) SectionGet(section, key string) (value string, ok bool) {
	if s := i.sections[section]; s != nil {
		value, ok = (s)[key]
	}
	return
}

func (i INI) GetKvmap(section string) (kvmap Kvmap, ok bool) {
	kvmap, ok = i.sections[section]
	return kvmap, ok
}

//////////////////////////////////////////////////////////////////////////

func (ini *INI) parseINI(data []byte, linesep, kvsep string) error {
	ini.linesep = linesep
	ini.kvsep = kvsep

	// Insert the default section
	var section string
	kvmap := make(Kvmap)
	ini.sections[section] = kvmap

	lines := bytes.Split(data, []byte(linesep))
	for _, line := range lines {
		line = bytes.TrimSpace(line)
		size := len(line)
		if size == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if line[0] == '[' && line[size-1] == ']' {
			// Try to parse INI-Section
			section = string(line[1 : size-1])
			//log.Printf("Got a sction [%v]\n", section)
			kvmap = make(Kvmap)
			ini.sections[section] = kvmap
			continue
		}

		pos := bytes.Index(line, []byte(kvsep))
		if pos < 0 {
			// ERROR happened when passing
			err := errors.New("Came accross an error : " + string(line) + " is NOT a valid key/value pair")
			return err
		}

		k := bytes.TrimSpace(line[0:pos])
		v := bytes.TrimSpace(line[pos+len(kvsep):])
		kvmap[string(k)] = string(v)
		//log.Printf("Got a key/value pair [%v/%v] for section [%v]\n", string(k), string(v), section)
	}
	return nil
}
<commit_msg>code format. extract some const the variables<commit_after>package wini

import (
	"bytes"
	"errors"
	"io/ioutil"
	"log"
)

// Suppress error if they are not otherwise used.
var _ = log.Printf

type Kvmap map[string]string
type SectionMap map[string]Kvmap

const (
	DefaultSection           = ""
	DefaultLineSeperator     = "\n"
	DefaultKeyValueSeperator = "="
)

type INI struct {
	sections SectionMap
	linesep  string
	kvsep    string
}

func New() *INI {
	ini := &INI{
		sections: make(SectionMap),
		linesep:  DefaultLineSeperator,
		kvsep:    DefaultKeyValueSeperator,
	}
	return ini
}

// ParseFile reads the INI file named by filename and parse the contents to store the data in the INI
// A successful call returns err == nil
func (ini *INI) ParseFile(filename string) error {
	contents, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}

	return ini.parseINI(contents, DefaultLineSeperator, DefaultKeyValueSeperator)
}

// Parse parse the data to store the data in the INI
// A successful call returns err == nil
func (ini *INI) Parse(data []byte, linesep, kvsep string) error {
	return ini.parseINI(data, linesep, kvsep)
}

// Get looks up a value for a key in the default section
// and returns that value, along with a boolean result similar to a map lookup.
func (ini *INI) Get(key string) (value string, ok bool) {

	return ini.SectionGet(DefaultSection, key)
}

// Get looks up a value for a key in a section
// and returns that value, along with a boolean result similar to a map lookup.
func (ini *INI) SectionGet(section, key string) (value string, ok bool) {
	if s := ini.sections[section]; s != nil {
		value, ok = s[key]
	}
	return
}

func (ini *INI) GetKvmap(section string) (kvmap Kvmap, ok bool) {
	kvmap, ok = ini.sections[section]
	return kvmap, ok
}

//////////////////////////////////////////////////////////////////////////

func (ini *INI) parseINI(data []byte, linesep, kvsep string) error {
	ini.linesep = linesep
	ini.kvsep = kvsep

	// Insert the default section
	var section string
	kvmap := make(Kvmap)
	ini.sections[section] = kvmap

	lines := bytes.Split(data, []byte(linesep))
	for _, line := range lines {
		line = bytes.TrimSpace(line)
		size := len(line)
		if size == 0 {
			// Skip blank lines
			continue
		}
		if line[0] == ';' || line[0] == '#' {
			// Skip comments
			continue
		}
		if line[0] == '[' && line[size-1] == ']' {
			// Parse INI-Section
			section = string(line[1 : size-1])
			kvmap = make(Kvmap)
			ini.sections[section] = kvmap
			continue
		}

		pos := bytes.Index(line, []byte(kvsep))
		if pos < 0 {
			// ERROR happened when passing
			err := errors.New("Came accross an error : " + string(line) + " is NOT a valid key/value pair")
			return err
		}

		k := bytes.TrimSpace(line[0:pos])
		v := bytes.TrimSpace(line[pos+len(kvsep):])
		kvmap[string(k)] = string(v)
	}
	return nil
}
<|endoftext|>


<commit_before>package linenoise

// -windows

// #include <stdlib.h>
// #include "linenoise.h"
// #include "linenoiseCompletionCallbackHook.h"
import "C"

import (
	"errors"
	"unsafe"
)

// KillSignalError is returned returned by Line() when a user quits from prompt.
// This occurs when the user enters ctrl+C or ctrl+D.
var KillSignalError = errors.New("prompt was quited with a killsignal")

func init() {
	C.linenoiseSetupCompletionCallbackHook()
}

// Line displays given string and returns line from user input.
func Line(prompt string) (string, error) { // char *linenoise(const char *prompt);
	promptCString := C.CString(prompt)
	resultCString := C.linenoise(promptCString)
	C.free(unsafe.Pointer(promptCString))
	defer C.free(unsafe.Pointer(resultCString))

	if resultCString == nil {
		return "", KillSignalError
	}

	result := C.GoString(resultCString)

	return result, nil
}

// AddHistory adds a line to history. Returns non-nil error on fail.
func AddHistory(line string) error { // int linenoiseHistoryAdd(const char *line);
	lineCString := C.CString(line)
	res := C.linenoiseHistoryAdd(lineCString)
	C.free(unsafe.Pointer(lineCString))
	if res != 1 {
		return errors.New("Could not add line to history.")
	}
	return nil
}

// SetHistoryCapacity changes the maximum length of history. Returns non-nil error on fail.
func SetHistoryCapacity(capacity int) error { // int linenoiseHistorySetMaxLen(int len);
	res := C.linenoiseHistorySetMaxLen(C.int(capacity))
	if res != 1 {
		return errors.New("Could not set history max len.")
	}
	return nil
}

// SaveHistory saves from file with given filename. Returns non-nil error on fail.
func SaveHistory(filename string) error { // int linenoiseHistorySave(char *filename);
	filenameCString := C.CString(filename)
	res := C.linenoiseHistorySave(filenameCString)
	C.free(unsafe.Pointer(filenameCString))
	if res != 0 {
		return errors.New("Could not save history to file.")
	}
	return nil
}

// LoadHistory loads from file with given filename. Returns non-nil error on fail.
func LoadHistory(filename string) error { // int linenoiseHistoryLoad(char *filename);
	filenameCString := C.CString(filename)
	res := C.linenoiseHistoryLoad(filenameCString)
	C.free(unsafe.Pointer(filenameCString))
	if res != 0 {
		return errors.New("Could not load history from file.")
	}
	return nil
}

// Clear clears the screen.
func Clear() { // void linenoiseClearScreen(void);
	C.linenoiseClearScreen()
}

// SetMultiline sets linenoise to multiline or single line.
// In multiline mode the user input will be wrapped to a new line when the length exceeds the amount of available rows in the terminal.
func SetMultiline(ml bool) { // void linenoiseSetMultiLine(int ml);
	if ml {
		C.linenoiseSetMultiLine(1)
	} else {
		C.linenoiseSetMultiLine(0)
	}
}

// CompletionHandler provides possible completions for given input
type CompletionHandler func(input string) []string

// DefaultCompletionHandler simply returns an empty slice.
var DefaultCompletionHandler = func(input string) []string {
	return make([]string, 0)
}

var complHandler = DefaultCompletionHandler

// SetCompletionHandler sets the CompletionHandler to be used for completion
func SetCompletionHandler(c CompletionHandler) {
	complHandler = c
}

// typedef struct linenoiseCompletions {
//   size_t len;
//   char **cvec;
// } linenoiseCompletions;
// typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
// void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
// void linenoiseAddCompletion(linenoiseCompletions *, char *);

//export linenoiseGoCompletionCallbackHook
func linenoiseGoCompletionCallbackHook(input *C.char, completions *C.linenoiseCompletions) {
	completionsSlice := complHandler(C.GoString(input))

	completionsLen := len(completionsSlice)
	completions.len = C.size_t(completionsLen)

	if completionsLen > 0 {
		cvec := C.malloc(C.size_t(int(unsafe.Sizeof(*(**C.char)(nil))) * completionsLen))
		cvecSlice := (*(*[999999]*C.char)(cvec))[:completionsLen]

		for i, str := range completionsSlice {
			cvecSlice[i] = C.CString(str)
		}
		completions.cvec = (**C.char)(cvec)
	}
}

// void linenoisePrintKeyCodes(void);

// PrintKeyCodes puts linenoise in key codes debugging mode.
// Press keys to see scan codes. Type 'quit' at any time to exit.
// PrintKeyCodes blocks until user enters 'quit'.
func PrintKeyCodes() {
	C.linenoisePrintKeyCodes()
}
<commit_msg>Move C header comment<commit_after>package linenoise

// -windows

// #include <stdlib.h>
// #include "linenoise.h"
// #include "linenoiseCompletionCallbackHook.h"
import "C"

import (
	"errors"
	"unsafe"
)

// KillSignalError is returned returned by Line() when a user quits from prompt.
// This occurs when the user enters ctrl+C or ctrl+D.
var KillSignalError = errors.New("prompt was quited with a killsignal")

func init() {
	C.linenoiseSetupCompletionCallbackHook()
}

// Line displays given string and returns line from user input.
func Line(prompt string) (string, error) { // char *linenoise(const char *prompt);
	promptCString := C.CString(prompt)
	resultCString := C.linenoise(promptCString)
	C.free(unsafe.Pointer(promptCString))
	defer C.free(unsafe.Pointer(resultCString))

	if resultCString == nil {
		return "", KillSignalError
	}

	result := C.GoString(resultCString)

	return result, nil
}

// AddHistory adds a line to history. Returns non-nil error on fail.
func AddHistory(line string) error { // int linenoiseHistoryAdd(const char *line);
	lineCString := C.CString(line)
	res := C.linenoiseHistoryAdd(lineCString)
	C.free(unsafe.Pointer(lineCString))
	if res != 1 {
		return errors.New("Could not add line to history.")
	}
	return nil
}

// SetHistoryCapacity changes the maximum length of history. Returns non-nil error on fail.
func SetHistoryCapacity(capacity int) error { // int linenoiseHistorySetMaxLen(int len);
	res := C.linenoiseHistorySetMaxLen(C.int(capacity))
	if res != 1 {
		return errors.New("Could not set history max len.")
	}
	return nil
}

// SaveHistory saves from file with given filename. Returns non-nil error on fail.
func SaveHistory(filename string) error { // int linenoiseHistorySave(char *filename);
	filenameCString := C.CString(filename)
	res := C.linenoiseHistorySave(filenameCString)
	C.free(unsafe.Pointer(filenameCString))
	if res != 0 {
		return errors.New("Could not save history to file.")
	}
	return nil
}

// LoadHistory loads from file with given filename. Returns non-nil error on fail.
func LoadHistory(filename string) error { // int linenoiseHistoryLoad(char *filename);
	filenameCString := C.CString(filename)
	res := C.linenoiseHistoryLoad(filenameCString)
	C.free(unsafe.Pointer(filenameCString))
	if res != 0 {
		return errors.New("Could not load history from file.")
	}
	return nil
}

// Clear clears the screen.
func Clear() { // void linenoiseClearScreen(void);
	C.linenoiseClearScreen()
}

// SetMultiline sets linenoise to multiline or single line.
// In multiline mode the user input will be wrapped to a new line when the length exceeds the amount of available rows in the terminal.
func SetMultiline(ml bool) { // void linenoiseSetMultiLine(int ml);
	if ml {
		C.linenoiseSetMultiLine(1)
	} else {
		C.linenoiseSetMultiLine(0)
	}
}

// CompletionHandler provides possible completions for given input
type CompletionHandler func(input string) []string

// DefaultCompletionHandler simply returns an empty slice.
var DefaultCompletionHandler = func(input string) []string {
	return make([]string, 0)
}

var complHandler = DefaultCompletionHandler

// SetCompletionHandler sets the CompletionHandler to be used for completion
func SetCompletionHandler(c CompletionHandler) {
	complHandler = c
}

// typedef struct linenoiseCompletions {
//   size_t len;
//   char **cvec;
// } linenoiseCompletions;
// typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
// void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
// void linenoiseAddCompletion(linenoiseCompletions *, char *);

//export linenoiseGoCompletionCallbackHook
func linenoiseGoCompletionCallbackHook(input *C.char, completions *C.linenoiseCompletions) {
	completionsSlice := complHandler(C.GoString(input))

	completionsLen := len(completionsSlice)
	completions.len = C.size_t(completionsLen)

	if completionsLen > 0 {
		cvec := C.malloc(C.size_t(int(unsafe.Sizeof(*(**C.char)(nil))) * completionsLen))
		cvecSlice := (*(*[999999]*C.char)(cvec))[:completionsLen]

		for i, str := range completionsSlice {
			cvecSlice[i] = C.CString(str)
		}
		completions.cvec = (**C.char)(cvec)
	}
}

// PrintKeyCodes puts linenoise in key codes debugging mode.
// Press keys to see scan codes. Type 'quit' at any time to exit.
// PrintKeyCodes blocks until user enters 'quit'.
func PrintKeyCodes() { // void linenoisePrintKeyCodes(void);
	C.linenoisePrintKeyCodes()
}
<|endoftext|>