<commit_before>package sparc

import (
	cs "github.com/bnagy/gapstone"
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"

	"github.com/lunixbochs/usercorn/go/models"
)

var Arch = &models.Arch{
	Bits:    32,
	Radare:  "sparc",
	CS_ARCH: cs.CS_ARCH_SPARC,
	CS_MODE: cs.CS_MODE_32,
	UC_ARCH: uc.ARCH_SPARC,
	UC_MODE: uc.MODE_32,
	PC:      uc.SPARC_REG_PC,
	SP:      uc.SPARC_REG_SP,
	Regs: map[string]int{
		// "g0": uc.SPARC_REG_G0, // g0 is always zero
		"g1": uc.SPARC_REG_G1,
		"g2": uc.SPARC_REG_G2,
		"g3": uc.SPARC_REG_G3,
		"g4": uc.SPARC_REG_G4,
		"g5": uc.SPARC_REG_G5,
		"g6": uc.SPARC_REG_G6,
		"g7": uc.SPARC_REG_G7,
		"o0": uc.SPARC_REG_O0,
		"o1": uc.SPARC_REG_O1,
		"o2": uc.SPARC_REG_O2,
		"o3": uc.SPARC_REG_O3,
		"o4": uc.SPARC_REG_O4,
		"o5": uc.SPARC_REG_O5,
		"o6": uc.SPARC_REG_O6, // sp
		"o7": uc.SPARC_REG_O7,
		"l0": uc.SPARC_REG_L0,
		"l1": uc.SPARC_REG_L1,
		"l2": uc.SPARC_REG_L2,
		"l3": uc.SPARC_REG_L3,
		"l4": uc.SPARC_REG_L4,
		"l5": uc.SPARC_REG_L5,
		"l6": uc.SPARC_REG_L6,
		"l7": uc.SPARC_REG_L7,
		"i0": uc.SPARC_REG_I0,
		"i1": uc.SPARC_REG_I1,
		"i2": uc.SPARC_REG_I2,
		"i3": uc.SPARC_REG_I3,
		"i4": uc.SPARC_REG_I4,
		"i5": uc.SPARC_REG_I5,
		"i6": uc.SPARC_REG_I6, // fp
		"i7": uc.SPARC_REG_I7,

		"sp": uc.SPARC_REG_SP,
		"fp": uc.SPARC_REG_FP,
	},
	DefaultRegs: []string{
		"g1", "g2", "g3", "g4", "g5", "g6", "g7",
		"o0", "o1", "o2", "o3", "o4", "o5", "o7",
		"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
		"i0", "i1", "i2", "i3", "i4", "i5", "i7",
	},
}
<commit_msg>fix sparc32 init<commit_after>package sparc

import (
	cs "github.com/bnagy/gapstone"
	uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"

	"github.com/lunixbochs/usercorn/go/models"
)

var Arch = &models.Arch{
	Bits:    32,
	Radare:  "sparc",
	CS_ARCH: cs.CS_ARCH_SPARC,
	CS_MODE: cs.CS_MODE_32,
	UC_ARCH: uc.ARCH_SPARC,
	UC_MODE: uc.MODE_SPARC32 | uc.MODE_BIG_ENDIAN,
	PC:      uc.SPARC_REG_PC,
	SP:      uc.SPARC_REG_SP,
	Regs: map[string]int{
		// "g0": uc.SPARC_REG_G0, // g0 is always zero
		"g1": uc.SPARC_REG_G1,
		"g2": uc.SPARC_REG_G2,
		"g3": uc.SPARC_REG_G3,
		"g4": uc.SPARC_REG_G4,
		"g5": uc.SPARC_REG_G5,
		"g6": uc.SPARC_REG_G6,
		"g7": uc.SPARC_REG_G7,
		"o0": uc.SPARC_REG_O0,
		"o1": uc.SPARC_REG_O1,
		"o2": uc.SPARC_REG_O2,
		"o3": uc.SPARC_REG_O3,
		"o4": uc.SPARC_REG_O4,
		"o5": uc.SPARC_REG_O5,
		"o6": uc.SPARC_REG_O6, // sp
		"o7": uc.SPARC_REG_O7,
		"l0": uc.SPARC_REG_L0,
		"l1": uc.SPARC_REG_L1,
		"l2": uc.SPARC_REG_L2,
		"l3": uc.SPARC_REG_L3,
		"l4": uc.SPARC_REG_L4,
		"l5": uc.SPARC_REG_L5,
		"l6": uc.SPARC_REG_L6,
		"l7": uc.SPARC_REG_L7,
		"i0": uc.SPARC_REG_I0,
		"i1": uc.SPARC_REG_I1,
		"i2": uc.SPARC_REG_I2,
		"i3": uc.SPARC_REG_I3,
		"i4": uc.SPARC_REG_I4,
		"i5": uc.SPARC_REG_I5,
		"i6": uc.SPARC_REG_I6, // fp
		"i7": uc.SPARC_REG_I7,

		"sp": uc.SPARC_REG_SP,
		"fp": uc.SPARC_REG_FP,
	},
	DefaultRegs: []string{
		"g1", "g2", "g3", "g4", "g5", "g6", "g7",
		"o0", "o1", "o2", "o3", "o4", "o5", "o7",
		"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
		"i0", "i1", "i2", "i3", "i4", "i5", "i7",
	},
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 dockertools

import (
	"encoding/json"
	"strconv"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	"k8s.io/kubernetes/pkg/kubelet/custommetrics"
	"k8s.io/kubernetes/pkg/kubelet/util/format"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/types"
)

// This file contains all docker label related constants and functions, including:
//  * label setters and getters
//  * label filters (maybe in the future)

const (
	kubernetesPodNameLabel                   = "io.kubernetes.pod.name"
	kubernetesPodNamespaceLabel              = "io.kubernetes.pod.namespace"
	kubernetesPodUIDLabel                    = "io.kubernetes.pod.uid"
	kubernetesPodDeletionGracePeriodLabel    = "io.kubernetes.pod.deletionGracePeriod"
	kubernetesPodTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod"

	kubernetesContainerNameLabel                   = "io.kubernetes.container.name"
	kubernetesContainerHashLabel                   = "io.kubernetes.container.hash"
	kubernetesContainerRestartCountLabel           = "io.kubernetes.container.restartCount"
	kubernetesContainerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
	kubernetesContainerPreStopHandlerLabel         = "io.kubernetes.container.preStopHandler"

	// TODO(random-liu): Keep this for old containers, remove this when we drop support for v1.1.
	kubernetesPodLabel = "io.kubernetes.pod.data"

	cadvisorPrometheusMetricsLabel = "io.cadvisor.metric.prometheus"
)

// Container information which has been labelled on each docker container
// TODO(random-liu): The type of Hash should be compliance with kubelet container status.
type labelledContainerInfo struct {
	PodName                   string
	PodNamespace              string
	PodUID                    types.UID
	PodDeletionGracePeriod    *int64
	PodTerminationGracePeriod *int64
	Name                      string
	Hash                      string
	RestartCount              int
	TerminationMessagePath    string
	PreStopHandler            *api.Handler
}

func GetContainerName(labels map[string]string) string {
	return labels[kubernetesContainerNameLabel]
}

func GetPodName(labels map[string]string) string {
	return labels[kubernetesPodNameLabel]
}

func GetPodUID(labels map[string]string) string {
	return labels[kubernetesPodUIDLabel]
}

func GetPodNamespace(labels map[string]string) string {
	return labels[kubernetesPodNamespaceLabel]
}

func newLabels(container *api.Container, pod *api.Pod, restartCount int, enableCustomMetrics bool) map[string]string {
	labels := map[string]string{}
	labels[kubernetesPodNameLabel] = pod.Name
	labels[kubernetesPodNamespaceLabel] = pod.Namespace
	labels[kubernetesPodUIDLabel] = string(pod.UID)
	if pod.DeletionGracePeriodSeconds != nil {
		labels[kubernetesPodDeletionGracePeriodLabel] = strconv.FormatInt(*pod.DeletionGracePeriodSeconds, 10)
	}
	if pod.Spec.TerminationGracePeriodSeconds != nil {
		labels[kubernetesPodTerminationGracePeriodLabel] = strconv.FormatInt(*pod.Spec.TerminationGracePeriodSeconds, 10)
	}

	labels[kubernetesContainerNameLabel] = container.Name
	labels[kubernetesContainerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16)
	labels[kubernetesContainerRestartCountLabel] = strconv.Itoa(restartCount)
	labels[kubernetesContainerTerminationMessagePathLabel] = container.TerminationMessagePath
	if container.Lifecycle != nil && container.Lifecycle.PreStop != nil {
		// Using json enconding so that the PreStop handler object is readable after writing as a label
		rawPreStop, err := json.Marshal(container.Lifecycle.PreStop)
		if err != nil {
			glog.Errorf("Unable to marshal lifecycle PreStop handler for container %q of pod %q: %v", container.Name, format.Pod(pod), err)
		} else {
			labels[kubernetesContainerPreStopHandlerLabel] = string(rawPreStop)
		}
	}

	if enableCustomMetrics {
		path, err := custommetrics.GetCAdvisorCustomMetricsDefinitionPath(container)
		if path != nil && err == nil {
			labels[cadvisorPrometheusMetricsLabel] = *path
		}
	}

	return labels
}

func getContainerInfoFromLabel(labels map[string]string) *labelledContainerInfo {
	var err error
	containerInfo := &labelledContainerInfo{
		PodName:      getStringValueFromLabel(labels, kubernetesPodNameLabel),
		PodNamespace: getStringValueFromLabel(labels, kubernetesPodNamespaceLabel),
		PodUID:       types.UID(getStringValueFromLabel(labels, kubernetesPodUIDLabel)),
		Name:         getStringValueFromLabel(labels, kubernetesContainerNameLabel),
		Hash:         getStringValueFromLabel(labels, kubernetesContainerHashLabel),
		TerminationMessagePath: getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePathLabel),
	}
	if containerInfo.RestartCount, err = getIntValueFromLabel(labels, kubernetesContainerRestartCountLabel); err != nil {
		logError(containerInfo, kubernetesContainerRestartCountLabel, err)
	}
	if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodDeletionGracePeriodLabel); err != nil {
		logError(containerInfo, kubernetesPodDeletionGracePeriodLabel, err)
	}
	if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodTerminationGracePeriodLabel); err != nil {
		logError(containerInfo, kubernetesPodTerminationGracePeriodLabel, err)
	}
	preStopHandler := &api.Handler{}
	if found, err := getJsonObjectFromLabel(labels, kubernetesContainerPreStopHandlerLabel, preStopHandler); err != nil {
		logError(containerInfo, kubernetesContainerPreStopHandlerLabel, err)
	} else if found {
		containerInfo.PreStopHandler = preStopHandler
	}
	supplyContainerInfoWithOldLabel(labels, containerInfo)
	return containerInfo
}

func getStringValueFromLabel(labels map[string]string, label string) string {
	if value, found := labels[label]; found {
		return value
	}
	// Do not report error, because there should be many old containers without label now.
	glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
	// Return empty string "" for these containers, the caller will get value by other ways.
	return ""
}

func getIntValueFromLabel(labels map[string]string, label string) (int, error) {
	if strValue, found := labels[label]; found {
		intValue, err := strconv.Atoi(strValue)
		if err != nil {
			// This really should not happen. Just set value to 0 to handle this abnormal case
			return 0, err
		}
		return intValue, nil
	}
	// Do not report error, because there should be many old containers without label now.
	glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
	// Just set the value to 0
	return 0, nil
}

func getInt64PointerFromLabel(labels map[string]string, label string) (*int64, error) {
	if strValue, found := labels[label]; found {
		int64Value, err := strconv.ParseInt(strValue, 10, 64)
		if err != nil {
			return nil, err
		}
		return &int64Value, nil
	}
	// Because it's normal that a container has no PodDeletionGracePeriod and PodTerminationGracePeriod label,
	// don't report any error here.
	return nil, nil
}

// getJsonObjectFromLabel returns a bool value indicating whether an object is found
func getJsonObjectFromLabel(labels map[string]string, label string, value interface{}) (bool, error) {
	if strValue, found := labels[label]; found {
		err := json.Unmarshal([]byte(strValue), value)
		return found, err
	}
	// Because it's normal that a container has no PreStopHandler label, don't report any error here.
	return false, nil
}

// The label kubernetesPodLabel is added a long time ago (#7421), it serialized the whole api.Pod to a docker label.
// We want to remove this label because it serialized too much useless information. However kubelet may still work
// with old containers which only have this label for a long time until we completely deprecate the old label.
// Before that to ensure correctness we have to supply information with the old labels when newly added labels
// are not available.
// TODO(random-liu): Remove this function when we can completely remove label kubernetesPodLabel, probably after
// dropping support for v1.1.
func supplyContainerInfoWithOldLabel(labels map[string]string, containerInfo *labelledContainerInfo) {
	// Get api.Pod from old label
	var pod *api.Pod
	data, found := labels[kubernetesPodLabel]
	if !found {
		// Don't report any error here, because it's normal that a container has no pod label, especially
		// when we gradually deprecate the old label
		return
	}
	pod = &api.Pod{}
	if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), []byte(data), pod); err != nil {
		// If the pod label can't be parsed, we should report an error
		logError(containerInfo, kubernetesPodLabel, err)
		return
	}
	if containerInfo.PodDeletionGracePeriod == nil {
		containerInfo.PodDeletionGracePeriod = pod.DeletionGracePeriodSeconds
	}
	if containerInfo.PodTerminationGracePeriod == nil {
		containerInfo.PodTerminationGracePeriod = pod.Spec.TerminationGracePeriodSeconds
	}

	// Get api.Container from api.Pod
	var container *api.Container
	for i := range pod.Spec.Containers {
		if pod.Spec.Containers[i].Name == containerInfo.Name {
			container = &pod.Spec.Containers[i]
			break
		}
	}
	if container == nil {
		glog.Errorf("Unable to find container %q in pod %q", containerInfo.Name, format.Pod(pod))
		return
	}
	if containerInfo.PreStopHandler == nil && container.Lifecycle != nil {
		containerInfo.PreStopHandler = container.Lifecycle.PreStop
	}
}

func logError(containerInfo *labelledContainerInfo, label string, err error) {
	glog.Errorf("Unable to get %q for container %q of pod %q: %v", label, containerInfo.Name,
		kubecontainer.BuildPodFullName(containerInfo.PodName, containerInfo.PodNamespace), err)
}
<commit_msg>sync pod's labels to docker container config<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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 dockertools

import (
	"encoding/json"
	"strconv"

	"github.com/golang/glog"
	"k8s.io/kubernetes/pkg/api"
	kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
	"k8s.io/kubernetes/pkg/kubelet/custommetrics"
	"k8s.io/kubernetes/pkg/kubelet/util/format"
	"k8s.io/kubernetes/pkg/runtime"
	"k8s.io/kubernetes/pkg/types"
)

// This file contains all docker label related constants and functions, including:
//  * label setters and getters
//  * label filters (maybe in the future)

const (
	kubernetesPodNameLabel                   = "io.kubernetes.pod.name"
	kubernetesPodNamespaceLabel              = "io.kubernetes.pod.namespace"
	kubernetesPodUIDLabel                    = "io.kubernetes.pod.uid"
	kubernetesPodDeletionGracePeriodLabel    = "io.kubernetes.pod.deletionGracePeriod"
	kubernetesPodTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod"

	kubernetesContainerNameLabel                   = "io.kubernetes.container.name"
	kubernetesContainerHashLabel                   = "io.kubernetes.container.hash"
	kubernetesContainerRestartCountLabel           = "io.kubernetes.container.restartCount"
	kubernetesContainerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath"
	kubernetesContainerPreStopHandlerLabel         = "io.kubernetes.container.preStopHandler"

	// TODO(random-liu): Keep this for old containers, remove this when we drop support for v1.1.
	kubernetesPodLabel = "io.kubernetes.pod.data"

	cadvisorPrometheusMetricsLabel = "io.cadvisor.metric.prometheus"
)

// Container information which has been labelled on each docker container
// TODO(random-liu): The type of Hash should be compliance with kubelet container status.
type labelledContainerInfo struct {
	PodName                   string
	PodNamespace              string
	PodUID                    types.UID
	PodDeletionGracePeriod    *int64
	PodTerminationGracePeriod *int64
	Name                      string
	Hash                      string
	RestartCount              int
	TerminationMessagePath    string
	PreStopHandler            *api.Handler
}

func GetContainerName(labels map[string]string) string {
	return labels[kubernetesContainerNameLabel]
}

func GetPodName(labels map[string]string) string {
	return labels[kubernetesPodNameLabel]
}

func GetPodUID(labels map[string]string) string {
	return labels[kubernetesPodUIDLabel]
}

func GetPodNamespace(labels map[string]string) string {
	return labels[kubernetesPodNamespaceLabel]
}

func newLabels(container *api.Container, pod *api.Pod, restartCount int, enableCustomMetrics bool) map[string]string {
	labels := map[string]string{}
	// copy pod labels to newLabels
	if pod.Labels != nil {
		labels = pod.Labels
	}
	labels[kubernetesPodNameLabel] = pod.Name
	labels[kubernetesPodNamespaceLabel] = pod.Namespace
	labels[kubernetesPodUIDLabel] = string(pod.UID)
	if pod.DeletionGracePeriodSeconds != nil {
		labels[kubernetesPodDeletionGracePeriodLabel] = strconv.FormatInt(*pod.DeletionGracePeriodSeconds, 10)
	}
	if pod.Spec.TerminationGracePeriodSeconds != nil {
		labels[kubernetesPodTerminationGracePeriodLabel] = strconv.FormatInt(*pod.Spec.TerminationGracePeriodSeconds, 10)
	}

	labels[kubernetesContainerNameLabel] = container.Name
	labels[kubernetesContainerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16)
	labels[kubernetesContainerRestartCountLabel] = strconv.Itoa(restartCount)
	labels[kubernetesContainerTerminationMessagePathLabel] = container.TerminationMessagePath
	if container.Lifecycle != nil && container.Lifecycle.PreStop != nil {
		// Using json enconding so that the PreStop handler object is readable after writing as a label
		rawPreStop, err := json.Marshal(container.Lifecycle.PreStop)
		if err != nil {
			glog.Errorf("Unable to marshal lifecycle PreStop handler for container %q of pod %q: %v", container.Name, format.Pod(pod), err)
		} else {
			labels[kubernetesContainerPreStopHandlerLabel] = string(rawPreStop)
		}
	}

	if enableCustomMetrics {
		path, err := custommetrics.GetCAdvisorCustomMetricsDefinitionPath(container)
		if path != nil && err == nil {
			labels[cadvisorPrometheusMetricsLabel] = *path
		}
	}

	return labels
}

func getContainerInfoFromLabel(labels map[string]string) *labelledContainerInfo {
	var err error
	containerInfo := &labelledContainerInfo{
		PodName:      getStringValueFromLabel(labels, kubernetesPodNameLabel),
		PodNamespace: getStringValueFromLabel(labels, kubernetesPodNamespaceLabel),
		PodUID:       types.UID(getStringValueFromLabel(labels, kubernetesPodUIDLabel)),
		Name:         getStringValueFromLabel(labels, kubernetesContainerNameLabel),
		Hash:         getStringValueFromLabel(labels, kubernetesContainerHashLabel),
		TerminationMessagePath: getStringValueFromLabel(labels, kubernetesContainerTerminationMessagePathLabel),
	}
	if containerInfo.RestartCount, err = getIntValueFromLabel(labels, kubernetesContainerRestartCountLabel); err != nil {
		logError(containerInfo, kubernetesContainerRestartCountLabel, err)
	}
	if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodDeletionGracePeriodLabel); err != nil {
		logError(containerInfo, kubernetesPodDeletionGracePeriodLabel, err)
	}
	if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(labels, kubernetesPodTerminationGracePeriodLabel); err != nil {
		logError(containerInfo, kubernetesPodTerminationGracePeriodLabel, err)
	}
	preStopHandler := &api.Handler{}
	if found, err := getJsonObjectFromLabel(labels, kubernetesContainerPreStopHandlerLabel, preStopHandler); err != nil {
		logError(containerInfo, kubernetesContainerPreStopHandlerLabel, err)
	} else if found {
		containerInfo.PreStopHandler = preStopHandler
	}
	supplyContainerInfoWithOldLabel(labels, containerInfo)
	return containerInfo
}

func getStringValueFromLabel(labels map[string]string, label string) string {
	if value, found := labels[label]; found {
		return value
	}
	// Do not report error, because there should be many old containers without label now.
	glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
	// Return empty string "" for these containers, the caller will get value by other ways.
	return ""
}

func getIntValueFromLabel(labels map[string]string, label string) (int, error) {
	if strValue, found := labels[label]; found {
		intValue, err := strconv.Atoi(strValue)
		if err != nil {
			// This really should not happen. Just set value to 0 to handle this abnormal case
			return 0, err
		}
		return intValue, nil
	}
	// Do not report error, because there should be many old containers without label now.
	glog.V(3).Infof("Container doesn't have label %s, it may be an old or invalid container", label)
	// Just set the value to 0
	return 0, nil
}

func getInt64PointerFromLabel(labels map[string]string, label string) (*int64, error) {
	if strValue, found := labels[label]; found {
		int64Value, err := strconv.ParseInt(strValue, 10, 64)
		if err != nil {
			return nil, err
		}
		return &int64Value, nil
	}
	// Because it's normal that a container has no PodDeletionGracePeriod and PodTerminationGracePeriod label,
	// don't report any error here.
	return nil, nil
}

// getJsonObjectFromLabel returns a bool value indicating whether an object is found
func getJsonObjectFromLabel(labels map[string]string, label string, value interface{}) (bool, error) {
	if strValue, found := labels[label]; found {
		err := json.Unmarshal([]byte(strValue), value)
		return found, err
	}
	// Because it's normal that a container has no PreStopHandler label, don't report any error here.
	return false, nil
}

// The label kubernetesPodLabel is added a long time ago (#7421), it serialized the whole api.Pod to a docker label.
// We want to remove this label because it serialized too much useless information. However kubelet may still work
// with old containers which only have this label for a long time until we completely deprecate the old label.
// Before that to ensure correctness we have to supply information with the old labels when newly added labels
// are not available.
// TODO(random-liu): Remove this function when we can completely remove label kubernetesPodLabel, probably after
// dropping support for v1.1.
func supplyContainerInfoWithOldLabel(labels map[string]string, containerInfo *labelledContainerInfo) {
	// Get api.Pod from old label
	var pod *api.Pod
	data, found := labels[kubernetesPodLabel]
	if !found {
		// Don't report any error here, because it's normal that a container has no pod label, especially
		// when we gradually deprecate the old label
		return
	}
	pod = &api.Pod{}
	if err := runtime.DecodeInto(api.Codecs.UniversalDecoder(), []byte(data), pod); err != nil {
		// If the pod label can't be parsed, we should report an error
		logError(containerInfo, kubernetesPodLabel, err)
		return
	}
	if containerInfo.PodDeletionGracePeriod == nil {
		containerInfo.PodDeletionGracePeriod = pod.DeletionGracePeriodSeconds
	}
	if containerInfo.PodTerminationGracePeriod == nil {
		containerInfo.PodTerminationGracePeriod = pod.Spec.TerminationGracePeriodSeconds
	}

	// Get api.Container from api.Pod
	var container *api.Container
	for i := range pod.Spec.Containers {
		if pod.Spec.Containers[i].Name == containerInfo.Name {
			container = &pod.Spec.Containers[i]
			break
		}
	}
	if container == nil {
		glog.Errorf("Unable to find container %q in pod %q", containerInfo.Name, format.Pod(pod))
		return
	}
	if containerInfo.PreStopHandler == nil && container.Lifecycle != nil {
		containerInfo.PreStopHandler = container.Lifecycle.PreStop
	}
}

func logError(containerInfo *labelledContainerInfo, label string, err error) {
	glog.Errorf("Unable to get %q for container %q of pod %q: %v", label, containerInfo.Name,
		kubecontainer.BuildPodFullName(containerInfo.PodName, containerInfo.PodNamespace), err)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 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 registrytest

import (
	"fmt"
	"testing"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest/resttest"
	etcdstorage "k8s.io/apiserver/pkg/storage/etcd"
	etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	storagetesting "k8s.io/apiserver/pkg/storage/testing"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
)

func NewEtcdStorage(t *testing.T, group string) (*storagebackend.Config, *etcdtesting.EtcdTestServer) {
	server, config := etcdtesting.NewUnsecuredEtcd3TestClientServer(t, api.Scheme)
	config.Codec = testapi.Groups[group].StorageCodec()
	return config, server
}

type Tester struct {
	tester  *resttest.Tester
	storage *genericregistry.Store
}
type UpdateFunc func(runtime.Object) runtime.Object

func New(t *testing.T, storage *genericregistry.Store) *Tester {
	return &Tester{
		tester:  resttest.New(t, storage, api.Scheme),
		storage: storage,
	}
}

func (t *Tester) TestNamespace() string {
	return t.tester.TestNamespace()
}

func (t *Tester) ClusterScope() *Tester {
	t.tester = t.tester.ClusterScope()
	return t
}

func (t *Tester) Namer(namer func(int) string) *Tester {
	t.tester = t.tester.Namer(namer)
	return t
}

func (t *Tester) AllowCreateOnUpdate() *Tester {
	t.tester = t.tester.AllowCreateOnUpdate()
	return t
}

func (t *Tester) GeneratesName() *Tester {
	t.tester = t.tester.GeneratesName()
	return t
}

func (t *Tester) ReturnDeletedObject() *Tester {
	t.tester = t.tester.ReturnDeletedObject()
	return t
}

func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) {
	t.tester.TestCreate(
		valid,
		t.createObject,
		t.getObject,
		invalid...,
	)
}

func (t *Tester) TestUpdate(valid runtime.Object, validUpdateFunc UpdateFunc, invalidUpdateFunc ...UpdateFunc) {
	var invalidFuncs []resttest.UpdateFunc
	for _, f := range invalidUpdateFunc {
		invalidFuncs = append(invalidFuncs, resttest.UpdateFunc(f))
	}
	t.tester.TestUpdate(
		valid,
		t.createObject,
		t.getObject,
		resttest.UpdateFunc(validUpdateFunc),
		invalidFuncs...,
	)
}

func (t *Tester) TestDelete(valid runtime.Object) {
	t.tester.TestDelete(
		valid,
		t.createObject,
		t.getObject,
		errors.IsNotFound,
	)
}

func (t *Tester) TestDeleteGraceful(valid runtime.Object, expectedGrace int64) {
	t.tester.TestDeleteGraceful(
		valid,
		t.createObject,
		t.getObject,
		expectedGrace,
	)
}

func (t *Tester) TestGet(valid runtime.Object) {
	t.tester.TestGet(valid)
}

func (t *Tester) TestList(valid runtime.Object) {
	t.tester.TestList(
		valid,
		t.setObjectsForList,
	)
}

func (t *Tester) TestWatch(valid runtime.Object, labelsPass, labelsFail []labels.Set, fieldsPass, fieldsFail []fields.Set) {
	t.tester.TestWatch(
		valid,
		t.emitObject,
		labelsPass,
		labelsFail,
		fieldsPass,
		fieldsFail,
		// TODO: This should be filtered, the registry should not be aware of this level of detail
		[]string{etcdstorage.EtcdCreate, etcdstorage.EtcdDelete},
	)
}

// =============================================================================
// get codec based on runtime.Object
func getCodec(obj runtime.Object) (runtime.Codec, error) {
	fqKinds, _, err := api.Scheme.ObjectKinds(obj)
	if err != nil {
		return nil, fmt.Errorf("unexpected encoding error: %v", err)
	}
	fqKind := fqKinds[0]
	// TODO: caesarxuchao: we should detect which group an object belongs to
	// by using the version returned by Schem.ObjectVersionAndKind() once we
	// split the schemes for internal objects.
	// TODO: caesarxuchao: we should add a map from kind to group in Scheme.
	var codec runtime.Codec
	if api.Scheme.Recognizes(api.Registry.GroupOrDie(api.GroupName).GroupVersion.WithKind(fqKind.Kind)) {
		codec = testapi.Default.Codec()
	} else if api.Scheme.Recognizes(testapi.Extensions.GroupVersion().WithKind(fqKind.Kind)) {
		codec = testapi.Extensions.Codec()
	} else {
		return nil, fmt.Errorf("unexpected kind: %v", fqKind)
	}
	return codec, nil
}

// Helper functions

func (t *Tester) getObject(ctx genericapirequest.Context, obj runtime.Object) (runtime.Object, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}

	result, err := t.storage.Get(ctx, accessor.GetName(), &metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (t *Tester) createObject(ctx genericapirequest.Context, obj runtime.Object) error {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return err
	}
	key, err := t.storage.KeyFunc(ctx, accessor.GetName())
	if err != nil {
		return err
	}
	return t.storage.Storage.Create(ctx, key, obj, nil, 0)
}

func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object {
	key := t.storage.KeyRootFunc(t.tester.TestContext())
	if err := storagetesting.CreateObjList(key, t.storage.Storage, objects); err != nil {
		t.tester.Errorf("unexpected error: %v", err)
		return nil
	}
	return objects
}

func (t *Tester) emitObject(obj runtime.Object, action string) error {
	ctx := t.tester.TestContext()
	var err error

	switch action {
	case etcdstorage.EtcdCreate:
		err = t.createObject(ctx, obj)
	case etcdstorage.EtcdDelete:
		accessor, err := meta.Accessor(obj)
		if err != nil {
			return err
		}
		_, _, err = t.storage.Delete(ctx, accessor.GetName(), nil)
		if err != nil {
			return err
		}
	default:
		err = fmt.Errorf("unexpected action: %v", action)
	}

	return err
}
<commit_msg>Unshadow error in registrytest<commit_after>/*
Copyright 2015 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 registrytest

import (
	"fmt"
	"testing"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
	"k8s.io/apiserver/pkg/registry/rest/resttest"
	etcdstorage "k8s.io/apiserver/pkg/storage/etcd"
	etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	storagetesting "k8s.io/apiserver/pkg/storage/testing"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/testapi"
)

func NewEtcdStorage(t *testing.T, group string) (*storagebackend.Config, *etcdtesting.EtcdTestServer) {
	server, config := etcdtesting.NewUnsecuredEtcd3TestClientServer(t, api.Scheme)
	config.Codec = testapi.Groups[group].StorageCodec()
	return config, server
}

type Tester struct {
	tester  *resttest.Tester
	storage *genericregistry.Store
}
type UpdateFunc func(runtime.Object) runtime.Object

func New(t *testing.T, storage *genericregistry.Store) *Tester {
	return &Tester{
		tester:  resttest.New(t, storage, api.Scheme),
		storage: storage,
	}
}

func (t *Tester) TestNamespace() string {
	return t.tester.TestNamespace()
}

func (t *Tester) ClusterScope() *Tester {
	t.tester = t.tester.ClusterScope()
	return t
}

func (t *Tester) Namer(namer func(int) string) *Tester {
	t.tester = t.tester.Namer(namer)
	return t
}

func (t *Tester) AllowCreateOnUpdate() *Tester {
	t.tester = t.tester.AllowCreateOnUpdate()
	return t
}

func (t *Tester) GeneratesName() *Tester {
	t.tester = t.tester.GeneratesName()
	return t
}

func (t *Tester) ReturnDeletedObject() *Tester {
	t.tester = t.tester.ReturnDeletedObject()
	return t
}

func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) {
	t.tester.TestCreate(
		valid,
		t.createObject,
		t.getObject,
		invalid...,
	)
}

func (t *Tester) TestUpdate(valid runtime.Object, validUpdateFunc UpdateFunc, invalidUpdateFunc ...UpdateFunc) {
	var invalidFuncs []resttest.UpdateFunc
	for _, f := range invalidUpdateFunc {
		invalidFuncs = append(invalidFuncs, resttest.UpdateFunc(f))
	}
	t.tester.TestUpdate(
		valid,
		t.createObject,
		t.getObject,
		resttest.UpdateFunc(validUpdateFunc),
		invalidFuncs...,
	)
}

func (t *Tester) TestDelete(valid runtime.Object) {
	t.tester.TestDelete(
		valid,
		t.createObject,
		t.getObject,
		errors.IsNotFound,
	)
}

func (t *Tester) TestDeleteGraceful(valid runtime.Object, expectedGrace int64) {
	t.tester.TestDeleteGraceful(
		valid,
		t.createObject,
		t.getObject,
		expectedGrace,
	)
}

func (t *Tester) TestGet(valid runtime.Object) {
	t.tester.TestGet(valid)
}

func (t *Tester) TestList(valid runtime.Object) {
	t.tester.TestList(
		valid,
		t.setObjectsForList,
	)
}

func (t *Tester) TestWatch(valid runtime.Object, labelsPass, labelsFail []labels.Set, fieldsPass, fieldsFail []fields.Set) {
	t.tester.TestWatch(
		valid,
		t.emitObject,
		labelsPass,
		labelsFail,
		fieldsPass,
		fieldsFail,
		// TODO: This should be filtered, the registry should not be aware of this level of detail
		[]string{etcdstorage.EtcdCreate, etcdstorage.EtcdDelete},
	)
}

// =============================================================================
// get codec based on runtime.Object
func getCodec(obj runtime.Object) (runtime.Codec, error) {
	fqKinds, _, err := api.Scheme.ObjectKinds(obj)
	if err != nil {
		return nil, fmt.Errorf("unexpected encoding error: %v", err)
	}
	fqKind := fqKinds[0]
	// TODO: caesarxuchao: we should detect which group an object belongs to
	// by using the version returned by Schem.ObjectVersionAndKind() once we
	// split the schemes for internal objects.
	// TODO: caesarxuchao: we should add a map from kind to group in Scheme.
	var codec runtime.Codec
	if api.Scheme.Recognizes(api.Registry.GroupOrDie(api.GroupName).GroupVersion.WithKind(fqKind.Kind)) {
		codec = testapi.Default.Codec()
	} else if api.Scheme.Recognizes(testapi.Extensions.GroupVersion().WithKind(fqKind.Kind)) {
		codec = testapi.Extensions.Codec()
	} else {
		return nil, fmt.Errorf("unexpected kind: %v", fqKind)
	}
	return codec, nil
}

// Helper functions

func (t *Tester) getObject(ctx genericapirequest.Context, obj runtime.Object) (runtime.Object, error) {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return nil, err
	}

	result, err := t.storage.Get(ctx, accessor.GetName(), &metav1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (t *Tester) createObject(ctx genericapirequest.Context, obj runtime.Object) error {
	accessor, err := meta.Accessor(obj)
	if err != nil {
		return err
	}
	key, err := t.storage.KeyFunc(ctx, accessor.GetName())
	if err != nil {
		return err
	}
	return t.storage.Storage.Create(ctx, key, obj, nil, 0)
}

func (t *Tester) setObjectsForList(objects []runtime.Object) []runtime.Object {
	key := t.storage.KeyRootFunc(t.tester.TestContext())
	if err := storagetesting.CreateObjList(key, t.storage.Storage, objects); err != nil {
		t.tester.Errorf("unexpected error: %v", err)
		return nil
	}
	return objects
}

func (t *Tester) emitObject(obj runtime.Object, action string) error {
	ctx := t.tester.TestContext()
	var err error

	switch action {
	case etcdstorage.EtcdCreate:
		err = t.createObject(ctx, obj)
	case etcdstorage.EtcdDelete:
		var accessor metav1.Object
		accessor, err = meta.Accessor(obj)
		if err != nil {
			return err
		}
		_, _, err = t.storage.Delete(ctx, accessor.GetName(), nil)
	default:
		err = fmt.Errorf("unexpected action: %v", action)
	}

	return err
}
<|endoftext|>


<commit_before>package grpclog

import (
	"go.skia.org/infra/go/sklog"
	grl "google.golang.org/grpc/grpclog"
)

// logger implements grpclog.Logger using sklog.
type logger struct{}

func (g *logger) Fatal(args ...interface{}) {
	sklog.Fatal(args...)
}
func (g *logger) Fatalf(format string, args ...interface{}) {
	sklog.Fatalf(format, args...)
}
func (g *logger) Fatalln(args ...interface{}) {
	sklog.Fatal(args...)
}
func (g *logger) Print(args ...interface{}) {
	sklog.Info(args...)
}
func (g *logger) Printf(format string, args ...interface{}) {
	sklog.Infof(format, args...)
}
func (g *logger) Println(args ...interface{}) {
	sklog.Info(args...)
}

// Init sets up grpc logging using sklog.
func Init() {
	grl.SetLogger(&logger{})
}
<commit_msg>Remove unused package grpclog<commit_after><|endoftext|>


<commit_before>package validation

import (
	"regexp"
	"strings"

	"fmt"

	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/docker/distribution/reference"
	"github.com/ninedraft/ranger/intranger"
	"github.com/satori/go.uuid"
)

const (
	ErrInvalidLabel         chkitErrors.Err = "invalid label"
	ErrInvalidImageName     chkitErrors.Err = "invalid image name"
	ErrInvalidContainerName chkitErrors.Err = "invalid container name"
	ErrInvalidDNSLabel      chkitErrors.Err = "invalid DNS label: "
)

var (
	dnsLabelRe      = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,63}[a-zA-Z0-9]$")
	numericRe       = regexp.MustCompile("^[0-9]+$")
	labelRe         = regexp.MustCompile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
	containerNameRe = regexp.MustCompile("^[a-z0-9]([a-z0-9-[^-]){1,61}[a-z0-9]$")
)

func ValidateContainerName(name string) error {
	name = strings.TrimSpace(name)
	if !containerNameRe.MatchString(name) {
		return ErrInvalidContainerName.CommentF("expect %v", containerNameRe)
	}
	return nil
}

func ValidateImageName(image string) error {
	image = strings.TrimSpace(image)
	if !reference.NameRegexp.MatchString(image) || image == "" {
		return ErrInvalidImageName
	}
	return nil
}

func ValidateLabel(label string) error {
	if !labelRe.MatchString(label) {
		return fmt.Errorf("%v: must satsify %v", ErrInvalidLabel, labelRe)
	}
	return nil
}

// RFC 952 and RFC 1123
func DNSLabel(label string) error {
	DNSlenLimits := intranger.IntRanger(1, 63)
	if !DNSlenLimits.Containing(len(label)) {
		return ErrInvalidDNSLabel.CommentF("DNS label length can be in range %v", DNSlenLimits)
	}
	if !dnsLabelRe.MatchString(label) {
		return ErrInvalidDNSLabel.Comment(
			"must consist of a-Z 1-9 and '-'(dash) letters",
			"must start and end with a-Z 1-9 letters",
		)
	}
	if numericRe.MatchString(label) {
		return ErrInvalidLabel.CommentF("must not consist of all numeric values")
	}
	return nil
}

func ValidateID(ID string) error {
	_, err := uuid.FromString(ID)
	return err
}
<commit_msg>add more info to error<commit_after>package validation

import (
	"fmt"
	"regexp"
	"strings"

	"github.com/containerum/chkit/pkg/chkitErrors"
	"github.com/docker/distribution/reference"
	"github.com/ninedraft/ranger/intranger"
	"github.com/satori/go.uuid"
)

const (
	ErrInvalidLabel         chkitErrors.Err = "invalid label"
	ErrInvalidImageName     chkitErrors.Err = "invalid image name"
	ErrInvalidContainerName chkitErrors.Err = "invalid container name"
	ErrInvalidDNSLabel      chkitErrors.Err = "invalid DNS label: "
)

var (
	dnsLabelRe      = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9\\-]{1,63}[a-zA-Z0-9]$")
	numericRe       = regexp.MustCompile("^[0-9]+$")
	labelRe         = regexp.MustCompile("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
	containerNameRe = regexp.MustCompile("^[a-z0-9]([a-z0-9-[^-]){1,61}[a-z0-9]$")
)

func ValidateContainerName(name string) error {
	name = strings.TrimSpace(name)
	if !containerNameRe.MatchString(name) {
		return ErrInvalidContainerName.CommentF("expect %v", containerNameRe)
	}
	return nil
}

func ValidateImageName(image string) error {
	image = strings.TrimSpace(image)
	if !reference.ReferenceRegexp.MatchString(image) || image == "" {
		return ErrInvalidImageName.CommentF("must match %v", reference.ReferenceRegexp)
	}
	return nil
}

func ValidateLabel(label string) error {
	if !labelRe.MatchString(label) {
		return fmt.Errorf("%v: must satsify %v", ErrInvalidLabel, labelRe)
	}
	return nil
}

// RFC 952 and RFC 1123
func DNSLabel(label string) error {
	DNSlenLimits := intranger.IntRanger(1, 63)
	if !DNSlenLimits.Containing(len(label)) {
		return ErrInvalidDNSLabel.CommentF("DNS label length can be in range %v", DNSlenLimits)
	}
	if !dnsLabelRe.MatchString(label) {
		return ErrInvalidDNSLabel.Comment(
			"must consist of a-Z 1-9 and '-'(dash) letters",
			"must start and end with a-Z 1-9 letters",
		)
	}
	if numericRe.MatchString(label) {
		return ErrInvalidLabel.CommentF("must not consist of all numeric values")
	}
	return nil
}

func ValidateID(ID string) error {
	_, err := uuid.FromString(ID)
	return err
}
<|endoftext|>


<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

// SessionHandler is the RPC handler for the session interface.
type SessionHandler struct {
	libkb.Contextified
	*BaseHandler
}

// NewSessionHandler creates a SessionHandler for the xp transport.
func NewSessionHandler(xp rpc.Transporter, g *libkb.GlobalContext) *SessionHandler {
	return &SessionHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

// CurrentSession uses the global session to find the session.  If
// the user isn't logged in, it returns libkb.NoSessionError.
//
// This function was modified to use cached information instead
// of loading the full self user and possibliy running sesscheck.
// The only potential problem with that is that the session token
// could be stale.  However, KBFS reports that they don't use
// the session token, so not an issue currently.
func (h *SessionHandler) CurrentSession(_ context.Context, sessionID int) (keybase1.Session, error) {
	var s keybase1.Session
	var uid keybase1.UID
	var username libkb.NormalizedUsername
	var token string
	var sibkey, subkey libkb.GenericKey
	var err error
	aerr := h.G().LoginState().Account(func(a *libkb.Account) {
		_, err = a.LoggedInProvisioned()
		if err != nil {
			return
		}
		uid = a.G().ActiveDevice.UID()
		username = a.G().Env.GetUsername()
		token = a.LocalSession().GetToken()
		sibkey, err = a.G().ActiveDevice.SigningKey()
		if err != nil {
			return
		}
		subkey, err = a.G().ActiveDevice.EncryptionKey()
		if err != nil {
			return
		}
	}, "Service - SessionHandler - CurrentSession")
	if aerr != nil {
		return s, aerr
	}
	if err != nil {
		if _, ok := err.(libkb.LoginRequiredError); ok {
			return s, libkb.NoSessionError{}
		}
		return s, err
	}
	s.Uid = uid
	s.Username = username.String()
	s.Token = token
	s.DeviceSubkeyKid = subkey.GetKID()
	s.DeviceSibkeyKid = sibkey.GetKID()
	return s, nil
}

// SessionPing can be used by keepalives for connected services.
func (h *SessionHandler) SessionPing(context.Context) error {
	return nil
}
<commit_msg>Return NoSessionError if no session file<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"os"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
)

// SessionHandler is the RPC handler for the session interface.
type SessionHandler struct {
	libkb.Contextified
	*BaseHandler
}

// NewSessionHandler creates a SessionHandler for the xp transport.
func NewSessionHandler(xp rpc.Transporter, g *libkb.GlobalContext) *SessionHandler {
	return &SessionHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
	}
}

// CurrentSession uses the global session to find the session.  If
// the user isn't logged in, it returns libkb.NoSessionError.
//
// This function was modified to use cached information instead
// of loading the full self user and possibliy running sesscheck.
// The only potential problem with that is that the session token
// could be stale.  However, KBFS reports that they don't use
// the session token, so not an issue currently.
func (h *SessionHandler) CurrentSession(_ context.Context, sessionID int) (keybase1.Session, error) {
	var s keybase1.Session
	var uid keybase1.UID
	var username libkb.NormalizedUsername
	var token string
	var sibkey, subkey libkb.GenericKey
	var err error
	aerr := h.G().LoginState().Account(func(a *libkb.Account) {
		_, err = a.LoggedInProvisioned()
		if err != nil {
			return
		}
		uid = a.G().ActiveDevice.UID()
		username = a.G().Env.GetUsername()
		token = a.LocalSession().GetToken()
		sibkey, err = a.G().ActiveDevice.SigningKey()
		if err != nil {
			return
		}
		subkey, err = a.G().ActiveDevice.EncryptionKey()
		if err != nil {
			return
		}
	}, "Service - SessionHandler - CurrentSession")
	if aerr != nil {
		return s, aerr
	}
	if err != nil {
		if _, ok := err.(libkb.LoginRequiredError); ok {
			return s, libkb.NoSessionError{}
		}
		if os.IsNotExist(err) {
			return s, libkb.NoSessionError{}
		}
		if _, ok := err.(libkb.NotFoundError); ok {
			return s, libkb.NoSessionError{}
		}
		return s, err
	}
	s.Uid = uid
	s.Username = username.String()
	s.Token = token
	s.DeviceSubkeyKid = subkey.GetKID()
	s.DeviceSibkeyKid = sibkey.GetKID()
	return s, nil
}

// SessionPing can be used by keepalives for connected services.
func (h *SessionHandler) SessionPing(context.Context) error {
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"math/rand"
	"net/http"
	"runtime"
	"strconv"
)

type MessageStruct struct {
	Message string
}

type World struct {
	Id           uint16 `json:"id"`
	RandomNumber uint16 `json:"randomNumber"`
}

const (
	DB_CONN_STR   = "benchmarkdbuser:benchmarkdbpass@tcp(172.16.98.98:3306)/hello_world?charset=utf8"
	DB_SELECT_SQL = "SELECT id, randomNumber FROM World where id = ?;"
	DB_ROWS       = 10000
)

var (
	db    *sql.DB
	query *sql.Stmt
)

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	var err error
	if db, err = sql.Open("mysql", DB_CONN_STR); err != nil {
		log.Fatalf("Error opening database: %s", err)
	}
	if query, err = db.Prepare(DB_SELECT_SQL); err != nil {
		log.Fatalf("Error preparing statement: %s", err)
	}
	http.HandleFunc("/json", jsonHandler)
	http.HandleFunc("/db", dbHandler)
	http.ListenAndServe(":8080", nil)
}

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/javascript")
	j, _ := json.Marshal(&MessageStruct{"Hello, world"})
	w.Header().Set("Content-Length", strconv.Itoa(len(j)))
	w.Write(j)
}

func dbHandler(w http.ResponseWriter, r *http.Request) {
  	qnum := 1
	if qnumStr := r.URL.Query().Get("queries"); len(qnumStr) != 0 {
		qnum, _ = strconv.Atoi(qnumStr)
	}
	ww := make([]World, qnum)
	for i := 0; i < qnum; i++ {
		query.QueryRow(rand.Intn(DB_ROWS)+1).Scan(&ww[i].Id, &ww[i].RandomNumber)
	}
	w.Header().Set("Content-Type", "application/javascript")
	j, _ := json.Marshal(ww)
	w.Header().Set("Content-Length", strconv.Itoa(len(j)))
	w.Write(j)
}
<commit_msg>prevent internal connection pooling by absuing transactions in a custom pool of MAX_CON connections<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"math/rand"
	"net/http"
	"runtime"
	"strconv"
)

type MessageStruct struct {
	Message string
}

type World struct {
	Id           uint16 `json:"id"`
	RandomNumber uint16 `json:"randomNumber"`
}

const (
	DB_CONN_STR   = "root@tcp(127.0.0.1:3306)/hello_world?charset=utf8"
	DB_SELECT_SQL = "SELECT id, randomNumber FROM World where id = ?"
	DB_ROWS       = 10000
	MAX_CON       = 100
)

var (
	stmts = make(chan *sql.Stmt, MAX_CON)
)

func jsonHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/javascript")
	j, _ := json.Marshal(&MessageStruct{"Hello, world"})
	w.Header().Set("Content-Length", strconv.Itoa(len(j)))
	w.Write(j)
}

func dbHandler(w http.ResponseWriter, r *http.Request) {
	n := 1
	if qnumStr := r.URL.Query().Get("queries"); len(qnumStr) != 0 {
		n, _ = strconv.Atoi(qnumStr)
	}
	stmt := <-stmts // wait for a connection
	ww := make([]World, n)
	for i := 0; i < n; i++ {
		stmt.QueryRow(rand.Intn(DB_ROWS)+1).Scan(
			&ww[i].Id,
			&ww[i].RandomNumber,
		)
	}
	stmts <- stmt // return a connection
	j, _ := json.Marshal(ww)
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Content-Length", strconv.Itoa(len(j)))
	w.Write(j)
}

func main() {
	http.HandleFunc("/db", dbHandler)
	http.HandleFunc("/json", jsonHandler)
	http.ListenAndServe(":8080", nil)
}

func init() {
	// use cores
	runtime.GOMAXPROCS(runtime.NumCPU())
	// setup connection pool
	if db, err := sql.Open("mysql", DB_CONN_STR); err == nil {
		for i := 0; i < MAX_CON; i++ {
			tx, err := db.Begin()
			if err != nil {
				log.Fatal(err)
			}
			stmt, err := tx.Prepare(DB_SELECT_SQL)
			if err != nil {
				log.Fatal(err)
			}
			stmts <- stmt
		}
	} else {
		log.Fatalf("Error opening database: %s", err)
	}
}
<|endoftext|>


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

// Package googleapi contains the common code shared by all Google API
// libraries.
package googleapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"strings"
)

// ContentTyper is an interface for Readers which know (or would like
// to override) their Content-Type. If a media body doesn't implement
// ContentTyper, the type is sniffed from the content using
// http.DetectContentType.
type ContentTyper interface {
	ContentType() string
}

const Version = "0.5"

type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func (e *Error) Error() string {
	return fmt.Sprintf("googleapi: Error %d: %s", e.Code, e.Message)
}

type errorReply struct {
	Error *Error `json:"error"`
}

func CheckResponse(res *http.Response) error {
	if res.StatusCode >= 200 && res.StatusCode <= 299 {
		return nil
	}
	slurp, err := ioutil.ReadAll(res.Body)
	if err == nil {
		jerr := new(errorReply)
		err = json.Unmarshal(slurp, jerr)
		if err == nil && jerr.Error != nil {
			return jerr.Error
		}
	}
	return fmt.Errorf("googleapi: got HTTP response code %d and error reading body: %v",
		res.StatusCode, err)
}

type MarshalStyle bool

var WithDataWrapper = MarshalStyle(true)
var WithoutDataWrapper = MarshalStyle(false)

func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
	buf := new(bytes.Buffer)
	if wrap {
		buf.Write([]byte(`{"data": `))
	}
	err := json.NewEncoder(buf).Encode(v)
	if err != nil {
		return nil, err
	}
	if wrap {
		buf.Write([]byte(`}`))
	}
	return buf, nil
}

func getMediaType(media io.Reader) (io.Reader, string) {
	if typer, ok := media.(ContentTyper); ok {
		return media, typer.ContentType()
	}

	typ := "application/octet-stream"
	buf := make([]byte, 1024)
	n, err := media.Read(buf)
	buf = buf[:n]
	if err == nil {
		typ = http.DetectContentType(buf)
	}
	return io.MultiReader(bytes.NewBuffer(buf), media), typ
}

type Lengther interface {
	Len() int
}

// endingWithErrorReader from r until it returns an error.  If the
// final error from r is os.EOF and e is non-nil, e is used instead.
type endingWithErrorReader struct {
	r io.Reader
	e error
}

func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
	n, err = er.r.Read(p)
	if err == io.EOF && er.e != nil {
		err = er.e
	}
	return
}

func getReaderSize(r io.Reader) (io.Reader, int64) {
	// Ideal case, the reader knows its own size.
	if lr, ok := r.(Lengther); ok {
		return r, int64(lr.Len())
	}

	// But maybe it's a seeker and we can seek to the end to find its size.
	if s, ok := r.(io.Seeker); ok {
		pos0, err := s.Seek(0, os.SEEK_CUR)
		if err == nil {
			posend, err := s.Seek(0, os.SEEK_END)
			if err == nil {
				_, err = s.Seek(pos0, os.SEEK_SET)
				if err == nil {
					return r, posend - pos0
				} else {
					// We moved it forward but can't restore it.
					// Seems unlikely, but can't really restore now.
					return endingWithErrorReader{strings.NewReader(""), err}, posend - pos0
				}
			}
		}
	}

	// Otherwise we have to make a copy to calculate how big the reader is.
	buf := new(bytes.Buffer)
	// TODO(bradfitz): put a cap on this copy? spill to disk after
	// a certain point?
	_, err := io.Copy(buf, r)
	return endingWithErrorReader{buf, err}, int64(buf.Len())
}

func typeHeader(contentType string) textproto.MIMEHeader {
	h := make(textproto.MIMEHeader)
	h.Set("Content-Type", contentType)
	return h
}

// countingWriter counts the number of bytes it receives to write, but
// discards them.
type countingWriter struct {
	n *int64
}

func (w countingWriter) Write(p []byte) (int, error) {
	*w.n += int64(len(p))
	return len(p), nil
}

// ConditionallyIncludeMedia does nothing if media is nil.
//
// bodyp is an in/out parameter.  It should initially point to the
// reader of the application/json (or whatever) payload to send in the
// API request.  It's updated to point to the multipart body reader.
//
// ctypep is an in/out parameter.  It should initially point to the
// content type of the bodyp, usually "application/json".  It's updated
// to the "multipart/related" content type, with random boundary.
//
// The return value is the content-length of the entire multpart body.
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (totalContentLength int64, ok bool) {
	if media == nil {
		return
	}
	// Get the media type and size. The type check might return a
	// different reader instance, so do the size check first,
	// which looks at the specific type of the io.Reader.
	media, mediaSize := getReaderSize(media)
	media, mediaType := getMediaType(media)
	body, bodyType := *bodyp, *ctypep
	body, bodySize := getReaderSize(body)

	// Calculate how big the the multipart will be.
	{
		totalContentLength = bodySize + mediaSize
		mpw := multipart.NewWriter(countingWriter{&totalContentLength})
		mpw.CreatePart(typeHeader(bodyType))
		mpw.CreatePart(typeHeader(mediaType))
		mpw.Close()
	}

	pr, pw := io.Pipe()
	mpw := multipart.NewWriter(pw)
	*bodyp = pr
	*ctypep = "multipart/related; boundary=" + mpw.Boundary()
	go func() {
		defer pw.Close()
		defer mpw.Close()

		w, err := mpw.CreatePart(typeHeader(bodyType))
		if err != nil {
			return
		}
		_, err = io.Copy(w, body)
		if err != nil {
			return
		}

		w, err = mpw.CreatePart(typeHeader(mediaType))
		if err != nil {
			return
		}
		_, err = io.Copy(w, media)
		if err != nil {
			return
		}
	}()
	return totalContentLength, true
}

func ResolveRelative(basestr, relstr string) string {
	u, _ := url.Parse(basestr)
	rel, _ := url.Parse(relstr)
	u = u.ResolveReference(rel)
	us := u.String()
	us = strings.Replace(us, "%7B", "{", -1)
	us = strings.Replace(us, "%7D", "}", -1)
	return us
}
<commit_msg>googleapi: call ContentTyper before the getReaderSize potentially clobbers it<commit_after>// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package googleapi contains the common code shared by all Google API
// libraries.
package googleapi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/textproto"
	"net/url"
	"os"
	"strings"
)

// ContentTyper is an interface for Readers which know (or would like
// to override) their Content-Type. If a media body doesn't implement
// ContentTyper, the type is sniffed from the content using
// http.DetectContentType.
type ContentTyper interface {
	ContentType() string
}

const Version = "0.5"

type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func (e *Error) Error() string {
	return fmt.Sprintf("googleapi: Error %d: %s", e.Code, e.Message)
}

type errorReply struct {
	Error *Error `json:"error"`
}

func CheckResponse(res *http.Response) error {
	if res.StatusCode >= 200 && res.StatusCode <= 299 {
		return nil
	}
	slurp, err := ioutil.ReadAll(res.Body)
	if err == nil {
		jerr := new(errorReply)
		err = json.Unmarshal(slurp, jerr)
		if err == nil && jerr.Error != nil {
			return jerr.Error
		}
	}
	return fmt.Errorf("googleapi: got HTTP response code %d and error reading body: %v",
		res.StatusCode, err)
}

type MarshalStyle bool

var WithDataWrapper = MarshalStyle(true)
var WithoutDataWrapper = MarshalStyle(false)

func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
	buf := new(bytes.Buffer)
	if wrap {
		buf.Write([]byte(`{"data": `))
	}
	err := json.NewEncoder(buf).Encode(v)
	if err != nil {
		return nil, err
	}
	if wrap {
		buf.Write([]byte(`}`))
	}
	return buf, nil
}

func getMediaType(media io.Reader) (io.Reader, string) {
	if typer, ok := media.(ContentTyper); ok {
		return media, typer.ContentType()
	}

	typ := "application/octet-stream"
	buf := make([]byte, 1024)
	n, err := media.Read(buf)
	buf = buf[:n]
	if err == nil {
		typ = http.DetectContentType(buf)
	}
	return io.MultiReader(bytes.NewBuffer(buf), media), typ
}

type Lengther interface {
	Len() int
}

// endingWithErrorReader from r until it returns an error.  If the
// final error from r is os.EOF and e is non-nil, e is used instead.
type endingWithErrorReader struct {
	r io.Reader
	e error
}

func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
	n, err = er.r.Read(p)
	if err == io.EOF && er.e != nil {
		err = er.e
	}
	return
}

func getReaderSize(r io.Reader) (io.Reader, int64) {
	// Ideal case, the reader knows its own size.
	if lr, ok := r.(Lengther); ok {
		return r, int64(lr.Len())
	}

	// But maybe it's a seeker and we can seek to the end to find its size.
	if s, ok := r.(io.Seeker); ok {
		pos0, err := s.Seek(0, os.SEEK_CUR)
		if err == nil {
			posend, err := s.Seek(0, os.SEEK_END)
			if err == nil {
				_, err = s.Seek(pos0, os.SEEK_SET)
				if err == nil {
					return r, posend - pos0
				} else {
					// We moved it forward but can't restore it.
					// Seems unlikely, but can't really restore now.
					return endingWithErrorReader{strings.NewReader(""), err}, posend - pos0
				}
			}
		}
	}

	// Otherwise we have to make a copy to calculate how big the reader is.
	buf := new(bytes.Buffer)
	// TODO(bradfitz): put a cap on this copy? spill to disk after
	// a certain point?
	_, err := io.Copy(buf, r)
	return endingWithErrorReader{buf, err}, int64(buf.Len())
}

func typeHeader(contentType string) textproto.MIMEHeader {
	h := make(textproto.MIMEHeader)
	h.Set("Content-Type", contentType)
	return h
}

// countingWriter counts the number of bytes it receives to write, but
// discards them.
type countingWriter struct {
	n *int64
}

func (w countingWriter) Write(p []byte) (int, error) {
	*w.n += int64(len(p))
	return len(p), nil
}

// ConditionallyIncludeMedia does nothing if media is nil.
//
// bodyp is an in/out parameter.  It should initially point to the
// reader of the application/json (or whatever) payload to send in the
// API request.  It's updated to point to the multipart body reader.
//
// ctypep is an in/out parameter.  It should initially point to the
// content type of the bodyp, usually "application/json".  It's updated
// to the "multipart/related" content type, with random boundary.
//
// The return value is the content-length of the entire multpart body.
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (totalContentLength int64, ok bool) {
	if media == nil {
		return
	}
	// Get the media type and size. The type check might return a
	// different reader instance, so do the size check first,
	// which looks at the specific type of the io.Reader.
	var mediaType string
	if typer, ok := media.(ContentTyper); ok {
		mediaType = typer.ContentType()
	}
	media, mediaSize := getReaderSize(media)
	if mediaType == "" {
		media, mediaType = getMediaType(media)
	}
	body, bodyType := *bodyp, *ctypep
	body, bodySize := getReaderSize(body)

	// Calculate how big the the multipart will be.
	{
		totalContentLength = bodySize + mediaSize
		mpw := multipart.NewWriter(countingWriter{&totalContentLength})
		mpw.CreatePart(typeHeader(bodyType))
		mpw.CreatePart(typeHeader(mediaType))
		mpw.Close()
	}

	pr, pw := io.Pipe()
	mpw := multipart.NewWriter(pw)
	*bodyp = pr
	*ctypep = "multipart/related; boundary=" + mpw.Boundary()
	go func() {
		defer pw.Close()
		defer mpw.Close()

		w, err := mpw.CreatePart(typeHeader(bodyType))
		if err != nil {
			return
		}
		_, err = io.Copy(w, body)
		if err != nil {
			return
		}

		w, err = mpw.CreatePart(typeHeader(mediaType))
		if err != nil {
			return
		}
		_, err = io.Copy(w, media)
		if err != nil {
			return
		}
	}()
	return totalContentLength, true
}

func ResolveRelative(basestr, relstr string) string {
	u, _ := url.Parse(basestr)
	rel, _ := url.Parse(relstr)
	u = u.ResolveReference(rel)
	us := u.String()
	us = strings.Replace(us, "%7B", "{", -1)
	us = strings.Replace(us, "%7D", "}", -1)
	return us
}
<|endoftext|>


<commit_before>package gorush

import (
	"errors"
	"fmt"
	"github.com/google/go-gcm"
	apns "github.com/sideshow/apns2"
	"github.com/sideshow/apns2/certificate"
	"github.com/sideshow/apns2/payload"
	"net/http"
	"net/url"
	"path/filepath"
	"time"
)

// D provide string array
type D map[string]interface{}

const (
	// ApnsPriorityLow will tell APNs to send the push message at a time that takes
	// into account power considerations for the device. Notifications with this
	// priority might be grouped and delivered in bursts. They are throttled, and
	// in some cases are not delivered.
	ApnsPriorityLow = 5

	// ApnsPriorityHigh will tell APNs to send the push message immediately.
	// Notifications with this priority must trigger an alert, sound, or badge on
	// the target device. It is an error to use this priority for a push
	// notification that contains only the content-available key.
	ApnsPriorityHigh = 10
)

// Alert is APNs payload
type Alert struct {
	Action       string   `json:"action,omitempty"`
	ActionLocKey string   `json:"action-loc-key,omitempty"`
	Body         string   `json:"body,omitempty"`
	LaunchImage  string   `json:"launch-image,omitempty"`
	LocArgs      []string `json:"loc-args,omitempty"`
	LocKey       string   `json:"loc-key,omitempty"`
	Title        string   `json:"title,omitempty"`
	TitleLocArgs []string `json:"title-loc-args,omitempty"`
	TitleLocKey  string   `json:"title-loc-key,omitempty"`
}

// RequestPush support multiple notification request.
type RequestPush struct {
	Notifications []PushNotification `json:"notifications" binding:"required"`
}

// PushNotification is single notification request
type PushNotification struct {
	// Common
	Tokens           []string `json:"tokens" binding:"required"`
	Platform         int      `json:"platform" binding:"required"`
	Message          string   `json:"message" binding:"required"`
	Title            string   `json:"title,omitempty"`
	Priority         string   `json:"priority,omitempty"`
	ContentAvailable bool     `json:"content_available,omitempty"`
	Sound            string   `json:"sound,omitempty"`
	Data             D        `json:"data,omitempty"`

	// Android
	APIKey                string           `json:"api_key,omitempty"`
	To                    string           `json:"to,omitempty"`
	CollapseKey           string           `json:"collapse_key,omitempty"`
	DelayWhileIdle        bool             `json:"delay_while_idle,omitempty"`
	TimeToLive            *uint            `json:"time_to_live,omitempty"`
	RestrictedPackageName string           `json:"restricted_package_name,omitempty"`
	DryRun                bool             `json:"dry_run,omitempty"`
	Notification          gcm.Notification `json:"notification,omitempty"`

	// iOS
	Expiration int64    `json:"expiration,omitempty"`
	ApnsID     string   `json:"apns_id,omitempty"`
	Topic      string   `json:"topic,omitempty"`
	Badge      int      `json:"badge,omitempty"`
	Category   string   `json:"category,omitempty"`
	URLArgs    []string `json:"url-args,omitempty"`
	Alert      Alert    `json:"alert,omitempty"`
}

// CheckMessage for check request message
func CheckMessage(req PushNotification) error {
	var msg string
	if req.Message == "" {
		msg = "the message must not be empty"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if len(req.Tokens) == 0 {
		msg = "the message must specify at least one registration ID"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if len(req.Tokens) == PlatFormIos && len(req.Tokens[0]) == 0 {
		msg = "the token must not be empty"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if req.Platform == PlatFormAndroid && len(req.Tokens) > 1000 {
		msg = "the message may specify at most 1000 registration IDs"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	// ref: https://developers.google.com/cloud-messaging/http-server-ref
	if req.Platform == PlatFormAndroid && req.TimeToLive != nil && (*req.TimeToLive < uint(0) || uint(2419200) < *req.TimeToLive) {
		msg = "the message's TimeToLive field must be an integer " +
			"between 0 and 2419200 (4 weeks)"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	return nil
}

func SetProxy(proxy string) error {

	proxyUrl, err := url.ParseRequestURI(proxy)

	if err != nil {
		return err
	}

	http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyUrl)}
	LogAccess.Debug("Set http proxy as " + proxy)

	return nil
}

// CheckPushConf provide check your yml config.
func CheckPushConf() error {
	if !PushConf.Ios.Enabled && !PushConf.Android.Enabled {
		return errors.New("Please enable iOS or Android config in yml config")
	}

	if PushConf.Ios.Enabled {
		if PushConf.Ios.KeyPath == "" {
			return errors.New("Missing iOS certificate path")
		}
	}

	if PushConf.Android.Enabled {
		if PushConf.Android.APIKey == "" {
			return errors.New("Missing Android API Key")
		}
	}

	return nil
}

// InitAPNSClient use for initialize APNs Client.
func InitAPNSClient() error {
	if PushConf.Ios.Enabled {
		var err error
		ext := filepath.Ext(PushConf.Ios.KeyPath)

		switch ext {
		case ".p12":
			CertificatePemIos, err = certificate.FromP12File(PushConf.Ios.KeyPath, PushConf.Ios.Password)
		case ".pem":
			CertificatePemIos, err = certificate.FromPemFile(PushConf.Ios.KeyPath, PushConf.Ios.Password)
		default:
			err = errors.New("Wrong Certificate key extension.")
		}

		if err != nil {
			LogError.Error("Cert Error:", err.Error())

			return err
		}

		if PushConf.Ios.Production {
			ApnsClient = apns.NewClient(CertificatePemIos).Production()
		} else {
			ApnsClient = apns.NewClient(CertificatePemIos).Development()
		}
	}

	return nil
}

// InitWorkers for initialize all workers.
func InitWorkers(workerNum, queueNum int) {
	LogAccess.Debug("worker number is ", workerNum, ", queue number is ", queueNum)
	QueueNotification = make(chan PushNotification, queueNum)
	for i := 0; i < workerNum; i++ {
		go startWorker()
	}
}

func startWorker() {
	for {
		notification := <-QueueNotification
		switch notification.Platform {
		case PlatFormIos:
			PushToIOS(notification)
		case PlatFormAndroid:
			PushToAndroid(notification)
		}
	}
}

// queueNotification add notification to queue list.
func queueNotification(req RequestPush) int {
	var count int
	for _, notification := range req.Notifications {
		switch notification.Platform {
		case PlatFormIos:
			if !PushConf.Ios.Enabled {
				continue
			}
		case PlatFormAndroid:
			if !PushConf.Android.Enabled {
				continue
			}
		}
		QueueNotification <- notification

		count += len(notification.Tokens)
	}

	StatStorage.AddTotalCount(int64(count))

	return count
}

func iosAlertDictionary(payload *payload.Payload, req PushNotification) *payload.Payload {
	// Alert dictionary

	if len(req.Title) > 0 {
		payload.AlertTitle(req.Title)
	}

	if len(req.Alert.TitleLocKey) > 0 {
		payload.AlertTitleLocKey(req.Alert.TitleLocKey)
	}

	if len(req.Alert.LocArgs) > 0 {
		payload.AlertLocArgs(req.Alert.LocArgs)
	}

	if len(req.Alert.TitleLocArgs) > 0 {
		payload.AlertTitleLocArgs(req.Alert.TitleLocArgs)
	}

	if len(req.Alert.Body) > 0 {
		payload.AlertBody(req.Alert.Body)
	}

	if len(req.Alert.LaunchImage) > 0 {
		payload.AlertLaunchImage(req.Alert.LaunchImage)
	}

	if len(req.Alert.LocKey) > 0 {
		payload.AlertLocKey(req.Alert.LocKey)
	}

	if len(req.Alert.Action) > 0 {
		payload.AlertAction(req.Alert.Action)
	}

	if len(req.Alert.ActionLocKey) > 0 {
		payload.AlertActionLocKey(req.Alert.ActionLocKey)
	}

	// General

	if len(req.Category) > 0 {
		payload.Category(req.Category)
	}

	return payload
}

// GetIOSNotification use for define iOS notificaiton.
// The iOS Notification Payload
// ref: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
func GetIOSNotification(req PushNotification) *apns.Notification {
	notification := &apns.Notification{
		ApnsID: req.ApnsID,
		Topic:  req.Topic,
	}

	if req.Expiration > 0 {
		notification.Expiration = time.Unix(req.Expiration, 0)
	}

	if len(req.Priority) > 0 && req.Priority == "normal" {
		notification.Priority = apns.PriorityLow
	}

	payload := payload.NewPayload().Alert(req.Message)

	if req.Badge > 0 {
		payload.Badge(req.Badge)
	}

	if len(req.Sound) > 0 {
		payload.Sound(req.Sound)
	}

	if req.ContentAvailable {
		payload.ContentAvailable()
	}

	if len(req.URLArgs) > 0 {
		payload.URLArgs(req.URLArgs)
	}

	for k, v := range req.Data {
		payload.Custom(k, v)
	}

	payload = iosAlertDictionary(payload, req)

	notification.Payload = payload

	return notification
}

// PushToIOS provide send notification to APNs server.
func PushToIOS(req PushNotification) bool {
	LogAccess.Debug("Start push notification for iOS")

	var isError bool

	notification := GetIOSNotification(req)

	for _, token := range req.Tokens {
		notification.DeviceToken = token

		// send ios notification
		res, err := ApnsClient.Push(notification)

		if err != nil {
			// apns server error
			LogPush(FailedPush, token, req, err)
			isError = true
			StatStorage.AddIosError(1)
			continue
		}

		if res.StatusCode != 200 {
			// error message:
			// ref: https://github.com/sideshow/apns2/blob/master/response.go#L14-L65
			LogPush(FailedPush, token, req, errors.New(res.Reason))
			StatStorage.AddIosError(1)
			continue
		}

		if res.Sent() {
			LogPush(SucceededPush, token, req, nil)
			StatStorage.AddIosSuccess(1)
		}
	}

	return isError
}

// GetAndroidNotification use for define Android notificaiton.
// HTTP Connection Server Reference for Android
// https://developers.google.com/cloud-messaging/http-server-ref
func GetAndroidNotification(req PushNotification) gcm.HttpMessage {
	notification := gcm.HttpMessage{
		To:                    req.To,
		CollapseKey:           req.CollapseKey,
		ContentAvailable:      req.ContentAvailable,
		DelayWhileIdle:        req.DelayWhileIdle,
		TimeToLive:            req.TimeToLive,
		RestrictedPackageName: req.RestrictedPackageName,
		DryRun:                req.DryRun,
	}

	notification.RegistrationIds = req.Tokens

	if len(req.Priority) > 0 && req.Priority == "high" {
		notification.Priority = "high"
	}

	// Add another field
	if len(req.Data) > 0 {
		notification.Data = make(map[string]interface{})
		for k, v := range req.Data {
			notification.Data[k] = v
		}
	}

	notification.Notification = &req.Notification

	// Set request message if body is empty
	if len(notification.Notification.Body) == 0 {
		notification.Notification.Body = req.Message
	}

	if len(req.Title) > 0 {
		notification.Notification.Title = req.Title
	}

	if len(req.Sound) > 0 {
		notification.Notification.Sound = req.Sound
	}

	return notification
}

// PushToAndroid provide send notification to Android server.
func PushToAndroid(req PushNotification) bool {
	LogAccess.Debug("Start push notification for Android")

	var APIKey string

	// check message
	err := CheckMessage(req)

	if err != nil {
		LogError.Error("request error: " + err.Error())
		return false
	}

	notification := GetAndroidNotification(req)

	if APIKey = PushConf.Android.APIKey; req.APIKey != "" {
		APIKey = req.APIKey
	}

	res, err := gcm.SendHttp(APIKey, notification)

	if err != nil {
		// GCM server error
		LogError.Error("GCM server error: " + err.Error())

		return false
	}

	LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
	StatStorage.AddAndroidSuccess(int64(res.Success))
	StatStorage.AddAndroidError(int64(res.Failure))

	for k, result := range res.Results {
		if result.Error != "" {
			LogPush(FailedPush, req.Tokens[k], req, errors.New(result.Error))
			continue
		}

		LogPush(SucceededPush, req.Tokens[k], req, nil)
	}

	return true
}
<commit_msg>fix SetProxy lint error.<commit_after>package gorush

import (
	"errors"
	"fmt"
	"github.com/google/go-gcm"
	apns "github.com/sideshow/apns2"
	"github.com/sideshow/apns2/certificate"
	"github.com/sideshow/apns2/payload"
	"net/http"
	"net/url"
	"path/filepath"
	"time"
)

// D provide string array
type D map[string]interface{}

const (
	// ApnsPriorityLow will tell APNs to send the push message at a time that takes
	// into account power considerations for the device. Notifications with this
	// priority might be grouped and delivered in bursts. They are throttled, and
	// in some cases are not delivered.
	ApnsPriorityLow = 5

	// ApnsPriorityHigh will tell APNs to send the push message immediately.
	// Notifications with this priority must trigger an alert, sound, or badge on
	// the target device. It is an error to use this priority for a push
	// notification that contains only the content-available key.
	ApnsPriorityHigh = 10
)

// Alert is APNs payload
type Alert struct {
	Action       string   `json:"action,omitempty"`
	ActionLocKey string   `json:"action-loc-key,omitempty"`
	Body         string   `json:"body,omitempty"`
	LaunchImage  string   `json:"launch-image,omitempty"`
	LocArgs      []string `json:"loc-args,omitempty"`
	LocKey       string   `json:"loc-key,omitempty"`
	Title        string   `json:"title,omitempty"`
	TitleLocArgs []string `json:"title-loc-args,omitempty"`
	TitleLocKey  string   `json:"title-loc-key,omitempty"`
}

// RequestPush support multiple notification request.
type RequestPush struct {
	Notifications []PushNotification `json:"notifications" binding:"required"`
}

// PushNotification is single notification request
type PushNotification struct {
	// Common
	Tokens           []string `json:"tokens" binding:"required"`
	Platform         int      `json:"platform" binding:"required"`
	Message          string   `json:"message" binding:"required"`
	Title            string   `json:"title,omitempty"`
	Priority         string   `json:"priority,omitempty"`
	ContentAvailable bool     `json:"content_available,omitempty"`
	Sound            string   `json:"sound,omitempty"`
	Data             D        `json:"data,omitempty"`

	// Android
	APIKey                string           `json:"api_key,omitempty"`
	To                    string           `json:"to,omitempty"`
	CollapseKey           string           `json:"collapse_key,omitempty"`
	DelayWhileIdle        bool             `json:"delay_while_idle,omitempty"`
	TimeToLive            *uint            `json:"time_to_live,omitempty"`
	RestrictedPackageName string           `json:"restricted_package_name,omitempty"`
	DryRun                bool             `json:"dry_run,omitempty"`
	Notification          gcm.Notification `json:"notification,omitempty"`

	// iOS
	Expiration int64    `json:"expiration,omitempty"`
	ApnsID     string   `json:"apns_id,omitempty"`
	Topic      string   `json:"topic,omitempty"`
	Badge      int      `json:"badge,omitempty"`
	Category   string   `json:"category,omitempty"`
	URLArgs    []string `json:"url-args,omitempty"`
	Alert      Alert    `json:"alert,omitempty"`
}

// CheckMessage for check request message
func CheckMessage(req PushNotification) error {
	var msg string
	if req.Message == "" {
		msg = "the message must not be empty"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if len(req.Tokens) == 0 {
		msg = "the message must specify at least one registration ID"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if len(req.Tokens) == PlatFormIos && len(req.Tokens[0]) == 0 {
		msg = "the token must not be empty"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	if req.Platform == PlatFormAndroid && len(req.Tokens) > 1000 {
		msg = "the message may specify at most 1000 registration IDs"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	// ref: https://developers.google.com/cloud-messaging/http-server-ref
	if req.Platform == PlatFormAndroid && req.TimeToLive != nil && (*req.TimeToLive < uint(0) || uint(2419200) < *req.TimeToLive) {
		msg = "the message's TimeToLive field must be an integer " +
			"between 0 and 2419200 (4 weeks)"
		LogAccess.Debug(msg)
		return errors.New(msg)
	}

	return nil
}

// SetProxy only working for GCM server.
func SetProxy(proxy string) error {

	proxyURL, err := url.ParseRequestURI(proxy)

	if err != nil {
		return err
	}

	http.DefaultTransport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
	LogAccess.Debug("Set http proxy as " + proxy)

	return nil
}

// CheckPushConf provide check your yml config.
func CheckPushConf() error {
	if !PushConf.Ios.Enabled && !PushConf.Android.Enabled {
		return errors.New("Please enable iOS or Android config in yml config")
	}

	if PushConf.Ios.Enabled {
		if PushConf.Ios.KeyPath == "" {
			return errors.New("Missing iOS certificate path")
		}
	}

	if PushConf.Android.Enabled {
		if PushConf.Android.APIKey == "" {
			return errors.New("Missing Android API Key")
		}
	}

	return nil
}

// InitAPNSClient use for initialize APNs Client.
func InitAPNSClient() error {
	if PushConf.Ios.Enabled {
		var err error
		ext := filepath.Ext(PushConf.Ios.KeyPath)

		switch ext {
		case ".p12":
			CertificatePemIos, err = certificate.FromP12File(PushConf.Ios.KeyPath, PushConf.Ios.Password)
		case ".pem":
			CertificatePemIos, err = certificate.FromPemFile(PushConf.Ios.KeyPath, PushConf.Ios.Password)
		default:
			err = errors.New("Wrong Certificate key extension.")
		}

		if err != nil {
			LogError.Error("Cert Error:", err.Error())

			return err
		}

		if PushConf.Ios.Production {
			ApnsClient = apns.NewClient(CertificatePemIos).Production()
		} else {
			ApnsClient = apns.NewClient(CertificatePemIos).Development()
		}
	}

	return nil
}

// InitWorkers for initialize all workers.
func InitWorkers(workerNum, queueNum int) {
	LogAccess.Debug("worker number is ", workerNum, ", queue number is ", queueNum)
	QueueNotification = make(chan PushNotification, queueNum)
	for i := 0; i < workerNum; i++ {
		go startWorker()
	}
}

func startWorker() {
	for {
		notification := <-QueueNotification
		switch notification.Platform {
		case PlatFormIos:
			PushToIOS(notification)
		case PlatFormAndroid:
			PushToAndroid(notification)
		}
	}
}

// queueNotification add notification to queue list.
func queueNotification(req RequestPush) int {
	var count int
	for _, notification := range req.Notifications {
		switch notification.Platform {
		case PlatFormIos:
			if !PushConf.Ios.Enabled {
				continue
			}
		case PlatFormAndroid:
			if !PushConf.Android.Enabled {
				continue
			}
		}
		QueueNotification <- notification

		count += len(notification.Tokens)
	}

	StatStorage.AddTotalCount(int64(count))

	return count
}

func iosAlertDictionary(payload *payload.Payload, req PushNotification) *payload.Payload {
	// Alert dictionary

	if len(req.Title) > 0 {
		payload.AlertTitle(req.Title)
	}

	if len(req.Alert.TitleLocKey) > 0 {
		payload.AlertTitleLocKey(req.Alert.TitleLocKey)
	}

	if len(req.Alert.LocArgs) > 0 {
		payload.AlertLocArgs(req.Alert.LocArgs)
	}

	if len(req.Alert.TitleLocArgs) > 0 {
		payload.AlertTitleLocArgs(req.Alert.TitleLocArgs)
	}

	if len(req.Alert.Body) > 0 {
		payload.AlertBody(req.Alert.Body)
	}

	if len(req.Alert.LaunchImage) > 0 {
		payload.AlertLaunchImage(req.Alert.LaunchImage)
	}

	if len(req.Alert.LocKey) > 0 {
		payload.AlertLocKey(req.Alert.LocKey)
	}

	if len(req.Alert.Action) > 0 {
		payload.AlertAction(req.Alert.Action)
	}

	if len(req.Alert.ActionLocKey) > 0 {
		payload.AlertActionLocKey(req.Alert.ActionLocKey)
	}

	// General

	if len(req.Category) > 0 {
		payload.Category(req.Category)
	}

	return payload
}

// GetIOSNotification use for define iOS notificaiton.
// The iOS Notification Payload
// ref: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
func GetIOSNotification(req PushNotification) *apns.Notification {
	notification := &apns.Notification{
		ApnsID: req.ApnsID,
		Topic:  req.Topic,
	}

	if req.Expiration > 0 {
		notification.Expiration = time.Unix(req.Expiration, 0)
	}

	if len(req.Priority) > 0 && req.Priority == "normal" {
		notification.Priority = apns.PriorityLow
	}

	payload := payload.NewPayload().Alert(req.Message)

	if req.Badge > 0 {
		payload.Badge(req.Badge)
	}

	if len(req.Sound) > 0 {
		payload.Sound(req.Sound)
	}

	if req.ContentAvailable {
		payload.ContentAvailable()
	}

	if len(req.URLArgs) > 0 {
		payload.URLArgs(req.URLArgs)
	}

	for k, v := range req.Data {
		payload.Custom(k, v)
	}

	payload = iosAlertDictionary(payload, req)

	notification.Payload = payload

	return notification
}

// PushToIOS provide send notification to APNs server.
func PushToIOS(req PushNotification) bool {
	LogAccess.Debug("Start push notification for iOS")

	var isError bool

	notification := GetIOSNotification(req)

	for _, token := range req.Tokens {
		notification.DeviceToken = token

		// send ios notification
		res, err := ApnsClient.Push(notification)

		if err != nil {
			// apns server error
			LogPush(FailedPush, token, req, err)
			isError = true
			StatStorage.AddIosError(1)
			continue
		}

		if res.StatusCode != 200 {
			// error message:
			// ref: https://github.com/sideshow/apns2/blob/master/response.go#L14-L65
			LogPush(FailedPush, token, req, errors.New(res.Reason))
			StatStorage.AddIosError(1)
			continue
		}

		if res.Sent() {
			LogPush(SucceededPush, token, req, nil)
			StatStorage.AddIosSuccess(1)
		}
	}

	return isError
}

// GetAndroidNotification use for define Android notificaiton.
// HTTP Connection Server Reference for Android
// https://developers.google.com/cloud-messaging/http-server-ref
func GetAndroidNotification(req PushNotification) gcm.HttpMessage {
	notification := gcm.HttpMessage{
		To:                    req.To,
		CollapseKey:           req.CollapseKey,
		ContentAvailable:      req.ContentAvailable,
		DelayWhileIdle:        req.DelayWhileIdle,
		TimeToLive:            req.TimeToLive,
		RestrictedPackageName: req.RestrictedPackageName,
		DryRun:                req.DryRun,
	}

	notification.RegistrationIds = req.Tokens

	if len(req.Priority) > 0 && req.Priority == "high" {
		notification.Priority = "high"
	}

	// Add another field
	if len(req.Data) > 0 {
		notification.Data = make(map[string]interface{})
		for k, v := range req.Data {
			notification.Data[k] = v
		}
	}

	notification.Notification = &req.Notification

	// Set request message if body is empty
	if len(notification.Notification.Body) == 0 {
		notification.Notification.Body = req.Message
	}

	if len(req.Title) > 0 {
		notification.Notification.Title = req.Title
	}

	if len(req.Sound) > 0 {
		notification.Notification.Sound = req.Sound
	}

	return notification
}

// PushToAndroid provide send notification to Android server.
func PushToAndroid(req PushNotification) bool {
	LogAccess.Debug("Start push notification for Android")

	var APIKey string

	// check message
	err := CheckMessage(req)

	if err != nil {
		LogError.Error("request error: " + err.Error())
		return false
	}

	notification := GetAndroidNotification(req)

	if APIKey = PushConf.Android.APIKey; req.APIKey != "" {
		APIKey = req.APIKey
	}

	res, err := gcm.SendHttp(APIKey, notification)

	if err != nil {
		// GCM server error
		LogError.Error("GCM server error: " + err.Error())

		return false
	}

	LogAccess.Debug(fmt.Sprintf("Android Success count: %d, Failure count: %d", res.Success, res.Failure))
	StatStorage.AddAndroidSuccess(int64(res.Success))
	StatStorage.AddAndroidError(int64(res.Failure))

	for k, result := range res.Results {
		if result.Error != "" {
			LogPush(FailedPush, req.Tokens[k], req, errors.New(result.Error))
			continue
		}

		LogPush(SucceededPush, req.Tokens[k], req, nil)
	}

	return true
}
<|endoftext|>