<commit_before>package driver

import (
	"github.com/realglobe-Inc/edo/util"
	"strconv"
	"strings"
	"time"
)

// メモリ上で完結する。デバッグ用。

// 非キャッシュ用。
type MemoryServiceExplorer struct {
	*serviceExplorerTree
}

func NewMemoryServiceExplorer() *MemoryServiceExplorer {
	return &MemoryServiceExplorer{newServiceExplorerTree()}
}

func (reg *MemoryServiceExplorer) ServiceUuid(servUri string) (servUuid string, err error) {
	return reg.get(servUri), nil
}
func (reg *MemoryServiceExplorer) AddServiceUuid(servUri, servUuid string) {
	reg.add(servUri, servUuid)
}
func (reg *MemoryServiceExplorer) RemoveIdProvider(servUri string) {
	reg.remove(servUri)
}

// キャッシュ用。
type MemoryDatedServiceExplorer struct {
	*MemoryServiceExplorer
	stmp    *Stamp
	expiDur time.Duration
}

func NewMemoryDatedServiceExplorer(expiDur time.Duration) *MemoryDatedServiceExplorer {
	return &MemoryDatedServiceExplorer{NewMemoryServiceExplorer(), &Stamp{Date: time.Now(), Digest: strconv.Itoa(0)}, expiDur}
}

func (reg *MemoryDatedServiceExplorer) StampedServiceUuid(servUri string, caStmp *Stamp) (servUuid string, newCaStmp *Stamp, err error) {
	newCaStmp = &Stamp{Date: reg.stmp.Date, ExpiDate: time.Now().Add(reg.expiDur), Digest: reg.stmp.Digest}

	if caStmp == nil || caStmp.Date.Before(reg.stmp.Date) || caStmp.Digest != reg.stmp.Digest {
		servUuid, _ = reg.ServiceUuid(servUri)
		if servUuid == "" {
			return "", nil, nil
		} else {
			return servUuid, newCaStmp, nil
		}
	}

	return "", newCaStmp, nil
}
func (reg *MemoryDatedServiceExplorer) AddServiceUuid(servUri, servUuid string) {
	reg.MemoryServiceExplorer.AddServiceUuid(servUri, servUuid)
	dig, _ := strconv.Atoi(reg.stmp.Digest)
	reg.stmp = &Stamp{Date: time.Now(), Digest: strconv.Itoa(dig + 1)}
}
func (reg *MemoryDatedServiceExplorer) RemoveServiceUuid(servUri string) {
	reg.MemoryServiceExplorer.RemoveIdProvider(servUri)
	dig, _ := strconv.Atoi(reg.stmp.Digest)
	reg.stmp = &Stamp{Date: time.Now(), Digest: strconv.Itoa(dig + 1)}
}

// 内部データ。
type serviceExplorerTree struct {
	*util.Tree
}

func newServiceExplorerTree() *serviceExplorerTree {
	return &serviceExplorerTree{util.NewTree(serviceExplorerTreeIsRoot, serviceExplorerTreeParent)}
}

func serviceExplorerTreeIsRoot(label string) bool {
	return label == ""
}

func serviceExplorerTreeParent(label string) string {
	if idx := strings.LastIndex(label, "/"); idx < 0 {
		// localhost とか。
		return ""
	} else if sepIdx := strings.Index(label, "://"); sepIdx < 0 {
		if idx == len(label)-1 {
			// localhost/api/hoge/ とか。
			return label[:idx]
		} else {
			// localhost/api/hoge/ とか。
			return label[:idx+1]
		}
	} else if idx <= sepIdx+3 {
		// https:// とか
		return ""
	} else {
		// https://localhost/api/hoge とか。
		if idx == len(label)-1 {
			// localhost/api/hoge/ とか。
			return label[:idx]
		} else {
			// localhost/api/hoge/ とか。
			return label[:idx+1]
		}
	}
}

func (tree *serviceExplorerTree) add(servUri string, servUuid string) {
	tree.Add(servUri, servUuid)
}

func (tree *serviceExplorerTree) remove(servUri string) {
	tree.Remove(servUri)
}

func (tree *serviceExplorerTree) get(servUri string) (servUuid string) {
	val := tree.ParentValue(servUri)
	if val == nil {
		return ""
	}
	return val.(string)
}

func (tree *serviceExplorerTree) fromContainer(cont map[string]string) {
	c := map[string]interface{}{}
	for name, addr := range cont {
		c[name] = addr
	}
	tree.FromContainer(c)
}

func (tree *serviceExplorerTree) toContainer() (cont map[string]string) {
	c := tree.ToContainer()
	cont = map[string]string{}
	for label, val := range c {
		cont[label] = val.(string)
	}
	return cont
}
<commit_msg>コメント・ドキュメントの直し<commit_after>package driver

import (
	"github.com/realglobe-Inc/edo/util"
	"strconv"
	"strings"
	"time"
)

// メモリ上で完結する。デバッグ用。

// 非キャッシュ用。
type MemoryServiceExplorer struct {
	*serviceExplorerTree
}

func NewMemoryServiceExplorer() *MemoryServiceExplorer {
	return &MemoryServiceExplorer{newServiceExplorerTree()}
}

func (reg *MemoryServiceExplorer) ServiceUuid(servUri string) (servUuid string, err error) {
	return reg.get(servUri), nil
}
func (reg *MemoryServiceExplorer) AddServiceUuid(servUri, servUuid string) {
	reg.add(servUri, servUuid)
}
func (reg *MemoryServiceExplorer) RemoveIdProvider(servUri string) {
	reg.remove(servUri)
}

// キャッシュ用。
type MemoryDatedServiceExplorer struct {
	*MemoryServiceExplorer
	stmp    *Stamp
	expiDur time.Duration
}

func NewMemoryDatedServiceExplorer(expiDur time.Duration) *MemoryDatedServiceExplorer {
	return &MemoryDatedServiceExplorer{NewMemoryServiceExplorer(), &Stamp{Date: time.Now(), Digest: strconv.Itoa(0)}, expiDur}
}

func (reg *MemoryDatedServiceExplorer) StampedServiceUuid(servUri string, caStmp *Stamp) (servUuid string, newCaStmp *Stamp, err error) {
	newCaStmp = &Stamp{Date: reg.stmp.Date, ExpiDate: time.Now().Add(reg.expiDur), Digest: reg.stmp.Digest}

	if caStmp == nil || caStmp.Date.Before(reg.stmp.Date) || caStmp.Digest != reg.stmp.Digest {
		servUuid, _ = reg.ServiceUuid(servUri)
		if servUuid == "" {
			return "", nil, nil
		} else {
			return servUuid, newCaStmp, nil
		}
	}

	return "", newCaStmp, nil
}
func (reg *MemoryDatedServiceExplorer) AddServiceUuid(servUri, servUuid string) {
	reg.MemoryServiceExplorer.AddServiceUuid(servUri, servUuid)
	dig, _ := strconv.Atoi(reg.stmp.Digest)
	reg.stmp = &Stamp{Date: time.Now(), Digest: strconv.Itoa(dig + 1)}
}
func (reg *MemoryDatedServiceExplorer) RemoveServiceUuid(servUri string) {
	reg.MemoryServiceExplorer.RemoveIdProvider(servUri)
	dig, _ := strconv.Atoi(reg.stmp.Digest)
	reg.stmp = &Stamp{Date: time.Now(), Digest: strconv.Itoa(dig + 1)}
}

// 内部データ。
type serviceExplorerTree struct {
	*util.Tree
}

func newServiceExplorerTree() *serviceExplorerTree {
	return &serviceExplorerTree{util.NewTree(serviceExplorerTreeIsRoot, serviceExplorerTreeParent)}
}

func serviceExplorerTreeIsRoot(label string) bool {
	return label == ""
}

func serviceExplorerTreeParent(label string) string {
	if idx := strings.LastIndex(label, "/"); idx < 0 {
		// localhost とか。
		return ""
	} else if sepIdx := strings.Index(label, "://"); sepIdx < 0 {
		if idx == len(label)-1 {
			// localhost/api/hoge/ とか。
			return label[:idx]
		} else {
			// localhost/api/hoge とか。
			return label[:idx+1]
		}
	} else if idx <= sepIdx+3 {
		// https:// とか
		return ""
	} else {
		// https://localhost/api/hoge とか。
		if idx == len(label)-1 {
			// localhost/api/hoge/ とか。
			return label[:idx]
		} else {
			// localhost/api/hoge とか。
			return label[:idx+1]
		}
	}
}

func (tree *serviceExplorerTree) add(servUri string, servUuid string) {
	tree.Add(servUri, servUuid)
}

func (tree *serviceExplorerTree) remove(servUri string) {
	tree.Remove(servUri)
}

func (tree *serviceExplorerTree) get(servUri string) (servUuid string) {
	val := tree.ParentValue(servUri)
	if val == nil {
		return ""
	}
	return val.(string)
}

func (tree *serviceExplorerTree) fromContainer(cont map[string]string) {
	c := map[string]interface{}{}
	for name, addr := range cont {
		c[name] = addr
	}
	tree.FromContainer(c)
}

func (tree *serviceExplorerTree) toContainer() (cont map[string]string) {
	c := tree.ToContainer()
	cont = map[string]string{}
	for label, val := range c {
		cont[label] = val.(string)
	}
	return cont
}
<|endoftext|>


<commit_before>package dns

import (
	"context"
	"fmt"
	"time"

	"github.com/golang/glog"
	"k8s.io/client-go/kubernetes"
	corev1listers "k8s.io/client-go/listers/core/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/clouddns"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/cloudflare"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/route53"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
)

const (
	cloudDNSServiceAccountKey = "service-account.json"
)

type solver interface {
	Present(domain, token, key string) error
	CleanUp(domain, token, key string) error
	Timeout() (timeout, interval time.Duration)
}

type Solver struct {
	issuer            v1alpha1.GenericIssuer
	client            kubernetes.Interface
	secretLister      corev1listers.SecretLister
	resourceNamespace string
}

func (s *Solver) Present(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}
	glog.V(4).Infof("Presenting DNS01 challenge for domain %q", domain)
	return slv.Present(domain, token, key)
}

func (s *Solver) Wait(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}

	type boolErr struct {
		bool
		error
	}

	fqdn, value, ttl := util.DNS01Record(domain, key)

	glog.V(4).Infof("Checking DNS propagation for %q using name servers: %v", domain, util.RecursiveNameservers)

	timeout, interval := slv.Timeout()
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()
	for {
		select {
		case r := <-func() <-chan boolErr {
			out := make(chan boolErr, 1)
			go func() {
				defer close(out)
				ok, err := util.PreCheckDNS(fqdn, value)
				out <- boolErr{ok, err}
			}()
			return out
		}():
			if r.bool {
				// TODO: move this to somewhere else
				// TODO: make this wait for whatever the record *was*, not is now
				glog.V(4).Infof("Waiting DNS record TTL (%ds) to allow propagation for propagation of DNS record for domain %q", ttl, fqdn)
				time.Sleep(time.Second * time.Duration(ttl))
				glog.V(4).Infof("ACME DNS01 validation record propagated for %q", fqdn)
				return nil
			}
			glog.V(4).Infof("DNS record for %q not yet propagated", domain)
			time.Sleep(interval)
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}

func (s *Solver) CleanUp(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}
	return slv.CleanUp(domain, token, key)
}

func (s *Solver) solverFor(crt *v1alpha1.Certificate, domain string) (solver, error) {
	var cfg *v1alpha1.ACMECertificateDNS01Config
	if cfg = crt.Spec.ACME.ConfigForDomain(domain).DNS01; cfg == nil ||
		cfg.Provider == "" ||
		s.issuer.GetSpec().ACME == nil ||
		s.issuer.GetSpec().ACME.DNS01 == nil {
		return nil, fmt.Errorf("no dns01 config found for domain '%s'", domain)
	}

	providerConfig, err := s.issuer.GetSpec().ACME.DNS01.Provider(cfg.Provider)
	if err != nil {
		return nil, fmt.Errorf("invalid provider config specified for domain '%s': %s", domain, err.Error())
	}

	var impl solver
	switch {
	case providerConfig.CloudDNS != nil:
		saSecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.CloudDNS.ServiceAccount.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting clouddns service account: %s", err.Error())
		}
		saBytes := saSecret.Data[providerConfig.CloudDNS.ServiceAccount.Key]

		impl, err = clouddns.NewDNSProviderServiceAccountBytes(providerConfig.CloudDNS.Project, saBytes)
		if err != nil {
			return nil, fmt.Errorf("error instantiating google clouddns challenge solver: %s", err.Error())
		}
	case providerConfig.Cloudflare != nil:
		apiKeySecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.Cloudflare.APIKey.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting cloudflare service account: %s", err.Error())
		}

		email := providerConfig.Cloudflare.Email
		apiKey := string(apiKeySecret.Data[providerConfig.Cloudflare.APIKey.Key])

		impl, err = cloudflare.NewDNSProviderCredentials(email, apiKey)
		if err != nil {
			return nil, fmt.Errorf("error instantiating cloudflare challenge solver: %s", err.Error())
		}
	case providerConfig.Route53 != nil:
		secretAccessKeySecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.Route53.SecretAccessKey.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting route53 secret access key: %s", err.Error())
		}

		secretAccessKeyBytes, ok := secretAccessKeySecret.Data[providerConfig.Route53.SecretAccessKey.Key]
		if !ok {
			return nil, fmt.Errorf("error getting route53 secret access key: key '%s' not found in secret", providerConfig.Route53.SecretAccessKey.Key)
		}

		impl, err = route53.NewDNSProviderAccessKey(
			providerConfig.Route53.AccessKeyID,
			string(secretAccessKeyBytes),
			providerConfig.Route53.HostedZoneID,
			providerConfig.Route53.Region,
		)
		if err != nil {
			return nil, fmt.Errorf("error instantiating route53 challenge solver: %s", err.Error())
		}
	default:
		return nil, fmt.Errorf("no dns provider config specified for domain '%s'", domain)
	}

	return impl, nil
}

func NewSolver(issuer v1alpha1.GenericIssuer, client kubernetes.Interface, secretLister corev1listers.SecretLister, resourceNamespace string) *Solver {
	return &Solver{issuer, client, secretLister, resourceNamespace}
}
<commit_msg>Log potential errors while waiting for DNS record propagation<commit_after>package dns

import (
	"context"
	"fmt"
	"time"

	"github.com/golang/glog"
	"k8s.io/client-go/kubernetes"
	corev1listers "k8s.io/client-go/listers/core/v1"

	"github.com/jetstack/cert-manager/pkg/apis/certmanager/v1alpha1"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/clouddns"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/cloudflare"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/route53"
	"github.com/jetstack/cert-manager/pkg/issuer/acme/dns/util"
)

const (
	cloudDNSServiceAccountKey = "service-account.json"
)

type solver interface {
	Present(domain, token, key string) error
	CleanUp(domain, token, key string) error
	Timeout() (timeout, interval time.Duration)
}

type Solver struct {
	issuer            v1alpha1.GenericIssuer
	client            kubernetes.Interface
	secretLister      corev1listers.SecretLister
	resourceNamespace string
}

func (s *Solver) Present(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}
	glog.V(4).Infof("Presenting DNS01 challenge for domain %q", domain)
	return slv.Present(domain, token, key)
}

func (s *Solver) Wait(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}

	type boolErr struct {
		bool
		error
	}

	fqdn, value, ttl := util.DNS01Record(domain, key)

	glog.V(4).Infof("Checking DNS propagation for %q using name servers: %v", domain, util.RecursiveNameservers)

	timeout, interval := slv.Timeout()
	ctx, cancel := context.WithTimeout(ctx, timeout)
	defer cancel()
	for {
		select {
		case r := <-func() <-chan boolErr {
			out := make(chan boolErr, 1)
			go func() {
				defer close(out)
				ok, err := util.PreCheckDNS(fqdn, value)
				out <- boolErr{ok, err}
			}()
			return out
		}():

			if r.error != nil {
				glog.Warningf("Failed to check for DNS propagation of %q: %v", domain, r.error)
			} else if r.bool {
				// TODO: move this to somewhere else
				// TODO: make this wait for whatever the record *was*, not is now
				glog.V(4).Infof("Waiting DNS record TTL (%ds) to allow propagation for propagation of DNS record for domain %q", ttl, fqdn)
				time.Sleep(time.Second * time.Duration(ttl))
				glog.V(4).Infof("ACME DNS01 validation record propagated for %q", fqdn)
				return nil
			} else {
				glog.V(4).Infof("DNS record for %q not yet propagated", domain)
			}
			time.Sleep(interval)
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}

func (s *Solver) CleanUp(ctx context.Context, crt *v1alpha1.Certificate, domain, token, key string) error {
	slv, err := s.solverFor(crt, domain)
	if err != nil {
		return err
	}
	return slv.CleanUp(domain, token, key)
}

func (s *Solver) solverFor(crt *v1alpha1.Certificate, domain string) (solver, error) {
	var cfg *v1alpha1.ACMECertificateDNS01Config
	if cfg = crt.Spec.ACME.ConfigForDomain(domain).DNS01; cfg == nil ||
		cfg.Provider == "" ||
		s.issuer.GetSpec().ACME == nil ||
		s.issuer.GetSpec().ACME.DNS01 == nil {
		return nil, fmt.Errorf("no dns01 config found for domain '%s'", domain)
	}

	providerConfig, err := s.issuer.GetSpec().ACME.DNS01.Provider(cfg.Provider)
	if err != nil {
		return nil, fmt.Errorf("invalid provider config specified for domain '%s': %s", domain, err.Error())
	}

	var impl solver
	switch {
	case providerConfig.CloudDNS != nil:
		saSecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.CloudDNS.ServiceAccount.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting clouddns service account: %s", err.Error())
		}
		saBytes := saSecret.Data[providerConfig.CloudDNS.ServiceAccount.Key]

		impl, err = clouddns.NewDNSProviderServiceAccountBytes(providerConfig.CloudDNS.Project, saBytes)
		if err != nil {
			return nil, fmt.Errorf("error instantiating google clouddns challenge solver: %s", err.Error())
		}
	case providerConfig.Cloudflare != nil:
		apiKeySecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.Cloudflare.APIKey.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting cloudflare service account: %s", err.Error())
		}

		email := providerConfig.Cloudflare.Email
		apiKey := string(apiKeySecret.Data[providerConfig.Cloudflare.APIKey.Key])

		impl, err = cloudflare.NewDNSProviderCredentials(email, apiKey)
		if err != nil {
			return nil, fmt.Errorf("error instantiating cloudflare challenge solver: %s", err.Error())
		}
	case providerConfig.Route53 != nil:
		secretAccessKeySecret, err := s.secretLister.Secrets(s.resourceNamespace).Get(providerConfig.Route53.SecretAccessKey.Name)
		if err != nil {
			return nil, fmt.Errorf("error getting route53 secret access key: %s", err.Error())
		}

		secretAccessKeyBytes, ok := secretAccessKeySecret.Data[providerConfig.Route53.SecretAccessKey.Key]
		if !ok {
			return nil, fmt.Errorf("error getting route53 secret access key: key '%s' not found in secret", providerConfig.Route53.SecretAccessKey.Key)
		}

		impl, err = route53.NewDNSProviderAccessKey(
			providerConfig.Route53.AccessKeyID,
			string(secretAccessKeyBytes),
			providerConfig.Route53.HostedZoneID,
			providerConfig.Route53.Region,
		)
		if err != nil {
			return nil, fmt.Errorf("error instantiating route53 challenge solver: %s", err.Error())
		}
	default:
		return nil, fmt.Errorf("no dns provider config specified for domain '%s'", domain)
	}

	return impl, nil
}

func NewSolver(issuer v1alpha1.GenericIssuer, client kubernetes.Interface, secretLister corev1listers.SecretLister, resourceNamespace string) *Solver {
	return &Solver{issuer, client, secretLister, resourceNamespace}
}
<|endoftext|>


<commit_before>package cmd

import (
	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
)

var deleteCmd = &cobra.Command{
	Use:   "delete",
	Short: "Delete simulation in Hoverfly",
	Long: `
Will delete simulation from Hoverfly.
`,

	Run: func(cmd *cobra.Command, args []string) {
		err := hoverfly.DeleteSimulations()
		handleIfError(err)

		log.Info("Simulations have been deleted from Hoverfly")
	},
}

func init() {
	RootCmd.AddCommand(deleteCmd)
}
<commit_msg>Update delete.go<commit_after>package cmd

import (
	log "github.com/Sirupsen/logrus"
	"github.com/spf13/cobra"
)

var deleteCmd = &cobra.Command{
	Use:   "delete",
	Short: "Delete Hoverfly simulation",
	Long: `
Deletes simulation data from the Hoverfly instance.
`,

	Run: func(cmd *cobra.Command, args []string) {
		err := hoverfly.DeleteSimulations()
		handleIfError(err)

		log.Info("Simulation data has been deleted from Hoverfly")
	},
}

func init() {
	RootCmd.AddCommand(deleteCmd)
}
<|endoftext|>


<commit_before>package comfoserver

import (
	"fmt"
	"net"
	"strings"

	rpc "github.com/ti-mo/comfo/rpc/comfo"
	"github.com/twitchtv/twirp"
)

// modifySpeed takes the unit's original speed (baseSpeed) and a protobuf FanSpeedTarget.
// Based on the target a new fan speed is returned between 1 and 4.
func modifySpeed(baseSpeed uint8, target *rpc.FanSpeedTarget) (tgtSpeed uint8, err error) {

	// Unit has 4 speed settings
	// 0 means auto, we don't use it
	var lowerBound uint8 = 1
	var upperBound uint8 = 4

	// Make sure only one of Abs and Rel is set
	if target.Abs != 0 && target.Rel != "" {
		return 0, twirp.InvalidArgumentError("Abs/Rel", errBothAbsRel.Error())
	} else if target.Abs == 0 && target.Rel == "" {
		return 0, twirp.InvalidArgumentError("Abs/Rel", errNoneAbsRel.Error())
	}

	// Determine Abs/Rel speed and target speed
	if target.Abs != 0 {
		tgtSpeed = uint8(target.Abs)
	} else if target.Rel != "" {
		if target.Rel == "+" {
			tgtSpeed = baseSpeed + 1
		} else if target.Rel == "-" {
			tgtSpeed = baseSpeed - 1
		} else {
			return 0, twirp.InvalidArgumentError("Rel", fmt.Sprintf("unknown value '%v'", target.Rel))
		}
	}

	// Bounds check
	if tgtSpeed < lowerBound || tgtSpeed > upperBound {
		return baseSpeed, twirp.InvalidArgumentError("FanSpeed", fmt.Sprintf("value '%v' out of range", tgtSpeed))
	}

	return
}

// ifaceAddrs returns a list of ipv4 and ipv6 addresses of the host.
func ifaceAddrs() (v4 []net.IP, v6 []net.IP) {

	// Get system interface addresses
	ifaces, _ := net.InterfaceAddrs()

	for _, i := range ifaces {
		ip, _, _ := net.ParseCIDR(i.String())

		if ip != nil && strings.Contains(ip.String(), ":") {
			v6 = append(v6, ip)
		} else {
			v4 = append(v4, ip)
		}
	}

	return
}

// printEndpoints prints a list of addresses the API is reachable on.
func printEndpoints(port string) {

	// Get host interface addresses
	v4, v6 := ifaceAddrs()

	fmt.Println("\nAPI listening on following endpoints:")

	fmt.Println("   IPv4:")
	for _, a := range v4 {
		fmt.Printf("    - http://%s:%s\n", a, port)
	}
	fmt.Println()

	fmt.Println("   IPv6:")
	for _, a := range v6 {
		fmt.Printf("    - http://[%s]:%s\n", a, port)
	}
	fmt.Println()
}
<commit_msg>comfoserver/helpers - remove unused printEndpoints and ifaceAddrs funcs<commit_after>package comfoserver

import (
	"fmt"

	rpc "github.com/ti-mo/comfo/rpc/comfo"
	"github.com/twitchtv/twirp"
)

// modifySpeed takes the unit's original speed (baseSpeed) and a protobuf FanSpeedTarget.
// Based on the target a new fan speed is returned between 1 and 4.
func modifySpeed(baseSpeed uint8, target *rpc.FanSpeedTarget) (tgtSpeed uint8, err error) {

	// Unit has 4 speed settings
	// 0 means auto, we don't use it
	var lowerBound uint8 = 1
	var upperBound uint8 = 4

	// Make sure only one of Abs and Rel is set
	if target.Abs != 0 && target.Rel != "" {
		return 0, twirp.InvalidArgumentError("Abs/Rel", errBothAbsRel.Error())
	} else if target.Abs == 0 && target.Rel == "" {
		return 0, twirp.InvalidArgumentError("Abs/Rel", errNoneAbsRel.Error())
	}

	// Determine Abs/Rel speed and target speed
	if target.Abs != 0 {
		tgtSpeed = uint8(target.Abs)
	} else if target.Rel != "" {
		if target.Rel == "+" {
			tgtSpeed = baseSpeed + 1
		} else if target.Rel == "-" {
			tgtSpeed = baseSpeed - 1
		} else {
			return 0, twirp.InvalidArgumentError("Rel", fmt.Sprintf("unknown value '%v'", target.Rel))
		}
	}

	// Bounds check
	if tgtSpeed < lowerBound || tgtSpeed > upperBound {
		return baseSpeed, twirp.InvalidArgumentError("FanSpeed", fmt.Sprintf("value '%v' out of range", tgtSpeed))
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
)

var pubAddr = flag.String("pubAddr", ":8080", "Address on which to serve public requests")
var apiAddr = flag.String("apiAddr", ":8081", "Address on which to receive reload requests")
var mongoUrl = flag.String("mongoUrl", "localhost", "Address of mongo cluster (e.g. 'mongo1,mongo2,mongo3')")
var mongoDbName = flag.String("mongoDbName", "router", "Name of mongo database to use")

var quit = make(chan int)

func main() {
	flag.Parse()

	rout := NewRouter(*mongoUrl, *mongoDbName)
	rout.ReloadRoutes()

	log.Println("router: listening for requests on " + *pubAddr)
	log.Println("router: listening for refresh on " + *apiAddr)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.NotFound(w, r)
			return
		}

		rout.ReloadRoutes()
	})

	go http.ListenAndServe(*pubAddr, rout)
	go http.ListenAndServe(*apiAddr, nil)

	<-quit
}
<commit_msg>Use all available cores in the router program<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"runtime"
)

var pubAddr = flag.String("pubAddr", ":8080", "Address on which to serve public requests")
var apiAddr = flag.String("apiAddr", ":8081", "Address on which to receive reload requests")
var mongoUrl = flag.String("mongoUrl", "localhost", "Address of mongo cluster (e.g. 'mongo1,mongo2,mongo3')")
var mongoDbName = flag.String("mongoDbName", "router", "Name of mongo database to use")

var quit = make(chan int)

func main() {
	// Use all available cores
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Parse()

	rout := NewRouter(*mongoUrl, *mongoDbName)
	rout.ReloadRoutes()

	log.Println("router: listening for requests on " + *pubAddr)
	log.Println("router: listening for refresh on " + *apiAddr)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.NotFound(w, r)
			return
		}

		rout.ReloadRoutes()
	})

	go http.ListenAndServe(*pubAddr, rout)
	go http.ListenAndServe(*apiAddr, nil)

	<-quit
}
<|endoftext|>


<commit_before>package bitfield

import "math"

// BitField type
type BitField []byte

// New returns a new BitField of at least n bits, all 0s
func New(n int) BitField {
	n = int(math.Ceil(float64(n) / 8.0))
	return BitField(make([]byte, n))
}

// NewFromUint32 returns a new BitField of 4 bytes, with n initial value
func NewFromUint32(n uint32) BitField {
	b := BitField(make([]byte, 4))
	b[0] = byte(n)
	b[1] = byte(n >> 8)
	b[2] = byte(n >> 16)
	b[3] = byte(n >> 24)
	return b
}

// NewFromUint64 returns a new BitField of 8 bytes, with n initial value
func NewFromUint64(n uint64) BitField {
	b := BitField(make([]byte, 8))
	b[0] = byte(n)
	b[1] = byte(n >> 8)
	b[2] = byte(n >> 16)
	b[3] = byte(n >> 24)
	b[4] = byte(n >> 32)
	b[5] = byte(n >> 40)
	b[6] = byte(n >> 48)
	b[7] = byte(n >> 56)
	return b
}

// Size returns BitField size in bytes (not bits)
func (b BitField) Size() int {
	return len(b)
}

// Set sets bit i to 1
func (b BitField) Set(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] |= (1 << uint(offset))
}

// Clear sets bit i to 0
func (b BitField) Clear(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] &= ^(1 << uint(offset))
}

// Flip toggles the value of bit i
func (b BitField) Flip(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] ^= (1 << uint(offset))
}

// Test returns true/false on bit i value
func (b BitField) Test(i uint32) bool {
	idx, offset := (i / 8), (i % 8)
	return (b[idx] & (1 << uint(offset))) != 0
}

// ClearAll sets all BitField values to 0
func (b BitField) ClearAll() {
	for idx := range b {
		b[idx] = 0
	}
}

// SetAll sets all BitField bits to 1
func (b BitField) SetAll() {
	for idx := range b {
		b[idx] = 0xff
	}
}

// FlipAll flips all the BitField bits (1's compliment)
func (b BitField) FlipAll() {
	for idx := range b {
		b[idx] = ^b[idx]
	}
}

// ANDMask performs an AND operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) ANDMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be 0 on AND
		if idx > maxidx {
			b[idx] = 0
			continue
		}
		b[idx] &= m[idx]
	}
}

// ORMask performs an OR operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) ORMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be b on OR
		if idx > maxidx {
			break
		}
		b[idx] |= m[idx]
	}
}

// XORMask performs an XOR operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) XORMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be b on XOR
		if idx > maxidx {
			break
		}
		b[idx] ^= m[idx]
	}
}

// ToUint32 returns the lowest 4 bytes as a uint32
// NO BOUNDS CHECKING, ENSURE BitField is at least 4 bytes long
func (b BitField) ToUint32() uint32 {
	var r uint32
	r |= uint32(b[0])
	r |= uint32(b[1]) << 8
	r |= uint32(b[2]) << 16
	r |= uint32(b[3]) << 24
	return r
}

// ToUint32Safe returns the lowest 4 bytes as a uint32
func (b BitField) ToUint32Safe() uint32 {
	var r uint32
	for idx := range b {
		r |= uint32(b[idx]) << uint32(idx*8)
		if idx == 3 {
			break
		}
	}
	return r
}

// ToUint64 returns the lowest 8 bytes as a uint64
// NO BOUNDS CHECKING, ENSURE BitField is at least 8 bytes long
func (b BitField) ToUint64() uint64 {
	var r uint64
	r |= uint64(b[0])
	r |= uint64(b[1]) << 8
	r |= uint64(b[2]) << 16
	r |= uint64(b[3]) << 24
	r |= uint64(b[4]) << 32
	r |= uint64(b[5]) << 40
	r |= uint64(b[6]) << 48
	r |= uint64(b[7]) << 56
	return r
}

// ToUint64Safe returns the lowest 8 bytes as a uint64
func (b BitField) ToUint64Safe() uint64 {
	var r uint64
	for idx := range b {
		r |= uint64(b[idx]) << uint64(idx*8)
		if idx == 7 {
			break
		}
	}
	return r
}
<commit_msg>Updated, constructor without Ceil or float casting<commit_after>package bitfield

// BitField type
type BitField []byte

// New returns a new BitField of at least n bits, all 0s
func New(n int) BitField {
	size = 1 + ((n - 1) / 8) // Ceiling of the division
	return BitField(make([]byte, size))
}

// NewFromUint32 returns a new BitField of 4 bytes, with n initial value
func NewFromUint32(n uint32) BitField {
	b := BitField(make([]byte, 4))
	b[0] = byte(n)
	b[1] = byte(n >> 8)
	b[2] = byte(n >> 16)
	b[3] = byte(n >> 24)
	return b
}

// NewFromUint64 returns a new BitField of 8 bytes, with n initial value
func NewFromUint64(n uint64) BitField {
	b := BitField(make([]byte, 8))
	b[0] = byte(n)
	b[1] = byte(n >> 8)
	b[2] = byte(n >> 16)
	b[3] = byte(n >> 24)
	b[4] = byte(n >> 32)
	b[5] = byte(n >> 40)
	b[6] = byte(n >> 48)
	b[7] = byte(n >> 56)
	return b
}

// Size returns BitField size in bytes (not bits)
func (b BitField) Size() int {
	return len(b)
}

// Set sets bit i to 1
func (b BitField) Set(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] |= (1 << uint(offset))
}

// Clear sets bit i to 0
func (b BitField) Clear(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] &= ^(1 << uint(offset))
}

// Flip toggles the value of bit i
func (b BitField) Flip(i uint32) {
	idx, offset := (i / 8), (i % 8)
	b[idx] ^= (1 << uint(offset))
}

// Test returns true/false on bit i value
func (b BitField) Test(i uint32) bool {
	idx, offset := (i / 8), (i % 8)
	return (b[idx] & (1 << uint(offset))) != 0
}

// ClearAll sets all BitField values to 0
func (b BitField) ClearAll() {
	for idx := range b {
		b[idx] = 0
	}
}

// SetAll sets all BitField bits to 1
func (b BitField) SetAll() {
	for idx := range b {
		b[idx] = 0xff
	}
}

// FlipAll flips all the BitField bits (1's compliment)
func (b BitField) FlipAll() {
	for idx := range b {
		b[idx] = ^b[idx]
	}
}

// ANDMask performs an AND operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) ANDMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be 0 on AND
		if idx > maxidx {
			b[idx] = 0
			continue
		}
		b[idx] &= m[idx]
	}
}

// ORMask performs an OR operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) ORMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be b on OR
		if idx > maxidx {
			break
		}
		b[idx] |= m[idx]
	}
}

// XORMask performs an XOR operation between b and m, storing result in b.
// If b is smaller than m, the extra bits of m are ignored (b isn't enlarged).
func (b BitField) XORMask(m BitField) {
	maxidx := len(m)
	for idx := range b {
		// B is longer than mask, everything else should be b on XOR
		if idx > maxidx {
			break
		}
		b[idx] ^= m[idx]
	}
}

// ToUint32 returns the lowest 4 bytes as a uint32
// NO BOUNDS CHECKING, ENSURE BitField is at least 4 bytes long
func (b BitField) ToUint32() uint32 {
	var r uint32
	r |= uint32(b[0])
	r |= uint32(b[1]) << 8
	r |= uint32(b[2]) << 16
	r |= uint32(b[3]) << 24
	return r
}

// ToUint32Safe returns the lowest 4 bytes as a uint32
func (b BitField) ToUint32Safe() uint32 {
	var r uint32
	for idx := range b {
		r |= uint32(b[idx]) << uint32(idx*8)
		if idx == 3 {
			break
		}
	}
	return r
}

// ToUint64 returns the lowest 8 bytes as a uint64
// NO BOUNDS CHECKING, ENSURE BitField is at least 8 bytes long
func (b BitField) ToUint64() uint64 {
	var r uint64
	r |= uint64(b[0])
	r |= uint64(b[1]) << 8
	r |= uint64(b[2]) << 16
	r |= uint64(b[3]) << 24
	r |= uint64(b[4]) << 32
	r |= uint64(b[5]) << 40
	r |= uint64(b[6]) << 48
	r |= uint64(b[7]) << 56
	return r
}

// ToUint64Safe returns the lowest 8 bytes as a uint64
func (b BitField) ToUint64Safe() uint64 {
	var r uint64
	for idx := range b {
		r |= uint64(b[idx]) << uint64(idx*8)
		if idx == 7 {
			break
		}
	}
	return r
}
<|endoftext|>


<commit_before>package spscq

import (
	"errors"
	"fmt"
	"github.com/fmstephe/flib/fmath"
	"github.com/fmstephe/flib/fsync/fatomic"
	"github.com/fmstephe/flib/fsync/padded"
	"github.com/fmstephe/flib/ftime"
	"sync/atomic"
)

const maxSize = 1 << 41

type commonQ struct {
	// Readonly Fields
	size       int64
	mask       int64
	pause      int64
	_ropadding padded.CacheBuffer
	// Writer fields
	write        padded.Int64
	writeSize    padded.Int64
	failedWrites padded.Int64
	readCache    padded.Int64
	// Reader fields
	read        padded.Int64
	readSize    padded.Int64
	failedReads padded.Int64
	writeCache  padded.Int64
}

func newCommonQ(size, pause int64) (commonQ, error) {
	var cq commonQ
	if !fmath.PowerOfTwo(size) {
		return cq, errors.New(fmt.Sprintf("Size (%d) must be a power of two", size))
	}
	if size > maxSize {
		return cq, errors.New(fmt.Sprintf("Size (%d) must be less than %d", size, maxSize))
	}
	return commonQ{size: size, mask: size - 1, pause: pause}, nil
}

func (q *commonQ) acquireWrite(bufferSize int64) (from int64, to int64) {
	write := q.write.Value
	from = write & q.mask
	bufferSize = fmath.Min(bufferSize, q.size-from)
	writeTo := write + bufferSize
	readLimit := writeTo - q.size
	to = from + bufferSize
	if readLimit > q.readCache.Value {
		q.readCache.Value = atomic.LoadInt64(&q.read.Value)
		if readLimit > q.readCache.Value {
			to = q.readCache.Value & q.mask
		}
	}
	if from == to {
		q.failedWrites.Value++
		ftime.Pause(q.pause)
	}
	q.writeSize.Value = to - from
	return from, to
}

func (q *commonQ) ReleaseWrite() {
	atomic.AddInt64(&q.write.Value, q.writeSize.Value)
	q.writeSize.Value = 0
}

func (q *commonQ) ReleaseWriteLazy() {
	fatomic.LazyStore(&q.write.Value, q.write.Value+q.writeSize.Value)
	q.writeSize.Value = 0
}

func (q *commonQ) acquireRead(bufferSize int64) (from int64, to int64) {
	read := q.read.Value
	from = read & q.mask
	bufferSize = fmath.Min(bufferSize, q.size-from)
	readTo := read + bufferSize
	to = from + bufferSize
	if readTo > q.writeCache.Value {
		q.writeCache.Value = atomic.LoadInt64(&q.write.Value)
		if readTo > q.writeCache.Value {
			to = q.writeCache.Value & q.mask
		}
	}
	if from == to {
		q.failedReads.Value++
		ftime.Pause(q.pause)
	}
	q.readSize.Value = to - from
	return from, to
}

func (q *commonQ) ReleaseRead() {
	atomic.AddInt64(&q.read.Value, q.readSize.Value)
	q.readSize.Value = 0
}

func (q *commonQ) ReleaseReadLazy() {
	fatomic.LazyStore(&q.read.Value, q.read.Value+q.readSize.Value)
	q.readSize.Value = 0
}

func (q *commonQ) writeWrappingBuffer(bufferSize int64) (from int64, to int64, wrap int64) {
	writeTo := q.write.Value + bufferSize
	readLimit := writeTo - q.size
	if readLimit > q.readCache.Value {
		q.readCache.Value = atomic.LoadInt64(&q.read.Value)
		if readLimit > q.readCache.Value {
			q.failedWrites.Value++
			ftime.Pause(q.pause)
			return 0, 0, 0
		}
	}
	from = q.write.Value & q.mask
	to = fmath.Min(from+bufferSize, q.size)
	wrap = bufferSize - (to - from)
	return from, to, wrap
}

func (q *commonQ) readWrappingBuffer(bufferSize int64) (from int64, to int64, wrap int64) {
	readTo := q.read.Value + bufferSize
	if readTo > q.writeCache.Value {
		q.writeCache.Value = atomic.LoadInt64(&q.write.Value)
		if readTo > q.writeCache.Value {
			q.failedReads.Value++
			ftime.Pause(q.pause)
			return 0, 0, 0
		}
	}
	from = q.read.Value & q.mask
	to = fmath.Min(from+bufferSize, q.size)
	wrap = bufferSize - (to - from)
	return from, to, wrap
}

func (q *commonQ) FailedWrites() int64 {
	return atomic.LoadInt64(&q.failedWrites.Value)
}

func (q *commonQ) FailedReads() int64 {
	return atomic.LoadInt64(&q.failedReads.Value)
}

func (q *commonQ) String() string {
	msg := "{Size %d, mask %d, write %d, writeSize %d, failedWrites %d, readCache %d, read %d, readSize %d, failedReads %d, writeCache %d}"
	size := q.size
	mask := q.mask
	write := q.write.Value
	writeSize := q.writeSize.Value
	failedWrites := q.failedWrites.Value
	readCache := q.readCache.Value
	read := q.read.Value
	readSize := q.readSize.Value
	failedReads := q.failedReads.Value
	writeCache := q.writeCache.Value
	return fmt.Sprintf(msg, size, mask, write, writeSize, failedWrites, readCache, read, readSize, failedReads, writeCache)
}
<commit_msg>Removed unnecessary _ropadding field from commonQ<commit_after>package spscq

import (
	"errors"
	"fmt"
	"sync/atomic"

	"github.com/fmstephe/flib/fmath"
	"github.com/fmstephe/flib/fsync/fatomic"
	"github.com/fmstephe/flib/fsync/padded"
	"github.com/fmstephe/flib/ftime"
)

const maxSize = 1 << 41

type commonQ struct {
	// Readonly Fields
	size  int64
	mask  int64
	pause int64
	// Writer fields
	write        padded.Int64
	writeSize    padded.Int64
	failedWrites padded.Int64
	readCache    padded.Int64
	// Reader fields
	read        padded.Int64
	readSize    padded.Int64
	failedReads padded.Int64
	writeCache  padded.Int64
}

func newCommonQ(size, pause int64) (commonQ, error) {
	var cq commonQ
	if !fmath.PowerOfTwo(size) {
		return cq, errors.New(fmt.Sprintf("Size (%d) must be a power of two", size))
	}
	if size > maxSize {
		return cq, errors.New(fmt.Sprintf("Size (%d) must be less than %d", size, maxSize))
	}
	return commonQ{size: size, mask: size - 1, pause: pause}, nil
}

func (q *commonQ) acquireWrite(bufferSize int64) (from int64, to int64) {
	write := q.write.Value
	from = write & q.mask
	bufferSize = fmath.Min(bufferSize, q.size-from)
	writeTo := write + bufferSize
	readLimit := writeTo - q.size
	to = from + bufferSize
	if readLimit > q.readCache.Value {
		q.readCache.Value = atomic.LoadInt64(&q.read.Value)
		if readLimit > q.readCache.Value {
			to = q.readCache.Value & q.mask
		}
	}
	if from == to {
		q.failedWrites.Value++
		ftime.Pause(q.pause)
	}
	q.writeSize.Value = to - from
	return from, to
}

func (q *commonQ) ReleaseWrite() {
	atomic.AddInt64(&q.write.Value, q.writeSize.Value)
	q.writeSize.Value = 0
}

func (q *commonQ) ReleaseWriteLazy() {
	fatomic.LazyStore(&q.write.Value, q.write.Value+q.writeSize.Value)
	q.writeSize.Value = 0
}

func (q *commonQ) acquireRead(bufferSize int64) (from int64, to int64) {
	read := q.read.Value
	from = read & q.mask
	bufferSize = fmath.Min(bufferSize, q.size-from)
	readTo := read + bufferSize
	to = from + bufferSize
	if readTo > q.writeCache.Value {
		q.writeCache.Value = atomic.LoadInt64(&q.write.Value)
		if readTo > q.writeCache.Value {
			to = q.writeCache.Value & q.mask
		}
	}
	if from == to {
		q.failedReads.Value++
		ftime.Pause(q.pause)
	}
	q.readSize.Value = to - from
	return from, to
}

func (q *commonQ) ReleaseRead() {
	atomic.AddInt64(&q.read.Value, q.readSize.Value)
	q.readSize.Value = 0
}

func (q *commonQ) ReleaseReadLazy() {
	fatomic.LazyStore(&q.read.Value, q.read.Value+q.readSize.Value)
	q.readSize.Value = 0
}

func (q *commonQ) writeWrappingBuffer(bufferSize int64) (from int64, to int64, wrap int64) {
	writeTo := q.write.Value + bufferSize
	readLimit := writeTo - q.size
	if readLimit > q.readCache.Value {
		q.readCache.Value = atomic.LoadInt64(&q.read.Value)
		if readLimit > q.readCache.Value {
			q.failedWrites.Value++
			ftime.Pause(q.pause)
			return 0, 0, 0
		}
	}
	from = q.write.Value & q.mask
	to = fmath.Min(from+bufferSize, q.size)
	wrap = bufferSize - (to - from)
	return from, to, wrap
}

func (q *commonQ) readWrappingBuffer(bufferSize int64) (from int64, to int64, wrap int64) {
	readTo := q.read.Value + bufferSize
	if readTo > q.writeCache.Value {
		q.writeCache.Value = atomic.LoadInt64(&q.write.Value)
		if readTo > q.writeCache.Value {
			q.failedReads.Value++
			ftime.Pause(q.pause)
			return 0, 0, 0
		}
	}
	from = q.read.Value & q.mask
	to = fmath.Min(from+bufferSize, q.size)
	wrap = bufferSize - (to - from)
	return from, to, wrap
}

func (q *commonQ) FailedWrites() int64 {
	return atomic.LoadInt64(&q.failedWrites.Value)
}

func (q *commonQ) FailedReads() int64 {
	return atomic.LoadInt64(&q.failedReads.Value)
}

func (q *commonQ) String() string {
	msg := "{Size %d, mask %d, write %d, writeSize %d, failedWrites %d, readCache %d, read %d, readSize %d, failedReads %d, writeCache %d}"
	size := q.size
	mask := q.mask
	write := q.write.Value
	writeSize := q.writeSize.Value
	failedWrites := q.failedWrites.Value
	readCache := q.readCache.Value
	read := q.read.Value
	readSize := q.readSize.Value
	failedReads := q.failedReads.Value
	writeCache := q.writeCache.Value
	return fmt.Sprintf(msg, size, mask, write, writeSize, failedWrites, readCache, read, readSize, failedReads, writeCache)
}
<|endoftext|>


<commit_before>package aead

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	rand3 "crypto/rand"
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"math"
	"time"
	"v2ray.com/core/common"
	antiReplayWindow "v2ray.com/core/common/antireplay"
)

func CreateAuthID(cmdKey []byte, time int64) [16]byte {
	buf := bytes.NewBuffer(nil)
	common.Must(binary.Write(buf, binary.BigEndian, time))
	var zero uint32
	common.Must2(io.CopyN(buf, rand3.Reader, 4))
	zero = crc32.ChecksumIEEE(buf.Bytes())
	common.Must(binary.Write(buf, binary.BigEndian, zero))
	aesBlock := NewCipherFromKey(cmdKey)
	if buf.Len() != 16 {
		panic("Size unexpected")
	}
	var result [16]byte
	aesBlock.Encrypt(result[:], buf.Bytes())
	return result
}

func NewCipherFromKey(cmdKey []byte) cipher.Block {
	aesBlock, err := aes.NewCipher(KDF16(cmdKey, "AES Auth ID Encryption"))
	if err != nil {
		panic(err)
	}
	return aesBlock
}

type AuthIDDecoder struct {
	s cipher.Block
}

func NewAuthIDDecoder(cmdKey []byte) *AuthIDDecoder {
	return &AuthIDDecoder{NewCipherFromKey(cmdKey)}
}

func (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte) {
	aidd.s.Decrypt(data[:], data[:])
	var t int64
	var zero uint32
	var rand int32
	reader := bytes.NewReader(data[:])
	common.Must(binary.Read(reader, binary.BigEndian, &t))
	common.Must(binary.Read(reader, binary.BigEndian, &rand))
	common.Must(binary.Read(reader, binary.BigEndian, &zero))
	return t, zero, rand, data[:]
}

func NewAuthIDDecoderHolder() *AuthIDDecoderHolder {
	return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antiReplayWindow.NewAntiReplayWindow(120)}
}

type AuthIDDecoderHolder struct {
	aidhi map[string]*AuthIDDecoderItem
	apw   *antiReplayWindow.AntiReplayWindow
}

type AuthIDDecoderItem struct {
	dec    *AuthIDDecoder
	ticket interface{}
}

func NewAuthIDDecoderItem(key [16]byte, ticket interface{}) *AuthIDDecoderItem {
	return &AuthIDDecoderItem{
		dec:    NewAuthIDDecoder(key[:]),
		ticket: ticket,
	}
}

func (a *AuthIDDecoderHolder) AddUser(key [16]byte, ticket interface{}) {
	a.aidhi[string(key[:])] = NewAuthIDDecoderItem(key, ticket)
}

func (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) {
	delete(a.aidhi, string(key[:]))
}

func (a *AuthIDDecoderHolder) Match(AuthID [16]byte) (interface{}, error) {
	for _, v := range a.aidhi {

		t, z, r, d := v.dec.Decode(AuthID)
		if z != crc32.ChecksumIEEE(d[:12]) {
			continue
		}

		if math.Abs(float64(t-time.Now().Unix())) > 120 {
			continue
		}

		if !a.apw.Check(AuthID[:]) {
			return nil, ErrReplay
		}

		_ = r

		return v.ticket, nil

	}
	return nil, ErrNotFound
}

var ErrNotFound = errors.New("user do not exist")

var ErrReplay = errors.New("replayed request")
<commit_msg>Reserve sign bit<commit_after>package aead

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	rand3 "crypto/rand"
	"encoding/binary"
	"errors"
	"hash/crc32"
	"io"
	"math"
	"time"
	"v2ray.com/core/common"
	antiReplayWindow "v2ray.com/core/common/antireplay"
)

func CreateAuthID(cmdKey []byte, time int64) [16]byte {
	buf := bytes.NewBuffer(nil)
	common.Must(binary.Write(buf, binary.BigEndian, time))
	var zero uint32
	common.Must2(io.CopyN(buf, rand3.Reader, 4))
	zero = crc32.ChecksumIEEE(buf.Bytes())
	common.Must(binary.Write(buf, binary.BigEndian, zero))
	aesBlock := NewCipherFromKey(cmdKey)
	if buf.Len() != 16 {
		panic("Size unexpected")
	}
	var result [16]byte
	aesBlock.Encrypt(result[:], buf.Bytes())
	return result
}

func NewCipherFromKey(cmdKey []byte) cipher.Block {
	aesBlock, err := aes.NewCipher(KDF16(cmdKey, "AES Auth ID Encryption"))
	if err != nil {
		panic(err)
	}
	return aesBlock
}

type AuthIDDecoder struct {
	s cipher.Block
}

func NewAuthIDDecoder(cmdKey []byte) *AuthIDDecoder {
	return &AuthIDDecoder{NewCipherFromKey(cmdKey)}
}

func (aidd *AuthIDDecoder) Decode(data [16]byte) (int64, uint32, int32, []byte) {
	aidd.s.Decrypt(data[:], data[:])
	var t int64
	var zero uint32
	var rand int32
	reader := bytes.NewReader(data[:])
	common.Must(binary.Read(reader, binary.BigEndian, &t))
	common.Must(binary.Read(reader, binary.BigEndian, &rand))
	common.Must(binary.Read(reader, binary.BigEndian, &zero))
	return t, zero, rand, data[:]
}

func NewAuthIDDecoderHolder() *AuthIDDecoderHolder {
	return &AuthIDDecoderHolder{make(map[string]*AuthIDDecoderItem), antiReplayWindow.NewAntiReplayWindow(120)}
}

type AuthIDDecoderHolder struct {
	aidhi map[string]*AuthIDDecoderItem
	apw   *antiReplayWindow.AntiReplayWindow
}

type AuthIDDecoderItem struct {
	dec    *AuthIDDecoder
	ticket interface{}
}

func NewAuthIDDecoderItem(key [16]byte, ticket interface{}) *AuthIDDecoderItem {
	return &AuthIDDecoderItem{
		dec:    NewAuthIDDecoder(key[:]),
		ticket: ticket,
	}
}

func (a *AuthIDDecoderHolder) AddUser(key [16]byte, ticket interface{}) {
	a.aidhi[string(key[:])] = NewAuthIDDecoderItem(key, ticket)
}

func (a *AuthIDDecoderHolder) RemoveUser(key [16]byte) {
	delete(a.aidhi, string(key[:]))
}

func (a *AuthIDDecoderHolder) Match(AuthID [16]byte) (interface{}, error) {
	for _, v := range a.aidhi {

		t, z, r, d := v.dec.Decode(AuthID)
		if z != crc32.ChecksumIEEE(d[:12]) {
			continue
		}

		if t < 0 {
			continue
		}

		if math.Abs(math.Abs(float64(t))-float64(time.Now().Unix())) > 120 {
			continue
		}

		if !a.apw.Check(AuthID[:]) {
			return nil, ErrReplay
		}

		_ = r

		return v.ticket, nil

	}
	return nil, ErrNotFound
}

var ErrNotFound = errors.New("user do not exist")

var ErrReplay = errors.New("replayed request")
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"

	k8sProwConfig "k8s.io/test-infra/prow/config"

	"istio.io/test-infra/tools/prowgen/pkg"
)

var (
	// regex to match the test image tags.
	tagRegex = regexp.MustCompile(`^(.+):(.+)-([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2})$`)

	inputDir            = flag.String("input-dir", "./prow/config/jobs", "directory of input jobs")
	outputDir           = flag.String("output-dir", "./prow/cluster/jobs", "directory of output jobs")
	longJobNamesAllowed = flag.Bool("allow-long-job-names", false, "allow job names that are longer than 63 characters")
)

func exit(err error, context string) {
	if context == "" {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
	} else {
		_, _ = fmt.Fprintf(os.Stderr, "%v: %v\n", context, err)
	}
	os.Exit(1)
}

func getFileName(repo string, org string, branch string) string {
	key := fmt.Sprintf("%s.%s.%s.gen.yaml", org, repo, branch)
	return path.Join(*outputDir, org, repo, key)
}

func main() {
	flag.Parse()

	// TODO: deserves a better CLI...
	if len(flag.Args()) < 1 {
		panic("must provide one of write, diff, print, branch")
	} else if flag.Arg(0) == "branch" {
		if len(flag.Args()) != 2 {
			panic("must specify branch name")
		}
	} else if len(flag.Args()) != 1 {
		panic("too many arguments")
	}

	var bc *pkg.BaseConfig
	if _, err := os.Stat(filepath.Join(*inputDir, ".base.yaml")); !os.IsNotExist(err) {
		bc = pkg.ReadBase(nil, filepath.Join(*inputDir, ".base.yaml"))
	}

	if os.Args[1] == "branch" {
		if err := filepath.WalkDir(*inputDir, func(path string, d os.DirEntry, err error) error {
			if !d.IsDir() {
				return nil
			}
			if err != nil {
				fmt.Printf("error: %s\n", err.Error())
			}
			baseConfig := bc
			if _, err := os.Stat(filepath.Join(path, ".base.yaml")); !os.IsNotExist(err) {
				baseConfig = pkg.ReadBase(baseConfig, filepath.Join(path, ".base.yaml"))
			}
			cli := pkg.Client{BaseConfig: *baseConfig, LongJobNamesAllowed: *longJobNamesAllowed}

			files, _ := ioutil.ReadDir(path)
			for _, file := range files {
				if file.IsDir() {
					continue
				}

				if (filepath.Ext(file.Name()) != ".yaml" && filepath.Ext(file.Name()) != ".yml") ||
					file.Name() == ".base.yaml" {
					log.Println("skipping", file.Name())
					continue
				}

				src := filepath.Join(path, file.Name())
				jobs := cli.ReadJobsConfig(src)
				jobs.Jobs = pkg.FilterReleaseBranchingJobs(jobs.Jobs)

				if jobs.SupportReleaseBranching {
					match := tagRegex.FindStringSubmatch(jobs.Image)
					branch := "release-" + flag.Arg(1)
					if len(match) == 4 {
						// HACK: replacing the branch name in the image tag and
						// adding it as a new tag.
						// For example, if the test image in the current Prow job
						// config is
						// `gcr.io/istio-testing/build-tools:release-1.10-2021-08-09T16-46-08`,
						// and the Prow job config for release-1.11 branch is
						// supposed to be generated, the image will be added a
						// new `release-1.11-2021-08-09T16-46-08` tag.
						// This is only needed for creating Prow jobs for a new
						// release branch for the first time, and the image tag
						// will be overwritten by Automator the next time the
						// image for the new branch is updated.
						newImage := fmt.Sprintf("%s:%s-%s", match[1], branch, match[3])
						if err := exec.Command("gcloud", "container", "images", "add-tag", match[0], newImage).Run(); err != nil {
							exit(err, "unable to add image tag: "+newImage)
						} else {
							jobs.Image = newImage
						}
					}
					jobs.Branches = []string{branch}
					jobs.SupportReleaseBranching = false

					name := file.Name()
					ext := filepath.Ext(name)
					name = name[:len(name)-len(ext)] + "-" + flag.Arg(1) + ext

					dst := filepath.Join(*inputDir, name)
					if err := pkg.WriteJobConfig(&jobs, dst); err != nil {
						exit(err, "writing branched config failed")
					}
				}
			}

			return nil
		}); err != nil {
			exit(err, "walking through the meta config files failed")
		}
	} else {
		type ref struct {
			org    string
			repo   string
			branch string
		}
		// Store the job config generated from all meta-config files in a cache map, and combine the
		// job configs before we generate the final config files.
		// In this way we can have multiple meta-config files for the same org/repo:branch
		cachedOutput := map[ref]k8sProwConfig.JobConfig{}
		if err := filepath.WalkDir(*inputDir, func(path string, d os.DirEntry, err error) error {
			if !d.IsDir() {
				return nil
			}
			if err != nil {
				fmt.Printf("error: %s\n", err.Error())
			}

			baseConfig := bc
			if _, err := os.Stat(filepath.Join(path, ".base.yaml")); !os.IsNotExist(err) {
				baseConfig = pkg.ReadBase(baseConfig, filepath.Join(path, ".base.yaml"))
			}
			cli := pkg.Client{BaseConfig: *baseConfig}

			files, _ := ioutil.ReadDir(path)
			for _, file := range files {
				if file.IsDir() {
					continue
				}

				if (filepath.Ext(file.Name()) != ".yaml" && filepath.Ext(file.Name()) != ".yml") ||
					file.Name() == ".base.yaml" {
					log.Println("skipping", file.Name())
					continue
				}

				src := filepath.Join(path, file.Name())
				jobs := cli.ReadJobsConfig(src)
				for _, branch := range jobs.Branches {
					cli.ValidateJobConfig(file.Name(), &jobs)
					output, err := cli.ConvertJobConfig(&jobs, branch)
					if err != nil {
						exit(err, "job name is too long")
					}
					rf := ref{jobs.Org, jobs.Repo, branch}
					if _, ok := cachedOutput[rf]; !ok {
						cachedOutput[rf] = output
					} else {
						cachedOutput[rf] = combineJobConfigs(cachedOutput[rf], output,
							fmt.Sprintf("%s/%s", jobs.Org, jobs.Repo))
					}
				}
			}
			return nil
		}); err != nil {
			exit(err, "walking through the meta config files failed")
		}

		for r, output := range cachedOutput {
			fname := getFileName(r.repo, r.org, r.branch)
			switch flag.Arg(0) {
			case "write":
				pkg.Write(output, fname, bc.AutogenHeader)
			case "diff":
				existing := pkg.ReadProwJobConfig(fname)
				pkg.Diff(output, existing)
			default:
				pkg.Print(output)
			}
		}
	}
}

func combineJobConfigs(jc1, jc2 k8sProwConfig.JobConfig, orgRepo string) k8sProwConfig.JobConfig {
	presubmits := jc1.PresubmitsStatic
	postsubmits := jc1.PostsubmitsStatic
	periodics := jc1.Periodics

	presubmits[orgRepo] = append(presubmits[orgRepo], jc2.PresubmitsStatic[orgRepo]...)
	postsubmits[orgRepo] = append(postsubmits[orgRepo], jc2.PostsubmitsStatic[orgRepo]...)
	periodics = append(periodics, jc2.Periodics...)

	return k8sProwConfig.JobConfig{
		PresubmitsStatic:  presubmits,
		PostsubmitsStatic: postsubmits,
		Periodics:         periodics,
	}
}
<commit_msg>Fix the logic to disable checking long job names (#3797)<commit_after>// Copyright 2019 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"

	k8sProwConfig "k8s.io/test-infra/prow/config"

	"istio.io/test-infra/tools/prowgen/pkg"
)

var (
	// regex to match the test image tags.
	tagRegex = regexp.MustCompile(`^(.+):(.+)-([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2})$`)

	inputDir            = flag.String("input-dir", "./prow/config/jobs", "directory of input jobs")
	outputDir           = flag.String("output-dir", "./prow/cluster/jobs", "directory of output jobs")
	longJobNamesAllowed = flag.Bool("allow-long-job-names", false, "allow job names that are longer than 63 characters")
)

func exit(err error, context string) {
	if context == "" {
		_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
	} else {
		_, _ = fmt.Fprintf(os.Stderr, "%v: %v\n", context, err)
	}
	os.Exit(1)
}

func getFileName(repo string, org string, branch string) string {
	key := fmt.Sprintf("%s.%s.%s.gen.yaml", org, repo, branch)
	return path.Join(*outputDir, org, repo, key)
}

func main() {
	flag.Parse()

	// TODO: deserves a better CLI...
	if len(flag.Args()) < 1 {
		panic("must provide one of write, diff, print, branch")
	} else if flag.Arg(0) == "branch" {
		if len(flag.Args()) != 2 {
			panic("must specify branch name")
		}
	} else if len(flag.Args()) != 1 {
		panic("too many arguments")
	}

	var bc *pkg.BaseConfig
	if _, err := os.Stat(filepath.Join(*inputDir, ".base.yaml")); !os.IsNotExist(err) {
		bc = pkg.ReadBase(nil, filepath.Join(*inputDir, ".base.yaml"))
	}

	if os.Args[1] == "branch" {
		if err := filepath.WalkDir(*inputDir, func(path string, d os.DirEntry, err error) error {
			if !d.IsDir() {
				return nil
			}
			if err != nil {
				fmt.Printf("error: %s\n", err.Error())
			}
			baseConfig := bc
			if _, err := os.Stat(filepath.Join(path, ".base.yaml")); !os.IsNotExist(err) {
				baseConfig = pkg.ReadBase(baseConfig, filepath.Join(path, ".base.yaml"))
			}
			cli := pkg.Client{BaseConfig: *baseConfig, LongJobNamesAllowed: *longJobNamesAllowed}

			files, _ := ioutil.ReadDir(path)
			for _, file := range files {
				if file.IsDir() {
					continue
				}

				if (filepath.Ext(file.Name()) != ".yaml" && filepath.Ext(file.Name()) != ".yml") ||
					file.Name() == ".base.yaml" {
					log.Println("skipping", file.Name())
					continue
				}

				src := filepath.Join(path, file.Name())
				jobs := cli.ReadJobsConfig(src)
				jobs.Jobs = pkg.FilterReleaseBranchingJobs(jobs.Jobs)

				if jobs.SupportReleaseBranching {
					match := tagRegex.FindStringSubmatch(jobs.Image)
					branch := "release-" + flag.Arg(1)
					if len(match) == 4 {
						// HACK: replacing the branch name in the image tag and
						// adding it as a new tag.
						// For example, if the test image in the current Prow job
						// config is
						// `gcr.io/istio-testing/build-tools:release-1.10-2021-08-09T16-46-08`,
						// and the Prow job config for release-1.11 branch is
						// supposed to be generated, the image will be added a
						// new `release-1.11-2021-08-09T16-46-08` tag.
						// This is only needed for creating Prow jobs for a new
						// release branch for the first time, and the image tag
						// will be overwritten by Automator the next time the
						// image for the new branch is updated.
						newImage := fmt.Sprintf("%s:%s-%s", match[1], branch, match[3])
						if err := exec.Command("gcloud", "container", "images", "add-tag", match[0], newImage).Run(); err != nil {
							exit(err, "unable to add image tag: "+newImage)
						} else {
							jobs.Image = newImage
						}
					}
					jobs.Branches = []string{branch}
					jobs.SupportReleaseBranching = false

					name := file.Name()
					ext := filepath.Ext(name)
					name = name[:len(name)-len(ext)] + "-" + flag.Arg(1) + ext

					dst := filepath.Join(*inputDir, name)
					if err := pkg.WriteJobConfig(&jobs, dst); err != nil {
						exit(err, "writing branched config failed")
					}
				}
			}

			return nil
		}); err != nil {
			exit(err, "walking through the meta config files failed")
		}
	} else {
		type ref struct {
			org    string
			repo   string
			branch string
		}
		// Store the job config generated from all meta-config files in a cache map, and combine the
		// job configs before we generate the final config files.
		// In this way we can have multiple meta-config files for the same org/repo:branch
		cachedOutput := map[ref]k8sProwConfig.JobConfig{}
		if err := filepath.WalkDir(*inputDir, func(path string, d os.DirEntry, err error) error {
			if !d.IsDir() {
				return nil
			}
			if err != nil {
				fmt.Printf("error: %s\n", err.Error())
			}

			baseConfig := bc
			if _, err := os.Stat(filepath.Join(path, ".base.yaml")); !os.IsNotExist(err) {
				baseConfig = pkg.ReadBase(baseConfig, filepath.Join(path, ".base.yaml"))
			}
			cli := pkg.Client{BaseConfig: *baseConfig, LongJobNamesAllowed: *longJobNamesAllowed}

			files, _ := ioutil.ReadDir(path)
			for _, file := range files {
				if file.IsDir() {
					continue
				}

				if (filepath.Ext(file.Name()) != ".yaml" && filepath.Ext(file.Name()) != ".yml") ||
					file.Name() == ".base.yaml" {
					log.Println("skipping", file.Name())
					continue
				}

				src := filepath.Join(path, file.Name())
				jobs := cli.ReadJobsConfig(src)
				for _, branch := range jobs.Branches {
					cli.ValidateJobConfig(file.Name(), &jobs)
					output, err := cli.ConvertJobConfig(&jobs, branch)
					if err != nil {
						exit(err, "job name is too long")
					}
					rf := ref{jobs.Org, jobs.Repo, branch}
					if _, ok := cachedOutput[rf]; !ok {
						cachedOutput[rf] = output
					} else {
						cachedOutput[rf] = combineJobConfigs(cachedOutput[rf], output,
							fmt.Sprintf("%s/%s", jobs.Org, jobs.Repo))
					}
				}
			}
			return nil
		}); err != nil {
			exit(err, "walking through the meta config files failed")
		}

		for r, output := range cachedOutput {
			fname := getFileName(r.repo, r.org, r.branch)
			switch flag.Arg(0) {
			case "write":
				pkg.Write(output, fname, bc.AutogenHeader)
			case "diff":
				existing := pkg.ReadProwJobConfig(fname)
				pkg.Diff(output, existing)
			default:
				pkg.Print(output)
			}
		}
	}
}

func combineJobConfigs(jc1, jc2 k8sProwConfig.JobConfig, orgRepo string) k8sProwConfig.JobConfig {
	presubmits := jc1.PresubmitsStatic
	postsubmits := jc1.PostsubmitsStatic
	periodics := jc1.Periodics

	presubmits[orgRepo] = append(presubmits[orgRepo], jc2.PresubmitsStatic[orgRepo]...)
	postsubmits[orgRepo] = append(postsubmits[orgRepo], jc2.PostsubmitsStatic[orgRepo]...)
	periodics = append(periodics, jc2.Periodics...)

	return k8sProwConfig.JobConfig{
		PresubmitsStatic:  presubmits,
		PostsubmitsStatic: postsubmits,
		Periodics:         periodics,
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"net"
	"os"
	"os/user"
	"syscall"

	"github.com/juju/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

var logger = loggo.GetLogger("juju.provider.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var providerInstance = &environProvider{}

func init() {
	environs.RegisterProvider(provider.Local, providerInstance)
}

var userCurrent = user.Current

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	if _, ok := cfg.AgentVersion(); !ok {
		newCfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": version.Current.Number.String(),
		})
		if err != nil {
			return nil, err
		}
		cfg = newCfg
	}
	// Set the "namespace" attribute. We do this here, and not in Prepare,
	// for backwards compatibility: older versions did not store the namespace
	// in config.
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, fmt.Errorf("failed to determine username for namespace: %v", err)
			}
			username = u.Username
		}
		var err error
		namespace = fmt.Sprintf("%s-%s", username, cfg.Name())
		cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace})
		if err != nil {
			return nil, fmt.Errorf("failed to create namespace: %v", err)
		}
	}
	// Do the initial validation on the config.
	localConfig, err := providerInstance.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	if err := VerifyPrerequisites(localConfig.container()); err != nil {
		logger.Errorf("failed verification of local provider prerequisites: %v", err)
		return nil, err
	}
	environ := &localEnviron{name: cfg.Name()}
	if err := environ.SetConfig(cfg); err != nil {
		logger.Errorf("failure setting config: %v", err)
		return nil, err
	}
	return environ, nil
}

var detectAptProxies = utils.DetectAptProxies

// Prepare implements environs.EnvironProvider.Prepare.
func (p environProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	// The user must not set bootstrap-ip; this is determined by the provider,
	// and its presence used to determine whether the environment has yet been
	// bootstrapped.
	if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok {
		return nil, fmt.Errorf("bootstrap-ip must not be specified")
	}
	err := checkLocalPort(cfg.StatePort(), "state port")
	if err != nil {
		return nil, err
	}
	err = checkLocalPort(cfg.APIPort(), "API port")
	if err != nil {
		return nil, err
	}
	// If the user has specified no values for any of the three normal
	// proxies, then look in the environment and set them.
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxy := osenv.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxy)
		setIfNotBlank("http-proxy", proxy.Http)
		setIfNotBlank("https-proxy", proxy.Https)
		setIfNotBlank("ftp-proxy", proxy.Ftp)
		setIfNotBlank("no-proxy", proxy.NoProxy)
	}
	if cfg.AptHttpProxy() == "" &&
		cfg.AptHttpsProxy() == "" &&
		cfg.AptFtpProxy() == "" {
		proxy, err := detectAptProxies()
		if err != nil {
			return nil, err
		}
		setIfNotBlank("apt-http-proxy", proxy.Http)
		setIfNotBlank("apt-https-proxy", proxy.Https)
		setIfNotBlank("apt-ftp-proxy", proxy.Ftp)
	}
	if len(attrs) > 0 {
		cfg, err = cfg.Apply(attrs)
		if err != nil {
			return nil, err
		}
	}

	return p.Open(cfg)
}

// checkLocalPort checks that the passed port is not used so far.
var checkLocalPort = func(port int, description string) error {
	logger.Infof("checking %s", description)
	// Try to connect the port on localhost.
	address := fmt.Sprintf("localhost:%d", port)
	// TODO(mue) Add a timeout?
	conn, err := net.Dial("tcp", address)
	if err != nil {
		if nerr, ok := err.(*net.OpError); ok {
			if nerr.Err == syscall.ECONNREFUSED {
				// No connection, so everything is fine.
				return nil
			}
		}
		return err
	}
	// Connected, so port is in use.
	err = conn.Close()
	if err != nil {
		return err
	}
	return fmt.Errorf("cannot use %d as %s, already in use", port, description)
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
	if err != nil {
		logger.Errorf("failed to validate unknown attrs: %v", err)
		return nil, err
	}
	localConfig := newEnvironConfig(cfg, validated)
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	containerType := localConfig.container()
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if containerType != oldLocalConfig.container() {
			return nil, fmt.Errorf("cannot change container from %q to %q",
				oldLocalConfig.container(), containerType)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.networkBridge() != oldLocalConfig.networkBridge() {
			return nil, fmt.Errorf("cannot change network-bridge from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.storagePort() != oldLocalConfig.storagePort() {
			return nil, fmt.Errorf("cannot change storage-port from %v to %v",
				oldLocalConfig.storagePort(),
				localConfig.storagePort())
		}
	}
	// Currently only supported containers are "lxc" and "kvm".
	if containerType != instance.LXC && containerType != instance.KVM {
		return nil, fmt.Errorf("unsupported container type: %q", containerType)
	}
	dir, err := utils.NormalizePath(localConfig.rootDir())
	if err != nil {
		return nil, err
	}
	if dir == "." {
		dir = osenv.JujuHomePath(cfg.Name())
	}
	// Always assign the normalized path.
	localConfig.attrs["root-dir"] = dir

	if containerType != instance.KVM {
		fastOptionAvailable := useFastLXC(containerType)
		if _, found := localConfig.attrs["lxc-clone"]; !found {
			localConfig.attrs["lxc-clone"] = fastOptionAvailable
		}
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
# https://juju.ubuntu.com/docs/config-local.html
local:
    type: local

    # root-dir holds the directory that is used for the storage files and
    # database. The default location is $JUJU_HOME/<env-name>.
    # $JUJU_HOME defaults to ~/.juju. Override if needed.
    #
    # root-dir: ~/.juju/local

    # storage-port holds the port where the local provider starts the
    # HTTP file server. Override the value if you have multiple local
    # providers, or if the default port is used by another program.
    #
    # storage-port: 8040

    # network-bridge holds the name of the LXC network bridge to use.
    # Override if the default LXC network bridge is different.
    #
    #
    # network-bridge: lxcbr0

    # The default series to deploy the state-server and charms on.
    # Make sure to uncomment the following option and set the value to
    # precise or trusty as desired.
    #
    # default-series: precise

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	// don't have any secret attrs
	return nil, nil
}

func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := p.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<commit_msg>remove some repetitive error messages when juju bootstrap<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"net"
	"os"
	"os/user"
	"syscall"

	"github.com/juju/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

var logger = loggo.GetLogger("juju.provider.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var providerInstance = &environProvider{}

func init() {
	environs.RegisterProvider(provider.Local, providerInstance)
}

var userCurrent = user.Current

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	if _, ok := cfg.AgentVersion(); !ok {
		newCfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": version.Current.Number.String(),
		})
		if err != nil {
			return nil, err
		}
		cfg = newCfg
	}
	// Set the "namespace" attribute. We do this here, and not in Prepare,
	// for backwards compatibility: older versions did not store the namespace
	// in config.
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, fmt.Errorf("failed to determine username for namespace: %v", err)
			}
			username = u.Username
		}
		var err error
		namespace = fmt.Sprintf("%s-%s", username, cfg.Name())
		cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace})
		if err != nil {
			return nil, fmt.Errorf("failed to create namespace: %v", err)
		}
	}
	// Do the initial validation on the config.
	localConfig, err := providerInstance.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	if err := VerifyPrerequisites(localConfig.container()); err != nil {
		return nil, fmt.Errorf("failed verification of local provider prerequisites: %v", err)
	}
	environ := &localEnviron{name: cfg.Name()}
	if err := environ.SetConfig(cfg); err != nil {
		return nil, fmt.Errorf("failure setting config: %v", err)
	}
	return environ, nil
}

var detectAptProxies = utils.DetectAptProxies

// Prepare implements environs.EnvironProvider.Prepare.
func (p environProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	// The user must not set bootstrap-ip; this is determined by the provider,
	// and its presence used to determine whether the environment has yet been
	// bootstrapped.
	if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok {
		return nil, fmt.Errorf("bootstrap-ip must not be specified")
	}
	err := checkLocalPort(cfg.StatePort(), "state port")
	if err != nil {
		return nil, err
	}
	err = checkLocalPort(cfg.APIPort(), "API port")
	if err != nil {
		return nil, err
	}
	// If the user has specified no values for any of the three normal
	// proxies, then look in the environment and set them.
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxy := osenv.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxy)
		setIfNotBlank("http-proxy", proxy.Http)
		setIfNotBlank("https-proxy", proxy.Https)
		setIfNotBlank("ftp-proxy", proxy.Ftp)
		setIfNotBlank("no-proxy", proxy.NoProxy)
	}
	if cfg.AptHttpProxy() == "" &&
		cfg.AptHttpsProxy() == "" &&
		cfg.AptFtpProxy() == "" {
		proxy, err := detectAptProxies()
		if err != nil {
			return nil, err
		}
		setIfNotBlank("apt-http-proxy", proxy.Http)
		setIfNotBlank("apt-https-proxy", proxy.Https)
		setIfNotBlank("apt-ftp-proxy", proxy.Ftp)
	}
	if len(attrs) > 0 {
		cfg, err = cfg.Apply(attrs)
		if err != nil {
			return nil, err
		}
	}

	return p.Open(cfg)
}

// checkLocalPort checks that the passed port is not used so far.
var checkLocalPort = func(port int, description string) error {
	logger.Infof("checking %s", description)
	// Try to connect the port on localhost.
	address := fmt.Sprintf("localhost:%d", port)
	// TODO(mue) Add a timeout?
	conn, err := net.Dial("tcp", address)
	if err != nil {
		if nerr, ok := err.(*net.OpError); ok {
			if nerr.Err == syscall.ECONNREFUSED {
				// No connection, so everything is fine.
				return nil
			}
		}
		return err
	}
	// Connected, so port is in use.
	err = conn.Close()
	if err != nil {
		return err
	}
	return fmt.Errorf("cannot use %d as %s, already in use", port, description)
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
	if err != nil {
		return nil, fmt.Errorf("failed to validate unknown attrs: %v", err)
	}
	localConfig := newEnvironConfig(cfg, validated)
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	containerType := localConfig.container()
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if containerType != oldLocalConfig.container() {
			return nil, fmt.Errorf("cannot change container from %q to %q",
				oldLocalConfig.container(), containerType)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.networkBridge() != oldLocalConfig.networkBridge() {
			return nil, fmt.Errorf("cannot change network-bridge from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.storagePort() != oldLocalConfig.storagePort() {
			return nil, fmt.Errorf("cannot change storage-port from %v to %v",
				oldLocalConfig.storagePort(),
				localConfig.storagePort())
		}
	}
	// Currently only supported containers are "lxc" and "kvm".
	if containerType != instance.LXC && containerType != instance.KVM {
		return nil, fmt.Errorf("unsupported container type: %q", containerType)
	}
	dir, err := utils.NormalizePath(localConfig.rootDir())
	if err != nil {
		return nil, err
	}
	if dir == "." {
		dir = osenv.JujuHomePath(cfg.Name())
	}
	// Always assign the normalized path.
	localConfig.attrs["root-dir"] = dir

	if containerType != instance.KVM {
		fastOptionAvailable := useFastLXC(containerType)
		if _, found := localConfig.attrs["lxc-clone"]; !found {
			localConfig.attrs["lxc-clone"] = fastOptionAvailable
		}
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
# https://juju.ubuntu.com/docs/config-local.html
local:
    type: local

    # root-dir holds the directory that is used for the storage files and
    # database. The default location is $JUJU_HOME/<env-name>.
    # $JUJU_HOME defaults to ~/.juju. Override if needed.
    #
    # root-dir: ~/.juju/local

    # storage-port holds the port where the local provider starts the
    # HTTP file server. Override the value if you have multiple local
    # providers, or if the default port is used by another program.
    #
    # storage-port: 8040

    # network-bridge holds the name of the LXC network bridge to use.
    # Override if the default LXC network bridge is different.
    #
    #
    # network-bridge: lxcbr0

    # The default series to deploy the state-server and charms on.
    # Make sure to uncomment the following option and set the value to
    # precise or trusty as desired.
    #
    # default-series: precise

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	// don't have any secret attrs
	return nil, nil
}

func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := p.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<|endoftext|>


<commit_before>// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for golang.org/x/crypto/ssh, strictly for use in testing.

// See the LICENSE file for information about the licensing of the original library.
// Source: golang.org/x/crypto/ssh (exports: ClientConfig,AuthMethod,HostKeyCallback,PublicKey; functions: InsecureIgnoreHostKey)

// Package ssh is a stub of golang.org/x/crypto/ssh, generated by depstubber.
package ssh

import (
	io "io"
	time "time"
)

type AuthMethod interface{}

type BannerCallback func(string) error

type ClientConfig struct {
	Config            Config
	User              string
	Auth              []AuthMethod
	HostKeyCallback   HostKeyCallback
	BannerCallback    BannerCallback
	ClientVersion     string
	HostKeyAlgorithms []string
	Timeout           time.Duration
}

func (_ *ClientConfig) SetDefaults() {}

type Config struct {
	Rand           io.Reader
	RekeyThreshold uint64
	KeyExchanges   []string
	Ciphers        []string
	MACs           []string
}

func (_ *Config) SetDefaults() {}

type HostKeyCallback func(string, Addr, PublicKey) error

func InsecureIgnoreHostKey() HostKeyCallback {
	return nil
}

type PublicKey interface {
	Marshal() []byte
	Type() string
	Verify(_ []byte, _ *Signature) error
}

type Signature struct {
	Format string
	Blob   []byte
	Rest   []byte
}
<commit_msg>Fix stub for `crypto/ssh`.<commit_after>// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for golang.org/x/crypto/ssh, strictly for use in testing.

// See the LICENSE file for information about the licensing of the original library.
// Source: golang.org/x/crypto/ssh (exports: ClientConfig,AuthMethod,HostKeyCallback,PublicKey; functions: InsecureIgnoreHostKey)

// Package ssh is a stub of golang.org/x/crypto/ssh, generated by depstubber.
package ssh

import (
	io "io"
	net "net"
	time "time"
)

type AuthMethod interface{}

type BannerCallback func(string) error

type ClientConfig struct {
	Config            Config
	User              string
	Auth              []AuthMethod
	HostKeyCallback   HostKeyCallback
	BannerCallback    BannerCallback
	ClientVersion     string
	HostKeyAlgorithms []string
	Timeout           time.Duration
}

func (_ *ClientConfig) SetDefaults() {}

type Config struct {
	Rand           io.Reader
	RekeyThreshold uint64
	KeyExchanges   []string
	Ciphers        []string
	MACs           []string
}

func (_ *Config) SetDefaults() {}

type HostKeyCallback func(string, net.Addr, PublicKey) error

func InsecureIgnoreHostKey() HostKeyCallback {
	return nil
}

type PublicKey interface {
	Marshal() []byte
	Type() string
	Verify(_ []byte, _ *Signature) error
}

type Signature struct {
	Format string
	Blob   []byte
	Rest   []byte
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Hiram Jerónimo Pérez worg{at}linuxmail[dot]org

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package merger is an utility to merge structs of the same type
package merger

import (
	"errors"
	"log"
	"reflect"
	"strings"
)

var (
	// ErrDistinctType occurs when trying to merge structs of distinct type
	ErrDistinctType = errors.New(`dst and src must be of the same type`)
	// ErrNoPtr occurs when no struct pointer is sent as destination
	ErrNoPtr = errors.New(`src must be a pointer to a struct`)
	// ErrNilArguments occurs on receiving nil as arguments
	ErrNilArguments = errors.New(`no nil values allowed`)
	// ErrUnknown occurs if the type can't be merged
	ErrUnknown = errors.New(`could not merge`)
)

// Merge sets zero values from dst to non zero values of src
// accepts two structs of the same type as arguments
// dst must be a pointer to a struct
func Merge(dst, src interface{}) error {
	if dst == nil || src == nil {
		return ErrNilArguments
	}

	if !isStructPtr(dst) {
		return ErrNoPtr
	}

	if !typesMatch(src, dst) {
		return ErrDistinctType
	}

	vSrc := getValue(src)
	vDst := getValue(dst)

	for i := 0; i < vSrc.NumField(); i++ {
		sf := vSrc.Field(i)
		df := vDst.Field(i)
		if err := merge(df, sf); err != nil {
			return err
		}
	}

	return nil
}

func merge(dst, src reflect.Value) (err error) {
	if dst.CanSet() && !isZero(src) {
		switch dst.Kind() {
		case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
			if isZero(dst) {
				switch dst.Kind() {
				case reflect.Int, reflect.Int64:
					dst.SetInt(src.Int())
				case reflect.Float32, reflect.Float64:
					dst.SetFloat(src.Float())
				case reflect.String:
					dst.SetString(src.String())
				case reflect.Bool:
					dst.SetBool(src.Bool())
				}
			}
		case reflect.Slice:
			dst.Set(mergeSlice(dst, src))
		case reflect.Map:
			dst.Set(mergeMap(dst, src))
		case reflect.Struct:
			for i := 0; i < src.NumField(); i++ {
				sf := src.Field(i)
				df := dst.Field(i)
				if err := merge(df, sf); err != nil {
					return err
				}
			}
		case reflect.Ptr:
			// defer pointers
			if !dst.IsNil() {
				dst = getValue(dst)
			} else {
				dst.Set(src)
				break
			}
			if src.CanAddr() && src.IsNil() {

				src = getValue(src)
				if err := merge(dst, src); err != nil {
					return err
				}
			}
		default:
			return ErrUnknown
		}
	}
	return
}

func mergeSlice(dst, src reflect.Value) (res reflect.Value) {
	for i := 0; i < src.Len(); i++ {
		if i >= dst.Len() {
			dst = reflect.Append(dst, src.Index(i))
		}
		if err := merge(dst.Index(i), src.Index(i)); err != nil {
			res = dst
			return
		}
	}

	res = dst
	log.Printf("\n\n\nRES: %+v\n\n\n", res.Interface())
	return
}

func mergeMap(dst, src reflect.Value) (res reflect.Value) {
	if dst.IsNil() {
		dst = reflect.MakeMap(dst.Type())
	}

	for _, k := range src.MapKeys() {
		vs := src.MapIndex(k)
		vd := dst.MapIndex(k)
		if !vd.IsValid() && isZero(vd) && !isZero(vs) {
			dst.SetMapIndex(k, vs)
		}
	}

	return dst
}

func typesMatch(a, b interface{}) bool {
	return strings.TrimPrefix(reflect.TypeOf(a).String(), "*") == strings.TrimPrefix(reflect.TypeOf(b).String(), "*")
}

func getValue(t interface{}) (rslt reflect.Value) {
	rslt = reflect.ValueOf(t)

	for rslt.Kind() == reflect.Ptr && !rslt.IsNil() {
		rslt = rslt.Elem()
	}

	return
}

func isStructPtr(v interface{}) bool {
	t := reflect.TypeOf(v)
	return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
}

func isZero(v reflect.Value) bool {
	if !v.CanSet() {
		return false
	}

	switch v.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		t := true
		for i := 0; i < v.Len(); i++ {
			t = t && isZero(v.Index(i))
		}
		return t
	case reflect.Struct:
		t := true
		for i := 0; i < v.NumField(); i++ {
			t = t && isZero(v.Field(i))
		}
		return t
	}
	// Compare other types directly:
	t := reflect.Zero(v.Type())
	return v.Interface() == t.Interface()
}
<commit_msg>remove unused stuff<commit_after>// Copyright (c) 2014 Hiram Jerónimo Pérez worg{at}linuxmail[dot]org

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package merger is an utility to merge structs of the same type
package merger

import (
	"errors"
	"reflect"
	"strings"
)

var (
	// ErrDistinctType occurs when trying to merge structs of distinct type
	ErrDistinctType = errors.New(`dst and src must be of the same type`)
	// ErrNoPtr occurs when no struct pointer is sent as destination
	ErrNoPtr = errors.New(`src must be a pointer to a struct`)
	// ErrNilArguments occurs on receiving nil as arguments
	ErrNilArguments = errors.New(`no nil values allowed`)
	// ErrUnknown occurs if the type can't be merged
	ErrUnknown = errors.New(`could not merge`)
)

// Merge sets zero values from dst to non zero values of src
// accepts two structs of the same type as arguments
// dst must be a pointer to a struct
func Merge(dst, src interface{}) error {
	if dst == nil || src == nil {
		return ErrNilArguments
	}

	if !isStructPtr(dst) {
		return ErrNoPtr
	}

	if !typesMatch(src, dst) {
		return ErrDistinctType
	}

	vSrc := getValue(src)
	vDst := getValue(dst)

	for i := 0; i < vSrc.NumField(); i++ {
		sf := vSrc.Field(i)
		df := vDst.Field(i)
		if err := merge(df, sf); err != nil {
			return err
		}
	}

	return nil
}

func merge(dst, src reflect.Value) (err error) {
	if dst.CanSet() && !isZero(src) {
		switch dst.Kind() {
		case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
			if isZero(dst) {
				switch dst.Kind() {
				case reflect.Int, reflect.Int64:
					dst.SetInt(src.Int())
				case reflect.Float32, reflect.Float64:
					dst.SetFloat(src.Float())
				case reflect.String:
					dst.SetString(src.String())
				case reflect.Bool:
					dst.SetBool(src.Bool())
				}
			}
		case reflect.Slice:
			dst.Set(mergeSlice(dst, src))
		case reflect.Map:
			dst.Set(mergeMap(dst, src))
		case reflect.Struct:
			for i := 0; i < src.NumField(); i++ {
				sf := src.Field(i)
				df := dst.Field(i)
				if err := merge(df, sf); err != nil {
					return err
				}
			}
		case reflect.Ptr:
			// defer pointers
			if !dst.IsNil() {
				dst = getValue(dst)
			} else {
				dst.Set(src)
				break
			}
			if src.CanAddr() && src.IsNil() {
				src = getValue(src)
				if err := merge(dst, src); err != nil {
					return err
				}
			}
		default:
			return ErrUnknown
		}
	}
	return
}

func mergeSlice(dst, src reflect.Value) (res reflect.Value) {
	for i := 0; i < src.Len(); i++ {
		if i >= dst.Len() {
			dst = reflect.Append(dst, src.Index(i))
		}
		if err := merge(dst.Index(i), src.Index(i)); err != nil {
			res = dst
			return
		}
	}

	res = dst
	return
}

func mergeMap(dst, src reflect.Value) (res reflect.Value) {
	if dst.IsNil() {
		dst = reflect.MakeMap(dst.Type())
	}

	for _, k := range src.MapKeys() {
		vs := src.MapIndex(k)
		vd := dst.MapIndex(k)
		if !vd.IsValid() && isZero(vd) && !isZero(vs) {
			dst.SetMapIndex(k, vs)
		}
	}

	return dst
}

func typesMatch(a, b interface{}) bool {
	return strings.TrimPrefix(reflect.TypeOf(a).String(), "*") == strings.TrimPrefix(reflect.TypeOf(b).String(), "*")
}

func getValue(t interface{}) (rslt reflect.Value) {
	rslt = reflect.ValueOf(t)

	for rslt.Kind() == reflect.Ptr && !rslt.IsNil() {
		rslt = rslt.Elem()
	}

	return
}

func isStructPtr(v interface{}) bool {
	t := reflect.TypeOf(v)
	return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
}

func isZero(v reflect.Value) bool {
	if !v.CanSet() {
		return false
	}

	switch v.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return v.IsNil()
	case reflect.Array:
		t := true
		for i := 0; i < v.Len(); i++ {
			t = t && isZero(v.Index(i))
		}
		return t
	case reflect.Struct:
		t := true
		for i := 0; i < v.NumField(); i++ {
			t = t && isZero(v.Field(i))
		}
		return t
	}
	// Compare other types directly:
	t := reflect.Zero(v.Type())
	return v.Interface() == t.Interface()
}
<|endoftext|>


<commit_before>package caches

import (
	"github.com/evolsnow/samaritan/common/dbms"
	"time"
)

// Different from LRU cache, this normal cache is saved in redis
// and shouldn't be deleted by the system automatically

var Cache *SimpleCache

type SimpleCache struct {
	cache map[string]interface{}
}

func NewCache() *SimpleCache {
	return &SimpleCache{
		cache: make(map[string]interface{}),
	}
}

// Add adds a value to the cache.
func (c *SimpleCache) Set(key string, value interface{}, px time.Duration) {
	dbms.CacheSet(key, value, px)
}

// Get looks up a key's value from the cache.
func (c *SimpleCache) Get(key string) (value string) {
	return dbms.CacheGet(key)
}

// Delete deletes a key immediately
func (c *SimpleCache) Delete(key string) {
	dbms.CacheDelete(key)
}
<commit_msg>new cache<commit_after>package caches

import (
	"github.com/evolsnow/samaritan/common/dbms"
	"time"
)

// Different from LRU cache, this normal cache is saved in redis
// and shouldn't be deleted by the system automatically

//var Cache *SimpleCache

type SimpleCache struct {
	cache map[string]interface{}
}

func NewCache() *SimpleCache {
	return &SimpleCache{
		cache: make(map[string]interface{}),
	}
}

// Add adds a value to the cache.
func (c *SimpleCache) Set(key string, value interface{}, px time.Duration) {
	dbms.CacheSet(key, value, px)
}

// Get looks up a key's value from the cache.
func (c *SimpleCache) Get(key string) (value string) {
	return dbms.CacheGet(key)
}

// Delete deletes a key immediately
func (c *SimpleCache) Delete(key string) {
	dbms.CacheDelete(key)
}
<|endoftext|>