<commit_before>/*
Copyright 2019 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 actions

import (
	"fmt"
	"time"

	"k8s.io/kubeadm/kinder/pkg/cluster/status"
	"k8s.io/kubeadm/kinder/pkg/constants"
)

// KubeadmJoin executes the kubeadm join workflow both for control-plane nodes and
// worker nodes
func KubeadmJoin(c *status.Cluster, usePhases bool, copyCertsMode CopyCertsMode, discoveryMode DiscoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors string, wait time.Duration, vLevel int) (err error) {
	if err := joinControlPlanes(c, usePhases, copyCertsMode, discoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors, wait, vLevel); err != nil {
		return err
	}

	if err := joinWorkers(c, usePhases, discoveryMode, wait, kubeadmConfigVersion, ignorePreflightErrors, vLevel); err != nil {
		return err
	}
	return nil
}

func joinControlPlanes(c *status.Cluster, usePhases bool, copyCertsMode CopyCertsMode, discoveryMode DiscoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors string, wait time.Duration, vLevel int) (err error) {
	cpX := []*status.Node{c.BootstrapControlPlane()}

	for _, cp2 := range c.SecondaryControlPlanes().EligibleForActions() {
		if err := copyPatchesToNode(cp2, patchesDir); err != nil {
			return err
		}

		// if not automatic copy certs, simulate manual copy
		if copyCertsMode == CopyCertsModeManual {
			if err := copyCertificatesToNode(c, cp2); err != nil {
				return err
			}
		}

		// checks pre-loaded images available on the node (this will report missing images, if any)
		kubeVersion, err := cp2.KubeVersion()
		if err != nil {
			return err
		}

		if err := checkImagesForVersion(cp2, kubeVersion); err != nil {
			return err
		}

		// prepares the kubeadm config on this node
		if err := KubeadmJoinConfig(c, kubeadmConfigVersion, copyCertsMode, discoveryMode, cp2); err != nil {
			return err
		}

		// executes the kubeadm join control-plane workflow
		if usePhases {
			err = kubeadmJoinControlPlaneWithPhases(cp2, patchesDir, ignorePreflightErrors, vLevel)
		} else {
			err = kubeadmJoinControlPlane(cp2, patchesDir, ignorePreflightErrors, vLevel)
		}
		if err != nil {
			return err
		}

		// updates the loadbalancer config with the new cp node
		cpX = append(cpX, cp2)
		if err := LoadBalancer(c, cpX...); err != nil {
			return err
		}

		if err := waitNewControlPlaneNodeReady(c, cp2, wait); err != nil {
			return err
		}
	}
	return nil
}

func kubeadmJoinControlPlane(cp *status.Node, patchesDir, ignorePreflightErrors string, vLevel int) (err error) {
	joinArgs := []string{
		"join",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	}
	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			joinArgs = append(joinArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", joinArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func kubeadmJoinControlPlaneWithPhases(cp *status.Node, patchesDir, ignorePreflightErrors string, vLevel int) (err error) {
	// kubeadm join phase preflight
	preflightArgs := []string{
		"join", "phase", "preflight",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	}

	if err := cp.Command(
		"kubeadm", preflightArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase control-plane-prepare
	prepareArgs := []string{
		"join", "phase", "control-plane-prepare", "all",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	}

	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			prepareArgs = append(prepareArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", prepareArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase kubelet-start
	if err := cp.Command(
		"kubeadm", "join", "phase", "kubelet-start",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase control-plane-join
	controlPlaneArgs := []string{
		"join", "phase", "control-plane-join", "all",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	}
	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			controlPlaneArgs = append(controlPlaneArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", controlPlaneArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func joinWorkers(c *status.Cluster, usePhases bool, discoveryMode DiscoveryMode, wait time.Duration, kubeadmConfigVersion, ignorePreflightErrors string, vLevel int) (err error) {
	for _, w := range c.Workers().EligibleForActions() {
		// checks pre-loaded images available on the node (this will report missing images, if any)
		kubeVersion, err := w.KubeVersion()
		if err != nil {
			return err
		}

		if err := checkImagesForVersion(w, kubeVersion); err != nil {
			return err
		}

		// prepares the kubeadm config on this node
		if err := KubeadmJoinConfig(c, kubeadmConfigVersion, CopyCertsModeNone, discoveryMode, w); err != nil {
			return err
		}

		// executes the kubeadm join workflow
		if usePhases {
			err = kubeadmJoinWorkerWithPhases(w, ignorePreflightErrors, vLevel)
		} else {
			err = kubeadmJoinWorker(w, ignorePreflightErrors, vLevel)
		}
		if err != nil {
			return err
		}

		if err := waitNewWorkerNodeReady(c, w, wait); err != nil {
			return err
		}
	}
	return nil
}

func kubeadmJoinWorker(w *status.Node, ignorePreflightErrors string, vLevel int) (err error) {
	if err := w.Command(
		"kubeadm", "join",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func kubeadmJoinWorkerWithPhases(w *status.Node, ignorePreflightErrors string, vLevel int) (err error) {
	// kubeadm join phase preflight
	if err := w.Command(
		"kubeadm", "join", "phase", "preflight",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// NB. kubeadm join phase control-plane-prepare should not be executed when joining a worker node

	// kubeadm join phase kubelet-start
	if err := w.Command(
		"kubeadm", "join", "phase", "kubelet-start",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// NB. kubeadm join phase control-plane-join should not be executed when joining a worker node

	return nil
}
<commit_msg>kinder: make sure worker nodes also get a patches dir created<commit_after>/*
Copyright 2019 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 actions

import (
	"fmt"
	"time"

	"k8s.io/kubeadm/kinder/pkg/cluster/status"
	"k8s.io/kubeadm/kinder/pkg/constants"
)

// KubeadmJoin executes the kubeadm join workflow both for control-plane nodes and
// worker nodes
func KubeadmJoin(c *status.Cluster, usePhases bool, copyCertsMode CopyCertsMode, discoveryMode DiscoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors string, wait time.Duration, vLevel int) (err error) {
	if err := joinControlPlanes(c, usePhases, copyCertsMode, discoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors, wait, vLevel); err != nil {
		return err
	}

	if err := joinWorkers(c, usePhases, discoveryMode, wait, kubeadmConfigVersion, patchesDir, ignorePreflightErrors, vLevel); err != nil {
		return err
	}
	return nil
}

func joinControlPlanes(c *status.Cluster, usePhases bool, copyCertsMode CopyCertsMode, discoveryMode DiscoveryMode, kubeadmConfigVersion, patchesDir, ignorePreflightErrors string, wait time.Duration, vLevel int) (err error) {
	cpX := []*status.Node{c.BootstrapControlPlane()}

	for _, cp2 := range c.SecondaryControlPlanes().EligibleForActions() {
		if err := copyPatchesToNode(cp2, patchesDir); err != nil {
			return err
		}

		// if not automatic copy certs, simulate manual copy
		if copyCertsMode == CopyCertsModeManual {
			if err := copyCertificatesToNode(c, cp2); err != nil {
				return err
			}
		}

		// checks pre-loaded images available on the node (this will report missing images, if any)
		kubeVersion, err := cp2.KubeVersion()
		if err != nil {
			return err
		}

		if err := checkImagesForVersion(cp2, kubeVersion); err != nil {
			return err
		}

		// prepares the kubeadm config on this node
		if err := KubeadmJoinConfig(c, kubeadmConfigVersion, copyCertsMode, discoveryMode, cp2); err != nil {
			return err
		}

		// executes the kubeadm join control-plane workflow
		if usePhases {
			err = kubeadmJoinControlPlaneWithPhases(cp2, patchesDir, ignorePreflightErrors, vLevel)
		} else {
			err = kubeadmJoinControlPlane(cp2, patchesDir, ignorePreflightErrors, vLevel)
		}
		if err != nil {
			return err
		}

		// updates the loadbalancer config with the new cp node
		cpX = append(cpX, cp2)
		if err := LoadBalancer(c, cpX...); err != nil {
			return err
		}

		if err := waitNewControlPlaneNodeReady(c, cp2, wait); err != nil {
			return err
		}
	}
	return nil
}

func kubeadmJoinControlPlane(cp *status.Node, patchesDir, ignorePreflightErrors string, vLevel int) (err error) {
	joinArgs := []string{
		"join",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	}
	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			joinArgs = append(joinArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", joinArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func kubeadmJoinControlPlaneWithPhases(cp *status.Node, patchesDir, ignorePreflightErrors string, vLevel int) (err error) {
	// kubeadm join phase preflight
	preflightArgs := []string{
		"join", "phase", "preflight",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	}

	if err := cp.Command(
		"kubeadm", preflightArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase control-plane-prepare
	prepareArgs := []string{
		"join", "phase", "control-plane-prepare", "all",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	}

	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			prepareArgs = append(prepareArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", prepareArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase kubelet-start
	if err := cp.Command(
		"kubeadm", "join", "phase", "kubelet-start",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// kubeadm join phase control-plane-join
	controlPlaneArgs := []string{
		"join", "phase", "control-plane-join", "all",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	}
	if patchesDir != "" {
		if cp.MustKubeadmVersion().LessThan(constants.V1_22) {
			controlPlaneArgs = append(controlPlaneArgs, "--experimental-patches", constants.PatchesDir)
		}
	}

	if err := cp.Command(
		"kubeadm", controlPlaneArgs...,
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func joinWorkers(c *status.Cluster, usePhases bool, discoveryMode DiscoveryMode, wait time.Duration, kubeadmConfigVersion, patchesDir, ignorePreflightErrors string, vLevel int) (err error) {
	for _, w := range c.Workers().EligibleForActions() {
		// checks pre-loaded images available on the node (this will report missing images, if any)
		kubeVersion, err := w.KubeVersion()
		if err != nil {
			return err
		}

		if err := copyPatchesToNode(w, patchesDir); err != nil {
			return err
		}

		if err := checkImagesForVersion(w, kubeVersion); err != nil {
			return err
		}

		// prepares the kubeadm config on this node
		if err := KubeadmJoinConfig(c, kubeadmConfigVersion, CopyCertsModeNone, discoveryMode, w); err != nil {
			return err
		}

		// executes the kubeadm join workflow
		if usePhases {
			err = kubeadmJoinWorkerWithPhases(w, ignorePreflightErrors, vLevel)
		} else {
			err = kubeadmJoinWorker(w, ignorePreflightErrors, vLevel)
		}
		if err != nil {
			return err
		}

		if err := waitNewWorkerNodeReady(c, w, wait); err != nil {
			return err
		}
	}
	return nil
}

func kubeadmJoinWorker(w *status.Node, ignorePreflightErrors string, vLevel int) (err error) {
	if err := w.Command(
		"kubeadm", "join",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	return nil
}

func kubeadmJoinWorkerWithPhases(w *status.Node, ignorePreflightErrors string, vLevel int) (err error) {
	// kubeadm join phase preflight
	if err := w.Command(
		"kubeadm", "join", "phase", "preflight",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--ignore-preflight-errors=%s", ignorePreflightErrors),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// NB. kubeadm join phase control-plane-prepare should not be executed when joining a worker node

	// kubeadm join phase kubelet-start
	if err := w.Command(
		"kubeadm", "join", "phase", "kubelet-start",
		fmt.Sprintf("--config=%s", constants.KubeadmConfigPath),
		fmt.Sprintf("--v=%d", vLevel),
	).RunWithEcho(); err != nil {
		return err
	}

	// NB. kubeadm join phase control-plane-join should not be executed when joining a worker node

	return nil
}
<|endoftext|>


<commit_before>package secret

import (
	"io/ioutil"
	"sort"

	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

const (
	// DefaultKMSKey represents default KMS key alias
	DefaultKMSKey = "valec"
)

// Secret represents key=value pair
type Secret struct {
	Key   string `yaml:"key"`
	Value string `yaml:"value"`
}

// Secrets represents the array of Secret
type Secrets []*Secret

// YAML represents secret yaml structure
type YAML struct {
	KMSKey  string  `yaml:"kms_key"`
	Secrets Secrets `yaml:"secrets"`
}

// Len returns the length of the array
func (ss Secrets) Len() int {
	return len(ss)
}

// Less returns Secrets[i] is less than Secrets[j]
func (ss Secrets) Less(i, j int) bool {
	si, sj := ss[i], ss[j]

	if si.Key < sj.Key {
		return true
	}

	if si.Key > sj.Key {
		return false
	}

	if si.Value < sj.Value {
		return true
	}

	if si.Value > sj.Value {
		return false
	}

	return false
}

// Swap swaps Secrets[i] and Secrets[j]
func (ss Secrets) Swap(i, j int) {
	ss[i], ss[j] = ss[j], ss[i]
}

// CompareList compares two secret lists and returns the differences between them
func (ss Secrets) CompareList(old Secrets) (added, updated, deleted Secrets) {
	newMap, oldMap := ss.ListToMap(), old.ListToMap()

	for _, c := range ss {
		v, ok := oldMap[c.Key]
		if !ok {
			added = append(added, c)
		} else if v != c.Value {
			updated = append(updated, c)
		}
	}

	for _, c := range old {
		_, ok := newMap[c.Key]
		if !ok {
			deleted = append(deleted, c)
		}
	}

	return added, updated, deleted
}

// ListToMap converts secret list to map
func (ss Secrets) ListToMap() map[string]string {
	secretMap := map[string]string{}

	for _, secret := range ss {
		secretMap[secret.Key] = secret.Value
	}

	return secretMap
}

// SaveAsYAML saves secrets to local secret file
func (ss Secrets) SaveAsYAML(filename, kmsKey string) error {
	y := &YAML{
		KMSKey:  kmsKey,
		Secrets: ss,
	}

	body, err := yaml.Marshal(y)
	if err != nil {
		return errors.Wrap(err, "Failed to convert secrets as YAML.")
	}

	if err := ioutil.WriteFile(filename, body, 0644); err != nil {
		return errors.Wrapf(err, "Failed to save file. filename=%s", filename)
	}

	return nil
}

// LoadFromYAML loads secrets from the given YAML file
func LoadFromYAML(filename string) (string, Secrets, error) {
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", Secrets{}, errors.Wrapf(err, "Failed to read secret file. filename=%s", filename)
	}

	var y YAML

	if err := yaml.Unmarshal(body, &y); err != nil {
		return "", Secrets{}, errors.Wrapf(err, "Failed to parse secret file as YAML. filename=%s", filename)
	}

	return y.KMSKey, y.Secrets, nil
}

// MapToList converts map to secret list
func MapToList(secretMap map[string]string) Secrets {
	secrets := Secrets{}

	for key, value := range secretMap {
		secrets = append(secrets, &Secret{
			Key:   key,
			Value: value,
		})
	}

	sort.Sort(secrets)

	return secrets
}
<commit_msg>Create secret directory if it does not exist<commit_after>package secret

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"

	"github.com/dtan4/valec/util"
	"github.com/pkg/errors"
	"gopkg.in/yaml.v2"
)

const (
	// DefaultKMSKey represents default KMS key alias
	DefaultKMSKey = "valec"
)

// Secret represents key=value pair
type Secret struct {
	Key   string `yaml:"key"`
	Value string `yaml:"value"`
}

// Secrets represents the array of Secret
type Secrets []*Secret

// YAML represents secret yaml structure
type YAML struct {
	KMSKey  string  `yaml:"kms_key"`
	Secrets Secrets `yaml:"secrets"`
}

// Len returns the length of the array
func (ss Secrets) Len() int {
	return len(ss)
}

// Less returns Secrets[i] is less than Secrets[j]
func (ss Secrets) Less(i, j int) bool {
	si, sj := ss[i], ss[j]

	if si.Key < sj.Key {
		return true
	}

	if si.Key > sj.Key {
		return false
	}

	if si.Value < sj.Value {
		return true
	}

	if si.Value > sj.Value {
		return false
	}

	return false
}

// Swap swaps Secrets[i] and Secrets[j]
func (ss Secrets) Swap(i, j int) {
	ss[i], ss[j] = ss[j], ss[i]
}

// CompareList compares two secret lists and returns the differences between them
func (ss Secrets) CompareList(old Secrets) (added, updated, deleted Secrets) {
	newMap, oldMap := ss.ListToMap(), old.ListToMap()

	for _, c := range ss {
		v, ok := oldMap[c.Key]
		if !ok {
			added = append(added, c)
		} else if v != c.Value {
			updated = append(updated, c)
		}
	}

	for _, c := range old {
		_, ok := newMap[c.Key]
		if !ok {
			deleted = append(deleted, c)
		}
	}

	return added, updated, deleted
}

// ListToMap converts secret list to map
func (ss Secrets) ListToMap() map[string]string {
	secretMap := map[string]string{}

	for _, secret := range ss {
		secretMap[secret.Key] = secret.Value
	}

	return secretMap
}

// SaveAsYAML saves secrets to local secret file
func (ss Secrets) SaveAsYAML(filename, kmsKey string) error {
	y := &YAML{
		KMSKey:  kmsKey,
		Secrets: ss,
	}

	body, err := yaml.Marshal(y)
	if err != nil {
		return errors.Wrap(err, "Failed to convert secrets as YAML.")
	}

	dir := filepath.Dir(filename)
	if !util.IsExist(dir) {
		if err := os.MkdirAll(dir, 0755); err != nil {
			return errors.Wrapf(err, "failed to create directory %q", dir)
		}
	}

	if err := ioutil.WriteFile(filename, body, 0644); err != nil {
		return errors.Wrapf(err, "Failed to save file. filename=%s", filename)
	}

	return nil
}

// LoadFromYAML loads secrets from the given YAML file
func LoadFromYAML(filename string) (string, Secrets, error) {
	body, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", Secrets{}, errors.Wrapf(err, "Failed to read secret file. filename=%s", filename)
	}

	var y YAML

	if err := yaml.Unmarshal(body, &y); err != nil {
		return "", Secrets{}, errors.Wrapf(err, "Failed to parse secret file as YAML. filename=%s", filename)
	}

	return y.KMSKey, y.Secrets, nil
}

// MapToList converts map to secret list
func MapToList(secretMap map[string]string) Secrets {
	secrets := Secrets{}

	for key, value := range secretMap {
		secrets = append(secrets, &Secret{
			Key:   key,
			Value: value,
		})
	}

	sort.Sort(secrets)

	return secrets
}
<|endoftext|>


<commit_before>/*

	golden is a package designed to make it possible to compare a game to a
	golden run for testing purposes. It takes a record saved in
	storage/filesystem format and compares it.

*/
package golden

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/storage/filesystem/record"
	"github.com/jkomoros/boardgame/storage/memory"
	"github.com/yudai/gojsondiff"
	"github.com/yudai/gojsondiff/formatter"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strconv"
)

//Compare is the primary method in the package. It takes a game delegate and a
//filename denoting a record to compare against. delegate shiould be a fresh
//delegate not yet affiliated with a manager.
func Compare(delegate boardgame.GameDelegate, recFilename string) error {

	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	rec, err := record.New(recFilename)

	if err != nil {
		return errors.New("Couldn't create record: " + err.Error())
	}

	return compare(manager, rec)

}

//CompareFolder is like Compare, except it will iterate through any file in
//recFolder that ends in .json. Errors if any of those files cannot be parsed
//into recs, or if no files match.
func CompareFolder(delegate boardgame.GameDelegate, recFolder string) error {
	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	infos, err := ioutil.ReadDir(recFolder)

	if err != nil {
		return errors.New("Couldn't read folder: " + err.Error())
	}

	processedRecs := 0

	for _, info := range infos {
		if info.IsDir() {
			continue
		}

		if filepath.Ext(info.Name()) != ".json" {
			continue
		}

		rec, err := record.New(filepath.Join(recFolder, info.Name()))

		if err != nil {
			return errors.New("File with name " + info.Name() + " couldn't be loaded into rec: " + err.Error())
		}

		if err := compare(manager, rec); err != nil {
			return errors.New("File named " + info.Name() + " had compare error: " + err.Error())
		}

		processedRecs++
	}

	if processedRecs < 1 {
		return errors.New("Processed 0 recs in folder")
	}

	return nil
}

func compare(manager *boardgame.GameManager, rec *record.Record) error {
	game, err := manager.RecreateGame(rec.Game())

	if err != nil {
		return errors.New("Couldn't create game: " + err.Error())
	}

	lastVerifiedVersion := 0

	for !game.Finished() {
		//Verify all new moves that have happened since the last time we
		//checked (often, fix-up moves).
		for lastVerifiedVersion < game.Version() {
			stateToCompare, err := rec.State(lastVerifiedVersion)

			if err != nil {
				return errors.New("Couldn't get " + strconv.Itoa(lastVerifiedVersion) + " state: " + err.Error())
			}

			//TODO: use go-test/deep (if vendored) for a more descriptive error.
			if err := compareStorageRecords(game.State(lastVerifiedVersion).StorageRecord(), stateToCompare); err != nil {
				return errors.New("State " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
			}

			//TODO: compare the move storage records too.

			lastVerifiedVersion++
		}

		nextMoveRec, err := rec.Move(lastVerifiedVersion + 1)

		if err != nil {
			//We'll assume that menas that's all of the moves there are to make.
			break
		}

		if nextMoveRec.Proposer < 0 {
			return errors.New("At version " + strconv.Itoa(lastVerifiedVersion) + " the next player move to apply was not applied by a player")
		}

		nextMove, err := nextMoveRec.Inflate(game)

		if err != nil {
			return errors.New("Couldn't inflate move: " + err.Error())
		}

		if err := <-game.ProposeMove(nextMove, nextMoveRec.Proposer); err != nil {
			return errors.New("Couldn't propose next move in chain: " + err.Error())
		}

	}

	if game.Finished() != rec.Game().Finished {
		return errors.New("Game finished did not match rec")
	}

	if !reflect.DeepEqual(game.Winners(), rec.Game().Winners) {
		return errors.New("Game winners did not match")
	}

	return nil
}

var differ = gojsondiff.New()

var diffformatter = formatter.NewDeltaFormatter()

func compareStorageRecords(one, two boardgame.StateStorageRecord) error {

	diff, err := differ.Compare(one, two)

	if err != nil {
		return errors.New("Couldn't diff: " + err.Error())
	}

	if diff.Modified() {

		str, err := diffformatter.Format(diff)

		if err != nil {
			return errors.New("Couldn't format diff: " + err.Error())
		}

		return errors.New("Diff: " + str)
	}

	return nil

}
<commit_msg>Remove a completed TODO. Part of #648.<commit_after>/*

	golden is a package designed to make it possible to compare a game to a
	golden run for testing purposes. It takes a record saved in
	storage/filesystem format and compares it.

*/
package golden

import (
	"errors"
	"github.com/jkomoros/boardgame"
	"github.com/jkomoros/boardgame/storage/filesystem/record"
	"github.com/jkomoros/boardgame/storage/memory"
	"github.com/yudai/gojsondiff"
	"github.com/yudai/gojsondiff/formatter"
	"io/ioutil"
	"path/filepath"
	"reflect"
	"strconv"
)

//Compare is the primary method in the package. It takes a game delegate and a
//filename denoting a record to compare against. delegate shiould be a fresh
//delegate not yet affiliated with a manager.
func Compare(delegate boardgame.GameDelegate, recFilename string) error {

	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	rec, err := record.New(recFilename)

	if err != nil {
		return errors.New("Couldn't create record: " + err.Error())
	}

	return compare(manager, rec)

}

//CompareFolder is like Compare, except it will iterate through any file in
//recFolder that ends in .json. Errors if any of those files cannot be parsed
//into recs, or if no files match.
func CompareFolder(delegate boardgame.GameDelegate, recFolder string) error {
	manager, err := boardgame.NewGameManager(delegate, memory.NewStorageManager())

	if err != nil {
		return errors.New("Couldn't create new manager: " + err.Error())
	}

	infos, err := ioutil.ReadDir(recFolder)

	if err != nil {
		return errors.New("Couldn't read folder: " + err.Error())
	}

	processedRecs := 0

	for _, info := range infos {
		if info.IsDir() {
			continue
		}

		if filepath.Ext(info.Name()) != ".json" {
			continue
		}

		rec, err := record.New(filepath.Join(recFolder, info.Name()))

		if err != nil {
			return errors.New("File with name " + info.Name() + " couldn't be loaded into rec: " + err.Error())
		}

		if err := compare(manager, rec); err != nil {
			return errors.New("File named " + info.Name() + " had compare error: " + err.Error())
		}

		processedRecs++
	}

	if processedRecs < 1 {
		return errors.New("Processed 0 recs in folder")
	}

	return nil
}

func compare(manager *boardgame.GameManager, rec *record.Record) error {
	game, err := manager.RecreateGame(rec.Game())

	if err != nil {
		return errors.New("Couldn't create game: " + err.Error())
	}

	lastVerifiedVersion := 0

	for !game.Finished() {
		//Verify all new moves that have happened since the last time we
		//checked (often, fix-up moves).
		for lastVerifiedVersion < game.Version() {
			stateToCompare, err := rec.State(lastVerifiedVersion)

			if err != nil {
				return errors.New("Couldn't get " + strconv.Itoa(lastVerifiedVersion) + " state: " + err.Error())
			}

			if err := compareStorageRecords(game.State(lastVerifiedVersion).StorageRecord(), stateToCompare); err != nil {
				return errors.New("State " + strconv.Itoa(lastVerifiedVersion) + " compared differently: " + err.Error())
			}

			//TODO: compare the move storage records too.

			lastVerifiedVersion++
		}

		nextMoveRec, err := rec.Move(lastVerifiedVersion + 1)

		if err != nil {
			//We'll assume that menas that's all of the moves there are to make.
			break
		}

		if nextMoveRec.Proposer < 0 {
			return errors.New("At version " + strconv.Itoa(lastVerifiedVersion) + " the next player move to apply was not applied by a player")
		}

		nextMove, err := nextMoveRec.Inflate(game)

		if err != nil {
			return errors.New("Couldn't inflate move: " + err.Error())
		}

		if err := <-game.ProposeMove(nextMove, nextMoveRec.Proposer); err != nil {
			return errors.New("Couldn't propose next move in chain: " + err.Error())
		}

	}

	if game.Finished() != rec.Game().Finished {
		return errors.New("Game finished did not match rec")
	}

	if !reflect.DeepEqual(game.Winners(), rec.Game().Winners) {
		return errors.New("Game winners did not match")
	}

	return nil
}

var differ = gojsondiff.New()

var diffformatter = formatter.NewDeltaFormatter()

func compareStorageRecords(one, two boardgame.StateStorageRecord) error {

	diff, err := differ.Compare(one, two)

	if err != nil {
		return errors.New("Couldn't diff: " + err.Error())
	}

	if diff.Modified() {

		str, err := diffformatter.Format(diff)

		if err != nil {
			return errors.New("Couldn't format diff: " + err.Error())
		}

		return errors.New("Diff: " + str)
	}

	return nil

}
<|endoftext|>


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

package seq

import (
	"github.com/dmiller/go-seq/iseq"
	"testing"
)

func TestConsCtors(t *testing.T) {
	c := NewCons("abc", nil)

	if c.Meta() != nil {
		t.Error("NewCons ctor should have nil meta")
	}

	if c.First() != "abc" {
		t.Error("NewCons ctor did not initialize first")
	}

	c1 := NewCons("def", c)
	if c1.First() != "def" {
		t.Error("NewCons ctor did not initialize first")
	}

	if c1.Next() != c {
		t.Error("NewCons ctor did nto initialize more/next")
	}

	// TODO: add tests for c-tor with meta -- we need a PMap implementation first
}

func TestConsImplementInterfaces(t *testing.T) {
	var c interface{} = NewCons("abc", nil)

	if _, ok := c.(iseq.MetaW); !ok {
		t.Error("Cons must implement MetaW")
	}

	if _, ok := c.(iseq.Meta); !ok {
		t.Error("Cons must implement Meta")
	}

	if _, ok := c.(iseq.PCollection); !ok {
		t.Error("Cons must implement PCollection")
	}

	if _, ok := c.(iseq.Seqable); !ok {
		t.Error("Cons must implement Seqable")
	}

	if _, ok := c.(iseq.Equivable); !ok {
		t.Error("Cons must implement Equatable")
	}

	if _, ok := c.(iseq.Hashable); !ok {
		t.Error("Cons must implement Hashable")
	}
}

func createComplicatedCons() *Cons {
	c1 := NewCons(1, nil)
	c2 := NewCons(2, c1)
	c3 := NewCons("abc", nil)
	c4 := NewCons(c3, c2)
	c5 := NewCons("def", c4)
	return c5
}

func TestConsCount(t *testing.T) {
	c := createComplicatedCons()
	if c.Count() != 4 {
		t.Errorf("Count: expected 4, got %v", c.Count())
	}
}

func TestConsSeq(t *testing.T) {
	c1 := NewCons("abc", nil)
	c2 := createComplicatedCons()
	if c1.Seq() != c1 {
		t.Error("Seq should return self")
	}
	if c2.Seq() != c2 {
		t.Error("Seq should return self")
	}
}

func TestConsEmpty(t *testing.T) {
	c := NewCons("abc", nil)
	e := c.Empty()
	if e != CachedEmptyList {
		t.Error("Empty should be  CachedEmptyList")
	}
}

func TestConsEquiv(t *testing.T) {
	c1 := createComplicatedCons()
	c2 := createComplicatedCons()
	if c1 == c2 {
		t.Error("Expect two calls to createComplicatedCons to return distinct structs")
	}
	if !c1.Equiv(c1) {
		t.Error("Expect cons to be equiv to itself")
	}
	if !c1.Equiv(c2) {
		t.Error("Expect cons to equiv similar cons")
	}

	c3 := NewCons("abc", nil)
	if c1.Equiv(c3) {
		t.Error("cons equiv dissimilar cons")
	}
}
<commit_msg>Add test for Cons zero-value<commit_after>// Copyright 2012 David Miller. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package seq

import (
	"github.com/dmiller/go-seq/iseq"
	"testing"
)

func TestConsCtors(t *testing.T) {
	c := NewCons("abc", nil)

	if c.Meta() != nil {
		t.Error("NewCons ctor should have nil meta")
	}

	if c.First() != "abc" {
		t.Error("NewCons ctor did not initialize first")
	}

	c1 := NewCons("def", c)
	if c1.First() != "def" {
		t.Error("NewCons ctor did not initialize first")
	}

	if c1.Next() != c {
		t.Error("NewCons ctor did nto initialize more/next")
	}

	// TODO: add tests for c-tor with meta -- we need a PMap implementation first
}

func TestConsImplementInterfaces(t *testing.T) {
	var c interface{} = NewCons("abc", nil)

	if _, ok := c.(iseq.MetaW); !ok {
		t.Error("Cons must implement MetaW")
	}

	if _, ok := c.(iseq.Meta); !ok {
		t.Error("Cons must implement Meta")
	}

	if _, ok := c.(iseq.PCollection); !ok {
		t.Error("Cons must implement PCollection")
	}

	if _, ok := c.(iseq.Seqable); !ok {
		t.Error("Cons must implement Seqable")
	}

	if _, ok := c.(iseq.Equivable); !ok {
		t.Error("Cons must implement Equatable")
	}

	if _, ok := c.(iseq.Hashable); !ok {
		t.Error("Cons must implement Hashable")
	}
}

func createComplicatedCons() *Cons {
	c1 := NewCons(1, nil)
	c2 := NewCons(2, c1)
	c3 := NewCons("abc", nil)
	c4 := NewCons(c3, c2)
	c5 := NewCons("def", c4)
	return c5
}

func TestConsCount(t *testing.T) {
	c := createComplicatedCons()
	if c.Count() != 4 {
		t.Errorf("Count: expected 4, got %v", c.Count())
	}
}

func TestConsSeq(t *testing.T) {
	c1 := NewCons("abc", nil)
	c2 := createComplicatedCons()
	if c1.Seq() != c1 {
		t.Error("Seq should return self")
	}
	if c2.Seq() != c2 {
		t.Error("Seq should return self")
	}
}

func TestConsEmpty(t *testing.T) {
	c := NewCons("abc", nil)
	e := c.Empty()
	if e != CachedEmptyList {
		t.Error("Empty should be  CachedEmptyList")
	}
}

func TestConsEquiv(t *testing.T) {
	c1 := createComplicatedCons()
	c2 := createComplicatedCons()
	if c1 == c2 {
		t.Error("Expect two calls to createComplicatedCons to return distinct structs")
	}
	if !c1.Equiv(c1) {
		t.Error("Expect cons to be equiv to itself")
	}
	if !c1.Equiv(c2) {
		t.Error("Expect cons to equiv similar cons")
	}

	c3 := NewCons("abc", nil)
	if c1.Equiv(c3) {
		t.Error("cons equiv dissimilar cons")
	}
}

func TestConsZeroValue(t *testing.T) {
	c1 := new(Cons)
	c2 := NewCons(nil, nil)
	if !c1.Equiv(c2) {
		t.Error("Expect zero-value Cons to be equiv to (nil)")
	}
}
<|endoftext|>


<commit_before>package radius

import (
	"context"
	"errors"
	"net"
	"sync"
	"sync/atomic"
)

type packetResponseWriter struct {
	// listener that received the packet
	conn net.PacketConn
	addr net.Addr
}

func (r *packetResponseWriter) Write(packet *Packet) error {
	encoded, err := packet.Encode()
	if err != nil {
		return err
	}
	if _, err := r.conn.WriteTo(encoded, r.addr); err != nil {
		return err
	}
	return nil
}

// PacketServer listens for RADIUS requests on a packet-based protocols (e.g.
// UDP).
type PacketServer struct {
	// The address on which the server listens. Defaults to :1812.
	Addr string

	// The network on which the server listens. Defaults to udp.
	Network string

	// The source from which the secret is obtained for parsing and validating
	// the request.
	SecretSource SecretSource

	// Handler which is called to process the request.
	Handler Handler

	// Skip incoming packet authenticity validation.
	// This should only be set to true for debugging purposes.
	InsecureSkipVerify bool

	shutdownRequested int32

	mu          sync.Mutex
	ctx         context.Context
	ctxDone     context.CancelFunc
	listeners   map[net.PacketConn]uint
	lastActive  chan struct{} // closed when the last active item finishes
	activeCount int32
}

func (s *PacketServer) initLocked() {
	if s.ctx == nil {
		s.ctx, s.ctxDone = context.WithCancel(context.Background())
		s.listeners = make(map[net.PacketConn]uint)
		s.lastActive = make(chan struct{})
	}
}

func (s *PacketServer) activeAdd() {
	atomic.AddInt32(&s.activeCount, 1)
}

func (s *PacketServer) activeDone() {
	if atomic.AddInt32(&s.activeCount, -1) == -1 {
		close(s.lastActive)
	}
}

// TODO: logger on PacketServer

// Serve accepts incoming connections on conn.
func (s *PacketServer) Serve(conn net.PacketConn) error {
	if s.Handler == nil {
		return errors.New("radius: nil Handler")
	}
	if s.SecretSource == nil {
		return errors.New("radius: nil SecretSource")
	}

	s.mu.Lock()
	s.initLocked()
	if atomic.LoadInt32(&s.shutdownRequested) == 1 {
		s.mu.Unlock()
		return ErrServerShutdown
	}

	s.listeners[conn]++
	s.mu.Unlock()

	type requestKey struct {
		IP         string
		Identifier byte
	}

	var (
		requestsLock sync.Mutex
		requests     = map[requestKey]struct{}{}
	)

	s.activeAdd()
	defer func() {
		s.mu.Lock()
		s.listeners[conn]--
		if s.listeners[conn] == 0 {
			delete(s.listeners, conn)
		}
		s.mu.Unlock()
		s.activeDone()
	}()

	var buff [MaxPacketLength]byte
	for {
		n, remoteAddr, err := conn.ReadFrom(buff[:])
		if err != nil {
			if atomic.LoadInt32(&s.shutdownRequested) == 1 {
				return ErrServerShutdown
			}

			if ne, ok := err.(net.Error); ok && !ne.Temporary() {
				return err
			}
			continue
		}

		s.activeAdd()
		go func(buff []byte, remoteAddr net.Addr) {
			defer s.activeDone()

			secret, err := s.SecretSource.RADIUSSecret(s.ctx, remoteAddr)
			if err != nil {
				return
			}
			if len(secret) == 0 {
				return
			}

			if !s.InsecureSkipVerify && !IsAuthenticRequest(buff, secret) {
				return
			}

			packet, err := Parse(buff, secret)
			if err != nil {
				return
			}

			key := requestKey{
				IP:         remoteAddr.String(),
				Identifier: packet.Identifier,
			}
			requestsLock.Lock()
			if _, ok := requests[key]; ok {
				requestsLock.Unlock()
				return
			}
			requests[key] = struct{}{}
			requestsLock.Unlock()

			response := packetResponseWriter{
				conn: conn,
				addr: remoteAddr,
			}

			defer func() {
				requestsLock.Lock()
				delete(requests, key)
				requestsLock.Unlock()
			}()

			request := Request{
				LocalAddr:  conn.LocalAddr(),
				RemoteAddr: remoteAddr,
				Packet:     packet,
				ctx:        s.ctx,
			}

			s.Handler.ServeRADIUS(&response, &request)
		}(append([]byte(nil), buff[:n]...), remoteAddr)
	}
}

// ListenAndServe starts a RADIUS server on the address given in s.
func (s *PacketServer) ListenAndServe() error {
	if s.Handler == nil {
		return errors.New("radius: nil Handler")
	}
	if s.SecretSource == nil {
		return errors.New("radius: nil SecretSource")
	}

	addrStr := ":1812"
	if s.Addr != "" {
		addrStr = s.Addr
	}

	network := "udp"
	if s.Network != "" {
		network = s.Network
	}

	pc, err := net.ListenPacket(network, addrStr)
	if err != nil {
		return err
	}
	defer pc.Close()
	return s.Serve(pc)
}

// Shutdown gracefully stops the server. It first closes all listeners and then
// waits for any running handlers to complete.
//
// Shutdown returns after nil all handlers have completed. ctx.Err() is
// returned if ctx is canceled.
//
// Any Serve methods return ErrShutdown after Shutdown is called.
func (s *PacketServer) Shutdown(ctx context.Context) error {
	s.mu.Lock()
	s.initLocked()
	if atomic.CompareAndSwapInt32(&s.shutdownRequested, 0, 1) {
		for listener := range s.listeners {
			listener.Close()
		}

		s.ctxDone()
		s.activeDone()
	}
	s.mu.Unlock()

	select {
	case <-s.lastActive:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<commit_msg>add PacketServer.ErrorLog<commit_after>package radius

import (
	"context"
	"errors"
	"log"
	"net"
	"sync"
	"sync/atomic"
)

type packetResponseWriter struct {
	// listener that received the packet
	conn net.PacketConn
	addr net.Addr
}

func (r *packetResponseWriter) Write(packet *Packet) error {
	encoded, err := packet.Encode()
	if err != nil {
		return err
	}
	if _, err := r.conn.WriteTo(encoded, r.addr); err != nil {
		return err
	}
	return nil
}

// PacketServer listens for RADIUS requests on a packet-based protocols (e.g.
// UDP).
type PacketServer struct {
	// The address on which the server listens. Defaults to :1812.
	Addr string

	// The network on which the server listens. Defaults to udp.
	Network string

	// The source from which the secret is obtained for parsing and validating
	// the request.
	SecretSource SecretSource

	// Handler which is called to process the request.
	Handler Handler

	// Skip incoming packet authenticity validation.
	// This should only be set to true for debugging purposes.
	InsecureSkipVerify bool

	// ErrorLog specifies an optional logger for errors
	// around packet accepting, processing, and validation.
	// If nil, logging is done via the log package's standard logger.
	ErrorLog *log.Logger

	shutdownRequested int32

	mu          sync.Mutex
	ctx         context.Context
	ctxDone     context.CancelFunc
	listeners   map[net.PacketConn]uint
	lastActive  chan struct{} // closed when the last active item finishes
	activeCount int32
}

func (s *PacketServer) initLocked() {
	if s.ctx == nil {
		s.ctx, s.ctxDone = context.WithCancel(context.Background())
		s.listeners = make(map[net.PacketConn]uint)
		s.lastActive = make(chan struct{})
	}
}

func (s *PacketServer) activeAdd() {
	atomic.AddInt32(&s.activeCount, 1)
}

func (s *PacketServer) activeDone() {
	if atomic.AddInt32(&s.activeCount, -1) == -1 {
		close(s.lastActive)
	}
}

func (s *PacketServer) logf(format string, args ...interface{}) {
	if s.ErrorLog != nil {
		s.ErrorLog.Printf(format, args...)
	} else {
		log.Printf(format, args...)
	}
}

// Serve accepts incoming connections on conn.
func (s *PacketServer) Serve(conn net.PacketConn) error {
	if s.Handler == nil {
		return errors.New("radius: nil Handler")
	}
	if s.SecretSource == nil {
		return errors.New("radius: nil SecretSource")
	}

	s.mu.Lock()
	s.initLocked()
	if atomic.LoadInt32(&s.shutdownRequested) == 1 {
		s.mu.Unlock()
		return ErrServerShutdown
	}

	s.listeners[conn]++
	s.mu.Unlock()

	type requestKey struct {
		IP         string
		Identifier byte
	}

	var (
		requestsLock sync.Mutex
		requests     = map[requestKey]struct{}{}
	)

	s.activeAdd()
	defer func() {
		s.mu.Lock()
		s.listeners[conn]--
		if s.listeners[conn] == 0 {
			delete(s.listeners, conn)
		}
		s.mu.Unlock()
		s.activeDone()
	}()

	var buff [MaxPacketLength]byte
	for {
		n, remoteAddr, err := conn.ReadFrom(buff[:])
		if err != nil {
			if atomic.LoadInt32(&s.shutdownRequested) == 1 {
				return ErrServerShutdown
			}

			if ne, ok := err.(net.Error); ok && !ne.Temporary() {
				return err
			}
			s.logf("radius: could not read packet: %v", err)
			continue
		}

		s.activeAdd()
		go func(buff []byte, remoteAddr net.Addr) {
			defer s.activeDone()

			secret, err := s.SecretSource.RADIUSSecret(s.ctx, remoteAddr)
			if err != nil {
				s.logf("radius: error fetching from secret source: %v", err)
				return
			}
			if len(secret) == 0 {
				s.logf("radius: empty secret returned from secret source")
				return
			}

			if !s.InsecureSkipVerify && !IsAuthenticRequest(buff, secret) {
				s.logf("radius: packet validation failed; bad secret")
				return
			}

			packet, err := Parse(buff, secret)
			if err != nil {
				s.logf("radius: unable to parse packet: %v", err)
				return
			}

			key := requestKey{
				IP:         remoteAddr.String(),
				Identifier: packet.Identifier,
			}

			requestsLock.Lock()
			if _, ok := requests[key]; ok {
				requestsLock.Unlock()
				return
			}
			requests[key] = struct{}{}
			requestsLock.Unlock()

			response := packetResponseWriter{
				conn: conn,
				addr: remoteAddr,
			}

			defer func() {
				requestsLock.Lock()
				delete(requests, key)
				requestsLock.Unlock()
			}()

			request := Request{
				LocalAddr:  conn.LocalAddr(),
				RemoteAddr: remoteAddr,
				Packet:     packet,
				ctx:        s.ctx,
			}

			s.Handler.ServeRADIUS(&response, &request)
		}(append([]byte(nil), buff[:n]...), remoteAddr)
	}
}

// ListenAndServe starts a RADIUS server on the address given in s.
func (s *PacketServer) ListenAndServe() error {
	if s.Handler == nil {
		return errors.New("radius: nil Handler")
	}
	if s.SecretSource == nil {
		return errors.New("radius: nil SecretSource")
	}

	addrStr := ":1812"
	if s.Addr != "" {
		addrStr = s.Addr
	}

	network := "udp"
	if s.Network != "" {
		network = s.Network
	}

	pc, err := net.ListenPacket(network, addrStr)
	if err != nil {
		return err
	}
	defer pc.Close()
	return s.Serve(pc)
}

// Shutdown gracefully stops the server. It first closes all listeners and then
// waits for any running handlers to complete.
//
// Shutdown returns after nil all handlers have completed. ctx.Err() is
// returned if ctx is canceled.
//
// Any Serve methods return ErrShutdown after Shutdown is called.
func (s *PacketServer) Shutdown(ctx context.Context) error {
	s.mu.Lock()
	s.initLocked()
	if atomic.CompareAndSwapInt32(&s.shutdownRequested, 0, 1) {
		for listener := range s.listeners {
			listener.Close()
		}

		s.ctxDone()
		s.activeDone()
	}
	s.mu.Unlock()

	select {
	case <-s.lastActive:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}
<|endoftext|>


<commit_before>package main

type GameEvent interface {
	Execute(*GameState) error
}

// create a ship
type CreateShipEvent struct {
	Time     uint64
	Id       string
	Position *Point
}

func (e *CreateShipEvent) Execute(state *GameState) error {
	state.Ships[e.Id] = CreateShip(e.Id, e.Position)
	return nil
}

// create an asteroid
type CreateAsteroidEvent struct {
	Time     uint64
	Id       string
	Position *Point
	Angle    float64
	Velocity *Vector
	Shape    []*Point
}

func (e *CreateAsteroidEvent) Execute(state *GameState) error {
	state.Asteroids[e.Id] = CreateAsteroid(e.Id, e.Position, e.Angle, e.Velocity, e.Shape)
	return nil
}

// remove a ship
type RemoveShipEvent struct {
	Time   uint64
	ShipId string
}

func (e *RemoveShipEvent) Execute(state *GameState) error {
	delete(state.Ships, e.ShipId)
	return nil
}

// change ship acceleration direction
type ChangeAccelerationEvent struct {
	Time      uint64
	ShipId    string
	Direction int8
}

func (e *ChangeAccelerationEvent) Execute(state *GameState) error {
	s := state.Ships[e.ShipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	s.Acceleration = e.Direction
	return nil
}

// change ship rotation direction
type ChangeRotationEvent struct {
	Time      uint64
	ShipId    string
	Direction int8
}

func (e *ChangeRotationEvent) Execute(state *GameState) error {
	s := state.Ships[e.ShipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	s.Rotation = e.Direction
	return nil
}

// fire ship laser!
type FireEvent struct {
	Time         uint64
	ShipId       string
	ProjectileId string
	Created      uint64
}

func (e *FireEvent) Execute(state *GameState) error {
	s := state.Ships[e.ShipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	pos := *s.Position // Clone ship position
	projectile := CreateProjectile(e.ProjectileId, &pos, s.Angle, e.Created, e.ShipId)
	state.Projectiles[projectile.Id] = projectile
	return nil
}

// remove dead objects
type CleanupEvent struct {
	Time uint64
}

func (e *CleanupEvent) Execute(state *GameState) error {
	dead := []string{}

	for k, v := range state.Projectiles {
		if !v.Alive {
			dead = append(dead, k)
		}
	}

	for i := range dead {
		delete(state.Projectiles, dead[i])
	}

	return nil
}
<commit_msg>Changed event fields to private, added Time() function.<commit_after>package main

type GameEvent interface {
	Time() uint64
	Execute(*GameState) error
}

// create a ship
type CreateShipEvent struct {
	time     uint64
	id       string
	position *Point
}

func (e *CreateShipEvent) Time() uint64 {
	return e.time
}

func (e *CreateShipEvent) Execute(state *GameState) error {
	state.Ships[e.id] = CreateShip(e.id, e.position)
	return nil
}

// create an asteroid
type CreateAsteroidEvent struct {
	time     uint64
	id       string
	position *Point
	angle    float64
	velocity *Vector
	shape    []*Point
}

func (e *CreateAsteroidEvent) Time() uint64 {
	return e.time
}

func (e *CreateAsteroidEvent) Execute(state *GameState) error {
	state.Asteroids[e.id] = CreateAsteroid(e.id, e.position, e.angle, e.velocity, e.shape)
	return nil
}

// remove a ship
type RemoveShipEvent struct {
	time   uint64
	shipId string
}

func (e *RemoveShipEvent) Time() uint64 {
	return e.time
}

func (e *RemoveShipEvent) Execute(state *GameState) error {
	delete(state.Ships, e.shipId)
	return nil
}

// change ship acceleration direction
type ChangeAccelerationEvent struct {
	time      uint64
	shipId    string
	direction int8
}

func (e *ChangeAccelerationEvent) Time() uint64 {
	return e.time
}

func (e *ChangeAccelerationEvent) Execute(state *GameState) error {
	s := state.Ships[e.shipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	s.Acceleration = e.direction
	return nil
}

// change ship rotation direction
type ChangeRotationEvent struct {
	time      uint64
	shipId    string
	direction int8
}

func (e *ChangeRotationEvent) Time() uint64 {
	return e.time
}

func (e *ChangeRotationEvent) Execute(state *GameState) error {
	s := state.Ships[e.shipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	s.Rotation = e.direction
	return nil
}

// fire ship laser!
type FireEvent struct {
	time         uint64
	shipId       string
	projectileId string
	Created      uint64
}

func (e *FireEvent) Time() uint64 {
	return e.time
}

func (e *FireEvent) Execute(state *GameState) error {
	s := state.Ships[e.shipId]
	if s == nil {
		return GameError{"Ship doesn't exist for player"}
	}

	pos := *s.Position // Clone ship position
	projectile := CreateProjectile(e.projectileId, &pos, s.Angle, e.Created, e.shipId)
	state.Projectiles[projectile.Id] = projectile
	return nil
}

// remove dead objects
type CleanupEvent struct {
	time uint64
}

func (e *CleanupEvent) Time() uint64 {
	return e.time
}

func (e *CleanupEvent) Execute(state *GameState) error {
	dead := []string{}

	for k, v := range state.Projectiles {
		if !v.Alive {
			dead = append(dead, k)
		}
	}

	for i := range dead {
		delete(state.Projectiles, dead[i])
	}

	return nil
}
<|endoftext|>


<commit_before>package goat

import (
	"fmt"
)

const APP = "goat"

func Manager(killChan chan bool, doneChan chan int, port string) {
	// Launch listeners
	go new(HttpListener).Listen(port)
	go new(UdpListener).Listen(port)

	fmt.Println(APP, ": HTTP and UDP listeners launched on port " + port)

	for {
		select {
		case <-killChan:
			//change this to kill workers gracefully and exit
			fmt.Println("done")
			doneChan <- 0
			// case freeWorker := <-ioReturn:
		}
	}
}
<commit_msg>manager now supports logging<commit_after>package goat

import (
	"fmt"
)

const APP = "goat"

func Manager(killChan chan bool, doneChan chan int, port string) {
	// Launch listeners
	logChan := make(chan string)
	go new(HttpListener).Listen(port,logChan)
	go new(UdpListener).Listen(port,logChan)
	go goat.LogMng(doneChan,logChan)

	fmt.Println(APP, ": HTTP and UDP listeners launched on port " + port)

	for {
		select {
		case <-killChan:
			//change this to kill workers gracefully and exit
			fmt.Println("done")
			doneChan <- 0
		case
		}
	}
}
<|endoftext|>


<commit_before>package utilcmd

import (
	"strings"

	"github.com/jasonpuglisi/ircutil"
)

// Say sends a message to a target. Function key: inami/utilcmd.Say
func Say(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	ircutil.SendPrivmsg(client, message.Args[0], strings.Join(message.Args[1:],
		" "))
}

// Init adds utilcmd's functions to the command map.
func Init(cmdMap ircutil.CmdMap) {
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Say", Say)
}
<commit_msg>Add basic utility commands<commit_after>package utilcmd

import (
	"strings"

	"github.com/jasonpuglisi/ircutil"
)

// Init adds utilcmd's functions to the command map.
func Init(cmdMap ircutil.CmdMap) {
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Nick", Nick)
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Join", Join)
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Part", Part)
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Say", Say)
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Notify", Notify)
	ircutil.AddCommand(cmdMap, "inami/utilcmd.Do", Do)
}

// Nick updates a nickname. Function key: inami/utilcmd.Nick
func Nick(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	ircutil.SendNick(client, message.Args[0])
}

// Join attahces to a channel with an optional password.
// Function key: inami/utilcmd.Join
func Join(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	pass := ""
	if len(message.Args) > 1 {
		pass = message.Args[1]
	}
	ircutil.SendJoin(client, message.Args[0], pass)
}

// Part detaches from a channel. Function key: inami/utilcmd.Part
func Part(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	msg := ""
	if len(message.Args) > 1 {
		msg = strings.Join(message.Args[1:], " ")
	}
	ircutil.SendPart(client, message.Args[0], msg)
}

// Say sends a message to a target. Function key: inami/utilcmd.Say
func Say(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	ircutil.SendPrivmsg(client, message.Args[0], strings.Join(message.Args[1:],
		" "))
}

// Notify sends a notice to a target. Function key: inami/utilcmd.Notify
func Notify(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	ircutil.SendNotice(client, message.Args[0], strings.Join(message.Args[1:],
		" "))
}

// Do performs an action at a target. Function key: inami/utilcmd.Do
func Do(client *ircutil.Client, command *ircutil.Command,
	message *ircutil.Message) {
	ircutil.SendPrivmsg(client, message.Args[0], "\x01ACTION "+
		strings.Join(message.Args[1:], " ")+"\x01")
}
<|endoftext|>


<commit_before>package utils

import (
	"fmt"
	"net/http"
	"time"
)

const (
	// ISODate - iso date format
	ISODate string = "2006-01-02"
	// ISODateTime - iso date time format
	ISODateTime string = "2006-01-02 15:04:05"
	// ISODateTimestamp - iso timestamp format
	ISODateTimestamp string = "2006-01-02 15:04:05.000"
	// ISODateTimeZ - iso datetime with timezone format
	ISODateTimeZ string = "2006-01-02 15:04:05Z07:00"
	// ISODateTimestampZ - iso timestamp with timezone format
	ISODateTimestampZ string = "2006-01-02 15:04:05.000Z07:00"
	// DMY - dd/MM/yyyy
	DMY string = "02/01/2006"
	// DMYTime - dd/MM/yyyy HH:m:ss
	DMYTime string = "02/01/2006 15:04:05"
	// UTCDate - date at midnight UTC
	UTCDate string = "UTCDate"
	// UTCDateTime - ISODateTime at UTC
	UTCDateTime string = "UTC"
	// UTCDateTimestamp - ISODateTimestamp at UTC
	UTCDateTimestamp string = "UTCTimestamp"
	// DateOffset - time zone offset
	DateOffset string = "Z07:00"
	// RSSDateTime - rss date time format
	RSSDateTime string = "Mon, _2 Jan 2006 15:04:05 Z07:00"
	// RSSDateTimeTZ - rss date time format with named timezone
	RSSDateTimeTZ string = "Mon, _2 Jan 2006 15:04:05 MST"
)

// IsISODate - checks if is in iso date format
func IsISODate(sval string) bool {
	_, err := String2date(sval, ISODate)

	if err != nil {
		return false
	}

	return true
}

// IsISODateTime - checks if is in iso datetime format
func IsISODateTime(sval string) bool {
	_, err := String2date(sval, ISODateTime)

	if err != nil {
		return false
	}

	return true
}

// DateFromISODateTime - Date From ISODateTime
func DateFromISODateTime(sval string) (time.Time, error) {
	return String2date(sval, ISODateTime)
}

// Date2string - Date to string
func Date2string(val time.Time, format string) string {
	switch format {
	case ISODate, ISODateTime, ISODateTimestamp, ISODateTimeZ, ISODateTimestampZ, DMY, DMYTime:
		return val.Format(format)
	case UTCDate:
		return val.UTC().Format(ISODate)
	case UTCDateTime:
		return val.UTC().Format(ISODateTimeZ)
	case UTCDateTimestamp:
		return val.UTC().Format(ISODateTimestampZ)
	case RSSDateTime:
		return val.UTC().Format(RSSDateTime)
	case RSSDateTimeTZ:
		return val.Format(RSSDateTimeTZ)
	default:
		return ""
	}

}

// String2dateNoErr - String to date NoErrCheck
func String2dateNoErr(sval string, format string) time.Time {
	dt, err := String2date(sval, format)
	if err != nil {
		panic(err)
	}
	return dt
}

// String2date - String to date
func String2date(sval string, format string) (time.Time, error) {
	switch format {
	case ISODate, ISODateTime, ISODateTimestamp, ISODateTimeZ, ISODateTimestampZ, DMY, DMYTime, DateOffset:
		loc, err := time.LoadLocation("Local")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(format, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDate:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODate, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDateTime:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODateTime, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDateTimestamp:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODateTimestamp, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case RSSDateTime:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(RSSDateTime, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case RSSDateTimeTZ:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(RSSDateTimeTZ, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	default:
		return time.Now(), fmt.Errorf("Unknown datetime format \"%s\"", format)
	}
}

// Server2ClientDmy - Server2ClientDmy
func Server2ClientDmy(r *http.Request, serverTime time.Time) string {
	t := Server2ClientLocal(r, serverTime)
	return Date2string(t, DMY)
}

// Server2ClientDmyTime - Server2ClientDmyTime
func Server2ClientDmyTime(r *http.Request, serverTime time.Time) string {
	t := Server2ClientLocal(r, serverTime)
	return Date2string(t, DMYTime)
}

// Server2ClientLocal - Server2ClientLocal
func Server2ClientLocal(r *http.Request, serverTime time.Time) time.Time {
	timeOffset := 0

	cookie, err := r.Cookie("time_zone_offset")
	if err != nil && err != http.ErrNoCookie {
		return serverTime.UTC()
	} else if err == http.ErrNoCookie {
		timeOffset = 0
	} else {
		timeOffset = String2int(cookie.Value)
	}

	return serverTime.UTC().Add(time.Duration(-1*timeOffset) * time.Minute)
}
<commit_msg>Parse RSS date<commit_after>package utils

import (
	"fmt"
	"net/http"
	"time"
)

const (
	// ISODate - iso date format
	ISODate string = "2006-01-02"
	// ISODateTime - iso date time format
	ISODateTime string = "2006-01-02 15:04:05"
	// ISODateTimestamp - iso timestamp format
	ISODateTimestamp string = "2006-01-02 15:04:05.000"
	// ISODateTimeZ - iso datetime with timezone format
	ISODateTimeZ string = "2006-01-02 15:04:05Z07:00"
	// ISODateTimestampZ - iso timestamp with timezone format
	ISODateTimestampZ string = "2006-01-02 15:04:05.000Z07:00"
	// DMY - dd/MM/yyyy
	DMY string = "02/01/2006"
	// DMYTime - dd/MM/yyyy HH:m:ss
	DMYTime string = "02/01/2006 15:04:05"
	// UTCDate - date at midnight UTC
	UTCDate string = "UTCDate"
	// UTCDateTime - ISODateTime at UTC
	UTCDateTime string = "UTC"
	// UTCDateTimestamp - ISODateTimestamp at UTC
	UTCDateTimestamp string = "UTCTimestamp"
	// DateOffset - time zone offset
	DateOffset string = "Z07:00"
	// RSSDateTime - rss date time format
	RSSDateTime string = "Mon, 02 Jan 2006 15:04:05 Z07:00"
	// RSSDateTime1 - rss date time format
	RSSDateTime1 string = "Mon, _2 Jan 2006 15:04:05 Z07:00"
	// RSSDateTime2 - rss date time format 2
	RSSDateTime2 string = "Mon, 02 Jan 2006 15:04:05 Z0700"
	// RSSDateTime3 - rss date time format 2
	RSSDateTime3 string = "Mon, _2 Jan 2006 15:04:05 Z0700"
	// RSSDateTimeTZ - rss date time format with named timezone
	RSSDateTimeTZ string = "Mon, 02 Jan 2006 15:04:05 MST"
	// RSSDateTimeTZ1 - rss date time format with named timezone
	RSSDateTimeTZ1 string = "Mon, _2 Jan 2006 15:04:05 MST"
)

// IsISODate - checks if is in iso date format
func IsISODate(sval string) bool {
	_, err := String2date(sval, ISODate)

	if err != nil {
		return false
	}

	return true
}

// IsISODateTime - checks if is in iso datetime format
func IsISODateTime(sval string) bool {
	_, err := String2date(sval, ISODateTime)

	if err != nil {
		return false
	}

	return true
}

// DateFromISODateTime - Date From ISODateTime
func DateFromISODateTime(sval string) (time.Time, error) {
	return String2date(sval, ISODateTime)
}

// Date2string - Date to string
func Date2string(val time.Time, format string) string {
	switch format {
	case ISODate, ISODateTime, ISODateTimestamp, ISODateTimeZ, ISODateTimestampZ, DMY, DMYTime:
		return val.Format(format)
	case UTCDate:
		return val.UTC().Format(ISODate)
	case UTCDateTime:
		return val.UTC().Format(ISODateTimeZ)
	case UTCDateTimestamp:
		return val.UTC().Format(ISODateTimestampZ)
	case RSSDateTime:
		return val.UTC().Format(RSSDateTime)
	case RSSDateTimeTZ:
		return val.Format(RSSDateTimeTZ)
	default:
		return ""
	}

}

// String2dateNoErr - String to date NoErrCheck
func String2dateNoErr(sval string, format string) time.Time {
	dt, err := String2date(sval, format)
	if err != nil {
		panic(err)
	}
	return dt
}

// String2date - String to date
func String2date(sval string, format string) (time.Time, error) {
	switch format {
	case ISODate, ISODateTime, ISODateTimestamp, ISODateTimeZ, ISODateTimestampZ, DMY, DMYTime, DateOffset:
		loc, err := time.LoadLocation("Local")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(format, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDate:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODate, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDateTime:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODateTime, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case UTCDateTimestamp:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(ISODateTimestamp, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case RSSDateTime:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(RSSDateTime, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	case RSSDateTimeTZ:
		loc, err := time.LoadLocation("UTC")
		if err != nil {
			return time.Now(), err
		}

		t, err := time.ParseInLocation(RSSDateTimeTZ, sval, loc)
		if err != nil {
			return time.Now(), err
		}
		return t, nil
	default:
		return time.Now(), fmt.Errorf("Unknown datetime format \"%s\"", format)
	}
}

// Server2ClientDmy - Server2ClientDmy
func Server2ClientDmy(r *http.Request, serverTime time.Time) string {
	t := Server2ClientLocal(r, serverTime)
	return Date2string(t, DMY)
}

// Server2ClientDmyTime - Server2ClientDmyTime
func Server2ClientDmyTime(r *http.Request, serverTime time.Time) string {
	t := Server2ClientLocal(r, serverTime)
	return Date2string(t, DMYTime)
}

// Server2ClientLocal - Server2ClientLocal
func Server2ClientLocal(r *http.Request, serverTime time.Time) time.Time {
	timeOffset := 0

	cookie, err := r.Cookie("time_zone_offset")
	if err != nil && err != http.ErrNoCookie {
		return serverTime.UTC()
	} else if err == http.ErrNoCookie {
		timeOffset = 0
	} else {
		timeOffset = String2int(cookie.Value)
	}

	return serverTime.UTC().Add(time.Duration(-1*timeOffset) * time.Minute)
}

// ParseRSSDate - try to parse RSS date in multiple formats
func ParseRSSDate(sdate string) (time.Time, error) {
	var err error
	var dt time.Time

	formats := []string{
		RSSDateTimeTZ,
		RSSDateTimeTZ1,
		RSSDateTime,
		RSSDateTime1,
		RSSDateTime2,
		RSSDateTime3,
	}

	for _, format := range formats {
		dt, err = String2date(sdate, format)
		if err == nil {
			break
		}
	}

	return dt.UTC(), err
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	crand "crypto/rand"
	"errors"
	"github.com/stretchr/testify/assert"
	"image"
	"image/color"
	"image/jpeg"
	"image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"testing"

	"github.com/eirka/eirka-libs/config"
	local "github.com/eirka/eirka-post/config"
)

func testPng(size int) *bytes.Buffer {

	output := new(bytes.Buffer)

	myimage := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{size, size}})

	// This loop just fills the image with random data
	for x := 0; x < size; x++ {
		for y := 0; y < size; y++ {
			c := color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255}
			myimage.Set(x, y, c)
		}
	}

	png.Encode(output, myimage)

	return output
}

func testJpeg(size int) *bytes.Buffer {

	output := new(bytes.Buffer)

	myimage := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{size, size}})

	// This loop just fills the image with random data
	for x := 0; x < size; x++ {
		for y := 0; y < size; y++ {
			c := color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255}
			myimage.Set(x, y, c)
		}
	}

	jpeg.Encode(output, myimage, nil)

	return output
}

func testRandom() []byte {
	bytes := make([]byte, 20000)

	if _, err := io.ReadFull(crand.Reader, bytes); err != nil {
		panic(err)
	}

	return bytes
}

func formJpegRequest(size int, filename string) *http.Request {

	var b bytes.Buffer

	w := multipart.NewWriter(&b)

	fw, _ := w.CreateFormFile("file", filename)

	io.Copy(fw, testJpeg(size))

	w.Close()

	req, _ := http.NewRequest("POST", "/reply", &b)
	req.Header.Set("Content-Type", w.FormDataContentType())

	return req
}

func formRandomRequest(filename string) *http.Request {

	var b bytes.Buffer

	w := multipart.NewWriter(&b)

	fw, _ := w.CreateFormFile("file", filename)

	io.Copy(fw, bytes.NewReader(testRandom()))

	w.Close()

	req, _ := http.NewRequest("POST", "/reply", &b)
	req.Header.Set("Content-Type", w.FormDataContentType())

	return req
}

func TestIsAllowedExt(t *testing.T) {

	assert.False(t, isAllowedExt(".png.exe"), "Should not be allowed")

	assert.False(t, isAllowedExt(".exe.png"), "Should not be allowed")

	assert.False(t, isAllowedExt(""), "Should not be allowed")

	assert.False(t, isAllowedExt("."), "Should not be allowed")

	assert.False(t, isAllowedExt(".pdf"), "Should not be allowed")

	assert.True(t, isAllowedExt(".jpg"), "Should be allowed")

	assert.True(t, isAllowedExt(".JPEG"), "Should be allowed")

}

func TestCheckReqGoodExt(t *testing.T) {

	var err error

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err = img.checkReqExt()
	assert.NoError(t, err, "An error was not expected")

}

func TestCheckReqBadExt(t *testing.T) {

	req := formJpegRequest(300, "test.crap")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("format not supported"), "Error should match")
	}

}

func TestCheckReqBadExtExploit1(t *testing.T) {

	req := formRandomRequest("test.exe.png")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	assert.NoError(t, err, "An error was not expected")

	err = img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("unknown file type"), "Error should match")
	}

}

func TestCheckReqBadExtExploit2(t *testing.T) {

	req := formRandomRequest("test.png.exe")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("format not supported"), "Error should match")
	}

}

func TestCheckReqNoExt(t *testing.T) {

	req := formJpegRequest(300, "test")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("no file extension"), "Error should match")
	}

}

func TestGetMD5(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

}

func TestCheckMagicGood(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, img.mime, "image/jpeg", "Mime type should be the same")
	}

}

func TestCheckMagicBad(t *testing.T) {

	req := formRandomRequest("test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("unknown file type"), "Error should match")
	}

}

func TestGetStatsGoodPng(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000000

	img := ImageType{}

	img.image = testPng(400)

	err := img.getStats()
	assert.NoError(t, err, "An error was not expected")

}

func TestGetStatsGoodJpeg(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000000

	img := ImageType{}

	img.image = testJpeg(400)

	err := img.getStats()
	assert.NoError(t, err, "An error was not expected")

}

func TestGetStatsBadSize(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000

	img := ImageType{}

	img.image = testPng(400)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image size too large"), "Error should match")
	}

}

func TestGetStatsBadMin(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 300000

	img := ImageType{}

	img.image = testPng(50)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image width too small"), "Error should match")
	}

}

func TestGetStatsBadMax(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 300000

	img := ImageType{}

	img.image = testPng(1200)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image width too large"), "Error should match")
	}

}

func TestMakeFilenames(t *testing.T) {

	img := ImageType{}

	img.makeFilenames()

	assert.NotEmpty(t, img.Filename, "Filename should be returned")

	assert.NotEmpty(t, img.Thumbnail, "Thumbnail name should be returned")

}

func TestSaveFile(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.ProcessFile()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
		assert.Equal(t, img.Ext, ".jpg", "Ext should be the same")
		assert.Equal(t, img.mime, "image/jpeg", "Mime type should be the same")
	}

	filesize := img.image.Len()

	err = img.getStats()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, img.OrigHeight, 300, "Height should be the same")
		assert.Equal(t, img.OrigWidth, 300, "Width should be the same")
	}

	err = img.saveFile()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.Filename, "Filename should be returned")
		assert.NotEmpty(t, img.Thumbnail, "Thumbnail name should be returned")
	}

	file, err = os.Open(filepath.Join(local.Settings.Directories.ImageDir, img.Filename))
	assert.NoError(t, err, "An error was not expected")

	info, err = file.Stat()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, info.Name(), img.File, "Name should be the same")
		assert.Equal(t, info.Size(), filesize, "Size should be the same")
	}
}
<commit_msg>add tests and change image functions a bit<commit_after>package utils

import (
	"bytes"
	crand "crypto/rand"
	"errors"
	"github.com/stretchr/testify/assert"
	"image"
	"image/color"
	"image/jpeg"
	"image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"testing"

	"github.com/eirka/eirka-libs/config"
	local "github.com/eirka/eirka-post/config"
)

func testPng(size int) *bytes.Buffer {

	output := new(bytes.Buffer)

	myimage := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{size, size}})

	// This loop just fills the image with random data
	for x := 0; x < size; x++ {
		for y := 0; y < size; y++ {
			c := color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255}
			myimage.Set(x, y, c)
		}
	}

	png.Encode(output, myimage)

	return output
}

func testJpeg(size int) *bytes.Buffer {

	output := new(bytes.Buffer)

	myimage := image.NewRGBA(image.Rectangle{image.Point{0, 0}, image.Point{size, size}})

	// This loop just fills the image with random data
	for x := 0; x < size; x++ {
		for y := 0; y < size; y++ {
			c := color.RGBA{uint8(rand.Intn(255)), uint8(rand.Intn(255)), uint8(rand.Intn(255)), 255}
			myimage.Set(x, y, c)
		}
	}

	jpeg.Encode(output, myimage, nil)

	return output
}

func testRandom() []byte {
	bytes := make([]byte, 20000)

	if _, err := io.ReadFull(crand.Reader, bytes); err != nil {
		panic(err)
	}

	return bytes
}

func formJpegRequest(size int, filename string) *http.Request {

	var b bytes.Buffer

	w := multipart.NewWriter(&b)

	fw, _ := w.CreateFormFile("file", filename)

	io.Copy(fw, testJpeg(size))

	w.Close()

	req, _ := http.NewRequest("POST", "/reply", &b)
	req.Header.Set("Content-Type", w.FormDataContentType())

	return req
}

func formRandomRequest(filename string) *http.Request {

	var b bytes.Buffer

	w := multipart.NewWriter(&b)

	fw, _ := w.CreateFormFile("file", filename)

	io.Copy(fw, bytes.NewReader(testRandom()))

	w.Close()

	req, _ := http.NewRequest("POST", "/reply", &b)
	req.Header.Set("Content-Type", w.FormDataContentType())

	return req
}

func TestIsAllowedExt(t *testing.T) {

	assert.False(t, isAllowedExt(".png.exe"), "Should not be allowed")

	assert.False(t, isAllowedExt(".exe.png"), "Should not be allowed")

	assert.False(t, isAllowedExt(""), "Should not be allowed")

	assert.False(t, isAllowedExt("."), "Should not be allowed")

	assert.False(t, isAllowedExt(".pdf"), "Should not be allowed")

	assert.True(t, isAllowedExt(".jpg"), "Should be allowed")

	assert.True(t, isAllowedExt(".JPEG"), "Should be allowed")

}

func TestCheckReqGoodExt(t *testing.T) {

	var err error

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err = img.checkReqExt()
	assert.NoError(t, err, "An error was not expected")

}

func TestCheckReqBadExt(t *testing.T) {

	req := formJpegRequest(300, "test.crap")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("format not supported"), "Error should match")
	}

}

func TestCheckReqBadExtExploit1(t *testing.T) {

	req := formRandomRequest("test.exe.png")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	assert.NoError(t, err, "An error was not expected")

	err = img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("unknown file type"), "Error should match")
	}

}

func TestCheckReqBadExtExploit2(t *testing.T) {

	req := formRandomRequest("test.png.exe")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("format not supported"), "Error should match")
	}

}

func TestCheckReqNoExt(t *testing.T) {

	req := formJpegRequest(300, "test")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.checkReqExt()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("no file extension"), "Error should match")
	}

}

func TestGetMD5(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

}

func TestCheckMagicGood(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, img.mime, "image/jpeg", "Mime type should be the same")
	}

}

func TestCheckMagicBad(t *testing.T) {

	req := formRandomRequest("test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.getMD5()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
	}

	err = img.checkMagic()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("unknown file type"), "Error should match")
	}

}

func TestGetStatsGoodPng(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000000

	img := ImageType{}

	img.image = testPng(400)

	err := img.getStats()
	assert.NoError(t, err, "An error was not expected")

}

func TestGetStatsGoodJpeg(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000000

	img := ImageType{}

	img.image = testJpeg(400)

	err := img.getStats()
	assert.NoError(t, err, "An error was not expected")

}

func TestGetStatsBadSize(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 3000

	img := ImageType{}

	img.image = testPng(400)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image size too large"), "Error should match")
	}

}

func TestGetStatsBadMin(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 300000

	img := ImageType{}

	img.image = testPng(50)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image width too small"), "Error should match")
	}

}

func TestGetStatsBadMax(t *testing.T) {

	config.Settings.Limits.ImageMaxWidth = 1000
	config.Settings.Limits.ImageMinWidth = 100
	config.Settings.Limits.ImageMaxHeight = 1000
	config.Settings.Limits.ImageMinHeight = 100
	config.Settings.Limits.ImageMaxSize = 300000

	img := ImageType{}

	img.image = testPng(1200)

	err := img.getStats()
	if assert.Error(t, err, "An error was expected") {
		assert.Equal(t, err, errors.New("image width too large"), "Error should match")
	}

}

func TestMakeFilenames(t *testing.T) {

	img := ImageType{}

	img.makeFilenames()

	assert.NotEmpty(t, img.Filename, "Filename should be returned")

	assert.NotEmpty(t, img.Thumbnail, "Thumbnail name should be returned")

}

func TestSaveFile(t *testing.T) {

	req := formJpegRequest(300, "test.jpeg")

	img := ImageType{}

	img.File, img.Header, _ = req.FormFile("file")

	err := img.ProcessFile()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.MD5, "MD5 should be returned")
		assert.Equal(t, img.Ext, ".jpg", "Ext should be the same")
		assert.Equal(t, img.mime, "image/jpeg", "Mime type should be the same")
	}

	filesize := img.image.Len()

	err = img.getStats()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, img.OrigHeight, 300, "Height should be the same")
		assert.Equal(t, img.OrigWidth, 300, "Width should be the same")
	}

	err = img.saveFile()
	if assert.NoError(t, err, "An error was not expected") {
		assert.NotEmpty(t, img.Filename, "Filename should be returned")
		assert.NotEmpty(t, img.Thumbnail, "Thumbnail name should be returned")
	}

	file, err := os.Open(filepath.Join(local.Settings.Directories.ImageDir, img.Filename))
	assert.NoError(t, err, "An error was not expected")

	info, err = file.Stat()
	if assert.NoError(t, err, "An error was not expected") {
		assert.Equal(t, info.Name(), img.File, "Name should be the same")
		assert.Equal(t, info.Size(), filesize, "Size should be the same")
	}
}
<|endoftext|>


<commit_before>package log

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// Config defines Logger configuration.
type Config struct {
	Disable     bool   `yaml:"disable"`
	ServiceName string `yaml:"service_name"`
	Path        string `yaml:"path"`
	Encoding    string `yaml:"encoding"`
}

func (c Config) applyDefaults() Config {
	if c.Path == "" {
		c.Path = "stderr"
	}
	if c.Encoding == "" {
		c.Encoding = "console"
	}
	return c
}

// New creates a logger that is not default.
func New(c Config, fields map[string]interface{}) (*zap.Logger, error) {
	c = c.applyDefaults()
	if c.Disable {
		return zap.NewNop(), nil
	}
	if fields == nil {
		fields = map[string]interface{}{}
	}
	if c.ServiceName != "" {
		fields["service_name"] = c.ServiceName
	}

	return zap.Config{
		Level: zap.NewAtomicLevel(),
		Sampling: &zap.SamplingConfig{
			Initial:    100,
			Thereafter: 100,
		},
		Encoding: c.Encoding,
		EncoderConfig: zapcore.EncoderConfig{
			MessageKey:     "message",
			NameKey:        "logger_name",
			LevelKey:       "level",
			TimeKey:        "ts",
			CallerKey:      "caller",
			StacktraceKey:  "stack",
			EncodeLevel:    zapcore.CapitalLevelEncoder,
			EncodeTime:     zapcore.ISO8601TimeEncoder,
			EncodeDuration: zapcore.SecondsDurationEncoder,
			EncodeCaller:   zapcore.ShortCallerEncoder,
		},
		OutputPaths:   []string{c.Path},
		InitialFields: fields,
	}.Build()
}
<commit_msg>Disable stacktrace<commit_after>package log

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

// Config defines Logger configuration.
type Config struct {
	Disable     bool   `yaml:"disable"`
	ServiceName string `yaml:"service_name"`
	Path        string `yaml:"path"`
	Encoding    string `yaml:"encoding"`
}

func (c Config) applyDefaults() Config {
	if c.Path == "" {
		c.Path = "stderr"
	}
	if c.Encoding == "" {
		c.Encoding = "console"
	}
	return c
}

// New creates a logger that is not default.
func New(c Config, fields map[string]interface{}) (*zap.Logger, error) {
	c = c.applyDefaults()
	if c.Disable {
		return zap.NewNop(), nil
	}
	if fields == nil {
		fields = map[string]interface{}{}
	}
	if c.ServiceName != "" {
		fields["service_name"] = c.ServiceName
	}

	return zap.Config{
		Level: zap.NewAtomicLevel(),
		Sampling: &zap.SamplingConfig{
			Initial:    100,
			Thereafter: 100,
		},
		Encoding: c.Encoding,
		EncoderConfig: zapcore.EncoderConfig{
			MessageKey:     "message",
			NameKey:        "logger_name",
			LevelKey:       "level",
			TimeKey:        "ts",
			CallerKey:      "caller",
			EncodeLevel:    zapcore.CapitalLevelEncoder,
			EncodeTime:     zapcore.ISO8601TimeEncoder,
			EncodeDuration: zapcore.SecondsDurationEncoder,
			EncodeCaller:   zapcore.ShortCallerEncoder,
		},
		DisableStacktrace: true,
		OutputPaths:       []string{c.Path},
		InitialFields:     fields,
	}.Build()
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. 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.

/*
helloworld tracks how often a user has visited the index page.

This program demonstrates usage of the Cloud Bigtable API for the App Engine Flex environment and Go.
Instructions for running this program are in the README.md.
*/
package main

import (
	"bytes"
	"encoding/binary"
	"html/template"
	"log"
	"net/http"

	"cloud.google.com/go/bigtable"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	aelog "google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
)

// User-provided constants.
const (
	project  = "PROJECT_ID"
	instance = "INSTANCE"
)

var (
	tableName  = "bigtable-hello"
	familyName = "emails"

	// Client is initialized by main.
	client *bigtable.Client
)

func main() {
	ctx := context.Background()

	// Set up admin client, tables, and column families.
	// NewAdminClient uses Application Default Credentials to authenticate.
	adminClient, err := bigtable.NewAdminClient(ctx, project, instance)
	if err != nil {
		log.Fatalf("Unable to create a table admin client. %v", err)
	}
	tables, err := adminClient.Tables(ctx)
	if err != nil {
		log.Fatalf("Unable to fetch table list. %v", err)
	}
	if !sliceContains(tables, tableName) {
		if err := adminClient.CreateTable(ctx, tableName); err != nil {
			log.Fatalf("Unable to create table: %v. %v", tableName, err)
		}
	}
	tblInfo, err := adminClient.TableInfo(ctx, tableName)
	if err != nil {
		log.Fatalf("Unable to read info for table: %v. %v", tableName, err)
	}
	if !sliceContains(tblInfo.Families, familyName) {
		if err := adminClient.CreateColumnFamily(ctx, tableName, familyName); err != nil {
			log.Fatalf("Unable to create column family: %v. %v", familyName, err)
		}
	}
	adminClient.Close()

	// Set up Bigtable data operations client.
	// NewClient uses Application Default Credentials to authenticate.
	client, err = bigtable.NewClient(ctx, project, instance)
	if err != nil {
		log.Fatalf("Unable to create data operations client. %v", err)
	}

	http.Handle("/", appHandler(mainHandler))
	appengine.Main() // Never returns.
}

// mainHandler tracks how many times each user has visited this page.
func mainHandler(w http.ResponseWriter, r *http.Request) *appError {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return nil
	}

	ctx := appengine.NewContext(r)
	u := user.Current(ctx)
	if u == nil {
		login, err := user.LoginURL(ctx, r.URL.String())
		if err != nil {
			return &appError{err, "Error finding login URL", http.StatusInternalServerError}
		}
		http.Redirect(w, r, login, http.StatusFound)
		return nil
	}
	logoutURL, err := user.LogoutURL(ctx, "/")
	if err != nil {
		return &appError{err, "Error finding logout URL", http.StatusInternalServerError}
	}

	// Display hello page.
	tbl := client.Open(tableName)
	rmw := bigtable.NewReadModifyWrite()
	rmw.Increment(familyName, u.Email, 1)
	row, err := tbl.ApplyReadModifyWrite(ctx, u.Email, rmw)
	if err != nil {
		return &appError{err, "Error applying ReadModifyWrite to row: " + u.Email, http.StatusInternalServerError}
	}
	data := struct {
		Username, Logout string
		Visits           uint64
	}{
		Username: u.Email,
		// Retrieve the most recently edited column.
		Visits: binary.BigEndian.Uint64(row[familyName][0].Value),
		Logout: logoutURL,
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		return &appError{err, "Error writing template", http.StatusInternalServerError}
	}
	buf.WriteTo(w)
	return nil
}

var tmpl = template.Must(template.New("").Parse(`

{{with .Username}} Hello {{.}}{{end}}
{{with .Logout}}Sign out{{end}}

You have visited {{.Visits}}

`))

// sliceContains reports whether the provided string is present in the given slice of strings.
func sliceContains(list []string, target string) bool {
	for _, s := range list {
		if s == target {
			return true
		}
	}
	return false
}

// More info about this method of error handling can be found at: http://blog.golang.org/error-handling-and-go
type appHandler func(http.ResponseWriter, *http.Request) *appError

type appError struct {
	Error   error
	Message string
	Code    int
}

func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if e := fn(w, r); e != nil {
		ctx := appengine.NewContext(r)
		aelog.Errorf(ctx, "%v", e.Error)
		http.Error(w, e.Message, e.Code)
	}
}
<commit_msg>doc: refer to the App Engine flexible env correctly<commit_after>// Copyright 2015 Google Inc. 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.

/*
helloworld tracks how often a user has visited the index page.

This program demonstrates usage of the Cloud Bigtable API for App Engine flexible environment and Go.
Instructions for running this program are in the README.md.
*/
package main

import (
	"bytes"
	"encoding/binary"
	"html/template"
	"log"
	"net/http"

	"cloud.google.com/go/bigtable"
	"golang.org/x/net/context"
	"google.golang.org/appengine"
	aelog "google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
)

// User-provided constants.
const (
	project  = "PROJECT_ID"
	instance = "INSTANCE"
)

var (
	tableName  = "bigtable-hello"
	familyName = "emails"

	// Client is initialized by main.
	client *bigtable.Client
)

func main() {
	ctx := context.Background()

	// Set up admin client, tables, and column families.
	// NewAdminClient uses Application Default Credentials to authenticate.
	adminClient, err := bigtable.NewAdminClient(ctx, project, instance)
	if err != nil {
		log.Fatalf("Unable to create a table admin client. %v", err)
	}
	tables, err := adminClient.Tables(ctx)
	if err != nil {
		log.Fatalf("Unable to fetch table list. %v", err)
	}
	if !sliceContains(tables, tableName) {
		if err := adminClient.CreateTable(ctx, tableName); err != nil {
			log.Fatalf("Unable to create table: %v. %v", tableName, err)
		}
	}
	tblInfo, err := adminClient.TableInfo(ctx, tableName)
	if err != nil {
		log.Fatalf("Unable to read info for table: %v. %v", tableName, err)
	}
	if !sliceContains(tblInfo.Families, familyName) {
		if err := adminClient.CreateColumnFamily(ctx, tableName, familyName); err != nil {
			log.Fatalf("Unable to create column family: %v. %v", familyName, err)
		}
	}
	adminClient.Close()

	// Set up Bigtable data operations client.
	// NewClient uses Application Default Credentials to authenticate.
	client, err = bigtable.NewClient(ctx, project, instance)
	if err != nil {
		log.Fatalf("Unable to create data operations client. %v", err)
	}

	http.Handle("/", appHandler(mainHandler))
	appengine.Main() // Never returns.
}

// mainHandler tracks how many times each user has visited this page.
func mainHandler(w http.ResponseWriter, r *http.Request) *appError {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return nil
	}

	ctx := appengine.NewContext(r)
	u := user.Current(ctx)
	if u == nil {
		login, err := user.LoginURL(ctx, r.URL.String())
		if err != nil {
			return &appError{err, "Error finding login URL", http.StatusInternalServerError}
		}
		http.Redirect(w, r, login, http.StatusFound)
		return nil
	}
	logoutURL, err := user.LogoutURL(ctx, "/")
	if err != nil {
		return &appError{err, "Error finding logout URL", http.StatusInternalServerError}
	}

	// Display hello page.
	tbl := client.Open(tableName)
	rmw := bigtable.NewReadModifyWrite()
	rmw.Increment(familyName, u.Email, 1)
	row, err := tbl.ApplyReadModifyWrite(ctx, u.Email, rmw)
	if err != nil {
		return &appError{err, "Error applying ReadModifyWrite to row: " + u.Email, http.StatusInternalServerError}
	}
	data := struct {
		Username, Logout string
		Visits           uint64
	}{
		Username: u.Email,
		// Retrieve the most recently edited column.
		Visits: binary.BigEndian.Uint64(row[familyName][0].Value),
		Logout: logoutURL,
	}
	var buf bytes.Buffer
	if err := tmpl.Execute(&buf, data); err != nil {
		return &appError{err, "Error writing template", http.StatusInternalServerError}
	}
	buf.WriteTo(w)
	return nil
}

var tmpl = template.Must(template.New("").Parse(`

{{with .Username}} Hello {{.}}{{end}}
{{with .Logout}}Sign out{{end}}

You have visited {{.Visits}}

`))

// sliceContains reports whether the provided string is present in the given slice of strings.
func sliceContains(list []string, target string) bool {
	for _, s := range list {
		if s == target {
			return true
		}
	}
	return false
}

// More info about this method of error handling can be found at: http://blog.golang.org/error-handling-and-go
type appHandler func(http.ResponseWriter, *http.Request) *appError

type appError struct {
	Error   error
	Message string
	Code    int
}

func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if e := fn(w, r); e != nil {
		ctx := appengine.NewContext(r)
		aelog.Errorf(ctx, "%v", e.Error)
		http.Error(w, e.Message, e.Code)
	}
}
<|endoftext|>