<commit_before>package shared

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/shared/units"
	"github.com/lxc/lxd/shared/validate"
)

// InstanceAction indicates the type of action being performed.
type InstanceAction string

// InstanceAction types.
const (
	Stop     InstanceAction = "stop"
	Start    InstanceAction = "start"
	Restart  InstanceAction = "restart"
	Freeze   InstanceAction = "freeze"
	Unfreeze InstanceAction = "unfreeze"
)

// ConfigVolatilePrefix indicates the prefix used for volatile config keys.
const ConfigVolatilePrefix = "volatile."

// IsRootDiskDevice returns true if the given device representation is configured as root disk for
// an instance. It typically get passed a specific entry of api.Instance.Devices.
func IsRootDiskDevice(device map[string]string) bool {
	// Root disk devices also need a non-empty "pool" property, but we can't check that here
	// because this function is used with clients talking to older servers where there was no
	// concept of a storage pool, and also it is used for migrating from old to new servers.
	// The validation of the non-empty "pool" property is done inside the disk device itself.
	if device["type"] == "disk" && device["path"] == "/" && device["source"] == "" {
		return true
	}

	return false
}

// ErrNoRootDisk means there is no root disk device found.
var ErrNoRootDisk = fmt.Errorf("No root device could be found")

// GetRootDiskDevice returns the instance device that is configured as root disk.
// Returns the device name and device config map.
func GetRootDiskDevice(devices map[string]map[string]string) (string, map[string]string, error) {
	var devName string
	var dev map[string]string

	for n, d := range devices {
		if IsRootDiskDevice(d) {
			if devName != "" {
				return "", nil, fmt.Errorf("More than one root device found")
			}

			devName = n
			dev = d
		}
	}

	if devName != "" {
		return devName, dev, nil
	}

	return "", nil, ErrNoRootDisk
}

// HugePageSizeKeys is a list of known hugepage size configuration keys.
var HugePageSizeKeys = [...]string{"limits.hugepages.64KB", "limits.hugepages.1MB", "limits.hugepages.2MB", "limits.hugepages.1GB"}

// HugePageSizeSuffix contains the list of known hugepage size suffixes.
var HugePageSizeSuffix = [...]string{"64KB", "1MB", "2MB", "1GB"}

// InstanceConfigKeysAny is a map of config key to validator. (keys applying to containers AND virtual machines)
var InstanceConfigKeysAny = map[string]func(value string) error{
	"boot.autostart":             validate.Optional(validate.IsBool),
	"boot.autostart.delay":       validate.Optional(validate.IsInt64),
	"boot.autostart.priority":    validate.Optional(validate.IsInt64),
	"boot.stop.priority":         validate.Optional(validate.IsInt64),
	"boot.host_shutdown_timeout": validate.Optional(validate.IsInt64),

	"cluster.evacuate": validate.Optional(validate.IsOneOf("auto", "migrate", "stop")),

	"limits.cpu": func(value string) error {
		if value == "" {
			return nil
		}

		// Validate the character set
		match, _ := regexp.MatchString("^[-,0-9]*$", value)
		if !match {
			return fmt.Errorf("Invalid CPU limit syntax")
		}

		// Validate first character
		if strings.HasPrefix(value, "-") || strings.HasPrefix(value, ",") {
			return fmt.Errorf("CPU limit can't start with a separator")
		}

		// Validate last character
		if strings.HasSuffix(value, "-") || strings.HasSuffix(value, ",") {
			return fmt.Errorf("CPU limit can't end with a separator")
		}

		return nil
	},
	"limits.disk.priority": validate.Optional(validate.IsPriority),
	"limits.memory": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			num, err := strconv.ParseInt(strings.TrimSuffix(value, "%"), 10, 64)
			if err != nil {
				return err
			}

			if num == 0 {
				return errors.New("Memory limit can't be 0%")
			}

			return nil
		}

		num, err := units.ParseByteSizeString(value)
		if err != nil {
			return err
		}

		if num == 0 {
			return fmt.Errorf("Memory limit can't be 0")
		}

		return nil
	},
	"limits.network.priority": validate.Optional(validate.IsPriority),

	// Caller is responsible for full validation of any raw.* value.
	"raw.apparmor": validate.IsAny,

	"security.devlxd":            validate.Optional(validate.IsBool),
	"security.protection.delete": validate.Optional(validate.IsBool),

	"snapshots.schedule":         validate.Optional(validate.IsCron([]string{"@hourly", "@daily", "@midnight", "@weekly", "@monthly", "@annually", "@yearly", "@startup"})),
	"snapshots.schedule.stopped": validate.Optional(validate.IsBool),
	"snapshots.pattern":          validate.IsAny,
	"snapshots.expiry": func(value string) error {
		// Validate expression
		_, err := GetSnapshotExpiry(time.Time{}, value)
		return err
	},

	// Volatile keys.
	"volatile.apply_template":   validate.IsAny,
	"volatile.base_image":       validate.IsAny,
	"volatile.evacuate.origin":  validate.IsAny,
	"volatile.last_state.idmap": validate.IsAny,
	"volatile.last_state.power": validate.IsAny,
	"volatile.idmap.base":       validate.IsAny,
	"volatile.idmap.current":    validate.IsAny,
	"volatile.idmap.next":       validate.IsAny,
	"volatile.apply_quota":      validate.IsAny,
	"volatile.uuid":             validate.Optional(validate.IsUUID),
	"volatile.vsock_id":         validate.Optional(validate.IsInt64),
}

// InstanceConfigKeysContainer is a map of config key to validator. (keys applying to containers only)
var InstanceConfigKeysContainer = map[string]func(value string) error{
	"limits.cpu.allowance": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			// Percentage based allocation
			_, err := strconv.Atoi(strings.TrimSuffix(value, "%"))
			if err != nil {
				return err
			}

			return nil
		}

		// Time based allocation
		fields := strings.SplitN(value, "/", 2)
		if len(fields) != 2 {
			return fmt.Errorf("Invalid allowance: %s", value)
		}

		_, err := strconv.Atoi(strings.TrimSuffix(fields[0], "ms"))
		if err != nil {
			return err
		}

		_, err = strconv.Atoi(strings.TrimSuffix(fields[1], "ms"))
		if err != nil {
			return err
		}

		return nil
	},
	"limits.cpu.priority":   validate.Optional(validate.IsPriority),
	"limits.hugepages.64KB": validate.Optional(validate.IsSize),
	"limits.hugepages.1MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.2MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.1GB":  validate.Optional(validate.IsSize),
	"limits.memory.enforce": validate.Optional(validate.IsOneOf("soft", "hard")),

	"limits.memory.swap":          validate.Optional(validate.IsBool),
	"limits.memory.swap.priority": validate.Optional(validate.IsPriority),
	"limits.processes":            validate.Optional(validate.IsInt64),

	"linux.kernel_modules": validate.IsAny,

	"migration.incremental.memory":            validate.Optional(validate.IsBool),
	"migration.incremental.memory.iterations": validate.Optional(validate.IsUint32),
	"migration.incremental.memory.goal":       validate.Optional(validate.IsUint32),

	"nvidia.runtime":             validate.Optional(validate.IsBool),
	"nvidia.driver.capabilities": validate.IsAny,
	"nvidia.require.cuda":        validate.IsAny,
	"nvidia.require.driver":      validate.IsAny,

	// Caller is responsible for full validation of any raw.* value.
	"raw.idmap":   validate.IsAny,
	"raw.lxc":     validate.IsAny,
	"raw.seccomp": validate.IsAny,

	"security.devlxd.images": validate.Optional(validate.IsBool),

	"security.idmap.base":     validate.Optional(validate.IsUint32),
	"security.idmap.isolated": validate.Optional(validate.IsBool),
	"security.idmap.size":     validate.Optional(validate.IsUint32),

	"security.nesting":          validate.Optional(validate.IsBool),
	"security.privileged":       validate.Optional(validate.IsBool),
	"security.protection.shift": validate.Optional(validate.IsBool),

	"security.syscalls.allow":                   validate.IsAny,
	"security.syscalls.blacklist_default":       validate.Optional(validate.IsBool),
	"security.syscalls.blacklist_compat":        validate.Optional(validate.IsBool),
	"security.syscalls.blacklist":               validate.IsAny,
	"security.syscalls.deny_default":            validate.Optional(validate.IsBool),
	"security.syscalls.deny_compat":             validate.Optional(validate.IsBool),
	"security.syscalls.deny":                    validate.IsAny,
	"security.syscalls.intercept.bpf":           validate.Optional(validate.IsBool),
	"security.syscalls.intercept.bpf.devices":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mknod":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount.allowed": validate.IsAny,
	"security.syscalls.intercept.mount.fuse":    validate.IsAny,
	"security.syscalls.intercept.mount.shift":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.setxattr":      validate.Optional(validate.IsBool),
	"security.syscalls.whitelist":               validate.IsAny,
}

// InstanceConfigKeysVM is a map of config key to validator. (keys applying to VM only)
var InstanceConfigKeysVM = map[string]func(value string) error{
	"limits.memory.hugepages": validate.Optional(validate.IsBool),

	"migration.stateful": validate.Optional(validate.IsBool),

	// Caller is responsible for full validation of any raw.* value.
	"raw.qemu": validate.IsAny,

	"security.secureboot": validate.Optional(validate.IsBool),
}

// ConfigKeyChecker returns a function that will check whether or not
// a provide value is valid for the associate config key.  Returns an
// error if the key is not known.  The checker function only performs
// syntactic checking of the value, semantic and usage checking must
// be done by the caller.  User defined keys are always considered to
// be valid, e.g. user.* and environment.* keys.
func ConfigKeyChecker(key string, instanceType instancetype.Type) (func(value string) error, error) {
	if f, ok := InstanceConfigKeysAny[key]; ok {
		return f, nil
	}

	if instanceType == instancetype.Any || instanceType == instancetype.Container {
		if f, ok := InstanceConfigKeysContainer[key]; ok {
			return f, nil
		}
	}

	if instanceType == instancetype.Any || instanceType == instancetype.VM {
		if f, ok := InstanceConfigKeysVM[key]; ok {
			return f, nil
		}
	}

	if strings.HasPrefix(key, ConfigVolatilePrefix) {
		if strings.HasSuffix(key, ".hwaddr") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".host_name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".mtu") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".created") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".id") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".vlan") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".spoofcheck") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".apply_quota") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".ceph_rbd") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".driver") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".uuid") {
			return validate.IsAny, nil
		}
	}

	if strings.HasPrefix(key, "environment.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "user.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "image.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "limits.kernel.") &&
		(len(key) > len("limits.kernel.")) {
		return validate.IsAny, nil
	}

	return nil, fmt.Errorf("Unknown configuration key: %s", key)
}

// InstanceGetParentAndSnapshotName returns the parent instance name, snapshot name,
// and whether it actually was a snapshot name.
func InstanceGetParentAndSnapshotName(name string) (string, string, bool) {
	fields := strings.SplitN(name, SnapshotDelimiter, 2)
	if len(fields) == 1 {
		return name, "", false
	}

	return fields[0], fields[1], true
}

// InstanceIncludeWhenCopying is used to decide whether to include a config item or not when copying an instance.
// The remoteCopy argument indicates if the copy is remote (i.e between LXD nodes) as this affects the keys kept.
func InstanceIncludeWhenCopying(configKey string, remoteCopy bool) bool {
	if configKey == "volatile.base_image" {
		return true // Include volatile.base_image always as it can help optimize copies.
	}

	if configKey == "volatile.last_state.idmap" && !remoteCopy {
		return true // Include volatile.last_state.idmap when doing local copy to avoid needless remapping.
	}

	if strings.HasPrefix(configKey, ConfigVolatilePrefix) {
		return false // Exclude all other volatile keys.
	}

	return true // Keep all other keys.
}
<commit_msg>shared/instance: Add linux.sysctl.*<commit_after>package shared

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/lxc/lxd/lxd/instance/instancetype"
	"github.com/lxc/lxd/shared/units"
	"github.com/lxc/lxd/shared/validate"
)

// InstanceAction indicates the type of action being performed.
type InstanceAction string

// InstanceAction types.
const (
	Stop     InstanceAction = "stop"
	Start    InstanceAction = "start"
	Restart  InstanceAction = "restart"
	Freeze   InstanceAction = "freeze"
	Unfreeze InstanceAction = "unfreeze"
)

// ConfigVolatilePrefix indicates the prefix used for volatile config keys.
const ConfigVolatilePrefix = "volatile."

// IsRootDiskDevice returns true if the given device representation is configured as root disk for
// an instance. It typically get passed a specific entry of api.Instance.Devices.
func IsRootDiskDevice(device map[string]string) bool {
	// Root disk devices also need a non-empty "pool" property, but we can't check that here
	// because this function is used with clients talking to older servers where there was no
	// concept of a storage pool, and also it is used for migrating from old to new servers.
	// The validation of the non-empty "pool" property is done inside the disk device itself.
	if device["type"] == "disk" && device["path"] == "/" && device["source"] == "" {
		return true
	}

	return false
}

// ErrNoRootDisk means there is no root disk device found.
var ErrNoRootDisk = fmt.Errorf("No root device could be found")

// GetRootDiskDevice returns the instance device that is configured as root disk.
// Returns the device name and device config map.
func GetRootDiskDevice(devices map[string]map[string]string) (string, map[string]string, error) {
	var devName string
	var dev map[string]string

	for n, d := range devices {
		if IsRootDiskDevice(d) {
			if devName != "" {
				return "", nil, fmt.Errorf("More than one root device found")
			}

			devName = n
			dev = d
		}
	}

	if devName != "" {
		return devName, dev, nil
	}

	return "", nil, ErrNoRootDisk
}

// HugePageSizeKeys is a list of known hugepage size configuration keys.
var HugePageSizeKeys = [...]string{"limits.hugepages.64KB", "limits.hugepages.1MB", "limits.hugepages.2MB", "limits.hugepages.1GB"}

// HugePageSizeSuffix contains the list of known hugepage size suffixes.
var HugePageSizeSuffix = [...]string{"64KB", "1MB", "2MB", "1GB"}

// InstanceConfigKeysAny is a map of config key to validator. (keys applying to containers AND virtual machines)
var InstanceConfigKeysAny = map[string]func(value string) error{
	"boot.autostart":             validate.Optional(validate.IsBool),
	"boot.autostart.delay":       validate.Optional(validate.IsInt64),
	"boot.autostart.priority":    validate.Optional(validate.IsInt64),
	"boot.stop.priority":         validate.Optional(validate.IsInt64),
	"boot.host_shutdown_timeout": validate.Optional(validate.IsInt64),

	"cluster.evacuate": validate.Optional(validate.IsOneOf("auto", "migrate", "stop")),

	"limits.cpu": func(value string) error {
		if value == "" {
			return nil
		}

		// Validate the character set
		match, _ := regexp.MatchString("^[-,0-9]*$", value)
		if !match {
			return fmt.Errorf("Invalid CPU limit syntax")
		}

		// Validate first character
		if strings.HasPrefix(value, "-") || strings.HasPrefix(value, ",") {
			return fmt.Errorf("CPU limit can't start with a separator")
		}

		// Validate last character
		if strings.HasSuffix(value, "-") || strings.HasSuffix(value, ",") {
			return fmt.Errorf("CPU limit can't end with a separator")
		}

		return nil
	},
	"limits.disk.priority": validate.Optional(validate.IsPriority),
	"limits.memory": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			num, err := strconv.ParseInt(strings.TrimSuffix(value, "%"), 10, 64)
			if err != nil {
				return err
			}

			if num == 0 {
				return errors.New("Memory limit can't be 0%")
			}

			return nil
		}

		num, err := units.ParseByteSizeString(value)
		if err != nil {
			return err
		}

		if num == 0 {
			return fmt.Errorf("Memory limit can't be 0")
		}

		return nil
	},
	"limits.network.priority": validate.Optional(validate.IsPriority),

	// Caller is responsible for full validation of any raw.* value.
	"raw.apparmor": validate.IsAny,

	"security.devlxd":            validate.Optional(validate.IsBool),
	"security.protection.delete": validate.Optional(validate.IsBool),

	"snapshots.schedule":         validate.Optional(validate.IsCron([]string{"@hourly", "@daily", "@midnight", "@weekly", "@monthly", "@annually", "@yearly", "@startup"})),
	"snapshots.schedule.stopped": validate.Optional(validate.IsBool),
	"snapshots.pattern":          validate.IsAny,
	"snapshots.expiry": func(value string) error {
		// Validate expression
		_, err := GetSnapshotExpiry(time.Time{}, value)
		return err
	},

	// Volatile keys.
	"volatile.apply_template":   validate.IsAny,
	"volatile.base_image":       validate.IsAny,
	"volatile.evacuate.origin":  validate.IsAny,
	"volatile.last_state.idmap": validate.IsAny,
	"volatile.last_state.power": validate.IsAny,
	"volatile.idmap.base":       validate.IsAny,
	"volatile.idmap.current":    validate.IsAny,
	"volatile.idmap.next":       validate.IsAny,
	"volatile.apply_quota":      validate.IsAny,
	"volatile.uuid":             validate.Optional(validate.IsUUID),
	"volatile.vsock_id":         validate.Optional(validate.IsInt64),
}

// InstanceConfigKeysContainer is a map of config key to validator. (keys applying to containers only)
var InstanceConfigKeysContainer = map[string]func(value string) error{
	"limits.cpu.allowance": func(value string) error {
		if value == "" {
			return nil
		}

		if strings.HasSuffix(value, "%") {
			// Percentage based allocation
			_, err := strconv.Atoi(strings.TrimSuffix(value, "%"))
			if err != nil {
				return err
			}

			return nil
		}

		// Time based allocation
		fields := strings.SplitN(value, "/", 2)
		if len(fields) != 2 {
			return fmt.Errorf("Invalid allowance: %s", value)
		}

		_, err := strconv.Atoi(strings.TrimSuffix(fields[0], "ms"))
		if err != nil {
			return err
		}

		_, err = strconv.Atoi(strings.TrimSuffix(fields[1], "ms"))
		if err != nil {
			return err
		}

		return nil
	},
	"limits.cpu.priority":   validate.Optional(validate.IsPriority),
	"limits.hugepages.64KB": validate.Optional(validate.IsSize),
	"limits.hugepages.1MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.2MB":  validate.Optional(validate.IsSize),
	"limits.hugepages.1GB":  validate.Optional(validate.IsSize),
	"limits.memory.enforce": validate.Optional(validate.IsOneOf("soft", "hard")),

	"limits.memory.swap":          validate.Optional(validate.IsBool),
	"limits.memory.swap.priority": validate.Optional(validate.IsPriority),
	"limits.processes":            validate.Optional(validate.IsInt64),

	"linux.kernel_modules": validate.IsAny,

	"migration.incremental.memory":            validate.Optional(validate.IsBool),
	"migration.incremental.memory.iterations": validate.Optional(validate.IsUint32),
	"migration.incremental.memory.goal":       validate.Optional(validate.IsUint32),

	"nvidia.runtime":             validate.Optional(validate.IsBool),
	"nvidia.driver.capabilities": validate.IsAny,
	"nvidia.require.cuda":        validate.IsAny,
	"nvidia.require.driver":      validate.IsAny,

	// Caller is responsible for full validation of any raw.* value.
	"raw.idmap":   validate.IsAny,
	"raw.lxc":     validate.IsAny,
	"raw.seccomp": validate.IsAny,

	"security.devlxd.images": validate.Optional(validate.IsBool),

	"security.idmap.base":     validate.Optional(validate.IsUint32),
	"security.idmap.isolated": validate.Optional(validate.IsBool),
	"security.idmap.size":     validate.Optional(validate.IsUint32),

	"security.nesting":          validate.Optional(validate.IsBool),
	"security.privileged":       validate.Optional(validate.IsBool),
	"security.protection.shift": validate.Optional(validate.IsBool),

	"security.syscalls.allow":                   validate.IsAny,
	"security.syscalls.blacklist_default":       validate.Optional(validate.IsBool),
	"security.syscalls.blacklist_compat":        validate.Optional(validate.IsBool),
	"security.syscalls.blacklist":               validate.IsAny,
	"security.syscalls.deny_default":            validate.Optional(validate.IsBool),
	"security.syscalls.deny_compat":             validate.Optional(validate.IsBool),
	"security.syscalls.deny":                    validate.IsAny,
	"security.syscalls.intercept.bpf":           validate.Optional(validate.IsBool),
	"security.syscalls.intercept.bpf.devices":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mknod":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount":         validate.Optional(validate.IsBool),
	"security.syscalls.intercept.mount.allowed": validate.IsAny,
	"security.syscalls.intercept.mount.fuse":    validate.IsAny,
	"security.syscalls.intercept.mount.shift":   validate.Optional(validate.IsBool),
	"security.syscalls.intercept.setxattr":      validate.Optional(validate.IsBool),
	"security.syscalls.whitelist":               validate.IsAny,
}

// InstanceConfigKeysVM is a map of config key to validator. (keys applying to VM only)
var InstanceConfigKeysVM = map[string]func(value string) error{
	"limits.memory.hugepages": validate.Optional(validate.IsBool),

	"migration.stateful": validate.Optional(validate.IsBool),

	// Caller is responsible for full validation of any raw.* value.
	"raw.qemu": validate.IsAny,

	"security.secureboot": validate.Optional(validate.IsBool),
}

// ConfigKeyChecker returns a function that will check whether or not
// a provide value is valid for the associate config key.  Returns an
// error if the key is not known.  The checker function only performs
// syntactic checking of the value, semantic and usage checking must
// be done by the caller.  User defined keys are always considered to
// be valid, e.g. user.* and environment.* keys.
func ConfigKeyChecker(key string, instanceType instancetype.Type) (func(value string) error, error) {
	if f, ok := InstanceConfigKeysAny[key]; ok {
		return f, nil
	}

	if instanceType == instancetype.Any || instanceType == instancetype.Container {
		if f, ok := InstanceConfigKeysContainer[key]; ok {
			return f, nil
		}
	}

	if instanceType == instancetype.Any || instanceType == instancetype.VM {
		if f, ok := InstanceConfigKeysVM[key]; ok {
			return f, nil
		}
	}

	if strings.HasPrefix(key, ConfigVolatilePrefix) {
		if strings.HasSuffix(key, ".hwaddr") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".host_name") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".mtu") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".created") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".id") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".vlan") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".spoofcheck") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".apply_quota") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".ceph_rbd") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".driver") {
			return validate.IsAny, nil
		}

		if strings.HasSuffix(key, ".uuid") {
			return validate.IsAny, nil
		}
	}

	if strings.HasPrefix(key, "environment.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "user.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "image.") {
		return validate.IsAny, nil
	}

	if strings.HasPrefix(key, "limits.kernel.") &&
		(len(key) > len("limits.kernel.")) {
		return validate.IsAny, nil
	}

	if (instanceType == instancetype.Any || instanceType == instancetype.Container) &&
		strings.HasPrefix(key, "linux.sysctl.") {
		return validate.IsAny, nil
	}

	return nil, fmt.Errorf("Unknown configuration key: %s", key)
}

// InstanceGetParentAndSnapshotName returns the parent instance name, snapshot name,
// and whether it actually was a snapshot name.
func InstanceGetParentAndSnapshotName(name string) (string, string, bool) {
	fields := strings.SplitN(name, SnapshotDelimiter, 2)
	if len(fields) == 1 {
		return name, "", false
	}

	return fields[0], fields[1], true
}

// InstanceIncludeWhenCopying is used to decide whether to include a config item or not when copying an instance.
// The remoteCopy argument indicates if the copy is remote (i.e between LXD nodes) as this affects the keys kept.
func InstanceIncludeWhenCopying(configKey string, remoteCopy bool) bool {
	if configKey == "volatile.base_image" {
		return true // Include volatile.base_image always as it can help optimize copies.
	}

	if configKey == "volatile.last_state.idmap" && !remoteCopy {
		return true // Include volatile.last_state.idmap when doing local copy to avoid needless remapping.
	}

	if strings.HasPrefix(configKey, ConfigVolatilePrefix) {
		return false // Exclude all other volatile keys.
	}

	return true // Keep all other keys.
}
<|endoftext|>


<commit_before>// Package l3gd20 allows interacting with L3GD20 gyroscoping sensor.
package l3gd20

import (
	"fmt"
	"log"
	"math"
	"sync"
	"time"

	"github.com/kid0m4n/go-rpi/i2c"
)

const (
	address = 0x6B
	id      = 0xD4

	dpsToRps = 0.017453293

	whoAmI    = 0x0F
	ctrlReg1  = 0x20
	ctrlReg2  = 0x21
	ctrlReg3  = 0x22
	ctrlReg4  = 0x23
	ctrlReg5  = 0x24
	tempData  = 0x26
	statusReg = 0x27

	xlReg = 0x28
	xhReg = 0x29
	ylReg = 0x2A
	yhReg = 0x2B
	zlReg = 0x2C
	zhReg = 0x2D

	xEnabled  = 0x01
	xDisabled = 0x00
	yEnabled  = 0x02
	yDisabled = 0x00
	zEnabled  = 0x04
	zDisabled = 0x00

	powerOn   = 0x08
	powerDown = 0x00

	ctrlReg1Default  = xEnabled | yEnabled | zEnabled | powerOn
	ctrlReg1Finished = xDisabled | yDisabled | zDisabled | powerDown

	zyxAvailable = 0x08

	pollDelay = 100
)

// Range represents a L3GD20 range setting.
type Range struct {
	sensitivity float64

	value byte
}

// The three range settings supported by L3GD20.
var (
	R250DPS  = &Range{sensitivity: 0.00875, value: 0x00}
	R500DPS  = &Range{sensitivity: 0.0175, value: 0x10}
	R2000DPS = &Range{sensitivity: 0.070, value: 0x20}
)

type axis struct {
	name string

	lowReg, highReg byte

	availableMask byte
}

func (a *axis) regs() (byte, byte) {
	return a.lowReg, a.highReg
}

func (a axis) String() string {
	return a.name
}

var (
	ax = &axis{name: "X", lowReg: xlReg, highReg: xhReg, availableMask: 0x01}
	ay = &axis{name: "Y", lowReg: ylReg, highReg: yhReg, availableMask: 0x02}
	az = &axis{name: "Z", lowReg: zlReg, highReg: zhReg, availableMask: 0x04}
)

type axisCalibration struct {
	min, max, mean float64
}

func (ac axisCalibration) adjust(value float64) float64 {
	if value >= ac.min && value <= ac.max {
		return 0
	}
	return value - ac.mean
}

func (ac axisCalibration) String() string {
	return fmt.Sprintf("%v, %v, %v", ac.min, ac.max, ac.mean)
}

type Orientation struct {
	X, Y, Z float64
}

// L3GD20 represents a L3GD20 3-axis gyroscope.
type L3GD20 struct {
	Bus   i2c.Bus
	Range *Range

	Poll int

	initialized bool
	mu          sync.RWMutex

	xac, yac, zac axisCalibration

	orientations chan Orientation
	closing      chan chan struct{}

	Debug bool
}

// New creates a new L3GD20 interface. The bus variable controls
// the I2C bus used to communicate with the device.
func New(bus i2c.Bus, Range *Range) *L3GD20 {
	return &L3GD20{
		Bus:   bus,
		Range: Range,
		Poll:  pollDelay,
		Debug: false,
	}
}

type values []float64

func (vs values) min() float64 {
	value := math.MaxFloat64
	for _, v := range vs {
		value = math.Min(value, v)
	}
	return value
}

func (vs values) max() float64 {
	value := -math.MaxFloat64
	for _, v := range vs {
		value = math.Max(value, v)
	}
	return value
}

func (vs values) mean() float64 {
	sum := 0.0
	for _, v := range vs {
		sum += v
	}
	return sum / float64(len(vs))
}

func (d *L3GD20) calibrate(a *axis) (ac axisCalibration, err error) {
	if d.Debug {
		log.Printf("l3gd20: calibrating %v axis", a)
	}

	values := make(values, 0)
	for i := 0; i < 20; i++ {
	again:
		var available bool
		if available, err = d.axisStatus(a); err != nil {
			return
		}
		if !available {
			time.Sleep(100 * time.Microsecond)
			goto again
		}
		var value float64
		if value, err = d.readOrientationDelta(a); err != nil {
			return
		}
		values = append(values, value)
	}
	ac.min, ac.max, ac.mean = values.min(), values.max(), values.mean()

	if d.Debug {
		log.Printf("l3gd20: %v axis calibration (%v)", a, ac)
	}

	return
}

func (d *L3GD20) setup() (err error) {
	d.mu.RLock()
	if d.initialized {
		d.mu.RUnlock()
		return
	}
	d.mu.RUnlock()

	d.mu.Lock()
	defer d.mu.Unlock()

	d.orientations = make(chan Orientation)

	if err = d.Bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
		return
	}
	if err = d.Bus.WriteByteToReg(address, ctrlReg4, d.Range.value); err != nil {
		return
	}

	// Calibrate
	if d.xac, err = d.calibrate(ax); err != nil {
		return
	}
	if d.yac, err = d.calibrate(ay); err != nil {
		return
	}
	if d.zac, err = d.calibrate(az); err != nil {
		return
	}

	d.initialized = true

	return
}

func (d *L3GD20) axisStatus(a *axis) (available bool, err error) {
	var data byte
	if data, err = d.Bus.ReadByteFromReg(address, statusReg); err != nil {
		return
	}

	if data&zyxAvailable == 0 {
		return
	}

	available = data&a.availableMask != 0

	return
}

func (d *L3GD20) readOrientationDelta(a *axis) (value float64, err error) {
	rl, rh := a.regs()
	var l, h byte
	if l, err = d.Bus.ReadByteFromReg(address, rl); err != nil {
		return
	}
	if h, err = d.Bus.ReadByteFromReg(address, rh); err != nil {
		return
	}

	value = float64(int16(h)<<8 | int16(l))
	value *= d.Range.sensitivity

	return
}

func (d *L3GD20) calibratedOrientationDelta(a *axis) (value float64, err error) {
	if value, err = d.readOrientationDelta(a); err != nil {
		return
	}

	switch a {
	case ax:
		value = d.xac.adjust(value)
	case ay:
		value = d.yac.adjust(value)
	case az:
		value = d.zac.adjust(value)
	}

	return
}

func (d *L3GD20) measureOrientationDelta() (dx, dy, dz float64, err error) {
	if err = d.setup(); err != nil {
		return
	}

	if dx, err = d.calibratedOrientationDelta(ax); err != nil {
		return
	}
	if dy, err = d.calibratedOrientationDelta(ay); err != nil {
		return
	}
	if dz, err = d.calibratedOrientationDelta(az); err != nil {
		return
	}

	return
}

// Orientation returns the current orientation reading.
func (d *L3GD20) OrientationDelta() (dx, dy, dz float64, err error) {
	return d.measureOrientationDelta()
}

// Temperature returns the current temperature reading.
func (d *L3GD20) Temperature() (temp int, err error) {
	if err = d.setup(); err != nil {
		return
	}

	var data byte
	if data, err = d.Bus.ReadByteFromReg(address, tempData); err != nil {
		return
	}

	temp = int(int8(data))

	return
}

func (d *L3GD20) Orientations() (orientations <-chan Orientation, err error) {
	if err = d.setup(); err != nil {
		return
	}

	orientations = d.orientations

	return
}

// Start starts the data acquisition loop.
func (d *L3GD20) Start() (err error) {
	if err = d.setup(); err != nil {
		return
	}

	d.closing = make(chan chan struct{})

	go func() {
		var x, y, z float64
		var orientations chan Orientation
		oldTime := time.Now()

		timer := time.Tick(time.Duration(d.Poll) * time.Millisecond)

		for {
			select {
			case currTime := <-timer:
				dx, dy, dz, err := d.measureOrientationDelta()
				if err != nil {
					log.Printf("l3gd20: %v", err)
				} else {
					timeElapsed := currTime.Sub(oldTime)
					mult := timeElapsed.Seconds()
					x += dx * mult
					y += dy * mult
					z += dz * mult
					orientations = d.orientations
				}
				oldTime = currTime
			case orientations <- Orientation{x, y, z}:
				orientations = nil
			case waitc := <-d.closing:
				waitc <- struct{}{}
				close(d.orientations)
				return
			}

		}
	}()

	return
}

func (d *L3GD20) Stop() (err error) {
	if d.closing != nil {
		waitc := make(chan struct{})
		d.closing <- waitc
		<-waitc
	}
	if err = d.Bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Finished); err != nil {
		return
	}
	d.initialized = false
	return
}

// Close.
func (d *L3GD20) Close() (err error) {
	return d.Stop()
}
<commit_msg>l3gd20: reset the timer after reading gyro reading<commit_after>// Package l3gd20 allows interacting with L3GD20 gyroscoping sensor.
package l3gd20

import (
	"fmt"
	"log"
	"math"
	"sync"
	"time"

	"github.com/kid0m4n/go-rpi/i2c"
)

const (
	address = 0x6B
	id      = 0xD4

	dpsToRps = 0.017453293

	whoAmI    = 0x0F
	ctrlReg1  = 0x20
	ctrlReg2  = 0x21
	ctrlReg3  = 0x22
	ctrlReg4  = 0x23
	ctrlReg5  = 0x24
	tempData  = 0x26
	statusReg = 0x27

	xlReg = 0x28
	xhReg = 0x29
	ylReg = 0x2A
	yhReg = 0x2B
	zlReg = 0x2C
	zhReg = 0x2D

	xEnabled  = 0x01
	xDisabled = 0x00
	yEnabled  = 0x02
	yDisabled = 0x00
	zEnabled  = 0x04
	zDisabled = 0x00

	powerOn   = 0x08
	powerDown = 0x00

	ctrlReg1Default  = xEnabled | yEnabled | zEnabled | powerOn
	ctrlReg1Finished = xDisabled | yDisabled | zDisabled | powerDown

	zyxAvailable = 0x08

	pollDelay = 100
)

// Range represents a L3GD20 range setting.
type Range struct {
	sensitivity float64

	value byte
}

// The three range settings supported by L3GD20.
var (
	R250DPS  = &Range{sensitivity: 0.00875, value: 0x00}
	R500DPS  = &Range{sensitivity: 0.0175, value: 0x10}
	R2000DPS = &Range{sensitivity: 0.070, value: 0x20}
)

type axis struct {
	name string

	lowReg, highReg byte

	availableMask byte
}

func (a *axis) regs() (byte, byte) {
	return a.lowReg, a.highReg
}

func (a axis) String() string {
	return a.name
}

var (
	ax = &axis{name: "X", lowReg: xlReg, highReg: xhReg, availableMask: 0x01}
	ay = &axis{name: "Y", lowReg: ylReg, highReg: yhReg, availableMask: 0x02}
	az = &axis{name: "Z", lowReg: zlReg, highReg: zhReg, availableMask: 0x04}
)

type axisCalibration struct {
	min, max, mean float64
}

func (ac axisCalibration) adjust(value float64) float64 {
	if value >= ac.min && value <= ac.max {
		return 0
	}
	return value - ac.mean
}

func (ac axisCalibration) String() string {
	return fmt.Sprintf("%v, %v, %v", ac.min, ac.max, ac.mean)
}

type Orientation struct {
	X, Y, Z float64
}

// L3GD20 represents a L3GD20 3-axis gyroscope.
type L3GD20 struct {
	Bus   i2c.Bus
	Range *Range

	Poll int

	initialized bool
	mu          sync.RWMutex

	xac, yac, zac axisCalibration

	orientations chan Orientation
	closing      chan chan struct{}

	Debug bool
}

// New creates a new L3GD20 interface. The bus variable controls
// the I2C bus used to communicate with the device.
func New(bus i2c.Bus, Range *Range) *L3GD20 {
	return &L3GD20{
		Bus:   bus,
		Range: Range,
		Poll:  pollDelay,
		Debug: false,
	}
}

type values []float64

func (vs values) min() float64 {
	value := math.MaxFloat64
	for _, v := range vs {
		value = math.Min(value, v)
	}
	return value
}

func (vs values) max() float64 {
	value := -math.MaxFloat64
	for _, v := range vs {
		value = math.Max(value, v)
	}
	return value
}

func (vs values) mean() float64 {
	sum := 0.0
	for _, v := range vs {
		sum += v
	}
	return sum / float64(len(vs))
}

func (d *L3GD20) calibrate(a *axis) (ac axisCalibration, err error) {
	if d.Debug {
		log.Printf("l3gd20: calibrating %v axis", a)
	}

	values := make(values, 0)
	for i := 0; i < 20; i++ {
	again:
		var available bool
		if available, err = d.axisStatus(a); err != nil {
			return
		}
		if !available {
			time.Sleep(100 * time.Microsecond)
			goto again
		}
		var value float64
		if value, err = d.readOrientationDelta(a); err != nil {
			return
		}
		values = append(values, value)
	}
	ac.min, ac.max, ac.mean = values.min(), values.max(), values.mean()

	if d.Debug {
		log.Printf("l3gd20: %v axis calibration (%v)", a, ac)
	}

	return
}

func (d *L3GD20) setup() (err error) {
	d.mu.RLock()
	if d.initialized {
		d.mu.RUnlock()
		return
	}
	d.mu.RUnlock()

	d.mu.Lock()
	defer d.mu.Unlock()

	d.orientations = make(chan Orientation)

	if err = d.Bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Default); err != nil {
		return
	}
	if err = d.Bus.WriteByteToReg(address, ctrlReg4, d.Range.value); err != nil {
		return
	}

	// Calibrate
	if d.xac, err = d.calibrate(ax); err != nil {
		return
	}
	if d.yac, err = d.calibrate(ay); err != nil {
		return
	}
	if d.zac, err = d.calibrate(az); err != nil {
		return
	}

	d.initialized = true

	return
}

func (d *L3GD20) axisStatus(a *axis) (available bool, err error) {
	var data byte
	if data, err = d.Bus.ReadByteFromReg(address, statusReg); err != nil {
		return
	}

	if data&zyxAvailable == 0 {
		return
	}

	available = data&a.availableMask != 0

	return
}

func (d *L3GD20) readOrientationDelta(a *axis) (value float64, err error) {
	rl, rh := a.regs()
	var l, h byte
	if l, err = d.Bus.ReadByteFromReg(address, rl); err != nil {
		return
	}
	if h, err = d.Bus.ReadByteFromReg(address, rh); err != nil {
		return
	}

	value = float64(int16(h)<<8 | int16(l))
	value *= d.Range.sensitivity

	return
}

func (d *L3GD20) calibratedOrientationDelta(a *axis) (value float64, err error) {
	if value, err = d.readOrientationDelta(a); err != nil {
		return
	}

	switch a {
	case ax:
		value = d.xac.adjust(value)
	case ay:
		value = d.yac.adjust(value)
	case az:
		value = d.zac.adjust(value)
	}

	return
}

func (d *L3GD20) measureOrientationDelta() (dx, dy, dz float64, err error) {
	if err = d.setup(); err != nil {
		return
	}

	if dx, err = d.calibratedOrientationDelta(ax); err != nil {
		return
	}
	if dy, err = d.calibratedOrientationDelta(ay); err != nil {
		return
	}
	if dz, err = d.calibratedOrientationDelta(az); err != nil {
		return
	}

	return
}

// Orientation returns the current orientation reading.
func (d *L3GD20) OrientationDelta() (dx, dy, dz float64, err error) {
	return d.measureOrientationDelta()
}

// Temperature returns the current temperature reading.
func (d *L3GD20) Temperature() (temp int, err error) {
	if err = d.setup(); err != nil {
		return
	}

	var data byte
	if data, err = d.Bus.ReadByteFromReg(address, tempData); err != nil {
		return
	}

	temp = int(int8(data))

	return
}

func (d *L3GD20) Orientations() (orientations <-chan Orientation, err error) {
	if err = d.setup(); err != nil {
		return
	}

	orientations = d.orientations

	return
}

// Start starts the data acquisition loop.
func (d *L3GD20) Start() (err error) {
	if err = d.setup(); err != nil {
		return
	}

	d.closing = make(chan chan struct{})

	go func() {
		var x, y, z float64
		var orientations chan Orientation
		oldTime := time.Now()

		var timer <-chan time.Time
		resetTimer := func() {
			timer = time.After(time.Duration(d.Poll) * time.Millisecond)
		}
		resetTimer()

		for {
			select {
			case currTime := <-timer:
				dx, dy, dz, err := d.measureOrientationDelta()
				if err != nil {
					log.Printf("l3gd20: %v", err)
				} else {
					timeElapsed := currTime.Sub(oldTime)
					mult := timeElapsed.Seconds()
					x += dx * mult
					y += dy * mult
					z += dz * mult
					orientations = d.orientations
				}
				oldTime = currTime
				resetTimer()
			case orientations <- Orientation{x, y, z}:
				orientations = nil
			case waitc := <-d.closing:
				waitc <- struct{}{}
				close(d.orientations)
				return
			}

		}
	}()

	return
}

func (d *L3GD20) Stop() (err error) {
	if d.closing != nil {
		waitc := make(chan struct{})
		d.closing <- waitc
		<-waitc
		d.closing = nil
	}
	if err = d.Bus.WriteByteToReg(address, ctrlReg1, ctrlReg1Finished); err != nil {
		return
	}
	d.initialized = false
	return
}

// Close.
func (d *L3GD20) Close() (err error) {
	return d.Stop()
}
<|endoftext|>


<commit_before>package oauth2

import (
	"errors"
	"net/http"
	"strings"
)

// NewBearerTokenResponse creates and returns a new token response that carries
// a bearer token.
func NewBearerTokenResponse(token string, expiresIn int) *TokenResponse {
	return NewTokenResponse("bearer", token, expiresIn)
}

// ParseBearerToken parses and returns the bearer token from a request. It will
// return standard errors if the extraction failed.
//
// Note: The spec also allows obtaining the bearer token from query parameters
// and the request body (form data). This implementation only supports obtaining
// the token from the "Authorization" header as this is the most common use case
// and considered most secure.
func ParseBearerToken(r *http.Request) (string, error) {
	// read header
	h := r.Header.Get("Authorization")

	// split header
	s := strings.SplitN(h, " ", 2)
	if len(s) != 2 || !strings.EqualFold(s[0], "bearer") {
		return "", errors.New("Malformed or missing authorization header")
	}

	// TODO: Implement "WWW-Authenticate" header in response: https://tools.ietf.org/html/rfc6750#section-3.

	return s[1], nil
}
<commit_msg>added bearer token type constant<commit_after>package oauth2

import (
	"errors"
	"net/http"
	"strings"
)

// The bearer token type.
const BearerTokenType = "bearer"

// NewBearerTokenResponse creates and returns a new token response that carries
// a bearer token.
func NewBearerTokenResponse(token string, expiresIn int) *TokenResponse {
	return NewTokenResponse(BearerTokenType, token, expiresIn)
}

// ParseBearerToken parses and returns the bearer token from a request. It will
// return standard errors if the extraction failed.
//
// Note: The spec also allows obtaining the bearer token from query parameters
// and the request body (form data). This implementation only supports obtaining
// the token from the "Authorization" header as this is the most common use case
// and considered most secure.
func ParseBearerToken(r *http.Request) (string, error) {
	// read header
	h := r.Header.Get("Authorization")

	// split header
	s := strings.SplitN(h, " ", 2)
	if len(s) != 2 || !strings.EqualFold(s[0], BearerTokenType) {
		return "", errors.New("Malformed or missing authorization header")
	}

	// TODO: Implement "WWW-Authenticate" header in response: https://tools.ietf.org/html/rfc6750#section-3.

	return s[1], nil
}
<|endoftext|>


<commit_before>//	Copyright 2013 slowfei And The Contributors All rights reserved.
//
//	Software Source Code License Agreement (BSD License)
//
//  Create on 2013-11-30
//  Update on 2014-06-01
//  Email  slowfei@foxmail.com
//  Home   http://www.slowfei.com

//	go html design static server
package main

import (
	"flag"
	"fmt"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"github.com/slowfei/leafveingo/template"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	port     = flag.Int("p", 8080, "http port default 8080")
	suffix   = flag.String("s", "tpl", "request url suffix default tpl")
	charset  = flag.String("c", "utf-8", "content-type charset default utf-8")
	isCmdDir = flag.Bool("cmddir", true, "is current cmd directory find files? default true. false is execute file directory find.")
	path     = flag.String("path", "", "specify the run path")
	compact  = flag.Bool("compact", false, "is compact html code? default false")
	template = LVTemplate.SharedTemplate()
)

func HtmlOut(rw http.ResponseWriter, req *http.Request) {

	reqPath := req.URL.Path

	if '/' == reqPath[len(reqPath)-1] {
		reqPath += "index." + *suffix
	}

	filePath := filepath.Join(template.BaseDir(), reqPath)

	isExists, isDir, _ := SFFileManager.Exists(filePath)
	if !isExists || isDir {
		http.NotFound(rw, req)
		return
	}

	fmt.Println("requet page:", filePath)

	if strings.HasSuffix(reqPath, *suffix) {
		e := req.ParseForm()
		if nil != e {
			fmt.Println("parse form error:", e)
			return
		}
		rw.Header().Set("Content-Type", "text/html; charset="+*charset)
		err := template.Execute(rw, LVTemplate.NewTemplateValue(reqPath, req.Form))
		if nil != err {
			fmt.Println("template error: ", err)
		}
	} else {
		http.ServeFile(rw, req, filePath)
	}

}

func main() {
	flag.Parse()
	http.HandleFunc("/", HtmlOut)

	if 0 == len(*path) {
		if *isCmdDir {
			template.SetBaseDir(SFFileManager.GetCmdDir())
		} else {
			template.SetBaseDir(SFFileManager.GetExecDir())
		}
	} else {
		template.SetBaseDir(*path)
	}

	template.SetCache(false)
	template.SetCompactHTML(*compact)

	err := http.ListenAndServe(":"+strconv.Itoa(*port), nil)
	if err != nil {
		fmt.Println("ListenAndServe:", err)
	}
}
<commit_msg>修正：leafveingo/template修改新的初始化函数<commit_after>//	Copyright 2013 slowfei And The Contributors All rights reserved.
//
//	Software Source Code License Agreement (BSD License)
//
//  Create on 2013-11-30
//  Update on 2015-06-18
//  Email  slowfei@foxmail.com
//  Home   http://www.slowfei.com

//	go html design static server
package main

import (
	"flag"
	"fmt"
	"github.com/slowfei/gosfcore/utils/filemanager"
	"github.com/slowfei/leafveingo/template"
	"net/http"
	"path/filepath"
	"strconv"
	"strings"
)

var (
	port     = flag.Int("p", 8080, "http port default 8080")
	suffix   = flag.String("s", "tpl", "request url suffix default tpl")
	charset  = flag.String("c", "utf-8", "content-type charset default utf-8")
	isCmdDir = flag.Bool("cmddir", true, "is current cmd directory find files? default true. false is execute file directory find.")
	path     = flag.String("path", "", "specify the run path")
	compact  = flag.Bool("compact", false, "is compact html code? default false")
	template = LVTemplate.NewTemplate()
)

func HtmlOut(rw http.ResponseWriter, req *http.Request) {

	reqPath := req.URL.Path

	if '/' == reqPath[len(reqPath)-1] {
		reqPath += "index." + *suffix
	}

	filePath := filepath.Join(template.BaseDir(), reqPath)

	isExists, isDir, _ := SFFileManager.Exists(filePath)
	if !isExists || isDir {
		http.NotFound(rw, req)
		return
	}

	fmt.Println("requet page:", filePath)

	if strings.HasSuffix(reqPath, *suffix) {
		e := req.ParseForm()
		if nil != e {
			fmt.Println("parse form error:", e)
			return
		}
		rw.Header().Set("Content-Type", "text/html; charset="+*charset)
		err := template.Execute(rw, LVTemplate.NewTemplateValue(reqPath, req.Form))
		if nil != err {
			fmt.Println("template error: ", err)
		}
	} else {
		http.ServeFile(rw, req, filePath)
	}

}

func main() {
	flag.Parse()
	http.HandleFunc("/", HtmlOut)

	if 0 == len(*path) {
		if *isCmdDir {
			template.SetBaseDir(SFFileManager.GetCmdDir())
		} else {
			template.SetBaseDir(SFFileManager.GetExecDir())
		}
	} else {
		template.SetBaseDir(*path)
	}

	template.SetCache(false)
	template.SetCompactHTML(*compact)

	err := http.ListenAndServe(":"+strconv.Itoa(*port), nil)
	if err != nil {
		fmt.Println("ListenAndServe:", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Yeung Shu Hung and The Go Authors.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements the web server side for FastCGI
// as specified in http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html

// A part of this file is from golang package net/http/cgi,
// in particular https://golang.org/src/net/http/cgi/host.go

package gofast

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// Request hold information of a standard
// FastCGI request
type Request struct {
	Raw      *http.Request
	ID       uint16
	Params   map[string]string
	Stdin    io.ReadCloser
	KeepConn bool
}

// client is the default implementation of Client
type client struct {
	conn   *conn
	chanID chan uint16
}

// AllocID implements Client.AllocID
func (c *client) AllocID() (reqID uint16) {
	reqID = <-c.chanID
	return
}

// ReleaseID implements Client.ReleaseID
func (c *client) ReleaseID(reqID uint16) {
	go func() {
		// release the ID back to channel for reuse
		// use goroutine to prevent blocking ReleaseID
		c.chanID <- reqID
	}()
}

// writeRequest writes params and stdin to the FastCGI application
func (c *client) writeRequest(resp *ResponsePipe, req *Request) (err error) {

	// FIXME: add other role implementation, add role field to Request
	err = c.conn.writeBeginRequest(req.ID, uint16(roleResponder), 0)
	if err != nil {
		resp.Close()
		return
	}
	err = c.conn.writePairs(typeParams, req.ID, req.Params)
	if err != nil {
		resp.Close()
		return
	}
	if req.Stdin == nil {
		err = c.conn.writeRecord(typeStdin, req.ID, []byte{})
	} else {
		defer req.Stdin.Close()
		p := make([]byte, 1024)
		var count int
		for {
			count, err = req.Stdin.Read(p)
			if err == io.EOF {
				err = nil
			} else if err != nil {
				break
			}
			if count == 0 {
				break
			}

			err = c.conn.writeRecord(typeStdin, req.ID, p[:count])
			if err != nil {
				break
			}
		}
	}

	if err != nil {
		resp.Close()
	}
	return
}

// readResponse read the FastCGI stdout and stderr, then write
// to the response pipe
func (c *client) readResponse(ctx context.Context, resp *ResponsePipe, req *Request) (err error) {

	var rec record
	var timeout <-chan time.Time
	readError := make(chan error)
	never := make(chan time.Time) // always block
	defer close(never)

	// define timeout
	if deadline, ok := ctx.Deadline(); ok {
		timeout = time.After(time.Until(deadline))
	} else {
		timeout = never
	}

	defer c.ReleaseID(req.ID)
	defer resp.Close()

	// readloop in goroutine
	go func() {
	readLoop:
		for {
			if err := rec.read(c.conn.rwc); err != nil {
				break
			}

			// different output type for different stream
			switch rec.h.Type {
			case typeStdout:
				resp.stdOutWriter.Write(rec.content())
			case typeStderr:
				resp.stdErrWriter.Write(rec.content())
			case typeEndRequest:
				break readLoop
			default:
				readError <- fmt.Errorf("unexpected type %#v in readLoop", rec.h.Type)
			}
		}
		close(readError)
	}()

	select {
	case err = <-readError:
	case <-timeout:
		err = fmt.Errorf("timeout")
	}
	return
}

// Do implements Client.Do
func (c *client) Do(req *Request) (resp *ResponsePipe, err error) {

	resp = NewResponsePipe()
	var timeout <-chan time.Time

	readError, writeError := make(chan error), make(chan error)
	never := make(chan time.Time) // always block
	timeout = never
	defer close(never)

	// if there is a raw request, use the context deadline
	var ctx context.Context
	if req.Raw != nil {
		ctx = req.Raw.Context()
		// if has no deadline, wait until ch is unblocked
		if deadline, ok := ctx.Deadline(); ok {
			timeout = time.After(time.Until(deadline))
		}
	} else {
		ctx = context.TODO()
	}

	// Run read and write in parallel.
	// Note: Specification never said "write before read".
	go func() {
		readError <- c.writeRequest(resp, req)
		close(readError)
	}()

	// get response in a goroutine and send to response pipe
	go func() {
		writeError <- c.readResponse(ctx, resp, req)
		close(writeError)
	}()

	// wait until context deadline
	// or until writeError is not blocked.
	select {
	case <-timeout:
		err = fmt.Errorf("timeout on context deadline")
	case err = <-readError:
		// do nothing and return the error
	case err = <-writeError:
		// do nothing and return the error
	}
	return
}

// NewRequest implements Client.NewRequest
func (c *client) NewRequest(r *http.Request) (req *Request) {
	req = &Request{
		Raw:    r,
		ID:     c.AllocID(),
		Params: make(map[string]string),
	}

	// if no http request, return here
	if r == nil {
		return
	}

	// pass body (io.ReadCloser) to stdio
	req.Stdin = r.Body

	return
}

// Client is a client interface of FastCGI
// application process through given
// connection (net.Conn)
type Client interface {

	// Do takes care of a proper FastCGI request
	Do(req *Request) (resp *ResponsePipe, err error)

	// NewRequest returns a standard FastCGI request
	// with a unique request ID allocted by the client
	NewRequest(*http.Request) *Request

	// AllocID allocates a new reqID.
	// It blocks if all possible uint16 IDs are allocated.
	AllocID() uint16

	// ReleaseID releases a reqID.
	// It never blocks.
	ReleaseID(uint16)
}

// NewClient returns a Client of the given
// connection (net.Conn).
//
// limit is the maximum number of request that the
// applcation support. 0 means the maximum number
// available for 16bit request id (65536).
// Default 0.
//
func NewClient(conn net.Conn, limit uint32) Client {
	cid := make(chan uint16)

	if limit == 0 || limit > 65536 {
		limit = 65536
	}
	go func(maxID uint16) {
		for i := uint16(0); i < maxID; i++ {
			cid <- i
		}
		cid <- uint16(maxID)
	}(uint16(limit - 1))

	return &client{
		conn:   newConn(conn),
		chanID: cid,
	}
}

// NewResponsePipe returns an initialized new ResponsePipe struct
func NewResponsePipe() (p *ResponsePipe) {
	p = new(ResponsePipe)
	p.stdOutReader, p.stdOutWriter = io.Pipe()
	p.stdErrReader, p.stdErrWriter = io.Pipe()
	return
}

// ResponsePipe contains readers and writers that handles
// all FastCGI output streams
type ResponsePipe struct {
	stdOutReader io.Reader
	stdOutWriter io.WriteCloser
	stdErrReader io.Reader
	stdErrWriter io.WriteCloser
}

// Close close all writers
func (pipes *ResponsePipe) Close() {
	pipes.stdOutWriter.Close()
	pipes.stdErrWriter.Close()
}

// WriteTo writes the given output into http.ResponseWriter
func (pipes *ResponsePipe) WriteTo(rw http.ResponseWriter, ew io.Writer) (err error) {
	chErr := make(chan error, 2)

	go func() {
		chErr <- pipes.writeResponse(rw)
	}()
	go func() {
		chErr <- pipes.writeError(ew)
	}()

	for i := 0; i < 2; i++ {
		if err = <-chErr; err != nil {
			close(chErr)
			return
		}
	}
	return
}

func (pipes *ResponsePipe) writeError(w io.Writer) (err error) {
	_, err = io.Copy(w, pipes.stdErrReader)
	if err != nil {
		err = fmt.Errorf("gofast: copy error: %v", err.Error())
	}
	return
}

// writeTo writes the given output into http.ResponseWriter
func (pipes *ResponsePipe) writeResponse(w http.ResponseWriter) (err error) {
	linebody := bufio.NewReaderSize(pipes.stdOutReader, 1024)
	headers := make(http.Header)
	statusCode := 0
	headerLines := 0
	sawBlankLine := false

	for {
		var line []byte
		var isPrefix bool
		line, isPrefix, err = linebody.ReadLine()
		if isPrefix {
			w.WriteHeader(http.StatusInternalServerError)
			err = fmt.Errorf("gofast: long header line from subprocess")
			return
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			err = fmt.Errorf("gofast: error reading headers: %v", err)
			return
		}
		if len(line) == 0 {
			sawBlankLine = true
			break
		}
		headerLines++
		parts := strings.SplitN(string(line), ":", 2)
		if len(parts) < 2 {
			err = fmt.Errorf("gofast: bogus header line: %s", string(line))
			return
		}
		header, val := parts[0], parts[1]
		header = strings.TrimSpace(header)
		val = strings.TrimSpace(val)
		switch {
		case header == "Status":
			if len(val) < 3 {
				err = fmt.Errorf("gofast: bogus status (short): %q", val)
				return
			}
			var code int
			code, err = strconv.Atoi(val[0:3])
			if err != nil {
				err = fmt.Errorf("gofast: bogus status: %q\nline was %q",
					val, line)
				return
			}
			statusCode = code
		default:
			headers.Add(header, val)
		}
	}
	if headerLines == 0 || !sawBlankLine {
		w.WriteHeader(http.StatusInternalServerError)
		err = fmt.Errorf("gofast: no headers")
		return
	}

	if loc := headers.Get("Location"); loc != "" {
		/*
			if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
				h.handleInternalRedirect(rw, req, loc)
				return
			}
		*/
		if statusCode == 0 {
			statusCode = http.StatusFound
		}
	}

	if statusCode == 0 && headers.Get("Content-Type") == "" {
		w.WriteHeader(http.StatusInternalServerError)
		err = fmt.Errorf("gofast: missing required Content-Type in headers")
		return
	}

	if statusCode == 0 {
		statusCode = http.StatusOK
	}

	// Copy headers to rw's headers, after we've decided not to
	// go into handleInternalRedirect, which won't want its rw
	// headers to have been touched.
	for k, vv := range headers {
		for _, v := range vv {
			w.Header().Add(k, v)
		}
	}

	w.WriteHeader(statusCode)

	_, err = io.Copy(w, linebody)
	if err != nil {
		err = fmt.Errorf("gofast: copy error: %v", err)
	}
	return
}
<commit_msg>replace time.Until with time.Sub<commit_after>// Copyright 2016 Yeung Shu Hung and The Go Authors.
// All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements the web server side for FastCGI
// as specified in http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html

// A part of this file is from golang package net/http/cgi,
// in particular https://golang.org/src/net/http/cgi/host.go

package gofast

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"
)

// Request hold information of a standard
// FastCGI request
type Request struct {
	Raw      *http.Request
	ID       uint16
	Params   map[string]string
	Stdin    io.ReadCloser
	KeepConn bool
}

// client is the default implementation of Client
type client struct {
	conn   *conn
	chanID chan uint16
}

// AllocID implements Client.AllocID
func (c *client) AllocID() (reqID uint16) {
	reqID = <-c.chanID
	return
}

// ReleaseID implements Client.ReleaseID
func (c *client) ReleaseID(reqID uint16) {
	go func() {
		// release the ID back to channel for reuse
		// use goroutine to prevent blocking ReleaseID
		c.chanID <- reqID
	}()
}

// writeRequest writes params and stdin to the FastCGI application
func (c *client) writeRequest(resp *ResponsePipe, req *Request) (err error) {

	// FIXME: add other role implementation, add role field to Request
	err = c.conn.writeBeginRequest(req.ID, uint16(roleResponder), 0)
	if err != nil {
		resp.Close()
		return
	}
	err = c.conn.writePairs(typeParams, req.ID, req.Params)
	if err != nil {
		resp.Close()
		return
	}
	if req.Stdin == nil {
		err = c.conn.writeRecord(typeStdin, req.ID, []byte{})
	} else {
		defer req.Stdin.Close()
		p := make([]byte, 1024)
		var count int
		for {
			count, err = req.Stdin.Read(p)
			if err == io.EOF {
				err = nil
			} else if err != nil {
				break
			}
			if count == 0 {
				break
			}

			err = c.conn.writeRecord(typeStdin, req.ID, p[:count])
			if err != nil {
				break
			}
		}
	}

	if err != nil {
		resp.Close()
	}
	return
}

// readResponse read the FastCGI stdout and stderr, then write
// to the response pipe
func (c *client) readResponse(ctx context.Context, resp *ResponsePipe, req *Request) (err error) {

	var rec record
	var timeout <-chan time.Time
	readError := make(chan error)
	never := make(chan time.Time) // always block
	defer close(never)

	// define timeout
	if deadline, ok := ctx.Deadline(); ok {
		timeout = time.After(deadline.Sub(time.Now()))
	} else {
		timeout = never
	}

	defer c.ReleaseID(req.ID)
	defer resp.Close()

	// readloop in goroutine
	go func() {
	readLoop:
		for {
			if err := rec.read(c.conn.rwc); err != nil {
				break
			}

			// different output type for different stream
			switch rec.h.Type {
			case typeStdout:
				resp.stdOutWriter.Write(rec.content())
			case typeStderr:
				resp.stdErrWriter.Write(rec.content())
			case typeEndRequest:
				break readLoop
			default:
				readError <- fmt.Errorf("unexpected type %#v in readLoop", rec.h.Type)
			}
		}
		close(readError)
	}()

	select {
	case err = <-readError:
	case <-timeout:
		err = fmt.Errorf("timeout")
	}
	return
}

// Do implements Client.Do
func (c *client) Do(req *Request) (resp *ResponsePipe, err error) {

	resp = NewResponsePipe()
	var timeout <-chan time.Time

	readError, writeError := make(chan error), make(chan error)
	never := make(chan time.Time) // always block
	timeout = never
	defer close(never)

	// if there is a raw request, use the context deadline
	var ctx context.Context
	if req.Raw != nil {
		ctx = req.Raw.Context()
		// if has no deadline, wait until ch is unblocked
		if deadline, ok := ctx.Deadline(); ok {
			timeout = time.After(deadline.Sub(time.Now()))
		}
	} else {
		ctx = context.TODO()
	}

	// Run read and write in parallel.
	// Note: Specification never said "write before read".
	go func() {
		readError <- c.writeRequest(resp, req)
		close(readError)
	}()

	// get response in a goroutine and send to response pipe
	go func() {
		writeError <- c.readResponse(ctx, resp, req)
		close(writeError)
	}()

	// wait until context deadline
	// or until writeError is not blocked.
	select {
	case <-timeout:
		err = fmt.Errorf("timeout on context deadline")
	case err = <-readError:
		// do nothing and return the error
	case err = <-writeError:
		// do nothing and return the error
	}
	return
}

// NewRequest implements Client.NewRequest
func (c *client) NewRequest(r *http.Request) (req *Request) {
	req = &Request{
		Raw:    r,
		ID:     c.AllocID(),
		Params: make(map[string]string),
	}

	// if no http request, return here
	if r == nil {
		return
	}

	// pass body (io.ReadCloser) to stdio
	req.Stdin = r.Body

	return
}

// Client is a client interface of FastCGI
// application process through given
// connection (net.Conn)
type Client interface {

	// Do takes care of a proper FastCGI request
	Do(req *Request) (resp *ResponsePipe, err error)

	// NewRequest returns a standard FastCGI request
	// with a unique request ID allocted by the client
	NewRequest(*http.Request) *Request

	// AllocID allocates a new reqID.
	// It blocks if all possible uint16 IDs are allocated.
	AllocID() uint16

	// ReleaseID releases a reqID.
	// It never blocks.
	ReleaseID(uint16)
}

// NewClient returns a Client of the given
// connection (net.Conn).
//
// limit is the maximum number of request that the
// applcation support. 0 means the maximum number
// available for 16bit request id (65536).
// Default 0.
//
func NewClient(conn net.Conn, limit uint32) Client {
	cid := make(chan uint16)

	if limit == 0 || limit > 65536 {
		limit = 65536
	}
	go func(maxID uint16) {
		for i := uint16(0); i < maxID; i++ {
			cid <- i
		}
		cid <- uint16(maxID)
	}(uint16(limit - 1))

	return &client{
		conn:   newConn(conn),
		chanID: cid,
	}
}

// NewResponsePipe returns an initialized new ResponsePipe struct
func NewResponsePipe() (p *ResponsePipe) {
	p = new(ResponsePipe)
	p.stdOutReader, p.stdOutWriter = io.Pipe()
	p.stdErrReader, p.stdErrWriter = io.Pipe()
	return
}

// ResponsePipe contains readers and writers that handles
// all FastCGI output streams
type ResponsePipe struct {
	stdOutReader io.Reader
	stdOutWriter io.WriteCloser
	stdErrReader io.Reader
	stdErrWriter io.WriteCloser
}

// Close close all writers
func (pipes *ResponsePipe) Close() {
	pipes.stdOutWriter.Close()
	pipes.stdErrWriter.Close()
}

// WriteTo writes the given output into http.ResponseWriter
func (pipes *ResponsePipe) WriteTo(rw http.ResponseWriter, ew io.Writer) (err error) {
	chErr := make(chan error, 2)

	go func() {
		chErr <- pipes.writeResponse(rw)
	}()
	go func() {
		chErr <- pipes.writeError(ew)
	}()

	for i := 0; i < 2; i++ {
		if err = <-chErr; err != nil {
			close(chErr)
			return
		}
	}
	return
}

func (pipes *ResponsePipe) writeError(w io.Writer) (err error) {
	_, err = io.Copy(w, pipes.stdErrReader)
	if err != nil {
		err = fmt.Errorf("gofast: copy error: %v", err.Error())
	}
	return
}

// writeTo writes the given output into http.ResponseWriter
func (pipes *ResponsePipe) writeResponse(w http.ResponseWriter) (err error) {
	linebody := bufio.NewReaderSize(pipes.stdOutReader, 1024)
	headers := make(http.Header)
	statusCode := 0
	headerLines := 0
	sawBlankLine := false

	for {
		var line []byte
		var isPrefix bool
		line, isPrefix, err = linebody.ReadLine()
		if isPrefix {
			w.WriteHeader(http.StatusInternalServerError)
			err = fmt.Errorf("gofast: long header line from subprocess")
			return
		}
		if err == io.EOF {
			break
		}
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			err = fmt.Errorf("gofast: error reading headers: %v", err)
			return
		}
		if len(line) == 0 {
			sawBlankLine = true
			break
		}
		headerLines++
		parts := strings.SplitN(string(line), ":", 2)
		if len(parts) < 2 {
			err = fmt.Errorf("gofast: bogus header line: %s", string(line))
			return
		}
		header, val := parts[0], parts[1]
		header = strings.TrimSpace(header)
		val = strings.TrimSpace(val)
		switch {
		case header == "Status":
			if len(val) < 3 {
				err = fmt.Errorf("gofast: bogus status (short): %q", val)
				return
			}
			var code int
			code, err = strconv.Atoi(val[0:3])
			if err != nil {
				err = fmt.Errorf("gofast: bogus status: %q\nline was %q",
					val, line)
				return
			}
			statusCode = code
		default:
			headers.Add(header, val)
		}
	}
	if headerLines == 0 || !sawBlankLine {
		w.WriteHeader(http.StatusInternalServerError)
		err = fmt.Errorf("gofast: no headers")
		return
	}

	if loc := headers.Get("Location"); loc != "" {
		/*
			if strings.HasPrefix(loc, "/") && h.PathLocationHandler != nil {
				h.handleInternalRedirect(rw, req, loc)
				return
			}
		*/
		if statusCode == 0 {
			statusCode = http.StatusFound
		}
	}

	if statusCode == 0 && headers.Get("Content-Type") == "" {
		w.WriteHeader(http.StatusInternalServerError)
		err = fmt.Errorf("gofast: missing required Content-Type in headers")
		return
	}

	if statusCode == 0 {
		statusCode = http.StatusOK
	}

	// Copy headers to rw's headers, after we've decided not to
	// go into handleInternalRedirect, which won't want its rw
	// headers to have been touched.
	for k, vv := range headers {
		for _, v := range vv {
			w.Header().Add(k, v)
		}
	}

	w.WriteHeader(statusCode)

	_, err = io.Copy(w, linebody)
	if err != nil {
		err = fmt.Errorf("gofast: copy error: %v", err)
	}
	return
}
<|endoftext|>


<commit_before>package godirwalk

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

var rootDir string

func TestMain(m *testing.M) {
	flag.Parse()

	// All tests use the same directory test scaffolding.  Create the directory
	// hierarchy, run the tests, then remove the root directory of the test
	// scaffolding.
	if err := setup(); err != nil {
		fmt.Fprintf(os.Stderr, "setup: %s\n", err)
		os.Exit(1)
	}

	code := m.Run()

	if err := teardown(); err != nil {
		fmt.Fprintf(os.Stderr, "teardown: %s\n", err)
		os.Exit(1)
	}

	os.Exit(code)
}

func setup() error {
	var err error

	rootDir, err = ioutil.TempDir(os.TempDir(), "godirwalk-")
	if err != nil {
		return err
	}

	// Create files, creating parent directories along the way.
	files := []string{
		"dir1/dir1a/file1a1",
		"dir1/dir1a/skip",
		"dir1/dir1a/z1a2",
		"dir1/file1b",
		"dir2/file2a",
		"dir2/skip/file2b1",
		"dir2/z2c/file2c1",
		"dir3/aaa.txt",
		"dir3/zzz/aaa.txt",
		"dir4/aaa.txt",
		"dir4/zzz/aaa.txt",
		"dir5/a1.txt",
		"dir5/a2/a2a/a2a1.txt",
		"dir5/a2/a2b.txt",
		"dir6/bravo.txt",
		"dir6/code/123.txt",
		"dir7/z",
		"file3",
	}

	for _, pathname := range files {
		pathname = filepath.Join(rootDir, filepath.FromSlash(pathname))

		if err := os.MkdirAll(filepath.Dir(pathname), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}

		if err = ioutil.WriteFile(pathname, []byte("some test data\n"), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create file for test scaffolding: %s", err)
		}
	}

	symlinks := []struct {
		newname, oldname string
	}{
		{"dir3/skip", "zzz"},
		{"dir4/symlinkToDirectory", "zzz"},
		{"dir4/symlinkToFile", "aaa.txt"},
		{"dir7/a/x", "../b"},
		{"dir7/b/y", "../z"},
		{"symlinks/dir-symlink", "../symlinks"}, // infinite loop of symlinks
		{"symlinks/file-symlink", "../file3"},
		{"symlinks/invalid-symlink", "/non/existing/file"},
	}

	for _, entry := range symlinks {
		newname := filepath.Join(rootDir, filepath.FromSlash(entry.newname))

		if err := os.MkdirAll(filepath.Dir(newname), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}

		oldname := filepath.FromSlash(entry.oldname)

		if err := os.Symlink(oldname, newname); err != nil {
			return fmt.Errorf("cannot create symbolic link for test scaffolding: %s", err)
		}
	}

	extraDirs := []string{
		"dir6/abc",
		"dir6/def",
	}

	for _, pathname := range extraDirs {
		pathname = filepath.Join(rootDir, filepath.FromSlash(pathname))

		if err := os.MkdirAll(pathname, os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}
	}

	if err := os.MkdirAll(filepath.Join(rootDir, filepath.FromSlash("dir6/noaccess")), os.FileMode(0)); err != nil {
		return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
	}

	return nil
}

func teardown() error {
	if err := os.Chmod(filepath.Join(rootDir, filepath.FromSlash("dir6/noaccess")), os.ModePerm); err != nil {
		return fmt.Errorf("cannot change permission to delete dir6/noaccess for test scaffolding: %s", err)
	}
	if err := os.RemoveAll(rootDir); err != nil {
		return err
	}
	return nil
}
<commit_msg>reverse order of node creations<commit_after>package godirwalk

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

var rootDir string

func TestMain(m *testing.M) {
	flag.Parse()

	// All tests use the same directory test scaffolding.  Create the directory
	// hierarchy, run the tests, then remove the root directory of the test
	// scaffolding.
	if err := setup(); err != nil {
		fmt.Fprintf(os.Stderr, "setup: %s\n", err)
		os.Exit(1)
	}

	code := m.Run()

	if err := teardown(); err != nil {
		fmt.Fprintf(os.Stderr, "teardown: %s\n", err)
		os.Exit(1)
	}

	os.Exit(code)
}

func setup() error {
	var err error

	rootDir, err = ioutil.TempDir(os.TempDir(), "godirwalk-")
	if err != nil {
		return err
	}

	// Create files, creating parent directories along the way.
	files := []string{
		"dir1/dir1a/file1a1",
		"dir1/dir1a/skip",
		"dir1/dir1a/z1a2",
		"dir1/file1b",
		"dir2/file2a",
		"dir2/skip/file2b1",
		"dir2/z2c/file2c1",
		"dir3/aaa.txt",
		"dir3/zzz/aaa.txt",
		"dir4/aaa.txt",
		"dir4/zzz/aaa.txt",
		"dir5/a1.txt",
		"dir5/a2/a2a/a2a1.txt",
		"dir5/a2/a2b.txt",
		"dir6/bravo.txt",
		"dir6/code/123.txt",
		"dir7/z",
		"file3",
	}

	for _, pathname := range files {
		pathname = filepath.Join(rootDir, filepath.FromSlash(pathname))

		if err := os.MkdirAll(filepath.Dir(pathname), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}

		if err = ioutil.WriteFile(pathname, []byte("some test data\n"), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create file for test scaffolding: %s", err)
		}
	}

	symlinks := []struct {
		newname, oldname string
	}{
		{"dir3/skip", "zzz"},
		{"dir4/symlinkToDirectory", "zzz"},
		{"dir4/symlinkToFile", "aaa.txt"},
		{"dir7/b/y", "../z"},
		{"dir7/a/x", "../b"},
		{"symlinks/dir-symlink", "../symlinks"}, // infinite loop of symlinks
		{"symlinks/file-symlink", "../file3"},
		{"symlinks/invalid-symlink", "/non/existing/file"},
	}

	for _, entry := range symlinks {
		newname := filepath.Join(rootDir, filepath.FromSlash(entry.newname))

		if err := os.MkdirAll(filepath.Dir(newname), os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}

		oldname := filepath.FromSlash(entry.oldname)

		if err := os.Symlink(oldname, newname); err != nil {
			return fmt.Errorf("cannot create symbolic link for test scaffolding: %s", err)
		}
	}

	extraDirs := []string{
		"dir6/abc",
		"dir6/def",
	}

	for _, pathname := range extraDirs {
		pathname = filepath.Join(rootDir, filepath.FromSlash(pathname))

		if err := os.MkdirAll(pathname, os.ModePerm); err != nil {
			return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
		}
	}

	if err := os.MkdirAll(filepath.Join(rootDir, filepath.FromSlash("dir6/noaccess")), os.FileMode(0)); err != nil {
		return fmt.Errorf("cannot create directory for test scaffolding: %s", err)
	}

	return nil
}

func teardown() error {
	if err := os.Chmod(filepath.Join(rootDir, filepath.FromSlash("dir6/noaccess")), os.ModePerm); err != nil {
		return fmt.Errorf("cannot change permission to delete dir6/noaccess for test scaffolding: %s", err)
	}
	if err := os.RemoveAll(rootDir); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package arp

import (
	"bytes"
	"errors"
	"net"
	"time"

	"github.com/mdlayher/ethernet"
	"github.com/mdlayher/raw"
)

var (
	// errNoIPv4Addr is returned when an interface does not have an IPv4
	// address.
	errNoIPv4Addr = errors.New("no IPv4 address available for interface")
)

// A Client is an ARP client, which can be used to send ARP requests to
// retrieve the hardware address of a machine using its IPv4 address.
type Client struct {
	ifi *net.Interface
	ip  net.IP
	p   net.PacketConn
}

// NewClient creates a new Client using the specified network interface.
// NewClient retrieves the IPv4 address of the interface and binds a raw socket
// to send and receive ARP packets.
func NewClient(ifi *net.Interface) (*Client, error) {
	// Open raw socket to send and receive ARP packets using ethernet frames
	// we build ourselves
	p, err := raw.ListenPacket(ifi, raw.ProtocolARP)
	if err != nil {
		return nil, err
	}

	// Check for usable IPv4 addresses for the Client
	addrs, err := ifi.Addrs()
	if err != nil {
		return nil, err
	}

	return newClient(ifi, p, addrs)
}

// newClient is the internal, generic implementation of newClient.  It is used
// to allow an arbitrary net.PacketConn to be used in a Client, so testing
// is easier to accomplish.
func newClient(ifi *net.Interface, p net.PacketConn, addrs []net.Addr) (*Client, error) {
	ip, err := firstIPv4Addr(addrs)
	if err != nil {
		return nil, err
	}

	return &Client{
		ifi: ifi,
		ip:  ip,
		p:   p,
	}, nil
}

// Close closes the Client's raw socket and stops sending and receiving
// ARP packets.
func (c *Client) Close() error {
	return c.p.Close()
}

// Request performs an ARP request, attempting to retrieve the hardware address
// of a machine using its IPv4 address.
func (c *Client) Request(ip net.IP) (net.HardwareAddr, error) {
	// Create ARP packet for broadcast address to attempt to find the
	// hardware address of the input IP address
	arp, err := NewPacket(OperationRequest, c.ifi.HardwareAddr, c.ip, ethernet.Broadcast, ip)
	if err != nil {
		return nil, err
	}
	arpb, err := arp.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// Create ethernet frame addressed to broadcast address to encapsulate the
	// ARP packet
	eth := &ethernet.Frame{
		Destination: ethernet.Broadcast,
		Source:      c.ifi.HardwareAddr,
		EtherType:   ethernet.EtherTypeARP,
		Payload:     arpb,
	}
	ethb, err := eth.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// Write frame to ethernet broadcast address
	_, err = c.p.WriteTo(ethb, &raw.Addr{
		HardwareAddr: ethernet.Broadcast,
	})
	if err != nil {
		return nil, err
	}

	// Loop and wait for replies
	buf := make([]byte, 128)
	for {
		n, _, err := c.p.ReadFrom(buf)
		if err != nil {
			return nil, err
		}

		// Unmarshal ethernet frame and check:
		//   - Frame is for our hardware address
		//   - Frame has ARP EtherType
		if err := eth.UnmarshalBinary(buf[:n]); err != nil {
			return nil, err
		}
		if !bytes.Equal(eth.Destination, c.ifi.HardwareAddr) {
			continue
		}
		if eth.EtherType != ethernet.EtherTypeARP {
			continue
		}

		// Unmarshal ARP packet and check:
		//   - Packet is a reply, not a request
		//   - Packet is for our IP address
		//   - Packet is for our hardware address
		if err := arp.UnmarshalBinary(eth.Payload); err != nil {
			return nil, err
		}
		if arp.Operation != OperationReply {
			continue
		}
		if !bytes.Equal(arp.TargetIP, c.ip) {
			continue
		}
		if !bytes.Equal(arp.TargetHardwareAddr, c.ifi.HardwareAddr) {
			continue
		}

		return arp.SenderHardwareAddr, nil
	}
}

// Copyright (c) 2012 The Go Authors. All rights reserved.
// Source code in this file is based on src/net/interface_linux.go,
// from the Go standard library.  The Go license can be found here:
// https://golang.org/LICENSE.

// Documentation taken from net.PacketConn interface.  Thanks:
// http://golang.org/pkg/net/#PacketConn.

// SetDeadline sets the read and write deadlines associated with the
// connection.
func (c *Client) SetDeadline(t time.Time) error {
	return c.p.SetDeadline(t)
}

// SetReadDeadline sets the deadline for future raw socket read calls.
// If the deadline is reached, a raw socket read will fail with a timeout
// (see type net.Error) instead of blocking.
// A zero value for t means a raw socket read will not time out.
func (c *Client) SetReadDeadline(t time.Time) error {
	return c.p.SetReadDeadline(t)
}

// SetWriteDeadline sets the deadline for future raw socket write calls.
// If the deadline is reached, a raw socket write will fail with a timeout
// (see type net.Error) instead of blocking.
// A zero value for t means a raw socket write will not time out.
// Even if a write times out, it may return n > 0, indicating that
// some of the data was successfully written.
func (c *Client) SetWriteDeadline(t time.Time) error {
	return c.p.SetWriteDeadline(t)
}

// firstIPv4Addr attempts to retrieve the first detected IPv4 address from an
// input slice of network addresses.
func firstIPv4Addr(addrs []net.Addr) (net.IP, error) {
	for _, a := range addrs {
		if a.Network() != "ip+net" {
			continue
		}

		ip, _, err := net.ParseCIDR(a.String())
		if err != nil {
			return nil, err
		}

		// "If ip is not an IPv4 address, To4 returns nil."
		// Reference: http://golang.org/pkg/net/#IP.To4
		if ip4 := ip.To4(); ip4 != nil {
			return ip4, nil
		}
	}

	return nil, errNoIPv4Addr
}
<commit_msg>client: use net.IP.Equal instead of bytes.Equal<commit_after>package arp

import (
	"bytes"
	"errors"
	"net"
	"time"

	"github.com/mdlayher/ethernet"
	"github.com/mdlayher/raw"
)

var (
	// errNoIPv4Addr is returned when an interface does not have an IPv4
	// address.
	errNoIPv4Addr = errors.New("no IPv4 address available for interface")
)

// A Client is an ARP client, which can be used to send ARP requests to
// retrieve the hardware address of a machine using its IPv4 address.
type Client struct {
	ifi *net.Interface
	ip  net.IP
	p   net.PacketConn
}

// NewClient creates a new Client using the specified network interface.
// NewClient retrieves the IPv4 address of the interface and binds a raw socket
// to send and receive ARP packets.
func NewClient(ifi *net.Interface) (*Client, error) {
	// Open raw socket to send and receive ARP packets using ethernet frames
	// we build ourselves
	p, err := raw.ListenPacket(ifi, raw.ProtocolARP)
	if err != nil {
		return nil, err
	}

	// Check for usable IPv4 addresses for the Client
	addrs, err := ifi.Addrs()
	if err != nil {
		return nil, err
	}

	return newClient(ifi, p, addrs)
}

// newClient is the internal, generic implementation of newClient.  It is used
// to allow an arbitrary net.PacketConn to be used in a Client, so testing
// is easier to accomplish.
func newClient(ifi *net.Interface, p net.PacketConn, addrs []net.Addr) (*Client, error) {
	ip, err := firstIPv4Addr(addrs)
	if err != nil {
		return nil, err
	}

	return &Client{
		ifi: ifi,
		ip:  ip,
		p:   p,
	}, nil
}

// Close closes the Client's raw socket and stops sending and receiving
// ARP packets.
func (c *Client) Close() error {
	return c.p.Close()
}

// Request performs an ARP request, attempting to retrieve the hardware address
// of a machine using its IPv4 address.
func (c *Client) Request(ip net.IP) (net.HardwareAddr, error) {
	// Create ARP packet for broadcast address to attempt to find the
	// hardware address of the input IP address
	arp, err := NewPacket(OperationRequest, c.ifi.HardwareAddr, c.ip, ethernet.Broadcast, ip)
	if err != nil {
		return nil, err
	}
	arpb, err := arp.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// Create ethernet frame addressed to broadcast address to encapsulate the
	// ARP packet
	eth := &ethernet.Frame{
		Destination: ethernet.Broadcast,
		Source:      c.ifi.HardwareAddr,
		EtherType:   ethernet.EtherTypeARP,
		Payload:     arpb,
	}
	ethb, err := eth.MarshalBinary()
	if err != nil {
		return nil, err
	}

	// Write frame to ethernet broadcast address
	_, err = c.p.WriteTo(ethb, &raw.Addr{
		HardwareAddr: ethernet.Broadcast,
	})
	if err != nil {
		return nil, err
	}

	// Loop and wait for replies
	buf := make([]byte, 128)
	for {
		n, _, err := c.p.ReadFrom(buf)
		if err != nil {
			return nil, err
		}

		// Unmarshal ethernet frame and check:
		//   - Frame is for our hardware address
		//   - Frame has ARP EtherType
		if err := eth.UnmarshalBinary(buf[:n]); err != nil {
			return nil, err
		}
		if !bytes.Equal(eth.Destination, c.ifi.HardwareAddr) {
			continue
		}
		if eth.EtherType != ethernet.EtherTypeARP {
			continue
		}

		// Unmarshal ARP packet and check:
		//   - Packet is a reply, not a request
		//   - Packet is for our IP address
		//   - Packet is for our hardware address
		if err := arp.UnmarshalBinary(eth.Payload); err != nil {
			return nil, err
		}
		if arp.Operation != OperationReply {
			continue
		}
		if !arp.TargetIP.Equal(c.ip) {
			continue
		}
		if !bytes.Equal(arp.TargetHardwareAddr, c.ifi.HardwareAddr) {
			continue
		}

		return arp.SenderHardwareAddr, nil
	}
}

// Copyright (c) 2012 The Go Authors. All rights reserved.
// Source code in this file is based on src/net/interface_linux.go,
// from the Go standard library.  The Go license can be found here:
// https://golang.org/LICENSE.

// Documentation taken from net.PacketConn interface.  Thanks:
// http://golang.org/pkg/net/#PacketConn.

// SetDeadline sets the read and write deadlines associated with the
// connection.
func (c *Client) SetDeadline(t time.Time) error {
	return c.p.SetDeadline(t)
}

// SetReadDeadline sets the deadline for future raw socket read calls.
// If the deadline is reached, a raw socket read will fail with a timeout
// (see type net.Error) instead of blocking.
// A zero value for t means a raw socket read will not time out.
func (c *Client) SetReadDeadline(t time.Time) error {
	return c.p.SetReadDeadline(t)
}

// SetWriteDeadline sets the deadline for future raw socket write calls.
// If the deadline is reached, a raw socket write will fail with a timeout
// (see type net.Error) instead of blocking.
// A zero value for t means a raw socket write will not time out.
// Even if a write times out, it may return n > 0, indicating that
// some of the data was successfully written.
func (c *Client) SetWriteDeadline(t time.Time) error {
	return c.p.SetWriteDeadline(t)
}

// firstIPv4Addr attempts to retrieve the first detected IPv4 address from an
// input slice of network addresses.
func firstIPv4Addr(addrs []net.Addr) (net.IP, error) {
	for _, a := range addrs {
		if a.Network() != "ip+net" {
			continue
		}

		ip, _, err := net.ParseCIDR(a.String())
		if err != nil {
			return nil, err
		}

		// "If ip is not an IPv4 address, To4 returns nil."
		// Reference: http://golang.org/pkg/net/#IP.To4
		if ip4 := ip.To4(); ip4 != nil {
			return ip4, nil
		}
	}

	return nil, errNoIPv4Addr
}
<|endoftext|>


<commit_before>package gode

import (
	"path/filepath"
	"runtime"
)

// The Node version to install.
// Override this by setting client.Version.
const DefaultNodeVersion = "v0.10.32"

// Client is the interface between Node and Go.
// It also setups up the Node environment if needed.
type Client struct {
	RootPath    string
	NodePath    string
	NpmPath     string
	ModulesPath string
	Version     string
	NodeURL     string
}

// NewClient creates a new Client at the specified rootPath
// The Node installation can then be setup here with client.Setup()
func NewClient(rootPath string) *Client {
	version := DefaultNodeVersion
	return &Client{
		RootPath:    rootPath,
		NodePath:    filepath.Join(rootPath, nodeBase(version), "bin", "node"),
		NpmPath:     filepath.Join(rootPath, nodeBase(version), "bin", "npm"),
		ModulesPath: filepath.Join(rootPath, "lib", "node_modules"),
		Version:     version,
		NodeURL:     nodeURL(version),
	}
}

func nodeBase(version string) string {
	switch {
	case runtime.GOARCH == "386":
		return "node-" + version + "-" + runtime.GOOS + "-x86"
	default:
		return "node-" + version + "-" + runtime.GOOS + "-x64"
	}
}

func nodeURL(version string) string {
	switch {
	case runtime.GOOS == "windows" && runtime.GOARCH == "386":
		return "http://nodejs.org/dist/" + version + "/node.exe"
	case runtime.GOOS == "windows" && runtime.GOARCH == "amd64":
		return "http://nodejs.org/dist/" + version + "/x64/node.exe"
	case runtime.GOARCH == "386":
		return "http://nodejs.org/dist/" + version + "/" + nodeBase(version) + ".tar.gz"
	default:
		return "http://nodejs.org/dist/" + version + "/" + nodeBase(version) + ".tar.gz"
	}
}
<commit_msg>small tweak<commit_after>package gode

import (
	"path/filepath"
	"runtime"
)

// The Node version to install.
// Override this by setting client.Version.
const DefaultNodeVersion = "v0.10.32"

// Client is the interface between Node and Go.
// It also setups up the Node environment if needed.
type Client struct {
	RootPath    string
	NodePath    string
	NpmPath     string
	ModulesPath string
	Version     string
	NodeURL     string
}

// NewClient creates a new Client at the specified rootPath
// The Node installation can then be setup here with client.Setup()
func NewClient(rootPath string) *Client {
	return &Client{
		RootPath:    rootPath,
		NodePath:    filepath.Join(rootPath, nodeBase(DefaultNodeVersion), "bin", "node"),
		NpmPath:     filepath.Join(rootPath, nodeBase(DefaultNodeVersion), "bin", "npm"),
		ModulesPath: filepath.Join(rootPath, "lib", "node_modules"),
		Version:     DefaultNodeVersion,
		NodeURL:     nodeURL(DefaultNodeVersion),
	}
}

func nodeBase(version string) string {
	switch {
	case runtime.GOARCH == "386":
		return "node-" + version + "-" + runtime.GOOS + "-x86"
	default:
		return "node-" + version + "-" + runtime.GOOS + "-x64"
	}
}

func nodeURL(version string) string {
	switch {
	case runtime.GOOS == "windows" && runtime.GOARCH == "386":
		return "http://nodejs.org/dist/" + version + "/node.exe"
	case runtime.GOOS == "windows" && runtime.GOARCH == "amd64":
		return "http://nodejs.org/dist/" + version + "/x64/node.exe"
	case runtime.GOARCH == "386":
		return "http://nodejs.org/dist/" + version + "/" + nodeBase(version) + ".tar.gz"
	default:
		return "http://nodejs.org/dist/" + version + "/" + nodeBase(version) + ".tar.gz"
	}
}
<|endoftext|>


<commit_before>package alchemyapi

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client implements a AlchemyAPI client.
type Client struct {
	*Config
}

type Entity struct {
	Type          string        `json:"type"`
	Relevance     string        `json:"relevance"`
	Count         string        `json:"count"`
	Text          string        `json:"text"`
	Disambiguated Disambiguated `json:"disambiguated"`
}

type Disambiguated struct {
	SubType  []string `json:"subType"`
	Name     string   `json:"name"`
	Freebase string   `json:"freebase"`
	Website  string   `json:"website"`
}

type Output struct {
	Status         string `json:"status"`
	StatusInfo     string `json:"statusInfo"`
	WarningMessage string `json:"warningMessage"`
	Usage          string `json:"usage"`
	URL            string `json:"url"`
}

// New client.
func New(config *Config) *Client {
	c := &Client{Config: config}
	return c
}

// call rpc style endpoint.
func (c *Client) call(path string, in map[string]string) (io.ReadCloser, error) {

	query := url.Values{}
	query.Set("apikey", c.APIKey)
	query.Set("outputMode", "json")

	u := "http://gateway-a.watsonplatform.net/calls" + path + "?" + query.Encode()

	form := url.Values{}
	for key, value := range in {
		form.Add(key, value)
	}

	req, err := http.NewRequest("POST", u, strings.NewReader(form.Encode()))
	if err != nil {
		return nil, err
	}

	req.PostForm = form
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	r, _, err := c.do(req)
	return r, err
}

// perform the request.
func (c *Client) do(req *http.Request) (io.ReadCloser, int64, error) {
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, 0, err
	}

	if res.StatusCode < 400 {
		return res.Body, res.ContentLength, err
	}

	defer res.Body.Close()

	e := &Error{
		Status:     http.StatusText(res.StatusCode),
		StatusCode: res.StatusCode,
	}

	kind := res.Header.Get("Content-Type")

	if strings.Contains(kind, "text/plain") {
		if b, err := ioutil.ReadAll(res.Body); err == nil {
			e.Summary = string(b)
			return nil, 0, e
		}

		return nil, 0, err
	}

	if err := json.NewDecoder(res.Body).Decode(e); err != nil {
		return nil, 0, err
	}

	return nil, 0, e
}
<commit_msg>add more Disambiguated sources<commit_after>package alchemyapi

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Client implements a AlchemyAPI client.
type Client struct {
	*Config
}

type Entity struct {
	Type          string        `json:"type"`
	Relevance     string        `json:"relevance"`
	Count         string        `json:"count"`
	Text          string        `json:"text"`
	Disambiguated Disambiguated `json:"disambiguated"`
}

type Disambiguated struct {
	SubType     []string `json:"subType"`
	Name        string   `json:"name"`
	DBpedia     string   `json:"dbpedia"`
	Yago        string   `json:"yago"`
	OpenCyc     string   `json:"opencyc"`
	Umbel       string   `json:"umbel"`
	MusicBrainz string   `json:"musicBrainz"`
	Freebase    string   `json:"freebase"`
	Website     string   `json:"website"`
}

type Output struct {
	Status         string `json:"status"`
	StatusInfo     string `json:"statusInfo"`
	WarningMessage string `json:"warningMessage"`
	Usage          string `json:"usage"`
	URL            string `json:"url"`
}

// New client.
func New(config *Config) *Client {
	c := &Client{Config: config}
	return c
}

// call rpc style endpoint.
func (c *Client) call(path string, in map[string]string) (io.ReadCloser, error) {

	query := url.Values{}
	query.Set("apikey", c.APIKey)
	query.Set("outputMode", "json")

	u := "http://gateway-a.watsonplatform.net/calls" + path + "?" + query.Encode()

	form := url.Values{}
	for key, value := range in {
		form.Add(key, value)
	}

	req, err := http.NewRequest("POST", u, strings.NewReader(form.Encode()))
	if err != nil {
		return nil, err
	}

	req.PostForm = form
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	r, _, err := c.do(req)
	return r, err
}

// perform the request.
func (c *Client) do(req *http.Request) (io.ReadCloser, int64, error) {
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, 0, err
	}

	if res.StatusCode < 400 {
		return res.Body, res.ContentLength, err
	}

	defer res.Body.Close()

	e := &Error{
		Status:     http.StatusText(res.StatusCode),
		StatusCode: res.StatusCode,
	}

	kind := res.Header.Get("Content-Type")

	if strings.Contains(kind, "text/plain") {
		if b, err := ioutil.ReadAll(res.Body); err == nil {
			e.Summary = string(b)
			return nil, 0, e
		}

		return nil, 0, err
	}

	if err := json.NewDecoder(res.Body).Decode(e); err != nil {
		return nil, 0, err
	}

	return nil, 0, e
}
<|endoftext|>


<commit_before>package client

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/rpc"
	"sync"
	"time"

	"github.com/hashicorp/go-msgpack/codec"
	"github.com/hashicorp/yamux"
)

const (
	// clientPreamble is the preamble to send before upgrading
	// the connection into a SCADA version 1 connection.
	clientPreamble = "SCADA 1\n"
)

var (
	// msgpackHandle is a shared handle for encoding/decoding of RPC messages
	msgpackHandle = &codec.MsgpackHandle{}
)

// Client is a SCADA compatible client. This is a bare bones client that
// only handles the framing and RPC protocol. Higher-level clients should
// be prefered.
type Client struct {
	conn   net.Conn
	client *yamux.Session

	closed     bool
	closedLock sync.Mutex
}

// Dial is used to establish a new connection over TCP
func Dial(addr string) (*Client, error) {
	// Dial a connection
	conn, err := net.DialTimeout("tcp", addr, 10*time.Second)
	if err != nil {
		return nil, err
	}
	return initClient(conn)
}

// DialTLS is used to establish a new connection using TLS/TCP
func DialTLS(addr string, tlsConf *tls.Config) (*Client, error) {
	// Dial a connection
	conn, err := tls.Dial("tcp", addr, tlsConf)
	if err != nil {
		return nil, err
	}
	return initClient(conn)
}

// initClient does the common initialization
func initClient(conn net.Conn) (*Client, error) {
	// Send the preamble
	_, err := conn.Write([]byte(clientPreamble))
	if err != nil {
		return nil, fmt.Errorf("preamble write failed: %v", err)
	}

	// Wrap the connection in yamux for multiplexing
	client, _ := yamux.Client(conn, yamux.DefaultConfig())

	// Create the client
	c := &Client{
		conn:   conn,
		client: client,
	}
	return c, nil
}

// Close is used to terminate the client connection
func (c *Client) Close() error {
	c.closedLock.Lock()
	defer c.closedLock.Unlock()

	if c.closed {
		return nil
	}
	c.closed = true
	c.client.GoAway() // Notify the other side of the close
	return c.client.Close()
}

// RPC is used to perform an RPC
func (c *Client) RPC(method string, args interface{}, resp interface{}) error {
	// Get a stream
	stream, err := c.Open()
	if err != nil {
		return fmt.Errorf("failed to open stream: %v", err)
	}
	defer stream.Close()

	// Create the RPC client
	cc := codec.GoRpc.ClientCodec(stream, msgpackHandle)
	client := rpc.NewClientWithCodec(cc)
	return client.Call(method, args, resp)
}

// Accept is used to accept an incoming connection
func (c *Client) Accept() (net.Conn, error) {
	return c.client.Accept()
}

// Open is used to open an outgoing connection
func (c *Client) Open() (net.Conn, error) {
	return c.client.Open()
}

// Addr is so that client can act like a net.Listener
func (c *Client) Addr() net.Addr {
	return c.client.LocalAddr()
}
<commit_msg>Avoid creating RPC client<commit_after>package client

import (
	"crypto/tls"
	"fmt"
	"net"
	"sync"
	"time"

	"github.com/hashicorp/net-rpc-msgpackrpc"
	"github.com/hashicorp/yamux"
)

const (
	// clientPreamble is the preamble to send before upgrading
	// the connection into a SCADA version 1 connection.
	clientPreamble = "SCADA 1\n"
)

// Client is a SCADA compatible client. This is a bare bones client that
// only handles the framing and RPC protocol. Higher-level clients should
// be prefered.
type Client struct {
	conn   net.Conn
	client *yamux.Session

	closed     bool
	closedLock sync.Mutex
}

// Dial is used to establish a new connection over TCP
func Dial(addr string) (*Client, error) {
	// Dial a connection
	conn, err := net.DialTimeout("tcp", addr, 10*time.Second)
	if err != nil {
		return nil, err
	}
	return initClient(conn)
}

// DialTLS is used to establish a new connection using TLS/TCP
func DialTLS(addr string, tlsConf *tls.Config) (*Client, error) {
	// Dial a connection
	conn, err := tls.Dial("tcp", addr, tlsConf)
	if err != nil {
		return nil, err
	}
	return initClient(conn)
}

// initClient does the common initialization
func initClient(conn net.Conn) (*Client, error) {
	// Send the preamble
	_, err := conn.Write([]byte(clientPreamble))
	if err != nil {
		return nil, fmt.Errorf("preamble write failed: %v", err)
	}

	// Wrap the connection in yamux for multiplexing
	client, _ := yamux.Client(conn, yamux.DefaultConfig())

	// Create the client
	c := &Client{
		conn:   conn,
		client: client,
	}
	return c, nil
}

// Close is used to terminate the client connection
func (c *Client) Close() error {
	c.closedLock.Lock()
	defer c.closedLock.Unlock()

	if c.closed {
		return nil
	}
	c.closed = true
	c.client.GoAway() // Notify the other side of the close
	return c.client.Close()
}

// RPC is used to perform an RPC
func (c *Client) RPC(method string, args interface{}, resp interface{}) error {
	// Get a stream
	stream, err := c.Open()
	if err != nil {
		return fmt.Errorf("failed to open stream: %v", err)
	}
	defer stream.Close()

	// Create the RPC client
	cc := msgpackrpc.NewCodec(true, true, stream)
	return msgpackrpc.CallWithCodec(cc, method, args, resp)
}

// Accept is used to accept an incoming connection
func (c *Client) Accept() (net.Conn, error) {
	return c.client.Accept()
}

// Open is used to open an outgoing connection
func (c *Client) Open() (net.Conn, error) {
	return c.client.Open()
}

// Addr is so that client can act like a net.Listener
func (c *Client) Addr() net.Addr {
	return c.client.LocalAddr()
}
<|endoftext|>