<commit_before>package cloud

import (
	"bytes"
	"strings"
	"text/template"

	api "github.com/appscode/pharmer/apis/v1alpha1"
	"github.com/ghodss/yaml"
	"github.com/hashicorp/go-version"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
)

type TemplateData struct {
	BinaryVersion      string
	KubeadmToken       string
	CAKey              string
	FrontProxyKey      string
	APIServerAddress   string
	ExtraDomains       string
	NetworkProvider    string
	CloudConfig        string
	Provider           string
	ExternalProvider   bool
	KubeadmTokenLoader string

	MasterConfiguration *kubeadmapi.MasterConfiguration
	KubeletExtraArgs    map[string]string
}

func (td TemplateData) MasterConfigurationYAML() (string, error) {
	if td.MasterConfiguration == nil {
		return "", nil
	}
	cb, err := yaml.Marshal(td.MasterConfiguration)
	return string(cb), err
}

func (td TemplateData) IsPreReleaseVersion() bool {
	if v, err := version.NewVersion(td.BinaryVersion); err == nil && v.Prerelease() != "" {
		return true
	}
	return false
}

func (td TemplateData) KubeletExtraArgsStr() string {
	var buf bytes.Buffer
	for k, v := range td.KubeletExtraArgs {
		buf.WriteString("--")
		buf.WriteString(k)
		buf.WriteRune('=')
		buf.WriteString(v)
		buf.WriteRune(' ')
	}
	return buf.String()
}

func (td TemplateData) KubeletExtraArgsEmptyCloudProviderStr() string {
	var buf bytes.Buffer
	for k, v := range td.KubeletExtraArgs {
		if k == "cloud-config" {
			continue
		}
		if k == "cloud-provider" {
			v = ""
		}
		buf.WriteString("--")
		buf.WriteString(k)
		buf.WriteRune('=')
		buf.WriteString(v)
		buf.WriteRune(' ')
	}
	return buf.String()
}

func (td TemplateData) PackageList() string {
	pkgs := []string{
		"cron",
		"docker.io",
		"ebtables",
		"git",
		"glusterfs-client",
		"haveged",
		"nfs-common",
		"socat",
	}
	if !td.IsPreReleaseVersion() {
		if td.BinaryVersion == "" {
			pkgs = append(pkgs, "kubeadm", "kubelet", "kubectl")
		} else {
			pkgs = append(pkgs, "kubeadm="+td.BinaryVersion, "kubelet="+td.BinaryVersion, "kubectl="+td.BinaryVersion)
		}
	}
	if td.Provider != "gce" && td.Provider != "gke" {
		pkgs = append(pkgs, "ntp")
	}
	return strings.Join(pkgs, " ")
}

var (
	StartupScriptTemplate = template.Must(template.New(api.RoleMaster).Parse(`#!/bin/bash
set -x
set -o errexit
set -o nounset
set -o pipefail

# log to /var/log/startup-script.log
exec > >(tee -a /var/log/startup-script.log)
exec 2>&1

# kill apt processes (E: Unable to lock directory /var/lib/apt/lists/)
kill $(ps aux | grep '[a]pt' | awk '{print $2}') || true

{{ template "prepare-host" . }}

apt-get update -y
apt-get install -y apt-transport-https curl ca-certificates

curl -fSsL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list

add-apt-repository -y ppa:gluster/glusterfs-3.10

apt-get update -y
apt-get install -y {{ .PackageList }} || true
{{ if .IsPreReleaseVersion }}
curl -Lo kubeadm https://dl.k8s.io/release/{{ .KubeadmVersion }}/bin/linux/amd64/kubeadm \
    && chmod +x kubeadm \
	&& mv kubeadm /usr/bin/
{{ end }}

curl -Lo pre-k https://cdn.appscode.com/binaries/pre-k/0.1.0-alpha.7/pre-k-linux-amd64 \
	&& chmod +x pre-k \
	&& mv pre-k /usr/bin/

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ if .ExternalProvider }}{{ .KubeletExtraArgsEmptyCloudProviderStr }}{{ else }}{{ .KubeletExtraArgsStr }}{{ end }}"
EOF

kubeadm reset

{{ template "setup-certs" . }}

{{ if .CloudConfig }}
cat > /etc/kubernetes/cloud-config <<EOF
{{ .CloudConfig }}
EOF
{{ end }}

mkdir -p /etc/kubernetes/kubeadm

{{ if .MasterConfiguration }}
cat > /etc/kubernetes/kubeadm/base.yaml <<EOF
{{ .MasterConfigurationYAML }}
EOF
{{ end }}

pre-k merge master-config \
	--config=/etc/kubernetes/kubeadm/base.yaml \
	--apiserver-advertise-address=$(pre-k get public-ips --all=false) \
	--apiserver-cert-extra-sans=$(pre-k get public-ips --routable) \
	--apiserver-cert-extra-sans=$(pre-k get private-ips) \
	--apiserver-cert-extra-sans={{ .ExtraDomains }} \
	> /etc/kubernetes/kubeadm/config.yaml
kubeadm init --config=/etc/kubernetes/kubeadm/config.yaml --skip-token-print

{{ if eq .NetworkProvider "flannel" }}
{{ template "flannel" . }}
{{ else if eq .NetworkProvider "calico" }}
{{ template "calico" . }}
{{ end }}

kubectl apply \
  -f https://raw.githubusercontent.com/appscode/pharmer/master/addons/kubeadm-probe/ds.yaml \
  --kubeconfig /etc/kubernetes/admin.conf

mkdir -p ~/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

{{ if .ExternalProvider }}
{{ template "ccm" . }}
{{end}}

`))

	_ = template.Must(StartupScriptTemplate.New(api.RoleNode).Parse(`#!/bin/bash
set -x
set -o errexit
set -o nounset
set -o pipefail

# log to /var/log/startup-script.log
exec > >(tee -a /var/log/startup-script.log)
exec 2>&1

# kill apt processes (E: Unable to lock directory /var/lib/apt/lists/)
kill $(ps aux | grep '[a]pt' | awk '{print $2}') || true

{{ template "prepare-host" . }}

apt-get update -y
apt-get install -y apt-transport-https curl ca-certificates

curl -fSsL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list

add-apt-repository -y ppa:gluster/glusterfs-3.10

apt-get update -y
apt-get install -y {{ .PackageList }} || true
{{ if .IsPreReleaseVersion }}
curl -Lo kubeadm https://dl.k8s.io/release/{{ .KubeadmVersion }}/bin/linux/amd64/kubeadm \
    && chmod +x kubeadm \
	&& mv kubeadm /usr/bin/
{{ end }}

systemctl enable docker
systemctl start docker

{{ if .CloudConfig }}
cat > /etc/kubernetes/cloud-config <<EOF
{{ .CloudConfig }}
EOF
{{ end }}

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
EOF

systemctl daemon-reload
systemctl restart kubelet

kubeadm reset
{{ .KubeadmTokenLoader  }}
KUBEADM_TOKEN=${KUBEADM_TOKEN:-{{ .KubeadmToken }}}
kubeadm join --token=${KUBEADM_TOKEN} {{ .APIServerAddress }}
`))

	_ = template.Must(StartupScriptTemplate.New("prepare-host").Parse(``))

	_ = template.Must(StartupScriptTemplate.New("setup-certs").Parse(`
mkdir -p /etc/kubernetes/pki

cat > /etc/kubernetes/pki/ca.key <<EOF
{{ .CAKey }}
EOF
pre-k get cacert --common-name=ca < /etc/kubernetes/pki/ca.key > /etc/kubernetes/pki/ca.crt

cat > /etc/kubernetes/pki/front-proxy-ca.key <<EOF
{{ .FrontProxyKey }}
EOF
pre-k get cacert --common-name=front-proxy-ca < /etc/kubernetes/pki/front-proxy-ca.key > /etc/kubernetes/pki/front-proxy-ca.crt
chmod 600 /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/front-proxy-ca.key
`))

	_ = template.Must(StartupScriptTemplate.New("ccm").Parse(`
kubectl apply \
  -f https://raw.githubusercontent.com/appscode/pharmer/master/cloud/providers/digitalocean/cloud-control-manager.yaml \
  --kubeconfig /etc/kubernetes/admin.conf

until [ $(kubectl get pods -n kube-system -l app=cloud-controller-manager -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
do
   echo '.'
   sleep 5
done

kubectl taint nodes $(uname -n) node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule --kubeconfig /etc/kubernetes/admin.conf

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
EOF
systemctl daemon-reload
systemctl restart kubelet

# systemctl enable docker
# systemctl start docker

# until [ $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
# do
#    echo '.'
#    sleep 5
# done
#
# kubectl apply -f "https://raw.githubusercontent.com/appscode/pharmer/master/cloud/providers/{{ .Provider }}/cloud-control-manager.yaml" --kubeconfig /etc/kubernetes/admin.conf
#
# until [ $(kubectl get pods -n kube-system -l app=cloud-controller-manager -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
# do
#    echo '.'
#    sleep 5
# done
#
# cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
# [Service]
# Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
# EOF
#
# NODE_NAME=$(uname -n)
# kubectl taint nodes $(uname -n) node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule --kubeconfig /etc/kubernetes/admin.conf
#
# systemctl daemon-reload
# systemctl restart kubelet

# sleep 10
# reboot
`))

	_ = template.Must(StartupScriptTemplate.New("calico").Parse(`
kubectl apply \
  -f https://docs.projectcalico.org/v2.6/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml \
  --kubeconfig /etc/kubernetes/admin.conf
`))

	_ = template.Must(StartupScriptTemplate.New("flannel").Parse(`
kubectl apply \
  -f https://raw.githubusercontent.com/coreos/flannel/v0.8.0/Documentation/kube-flannel.yml \
  --kubeconfig /etc/kubernetes/admin.conf
kubectl apply \
  -f https://raw.githubusercontent.com/coreos/flannel/v0.8.0/Documentation/kube-flannel-rbac.yml \
  --kubeconfig /etc/kubernetes/admin.conf
`))
)
<commit_msg>Wait for kube-dns to run before running CCM<commit_after>package cloud

import (
	"bytes"
	"strings"
	"text/template"

	api "github.com/appscode/pharmer/apis/v1alpha1"
	"github.com/ghodss/yaml"
	"github.com/hashicorp/go-version"
	kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
)

type TemplateData struct {
	BinaryVersion      string
	KubeadmToken       string
	CAKey              string
	FrontProxyKey      string
	APIServerAddress   string
	ExtraDomains       string
	NetworkProvider    string
	CloudConfig        string
	Provider           string
	ExternalProvider   bool
	KubeadmTokenLoader string

	MasterConfiguration *kubeadmapi.MasterConfiguration
	KubeletExtraArgs    map[string]string
}

func (td TemplateData) MasterConfigurationYAML() (string, error) {
	if td.MasterConfiguration == nil {
		return "", nil
	}
	cb, err := yaml.Marshal(td.MasterConfiguration)
	return string(cb), err
}

func (td TemplateData) IsPreReleaseVersion() bool {
	if v, err := version.NewVersion(td.BinaryVersion); err == nil && v.Prerelease() != "" {
		return true
	}
	return false
}

func (td TemplateData) KubeletExtraArgsStr() string {
	var buf bytes.Buffer
	for k, v := range td.KubeletExtraArgs {
		buf.WriteString("--")
		buf.WriteString(k)
		buf.WriteRune('=')
		buf.WriteString(v)
		buf.WriteRune(' ')
	}
	return buf.String()
}

func (td TemplateData) KubeletExtraArgsEmptyCloudProviderStr() string {
	var buf bytes.Buffer
	for k, v := range td.KubeletExtraArgs {
		if k == "cloud-config" {
			continue
		}
		if k == "cloud-provider" {
			v = ""
		}
		buf.WriteString("--")
		buf.WriteString(k)
		buf.WriteRune('=')
		buf.WriteString(v)
		buf.WriteRune(' ')
	}
	return buf.String()
}

func (td TemplateData) PackageList() string {
	pkgs := []string{
		"cron",
		"docker.io",
		"ebtables",
		"git",
		"glusterfs-client",
		"haveged",
		"nfs-common",
		"socat",
	}
	if !td.IsPreReleaseVersion() {
		if td.BinaryVersion == "" {
			pkgs = append(pkgs, "kubeadm", "kubelet", "kubectl")
		} else {
			pkgs = append(pkgs, "kubeadm="+td.BinaryVersion, "kubelet="+td.BinaryVersion, "kubectl="+td.BinaryVersion)
		}
	}
	if td.Provider != "gce" && td.Provider != "gke" {
		pkgs = append(pkgs, "ntp")
	}
	return strings.Join(pkgs, " ")
}

var (
	StartupScriptTemplate = template.Must(template.New(api.RoleMaster).Parse(`#!/bin/bash
set -x
set -o errexit
set -o nounset
set -o pipefail

# log to /var/log/startup-script.log
exec > >(tee -a /var/log/startup-script.log)
exec 2>&1

# kill apt processes (E: Unable to lock directory /var/lib/apt/lists/)
kill $(ps aux | grep '[a]pt' | awk '{print $2}') || true

{{ template "prepare-host" . }}

apt-get update -y
apt-get install -y apt-transport-https curl ca-certificates

curl -fSsL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list

add-apt-repository -y ppa:gluster/glusterfs-3.10

apt-get update -y
apt-get install -y {{ .PackageList }} || true
{{ if .IsPreReleaseVersion }}
curl -Lo kubeadm https://dl.k8s.io/release/{{ .KubeadmVersion }}/bin/linux/amd64/kubeadm \
    && chmod +x kubeadm \
	&& mv kubeadm /usr/bin/
{{ end }}

curl -Lo pre-k https://cdn.appscode.com/binaries/pre-k/0.1.0-alpha.7/pre-k-linux-amd64 \
	&& chmod +x pre-k \
	&& mv pre-k /usr/bin/

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ if .ExternalProvider }}{{ .KubeletExtraArgsEmptyCloudProviderStr }}{{ else }}{{ .KubeletExtraArgsStr }}{{ end }}"
EOF

kubeadm reset

{{ template "setup-certs" . }}

{{ if .CloudConfig }}
cat > /etc/kubernetes/cloud-config <<EOF
{{ .CloudConfig }}
EOF
{{ end }}

mkdir -p /etc/kubernetes/kubeadm

{{ if .MasterConfiguration }}
cat > /etc/kubernetes/kubeadm/base.yaml <<EOF
{{ .MasterConfigurationYAML }}
EOF
{{ end }}

pre-k merge master-config \
	--config=/etc/kubernetes/kubeadm/base.yaml \
	--apiserver-advertise-address=$(pre-k get public-ips --all=false) \
	--apiserver-cert-extra-sans=$(pre-k get public-ips --routable) \
	--apiserver-cert-extra-sans=$(pre-k get private-ips) \
	--apiserver-cert-extra-sans={{ .ExtraDomains }} \
	> /etc/kubernetes/kubeadm/config.yaml
kubeadm init --config=/etc/kubernetes/kubeadm/config.yaml --skip-token-print

{{ if eq .NetworkProvider "flannel" }}
{{ template "flannel" . }}
{{ else if eq .NetworkProvider "calico" }}
{{ template "calico" . }}
{{ end }}

kubectl apply \
  -f https://raw.githubusercontent.com/appscode/pharmer/master/addons/kubeadm-probe/ds.yaml \
  --kubeconfig /etc/kubernetes/admin.conf

mkdir -p ~/.kube
sudo cp -i /etc/kubernetes/admin.conf ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config

{{ if .ExternalProvider }}
{{ template "ccm" . }}
{{end}}

`))

	_ = template.Must(StartupScriptTemplate.New(api.RoleNode).Parse(`#!/bin/bash
set -x
set -o errexit
set -o nounset
set -o pipefail

# log to /var/log/startup-script.log
exec > >(tee -a /var/log/startup-script.log)
exec 2>&1

# kill apt processes (E: Unable to lock directory /var/lib/apt/lists/)
kill $(ps aux | grep '[a]pt' | awk '{print $2}') || true

{{ template "prepare-host" . }}

apt-get update -y
apt-get install -y apt-transport-https curl ca-certificates

curl -fSsL https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' > /etc/apt/sources.list.d/kubernetes.list

add-apt-repository -y ppa:gluster/glusterfs-3.10

apt-get update -y
apt-get install -y {{ .PackageList }} || true
{{ if .IsPreReleaseVersion }}
curl -Lo kubeadm https://dl.k8s.io/release/{{ .KubeadmVersion }}/bin/linux/amd64/kubeadm \
    && chmod +x kubeadm \
	&& mv kubeadm /usr/bin/
{{ end }}

systemctl enable docker
systemctl start docker

{{ if .CloudConfig }}
cat > /etc/kubernetes/cloud-config <<EOF
{{ .CloudConfig }}
EOF
{{ end }}

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
EOF

systemctl daemon-reload
systemctl restart kubelet

kubeadm reset
{{ .KubeadmTokenLoader  }}
KUBEADM_TOKEN=${KUBEADM_TOKEN:-{{ .KubeadmToken }}}
kubeadm join --token=${KUBEADM_TOKEN} {{ .APIServerAddress }}
`))

	_ = template.Must(StartupScriptTemplate.New("prepare-host").Parse(``))

	_ = template.Must(StartupScriptTemplate.New("setup-certs").Parse(`
mkdir -p /etc/kubernetes/pki

cat > /etc/kubernetes/pki/ca.key <<EOF
{{ .CAKey }}
EOF
pre-k get cacert --common-name=ca < /etc/kubernetes/pki/ca.key > /etc/kubernetes/pki/ca.crt

cat > /etc/kubernetes/pki/front-proxy-ca.key <<EOF
{{ .FrontProxyKey }}
EOF
pre-k get cacert --common-name=front-proxy-ca < /etc/kubernetes/pki/front-proxy-ca.key > /etc/kubernetes/pki/front-proxy-ca.crt
chmod 600 /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/front-proxy-ca.key
`))

	_ = template.Must(StartupScriptTemplate.New("ccm").Parse(`
until [ $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
do
   echo '.'
   sleep 5
done

kubectl apply \
  -f https://raw.githubusercontent.com/appscode/pharmer/master/cloud/providers/digitalocean/cloud-control-manager.yaml \
  --kubeconfig /etc/kubernetes/admin.conf

until [ $(kubectl get pods -n kube-system -l app=cloud-controller-manager -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
do
   echo '.'
   sleep 5
done

kubectl taint nodes $(uname -n) node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule --kubeconfig /etc/kubernetes/admin.conf

cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
[Service]
Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
EOF
systemctl daemon-reload
systemctl restart kubelet

# systemctl enable docker
# systemctl start docker

# until [ $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
# do
#    echo '.'
#    sleep 5
# done
#
# kubectl apply -f "https://raw.githubusercontent.com/appscode/pharmer/master/cloud/providers/{{ .Provider }}/cloud-control-manager.yaml" --kubeconfig /etc/kubernetes/admin.conf
#
# until [ $(kubectl get pods -n kube-system -l app=cloud-controller-manager -o jsonpath='{.items[0].status.phase}' --kubeconfig /etc/kubernetes/admin.conf) == "Running" ]
# do
#    echo '.'
#    sleep 5
# done
#
# cat > /etc/systemd/system/kubelet.service.d/20-pharmer.conf <<EOF
# [Service]
# Environment="KUBELET_EXTRA_ARGS={{ .KubeletExtraArgsStr }}"
# EOF
#
# NODE_NAME=$(uname -n)
# kubectl taint nodes $(uname -n) node.cloudprovider.kubernetes.io/uninitialized=true:NoSchedule --kubeconfig /etc/kubernetes/admin.conf
#
# systemctl daemon-reload
# systemctl restart kubelet

# sleep 10
# reboot
`))

	_ = template.Must(StartupScriptTemplate.New("calico").Parse(`
kubectl apply \
  -f https://docs.projectcalico.org/v2.6/getting-started/kubernetes/installation/hosted/kubeadm/1.6/calico.yaml \
  --kubeconfig /etc/kubernetes/admin.conf
`))

	_ = template.Must(StartupScriptTemplate.New("flannel").Parse(`
kubectl apply \
  -f https://raw.githubusercontent.com/coreos/flannel/v0.8.0/Documentation/kube-flannel.yml \
  --kubeconfig /etc/kubernetes/admin.conf
kubectl apply \
  -f https://raw.githubusercontent.com/coreos/flannel/v0.8.0/Documentation/kube-flannel-rbac.yml \
  --kubeconfig /etc/kubernetes/admin.conf
`))
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"

	"github.com/pkg/errors"
)

const (
	VulcandKeyBase = "/vulcand"
)

var (
	httpBackendJSON string
)

type Vulcand struct {
	etcd *Etcd
}

type VulcandBackend struct {
	Type string `json:"Type"`
}

type VulcandServer struct {
	URL string `json:"URL"`
}

type VulcandFrontend struct {
	Type      string                  `json:"Type"`
	BackendId string                  `json:"BackendId"`
	Route     string                  `json:"Route"`
	Settings  VulcandFrontendSettings `json:"Settings"`
}

type VulcandFrontendSettings struct {
	TrustForwardHeader bool `json:"TrustForwardHeader"`
}

func NewVulcand(etcd *Etcd) *Vulcand {
	backend := VulcandBackend{
		Type: "http",
	}

	b, _ := json.Marshal(backend)
	httpBackendJSON = string(b)

	return &Vulcand{
		etcd: etcd,
	}
}

// {"Type": "http"}
func (v *Vulcand) SetBackend(application *Application, baseDomain string) error {
	key := fmt.Sprintf("%s/backends/%s/backend", VulcandKeyBase, application.ProjectName)

	if err := v.etcd.Set(key, httpBackendJSON); err != nil {
		return errors.Wrap(err, "Failed to set vulcand backend in etcd.")
	}

	return nil
}

// {"Type": "http", "BackendId": "$identifier", "Route": "Host(`$identifier.$base_domain`) && PathRegexp(`/`)", "Settings": {"TrustForwardHeader": true}}
func (v *Vulcand) SetFrontend(application *Application, identifier, baseDomain string) error {
	key := fmt.Sprintf("%s/frontends/%s/frontend", VulcandKeyBase, identifier)
	frontend := VulcandFrontend{
		Type:      "http",
		BackendId: application.ProjectName,
		Route:     fmt.Sprintf("Host(`%s.%s`) && PathRegexp(`/`)", identifier, baseDomain),
		Settings: VulcandFrontendSettings{
			TrustForwardHeader: true,
		},
	}

	b, err := json.Marshal(frontend)

	if err != nil {
		return errors.Wrap(err, "Failed to generate vulcand frontend JSON.")
	}

	// json.Marshal generates HTML-escaped JSON string
	b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
	json := string(b)

	if err := v.etcd.Set(key, json); err != nil {
		return errors.Wrap(err, "Failed to set vulcand frontend in etcd.")
	}

	return nil
}

// {"URL": "http://$web_container_host_ip:$web_container_port"}
func (v *Vulcand) SetServer(application *Application, container *Container, baseDomain string) error {
	key := fmt.Sprintf("%s/backends/%s/servers/%s", VulcandKeyBase, application.ProjectName, container.ContainerId)
	server := VulcandServer{
		URL: fmt.Sprintf("http://%s:%s", container.HostIP(), container.HostPort()),
	}

	b, err := json.Marshal(server)

	if err != nil {
		return errors.Wrap(err, "Failed to generate vulcand server JSON.")
	}

	json := string(b)

	if err := v.etcd.Set(key, json); err != nil {
		return errors.Wrap(err, "Failed to set vulcand server in etcd.")
	}

	return nil
}
<commit_msg>Register lower-case domain<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/pkg/errors"
)

const (
	VulcandKeyBase = "/vulcand"
)

var (
	httpBackendJSON string
)

type Vulcand struct {
	etcd *Etcd
}

type VulcandBackend struct {
	Type string `json:"Type"`
}

type VulcandServer struct {
	URL string `json:"URL"`
}

type VulcandFrontend struct {
	Type      string                  `json:"Type"`
	BackendId string                  `json:"BackendId"`
	Route     string                  `json:"Route"`
	Settings  VulcandFrontendSettings `json:"Settings"`
}

type VulcandFrontendSettings struct {
	TrustForwardHeader bool `json:"TrustForwardHeader"`
}

func NewVulcand(etcd *Etcd) *Vulcand {
	backend := VulcandBackend{
		Type: "http",
	}

	b, _ := json.Marshal(backend)
	httpBackendJSON = string(b)

	return &Vulcand{
		etcd: etcd,
	}
}

// {"Type": "http"}
func (v *Vulcand) SetBackend(application *Application, baseDomain string) error {
	key := fmt.Sprintf("%s/backends/%s/backend", VulcandKeyBase, application.ProjectName)

	if err := v.etcd.Set(key, httpBackendJSON); err != nil {
		return errors.Wrap(err, "Failed to set vulcand backend in etcd.")
	}

	return nil
}

// {"Type": "http", "BackendId": "$identifier", "Route": "Host(`$identifier.$base_domain`) && PathRegexp(`/`)", "Settings": {"TrustForwardHeader": true}}
func (v *Vulcand) SetFrontend(application *Application, identifier, baseDomain string) error {
	key := fmt.Sprintf("%s/frontends/%s/frontend", VulcandKeyBase, identifier)
	frontend := VulcandFrontend{
		Type:      "http",
		BackendId: application.ProjectName,
		Route:     fmt.Sprintf("Host(`%s.%s`) && PathRegexp(`/`)", strings.ToLower(identifier), strings.ToLower(baseDomain)),
		Settings: VulcandFrontendSettings{
			TrustForwardHeader: true,
		},
	}

	b, err := json.Marshal(frontend)

	if err != nil {
		return errors.Wrap(err, "Failed to generate vulcand frontend JSON.")
	}

	// json.Marshal generates HTML-escaped JSON string
	b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
	json := string(b)

	if err := v.etcd.Set(key, json); err != nil {
		return errors.Wrap(err, "Failed to set vulcand frontend in etcd.")
	}

	return nil
}

// {"URL": "http://$web_container_host_ip:$web_container_port"}
func (v *Vulcand) SetServer(application *Application, container *Container, baseDomain string) error {
	key := fmt.Sprintf("%s/backends/%s/servers/%s", VulcandKeyBase, application.ProjectName, container.ContainerId)
	server := VulcandServer{
		URL: fmt.Sprintf("http://%s:%s", container.HostIP(), container.HostPort()),
	}

	b, err := json.Marshal(server)

	if err != nil {
		return errors.Wrap(err, "Failed to generate vulcand server JSON.")
	}

	json := string(b)

	if err := v.etcd.Set(key, json); err != nil {
		return errors.Wrap(err, "Failed to set vulcand server in etcd.")
	}

	return nil
}
<|endoftext|>


<commit_before>// Clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

// Update target and motto as desired.
var (
	target = time.Date(2019, 4, 16, 0, 0, 0, 0, time.UTC)
	motto  = "Just Go"
)

func main() {
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now.In(target.Location()), countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
	indent         = "\t"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<commit_msg>simple motto<commit_after>// Clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

// Update target and motto as desired.
var (
	target = time.Date(2019, 4, 16, 0, 0, 0, 0, time.UTC)
	motto  = "Simply Go"
)

func main() {
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now.In(target.Location()), countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
	indent         = "\t"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2017, 3, 25, 0, 0, 0, 0, time.Local)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now, countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<commit_msg>April 1<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2017, 4, 1, 0, 0, 0, 0, time.UTC)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now, countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 7, 10, 0, 0, 0, 0, time.UTC)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<commit_msg>go 1.6.3<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 7, 18, 12, 0, 0, 0, time.Local)
	motto := "Just Go"
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent         = "\t"
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/robfig/cron"
	"github.com/spf13/viper"
	"github.com/markbao/redditdaily/redditdaily"
	"fmt"
	"time"
)

func main() {
	viper.SetConfigType("yaml")
	viper.SetConfigName("config")
	viper.AddConfigPath("../")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	c := cron.New();
	error := c.AddFunc(fmt.Sprintf("0 %v %v * * *", viper.GetInt("cron_min"), viper.GetInt("cron_hour")), redditdaily.Run)
	if error != nil {
		fmt.Println(error)
	}
	c.Start();

	fmt.Println("Cron started.")

	select{}
}
<commit_msg>Fix issue with time import<commit_after>package main

import (
	"github.com/robfig/cron"
	"github.com/spf13/viper"
	"github.com/markbao/redditdaily/redditdaily"
	"fmt"
)

func main() {
	viper.SetConfigType("yaml")
	viper.SetConfigName("config")
	viper.AddConfigPath("../")
	viper.AddConfigPath(".")
	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	c := cron.New();
	error := c.AddFunc(fmt.Sprintf("0 %v %v * * *", viper.GetInt("cron_min"), viper.GetInt("cron_hour")), redditdaily.Run)
	if error != nil {
		fmt.Println(error)
	}
	c.Start();

	fmt.Println("Cron started.")

	select{}
}
<|endoftext|>


<commit_before>// Clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

// Update target and motto as desired.
var (
	target = time.Date(2019, 4, 16, 0, 0, 0, 0, time.UTC)
	motto  = "Simply Go"
)

func main() {
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now.In(target.Location()), countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
	indent         = "\t"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<commit_msg>back to Local<commit_after>// Clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

// Update target and motto as desired.
var (
	target = time.Date(2019, 4, 16, 0, 0, 0, 0, time.Local)
	motto  = "Simply Go"
)

func main() {
	printTargetTime(target, motto)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now().Truncate(time.Second)
		if now != previous {
			previous = now
			countdown := now.Sub(target) // Negative times are before the target
			printCountdown(now.In(target.Location()), countdown)
		}
		time.Sleep(100 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	highlightStart = "\x1b[1;35m"
	highlightEnd   = "\x1b[0m"
	indent         = "\t"
)

func printTargetTime(target time.Time, motto string) {
	fmt.Print(indent, highlightStart, motto, highlightEnd, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printCountdown(now time.Time, countdown time.Duration) {
	var sign string
	if countdown >= 0 {
		sign = "+"
	} else {
		sign = "-"
		countdown = -countdown
	}

	days := int(countdown / (24 * time.Hour))
	countdown = countdown % (24 * time.Hour)

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(countdown, "          \r")
	os.Stdout.Sync()
}
<|endoftext|>


<commit_before>package stream

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sync"
	"time"

	"github.com/gallir/bytebufferpool"
	"github.com/gallir/radix.improved/redis"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var (
	msgBytesPool = &bytebufferpool.Pool{}
	msgPool      = &sync.Pool{
		New: func() interface{} {
			return &Msg{}
		},
	}
)

const (
	ext = "log"
)

func getMsg(srv *Server) *Msg {
	m := msgPool.Get().(*Msg)
	m.t = time.Now()
	m.b = msgBytesPool.Get()
	m.srv = srv
	return m
}

func putMsg(m *Msg) {
	msgBytesPool.Put(m.b)
	m.b = nil
	m.k = ""
	msgPool.Put(m)
}

type Msg struct {
	t   time.Time
	k   string
	b   *bytebufferpool.ByteBuffer
	srv *Server
}

func (m *Msg) fullpath() string {
	return m.srv.fullpath(m.t)
}

func (m *Msg) path() string {
	return m.srv.path(m.t)
}

func (m *Msg) filename() string {
	return fmt.Sprintf("%d-%s.%s", m.t.Unix(), m.k, ext)
}

func (m *Msg) parse(r []*redis.Resp) (err error) {

	// Read first argument to be parsed as Int64
	var i int64
	i, err = r[1].Int64()
	if err != nil {
		return err
	}

	// Convert int64 to Time
	m.t = time.Unix(i, 0)

	// Read and store the string key
	if m.k, err = r[2].Str(); err != nil {
		return err
	}

	return nil
}

func (m *Msg) Bytes() (b []byte, err error) {

	// if b, err = m.bytesFile(); err == nil {
	// 	return b, err
	// }

	b, err = m.bytesS3()
	return b, err
}

func (m *Msg) bytesFile() ([]byte, error) {
	// Build the path + filename
	filename := fmt.Sprintf("%s/%s", m.fullpath(), m.filename())

	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	b, _ := ioutil.ReadAll(file)

	return b, nil
}

func (m *Msg) bytesS3() ([]byte, error) {

	downloader := s3manager.NewDownloader(m.srv.s3sess)

	file, err := ioutil.TempFile("", "logs-download")
	if err != nil {
		return nil, err
	}
	defer os.Remove(file.Name())
	defer file.Close()

	_, err = downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: &m.srv.config.S3Bucket,                               // Required
			Key:    aws.String(fmt.Sprintf("%s/records-1.gz", m.path())), // Required
		})
	if err != nil {
		return nil, err
	}

	file.Seek(0, 0)

	r, err := gzip.NewReader(file)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	b := bytebufferpool.Get()

	recFound := false

	unixFound := false
	unix := make([]byte, 0)
	keyFound := false
	key := make([]byte, 0)

	for {

		buf := make([]byte, 1*1024)
		if _, err := r.Read(buf); err != nil {
			if recFound {
				if err == io.EOF {
					b.Write(buf)
					break
				}
				return nil, err
			}
			return nil, errors.New("Key not found")
		}

	S:
		// Check again "sep"
		if !unixFound {
			n := -1
			nb := byte('\n')
			for n, nb = range buf {
				if nb == sep[0] {
					unixFound = true
					break
				}
				unix = append(unix, nb)
			}
			if n > -1 {
				buf = buf[n+1:]
				//log.Printf("UNIX: %d |%s|: |%s|", n, string(unix), string(buf))
				if len(buf) == 0 {
					continue
				}
			} else {
				log.Printf("U == %s (%d)", string(buf), len(buf))
			}
		}

		if !keyFound {
			n := -1
			nb := byte('\n')
			for n, nb = range buf {
				if nb == sep[0] {
					keyFound = true
					//log.Printf("COMPARE: %s", string(buf))
					log.Printf("COMPARE: %d |%s| |%s| == |%s|", n, string(unix), string(key), m.k)
					if string(key) == m.k {
						recFound = true
					}
					break
				}
				key = append(key, nb)
			}
			if n > -1 {
				buf = buf[n+1:]
				//log.Printf("KEY: %d |%s| |%s|: |%s|", n, string(unix), string(key), string(buf))
				if len(buf) == 0 {
					continue
				}
			} else {
				log.Printf("K == %s (%d)", string(buf), len(buf))
			}
		}

		if bytes.Contains(buf, newLine) {
			i := bytes.IndexByte(buf, newLine[0])

			if recFound {
				last := buf[0:i]
				b.Write(last)
				//log.Printf("BREAK: %v |%s| |%s| |%s|", keyFound, unix, key, string(last))
				break
			}

			recFound = false
			unixFound = false
			unix = make([]byte, 0)
			keyFound = false
			key = make([]byte, 0)

			buf = buf[i+1:]
			//log.Printf("N: %v |%s| |%s| |%s|", recFound, string(unix), string(key), string(buf[len(buf)-100:len(buf)]))
			goto S
		}

		if recFound {
			b.Write(buf)
		}
	}

	//log.Printf("S: %s", string(b.B[0:1024]))
	//log.Printf("E: %s", string(b.B[b.Len()-1024:b.Len()]))
	//log.Printf("L: %d", b.Len())
	return base64.StdEncoding.DecodeString(b.String())
}
<commit_msg>FIX: bug in locate new line if is the last byte of the buffer<commit_after>package stream

import (
	"bytes"
	"compress/gzip"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"sync"
	"time"

	"github.com/gallir/bytebufferpool"
	"github.com/gallir/radix.improved/redis"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var (
	msgBytesPool = &bytebufferpool.Pool{}
	msgPool      = &sync.Pool{
		New: func() interface{} {
			return &Msg{}
		},
	}
)

const (
	ext = "log"
)

func getMsg(srv *Server) *Msg {
	m := msgPool.Get().(*Msg)
	m.t = time.Now()
	m.b = msgBytesPool.Get()
	m.srv = srv
	return m
}

func putMsg(m *Msg) {
	msgBytesPool.Put(m.b)
	m.b = nil
	m.k = ""
	msgPool.Put(m)
}

type Msg struct {
	t   time.Time
	k   string
	b   *bytebufferpool.ByteBuffer
	srv *Server
}

func (m *Msg) fullpath() string {
	return m.srv.fullpath(m.t)
}

func (m *Msg) path() string {
	return m.srv.path(m.t)
}

func (m *Msg) filename() string {
	return fmt.Sprintf("%d-%s.%s", m.t.Unix(), m.k, ext)
}

func (m *Msg) parse(r []*redis.Resp) (err error) {

	// Read first argument to be parsed as Int64
	var i int64
	i, err = r[1].Int64()
	if err != nil {
		return err
	}

	// Convert int64 to Time
	m.t = time.Unix(i, 0)

	// Read and store the string key
	if m.k, err = r[2].Str(); err != nil {
		return err
	}

	return nil
}

func (m *Msg) Bytes() (b []byte, err error) {

	// if b, err = m.bytesFile(); err == nil {
	// 	return b, err
	// }

	b, err = m.bytesS3()
	return b, err
}

func (m *Msg) bytesFile() ([]byte, error) {
	// Build the path + filename
	filename := fmt.Sprintf("%s/%s", m.fullpath(), m.filename())

	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	b, _ := ioutil.ReadAll(file)

	return b, nil
}

func (m *Msg) bytesS3() ([]byte, error) {

	downloader := s3manager.NewDownloader(m.srv.s3sess)

	file, err := ioutil.TempFile("", "logs-download")
	if err != nil {
		return nil, err
	}
	defer os.Remove(file.Name())
	defer file.Close()

	_, err = downloader.Download(file,
		&s3.GetObjectInput{
			Bucket: &m.srv.config.S3Bucket,                               // Required
			Key:    aws.String(fmt.Sprintf("%s/records-1.gz", m.path())), // Required
		})
	if err != nil {
		return nil, err
	}

	file.Seek(0, 0)

	r, err := gzip.NewReader(file)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	b := bytebufferpool.Get()

	recFound := false

	unixFound := false
	unix := make([]byte, 0)
	keyFound := false
	key := make([]byte, 0)

	for {

		buf := make([]byte, 1*1024)
		if _, err := r.Read(buf); err != nil {
			if recFound {
				if err == io.EOF {
					b.Write(buf)
					break
				}
				return nil, err
			}
			return nil, errors.New("Key not found")
		}

	S:
		// Check again "sep"
		if !unixFound {
			n := -1
			var nb byte
			for n, nb = range buf {
				if nb == sep[0] {
					unixFound = true
					break
				}
				unix = append(unix, nb)
			}
			if n > -1 {
				buf = buf[n+1:]
				//log.Printf("UNIX: %d |%s|: |%s|", n, string(unix), string(buf))
				if len(buf) == 0 {
					continue
				}
			} else {
				log.Printf("U == %s (%d)", string(buf), len(buf))
			}
		}

		if !keyFound {
			n := -1
			var nb byte
			for n, nb = range buf {
				if nb == sep[0] {
					keyFound = true
					//log.Printf("COMPARE: %s", string(buf))
					log.Printf("COMPARE: %d |%s| |%s| == |%s|", n, string(unix), string(key), m.k)
					if string(key) == m.k {
						recFound = true
					}
					break
				}
				key = append(key, nb)
			}
			if n > -1 {
				buf = buf[n+1:]
				//log.Printf("KEY: %d |%s| |%s|: |%s|", n, string(unix), string(key), string(buf))
				if len(buf) == 0 {
					continue
				}
			} else {
				log.Printf("K == %s (%d)", string(buf), len(buf))
			}
		}

		if i := bytes.IndexByte(buf, newLine[0]); i > -1 {
			if recFound {
				b.Write(buf[0:i])
				break
			}

			recFound = false
			unixFound = false
			unix = make([]byte, 0)
			keyFound = false
			key = make([]byte, 0)

			buf = buf[i+1:]
			//log.Printf("N: %v |%s| |%s| |%s|", recFound, string(unix), string(key), string(buf[len(buf)-100:len(buf)]))
			goto S
		}

		if recFound {
			b.Write(buf)
		}
	}

	//log.Printf("S: %s", string(b.B[0:1024]))
	//log.Printf("E: %s", string(b.B[b.Len()-1024:b.Len()]))
	//log.Printf("D: |%s|", string(b.B[269897-100:269897+100]))
	//log.Printf("L: %d", b.Len())
	return base64.StdEncoding.DecodeString(b.String())
}
<|endoftext|>


<commit_before><commit_msg>Unexport gopsutil.SystemInfo<commit_after><|endoftext|>


<commit_before>// Copyright 2016 The Cockroach 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.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package gossip_test

import (
	"net"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/pkg/errors"

	"github.com/cockroachdb/cockroach/gossip"
	"github.com/cockroachdb/cockroach/gossip/resolver"
	"github.com/cockroachdb/cockroach/gossip/simulation"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/protoutil"
	"github.com/cockroachdb/cockroach/util/syncutil"
)

type testStorage struct {
	syncutil.Mutex
	read, write bool
	info        gossip.BootstrapInfo
}

func (ts *testStorage) isRead() bool {
	ts.Lock()
	defer ts.Unlock()
	return ts.read
}

func (ts *testStorage) isWrite() bool {
	ts.Lock()
	defer ts.Unlock()
	return ts.write
}

func (ts *testStorage) Info() gossip.BootstrapInfo {
	ts.Lock()
	defer ts.Unlock()
	return ts.info
}

func (ts *testStorage) Len() int {
	ts.Lock()
	defer ts.Unlock()
	return len(ts.info.Addresses)
}

func (ts *testStorage) ReadBootstrapInfo(info *gossip.BootstrapInfo) error {
	ts.Lock()
	defer ts.Unlock()
	ts.read = true
	*info = *protoutil.Clone(&ts.info).(*gossip.BootstrapInfo)
	return nil
}

func (ts *testStorage) WriteBootstrapInfo(info *gossip.BootstrapInfo) error {
	ts.Lock()
	defer ts.Unlock()
	ts.write = true
	ts.info = *protoutil.Clone(info).(*gossip.BootstrapInfo)
	return nil
}

type unresolvedAddrSlice []util.UnresolvedAddr

func (s unresolvedAddrSlice) Len() int {
	return len(s)
}
func (s unresolvedAddrSlice) Less(i, j int) bool {
	networkCmp := strings.Compare(s[i].Network(), s[j].Network())
	return networkCmp < 0 || networkCmp == 0 && strings.Compare(s[i].String(), s[j].String()) < 0
}
func (s unresolvedAddrSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// TestGossipStorage verifies that a gossip node can join the cluster
// using the bootstrap hosts in a gossip.Storage object.
func TestGossipStorage(t *testing.T) {
	defer leaktest.AfterTest(t)()

	network := simulation.NewNetwork(3, true)
	defer network.Stop()

	// Set storage for each of the nodes.
	addresses := make(unresolvedAddrSlice, len(network.Nodes))
	stores := make([]testStorage, len(network.Nodes))
	for i, n := range network.Nodes {
		addresses[i] = util.MakeUnresolvedAddr(n.Addr().Network(), n.Addr().String())
		if err := n.Gossip.SetStorage(&stores[i]); err != nil {
			t.Fatal(err)
		}
	}

	// Wait for the gossip network to connect.
	network.RunUntilFullyConnected()

	// Wait long enough for storage to get the expected number of addresses.
	util.SucceedsSoon(t, func() error {
		for i := range stores {
			p := &stores[i]

			if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, p.Len(); expected != actual {
				return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, p.Info().Addresses)
			}
		}
		return nil
	})

	for i := range stores {
		p := &stores[i]

		if !p.isRead() {
			t.Errorf("%d: expected read from storage", i)
		}
		if !p.isWrite() {
			t.Errorf("%d: expected write from storage", i)
		}

		p.Lock()
		gotAddresses := unresolvedAddrSlice(p.info.Addresses)
		sort.Sort(gotAddresses)
		var expectedAddresses unresolvedAddrSlice
		for j, addr := range addresses {
			if i != j { // skip node's own address
				expectedAddresses = append(expectedAddresses, addr)
			}
		}
		sort.Sort(expectedAddresses)

		// Verify all gossip addresses are written to each persistent store.
		if !reflect.DeepEqual(gotAddresses, expectedAddresses) {
			t.Errorf("%d: expected addresses: %s, got: %s", i, expectedAddresses, gotAddresses)
		}
		p.Unlock()
	}

	// Create an unaffiliated gossip node with only itself as a resolver,
	// leaving it no way to reach the gossip network.
	node, err := network.CreateNode()
	if err != nil {
		t.Fatal(err)
	}
	node.Gossip.SetBootstrapInterval(1 * time.Millisecond)

	r, err := resolver.NewResolverFromAddress(node.Addr())
	if err != nil {
		t.Fatal(err)
	}
	node.Gossip.SetResolvers([]resolver.Resolver{r})
	if err := network.StartNode(node); err != nil {
		t.Fatal(err)
	}

	// Wait for a bit to ensure no connection.
	select {
	case <-time.After(10 * time.Millisecond):
		// expected outcome...
	case <-node.Gossip.Connected:
		t.Fatal("unexpectedly connected to gossip")
	}

	// Give the new node storage with info established from a node
	// in the established network.
	var ts2 testStorage
	if err := stores[0].ReadBootstrapInfo(&ts2.info); err != nil {
		t.Fatal(err)
	}
	if err := node.Gossip.SetStorage(&ts2); err != nil {
		t.Fatal(err)
	}

	network.SimulateNetwork(func(cycle int, network *simulation.Network) bool {
		if cycle > 1000 {
			t.Fatal("failed to connect to gossip")
		}
		select {
		case <-node.Gossip.Connected:
			return false
		default:
			return true
		}
	})

	util.SucceedsSoon(t, func() error {
		if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, ts2.Len(); expected != actual {
			return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, ts2.Info().Addresses)
		}
		return nil
	})
}

// TestGossipStorageCleanup verifies that bad resolvers are purged
// from the bootstrap info after gossip has successfully connected.
func TestGossipStorageCleanup(t *testing.T) {
	defer leaktest.AfterTest(t)()

	const numNodes = 3
	network := simulation.NewNetwork(numNodes, false)
	defer network.Stop()

	// Create a definitely closed address.
	ln, err := net.Listen("tcp", util.TestAddr.String())
	if err != nil {
		t.Fatal(err)
	}
	closedAddr := ln.Addr()
	ln.Close()

	const invalidAddr = "10.0.0.1000:3333333"
	// Set storage for each of the nodes.
	addresses := make(unresolvedAddrSlice, len(network.Nodes))
	stores := make([]testStorage, len(network.Nodes))
	for i, n := range network.Nodes {
		addresses[i] = util.MakeUnresolvedAddr(n.Addr().Network(), n.Addr().String())
		// Pre-add an invalid address to each gossip storage.
		if err := stores[i].WriteBootstrapInfo(&gossip.BootstrapInfo{
			Addresses: []util.UnresolvedAddr{
				util.MakeUnresolvedAddr("tcp", network.Nodes[(i+1)%numNodes].Addr().String()), // node i+1 address
				util.MakeUnresolvedAddr(closedAddr.Network(), closedAddr.String()),            // valid but closed address
				util.MakeUnresolvedAddr("tcp", invalidAddr),                                   // invalid address
			},
		}); err != nil {
			t.Fatal(err)
		}
		if err := n.Gossip.SetStorage(&stores[i]); err != nil {
			t.Fatal(err)
		}
		n.Gossip.SetStallInterval(1 * time.Millisecond)
		n.Gossip.SetBootstrapInterval(1 * time.Millisecond)
	}

	// Wait for the gossip network to connect.
	network.RunUntilFullyConnected()

	// Wait long enough for storage to get the expected number of
	// addresses and no pending cleanups.
	util.SucceedsSoon(t, func() error {
		for i := range stores {
			p := &stores[i]
			if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, p.Len(); expected != actual {
				return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, p.Info().Addresses)
			}
			for _, addr := range p.Info().Addresses {
				if addr.String() == invalidAddr {
					return errors.Errorf("node %d still needs bootstrap cleanup", i)
				}
			}
		}
		return nil
	})
}
<commit_msg>Use a 100% unreachable address instead of a recently closed port<commit_after>// Copyright 2016 The Cockroach 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.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)

package gossip_test

import (
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/pkg/errors"

	"github.com/cockroachdb/cockroach/gossip"
	"github.com/cockroachdb/cockroach/gossip/resolver"
	"github.com/cockroachdb/cockroach/gossip/simulation"
	"github.com/cockroachdb/cockroach/util"
	"github.com/cockroachdb/cockroach/util/leaktest"
	"github.com/cockroachdb/cockroach/util/protoutil"
	"github.com/cockroachdb/cockroach/util/syncutil"
)

type testStorage struct {
	syncutil.Mutex
	read, write bool
	info        gossip.BootstrapInfo
}

func (ts *testStorage) isRead() bool {
	ts.Lock()
	defer ts.Unlock()
	return ts.read
}

func (ts *testStorage) isWrite() bool {
	ts.Lock()
	defer ts.Unlock()
	return ts.write
}

func (ts *testStorage) Info() gossip.BootstrapInfo {
	ts.Lock()
	defer ts.Unlock()
	return ts.info
}

func (ts *testStorage) Len() int {
	ts.Lock()
	defer ts.Unlock()
	return len(ts.info.Addresses)
}

func (ts *testStorage) ReadBootstrapInfo(info *gossip.BootstrapInfo) error {
	ts.Lock()
	defer ts.Unlock()
	ts.read = true
	*info = *protoutil.Clone(&ts.info).(*gossip.BootstrapInfo)
	return nil
}

func (ts *testStorage) WriteBootstrapInfo(info *gossip.BootstrapInfo) error {
	ts.Lock()
	defer ts.Unlock()
	ts.write = true
	ts.info = *protoutil.Clone(info).(*gossip.BootstrapInfo)
	return nil
}

type unresolvedAddrSlice []util.UnresolvedAddr

func (s unresolvedAddrSlice) Len() int {
	return len(s)
}
func (s unresolvedAddrSlice) Less(i, j int) bool {
	networkCmp := strings.Compare(s[i].Network(), s[j].Network())
	return networkCmp < 0 || networkCmp == 0 && strings.Compare(s[i].String(), s[j].String()) < 0
}
func (s unresolvedAddrSlice) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// TestGossipStorage verifies that a gossip node can join the cluster
// using the bootstrap hosts in a gossip.Storage object.
func TestGossipStorage(t *testing.T) {
	defer leaktest.AfterTest(t)()

	network := simulation.NewNetwork(3, true)
	defer network.Stop()

	// Set storage for each of the nodes.
	addresses := make(unresolvedAddrSlice, len(network.Nodes))
	stores := make([]testStorage, len(network.Nodes))
	for i, n := range network.Nodes {
		addresses[i] = util.MakeUnresolvedAddr(n.Addr().Network(), n.Addr().String())
		if err := n.Gossip.SetStorage(&stores[i]); err != nil {
			t.Fatal(err)
		}
	}

	// Wait for the gossip network to connect.
	network.RunUntilFullyConnected()

	// Wait long enough for storage to get the expected number of addresses.
	util.SucceedsSoon(t, func() error {
		for i := range stores {
			p := &stores[i]

			if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, p.Len(); expected != actual {
				return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, p.Info().Addresses)
			}
		}
		return nil
	})

	for i := range stores {
		p := &stores[i]

		if !p.isRead() {
			t.Errorf("%d: expected read from storage", i)
		}
		if !p.isWrite() {
			t.Errorf("%d: expected write from storage", i)
		}

		p.Lock()
		gotAddresses := unresolvedAddrSlice(p.info.Addresses)
		sort.Sort(gotAddresses)
		var expectedAddresses unresolvedAddrSlice
		for j, addr := range addresses {
			if i != j { // skip node's own address
				expectedAddresses = append(expectedAddresses, addr)
			}
		}
		sort.Sort(expectedAddresses)

		// Verify all gossip addresses are written to each persistent store.
		if !reflect.DeepEqual(gotAddresses, expectedAddresses) {
			t.Errorf("%d: expected addresses: %s, got: %s", i, expectedAddresses, gotAddresses)
		}
		p.Unlock()
	}

	// Create an unaffiliated gossip node with only itself as a resolver,
	// leaving it no way to reach the gossip network.
	node, err := network.CreateNode()
	if err != nil {
		t.Fatal(err)
	}
	node.Gossip.SetBootstrapInterval(1 * time.Millisecond)

	r, err := resolver.NewResolverFromAddress(node.Addr())
	if err != nil {
		t.Fatal(err)
	}
	node.Gossip.SetResolvers([]resolver.Resolver{r})
	if err := network.StartNode(node); err != nil {
		t.Fatal(err)
	}

	// Wait for a bit to ensure no connection.
	select {
	case <-time.After(10 * time.Millisecond):
		// expected outcome...
	case <-node.Gossip.Connected:
		t.Fatal("unexpectedly connected to gossip")
	}

	// Give the new node storage with info established from a node
	// in the established network.
	var ts2 testStorage
	if err := stores[0].ReadBootstrapInfo(&ts2.info); err != nil {
		t.Fatal(err)
	}
	if err := node.Gossip.SetStorage(&ts2); err != nil {
		t.Fatal(err)
	}

	network.SimulateNetwork(func(cycle int, network *simulation.Network) bool {
		if cycle > 1000 {
			t.Fatal("failed to connect to gossip")
		}
		select {
		case <-node.Gossip.Connected:
			return false
		default:
			return true
		}
	})

	util.SucceedsSoon(t, func() error {
		if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, ts2.Len(); expected != actual {
			return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, ts2.Info().Addresses)
		}
		return nil
	})
}

// TestGossipStorageCleanup verifies that bad resolvers are purged
// from the bootstrap info after gossip has successfully connected.
func TestGossipStorageCleanup(t *testing.T) {
	defer leaktest.AfterTest(t)()

	const numNodes = 3
	network := simulation.NewNetwork(numNodes, false)
	defer network.Stop()

	const notReachableAddr = "localhost:0"
	const invalidAddr = "10.0.0.1000:3333333"
	// Set storage for each of the nodes.
	addresses := make(unresolvedAddrSlice, len(network.Nodes))
	stores := make([]testStorage, len(network.Nodes))
	for i, n := range network.Nodes {
		addresses[i] = util.MakeUnresolvedAddr(n.Addr().Network(), n.Addr().String())
		// Pre-add an invalid address to each gossip storage.
		if err := stores[i].WriteBootstrapInfo(&gossip.BootstrapInfo{
			Addresses: []util.UnresolvedAddr{
				util.MakeUnresolvedAddr("tcp", network.Nodes[(i+1)%numNodes].Addr().String()), // node i+1 address
				util.MakeUnresolvedAddr("tcp", notReachableAddr),                              // unreachable address
				util.MakeUnresolvedAddr("tcp", invalidAddr),                                   // invalid address
			},
		}); err != nil {
			t.Fatal(err)
		}
		if err := n.Gossip.SetStorage(&stores[i]); err != nil {
			t.Fatal(err)
		}
		n.Gossip.SetStallInterval(1 * time.Millisecond)
		n.Gossip.SetBootstrapInterval(1 * time.Millisecond)
	}

	// Wait for the gossip network to connect.
	network.RunUntilFullyConnected()

	// Wait long enough for storage to get the expected number of
	// addresses and no pending cleanups.
	util.SucceedsSoon(t, func() error {
		for i := range stores {
			p := &stores[i]
			if expected, actual := len(network.Nodes)-1 /* -1 is ourself */, p.Len(); expected != actual {
				return errors.Errorf("expected %v, got %v (info: %#v)", expected, actual, p.Info().Addresses)
			}
			for _, addr := range p.Info().Addresses {
				if addr.String() == invalidAddr {
					return errors.Errorf("node %d still needs bootstrap cleanup", i)
				}
			}
		}
		return nil
	})
}
<|endoftext|>


<commit_before>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package refactor

import (
	"fmt"
	"io"

	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/TheThingsNetwork/ttn/utils/readwriter"
	"github.com/brocaar/lorawan"
)

type RPacket interface {
	Packet
	Metadata() Metadata
	Payload() lorawan.PHYPayload
	DevEUI() lorawan.EUI64
}

// rpacket implements the core.RPacket interface
type rpacket struct {
	metadata Metadata
	payload  lorawan.PHYPayload
}

// NewRPacket construct a new router packet given a payload and metadata
func NewRPacket(payload lorawan.PHYPayload, metadata Metadata) (RPacket, error) {
	packet := rpacket{payload: payload, metadata: metadata}

	// Check and extract the devEUI
	if payload.MACPayload == nil {
		return nil, errors.New(errors.Structural, "MACPAyload should not be empty")
	}

	_, ok := payload.MACPayload.(*lorawan.MACPayload)
	if !ok {
		return nil, errors.New(errors.Structural, "Packet does not carry a MACPayload")
	}

	return &packet, nil
}

// DevEUI implements the core.BPacket interface
func (p rpacket) DevEUI() lorawan.EUI64 {
	var devEUI lorawan.EUI64
	copy(devEUI[4:], p.payload.MACPayload.(*lorawan.MACPayload).FHDR.DevAddr[:])
	return devEUI
}

// Metadata implements the core.RPacket interface
func (p rpacket) Metadata() Metadata {
	return p.metadata
}

// Payload implements the core.RPacket interface
func (p rpacket) Payload() lorawan.PHYPayload {
	return p.payload
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p rpacket) MarshalBinary() ([]byte, error) {
	var mtype byte
	switch p.payload.MHDR.MType {
	case lorawan.JoinRequest:
		fallthrough
	case lorawan.UnconfirmedDataUp:
		fallthrough
	case lorawan.ConfirmedDataUp:
		mtype = 1 // Up
	case lorawan.JoinAccept:
		fallthrough
	case lorawan.UnconfirmedDataDown:
		fallthrough
	case lorawan.ConfirmedDataDown:
		mtype = 2 // Down
	default:
		msg := fmt.Sprintf("Unsupported mtype: %s", p.payload.MHDR.MType.String())
		return nil, errors.New(errors.Implementation, msg)
	}

	dataMetadata, err := p.metadata.MarshalJSON()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	dataPayload, err := p.payload.MarshalBinary()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw := readwriter.New(nil)
	rw.Write([]byte{mtype})
	rw.Write(dataMetadata)
	rw.Write(dataPayload)
	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *rpacket) UnmarshalBinary(data []byte) error {
	if p == nil {
		return errors.New(errors.Structural, "Cannot unmarshal nil packet")
	}
	var isUp bool
	rw := readwriter.New(data)
	rw.Read(func(data []byte) {
		if data[0] == 1 {
			isUp = true
		}
	})

	var dataMetadata []byte
	rw.Read(func(data []byte) { dataMetadata = data })

	var dataPayload []byte
	rw.Read(func(data []byte) { dataPayload = data })

	if rw.Err() != nil {
		return errors.New(errors.Structural, rw.Err())
	}

	p.metadata = Metadata{}
	if err := p.metadata.UnmarshalJSON(dataMetadata); err != nil {
		return errors.New(errors.Structural, err)
	}

	p.payload = lorawan.NewPHYPayload(isUp)
	if err := p.payload.UnmarshalBinary(dataPayload); err != nil {
		return errors.New(errors.Structural, err)
	}

	return nil
}

// String implements the Stringer interface
func (p rpacket) String() string {
	str := "Packet {"
	str += fmt.Sprintf("\n\t%s}", p.metadata.String())
	str += fmt.Sprintf("\n\tPayload%+v\n}", p.payload)
	return str
}

type BPacket interface {
	Packet
	Commands() []lorawan.MACCommand
	DevEUI() lorawan.EUI64
	FCnt() uint32
	Metadata() Metadata
	Payload() []byte
	ValidateMIC(key lorawan.AES128Key) (bool, error)
}

// bpacket implements the core.BPacket interface
type bpacket struct {
	rpacket
}

// NewBPacket constructs a new broker packets given a payload and metadata
func NewBPacket(payload lorawan.PHYPayload, metadata Metadata) (BPacket, error) {
	packet, err := NewRPacket(payload, metadata)
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	macPayload := packet.Payload().MACPayload.(*lorawan.MACPayload)
	if len(macPayload.FRMPayload) != 1 {
		return nil, errors.New(errors.Structural, "Invalid frame payload. Expected exactly 1")
	}

	_, ok := macPayload.FRMPayload[0].(*lorawan.DataPayload)
	if !ok {
		return nil, errors.New(errors.Structural, "Invalid frame payload. Expected only data")
	}

	return bpacket{rpacket: packet.(rpacket)}, nil
}

// FCnt implements the core.BPacket interface
func (p bpacket) FCnt() uint32 {
	return p.payload.MACPayload.(*lorawan.MACPayload).FHDR.FCnt
}

// Payload implements the core.BPacket interface
func (p bpacket) Payload() []byte {
	macPayload := p.rpacket.payload.MACPayload.(*lorawan.MACPayload)
	return macPayload.FRMPayload[0].(*lorawan.DataPayload).Bytes
}

// ValidateMIC implements the core.BPacket interface
func (p bpacket) ValidateMIC(key lorawan.AES128Key) (bool, error) {
	return p.rpacket.payload.ValidateMIC(key)
}

// Commands implements the core.BPacket interface
func (p bpacket) Commands() []lorawan.MACCommand {
	return p.rpacket.payload.MACPayload.(*lorawan.MACPayload).FHDR.FOpts
}

type HPacket interface {
	Packet
	AppEUI() lorawan.EUI64
	DevEUI() lorawan.EUI64
	Payload() []byte    // FRMPayload
	Metadata() Metadata // TTL on down, DutyCycle + Rssi on Up
}

// hpacket implements the HPacket interface
type hpacket struct {
	appEUI   lorawan.EUI64
	devEUI   lorawan.EUI64
	payload  []byte
	metadata Metadata
}

// NewHPacket constructs a new Handler packet
func NewHPacket(a lorawan.EUI64, d lorawan.EUI64, p []byte, m Metadata) HPacket {
	if p == nil {
		p = make([]byte, 0)
	}
	return &hpacket{
		appEUI:   a,
		devEUI:   d,
		payload:  p,
		metadata: m,
	}
}

// AppEUI implements the core.HPacket interface
func (p hpacket) AppEUI() lorawan.EUI64 {
	return p.appEUI
}

// DevEUI implements the core.HPacket interface
func (p hpacket) DevEUI() lorawan.EUI64 {
	return p.devEUI
}

// Payload implements the core.HPacket interface
func (p hpacket) Payload() []byte {
	return p.payload
}

// Metadata implements the core.Metadata interface
func (p hpacket) Metadata() Metadata {
	return p.metadata
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p hpacket) MarshalBinary() ([]byte, error) {
	dataMetadata, err := p.Metadata().MarshalJSON()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw := readwriter.New(nil)
	rw.Write(p.appEUI)
	rw.Write(p.devEUI)
	rw.Write(p.payload)
	rw.Write(dataMetadata)
	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *hpacket) UnmarshalBinary(data []byte) error {
	if p == nil {
		return errors.New(errors.Structural, "Cannot unmarshal nil hpacket")
	}

	rw := readwriter.New(data)
	rw.Read(func(data []byte) { copy(p.appEUI[:], data) })
	rw.Read(func(data []byte) { copy(p.devEUI[:], data) })
	rw.Read(func(data []byte) { p.payload = data })
	var dataMetadata []byte
	rw.Read(func(data []byte) { dataMetadata = data })
	if err := p.metadata.UnmarshalJSON(dataMetadata); err != nil {
		return errors.New(errors.Structural, err)
	}
	return nil
}

// String implements the fmt.Stringer interface
func (p hpacket) String() string {
	str := "Packet {"
	str += fmt.Sprintf("\n\t%s}", p.metadata.String())
	str += fmt.Sprintf("\n\tAppEUI:%+x\n,", p.appEUI)
	str += fmt.Sprintf("\n\tDevEUI:%+x\n,", p.devEUI)
	str += fmt.Sprintf("\n\tPayload:%v\n}", p.Payload)
	return str
}

type APacket interface {
	Packet
	Payload() []byte
	Metadata() []Metadata
}

// apacket implements the core.APacket interface
type apacket struct {
	payload  []byte
	metadata []Metadata
}

// NewAPacket constructs a new application packet
func NewAPacket(payload []byte, metadata []Metadata) (APacket, error) {
	if len(payload) == 0 {
		return nil, errors.New(errors.Structural, "Application packet must hold a payload")
	}

	return &apacket{payload: payload, metadata: metadata}, nil
}

// Payload implements the core.APacket interface
func (p apacket) Payload() []byte {
	return p.payload
}

// Metadata implements the core.Metadata interface
func (p apacket) Metadata() []Metadata {
	return p.metadata
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p apacket) MarshalBinary() ([]byte, error) {
	rw := readwriter.New(nil)
	for _, m := range p.metadata {
		data, err := m.MarshalJSON()
		if err != nil {
			return nil, errors.New(errors.Structural, err)
		}
		rw.Write(data)
	}
	data, err := rw.Bytes()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw = readwriter.New(nil)
	rw.Write(p.payload)
	rw.Write(data)

	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *apacket) UnmarshalBinary(data []byte) error {
	if p == nil {
		return errors.New(errors.Structural, "Cannot unmarshal nil apacket")
	}

	var dataMetadata []byte
	rw := readwriter.New(data)
	rw.Read(func(data []byte) { p.payload = data })
	rw.Read(func(data []byte) { dataMetadata = data })
	if rw.Err() != nil {
		return errors.New(errors.Structural, rw.Err())
	}

	p.metadata = make([]Metadata, 0)
	rw = readwriter.New(dataMetadata)
	for {
		var dataMetadata []byte
		rw.Read(func(data []byte) { dataMetadata = data })
		if rw.Err() != nil {
			err, ok := rw.Err().(errors.Failure)
			if ok && err.Fault == io.EOF {
				break
			}
			return errors.New(errors.Structural, rw.Err())
		}
		metadata := new(Metadata)
		if err := metadata.UnmarshalJSON(dataMetadata); err != nil {
			return errors.New(errors.Structural, err)
		}

		p.metadata = append(p.metadata, *metadata)
	}

	return nil
}

// String implements the fmt.Stringer interface
func (p apacket) String() string {
	return "TODO"
}
<commit_msg>[refactor] Write and implements acceptPacket and joinPacket<commit_after>// Copyright © 2015 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package refactor

import (
	"fmt"
	"io"

	"github.com/TheThingsNetwork/ttn/utils/errors"
	"github.com/TheThingsNetwork/ttn/utils/readwriter"
	"github.com/brocaar/lorawan"
)

type RPacket interface {
	Packet
	Metadata() Metadata
	Payload() lorawan.PHYPayload
	DevEUI() lorawan.EUI64
}

// rpacket implements the core.RPacket interface
type rpacket struct {
	metadata Metadata
	payload  lorawan.PHYPayload
}

// NewRPacket construct a new router packet given a payload and metadata
func NewRPacket(payload lorawan.PHYPayload, metadata Metadata) (RPacket, error) {
	packet := rpacket{payload: payload, metadata: metadata}

	// Check and extract the devEUI
	if payload.MACPayload == nil {
		return nil, errors.New(errors.Structural, "MACPAyload should not be empty")
	}

	_, ok := payload.MACPayload.(*lorawan.MACPayload)
	if !ok {
		return nil, errors.New(errors.Structural, "Packet does not carry a MACPayload")
	}

	return &packet, nil
}

// DevEUI implements the core.BPacket interface
func (p rpacket) DevEUI() lorawan.EUI64 {
	var devEUI lorawan.EUI64
	copy(devEUI[4:], p.payload.MACPayload.(*lorawan.MACPayload).FHDR.DevAddr[:])
	return devEUI
}

// Metadata implements the core.RPacket interface
func (p rpacket) Metadata() Metadata {
	return p.metadata
}

// Payload implements the core.RPacket interface
func (p rpacket) Payload() lorawan.PHYPayload {
	return p.payload
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p rpacket) MarshalBinary() ([]byte, error) {
	var mtype byte
	switch p.payload.MHDR.MType {
	case lorawan.JoinRequest:
		fallthrough
	case lorawan.UnconfirmedDataUp:
		fallthrough
	case lorawan.ConfirmedDataUp:
		mtype = 1 // Up
	case lorawan.JoinAccept:
		fallthrough
	case lorawan.UnconfirmedDataDown:
		fallthrough
	case lorawan.ConfirmedDataDown:
		mtype = 2 // Down
	default:
		msg := fmt.Sprintf("Unsupported mtype: %s", p.payload.MHDR.MType.String())
		return nil, errors.New(errors.Implementation, msg)
	}

	dataMetadata, err := p.metadata.MarshalJSON()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	dataPayload, err := p.payload.MarshalBinary()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw := readwriter.New(nil)
	rw.Write([]byte{mtype})
	rw.Write(dataMetadata)
	rw.Write(dataPayload)
	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *rpacket) UnmarshalBinary(data []byte) error {
	if p == nil {
		return errors.New(errors.Structural, "Cannot unmarshal nil packet")
	}
	var isUp bool
	rw := readwriter.New(data)
	rw.Read(func(data []byte) {
		if data[0] == 1 {
			isUp = true
		}
	})

	var dataMetadata []byte
	rw.Read(func(data []byte) { dataMetadata = data })

	var dataPayload []byte
	rw.Read(func(data []byte) { dataPayload = data })

	if rw.Err() != nil {
		return errors.New(errors.Structural, rw.Err())
	}

	p.metadata = Metadata{}
	if err := p.metadata.UnmarshalJSON(dataMetadata); err != nil {
		return errors.New(errors.Structural, err)
	}

	p.payload = lorawan.NewPHYPayload(isUp)
	if err := p.payload.UnmarshalBinary(dataPayload); err != nil {
		return errors.New(errors.Structural, err)
	}

	return nil
}

// String implements the Stringer interface
func (p rpacket) String() string {
	str := "Packet {"
	str += fmt.Sprintf("\n\t%s}", p.metadata.String())
	str += fmt.Sprintf("\n\tPayload%+v\n}", p.payload)
	return str
}

type BPacket interface {
	Packet
	Commands() []lorawan.MACCommand
	DevEUI() lorawan.EUI64
	FCnt() uint32
	Metadata() Metadata
	Payload() []byte
	ValidateMIC(key lorawan.AES128Key) (bool, error)
}

// bpacket implements the core.BPacket interface
type bpacket struct {
	rpacket
}

// NewBPacket constructs a new broker packets given a payload and metadata
func NewBPacket(payload lorawan.PHYPayload, metadata Metadata) (BPacket, error) {
	packet, err := NewRPacket(payload, metadata)
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	macPayload := packet.Payload().MACPayload.(*lorawan.MACPayload)
	if len(macPayload.FRMPayload) != 1 {
		return nil, errors.New(errors.Structural, "Invalid frame payload. Expected exactly 1")
	}

	_, ok := macPayload.FRMPayload[0].(*lorawan.DataPayload)
	if !ok {
		return nil, errors.New(errors.Structural, "Invalid frame payload. Expected only data")
	}

	return bpacket{rpacket: packet.(rpacket)}, nil
}

// FCnt implements the core.BPacket interface
func (p bpacket) FCnt() uint32 {
	return p.payload.MACPayload.(*lorawan.MACPayload).FHDR.FCnt
}

// Payload implements the core.BPacket interface
func (p bpacket) Payload() []byte {
	macPayload := p.rpacket.payload.MACPayload.(*lorawan.MACPayload)
	return macPayload.FRMPayload[0].(*lorawan.DataPayload).Bytes
}

// ValidateMIC implements the core.BPacket interface
func (p bpacket) ValidateMIC(key lorawan.AES128Key) (bool, error) {
	return p.rpacket.payload.ValidateMIC(key)
}

// Commands implements the core.BPacket interface
func (p bpacket) Commands() []lorawan.MACCommand {
	return p.rpacket.payload.MACPayload.(*lorawan.MACPayload).FHDR.FOpts
}

type HPacket interface {
	Packet
	AppEUI() lorawan.EUI64
	DevEUI() lorawan.EUI64
	Payload() []byte    // FRMPayload
	Metadata() Metadata // TTL on down, DutyCycle + Rssi on Up
}

// hpacket implements the HPacket interface
type hpacket struct {
	*basehpacket
	metadata Metadata
}

// NewHPacket constructs a new Handler packet
func NewHPacket(appEUI lorawan.EUI64, devEUI lorawan.EUI64, payload []byte, metadata Metadata) HPacket {
	if payload == nil {
		payload = make([]byte, 0)
	}
	return &hpacket{
		basehpacket: &basehpacket{
			appEUI:  appEUI,
			devEUI:  devEUI,
			payload: payload,
		},
		metadata: metadata,
	}
}

// Metadata implements the core.Metadata interface
func (p hpacket) Metadata() Metadata {
	return p.metadata
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p hpacket) MarshalBinary() ([]byte, error) {
	dataMetadata, err := p.Metadata().MarshalJSON()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	data, err := p.basehpacket.MarshalBinary()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw := readwriter.New(data)
	rw.Write(dataMetadata)
	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *hpacket) UnmarshalBinary(data []byte) error {
	rw := readwriter.New(data)
	rw.Read(func(data []byte) { copy(p.basehpacket.appEUI[:], data) })
	rw.Read(func(data []byte) { copy(p.basehpacket.devEUI[:], data) })
	rw.Read(func(data []byte) { p.basehpacket.payload = data })
	var dataMetadata []byte
	rw.Read(func(data []byte) { dataMetadata = data })
	if err := p.metadata.UnmarshalJSON(dataMetadata); err != nil {
		return errors.New(errors.Structural, err)
	}
	return nil
}

// String implements the fmt.Stringer interface
func (p hpacket) String() string {
	str := "Packet {"
	str += fmt.Sprintf("\n\t%s}", p.metadata.String())
	str += fmt.Sprintf("\n\tAppEUI:%+x\n,", p.appEUI)
	str += fmt.Sprintf("\n\tDevEUI:%+x\n,", p.devEUI)
	str += fmt.Sprintf("\n\tPayload:%v\n}", p.Payload)
	return str
}

type APacket interface {
	Packet
	Payload() []byte
	Metadata() []Metadata
}

// apacket implements the core.APacket interface
type apacket struct {
	payload  []byte
	metadata []Metadata
}

// NewAPacket constructs a new application packet
func NewAPacket(payload []byte, metadata []Metadata) (APacket, error) {
	if len(payload) == 0 {
		return nil, errors.New(errors.Structural, "Application packet must hold a payload")
	}

	return &apacket{payload: payload, metadata: metadata}, nil
}

// Payload implements the core.APacket interface
func (p apacket) Payload() []byte {
	return p.payload
}

// Metadata implements the core.Metadata interface
func (p apacket) Metadata() []Metadata {
	return p.metadata
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p apacket) MarshalBinary() ([]byte, error) {
	rw := readwriter.New(nil)
	for _, m := range p.metadata {
		data, err := m.MarshalJSON()
		if err != nil {
			return nil, errors.New(errors.Structural, err)
		}
		rw.Write(data)
	}
	data, err := rw.Bytes()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}

	rw = readwriter.New(nil)
	rw.Write(p.payload)
	rw.Write(data)

	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *apacket) UnmarshalBinary(data []byte) error {
	if p == nil {
		return errors.New(errors.Structural, "Cannot unmarshal nil apacket")
	}

	var dataMetadata []byte
	rw := readwriter.New(data)
	rw.Read(func(data []byte) { p.payload = data })
	rw.Read(func(data []byte) { dataMetadata = data })
	if rw.Err() != nil {
		return errors.New(errors.Structural, rw.Err())
	}

	p.metadata = make([]Metadata, 0)
	rw = readwriter.New(dataMetadata)
	for {
		var dataMetadata []byte
		rw.Read(func(data []byte) { dataMetadata = data })
		if rw.Err() != nil {
			err, ok := rw.Err().(errors.Failure)
			if ok && err.Fault == io.EOF {
				break
			}
			return errors.New(errors.Structural, rw.Err())
		}
		metadata := new(Metadata)
		if err := metadata.UnmarshalJSON(dataMetadata); err != nil {
			return errors.New(errors.Structural, err)
		}

		p.metadata = append(p.metadata, *metadata)
	}

	return nil
}

// String implements the fmt.Stringer interface
func (p apacket) String() string {
	return "TODO"
}

type JoinPacket interface {
	Packet
	AppEUI() lorawan.EUI64
	DevEUI() lorawan.EUI64
	DevNonce() [2]byte
	Metadata() Metadata // Rssi + DutyCycle
}

// joinPacket implements the core.JoinPacket interface
type joinpacket struct {
	*basehpacket
	metadata Metadata
}

// NewJoinPacket constructs a new JoinPacket
func NewJoinPacket(appEUI lorawan.EUI64, devEUI lorawan.EUI64, devNonce [2]byte, metadata Metadata) JoinPacket {
	return &joinpacket{
		basehpacket: &basehpacket{
			appEUI:  appEUI,
			devEUI:  devEUI,
			payload: devNonce[:],
		},
		metadata: metadata,
	}
}

// DevNonce implements the core.JoinPacket interface
func (p joinpacket) DevNonce() [2]byte {
	return [2]byte{p.basehpacket.payload[0], p.basehpacket.payload[1]}
}

// Metadata implements the core.JoinPacket interface
func (p joinpacket) Metadata() Metadata {
	return p.metadata
}

// String implements the fmt.Stringer interface
func (p joinpacket) String() string {
	return "TODO"
}

type AcceptPacket interface {
	Packet
	AppEUI() lorawan.EUI64
	DevEUI() lorawan.EUI64
	Payload() []byte
	NwkSKey() lorawan.AES128Key
}

// acceptpacket implements the core.AcceptPacket interface
type acceptpacket struct {
	*basehpacket
	nwkSKey lorawan.AES128Key
}

// NewAcceptPacket constructs a new AcceptPacket
func NewAcceptPacket(appEUI lorawan.EUI64, devEUI lorawan.EUI64, payload []byte, nwkSKey lorawan.AES128Key) (AcceptPacket, error) {
	if len(payload) == 0 {
		return nil, errors.New(errors.Structural, "Payload cannot be empty")
	}

	return &acceptpacket{
		basehpacket: &basehpacket{
			appEUI:  appEUI,
			devEUI:  devEUI,
			payload: payload,
		},
		nwkSKey: nwkSKey,
	}, nil
}

// NwkSKey implements the core.AcceptPacket interface
func (p acceptpacket) NwkSKey() lorawan.AES128Key {
	return p.nwkSKey
}

// MarshalBinary implements the encoding.BinaryMarshaler interface
func (p acceptpacket) MarshalBinary() ([]byte, error) {
	data, err := p.basehpacket.MarshalBinary()
	if err != nil {
		return nil, errors.New(errors.Structural, err)
	}
	rw := readwriter.New(data)
	rw.Write(p.nwkSKey)
	return rw.Bytes()
}

// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (p *acceptpacket) UnmarshalBinary(data []byte) error {
	rw := readwriter.New(data)
	rw.Read(func(data []byte) { copy(p.basehpacket.appEUI[:], data) })
	rw.Read(func(data []byte) { copy(p.basehpacket.devEUI[:], data) })
	rw.Read(func(data []byte) { p.basehpacket.payload = data })
	rw.Read(func(data []byte) { copy(p.nwkSKey[:], data) })
	return rw.Err()
}

// String implements the fmt.Stringer interface
func (p acceptpacket) String() string {
	return "TODO"
}

// basehpacket is used to compose other packets
type basehpacket struct {
	appEUI  lorawan.EUI64
	devEUI  lorawan.EUI64
	payload []byte
}

func (p basehpacket) AppEUI() lorawan.EUI64 {
	return p.appEUI
}

func (p basehpacket) DevEUI() lorawan.EUI64 {
	return p.devEUI
}

func (p basehpacket) Payload() []byte {
	return p.payload
}

func (p basehpacket) MarshalBinary() ([]byte, error) {
	rw := readwriter.New(nil)
	rw.Write(p.appEUI)
	rw.Write(p.devEUI)
	rw.Write(p.payload)
	return rw.Bytes()
}
<|endoftext|>


<commit_before>// Copyright (C) 2015  The GoHBase Authors.  All rights reserved.
// This file is part of GoHBase.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package region_test

import (
	"testing"

	. "github.com/tsuna/gohbase/region"
)

func TestCompare(t *testing.T) {
	// Test cases from AsyncHBase
	testcases := []struct {
		a, b []byte // Region names, where a > b
	}{{
		// Different table names.
		[]byte("table,,1234567890"), []byte(".META.,,1234567890"),
	}, {
		// Different table names but same prefix.
		[]byte("tabl2,,1234567890"), []byte("tabl1,,1234567890"),
	}, {
		// Different table names (different lengths).
		[]byte("table,,1234567890"), []byte("tabl,,1234567890"),
	}, {
		// Any key is greater than the start key.
		[]byte("table,foo,1234567890"), []byte("table,,1234567890"),
	}, {
		// Different keys.
		[]byte("table,foo,1234567890"), []byte("table,bar,1234567890"),
	}, {
		// Shorter key is smaller than longer key.
		[]byte("table,fool,1234567890"), []byte("table,foo,1234567890"),
	}, {
		// Properly handle keys that contain commas.
		[]byte("table,a,,c,1234567890"), []byte("table,a,,b,1234567890"),
	}, {
		// If keys are equal, then start code should break the tie.
		[]byte("table,foo,1234567891"), []byte("table,foo,1234567890"),
	}, {
		// Make sure that a start code being a prefix of another is handled.
		[]byte("table,foo,1234567890"), []byte("table,foo,123456789"),
	}, {
		// If both are start keys, then start code should break the tie.
		[]byte("table,,1234567891"), []byte("table,,1234567890"),
	}, {
		// The value `:' is always greater than any start code.
		[]byte("table,foo,:"), []byte("table,foo,9999999999"),
	}, {
		// Issue 27: searching for key "8,\001" and region key is "8".
		[]byte("table,8,\001,:"), []byte("table,8,1339667458224"),
	}}

	for _, tcase := range testcases {
		if i := Compare(tcase.a, tcase.b); i <= 0 {
			t.Errorf("%q was found to be less than %q (%d)", tcase.a, tcase.b, i)
		}
		if i := Compare(tcase.b, tcase.a); i >= 0 {
			t.Errorf("%q was found to be greater than %q (%d)", tcase.b, tcase.a, i)
		}
	}

	meta := []byte("hbase:meta,,1")
	if i := Compare(meta, meta); i != 0 {
		t.Errorf("%q was found to not be equal to itself (%d)", meta, i)
	}
}

func TestCompareBogusName(t *testing.T) {
	defer func() {
		expected := `No comma found in "bogus" after offset 5`
		v := recover()
		if v == nil {
			t.Errorf("Should have panic'ed")
		} else if e, ok := v.(error); !ok {
			t.Errorf("panic'ed with a %T instead of an error (%#v)", v, v)
		} else if e.Error() != expected {
			t.Errorf("Expected panic(%q) but got %q", expected, e)
		}
	}()
	Compare([]byte("bogus"), []byte("bogus"))
}
<commit_msg>Add tests for parsing META entries from their protobufs.<commit_after>// Copyright (C) 2015  The GoHBase Authors.  All rights reserved.
// This file is part of GoHBase.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.

package region_test

import (
	"bytes"
	"strings"
	"testing"

	"github.com/golang/protobuf/proto"
	"github.com/tsuna/gohbase/pb"
	. "github.com/tsuna/gohbase/region"
)

// Test parsing the contents of a cell found in meta.
func TestInfoFromMeta(t *testing.T) {
	put := pb.CellType_PUT
	regionName := []byte("table,foo,1431921690563.53e41f94d5c3087af0d13259b8c4186d.")
	buf := []byte("PBUF\010\303\217\274\251\326)\022\020\n\007default" +
		"\022\005table\032\000\"\000(\0000\0008\000")
	cell := &pb.Cell{
		Row:       regionName,
		Family:    []byte("info"),
		Qualifier: []byte("regioninfo"),
		Timestamp: proto.Uint64(1431921690626),
		CellType:  &put,
	}
	info, err := InfoFromCell(cell)
	if err == nil || !strings.HasPrefix(err.Error(), "empty value") {
		t.Errorf("Unexpected error on empty value: %s", err)
	}
	cell.Value = buf
	info, err = InfoFromCell(cell)
	if err != nil {
		t.Fatalf("Failed to parse cell: %s", err)
	}
	if !bytes.Equal(info.RegionName, regionName) {
		t.Errorf("Unexpected regionName name: %q", info.RegionName)
	}
	if len(info.StopKey) != 0 {
		t.Errorf("Expected empty StopKey but got %q", info.StopKey)
	}

	expected := `*region.Info{Table: "table", RegionName: "table,foo,` +
		`1431921690563.53e41f94d5c3087af0d13259b8c4186d.", StopKey: ""}`
	if s := info.String(); s != expected {
		t.Errorf("Unexpected string representation.\nExpected: %q\n  Actual: %q", expected, s)
	}

	// Corrupt the protobuf.
	buf[4] = 0xFF
	_, err = InfoFromCell(cell)
	if err == nil || !strings.HasPrefix(err.Error(), "failed to decode") {
		t.Errorf("Unexpected error on corrupt protobuf: %s", err)
	}

	// Corrupt the magic number.
	buf[1] = 0xFF
	_, err = InfoFromCell(cell)
	if err == nil || !strings.HasPrefix(err.Error(), "invalid magic number") {
		t.Errorf("Unexpected error on invalid magic number %s", err)
	}

	// Corrupt the magic number (first byte).
	buf[0] = 0xFF
	_, err = InfoFromCell(cell)
	if err == nil || !strings.HasPrefix(err.Error(), "unsupported region info version") {
		t.Errorf("Unexpected error on invalid magic number %s", err)
	}
}

func TestCompare(t *testing.T) {
	// Test cases from AsyncHBase
	testcases := []struct {
		a, b []byte // Region names, where a > b
	}{{
		// Different table names.
		[]byte("table,,1234567890"), []byte(".META.,,1234567890"),
	}, {
		// Different table names but same prefix.
		[]byte("tabl2,,1234567890"), []byte("tabl1,,1234567890"),
	}, {
		// Different table names (different lengths).
		[]byte("table,,1234567890"), []byte("tabl,,1234567890"),
	}, {
		// Any key is greater than the start key.
		[]byte("table,foo,1234567890"), []byte("table,,1234567890"),
	}, {
		// Different keys.
		[]byte("table,foo,1234567890"), []byte("table,bar,1234567890"),
	}, {
		// Shorter key is smaller than longer key.
		[]byte("table,fool,1234567890"), []byte("table,foo,1234567890"),
	}, {
		// Properly handle keys that contain commas.
		[]byte("table,a,,c,1234567890"), []byte("table,a,,b,1234567890"),
	}, {
		// If keys are equal, then start code should break the tie.
		[]byte("table,foo,1234567891"), []byte("table,foo,1234567890"),
	}, {
		// Make sure that a start code being a prefix of another is handled.
		[]byte("table,foo,1234567890"), []byte("table,foo,123456789"),
	}, {
		// If both are start keys, then start code should break the tie.
		[]byte("table,,1234567891"), []byte("table,,1234567890"),
	}, {
		// The value `:' is always greater than any start code.
		[]byte("table,foo,:"), []byte("table,foo,9999999999"),
	}, {
		// Issue 27: searching for key "8,\001" and region key is "8".
		[]byte("table,8,\001,:"), []byte("table,8,1339667458224"),
	}}

	for _, tcase := range testcases {
		if i := Compare(tcase.a, tcase.b); i <= 0 {
			t.Errorf("%q was found to be less than %q (%d)", tcase.a, tcase.b, i)
		}
		if i := Compare(tcase.b, tcase.a); i >= 0 {
			t.Errorf("%q was found to be greater than %q (%d)", tcase.b, tcase.a, i)
		}
	}

	meta := []byte("hbase:meta,,1")
	if i := CompareGeneric(meta, meta); i != 0 {
		t.Errorf("%q was found to not be equal to itself (%d)", meta, i)
	}
}

func TestCompareBogusName(t *testing.T) {
	defer func() {
		expected := `No comma found in "bogus" after offset 5`
		v := recover()
		if v == nil {
			t.Errorf("Should have panic'ed")
		} else if e, ok := v.(error); !ok {
			t.Errorf("panic'ed with a %T instead of an error (%#v)", v, v)
		} else if e.Error() != expected {
			t.Errorf("Expected panic(%q) but got %q", expected, e)
		}
	}()
	Compare([]byte("bogus"), []byte("bogus"))
}
<|endoftext|>