<commit_before>/*
Copyright 2017 The Kubernetes 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 provision

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/golang/glog"
	"github.com/kubernetes-incubator/external-storage/lib/controller"
	"github.com/kubernetes-incubator/external-storage/lib/util"
	"github.com/miekg/dns"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/apis/core/v1/helper"
	"k8s.io/kubernetes/pkg/volume"
)

const (
	// ProvisionerName is a unique string to represent this volume provisioner. This value will be
	// added in PV annotations under 'pv.kubernetes.io/provisioned-by' key.
	ProvisionerName = "ceph.com/rbd"
	// Each provisioner have a identify string to distinguish with others. This
	// identify string will be added in PV annoations under this key.
	provisionerIDAnn = "rbdProvisionerIdentity"

	secretKeyName   = "key" // key name used in secret
	rbdImageFormat1 = "1"
	rbdImageFormat2 = "2"
)

var (
	supportedFeatures = sets.NewString("layering")
)

// rbdProvisionOptions is internal representation of rbd provision options,
// parsed out from storage class parameters.
// https://github.com/kubernetes/website/blob/master/docs/concepts/storage/storage-classes.md#ceph-rbd
type rbdProvisionOptions struct {
	// Ceph monitors.
	monitors []string
	// Ceph RBD pool. Default is "rbd".
	pool string
	// Ceph client ID that is capable of creating images in the pool. Default is "admin".
	adminID string
	// Secret of admin client ID.
	adminSecret string
	// Ceph client ID that is used to map the RBD image. Default is the same as admin client ID.
	userID string
	// The name of Ceph Secret for userID to map RBD image. This parameter is required.
	userSecretName string
	// The namespace of Ceph Secret for userID to map RBD image. This parameter is optional.
	userSecretNamespace string
	// fsType that is supported by kubernetes. Default: "ext4".
	fsType string
	// Ceph RBD image format, "1" or "2". Default is "1".
	imageFormat string
	// This parameter is optional and should only be used if you set
	// imageFormat to "2". Currently supported features are layering only.
	// Default is "", and no features are turned on.
	imageFeatures []string
}

type rbdProvisioner struct {
	// Kubernetes Client. Use to retrieve Ceph admin secret
	client kubernetes.Interface
	// Identity of this rbdProvisioner, generated. Used to identify "this"
	// provisioner's PVs.
	identity string
	rbdUtil  *RBDUtil
	dnsip    string
}

// NewRBDProvisioner creates a Provisioner that provisions Ceph RBD PVs backed by Ceph RBD images.
func NewRBDProvisioner(client kubernetes.Interface, id string) controller.Provisioner {
	return &rbdProvisioner{
		client:   client,
		identity: id,
		rbdUtil:  &RBDUtil{},
	}
}

var _ controller.Provisioner = &rbdProvisioner{}

// getAccessModes returns access modes RBD volume supported.
func (p *rbdProvisioner) getAccessModes() []v1.PersistentVolumeAccessMode {
	return []v1.PersistentVolumeAccessMode{
		v1.ReadWriteOnce,
		v1.ReadOnlyMany,
	}
}

// Provision creates a storage asset and returns a PV object representing it.
func (p *rbdProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) {
	if !util.AccessModesContainedInAll(p.getAccessModes(), options.PVC.Spec.AccessModes) {
		return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", options.PVC.Spec.AccessModes, p.getAccessModes())
	}
	if options.PVC.Spec.Selector != nil {
		return nil, fmt.Errorf("claim Selector is not supported")
	}
	opts, err := p.parseParameters(options.Parameters)
	if err != nil {
		return nil, err
	}
	// create random image name
	image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
	rbd, sizeMB, err := p.rbdUtil.CreateImage(image, opts, options)
	if err != nil {
		glog.Errorf("rbd: create volume failed, err: %v", err)
		return nil, err
	}
	glog.Infof("successfully created rbd image %q", image)

	rbd.SecretRef = new(v1.SecretReference)
	rbd.SecretRef.Name = opts.userSecretName
	if len(opts.userSecretNamespace) > 0 {
		rbd.SecretRef.Namespace = opts.userSecretNamespace
	}
	rbd.RadosUser = opts.userID

	pv := &v1.PersistentVolume{
		ObjectMeta: metav1.ObjectMeta{
			Name: options.PVName,
			Annotations: map[string]string{
				provisionerIDAnn: p.identity,
			},
		},
		Spec: v1.PersistentVolumeSpec{
			PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy,
			AccessModes:                   options.PVC.Spec.AccessModes,
			Capacity: v1.ResourceList{
				v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
			},
			PersistentVolumeSource: v1.PersistentVolumeSource{
				RBD: rbd,
			},
		},
	}
	// use default access modes if missing
	if len(pv.Spec.AccessModes) == 0 {
		glog.Warningf("no access modes specified, use default: %v", p.getAccessModes())
		pv.Spec.AccessModes = p.getAccessModes()
	}

	return pv, nil
}

// Delete removes the storage asset that was created by Provision represented
// by the given PV.
func (p *rbdProvisioner) Delete(volume *v1.PersistentVolume) error {
	// TODO: Should we check `pv.kubernetes.io/provisioned-by` key too?
	ann, ok := volume.Annotations[provisionerIDAnn]
	if !ok {
		return errors.New("identity annotation not found on PV")
	}
	if ann != p.identity {
		return &controller.IgnoredError{Reason: "identity annotation on PV does not match ours"}
	}

	class, err := p.client.StorageV1beta1().StorageClasses().Get(helper.GetPersistentVolumeClass(volume), metav1.GetOptions{})
	if err != nil {
		return err
	}
	opts, err := p.parseParameters(class.Parameters)
	if err != nil {
		return err
	}
	image := volume.Spec.PersistentVolumeSource.RBD.RBDImage
	return p.rbdUtil.DeleteImage(image, opts)
}

// Look up the cluster dns service by label "kube-dns"
func findDNSIP(p *rbdProvisioner) (dnsip string) {
	// find DNS server address through client API
	// cache result in rbdProvisioner
	var dnssvc *v1.Service

	if p.dnsip == "" {
		coredns, err := p.client.CoreV1().Services(metav1.NamespaceSystem).Get("coredns", metav1.GetOptions{})

		if err != nil {
			glog.Warningf("error getting coredns service: %v. Falling back to kube-dns\n", err)
			kubedns, err := p.client.CoreV1().Services(metav1.NamespaceSystem).Get("kube-dns", metav1.GetOptions{})
			if err != nil {
				glog.Errorf("error getting kube-dns service: %v\n", err)
				return ""
			}
			dnssvc = kubedns
		} else {
			dnssvc = coredns
		}

		if len(dnssvc.Spec.ClusterIP) == 0 {
			glog.Errorf("DNS service ClusterIP bad\n")
			return ""
		}

		p.dnsip = dnssvc.Spec.ClusterIP
	}

	return p.dnsip
}

// Look up hostname in dns server serverip.
func lookuphost(hostname string, serverip string) (iplist []string, err error) {
	glog.V(4).Infof("lookuphost %q on %q\n", hostname, serverip)
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(hostname), dns.TypeA)
	in, err := dns.Exchange(m, joinHostPort(serverip, "53"))
	if err != nil {
		glog.Errorf("dns lookup of %q failed: err %v", hostname, err)
		return nil, err
	}
	for _, a := range in.Answer {
		glog.V(4).Infof("lookuphost answer: %v\n", a)
		if t, ok := a.(*dns.A); ok {
			iplist = append(iplist, t.A.String())
		}
	}

	return iplist, nil
}

func splitHostPort(hostport string) (host, port string) {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		host, port = hostport, ""
	}
	return host, port
}

func joinHostPort(host, port string) (hostport string) {
	if port != "" {
		return net.JoinHostPort(host, port)
	}
	return host
}

func (p *rbdProvisioner) parseParameters(parameters map[string]string) (*rbdProvisionOptions, error) {
	// options with default values
	opts := &rbdProvisionOptions{
		pool:        "rbd",
		adminID:     "admin",
		imageFormat: rbdImageFormat1,
	}

	var (
		err                  error
		adminSecretName      = ""
		adminSecretNamespace = "default"
	)

	for k, v := range parameters {
		switch strings.ToLower(k) {
		case "monitors":
			// Try to find DNS info in local cluster DNS so that the kubernetes
			// host DNS config doesn't have to know about cluster DNS
			dnsip := findDNSIP(p)
			glog.V(4).Infof("dnsip: %q\n", dnsip)
			arr := strings.Split(v, ",")
			for _, m := range arr {
				mhost, mport := splitHostPort(m)
				if dnsip != "" {
					var lookup []string
					if lookup, err = lookuphost(mhost, dnsip); err == nil {
						for _, a := range lookup {
							glog.V(1).Infof("adding %+v from mon lookup\n", a)
							opts.monitors = append(opts.monitors, joinHostPort(a, mport))
						}
					} else {
						opts.monitors = append(opts.monitors, joinHostPort(mhost, mport))
					}
				} else {
					opts.monitors = append(opts.monitors, joinHostPort(mhost, mport))
				}
			}
			glog.V(4).Infof("final monitors list: %v\n", opts.monitors)
			if len(opts.monitors) < 1 {
				return nil, fmt.Errorf("missing Ceph monitors")
			}
		case "adminid":
			if v == "" {
				// keep consistent behavior with in-tree rbd provisioner, which use default value if user provides empty string
				// TODO: treat empty string invalid value?
				v = "admin"
			}
			opts.adminID = v
		case "adminsecretname":
			adminSecretName = v
		case "adminsecretnamespace":
			adminSecretNamespace = v
		case "userid":
			opts.userID = v
		case "pool":
			if v == "" {
				// keep consistent behavior with in-tree rbd provisioner, which use default value if user provides empty string
				// TODO: treat empty string invalid value?
				v = "rbd"
			}
			opts.pool = v
		case "usersecretname":
			if v == "" {
				return nil, fmt.Errorf("missing user secret name")
			}
			opts.userSecretName = v
		case "usersecretnamespace":
			opts.userSecretNamespace = v
		case "imageformat":
			if v != rbdImageFormat1 && v != rbdImageFormat2 {
				return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s", v, rbdImageFormat1, rbdImageFormat2)
			}
			opts.imageFormat = v
		case "imagefeatures":
			arr := strings.Split(v, ",")
			for _, f := range arr {
				if !supportedFeatures.Has(f) {
					return nil, fmt.Errorf("invalid feature %q for %s provisioner, supported features are: %v", f, ProvisionerName, supportedFeatures)
				}
				opts.imageFeatures = append(opts.imageFeatures, f)
			}
		case volume.VolumeParameterFSType:
			opts.fsType = v
		default:
			return nil, fmt.Errorf("invalid option %q for %s provisioner", k, ProvisionerName)
		}
	}

	// find adminSecret
	var secret string
	if adminSecretName == "" {
		return nil, fmt.Errorf("missing Ceph admin secret name")
	}
	if secret, err = p.parsePVSecret(adminSecretNamespace, adminSecretName); err != nil {
		return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
	}
	opts.adminSecret = secret

	// set user ID to admin ID if empty
	if opts.userID == "" {
		opts.userID = opts.adminID
	}

	return opts, nil
}

// parsePVSecret retrives secret value for a given namespace and name.
func (p *rbdProvisioner) parsePVSecret(namespace, secretName string) (string, error) {
	if p.client == nil {
		return "", fmt.Errorf("Cannot get kube client")
	}
	secrets, err := p.client.CoreV1().Secrets(namespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return "", err
	}
	// TODO: Should we check secret.Type, like `k8s.io/kubernetes/pkg/volume/util.GetSecretForPV` function?
	secret := ""
	for k, v := range secrets.Data {
		if k == secretKeyName {
			return string(v), nil
		}
		secret = string(v)
	}

	// If not found, the last secret in the map wins as done before
	return secret, nil
}
<commit_msg>Update docstring<commit_after>/*
Copyright 2017 The Kubernetes 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 provision

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/golang/glog"
	"github.com/kubernetes-incubator/external-storage/lib/controller"
	"github.com/kubernetes-incubator/external-storage/lib/util"
	"github.com/miekg/dns"
	"k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/apimachinery/pkg/util/uuid"
	"k8s.io/client-go/kubernetes"
	"k8s.io/kubernetes/pkg/apis/core/v1/helper"
	"k8s.io/kubernetes/pkg/volume"
)

const (
	// ProvisionerName is a unique string to represent this volume provisioner. This value will be
	// added in PV annotations under 'pv.kubernetes.io/provisioned-by' key.
	ProvisionerName = "ceph.com/rbd"
	// Each provisioner have a identify string to distinguish with others. This
	// identify string will be added in PV annoations under this key.
	provisionerIDAnn = "rbdProvisionerIdentity"

	secretKeyName   = "key" // key name used in secret
	rbdImageFormat1 = "1"
	rbdImageFormat2 = "2"
)

var (
	supportedFeatures = sets.NewString("layering")
)

// rbdProvisionOptions is internal representation of rbd provision options,
// parsed out from storage class parameters.
// https://github.com/kubernetes/website/blob/master/docs/concepts/storage/storage-classes.md#ceph-rbd
type rbdProvisionOptions struct {
	// Ceph monitors.
	monitors []string
	// Ceph RBD pool. Default is "rbd".
	pool string
	// Ceph client ID that is capable of creating images in the pool. Default is "admin".
	adminID string
	// Secret of admin client ID.
	adminSecret string
	// Ceph client ID that is used to map the RBD image. Default is the same as admin client ID.
	userID string
	// The name of Ceph Secret for userID to map RBD image. This parameter is required.
	userSecretName string
	// The namespace of Ceph Secret for userID to map RBD image. This parameter is optional.
	userSecretNamespace string
	// fsType that is supported by kubernetes. Default: "ext4".
	fsType string
	// Ceph RBD image format, "1" or "2". Default is "1".
	imageFormat string
	// This parameter is optional and should only be used if you set
	// imageFormat to "2". Currently supported features are layering only.
	// Default is "", and no features are turned on.
	imageFeatures []string
}

type rbdProvisioner struct {
	// Kubernetes Client. Use to retrieve Ceph admin secret
	client kubernetes.Interface
	// Identity of this rbdProvisioner, generated. Used to identify "this"
	// provisioner's PVs.
	identity string
	rbdUtil  *RBDUtil
	dnsip    string
}

// NewRBDProvisioner creates a Provisioner that provisions Ceph RBD PVs backed by Ceph RBD images.
func NewRBDProvisioner(client kubernetes.Interface, id string) controller.Provisioner {
	return &rbdProvisioner{
		client:   client,
		identity: id,
		rbdUtil:  &RBDUtil{},
	}
}

var _ controller.Provisioner = &rbdProvisioner{}

// getAccessModes returns access modes RBD volume supported.
func (p *rbdProvisioner) getAccessModes() []v1.PersistentVolumeAccessMode {
	return []v1.PersistentVolumeAccessMode{
		v1.ReadWriteOnce,
		v1.ReadOnlyMany,
	}
}

// Provision creates a storage asset and returns a PV object representing it.
func (p *rbdProvisioner) Provision(options controller.VolumeOptions) (*v1.PersistentVolume, error) {
	if !util.AccessModesContainedInAll(p.getAccessModes(), options.PVC.Spec.AccessModes) {
		return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", options.PVC.Spec.AccessModes, p.getAccessModes())
	}
	if options.PVC.Spec.Selector != nil {
		return nil, fmt.Errorf("claim Selector is not supported")
	}
	opts, err := p.parseParameters(options.Parameters)
	if err != nil {
		return nil, err
	}
	// create random image name
	image := fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
	rbd, sizeMB, err := p.rbdUtil.CreateImage(image, opts, options)
	if err != nil {
		glog.Errorf("rbd: create volume failed, err: %v", err)
		return nil, err
	}
	glog.Infof("successfully created rbd image %q", image)

	rbd.SecretRef = new(v1.SecretReference)
	rbd.SecretRef.Name = opts.userSecretName
	if len(opts.userSecretNamespace) > 0 {
		rbd.SecretRef.Namespace = opts.userSecretNamespace
	}
	rbd.RadosUser = opts.userID

	pv := &v1.PersistentVolume{
		ObjectMeta: metav1.ObjectMeta{
			Name: options.PVName,
			Annotations: map[string]string{
				provisionerIDAnn: p.identity,
			},
		},
		Spec: v1.PersistentVolumeSpec{
			PersistentVolumeReclaimPolicy: options.PersistentVolumeReclaimPolicy,
			AccessModes:                   options.PVC.Spec.AccessModes,
			Capacity: v1.ResourceList{
				v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dMi", sizeMB)),
			},
			PersistentVolumeSource: v1.PersistentVolumeSource{
				RBD: rbd,
			},
		},
	}
	// use default access modes if missing
	if len(pv.Spec.AccessModes) == 0 {
		glog.Warningf("no access modes specified, use default: %v", p.getAccessModes())
		pv.Spec.AccessModes = p.getAccessModes()
	}

	return pv, nil
}

// Delete removes the storage asset that was created by Provision represented
// by the given PV.
func (p *rbdProvisioner) Delete(volume *v1.PersistentVolume) error {
	// TODO: Should we check `pv.kubernetes.io/provisioned-by` key too?
	ann, ok := volume.Annotations[provisionerIDAnn]
	if !ok {
		return errors.New("identity annotation not found on PV")
	}
	if ann != p.identity {
		return &controller.IgnoredError{Reason: "identity annotation on PV does not match ours"}
	}

	class, err := p.client.StorageV1beta1().StorageClasses().Get(helper.GetPersistentVolumeClass(volume), metav1.GetOptions{})
	if err != nil {
		return err
	}
	opts, err := p.parseParameters(class.Parameters)
	if err != nil {
		return err
	}
	image := volume.Spec.PersistentVolumeSource.RBD.RBDImage
	return p.rbdUtil.DeleteImage(image, opts)
}

// Look up the cluster dns service by label "coredns", falling back to "kube-dns" if not found
func findDNSIP(p *rbdProvisioner) (dnsip string) {
	// find DNS server address through client API
	// cache result in rbdProvisioner
	var dnssvc *v1.Service

	if p.dnsip == "" {
		coredns, err := p.client.CoreV1().Services(metav1.NamespaceSystem).Get("coredns", metav1.GetOptions{})

		if err != nil {
			glog.Warningf("error getting coredns service: %v. Falling back to kube-dns\n", err)
			kubedns, err := p.client.CoreV1().Services(metav1.NamespaceSystem).Get("kube-dns", metav1.GetOptions{})
			if err != nil {
				glog.Errorf("error getting kube-dns service: %v\n", err)
				return ""
			}
			dnssvc = kubedns
		} else {
			dnssvc = coredns
		}

		if len(dnssvc.Spec.ClusterIP) == 0 {
			glog.Errorf("DNS service ClusterIP bad\n")
			return ""
		}

		p.dnsip = dnssvc.Spec.ClusterIP
	}

	return p.dnsip
}

// Look up hostname in dns server serverip.
func lookuphost(hostname string, serverip string) (iplist []string, err error) {
	glog.V(4).Infof("lookuphost %q on %q\n", hostname, serverip)
	m := new(dns.Msg)
	m.SetQuestion(dns.Fqdn(hostname), dns.TypeA)
	in, err := dns.Exchange(m, joinHostPort(serverip, "53"))
	if err != nil {
		glog.Errorf("dns lookup of %q failed: err %v", hostname, err)
		return nil, err
	}
	for _, a := range in.Answer {
		glog.V(4).Infof("lookuphost answer: %v\n", a)
		if t, ok := a.(*dns.A); ok {
			iplist = append(iplist, t.A.String())
		}
	}

	return iplist, nil
}

func splitHostPort(hostport string) (host, port string) {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		host, port = hostport, ""
	}
	return host, port
}

func joinHostPort(host, port string) (hostport string) {
	if port != "" {
		return net.JoinHostPort(host, port)
	}
	return host
}

func (p *rbdProvisioner) parseParameters(parameters map[string]string) (*rbdProvisionOptions, error) {
	// options with default values
	opts := &rbdProvisionOptions{
		pool:        "rbd",
		adminID:     "admin",
		imageFormat: rbdImageFormat1,
	}

	var (
		err                  error
		adminSecretName      = ""
		adminSecretNamespace = "default"
	)

	for k, v := range parameters {
		switch strings.ToLower(k) {
		case "monitors":
			// Try to find DNS info in local cluster DNS so that the kubernetes
			// host DNS config doesn't have to know about cluster DNS
			dnsip := findDNSIP(p)
			glog.V(4).Infof("dnsip: %q\n", dnsip)
			arr := strings.Split(v, ",")
			for _, m := range arr {
				mhost, mport := splitHostPort(m)
				if dnsip != "" {
					var lookup []string
					if lookup, err = lookuphost(mhost, dnsip); err == nil {
						for _, a := range lookup {
							glog.V(1).Infof("adding %+v from mon lookup\n", a)
							opts.monitors = append(opts.monitors, joinHostPort(a, mport))
						}
					} else {
						opts.monitors = append(opts.monitors, joinHostPort(mhost, mport))
					}
				} else {
					opts.monitors = append(opts.monitors, joinHostPort(mhost, mport))
				}
			}
			glog.V(4).Infof("final monitors list: %v\n", opts.monitors)
			if len(opts.monitors) < 1 {
				return nil, fmt.Errorf("missing Ceph monitors")
			}
		case "adminid":
			if v == "" {
				// keep consistent behavior with in-tree rbd provisioner, which use default value if user provides empty string
				// TODO: treat empty string invalid value?
				v = "admin"
			}
			opts.adminID = v
		case "adminsecretname":
			adminSecretName = v
		case "adminsecretnamespace":
			adminSecretNamespace = v
		case "userid":
			opts.userID = v
		case "pool":
			if v == "" {
				// keep consistent behavior with in-tree rbd provisioner, which use default value if user provides empty string
				// TODO: treat empty string invalid value?
				v = "rbd"
			}
			opts.pool = v
		case "usersecretname":
			if v == "" {
				return nil, fmt.Errorf("missing user secret name")
			}
			opts.userSecretName = v
		case "usersecretnamespace":
			opts.userSecretNamespace = v
		case "imageformat":
			if v != rbdImageFormat1 && v != rbdImageFormat2 {
				return nil, fmt.Errorf("invalid ceph imageformat %s, expecting %s or %s", v, rbdImageFormat1, rbdImageFormat2)
			}
			opts.imageFormat = v
		case "imagefeatures":
			arr := strings.Split(v, ",")
			for _, f := range arr {
				if !supportedFeatures.Has(f) {
					return nil, fmt.Errorf("invalid feature %q for %s provisioner, supported features are: %v", f, ProvisionerName, supportedFeatures)
				}
				opts.imageFeatures = append(opts.imageFeatures, f)
			}
		case volume.VolumeParameterFSType:
			opts.fsType = v
		default:
			return nil, fmt.Errorf("invalid option %q for %s provisioner", k, ProvisionerName)
		}
	}

	// find adminSecret
	var secret string
	if adminSecretName == "" {
		return nil, fmt.Errorf("missing Ceph admin secret name")
	}
	if secret, err = p.parsePVSecret(adminSecretNamespace, adminSecretName); err != nil {
		return nil, fmt.Errorf("failed to get admin secret from [%q/%q]: %v", adminSecretNamespace, adminSecretName, err)
	}
	opts.adminSecret = secret

	// set user ID to admin ID if empty
	if opts.userID == "" {
		opts.userID = opts.adminID
	}

	return opts, nil
}

// parsePVSecret retrives secret value for a given namespace and name.
func (p *rbdProvisioner) parsePVSecret(namespace, secretName string) (string, error) {
	if p.client == nil {
		return "", fmt.Errorf("Cannot get kube client")
	}
	secrets, err := p.client.CoreV1().Secrets(namespace).Get(secretName, metav1.GetOptions{})
	if err != nil {
		return "", err
	}
	// TODO: Should we check secret.Type, like `k8s.io/kubernetes/pkg/volume/util.GetSecretForPV` function?
	secret := ""
	for k, v := range secrets.Data {
		if k == secretKeyName {
			return string(v), nil
		}
		secret = string(v)
	}

	// If not found, the last secret in the map wins as done before
	return secret, nil
}
<|endoftext|>


<commit_before>package pip

import (
	"fmt"
	"os/exec"
	"sync"

	"github.com/open-lambda/open-lambda/worker/config"
)

/*
 * InstallManager is the interface for installing pip packages locally.
 * The manager installs to the worker host from an optional pip mirror.
 *
 * TODO: implement eviction, support multiple versions
 */

type InstallManager interface {
	Install(pkgs []string) error
}

type PackageState struct {
	mutex *sync.RWMutex
}

type Installer struct {
	cmd       string
	args      []string
	mutex     *sync.Mutex
	pkgStates map[string]*PackageState
}

func InitInstallManager(opts *config.Config) (*Installer, error) {
	cmd := "pip"
	args := []string{"install", "--no-deps"}
	if opts.Pip_index != "" {
		args = append(args, "-i", opts.Pip_index)
	}

	args = append(args, "-t", opts.Pkgs_dir)

	installer := &Installer{
		cmd:       cmd,
		args:      args,
		mutex:     &sync.Mutex{},
		pkgStates: make(map[string]*PackageState),
	}

	if err := installer.Install(opts.Startup_pkgs); err != nil {
		return nil, err
	}

	return installer, nil
}

func (i *Installer) Install(pkgs []string) error {
	for _, pkg := range pkgs {
		i.mutex.Lock()
		pkgState, ok := i.pkgStates[pkg]
		if !ok {
			rwMutex := &sync.RWMutex{}
			rwMutex.Lock()
			i.pkgStates[pkg] = &PackageState{rwMutex}
			i.mutex.Unlock()

			cmd := exec.Command(i.cmd, append(i.args, pkg)...)
			if err := cmd.Run(); err != nil {
				delete(i.pkgStates, pkg)
				i.mutex.Unlock()
				return fmt.Errorf("failed to install package '%s' :: %v", pkg, err)
			}
			rwMutex.Unlock()
		} else {
			// The ordering here will have to change when we implement package
			// eviction - the package could be evicted after dropping the global
			// lock. We will also have to release reader locks on eviction of
			// handlers/cache entries.
			i.mutex.Unlock()
			pkgState.mutex.RLock()
		}
	}

	return nil
}
<commit_msg>Add i.mutex.Lock() before delete(i.pkgStates, pkg) to avoid calling i.mutex.Unlock() twice when cmd returns an error.<commit_after>package pip

import (
	"fmt"
	"os/exec"
	"sync"

	"github.com/open-lambda/open-lambda/worker/config"
)

/*
 * InstallManager is the interface for installing pip packages locally.
 * The manager installs to the worker host from an optional pip mirror.
 *
 * TODO: implement eviction, support multiple versions
 */

type InstallManager interface {
	Install(pkgs []string) error
}

type PackageState struct {
	mutex *sync.RWMutex
}

type Installer struct {
	cmd       string
	args      []string
	mutex     *sync.Mutex
	pkgStates map[string]*PackageState
}

func InitInstallManager(opts *config.Config) (*Installer, error) {
	cmd := "pip"
	args := []string{"install", "--no-deps"}
	if opts.Pip_index != "" {
		args = append(args, "-i", opts.Pip_index)
	}

	args = append(args, "-t", opts.Pkgs_dir)

	installer := &Installer{
		cmd:       cmd,
		args:      args,
		mutex:     &sync.Mutex{},
		pkgStates: make(map[string]*PackageState),
	}

	if err := installer.Install(opts.Startup_pkgs); err != nil {
		return nil, err
	}

	return installer, nil
}

func (i *Installer) Install(pkgs []string) error {
	for _, pkg := range pkgs {
		i.mutex.Lock()
		pkgState, ok := i.pkgStates[pkg]
		if !ok {
			rwMutex := &sync.RWMutex{}
			rwMutex.Lock()
			defer rwMutex.Unlock()
			i.pkgStates[pkg] = &PackageState{rwMutex}
			i.mutex.Unlock()
			cmd := exec.Command(i.cmd, append(i.args, pkg)...)
			if err := cmd.Run(); err != nil {
				i.mutex.Lock()
				delete(i.pkgStates, pkg)
				i.mutex.Unlock()
				return fmt.Errorf("failed to install package '%s' :: %v :: %v", pkg, err, cmd)
			}
		} else {
			// The ordering here will have to change when we implement package
			// eviction - the package could be evicted after dropping the global
			// lock. We will also have to release reader locks on eviction of
			// handlers/cache entries.
			i.mutex.Unlock()
			pkgState.mutex.RLock()
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package reflections_test

import (
    "fmt"
    "github.com/oleiade/reflections"
)

func ExampleGetField() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    fieldsToExtract := []string{"FirstField", "ThirdField"}

    for _, fieldName := range fieldsToExtract {
        value, err := reflections.GetField(s, fieldName)
        fmt.Println(value)
    }
}

func ExampleHasField() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    // has == true
    has, _ := reflections.HasField(s, "FirstField")

    // has == false
    has, _ := reflections.HasField(s, "FourthField")
}

func ExampleFields() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    var fields []string

    // Fields will list every structure exportable fields.
    // Here, it's content would be equal to:
    // []string{"FirstField", "SecondField", "ThirdField"}
    fields, _ = reflections.Fields(s)
}

func ExampleItems() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    var structItems map[string]interface{}

    // Items will return a field name to
    // field value map
    structItems, _ = reflections.Items(s)
}

func ExampleTags() {
    s := MyStruct {
        FirstField: "first value",      `matched:"first tag"`
        SecondField: 2,                 `matched:"second tag"`
        ThirdField: "third value",      `unmatched:"third tag"`
    }

    var structTags map[string]string

    // Tags will return a field name to tag content
    // map. Nota that only field with the tag name
    // you've provided which will be matched.
    // Here structTags will contain:
    // {
    //     "FirstField": "first tag",
    //     "SecondField": "second tag",
    // }
    structTags, _ = reflections.Tags(s, "matched")
}<commit_msg>Add: SetField function usage example to documentation<commit_after>package reflections_test

import (
    "fmt"
    "github.com/oleiade/reflections"
)

func ExampleGetField() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    fieldsToExtract := []string{"FirstField", "ThirdField"}

    for _, fieldName := range fieldsToExtract {
        value, err := reflections.GetField(s, fieldName)
        fmt.Println(value)
    }
}

func ExampleHasField() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    // has == true
    has, _ := reflections.HasField(s, "FirstField")

    // has == false
    has, _ := reflections.HasField(s, "FourthField")
}

func ExampleFields() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    var fields []string

    // Fields will list every structure exportable fields.
    // Here, it's content would be equal to:
    // []string{"FirstField", "SecondField", "ThirdField"}
    fields, _ = reflections.Fields(s)
}

func ExampleItems() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    var structItems map[string]interface{}

    // Items will return a field name to
    // field value map
    structItems, _ = reflections.Items(s)
}

func ExampleTags() {
    s := MyStruct {
        FirstField: "first value",      `matched:"first tag"`
        SecondField: 2,                 `matched:"second tag"`
        ThirdField: "third value",      `unmatched:"third tag"`
    }

    var structTags map[string]string

    // Tags will return a field name to tag content
    // map. Nota that only field with the tag name
    // you've provided which will be matched.
    // Here structTags will contain:
    // {
    //     "FirstField": "first tag",
    //     "SecondField": "second tag",
    // }
    structTags, _ = reflections.Tags(s, "matched")
}

func ExampleSetField() {
    s := MyStruct {
        FirstField: "first value",
        SecondField: 2,
        ThirdField: "third value",
    }

    // In order to be able to set the structure's values,
    // a pointer to it has to be passed to it.
    _ := reflections.SetField(&s, "FirstField", "new value")

    // If you try to set a field's value using the wrong type,
    // an error will be returned
    err := reflection.SetField(&s, "FirstField", 123)  // err != nil
}<|endoftext|>


<commit_before>// Copyright 2015 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.

package ipaddr_test

import (
	"fmt"
	"log"
	"net"

	"github.com/mikioh/ipaddr"
)

func ExampleCursor_traversal() {
	c, err := ipaddr.Parse("2001:db8::/126,192.168.1.128/30,192.168.0.0/29")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	for pos := c.Next(); pos != nil; pos = c.Next() {
		fmt.Println(pos)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	for pos := c.Prev(); pos != nil; pos = c.Prev() {
		fmt.Println(pos)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	// Output:
	// &{192.168.0.0 192.168.0.0/29} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
	// &{192.168.0.1 192.168.0.0/29}
	// &{192.168.0.2 192.168.0.0/29}
	// &{192.168.0.3 192.168.0.0/29}
	// &{192.168.0.4 192.168.0.0/29}
	// &{192.168.0.5 192.168.0.0/29}
	// &{192.168.0.6 192.168.0.0/29}
	// &{192.168.0.7 192.168.0.0/29}
	// &{192.168.1.128 192.168.1.128/30}
	// &{192.168.1.129 192.168.1.128/30}
	// &{192.168.1.130 192.168.1.128/30}
	// &{192.168.1.131 192.168.1.128/30}
	// &{2001:db8:: 2001:db8::/126}
	// &{2001:db8::1 2001:db8::/126}
	// &{2001:db8::2 2001:db8::/126}
	// &{2001:db8::3 2001:db8::/126}
	// &{2001:db8::3 2001:db8::/126} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
	// &{2001:db8::2 2001:db8::/126}
	// &{2001:db8::1 2001:db8::/126}
	// &{2001:db8:: 2001:db8::/126}
	// &{192.168.1.131 192.168.1.128/30}
	// &{192.168.1.130 192.168.1.128/30}
	// &{192.168.1.129 192.168.1.128/30}
	// &{192.168.1.128 192.168.1.128/30}
	// &{192.168.0.7 192.168.0.0/29}
	// &{192.168.0.6 192.168.0.0/29}
	// &{192.168.0.5 192.168.0.0/29}
	// &{192.168.0.4 192.168.0.0/29}
	// &{192.168.0.3 192.168.0.0/29}
	// &{192.168.0.2 192.168.0.0/29}
	// &{192.168.0.1 192.168.0.0/29}
	// &{192.168.0.0 192.168.0.0/29}
	// &{192.168.0.0 192.168.0.0/29} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
}

func ExamplePrefix_subnettingAndSupernetting() {
	_, n, err := net.ParseCIDR("172.16.0.0/16")
	if err != nil {
		log.Fatal(err)
	}
	p := ipaddr.NewPrefix(n)
	fmt.Println(p.IP, p.Last(), p.Len(), p.Mask, p.Hostmask())
	ps := p.Subnets(3)
	for _, p := range ps {
		fmt.Println(p)
	}
	fmt.Println(ipaddr.Supernet(ps[4:6]))
	// Output:
	// 172.16.0.0 172.16.255.255 16 ffff0000 0000ffff
	// 172.16.0.0/19
	// 172.16.32.0/19
	// 172.16.64.0/19
	// 172.16.96.0/19
	// 172.16.128.0/19
	// 172.16.160.0/19
	// 172.16.192.0/19
	// 172.16.224.0/19
	// 172.16.128.0/18
}

func ExamplePrefix_subnettingAndAggregation() {
	_, n, err := net.ParseCIDR("192.168.0.0/24")
	if err != nil {
		log.Fatal(err)
	}
	p := ipaddr.NewPrefix(n)
	fmt.Println(p.IP, p.Last(), p.Len(), p.Mask, p.Hostmask())
	ps := p.Subnets(2)
	for _, p := range ps {
		fmt.Println(p)
	}
	_, n, err = net.ParseCIDR("192.168.100.0/24")
	if err != nil {
		log.Fatal(err)
	}
	ps = append(ps, *ipaddr.NewPrefix(n))
	fmt.Println(ipaddr.Aggregate(ps[2:]))
	// Output:
	// 192.168.0.0 192.168.0.255 24 ffffff00 000000ff
	// 192.168.0.0/26
	// 192.168.0.64/26
	// 192.168.0.128/26
	// 192.168.0.192/26
	// [192.168.0.128/25 192.168.100.0/24]
}

func ExamplePrefix_addressRangeSummarization() {
	ps := ipaddr.Summarize(net.ParseIP("2001:db8::1"), net.ParseIP("2001:db8::8000"))
	for _, p := range ps {
		fmt.Println(p)
	}
	// Output:
	// 2001:db8::1/128
	// 2001:db8::2/127
	// 2001:db8::4/126
	// 2001:db8::8/125
	// 2001:db8::10/124
	// 2001:db8::20/123
	// 2001:db8::40/122
	// 2001:db8::80/121
	// 2001:db8::100/120
	// 2001:db8::200/119
	// 2001:db8::400/118
	// 2001:db8::800/117
	// 2001:db8::1000/116
	// 2001:db8::2000/115
	// 2001:db8::4000/114
	// 2001:db8::8000/128
}
<commit_msg>ipaddr: tweak examples<commit_after>// Copyright 2015 Mikio Hara. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.

package ipaddr_test

import (
	"fmt"
	"log"
	"net"

	"github.com/mikioh/ipaddr"
)

func ExampleCursor_traversal() {
	c, err := ipaddr.Parse("2001:db8::/126,192.168.1.128/30,192.168.0.0/29")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	for pos := c.Next(); pos != nil; pos = c.Next() {
		fmt.Println(pos)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	for pos := c.Prev(); pos != nil; pos = c.Prev() {
		fmt.Println(pos)
	}
	fmt.Println(c.Pos(), c.First(), c.Last(), c.List())
	// Output:
	// &{192.168.0.0 192.168.0.0/29} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
	// &{192.168.0.1 192.168.0.0/29}
	// &{192.168.0.2 192.168.0.0/29}
	// &{192.168.0.3 192.168.0.0/29}
	// &{192.168.0.4 192.168.0.0/29}
	// &{192.168.0.5 192.168.0.0/29}
	// &{192.168.0.6 192.168.0.0/29}
	// &{192.168.0.7 192.168.0.0/29}
	// &{192.168.1.128 192.168.1.128/30}
	// &{192.168.1.129 192.168.1.128/30}
	// &{192.168.1.130 192.168.1.128/30}
	// &{192.168.1.131 192.168.1.128/30}
	// &{2001:db8:: 2001:db8::/126}
	// &{2001:db8::1 2001:db8::/126}
	// &{2001:db8::2 2001:db8::/126}
	// &{2001:db8::3 2001:db8::/126}
	// &{2001:db8::3 2001:db8::/126} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
	// &{2001:db8::2 2001:db8::/126}
	// &{2001:db8::1 2001:db8::/126}
	// &{2001:db8:: 2001:db8::/126}
	// &{192.168.1.131 192.168.1.128/30}
	// &{192.168.1.130 192.168.1.128/30}
	// &{192.168.1.129 192.168.1.128/30}
	// &{192.168.1.128 192.168.1.128/30}
	// &{192.168.0.7 192.168.0.0/29}
	// &{192.168.0.6 192.168.0.0/29}
	// &{192.168.0.5 192.168.0.0/29}
	// &{192.168.0.4 192.168.0.0/29}
	// &{192.168.0.3 192.168.0.0/29}
	// &{192.168.0.2 192.168.0.0/29}
	// &{192.168.0.1 192.168.0.0/29}
	// &{192.168.0.0 192.168.0.0/29}
	// &{192.168.0.0 192.168.0.0/29} &{192.168.0.0 192.168.0.0/29} &{2001:db8::3 2001:db8::/126} [192.168.0.0/29 192.168.1.128/30 2001:db8::/126]
}

func ExamplePrefix_subnettingAndSupernetting() {
	_, n, err := net.ParseCIDR("172.16.0.0/16")
	if err != nil {
		log.Fatal(err)
	}
	p := ipaddr.NewPrefix(n)
	fmt.Println(p.IP, p.Last(), p.Len(), p.Mask, p.Hostmask())
	fmt.Println()
	ps := p.Subnets(3)
	for _, p := range ps {
		fmt.Println(p)
	}
	fmt.Println()
	fmt.Println(ipaddr.Supernet(ps[4:6]))
	// Output:
	// 172.16.0.0 172.16.255.255 16 ffff0000 0000ffff
	//
	// 172.16.0.0/19
	// 172.16.32.0/19
	// 172.16.64.0/19
	// 172.16.96.0/19
	// 172.16.128.0/19
	// 172.16.160.0/19
	// 172.16.192.0/19
	// 172.16.224.0/19
	//
	// 172.16.128.0/18
}

func ExamplePrefix_subnettingAndAggregation() {
	_, n, err := net.ParseCIDR("192.168.0.0/24")
	if err != nil {
		log.Fatal(err)
	}
	p := ipaddr.NewPrefix(n)
	fmt.Println(p.IP, p.Last(), p.Len(), p.Mask, p.Hostmask())
	fmt.Println()
	ps := p.Subnets(2)
	for _, p := range ps {
		fmt.Println(p)
	}
	fmt.Println()
	_, n, err = net.ParseCIDR("192.168.100.0/24")
	if err != nil {
		log.Fatal(err)
	}
	ps = append(ps, *ipaddr.NewPrefix(n))
	fmt.Println(ipaddr.Aggregate(ps[2:]))
	// Output:
	// 192.168.0.0 192.168.0.255 24 ffffff00 000000ff
	//
	// 192.168.0.0/26
	// 192.168.0.64/26
	// 192.168.0.128/26
	// 192.168.0.192/26
	//
	// [192.168.0.128/25 192.168.100.0/24]
}

func ExamplePrefix_addressRangeSummarization() {
	ps := ipaddr.Summarize(net.ParseIP("2001:db8::1"), net.ParseIP("2001:db8::8000"))
	for _, p := range ps {
		fmt.Println(p)
	}
	// Output:
	// 2001:db8::1/128
	// 2001:db8::2/127
	// 2001:db8::4/126
	// 2001:db8::8/125
	// 2001:db8::10/124
	// 2001:db8::20/123
	// 2001:db8::40/122
	// 2001:db8::80/121
	// 2001:db8::100/120
	// 2001:db8::200/119
	// 2001:db8::400/118
	// 2001:db8::800/117
	// 2001:db8::1000/116
	// 2001:db8::2000/115
	// 2001:db8::4000/114
	// 2001:db8::8000/128
}
<|endoftext|>


<commit_before>package sftp_test

import (
	"log"

	"code.google.com/p/go.crypto/ssh"

	"github.com/pkg/sftp"
)

func ExampleNewClient(conn *ssh.ClientConn) {
	// open an SFTP sesison over an existing ssh connection.
	sftp, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer sftp.Close()

	// walk a directory
	w := sftp.Walk("/home/user")
	for w.Step() {
		if w.Err() != nil {
			continue
		}
		log.Println(w.Path())
	}

	// leave your mark
	f, err := sftp.Create("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	if _, err := f.Write([]byte("Hello world!")); err != nil {
		log.Fatal(err)
	}

	// check it's there
	fi, err := sftp.Lstat("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	log.Println(fi)
}
<commit_msg>move example to top level<commit_after>package sftp_test

import (
	"log"

	"code.google.com/p/go.crypto/ssh"

	"github.com/pkg/sftp"
)

func Example(conn *ssh.ClientConn) {
	// open an SFTP sesison over an existing ssh connection.
	sftp, err := sftp.NewClient(conn)
	if err != nil {
		log.Fatal(err)
	}
	defer sftp.Close()

	// walk a directory
	w := sftp.Walk("/home/user")
	for w.Step() {
		if w.Err() != nil {
			continue
		}
		log.Println(w.Path())
	}

	// leave your mark
	f, err := sftp.Create("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	if _, err := f.Write([]byte("Hello world!")); err != nil {
		log.Fatal(err)
	}

	// check it's there
	fi, err := sftp.Lstat("hello.txt")
	if err != nil {
		log.Fatal(err)
	}
	log.Println(fi)
}
<|endoftext|>


<commit_before>package stomp

import (
	"bytes"
	"fmt"
	"strings"
)

func encodeHeader(key, value string) string {
	encode := func(v string) string {
		v = strings.Replace(v, "\r", "\\r", -1)
		v = strings.Replace(v, "\n", "\\n", -1)
		v = strings.Replace(v, ":", "\\c", -1)
		v = strings.Replace(v, "\\", "\\\\", -1)
		return v
	}

	return fmt.Sprintf("%s:%s", encode(key), encode(value))
}

func encodeFrame(f *Frame) []byte {
	buf := bytes.Buffer{}

	// encode command
	buf.WriteString(f.Command)
	buf.WriteString("\n")

	// encode header
	for key, value := range f.Header {
		buf.WriteString(encodeHeader(key, value))
		buf.WriteString("\n")
	}
	buf.WriteString("\n")

	// encode body
	buf.Write(f.Body)
	// terminate frame
	buf.WriteString("\x00\n")

	return buf.Bytes()
}

func (c *Conn) writeFrame(f *Frame, options ...Option) error {
	c.closeMu.Lock()
	closed := c.closed
	c.closeMu.Unlock()
	if closed {
		return fmt.Errorf("writing to closed connection")
	}

	for _, fn := range options {
		fn(f)
	}

	data := encodeFrame(f)

	c.writeMu.Lock()
	defer c.writeMu.Unlock()
	_, err := c.conn.Write(data)
	return err
}

func (c *Conn) writeHeartBeat() error {
	c.closeMu.Lock()
	closed := c.closed
	c.closeMu.Unlock()
	if closed {
		return fmt.Errorf("writing to closed connection")
	}

	c.writeMu.Lock()
	defer c.writeMu.Unlock()
	_, err := c.conn.Write([]byte{'\n'})
	return err
}
<commit_msg>fixed bug with wrong header encoding<commit_after>package stomp

import (
	"bytes"
	"fmt"
	"strings"
)

func encodeHeader(key, value string) string {
	encode := func(v string) string {
		v = strings.Replace(v, "\\", "\\\\", -1)
		v = strings.Replace(v, "\r", "\\r", -1)
		v = strings.Replace(v, "\n", "\\n", -1)
		v = strings.Replace(v, ":", "\\c", -1)
		return v
	}

	return fmt.Sprintf("%s:%s", encode(key), encode(value))
}

func encodeFrame(f *Frame) []byte {
	buf := bytes.Buffer{}

	// encode command
	buf.WriteString(f.Command)
	buf.WriteString("\n")

	// encode header
	for key, value := range f.Header {
		buf.WriteString(encodeHeader(key, value))
		buf.WriteString("\n")
	}
	buf.WriteString("\n")

	// encode body
	buf.Write(f.Body)
	// terminate frame
	buf.WriteString("\x00\n")

	return buf.Bytes()
}

func (c *Conn) writeFrame(f *Frame, options ...Option) error {
	c.closeMu.Lock()
	closed := c.closed
	c.closeMu.Unlock()
	if closed {
		return fmt.Errorf("writing to closed connection")
	}

	for _, fn := range options {
		fn(f)
	}

	data := encodeFrame(f)

	c.writeMu.Lock()
	defer c.writeMu.Unlock()
	_, err := c.conn.Write(data)
	return err
}

func (c *Conn) writeHeartBeat() error {
	c.closeMu.Lock()
	closed := c.closed
	c.closeMu.Unlock()
	if closed {
		return fmt.Errorf("writing to closed connection")
	}

	c.writeMu.Lock()
	defer c.writeMu.Unlock()
	_, err := c.conn.Write([]byte{'\n'})
	return err
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version        int                 `json:"v"`
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					log.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			log.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			log.Println(fmt.Sprintf("Error uncompressing message type %d: %s", messageType, err1))
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				log.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		log.Println(fmt.Sprintf("Error decoding message type %d: %s", messageType, err))
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = unmarshal(e.RawData, i); err != nil {
			log.Println(fmt.Sprintf("Unable to unmarshal event %s data: %s", e.Type, err))
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = nil
			}
		}
	} else {
		log.Println("Unknown event.")
		i = nil
	}

	if i != nil {
		s.handle(i)
	}

	e.Struct = i
	s.handle(e)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID, mute, deaf)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		GuildID:     gID,
		ChannelID:   cID,
		session:     s,
		connected:   make(chan bool),
		sessionRecv: make(chan string),
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.waitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		log.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID

	// TODO: Consider this...
	// voice.sessionRecv <- st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		return
	}

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	// voice.Close()

	// Wait for the sessionID from onVoiceStateUpdate
	// voice.sessionID = <-voice.sessionRecv
	// TODO review above
	// wouldn't this cause a huge problem, if it's just a guild server
	// update.. ?
	// I could add a timeout loop of some sort and also check if the
	// sessionID doesn't or does exist already...
	// something.. a bit smarter.

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := voice.open()
	if err != nil {
		log.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<commit_msg>Use json.Unmarshal in event handling so errors are better.<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version        int                 `json:"v"`
	Token          string              `json:"token"`
	Properties     handshakeProperties `json:"properties"`
	LargeThreshold int                 `json:"large_threshold"`
	Compress       bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	s.VoiceConnections = make(map[string]*VoiceConnection)

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, 250, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.initialize()
	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					log.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {

	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	var err error
	ticker := time.NewTicker(i * time.Millisecond)
	for {
		err = wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
		if err != nil {
			log.Println("Error sending heartbeat:", err)
			return
		}

		select {
		case <-ticker.C:
			// continue loop and send heartbeat
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	var err error
	var reader io.Reader

	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			log.Println(fmt.Sprintf("Error uncompressing message type %d: %s", messageType, err1))
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				log.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		log.Println(fmt.Sprintf("Error decoding message type %d: %s", messageType, err))
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = json.Unmarshal(e.RawData, i); err != nil {
			log.Println(fmt.Sprintf("Unable to unmarshal event %s data: %s", e.Type, err))
			// Ready events must fire, even if they are empty.
			if e.Type != "READY" {
				i = nil
			}
		}
	} else {
		log.Println("Unknown event.")
		i = nil
	}

	if i != nil {
		s.handle(i)
	}

	e.Struct = i
	s.handle(e)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   *string `json:"guild_id"`
	ChannelID *string `json:"channel_id"`
	SelfMute  bool    `json:"self_mute"`
	SelfDeaf  bool    `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel.
//
//    gID     : Guild ID of the channel to join.
//    cID     : Channel ID of the channel to join.
//    mute    : If true, you will be set to muted upon joining.
//    deaf    : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (voice *VoiceConnection, err error) {

	// If a voice connection already exists for this guild then
	// return that connection. If the channel differs, also change channels.
	var ok bool
	if voice, ok = s.VoiceConnections[gID]; ok && voice.GuildID != "" {
		//TODO: consider a better variable than GuildID in the above check
		// to verify if this connection is valid or not.

		if voice.ChannelID != cID {
			err = voice.ChangeChannel(cID, mute, deaf)
		}
		return
	}

	// Create a new voice session
	// TODO review what all these things are for....
	voice = &VoiceConnection{
		GuildID:     gID,
		ChannelID:   cID,
		session:     s,
		connected:   make(chan bool),
		sessionRecv: make(chan string),
	}

	// Store voice in VoiceConnections map for this GuildID
	s.VoiceConnections[gID] = voice

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		delete(s.VoiceConnections, gID)
		return
	}

	// doesn't exactly work perfect yet.. TODO
	err = voice.waitUntilConnected()
	if err != nil {
		voice.Close()
		delete(s.VoiceConnections, gID)
		return
	}

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data websocket.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// If we don't have a connection for the channel, don't bother
	if st.ChannelID == "" {
		return
	}

	// Check if we have a voice connection to update
	voice, exists := s.VoiceConnections[st.GuildID]
	if !exists {
		return
	}

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		log.Println(err)
		return
	}

	// We only care about events that are about us
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	voice.UserID = self.ID // TODO: Review
	voice.sessionID = st.SessionID

	// TODO: Consider this...
	// voice.sessionRecv <- st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	voice, exists := s.VoiceConnections[st.GuildID]

	// If no VoiceConnection exists, just skip this
	if !exists {
		return
	}

	// Store values for later use
	voice.token = st.Token
	voice.endpoint = st.Endpoint
	voice.GuildID = st.GuildID

	// If currently connected to voice ws/udp, then disconnect.
	// Has no effect if not connected.
	// voice.Close()

	// Wait for the sessionID from onVoiceStateUpdate
	// voice.sessionID = <-voice.sessionRecv
	// TODO review above
	// wouldn't this cause a huge problem, if it's just a guild server
	// update.. ?
	// I could add a timeout loop of some sort and also check if the
	// sessionID doesn't or does exist already...
	// something.. a bit smarter.

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := voice.open()
	if err != nil {
		log.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<|endoftext|>


<commit_before>// (C) 2016 by Ricardo Branco
//
// MIT License
//
// v0.3.3
//
// TODO:
// + Support HMAC
// + Read filenames from file
// + Support -c option like md5sum(1)
// + Use getopt
// + Use different output formats for display

package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	ossl_blake2b "github.com/ricardobranco777/dgst/blake2b"
	ossl_blake2s "github.com/ricardobranco777/dgst/blake2s"
	ossl_md4 "github.com/ricardobranco777/dgst/md4"
	ossl_md5 "github.com/ricardobranco777/dgst/md5"
	ossl_ripemd160 "github.com/ricardobranco777/dgst/ripemd160"
	ossl_sha1 "github.com/ricardobranco777/dgst/sha1"
	ossl_sha256 "github.com/ricardobranco777/dgst/sha256"
	ossl_sha512 "github.com/ricardobranco777/dgst/sha512"
	"golang.org/x/crypto/blake2b"
	"golang.org/x/crypto/blake2s"
	"golang.org/x/crypto/md4"
	"golang.org/x/crypto/ripemd160"
	"golang.org/x/crypto/sha3"
	"hash"
	"io"
	"os"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
)

var hashes = map[string]*struct {
	sum string
	hash.Hash
	size int
}{
	"BLAKE2b256": {"", nil, 32},
	"BLAKE2b384": {"", nil, 48},
	"BLAKE2b512": {"", nil, 64},
	"BLAKE2s256": {"", nil, 32},
	"MD4":        {"", nil, 16},
	"MD5":        {"", nil, 16},
	"RIPEMD160":  {"", nil, 20},
	"SHA1":       {"", nil, 20},
	"SHA224":     {"", nil, 28},
	"SHA256":     {"", nil, 32},
	"SHA384":     {"", nil, 48},
	"SHA512":     {"", nil, 64},
	"SHA512-224": {"", nil, 28},
	"SHA512-256": {"", nil, 32},
	"SHA3-224":   {"", nil, 28},
	"SHA3-256":   {"", nil, 32},
	"SHA3-384":   {"", nil, 48},
	"SHA3-512":   {"", nil, 64},
}

// The keys to the above dictionary in sorted order
var keys []string

var progname string

var done chan error

func main() {
	progname = path.Base(os.Args[0])

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] [-s STRING...]|[FILE... DIRECTORY...]\n\n", progname)
		flag.PrintDefaults()
	}

	chosen := make(map[string]*bool)
	for h := range hashes {
		chosen[h] = flag.Bool(strings.ToLower(h), false, fmt.Sprintf("%s algorithm", h))
	}

	var all, ossl, isString *bool
	all = flag.Bool("all", false, "all algorithms")
	ossl = flag.Bool("ossl", false, "use OpenSSL")
	isString = flag.Bool("s", false, "treat arguments as strings")

	var size_hashes = map[int]*struct {
		hashes []string
		set    *bool
	}{
		128: {},
		160: {},
		224: {},
		256: {},
		384: {},
		512: {},
	}

	for h := range hashes {
		size_hashes[hashes[h].size*8].hashes = append(size_hashes[hashes[h].size*8].hashes, h)
	}

	for size := range size_hashes {
		sizeStr := strconv.Itoa(size)
		if len(size_hashes[size].hashes) > 0 {
			size_hashes[size].set = flag.Bool(sizeStr, false, "all "+sizeStr+" bits algorithms")
		}
	}
	var sha3Opt, sha2Opt, blake2Opt *bool
	sha3Opt = flag.Bool("sha3", false, "all SHA-3 algorithms")
	sha2Opt = flag.Bool("sha2", false, "all SHA-2 algorithms")
	blake2Opt = flag.Bool("blake2", false, "all BLAKE2 algorithms")

	flag.Parse()

	for size := range size_hashes {
		if !*(size_hashes[size].set) {
			continue
		}
		for _, h := range size_hashes[size].hashes {
			*chosen[h] = true
		}
	}

	if *sha3Opt {
		for h := range hashes {
			if strings.HasPrefix(h, "SHA3-") {
				*chosen[h] = true
			}
		}
	}
	if *sha2Opt {
		for h := range hashes {
			if strings.HasPrefix(h, "SHA2") || strings.HasPrefix(h, "SHA384") || strings.HasPrefix(h, "SHA512") {
				*chosen[h] = true
			}
		}
	}
	if *blake2Opt {
		for h := range hashes {
			if strings.HasPrefix(h, "BLAKE2") {
				*chosen[h] = true
			}
		}
	}

	if !(*all || choices(chosen)) {
		*all = true
	}

	for h := range chosen {
		if (*all && *chosen[h]) || !(*all || *chosen[h]) {
			delete(hashes, h)
		}
	}

	for k := range hashes {
		keys = append(keys, k)
		switch k {
		case "BLAKE2b256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New256)
			} else {
				hashes[k].Hash = blake2_(blake2b.New256)
			}
		case "BLAKE2b384":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New384)
			} else {
				hashes[k].Hash = blake2_(blake2b.New384)
			}
		case "BLAKE2b512":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2b.New512)
			} else {
				hashes[k].Hash = blake2_(blake2b.New512)
			}
		case "BLAKE2s256":
			if *ossl {
				hashes[k].Hash = blake2_(ossl_blake2s.New256)
			} else {
				hashes[k].Hash = blake2_(blake2s.New256)
			}
		case "MD4":
			if *ossl {
				hashes[k].Hash = ossl_md4.New()
			} else {
				hashes[k].Hash = md4.New()
			}
		case "MD5":
			if *ossl {
				hashes[k].Hash = ossl_md5.New()
			} else {
				hashes[k].Hash = md5.New()
			}
		case "RIPEMD160":
			if *ossl {
				hashes[k].Hash = ossl_ripemd160.New()
			} else {
				hashes[k].Hash = ripemd160.New()
			}
		case "SHA1":
			if *ossl {
				hashes[k].Hash = ossl_sha1.New()
			} else {
				hashes[k].Hash = sha1.New()
			}
		case "SHA224":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New224()
			} else {
				hashes[k].Hash = sha256.New224()
			}
		case "SHA256":
			if *ossl {
				hashes[k].Hash = ossl_sha256.New()
			} else {
				hashes[k].Hash = sha256.New()
			}
		case "SHA384":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New384()
			} else {
				hashes[k].Hash = sha512.New384()
			}
		case "SHA512":
			if *ossl {
				hashes[k].Hash = ossl_sha512.New()
			} else {
				hashes[k].Hash = sha512.New()
			}
		case "SHA512-224":
			hashes[k].Hash = sha512.New512_224()
		case "SHA512-256":
			hashes[k].Hash = sha512.New512_256()
		case "SHA3-224":
			hashes[k].Hash = sha3.New224()
		case "SHA3-256":
			hashes[k].Hash = sha3.New256()
		case "SHA3-384":
			hashes[k].Hash = sha3.New384()
		case "SHA3-512":
			hashes[k].Hash = sha3.New512()
		}
	}

	sort.Strings(keys)

	if len(hashes) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if flag.NArg() == 0 {
		hash_stdin()
		os.Exit(0)
	}

	var errors bool

	if *isString {
		for _, s := range flag.Args() {
			hash_string(s)
		}
	} else {
		done = make(chan error, len(hashes))
		defer close(done)

		for _, pathname := range flag.Args() {
			info, err := os.Stat(pathname)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
				errors = true
			} else if info.IsDir() {
				errors = hash_dir(pathname)
			} else {
				errors = hash_file(pathname)
			}
		}
	}

	if errors {
		os.Exit(1)
	}
}

// Wrapper for the Blake2 New() methods that needs an optional for MAC
func blake2_(f func([]byte) (hash.Hash, error)) hash.Hash {
	h, _ := f(nil)
	return h
}

// Returns true if at least some algorithm was specified on the command line
func choices(chosen map[string]*bool) bool {
	for h := range chosen {
		if *chosen[h] {
			return true
		}
	}
	return false
}

func display() {
	for _, k := range keys {
		fmt.Println(hashes[k].sum)
	}
}

func hash_string(str string) {
	var wg sync.WaitGroup
	wg.Add(len(hashes))
	for h := range hashes {
		go func(h string) {
			defer wg.Done()
			hashes[h].Write([]byte(str))
			hashes[h].sum = fmt.Sprintf("%s(\"%s\") = %x", h, str, hashes[h].Sum(nil))
			hashes[h].Reset()
		}(h)
	}
	wg.Wait()
	display()
}

func hash_file(filename string) (errors bool) {
	for h := range hashes {
		go func(h string) {
			f, err := os.Open(filename)
			if err != nil {
				done <- err
				return
			}
			defer f.Close()

			if _, err := io.Copy(hashes[h], f); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s(%s) = %x", h, filename, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if !errors {
		display()
	}
	return
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil && !os.IsPermission(err) {
		return err
	}
	if f.Mode().IsRegular() {
		hash_file(path)
	}
	return nil
}

func hash_dir(dir string) bool {
	err := filepath.Walk(dir, visit)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
		return false
	}
	return true
}

func hash_stdin() (errors bool) {
	for h := range hashes {
		go func(h string) {
			if _, err := io.Copy(hashes[h], os.Stdin); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s() = %x", h, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if !errors {
		display()
	}
	return
}
<commit_msg>Use slice instead of map for performance. Remove -ossl, -blake2, -sha2, sha3 group options<commit_after>// (C) 2016 by Ricardo Branco
//
// MIT License
//
// v0.3.4
//
// TODO:
// + Support HMAC
// + Read filenames from file
// + Support -c option like md5sum(1)
// + Use getopt
// + Use different output formats for display

package main

import (
	"crypto"
	/*
		_ "crypto/md5"
		_ "crypto/sha1"
		_ "crypto/sha256"
		_ "crypto/sha512"
	*/
	"flag"
	"fmt"
	"github.com/ricardobranco777/dgst/blake2b"
	"github.com/ricardobranco777/dgst/blake2s"
	_ "github.com/ricardobranco777/dgst/md4"
	_ "github.com/ricardobranco777/dgst/md5"
	_ "github.com/ricardobranco777/dgst/ripemd160"
	_ "github.com/ricardobranco777/dgst/sha1"
	_ "github.com/ricardobranco777/dgst/sha256"
	_ "github.com/ricardobranco777/dgst/sha512"
	/*
		"golang.org/x/crypto/blake2b"
		"golang.org/x/crypto/blake2s"
		_ "golang.org/x/crypto/md4"
		_ "golang.org/x/crypto/ripemd160"
	*/
	_ "golang.org/x/crypto/sha3"
	"hash"
	"io"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

const (
	BLAKE2b256 = 100 + iota
	BLAKE2b384
	BLAKE2b512
	BLAKE2s256
)

var hashes = []*struct {
	hash crypto.Hash
	name string
	sum  string
	hash.Hash
	size int
}{
	{name: "BLAKE2b256",
		hash: BLAKE2b256,
		size: 32},
	{name: "BLAKE2b384",
		hash: BLAKE2b384,
		size: 48},
	{name: "BLAKE2b512",
		hash: BLAKE2b512,
		size: 64},
	{name: "BLAKE2s256",
		hash: BLAKE2s256,
		size: 32},
	{name: "MD4",
		hash: crypto.MD4,
		size: 16},
	{name: "MD5",
		hash: crypto.MD5,
		size: 16},
	{name: "RIPEMD160",
		hash: crypto.RIPEMD160,
		size: 20},
	{name: "SHA1",
		hash: crypto.SHA1,
		size: 20},
	{name: "SHA224",
		hash: crypto.SHA224,
		size: 28},
	{name: "SHA256",
		hash: crypto.SHA256,
		size: 32},
	{name: "SHA384",
		hash: crypto.SHA384,
		size: 48},
	{name: "SHA512",
		hash: crypto.SHA512,
		size: 64},
	{name: "SHA512-224",
		hash: crypto.SHA512_224,
		size: 28},
	{name: "SHA512-256",
		hash: crypto.SHA512_256,
		size: 32},
	{name: "SHA3-224",
		hash: crypto.SHA3_224,
		size: 28},
	{name: "SHA3-256",
		hash: crypto.SHA3_256,
		size: 32},
	{name: "SHA3-384",
		hash: crypto.SHA3_384,
		size: 48},
	{name: "SHA3-512",
		hash: crypto.SHA3_512,
		size: 64},
}

var progname string

var done chan error

func main() {
	progname = path.Base(os.Args[0])

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [OPTIONS] [-s STRING...]|[FILE... DIRECTORY...]\n\n", progname)
		flag.PrintDefaults()
	}

	chosen := make(map[crypto.Hash]*bool)
	for i := range hashes {
		name := strings.ToLower(hashes[i].name)
		chosen[hashes[i].hash] = flag.Bool(name, false, fmt.Sprintf("%s algorithm", name))
	}

	var all, isString *bool
	all = flag.Bool("all", false, "all algorithms")
	isString = flag.Bool("s", false, "treat arguments as strings")

	var size_hashes = map[int]*struct {
		hashes []crypto.Hash
		set    *bool
	}{
		128: {},
		160: {},
		224: {},
		256: {},
		384: {},
		512: {},
	}

	for h := range hashes {
		size_hashes[hashes[h].size*8].hashes = append(size_hashes[hashes[h].size*8].hashes, hashes[h].hash)
	}

	for size := range size_hashes {
		sizeStr := strconv.Itoa(size)
		if len(size_hashes[size].hashes) > 0 {
			size_hashes[size].set = flag.Bool(sizeStr, false, "all "+sizeStr+" bits algorithms")
		}
	}

	flag.Parse()

	for size := range size_hashes {
		if !*(size_hashes[size].set) {
			continue
		}
		for _, h := range size_hashes[size].hashes {
			*chosen[h] = true
		}
	}

	if !(*all || choices(chosen)) {
		*all = true
	}

	for h := range chosen {
		if (*all && *chosen[h]) || !(*all || *chosen[h]) {
			removeHash(h)
		}
		delete(chosen, h)
	}

	for i := 0; ; i++ {
		if i >= len(hashes) {
			break
		}
		switch hashes[i].hash {
		case BLAKE2b256:
			hashes[i].Hash = blake2_(blake2b.New256)
		case BLAKE2b384:
			hashes[i].Hash = blake2_(blake2b.New384)
		case BLAKE2b512:
			hashes[i].Hash = blake2_(blake2b.New512)
		case BLAKE2s256:
			hashes[i].Hash = blake2_(blake2s.New256)
		default:
			if !hashes[i].hash.Available() {
				removeHash(hashes[i].hash)
				i--
				continue
			}
			hashes[i].Hash = hashes[i].hash.New()
		}
	}

	if len(hashes) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	if flag.NArg() == 0 {
		hash_stdin()
		os.Exit(0)
	}

	var errors bool

	if *isString {
		for _, s := range flag.Args() {
			hash_string(s)
		}
	} else {
		done = make(chan error, len(hashes))
		defer close(done)

		for _, pathname := range flag.Args() {
			info, err := os.Stat(pathname)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
				errors = true
			} else if info.IsDir() {
				errors = hash_dir(pathname)
			} else {
				errors = hash_file(pathname)
			}
		}
	}

	if errors {
		os.Exit(1)
	}
}

func removeHash(h crypto.Hash) {
	i := -1
	for i = range hashes {
		if hashes[i].hash == h {
			break
		}
	}
	copy(hashes[i:], hashes[i+1:])
	hashes[len(hashes)-1] = nil // item will be garbage-collected
	hashes = hashes[:len(hashes)-1]
}

// Wrapper for the Blake2 New() methods that needs an optional for MAC
func blake2_(f func([]byte) (hash.Hash, error)) hash.Hash {
	h, _ := f(nil)
	return h
}

// Returns true if at least some algorithm was specified on the command line
func choices(chosen map[crypto.Hash]*bool) bool {
	for h := range chosen {
		if *chosen[h] {
			return true
		}
	}
	return false
}

func display() {
	for i := range hashes {
		fmt.Println(hashes[i].sum)
	}
}

func hash_string(str string) {
	var wg sync.WaitGroup
	wg.Add(len(hashes))
	for h := range hashes {
		go func(h int) {
			defer wg.Done()
			hashes[h].Write([]byte(str))
			hashes[h].sum = fmt.Sprintf("%s(\"%s\") = %x", hashes[h].name, str, hashes[h].Sum(nil))
			hashes[h].Reset()
		}(h)
	}
	wg.Wait()
	display()
}

func hash_file(filename string) (errors bool) {
	for h := range hashes {
		go func(h int) {
			f, err := os.Open(filename)
			if err != nil {
				done <- err
				return
			}
			defer f.Close()

			if _, err := io.Copy(hashes[h], f); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s(%s) = %x", hashes[h].name, filename, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if !errors {
		display()
	}
	return
}

func visit(path string, f os.FileInfo, err error) error {
	if err != nil && !os.IsPermission(err) {
		return err
	}
	if f.Mode().IsRegular() {
		hash_file(path)
	}
	return nil
}

func hash_dir(dir string) bool {
	err := filepath.Walk(dir, visit)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
		return false
	}
	return true
}

func hash_stdin() (errors bool) {
	for h := range hashes {
		go func(h int) {
			if _, err := io.Copy(hashes[h], os.Stdin); err != nil {
				done <- err
				return
			}
			hashes[h].sum = fmt.Sprintf("%s() = %x", hashes[h].name, hashes[h].Sum(nil))
			hashes[h].Reset()
			done <- nil
		}(h)
	}
	for range hashes {
		err := <-done
		if err != nil {
			if !errors {
				fmt.Fprintf(os.Stderr, "%s: %v\n", progname, err)
			}
			errors = true
		}
	}
	if !errors {
		display()
	}
	return
}
<|endoftext|>


<commit_before>// This file is part of *xliffer*
//
// Copyright (C) 2015, Travelping GmbH <copyright@travelping.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"encoding/xml"
	"os"
)

type xliffTransUnitInner struct {
	Inner string `xml:",chardata"`
	Lang  string `xml:"xml:lang,attr"`
	Space string `xml:"xml:space,attr"`
}

type xliffTransUnit struct {
	ID     string              `xml:"id,attr"`
	Source xliffTransUnitInner `xml:"source"`
	Target xliffTransUnitInner `xml:"target"`
	Note   string              `xml:"note,omitempty"`
}

type xliffBody struct {
	XMLName   xml.Name         `xml:"body"`
	TransUnit []xliffTransUnit `xml:"trans-unit"`
}

type xliffFile struct {
	Original   string    `xml:"original,attr"`
	SourceLang string    `xml:"source-language,attr,omitempty"`
	TargetLang string    `xml:"target-language,attr,omitempty"`
	DataType   string    `xml:"datatype,attr,omitempty"`
	Body       xliffBody `xml:"body"`
}

type xliffDoc struct {
	XMLName xml.Name    `xml:"xliff"`
	Version string      `xml:"version,attr"`
	Xmlns   string      `xml:"xmlns,attr"`
	File    []xliffFile `xml:"file"`
}

func newXliffDoc(original, origLang string) *xliffDoc {

	var doc = new(xliffDoc)

	doc.Version = "1.2"
	doc.Xmlns = "urn:oasis:names:tc:xliff:document:1.2"
	doc.File = make([]xliffFile, 1)
	doc.File[0].Original = original
	doc.File[0].Body.TransUnit = []xliffTransUnit{}
	doc.File[0].SourceLang = origLang
	doc.File[0].DataType = "html"

	return doc
}

func xliffFromFile(fileName string) (*xliffDoc, error) {
	var f, err = os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var doc = new(xliffDoc)
	var dec = xml.NewDecoder(f)
	if err = dec.Decode(doc); err != nil {
		return nil, err
	}
	return doc, err
}
<commit_msg>omit empty attributes; don't enforce xml-namespace<commit_after>// This file is part of *xliffer*
//
// Copyright (C) 2015, Travelping GmbH <copyright@travelping.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package main

import (
	"encoding/xml"
	"os"
)

type xliffTransUnitInner struct {
	Inner string `xml:",chardata"`
	Lang  string `xml:"lang,attr"`
	Space string `xml:"space,attr,omitempty"`
}

type xliffTransUnit struct {
	ID     string              `xml:"id,attr"`
	Source xliffTransUnitInner `xml:"source"`
	Target xliffTransUnitInner `xml:"target"`
	Note   string              `xml:"note,omitempty"`
}

type xliffBody struct {
	XMLName   xml.Name         `xml:"body"`
	TransUnit []xliffTransUnit `xml:"trans-unit"`
}

type xliffFile struct {
	Original   string    `xml:"original,attr"`
	SourceLang string    `xml:"source-language,attr,omitempty"`
	TargetLang string    `xml:"target-language,attr,omitempty"`
	DataType   string    `xml:"datatype,attr,omitempty"`
	Body       xliffBody `xml:"body"`
}

type xliffDoc struct {
	XMLName xml.Name    `xml:"xliff"`
	Version string      `xml:"version,attr"`
	Xmlns   string      `xml:"xmlns,attr"`
	File    []xliffFile `xml:"file"`
}

func newXliffDoc(original, origLang string) *xliffDoc {

	var doc = new(xliffDoc)

	doc.Version = "1.2"
	doc.Xmlns = "urn:oasis:names:tc:xliff:document:1.2"
	doc.File = make([]xliffFile, 1)
	doc.File[0].Original = original
	doc.File[0].Body.TransUnit = []xliffTransUnit{}
	doc.File[0].SourceLang = origLang
	doc.File[0].DataType = "html"

	return doc
}

func xliffFromFile(fileName string) (*xliffDoc, error) {
	var f, err = os.Open(fileName)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var doc = new(xliffDoc)
	var dec = xml.NewDecoder(f)
	if err = dec.Decode(doc); err != nil {
		return nil, err
	}
	return doc, err
}
<|endoftext|>


<commit_before>// Copyright 2014 The goyy Authors.  All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package xhttp

import (
	"gopkg.in/goyy/goyy.v0/data/domain"
	"gopkg.in/goyy/goyy.v0/data/entity"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/web/session"
	"net/http"
	"net/url"
)

func newContext(w http.ResponseWriter, s session.Interface, r *http.Request, vs url.Values, hs Handlers) Context {
	c := &context{}
	c.request = r
	c.session = s
	c.response = w
	c.params = vs
	c.attributes = make(map[string]interface{}, 0)
	c.handlers = hs
	return c
}

type context struct {
	request    *http.Request
	session    session.Interface
	response   http.ResponseWriter
	params     url.Values
	attributes map[string]interface{}
	handlers   Handlers
	index      int8
}

func (me *context) Request() *http.Request {
	return me.request
}

func (me *context) Session() session.Interface {
	return me.session
}

func (me *context) ResponseWriter() http.ResponseWriter {
	return me.response
}

func (me *context) Params() url.Values {
	return me.params
}

func (me *context) Param(key string) string {
	return strings.JoinIgnoreBlank(me.params[key], ",")
}

func (me *context) Bind(out entity.Interface) error {
	sifts, err := domain.NewSifts(me.params, defaultEntityPrefix)
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	for _, sift := range sifts {
		out.SetString(sift.Key(), sift.Value())
	}
	return nil
}

func (me *context) Attribute(key string) interface{} {
	return me.attributes[key]
}

func (me *context) Attributes() map[string]interface{} {
	return me.attributes
}

func (me *context) SetAttribute(key string, value interface{}) {
	if strings.IsNotBlank(key) && value != nil {
		me.attributes[key] = value
	}
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
func (me *context) Next() {
	s := int8(len(me.handlers))
	if s > 0 && me.index < s {
		i := me.index
		me.index++
		me.handlers[i](me)
	}
}

// Returns if the currect context was aborted.
func (me *context) IsAborted() bool {
	return me.index == AbortIndex
}

// Stops the system to continue calling the pending handlers in the chain.
// Let's say you have an authorization middleware that validates if the request is authorized
// if the authorization fails (the password does not match). This method (Abort()) should be called
// in order to stop the execution of the actual handler.
func (me *context) Abort() {
	me.index = AbortIndex
}

// It calls Abort() and writes the headers with the specified status code.
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
func (me *context) AbortWithStatus(code int) {
	me.response.WriteHeader(code)
	me.Abort()
}

func (me *context) HTML(status int, name string, v interface{}) error {
	return r.HTML(me.ResponseWriter(), status, name, v)
}

func (me *context) JSON(status int, v interface{}) error {
	return r.JSON(me.ResponseWriter(), status, v)
}

func (me *context) JSONP(status int, callback string, v interface{}) error {
	return r.JSONP(me.ResponseWriter(), status, callback, v)
}

func (me *context) XML(status int, v interface{}) error {
	return r.XML(me.ResponseWriter(), status, v)
}

func (me *context) Text(status int, format string, values ...interface{}) error {
	return r.Text(me.ResponseWriter(), status, format, values...)
}

func (me *context) Error(status int) error {
	return r.Error(me.ResponseWriter(), status)
}

func (me *context) Redirect(location string, status ...int) error {
	return r.Redirect(me.ResponseWriter(), me.Request(), location, status...)
}
<commit_msg>Context.Bind : value isBlank -> exec SetString(k, value)<commit_after>// Copyright 2014 The goyy Authors.  All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package xhttp

import (
	"gopkg.in/goyy/goyy.v0/data/entity"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/web/session"
	"net/http"
	"net/url"
)

func newContext(w http.ResponseWriter, s session.Interface, r *http.Request, vs url.Values, hs Handlers) Context {
	c := &context{}
	c.request = r
	c.session = s
	c.response = w
	c.params = vs
	c.attributes = make(map[string]interface{}, 0)
	c.handlers = hs
	return c
}

type context struct {
	request    *http.Request
	session    session.Interface
	response   http.ResponseWriter
	params     url.Values
	attributes map[string]interface{}
	handlers   Handlers
	index      int8
}

func (me *context) Request() *http.Request {
	return me.request
}

func (me *context) Session() session.Interface {
	return me.session
}

func (me *context) ResponseWriter() http.ResponseWriter {
	return me.response
}

func (me *context) Params() url.Values {
	return me.params
}

func (me *context) Param(key string) string {
	return strings.JoinIgnoreBlank(me.params[key], ",")
}

func (me *context) Bind(out entity.Interface) error {
	for k, v := range me.params {
		value := strings.JoinIgnoreBlank(v, ",")
		// value isNotBlank -> exec SetString(k, value)
		// value isBlank -> exec SetString(k, value)
		if err := out.SetString(k, value); err != nil {
			logger.Error(err.Error())
			return err
		}
	}
	return nil
}

func (me *context) Attribute(key string) interface{} {
	return me.attributes[key]
}

func (me *context) Attributes() map[string]interface{} {
	return me.attributes
}

func (me *context) SetAttribute(key string, value interface{}) {
	if strings.IsNotBlank(key) && value != nil {
		me.attributes[key] = value
	}
}

// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
func (me *context) Next() {
	s := int8(len(me.handlers))
	if s > 0 && me.index < s {
		i := me.index
		me.index++
		me.handlers[i](me)
	}
}

// Returns if the currect context was aborted.
func (me *context) IsAborted() bool {
	return me.index == AbortIndex
}

// Stops the system to continue calling the pending handlers in the chain.
// Let's say you have an authorization middleware that validates if the request is authorized
// if the authorization fails (the password does not match). This method (Abort()) should be called
// in order to stop the execution of the actual handler.
func (me *context) Abort() {
	me.index = AbortIndex
}

// It calls Abort() and writes the headers with the specified status code.
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
func (me *context) AbortWithStatus(code int) {
	me.response.WriteHeader(code)
	me.Abort()
}

func (me *context) HTML(status int, name string, v interface{}) error {
	return r.HTML(me.ResponseWriter(), status, name, v)
}

func (me *context) JSON(status int, v interface{}) error {
	return r.JSON(me.ResponseWriter(), status, v)
}

func (me *context) JSONP(status int, callback string, v interface{}) error {
	return r.JSONP(me.ResponseWriter(), status, callback, v)
}

func (me *context) XML(status int, v interface{}) error {
	return r.XML(me.ResponseWriter(), status, v)
}

func (me *context) Text(status int, format string, values ...interface{}) error {
	return r.Text(me.ResponseWriter(), status, format, values...)
}

func (me *context) Error(status int) error {
	return r.Error(me.ResponseWriter(), status)
}

func (me *context) Redirect(location string, status ...int) error {
	return r.Redirect(me.ResponseWriter(), me.Request(), location, status...)
}
<|endoftext|>