<commit_before>// Copyright 2017 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.

package cache

import (
	"fmt"

	"github.com/google/trillian/merkle/compact"
	"github.com/google/trillian/merkle/hashers"
	"github.com/google/trillian/storage"
	"github.com/google/trillian/storage/storagepb"
)

// NewLogSubtreeCache creates and returns a SubtreeCache appropriate for use with a log
// tree. The caller must supply the strata depths to be used and a suitable LogHasher.
func NewLogSubtreeCache(logStrata []int, hasher hashers.LogHasher) SubtreeCache {
	return NewSubtreeCache(logStrata, populateLogSubtreeNodes(hasher), prepareLogSubtreeWrite())
}

// LogPopulateFunc obtains a log storage population function based on a supplied LogHasher.
// This is intended for use by storage utilities.
func LogPopulateFunc(hasher hashers.LogHasher) storage.PopulateSubtreeFunc {
	return populateLogSubtreeNodes(hasher)
}

// populateLogSubtreeNodes re-creates a Log subtree's InternalNodes from the
// subtree Leaves map.
//
// This uses the compact Merkle tree to repopulate internal nodes, and so will
// handle imperfect (but left-hand dense) subtrees. Note that we only rebuild internal
// nodes when the subtree is fully populated. For an explanation of why see the comments
// below for PrepareLogSubtreeWrite.
func populateLogSubtreeNodes(hasher hashers.LogHasher) storage.PopulateSubtreeFunc {
	return func(st *storagepb.SubtreeProto) error {
		cmt := compact.NewTree(hasher)
		if st.Depth < 1 {
			return fmt.Errorf("populate log subtree with invalid depth: %d", st.Depth)
		}
		// maxLeaves is the number of leaves that fully populates a subtree of the depth we are
		// working with.
		maxLeaves := 1 << uint(st.Depth)

		// If the subtree is fully populated then the internal node map is expected to be nil but in
		// case it isn't we recreate it as we're about to rebuild the contents. We'll check
		// below that the number of nodes is what we expected to have.
		if st.InternalNodes == nil || len(st.Leaves) == maxLeaves {
			st.InternalNodes = make(map[string][]byte)
		}

		// We need to update the subtree root hash regardless of whether it's fully populated
		for leafIndex := int64(0); leafIndex < int64(len(st.Leaves)); leafIndex++ {
			nodeID := storage.NewNodeIDFromPrefix(st.Prefix, logStrataDepth, leafIndex, logStrataDepth, maxLogDepth)
			_, sfx := nodeID.Split(len(st.Prefix), int(st.Depth))
			sfxKey := sfx.String()
			h := st.Leaves[sfxKey]
			if h == nil {
				return fmt.Errorf("unexpectedly got nil for subtree leaf suffix %s", sfx)
			}
			seq, err := cmt.AddLeafHash(h, func(height int, index int64, h []byte) error {
				if height == logStrataDepth && index == 0 {
					// no space for the root in the node cache
					return nil
				}

				subDepth := logStrataDepth - height
				nodeID := storage.NewNodeIDFromPrefix(st.Prefix, subDepth, index, logStrataDepth, maxLogDepth)
				_, sfx := nodeID.Split(len(st.Prefix), int(st.Depth))
				sfxKey := sfx.String()
				// Don't put leaves into the internal map and only update if we're rebuilding internal
				// nodes. If the subtree was saved with internal nodes then we don't touch the map.
				if height > 0 && len(st.Leaves) == maxLeaves {
					st.InternalNodes[sfxKey] = h
				}
				return nil
			})
			if err != nil {
				return err
			}
			if got, expected := seq, leafIndex; got != expected {
				return fmt.Errorf("got seq of %d, but expected %d", got, expected)
			}
		}
		st.RootHash = cmt.CurrentRoot()

		// Additional check - after population we should have the same number of internal nodes
		// as before the subtree was written to storage. Either because they were loaded from
		// storage or just rebuilt above.
		if got, want := uint32(len(st.InternalNodes)), st.InternalNodeCount; got != want {
			// TODO(Martin2112): Possibly replace this with stronger checks on the data in
			// subtrees on disk so we can detect corruption.
			return fmt.Errorf("log repop got: %d internal nodes, want: %d", got, want)
		}

		return nil
	}
}

// prepareLogSubtreeWrite prepares a log subtree for writing. If the subtree is fully
// populated the internal nodes are cleared. Otherwise they are written.
//
// To see why this is necessary consider the case where a tree has a single full subtree
// and then an additional leaf is added.
//
// This causes an extra level to be added to the tree with an internal node that is a hash
// of the root of the left full subtree and the new leaf. Note that the leaves remain at
// level zero in the overall tree coordinate space but they are now in a lower subtree stratum
// than they were before the last node was added as the tree has grown above them.
//
// Thus in the case just discussed the internal nodes cannot be correctly reconstructed
// in isolation when the tree is reloaded because of the dependency on another subtree.
//
// Fully populated subtrees don't have this problem because by definition they can only
// contain internal nodes built from their own contents.
func prepareLogSubtreeWrite() storage.PrepareSubtreeWriteFunc {
	return func(st *storagepb.SubtreeProto) error {
		st.InternalNodeCount = uint32(len(st.InternalNodes))
		if st.Depth < 1 {
			return fmt.Errorf("prepare subtree for log write invalid depth: %d", st.Depth)
		}
		maxLeaves := 1 << uint(st.Depth)
		// If the subtree is fully populated we can safely clear the internal nodes
		if len(st.Leaves) == maxLeaves {
			st.InternalNodes = nil
		}
		return nil
	}
}
<commit_msg>Small subtree cache optimization.<commit_after>// Copyright 2017 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.

package cache

import (
	"fmt"

	"github.com/google/trillian/merkle/compact"
	"github.com/google/trillian/merkle/hashers"
	"github.com/google/trillian/storage"
	"github.com/google/trillian/storage/storagepb"
)

// NewLogSubtreeCache creates and returns a SubtreeCache appropriate for use with a log
// tree. The caller must supply the strata depths to be used and a suitable LogHasher.
func NewLogSubtreeCache(logStrata []int, hasher hashers.LogHasher) SubtreeCache {
	return NewSubtreeCache(logStrata, populateLogSubtreeNodes(hasher), prepareLogSubtreeWrite())
}

// LogPopulateFunc obtains a log storage population function based on a supplied LogHasher.
// This is intended for use by storage utilities.
func LogPopulateFunc(hasher hashers.LogHasher) storage.PopulateSubtreeFunc {
	return populateLogSubtreeNodes(hasher)
}

// populateLogSubtreeNodes re-creates a Log subtree's InternalNodes from the
// subtree Leaves map.
//
// This uses the compact Merkle tree to repopulate internal nodes, and so will
// handle imperfect (but left-hand dense) subtrees. Note that we only rebuild internal
// nodes when the subtree is fully populated. For an explanation of why see the comments
// below for PrepareLogSubtreeWrite.
func populateLogSubtreeNodes(hasher hashers.LogHasher) storage.PopulateSubtreeFunc {
	return func(st *storagepb.SubtreeProto) error {
		cmt := compact.NewTree(hasher)
		if st.Depth < 1 {
			return fmt.Errorf("populate log subtree with invalid depth: %d", st.Depth)
		}
		// maxLeaves is the number of leaves that fully populates a subtree of the depth we are
		// working with.
		maxLeaves := 1 << uint(st.Depth)

		// If the subtree is fully populated then the internal node map is expected to be nil but in
		// case it isn't we recreate it as we're about to rebuild the contents. We'll check
		// below that the number of nodes is what we expected to have.
		if st.InternalNodes == nil || len(st.Leaves) == maxLeaves {
			st.InternalNodes = make(map[string][]byte)
		}

		// We need to update the subtree root hash regardless of whether it's fully populated
		for leafIndex := int64(0); leafIndex < int64(len(st.Leaves)); leafIndex++ {
			nodeID := storage.NewNodeIDFromPrefix(st.Prefix, logStrataDepth, leafIndex, logStrataDepth, maxLogDepth)
			_, sfx := nodeID.Split(len(st.Prefix), int(st.Depth))
			sfxKey := sfx.String()
			h := st.Leaves[sfxKey]
			if h == nil {
				return fmt.Errorf("unexpectedly got nil for subtree leaf suffix %s", sfx)
			}
			seq, err := cmt.AddLeafHash(h, func(height int, index int64, h []byte) error {
				if height == logStrataDepth && index == 0 {
					// no space for the root in the node cache
					return nil
				}

				// Don't put leaves into the internal map and only update if we're rebuilding internal
				// nodes. If the subtree was saved with internal nodes then we don't touch the map.
				if height > 0 && len(st.Leaves) == maxLeaves {
					subDepth := logStrataDepth - height
					nodeID := storage.NewNodeIDFromPrefix(st.Prefix, subDepth, index, logStrataDepth, maxLogDepth)
					_, sfx := nodeID.Split(len(st.Prefix), int(st.Depth))
					sfxKey := sfx.String()
					st.InternalNodes[sfxKey] = h
				}
				return nil
			})
			if err != nil {
				return err
			}
			if got, expected := seq, leafIndex; got != expected {
				return fmt.Errorf("got seq of %d, but expected %d", got, expected)
			}
		}
		st.RootHash = cmt.CurrentRoot()

		// Additional check - after population we should have the same number of internal nodes
		// as before the subtree was written to storage. Either because they were loaded from
		// storage or just rebuilt above.
		if got, want := uint32(len(st.InternalNodes)), st.InternalNodeCount; got != want {
			// TODO(Martin2112): Possibly replace this with stronger checks on the data in
			// subtrees on disk so we can detect corruption.
			return fmt.Errorf("log repop got: %d internal nodes, want: %d", got, want)
		}

		return nil
	}
}

// prepareLogSubtreeWrite prepares a log subtree for writing. If the subtree is fully
// populated the internal nodes are cleared. Otherwise they are written.
//
// To see why this is necessary consider the case where a tree has a single full subtree
// and then an additional leaf is added.
//
// This causes an extra level to be added to the tree with an internal node that is a hash
// of the root of the left full subtree and the new leaf. Note that the leaves remain at
// level zero in the overall tree coordinate space but they are now in a lower subtree stratum
// than they were before the last node was added as the tree has grown above them.
//
// Thus in the case just discussed the internal nodes cannot be correctly reconstructed
// in isolation when the tree is reloaded because of the dependency on another subtree.
//
// Fully populated subtrees don't have this problem because by definition they can only
// contain internal nodes built from their own contents.
func prepareLogSubtreeWrite() storage.PrepareSubtreeWriteFunc {
	return func(st *storagepb.SubtreeProto) error {
		st.InternalNodeCount = uint32(len(st.InternalNodes))
		if st.Depth < 1 {
			return fmt.Errorf("prepare subtree for log write invalid depth: %d", st.Depth)
		}
		maxLeaves := 1 << uint(st.Depth)
		// If the subtree is fully populated we can safely clear the internal nodes
		if len(st.Leaves) == maxLeaves {
			st.InternalNodes = nil
		}
		return nil
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The OpenEBS 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 command

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
	"github.com/openebs/maya/pkg/client/mapiserver"
	"github.com/openebs/maya/pkg/util"
	"github.com/spf13/cobra"
)

// VolumeInfo stores the volume information
type VolumeInfo struct {
	Volume v1alpha1.CASVolume
}

// CmdVolumeOptions stores information of volume being operated
type CmdVolumeOptions struct {
	volName          string
	sourceVolumeName string
	snapshotName     string
	size             string
	namespace        string
	json             string
}

// CASType is engine type
type CASType string

const (
	// VolumeAPIPath is the api path to get volume information
	VolumeAPIPath      = "/latest/volumes/"
	controllerStatusOk = "running"
	volumeStatusOK     = "Running"
	// JivaStorageEngine is constant for jiva engine
	JivaStorageEngine CASType = "jiva"
	// CstorStorageEngine is constant for cstor engine
	CstorStorageEngine CASType = "cstor"
	timeout                    = 5 * time.Second
)

var (
	volumeCommandHelpText = `
The following commands helps in operating a Volume such as create, list, and so on.

Usage: mayactl volume <subcommand> [options] [args]

Examples:

 # Create a Volume:
   $ mayactl volume create --volname <vol> --size <size>

 # List Volumes:
   $ mayactl volume list

 # Delete a Volume:
   $ mayactl volume delete --volname <vol>

 # Delete a Volume created in 'test' namespace:
   $ mayactl volume delete --volname <vol> --namespace test

 # Statistics of a Volume:
   $ mayactl volume stats --volname <vol>

 # Statistics of a Volume created in 'test' namespace:
   $ mayactl volume stats --volname <vol> --namespace test

 # Info of a Volume:
   $ mayactl volume info --volname <vol>

 # Info of a Volume created in 'test' namespace:
   $ mayactl volume info --volname <vol> --namespace test
`
	options = &CmdVolumeOptions{
		namespace: "default",
	}
)

// NewCmdVolume provides options for managing OpenEBS Volume
func NewCmdVolume() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "volume",
		Short: "Provides operations related to a Volume",
		Long:  volumeCommandHelpText,
	}

	cmd.AddCommand(
		NewCmdVolumeCreate(),
		NewCmdVolumesList(),
		NewCmdVolumeDelete(),
		NewCmdVolumeStats(),
		NewCmdVolumeInfo(),
	)
	cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace,
		"namespace name, required if volume is not in the default namespace")

	cmd.PersistentFlags().AddGoFlagSet(flag.CommandLine)
	flag.CommandLine.Parse([]string{})
	return cmd
}

// Validate verifies whether a volume name,source name or snapshot name is provided or not followed by
// stats command. It returns nil and proceeds to execute the command if there is
// no error and returns an error if it is missing.
func (c *CmdVolumeOptions) Validate(cmd *cobra.Command, snapshotnameverify, sourcenameverify, volnameverify bool) error {
	if snapshotnameverify {
		if len(c.snapshotName) == 0 {
			return errors.New("--snapname is missing. Please provide a snapshotname")
		}
	}
	if sourcenameverify {
		if len(c.sourceVolumeName) == 0 {
			return errors.New("--sourcevol is missing. Please specify a sourcevolumename")
		}
	}
	if volnameverify {
		if len(c.volName) == 0 {
			return errors.New("--volname is missing. Please specify a unique volumename")
		}
	}
	return nil
}

// NewVolumeInfo fetches and fills CASVolume structure from URL given to it
func NewVolumeInfo(URL string, volname string, namespace string) (volInfo *VolumeInfo, err error) {
	url := URL
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}
	req.Header.Set("namespace", namespace)

	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		fmt.Printf("Can't get a response, error found: %v", err)
		return
	}
	if resp != nil && resp.StatusCode != 200 {
		if resp.StatusCode == 500 {
			fmt.Printf("Volume: %s not found at namespace: %q\n", volname, namespace)
			err = util.InternalServerError
		} else if resp.StatusCode == 503 {
			fmt.Printf("maya apiservice not reachable at %q\n", mapiserver.GetURL())
			err = util.ServerUnavailable
		} else if resp.StatusCode == 404 {
			fmt.Printf("Volume: %s not found at namespace: %q error: %s\n", volname, namespace, http.StatusText(resp.StatusCode))
			err = util.PageNotFound
		}
		fmt.Printf("Received an error from maya apiservice: statuscode: %d", resp.StatusCode)
		err = fmt.Errorf("Received an error from maya apiservice: statuscode: %d", resp.StatusCode)
		return
	}
	defer resp.Body.Close()
	casVol := v1alpha1.CASVolume{}
	err = json.NewDecoder(resp.Body).Decode(&casVol)
	if err != nil {
		fmt.Printf("Response decode failed: error '%+v'", err)
		return
	}
	if casVol.Status.Reason == "pending" {
		fmt.Println("VOLUME status Unknown to maya apiservice")
		err = fmt.Errorf("VOLUME status Unknown to maya apiservice")
		return
	}
	volInfo = &VolumeInfo{
		Volume: casVol,
	}
	return
}

// GetCASType returns the CASType of the volume in lowercase
func (volInfo *VolumeInfo) GetCASType() string {
	if len(volInfo.Volume.Spec.CasType) == 0 {
		return string(JivaStorageEngine)
	}
	return strings.ToLower(volInfo.Volume.Spec.CasType)
}

// GetClusterIP returns the ClusterIP of the cluster
func (volInfo *VolumeInfo) GetClusterIP() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/cluster-ips"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/cluster-ips"]; ok {
		return val
	}
	return ""
}

// GetControllerStatus returns the status of the volume controller
func (volInfo *VolumeInfo) GetControllerStatus() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/controller-status"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/controller-status"]; ok {
		return val
	}
	return ""
}

// GetIQN returns the IQN of the volume
func (volInfo *VolumeInfo) GetIQN() string {
	if len(volInfo.Volume.Spec.Iqn) > 0 {
		return volInfo.Volume.Spec.Iqn
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/iqn"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/iqn"]; ok {
		return val
	}
	return ""

}

// GetVolumeName returns the volume name
func (volInfo *VolumeInfo) GetVolumeName() string {
	return volInfo.Volume.ObjectMeta.Name
}

// GetTargetPortal returns the TargetPortal of the volume
func (volInfo *VolumeInfo) GetTargetPortal() string {
	if len(volInfo.Volume.Spec.TargetPortal) > 0 {
		return volInfo.Volume.Spec.TargetPortal
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/targetportals"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/targetportals"]; ok {
		return val
	}
	return ""
}

// GetVolumeSize returns the capacity of the volume
func (volInfo *VolumeInfo) GetVolumeSize() string {
	if len(volInfo.Volume.Spec.Capacity) > 0 {
		return volInfo.Volume.Spec.Capacity
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/volume-size"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/volume-size"]; ok {
		return val
	}
	return ""
}

// GetReplicaCount returns the volume replica count
func (volInfo *VolumeInfo) GetReplicaCount() string {
	if len(volInfo.Volume.Spec.Replicas) > 0 {
		return volInfo.Volume.Spec.Replicas
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-count"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-count"]; ok {
		return val
	}
	return ""
}

// GetReplicaStatus returns the replica status of the volume replica
func (volInfo *VolumeInfo) GetReplicaStatus() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-status"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-status"]; ok {
		return val
	}
	return ""
}

// GetReplicaIP returns the IP of volume replica
func (volInfo *VolumeInfo) GetReplicaIP() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-ips"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-ips"]; ok {
		return val
	}
	return ""
}
<commit_msg>Disabled volume create and delete command in mayactl<commit_after>/*
Copyright 2017 The OpenEBS 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 command

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/openebs/maya/pkg/apis/openebs.io/v1alpha1"
	"github.com/openebs/maya/pkg/client/mapiserver"
	"github.com/openebs/maya/pkg/util"
	"github.com/spf13/cobra"
)

// VolumeInfo stores the volume information
type VolumeInfo struct {
	Volume v1alpha1.CASVolume
}

// CmdVolumeOptions stores information of volume being operated
type CmdVolumeOptions struct {
	volName          string
	sourceVolumeName string
	snapshotName     string
	size             string
	namespace        string
	json             string
}

// CASType is engine type
type CASType string

const (
	// VolumeAPIPath is the api path to get volume information
	VolumeAPIPath      = "/latest/volumes/"
	controllerStatusOk = "running"
	volumeStatusOK     = "Running"
	// JivaStorageEngine is constant for jiva engine
	JivaStorageEngine CASType = "jiva"
	// CstorStorageEngine is constant for cstor engine
	CstorStorageEngine CASType = "cstor"
	timeout                    = 5 * time.Second
)

// # Create a Volume:
// $ mayactl volume create --volname <vol> --size <size>

var (
	volumeCommandHelpText = `
The following commands helps in operating a Volume such as create, list, and so on.

Usage: mayactl volume <subcommand> [options] [args]

Examples:
 # List Volumes:
   $ mayactl volume list

 # Statistics of a Volume:
   $ mayactl volume stats --volname <vol>

 # Statistics of a Volume created in 'test' namespace:
   $ mayactl volume stats --volname <vol> --namespace test

 # Info of a Volume:
   $ mayactl volume info --volname <vol>

 # Info of a Volume created in 'test' namespace:
   $ mayactl volume info --volname <vol> --namespace test

 # Delete a Volume:
   $ mayactl volume delete --volname <vol>

 # Delete a Volume created in 'test' namespace:
   $ mayactl volume delete --volname <vol> --namespace test
`
	options = &CmdVolumeOptions{
		namespace: "default",
	}
)

// NewCmdVolume provides options for managing OpenEBS Volume
func NewCmdVolume() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "volume",
		Short: "Provides operations related to a Volume",
		Long:  volumeCommandHelpText,
	}

	cmd.AddCommand(
		// NewCmdVolumeCreate(),
		NewCmdVolumesList(),
		NewCmdVolumeDelete(),
		NewCmdVolumeStats(),
		NewCmdVolumeInfo(),
	)
	cmd.PersistentFlags().StringVarP(&options.namespace, "namespace", "n", options.namespace,
		"namespace name, required if volume is not in the default namespace")

	cmd.PersistentFlags().AddGoFlagSet(flag.CommandLine)
	flag.CommandLine.Parse([]string{})
	return cmd
}

// Validate verifies whether a volume name,source name or snapshot name is provided or not followed by
// stats command. It returns nil and proceeds to execute the command if there is
// no error and returns an error if it is missing.
func (c *CmdVolumeOptions) Validate(cmd *cobra.Command, snapshotnameverify, sourcenameverify, volnameverify bool) error {
	if snapshotnameverify {
		if len(c.snapshotName) == 0 {
			return errors.New("--snapname is missing. Please provide a snapshotname")
		}
	}
	if sourcenameverify {
		if len(c.sourceVolumeName) == 0 {
			return errors.New("--sourcevol is missing. Please specify a sourcevolumename")
		}
	}
	if volnameverify {
		if len(c.volName) == 0 {
			return errors.New("--volname is missing. Please specify a unique volumename")
		}
	}
	return nil
}

// NewVolumeInfo fetches and fills CASVolume structure from URL given to it
func NewVolumeInfo(URL string, volname string, namespace string) (volInfo *VolumeInfo, err error) {
	url := URL
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return
	}
	req.Header.Set("namespace", namespace)

	c := &http.Client{
		Timeout: timeout,
	}
	resp, err := c.Do(req)
	if err != nil {
		fmt.Printf("Can't get a response, error found: %v", err)
		return
	}
	if resp != nil && resp.StatusCode != 200 {
		if resp.StatusCode == 500 {
			fmt.Printf("Volume: %s not found at namespace: %q\n", volname, namespace)
			err = util.InternalServerError
		} else if resp.StatusCode == 503 {
			fmt.Printf("maya apiservice not reachable at %q\n", mapiserver.GetURL())
			err = util.ServerUnavailable
		} else if resp.StatusCode == 404 {
			fmt.Printf("Volume: %s not found at namespace: %q error: %s\n", volname, namespace, http.StatusText(resp.StatusCode))
			err = util.PageNotFound
		}
		fmt.Printf("Received an error from maya apiservice: statuscode: %d", resp.StatusCode)
		err = fmt.Errorf("Received an error from maya apiservice: statuscode: %d", resp.StatusCode)
		return
	}
	defer resp.Body.Close()
	casVol := v1alpha1.CASVolume{}
	err = json.NewDecoder(resp.Body).Decode(&casVol)
	if err != nil {
		fmt.Printf("Response decode failed: error '%+v'", err)
		return
	}
	if casVol.Status.Reason == "pending" {
		fmt.Println("VOLUME status Unknown to maya apiservice")
		err = fmt.Errorf("VOLUME status Unknown to maya apiservice")
		return
	}
	volInfo = &VolumeInfo{
		Volume: casVol,
	}
	return
}

// GetCASType returns the CASType of the volume in lowercase
func (volInfo *VolumeInfo) GetCASType() string {
	if len(volInfo.Volume.Spec.CasType) == 0 {
		return string(JivaStorageEngine)
	}
	return strings.ToLower(volInfo.Volume.Spec.CasType)
}

// GetClusterIP returns the ClusterIP of the cluster
func (volInfo *VolumeInfo) GetClusterIP() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/cluster-ips"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/cluster-ips"]; ok {
		return val
	}
	return ""
}

// GetControllerStatus returns the status of the volume controller
func (volInfo *VolumeInfo) GetControllerStatus() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/controller-status"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/controller-status"]; ok {
		return val
	}
	return ""
}

// GetIQN returns the IQN of the volume
func (volInfo *VolumeInfo) GetIQN() string {
	if len(volInfo.Volume.Spec.Iqn) > 0 {
		return volInfo.Volume.Spec.Iqn
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/iqn"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/iqn"]; ok {
		return val
	}
	return ""

}

// GetVolumeName returns the volume name
func (volInfo *VolumeInfo) GetVolumeName() string {
	return volInfo.Volume.ObjectMeta.Name
}

// GetTargetPortal returns the TargetPortal of the volume
func (volInfo *VolumeInfo) GetTargetPortal() string {
	if len(volInfo.Volume.Spec.TargetPortal) > 0 {
		return volInfo.Volume.Spec.TargetPortal
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/targetportals"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/targetportals"]; ok {
		return val
	}
	return ""
}

// GetVolumeSize returns the capacity of the volume
func (volInfo *VolumeInfo) GetVolumeSize() string {
	if len(volInfo.Volume.Spec.Capacity) > 0 {
		return volInfo.Volume.Spec.Capacity
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/volume-size"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/volume-size"]; ok {
		return val
	}
	return ""
}

// GetReplicaCount returns the volume replica count
func (volInfo *VolumeInfo) GetReplicaCount() string {
	if len(volInfo.Volume.Spec.Replicas) > 0 {
		return volInfo.Volume.Spec.Replicas
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-count"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-count"]; ok {
		return val
	}
	return ""
}

// GetReplicaStatus returns the replica status of the volume replica
func (volInfo *VolumeInfo) GetReplicaStatus() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-status"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-status"]; ok {
		return val
	}
	return ""
}

// GetReplicaIP returns the IP of volume replica
func (volInfo *VolumeInfo) GetReplicaIP() string {
	if val, ok := volInfo.Volume.ObjectMeta.Annotations["openebs.io/replica-ips"]; ok {
		return val
	} else if val, ok := volInfo.Volume.ObjectMeta.Annotations["vsm.openebs.io/replica-ips"]; ok {
		return val
	}
	return ""
}
<|endoftext|>


<commit_before>// Copyright 2016 Hajime Hoshi
//
// 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 wav

import (
	"bytes"
	"fmt"
	"io"

	"github.com/hajimehoshi/ebiten/exp/audio"
)

type Stream struct {
	src        audio.ReadSeekCloser
	headerSize int64
	dataSize   int64
}

func (s *Stream) Read(p []byte) (int, error) {
	return s.src.Read(p)
}

func (s *Stream) Seek(offset int64, whence int) (int64, error) {
	if whence == 0 {
		offset += s.headerSize
	}
	return s.src.Seek(offset, whence)
}

func (s *Stream) Close() error {
	return s.src.Close()
}

func (s *Stream) Size() int64 {
	return s.dataSize
}

func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) {
	buf := make([]byte, 12)
	n, err := io.ReadFull(src, buf)
	if n != len(buf) {
		return nil, fmt.Errorf("wav: invalid header")
	}
	if err != nil {
		return nil, err
	}
	if !bytes.Equal(buf[0:4], []byte("RIFF")) {
		return nil, fmt.Errorf("wav: invalid header: 'RIFF' not found")
	}
	if !bytes.Equal(buf[8:12], []byte("WAVE")) {
		return nil, fmt.Errorf("wav: invalid header: 'WAVE' not found")
	}

	// Read chunks
	dataSize := int64(0)
	headerSize := int64(0)
chunks:
	for {
		buf := make([]byte, 8)
		n, err := io.ReadFull(src, buf)
		if n != len(buf) {
			return nil, fmt.Errorf("wav: invalid header")
		}
		if err != nil {
			return nil, err
		}
		headerSize += 8
		size := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7]<<24)
		switch {
		case bytes.Equal(buf[0:4], []byte("fmt ")):
			if size != 16 {
				return nil, fmt.Errorf("wav: invalid header: maybe non-PCM file?")
			}
			buf := make([]byte, size)
			n, err := io.ReadFull(src, buf)
			if n != len(buf) {
				return nil, fmt.Errorf("wav: invalid header")
			}
			if err != nil {
				return nil, err
			}
			// TODO: Remove this magic number
			if buf[2] != 2 {
				return nil, fmt.Errorf("wav: invalid header: channel num must be 2")
			}
			// TODO: Remove this magic number
			if buf[14] != 16 {
				return nil, fmt.Errorf("wav: invalid header: depth must be 16")
			}
			sampleRate := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7]<<24)
			if int64(context.SampleRate()) != sampleRate {
				return nil, fmt.Errorf("wav: sample rate must be %d but %d", context.SampleRate(), sampleRate)
			}
			headerSize += size
		case bytes.Equal(buf[0:4], []byte("data")):
			dataSize = size
			break chunks
		default:
			buf := make([]byte, size)
			n, err := io.ReadFull(src, buf)
			if n != len(buf) {
				return nil, fmt.Errorf("wav: invalid header")
			}
			if err != nil {
				return nil, err
			}
			headerSize += size
		}
	}
	s := &Stream{
		src:        src,
		headerSize: headerSize,
		dataSize:   dataSize,
	}
	return s, nil
}
<commit_msg>audio/wav: Parse header more accurately<commit_after>// Copyright 2016 Hajime Hoshi
//
// 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 wav

import (
	"bytes"
	"fmt"
	"io"

	"github.com/hajimehoshi/ebiten/exp/audio"
)

type Stream struct {
	src        audio.ReadSeekCloser
	headerSize int64
	dataSize   int64
}

func (s *Stream) Read(p []byte) (int, error) {
	return s.src.Read(p)
}

func (s *Stream) Seek(offset int64, whence int) (int64, error) {
	if whence == 0 {
		offset += s.headerSize
	}
	return s.src.Seek(offset, whence)
}

func (s *Stream) Close() error {
	return s.src.Close()
}

func (s *Stream) Size() int64 {
	return s.dataSize
}

func Decode(context *audio.Context, src audio.ReadSeekCloser) (*Stream, error) {
	buf := make([]byte, 12)
	n, err := io.ReadFull(src, buf)
	if n != len(buf) {
		return nil, fmt.Errorf("wav: invalid header")
	}
	if err != nil {
		return nil, err
	}
	if !bytes.Equal(buf[0:4], []byte("RIFF")) {
		return nil, fmt.Errorf("wav: invalid header: 'RIFF' not found")
	}
	if !bytes.Equal(buf[8:12], []byte("WAVE")) {
		return nil, fmt.Errorf("wav: invalid header: 'WAVE' not found")
	}

	// Read chunks
	dataSize := int64(0)
	headerSize := int64(0)
chunks:
	for {
		buf := make([]byte, 8)
		n, err := io.ReadFull(src, buf)
		if n != len(buf) {
			return nil, fmt.Errorf("wav: invalid header")
		}
		if err != nil {
			return nil, err
		}
		headerSize += 8
		size := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7]<<24)
		switch {
		case bytes.Equal(buf[0:4], []byte("fmt ")):
			if size != 16 {
				return nil, fmt.Errorf("wav: invalid header: maybe non-PCM file?")
			}
			buf := make([]byte, size)
			n, err := io.ReadFull(src, buf)
			if n != len(buf) {
				return nil, fmt.Errorf("wav: invalid header")
			}
			if err != nil {
				return nil, err
			}
			format := int(buf[0]) | int(buf[1])<<8
			if format != 1 {
				return nil, fmt.Errorf("wav: format must be linear PCM")
			}
			channelNum := int(buf[2]) | int(buf[3])<<8
			// TODO: Remove this magic number
			if channelNum != 2 {
				return nil, fmt.Errorf("wav: channel num must be 2")
			}
			bitsPerSample := int(buf[14]) | int(buf[15])<<8
			// TODO: Remove this magic number
			if bitsPerSample != 16 {
				return nil, fmt.Errorf("wav: bits per sample must be 16")
			}
			sampleRate := int64(buf[4]) | int64(buf[5])<<8 | int64(buf[6])<<16 | int64(buf[7]<<24)
			if int64(context.SampleRate()) != sampleRate {
				return nil, fmt.Errorf("wav: sample rate must be %d but %d", context.SampleRate(), sampleRate)
			}
			headerSize += size
		case bytes.Equal(buf[0:4], []byte("data")):
			dataSize = size
			break chunks
		default:
			buf := make([]byte, size)
			n, err := io.ReadFull(src, buf)
			if n != len(buf) {
				return nil, fmt.Errorf("wav: invalid header")
			}
			if err != nil {
				return nil, err
			}
			headerSize += size
		}
	}
	s := &Stream{
		src:        src,
		headerSize: headerSize,
		dataSize:   dataSize,
	}
	return s, nil
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Apcera Inc. All rights reserved.

package test

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/nats-io/nats"
)

func TestServerRestartReSliceIssue(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// msg to send..
	msg := []byte("Hello World")

	servers := []string{urlA, urlB}

	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000

	reconnects := int32(0)
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		atomic.AddInt32(&reconnects, 1)
		reconnectsDone <- true
	}

	// Create 20 random clients.
	// Half connected to A and half to B..
	numClients := 20
	for i := 0; i < numClients; i++ {
		opts.Url = servers[i%2]
		nc, err := opts.Connect()
		defer nc.Close()

		if err != nil {
			t.Fatalf("Failed to create connection: %v\n", err)
		}
		// Create 10 subscriptions each..
		for x := 0; x < 10; x++ {
			subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
			nc.Subscribe(subject, func(m *nats.Msg) {
				// Just eat it..
			})
		}
		// Pick one subject to send to..
		subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
		go func() {
			time.Sleep(10 * time.Millisecond)
			for i := 1; 1 <= 100; i++ {
				if err := nc.Publish(subject, msg); err != nil {
					return
				}
				if i%10 == 0 {
					time.Sleep(time.Millisecond)
				}
			}
		}()
	}

	// Wait for a short bit..
	time.Sleep(20 * time.Millisecond)

	// Restart SrvB
	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	select {
	case <-reconnectsDone:
		break
	case <-time.After(2 * time.Second):
		t.Fatalf("Expected %d reconnects, got %d\n", numClients/2, reconnects)
	}
}

// This will test queue subscriber semantics across a cluster in the presence
// of server restarts.
func TestServerRestartAndQueueSubs(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// Client options
	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000
	opts.NoRandomize = true

	// Allow us to block on a reconnect completion.
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		reconnectsDone <- true
	}

	// Helper to wait on a reconnect.
	waitOnReconnect := func() {
		var rcs int64
		for {
			select {
			case <-reconnectsDone:
				atomic.AddInt64(&rcs, 1)
				if rcs >= 2 {
					return
				}
			case <-time.After(2 * time.Second):
				t.Fatalf("Expected a reconnect, timedout!\n")
			}
		}
	}

	// Create two clients..
	opts.Servers = []string{urlA}
	nc1, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	opts.Servers = []string{urlB}
	nc2, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}

	c1, _ := nats.NewEncodedConn(nc1, "json")
	defer c1.Close()
	c2, _ := nats.NewEncodedConn(nc2, "json")
	defer c2.Close()

	// Flusher helper function.
	flush := func() {
		// Wait for processing.
		c1.Flush()
		c2.Flush()
		// Wait for a short bit for cluster propogation.
		time.Sleep(50 * time.Millisecond)
	}

	// To hold queue results.
	results := make(map[int]int)
	var mu sync.Mutex

	// This corresponds to the subsriptions below.
	const ExpectedMsgCount = 3

	// Make sure we got what we needed, 1 msg only and all seqnos accounted for..
	checkResults := func(numSent int) {
		mu.Lock()
		defer mu.Unlock()

		for i := 0; i < numSent; i++ {
			if results[i] != ExpectedMsgCount {
				t.Fatalf("Received incorrect number of messages, [%d] for seq: %d\n", results[i], i)
			}
		}

		// Auto reset results map
		results = make(map[int]int)
	}

	subj := "foo.bar"
	qgroup := "workers"

	cb := func(seqno int) {
		mu.Lock()
		defer mu.Unlock()
		results[seqno] = results[seqno] + 1
	}

	// Create queue subscribers
	c1.QueueSubscribe(subj, qgroup, cb)
	c2.QueueSubscribe(subj, qgroup, cb)

	// Do a wildcard subscription.
	c1.Subscribe("foo.*", cb)
	c2.Subscribe("foo.*", cb)

	// Wait for processing.
	flush()

	sendAndCheckMsgs := func(numToSend int) {
		for i := 0; i < numToSend; i++ {
			if i%2 == 0 {
				c1.Publish(subj, i)
			} else {
				c2.Publish(subj, i)
			}
		}
		// Wait for processing.
		flush()
		// Check Results
		checkResults(numToSend)
	}

	////////////////////////////////////////////////////////////////////////////
	// Base Test
	////////////////////////////////////////////////////////////////////////////

	// Now send 10 messages, from each client..
	sendAndCheckMsgs(10)

	////////////////////////////////////////////////////////////////////////////
	// Now restart SrvA and srvB, re-run test
	////////////////////////////////////////////////////////////////////////////

	srvA.Shutdown()
	srvA = RunServer(optsA)
	defer srvA.Shutdown()

	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	waitOnReconnect()

	time.Sleep(50 * time.Millisecond)

	// Now send another 10 messages, from each client..
	sendAndCheckMsgs(10)
}

// This will test request semantics across a route
func TestRequestsAcrossRoutes(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect responder to srvA
	nc1.Subscribe("foo-req", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}

// This will test request semantics across a route to queues
func TestRequestsAcrossRoutesToQueues(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec1, _ := nats.NewEncodedConn(nc1, nats.JSON_ENCODER)
	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect one responder to srvA
	nc1.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	// Connect the other responder to srvB
	nc2.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc2.Publish(m.Reply, response)
	})

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}

	for i := 0; i < 100; i++ {
		if err := ec1.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}
<commit_msg>Fix test that was failing on Windows.<commit_after>// Copyright 2013-2014 Apcera Inc. All rights reserved.

package test

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"testing"
	"time"

	"github.com/nats-io/nats"
)

func TestServerRestartReSliceIssue(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// msg to send..
	msg := []byte("Hello World")

	servers := []string{urlA, urlB}

	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000

	reconnects := int32(0)
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		atomic.AddInt32(&reconnects, 1)
		reconnectsDone <- true
	}

	// Create 20 random clients.
	// Half connected to A and half to B..
	numClients := 20

	clients := make([]*nats.Conn, numClients)

	for i := 0; i < numClients; i++ {
		opts.Url = servers[i%2]
		nc, err := opts.Connect()
		defer nc.Close()
		clients = append(clients, nc)

		if err != nil {
			t.Fatalf("Failed to create connection: %v\n", err)
		}
		// Create 10 subscriptions each..
		for x := 0; x < 10; x++ {
			subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
			nc.Subscribe(subject, func(m *nats.Msg) {
				// Just eat it..
			})
		}
		// Pick one subject to send to..
		subject := fmt.Sprintf("foo.%d", (rand.Int()%50)+1)
		go func() {
			time.Sleep(10 * time.Millisecond)
			for i := 1; i <= 100; i++ {
				if err := nc.Publish(subject, msg); err != nil {
					return
				}
				if i%10 == 0 {
					time.Sleep(time.Millisecond)
				}
			}
		}()
	}

	// Wait for a short bit..
	time.Sleep(20 * time.Millisecond)

	// Restart SrvB
	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	select {
	case <-reconnectsDone:
		break
	case <-time.After(2 * time.Second):
		t.Fatalf("Expected %d reconnects, got %d\n", numClients/2, reconnects)
	}

	// On windows, as of go 1.5.2, the test does not exit until we close
	// the connections...
	for _, nc := range clients {
		if nc != nil {
			nc.Close()
		}
	}
}

// This will test queue subscriber semantics across a cluster in the presence
// of server restarts.
func TestServerRestartAndQueueSubs(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	// Client options
	opts := nats.DefaultOptions
	opts.Timeout = (5 * time.Second)
	opts.ReconnectWait = (50 * time.Millisecond)
	opts.MaxReconnect = 1000
	opts.NoRandomize = true

	// Allow us to block on a reconnect completion.
	reconnectsDone := make(chan bool)
	opts.ReconnectedCB = func(nc *nats.Conn) {
		reconnectsDone <- true
	}

	// Helper to wait on a reconnect.
	waitOnReconnect := func() {
		var rcs int64
		for {
			select {
			case <-reconnectsDone:
				atomic.AddInt64(&rcs, 1)
				if rcs >= 2 {
					return
				}
			case <-time.After(2 * time.Second):
				t.Fatalf("Expected a reconnect, timedout!\n")
			}
		}
	}

	// Create two clients..
	opts.Servers = []string{urlA}
	nc1, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}

	opts.Servers = []string{urlB}
	nc2, err := opts.Connect()
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}

	c1, _ := nats.NewEncodedConn(nc1, "json")
	defer c1.Close()
	c2, _ := nats.NewEncodedConn(nc2, "json")
	defer c2.Close()

	// Flusher helper function.
	flush := func() {
		// Wait for processing.
		c1.Flush()
		c2.Flush()
		// Wait for a short bit for cluster propogation.
		time.Sleep(50 * time.Millisecond)
	}

	// To hold queue results.
	results := make(map[int]int)
	var mu sync.Mutex

	// This corresponds to the subsriptions below.
	const ExpectedMsgCount = 3

	// Make sure we got what we needed, 1 msg only and all seqnos accounted for..
	checkResults := func(numSent int) {
		mu.Lock()
		defer mu.Unlock()

		for i := 0; i < numSent; i++ {
			if results[i] != ExpectedMsgCount {
				t.Fatalf("Received incorrect number of messages, [%d] for seq: %d\n", results[i], i)
			}
		}

		// Auto reset results map
		results = make(map[int]int)
	}

	subj := "foo.bar"
	qgroup := "workers"

	cb := func(seqno int) {
		mu.Lock()
		defer mu.Unlock()
		results[seqno] = results[seqno] + 1
	}

	// Create queue subscribers
	c1.QueueSubscribe(subj, qgroup, cb)
	c2.QueueSubscribe(subj, qgroup, cb)

	// Do a wildcard subscription.
	c1.Subscribe("foo.*", cb)
	c2.Subscribe("foo.*", cb)

	// Wait for processing.
	flush()

	sendAndCheckMsgs := func(numToSend int) {
		for i := 0; i < numToSend; i++ {
			if i%2 == 0 {
				c1.Publish(subj, i)
			} else {
				c2.Publish(subj, i)
			}
		}
		// Wait for processing.
		flush()
		// Check Results
		checkResults(numToSend)
	}

	////////////////////////////////////////////////////////////////////////////
	// Base Test
	////////////////////////////////////////////////////////////////////////////

	// Now send 10 messages, from each client..
	sendAndCheckMsgs(10)

	////////////////////////////////////////////////////////////////////////////
	// Now restart SrvA and srvB, re-run test
	////////////////////////////////////////////////////////////////////////////

	srvA.Shutdown()
	srvA = RunServer(optsA)
	defer srvA.Shutdown()

	srvB.Shutdown()
	srvB = RunServer(optsB)
	defer srvB.Shutdown()

	waitOnReconnect()

	time.Sleep(50 * time.Millisecond)

	// Now send another 10 messages, from each client..
	sendAndCheckMsgs(10)
}

// This will test request semantics across a route
func TestRequestsAcrossRoutes(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect responder to srvA
	nc1.Subscribe("foo-req", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}

// This will test request semantics across a route to queues
func TestRequestsAcrossRoutesToQueues(t *testing.T) {
	srvA, srvB, optsA, optsB := runServers(t)
	defer srvA.Shutdown()
	defer srvB.Shutdown()

	urlA := fmt.Sprintf("nats://%s:%d/", optsA.Host, optsA.Port)
	urlB := fmt.Sprintf("nats://%s:%d/", optsB.Host, optsB.Port)

	nc1, err := nats.Connect(urlA)
	if err != nil {
		t.Fatalf("Failed to create connection for nc1: %v\n", err)
	}
	defer nc1.Close()

	nc2, err := nats.Connect(urlB)
	if err != nil {
		t.Fatalf("Failed to create connection for nc2: %v\n", err)
	}
	defer nc2.Close()

	ec1, _ := nats.NewEncodedConn(nc1, nats.JSON_ENCODER)
	ec2, _ := nats.NewEncodedConn(nc2, nats.JSON_ENCODER)

	response := []byte("I will help you")

	// Connect one responder to srvA
	nc1.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc1.Publish(m.Reply, response)
	})
	// Make sure the route and the subscription are propogated.
	nc1.Flush()

	// Connect the other responder to srvB
	nc2.QueueSubscribe("foo-req", "booboo", func(m *nats.Msg) {
		nc2.Publish(m.Reply, response)
	})

	var resp string

	for i := 0; i < 100; i++ {
		if err := ec2.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}

	for i := 0; i < 100; i++ {
		if err := ec1.Request("foo-req", i, &resp, 100*time.Millisecond); err != nil {
			t.Fatalf("Received an error on Request test [%d]: %s", i, err)
		}
	}
}
<|endoftext|>


<commit_before>package agozon

// Locale Information
type LocaleSearchIndex struct {
	BrowseNode           int64    `json:"BrowseNode"`
	SortValues           []string `json:"SortValues"`
	ItemSearchParameters []string `json:"ItemSearchParameters"`
}

var LocaleInformation = []map[string]LocaleSearchIndex{
	LocaleBRMap, LocaleCAMap, LocaleCNMap, LocaleDEMap, LocaleESMap, LocaleFRMap, LocaleINMap,
	LocaleITMap, LocaleJPMap, LocaleUKMap, LocaleUSMap,
}
<commit_msg>update localeinformation to map[string]map[string]LocaleSearchIndex<commit_after>package agozon

// Locale Information
type LocaleSearchIndex struct {
	BrowseNode           int64    `json:"BrowseNode"`
	SortValues           []string `json:"SortValues"`
	ItemSearchParameters []string `json:"ItemSearchParameters"`
}

var LocaleInformation = map[string]map[string]LocaleSearchIndex{
	"BR": LocaleBRMap,
	"CA": LocaleCAMap,
	"CN": LocaleCNMap,
	"DE": LocaleDEMap,
	"ES": LocaleESMap,
	"FR": LocaleFRMap,
	"IN": LocaleINMap,
	"IT": LocaleITMap,
	"JP": LocaleJPMap,
	"UK": LocaleUKMap,
	"US": LocaleUSMap,
}
<|endoftext|>


<commit_before>package rest

import (
	"connectordb/plugins/rest/restcore"
	"connectordb/streamdb/datastream"
	"connectordb/streamdb/operator"
	"connectordb/streamdb/operator/messenger"
	"connectordb/streamdb/query"
	"connectordb/streamdb/query/transforms"
	"errors"
	"io"
	"net/http"
	"sync"
	"sync/atomic"
	"time"

	"github.com/gorilla/websocket"
	"github.com/nats-io/nats"

	log "github.com/Sirupsen/logrus"
)

const (
	//The max size of a websocket message
	messageSizeLimit = 1 * restcore.Mb

	//The time allowed to write a message
	writeWait = 2 * time.Second

	//Ping pong stuff - making sure that the connection still exists
	pongWait   = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10

	//The number of messages to buffer
	messageBuffer = 3

	webSocketClosed         = "EXIT"
	webSocketClosedNonClean = "@EXIT"
)

//The websocket upgrader
var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		// Allow from all origins
		CheckOrigin: func(r *http.Request) bool { return true },
	}

	//websocketWaitGroup is the WaitGroup of websockets that are currently open
	websocketWaitGroup = sync.WaitGroup{}
)

type Subscription struct {
	sync.Mutex //The transform mutex

	nats *nats.Subscription //The nats subscription

	transform map[string]transforms.DatapointTransform //the transforms associated with the subscription - this allows us to run transforms on the data!
}

func NewSubscription(subs *nats.Subscription) *Subscription {
	return &Subscription{
		nats:      subs,
		transform: make(map[string]transforms.DatapointTransform),
	}
}

//Close shuts down the subscription
func (s *Subscription) Close() {
	s.Lock()
	defer s.Unlock()
	s.nats.Unsubscribe()
}

//Size is the number of subscriptions to the stream (using different transforms)
func (s *Subscription) Size() int {
	s.Lock()
	defer s.Unlock()
	return len(s.transform)
}

//Add a transform subscription to the string
func (s *Subscription) AddTransform(transform string) (err error) {
	if _, ok := s.transform[transform]; ok {
		return errors.New("Subscription to the transform already exists")
	}

	//First, attempt to generate the transform
	var t transforms.DatapointTransform
	if transform != "" {
		t, err = transforms.NewTransformPipeline(transform)
		if err != nil {
			return err
		}
	}

	s.Lock()
	s.transform[transform] = t
	s.Unlock()

	return nil
}

//RemTransform deletes a transform from the subscriptions
func (s *Subscription) RemTransform(transform string) (err error) {
	s.Lock()
	delete(s.transform, transform)
	s.Unlock()
	return nil
}

//WebsocketConnection is the general connection with a websocket that is run.
//Loosely based on github.com/gorilla/websocket/blob/master/examples/chat/conn.go
//No need for mutex because only reader reads and implements commands
type WebsocketConnection struct {
	ws *websocket.Conn

	subscriptions map[string]*Subscription

	c chan messenger.Message

	logger *log.Entry //logrus uses a mutex internally
	o      operator.Operator
}

//NewWebsocketConnection creates a new websocket connection based on the operators and stuff
func NewWebsocketConnection(o operator.Operator, writer http.ResponseWriter, request *http.Request, logger *log.Entry) (*WebsocketConnection, error) {

	ws, err := upgrader.Upgrade(writer, request, nil)
	if err != nil {
		logger.Errorln(err)
		return nil, err
	}

	ws.SetReadLimit(messageSizeLimit)

	return &WebsocketConnection{ws, make(map[string]*Subscription), make(chan messenger.Message, messageBuffer), logger, o}, nil
}

func (c *WebsocketConnection) write(obj interface{}) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteJSON(obj)
}

//Close the websocket connection
func (c *WebsocketConnection) Close() {
	c.UnsubscribeAll()
	close(c.c)
	c.ws.Close()
	c.logger.WithField("cmd", "close").Debugln()
}

//Insert a datapoint using the websocket
func (c *WebsocketConnection) Insert(ws *websocketCommand) {
	logger := c.logger.WithFields(log.Fields{"cmd": "insert", "arg": ws.Arg})
	logger.Debugln("Inserting", len(ws.D), "dp")
	err := c.o.InsertStream(ws.Arg, ws.D, true)
	if err != nil {
		//TODO: Notify user of insert failure
		logger.Warn(err.Error())
	} else {
		atomic.AddUint32(&restcore.StatsInserts, uint32(len(ws.D)))
	}
}

//Subscribe to the given data stream
func (c *WebsocketConnection) Subscribe(s, transform string) {
	logger := c.logger.WithFields(log.Fields{"cmd": "subscribe", "arg": s})

	//Next check if nats is subscribed
	if _, ok := c.subscriptions[s]; !ok {
		subs, err := c.o.Subscribe(s, c.c)
		if err != nil {
			logger.Warningln(err)
		} else {

			logger.Debugln("Initializing subscription")
			c.subscriptions[s] = NewSubscription(subs)
		}
	}

	err := c.subscriptions[s].AddTransform(transform)
	if err != nil {
		logger.Warningln(err)
	}
}

//Unsubscribe from the given data stream
func (c *WebsocketConnection) Unsubscribe(s, transform string) {
	logger := c.logger.WithFields(log.Fields{"cmd": "unsubscribe", "arg": s})
	if val, ok := c.subscriptions[s]; ok {
		val.RemTransform(transform)
		if val.Size() == 0 {
			logger.Debugln("Full unsubscribe")
			val.Close()
			delete(c.subscriptions, s)
		} else {
			logger.Debugln("transform subscription removed")
		}

	} else {
		logger.Warningln("subscription DNE")
	}
}

//UnsubscribeAll from all streams of data
func (c *WebsocketConnection) UnsubscribeAll() {
	c.logger.WithField("cmd", "unsubscribeALL").Debugln()
	for _, val := range c.subscriptions {
		val.Close()
	}
	c.subscriptions = make(map[string]*Subscription)
}

//A command is a cmd and the arg operation
type websocketCommand struct {
	Cmd       string
	Arg       string
	Transform string //Allows subscribing with a transform

	D []datastream.Datapoint //If the command is "insert", it needs an additional datapoint
}

//RunReader runs the reading routine. It also maps the commands to actual subscriptions
func (c *WebsocketConnection) RunReader(readmessenger chan string) {

	//Set up the heartbeat reader(makes sure that sockets are alive)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error {
		//c.logger.WithField("cmd", "PingPong").Debugln()
		c.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	var cmd websocketCommand
	for {
		err := c.ws.ReadJSON(&cmd)
		if err != nil {
			if err == io.EOF {
				readmessenger <- webSocketClosed
				return //On EOF, do nothing - it is just a close
			}
			c.logger.Warningln(err)
			break
		}
		switch cmd.Cmd {
		default:
			c.logger.Warningln("Command not recognized:", cmd.Cmd)
			//Do nothing - the command is not recognized
		case "insert":
			c.Insert(&cmd)
		case "subscribe":
			c.Subscribe(cmd.Arg, cmd.Transform)
		case "unsubscribe":
			c.Unsubscribe(cmd.Arg, cmd.Transform)
		case "unsubscribe_all":
			c.UnsubscribeAll()
		}
	}
	//Since the reader is exiting, notify the writer to send close message
	readmessenger <- webSocketClosedNonClean
}

//RunWriter writes the subscription data as well as the heartbeat pings.
func (c *WebsocketConnection) RunWriter(readmessenger chan string, exitchan chan bool) {
	ticker := time.NewTicker(pingPeriod)
	defer ticker.Stop()
loop:
	for {
		select {
		case dp, ok := <-c.c:
			if !ok {
				c.ws.SetWriteDeadline(time.Now().Add(writeWait))
				c.ws.WriteMessage(websocket.CloseMessage, []byte{})
				break loop
			}
			c.logger.WithFields(log.Fields{"cmd": "MSG", "arg": dp.Stream}).Debugln()

			//Now loop through all transforms for the datapoint array
			subs, ok := c.subscriptions[dp.Stream]
			if ok {
				subs.Lock()
				for transform, tf := range subs.transform {
					if transform == "" {
						log.Debugf("wrote (no transform)")
						if err := c.write(dp); err != nil {
							break loop
						}
					} else {
						dpa, err := query.TransformArray(tf, &dp.Data)
						log.Debugf("Wrote: %s", transform)
						if err == nil && dpa.Length() > 0 {
							if err := c.write(messenger.Message{
								Stream:    dp.Stream,
								Transform: transform,
								Data:      *dpa,
							}); err != nil {
								break loop
							}
						}
					}

				}
				subs.Unlock()
			}
			if err := c.write(dp); err != nil {
				break loop
			}
		case <-ticker.C:
			//c.logger.WithField("cmd", "PING").Debugln()
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := c.ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				break loop
			}
		case msg := <-readmessenger:
			if msg == webSocketClosed {
				break loop
			} else if msg == webSocketClosedNonClean {
				c.ws.SetWriteDeadline(time.Now().Add(writeWait))
				c.ws.WriteMessage(websocket.CloseMessage, []byte{})
				break loop
			}
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			c.ws.WriteMessage(websocket.TextMessage, []byte(msg))
		case <-restcore.ShutdownChannel:
			restcore.ShutdownChannel <- true
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			c.ws.WriteMessage(websocket.CloseMessage, []byte{})
			break loop
		}
	}
	exitchan <- true
}

//Run the websocket operations
func (c *WebsocketConnection) Run() error {
	c.logger.Debugln("Running websocket...")
	websocketWaitGroup.Add(1)

	//The reader can communicate with the writer through the channel
	msgchn := make(chan string, 1)
	exitchan := make(chan bool, 1)
	go c.RunWriter(msgchn, exitchan)
	c.RunReader(msgchn)
	//Wait for writer to exit, or for the exit timeout to happen
	go func() {
		time.Sleep(writeWait)
		exitchan <- false
	}()

	if !<-exitchan {
		c.logger.Error("writer exit timeout")
	}
	websocketWaitGroup.Done()
	return nil
}

//RunWebsocket runs the websocket handler
func RunWebsocket(o operator.Operator, writer http.ResponseWriter, request *http.Request, logger *log.Entry) (int, string) {
	conn, err := NewWebsocketConnection(o, writer, request, logger)
	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		return 3, err.Error()
	}
	defer conn.Close()
	err = conn.Run()
	if err != nil {
		return 2, err.Error()
	}
	return 0, ""
}
<commit_msg>Small fixes to websocket<commit_after>package rest

import (
	"connectordb/plugins/rest/restcore"
	"connectordb/streamdb/datastream"
	"connectordb/streamdb/operator"
	"connectordb/streamdb/operator/messenger"
	"connectordb/streamdb/query"
	"connectordb/streamdb/query/transforms"
	"errors"
	"io"
	"net/http"
	"sync"
	"sync/atomic"
	"time"

	"github.com/gorilla/websocket"
	"github.com/nats-io/nats"

	log "github.com/Sirupsen/logrus"
)

const (
	//The max size of a websocket message
	messageSizeLimit = 1 * restcore.Mb

	//The time allowed to write a message
	writeWait = 2 * time.Second

	//Ping pong stuff - making sure that the connection still exists
	pongWait   = 60 * time.Second
	pingPeriod = (pongWait * 9) / 10

	//The number of messages to buffer
	messageBuffer = 3

	webSocketClosed         = "EXIT"
	webSocketClosedNonClean = "@EXIT"
)

//The websocket upgrader
var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		// Allow from all origins
		CheckOrigin: func(r *http.Request) bool { return true },
	}

	//websocketWaitGroup is the WaitGroup of websockets that are currently open
	websocketWaitGroup = sync.WaitGroup{}
)

type Subscription struct {
	sync.Mutex //The transform mutex

	nats *nats.Subscription //The nats subscription

	transform map[string]transforms.DatapointTransform //the transforms associated with the subscription - this allows us to run transforms on the data!
}

func NewSubscription(subs *nats.Subscription) *Subscription {
	return &Subscription{
		nats:      subs,
		transform: make(map[string]transforms.DatapointTransform),
	}
}

//Close shuts down the subscription
func (s *Subscription) Close() {
	s.Lock()
	defer s.Unlock()
	s.nats.Unsubscribe()
}

//Size is the number of subscriptions to the stream (using different transforms)
func (s *Subscription) Size() int {
	s.Lock()
	defer s.Unlock()
	return len(s.transform)
}

//Add a transform subscription to the string
func (s *Subscription) AddTransform(transform string) (err error) {
	if _, ok := s.transform[transform]; ok {
		return errors.New("Subscription to the transform already exists")
	}

	//First, attempt to generate the transform
	var t transforms.DatapointTransform
	if transform != "" {
		t, err = transforms.NewTransformPipeline(transform)
		if err != nil {
			return err
		}
	}

	s.Lock()
	s.transform[transform] = t
	s.Unlock()

	return nil
}

//RemTransform deletes a transform from the subscriptions
func (s *Subscription) RemTransform(transform string) (err error) {
	s.Lock()
	delete(s.transform, transform)
	s.Unlock()
	return nil
}

//WebsocketConnection is the general connection with a websocket that is run.
//Loosely based on github.com/gorilla/websocket/blob/master/examples/chat/conn.go
//No need for mutex because only reader reads and implements commands
type WebsocketConnection struct {
	ws *websocket.Conn

	subscriptions map[string]*Subscription

	c chan messenger.Message

	logger *log.Entry //logrus uses a mutex internally
	o      operator.Operator
}

//NewWebsocketConnection creates a new websocket connection based on the operators and stuff
func NewWebsocketConnection(o operator.Operator, writer http.ResponseWriter, request *http.Request, logger *log.Entry) (*WebsocketConnection, error) {

	ws, err := upgrader.Upgrade(writer, request, nil)
	if err != nil {
		logger.Errorln(err)
		return nil, err
	}

	ws.SetReadLimit(messageSizeLimit)

	return &WebsocketConnection{ws, make(map[string]*Subscription), make(chan messenger.Message, messageBuffer), logger, o}, nil
}

func (c *WebsocketConnection) write(obj interface{}) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteJSON(obj)
}

//Close the websocket connection
func (c *WebsocketConnection) Close() {
	c.UnsubscribeAll()
	close(c.c)
	c.ws.Close()
	c.logger.WithField("cmd", "close").Debugln()
}

//Insert a datapoint using the websocket
func (c *WebsocketConnection) Insert(ws *websocketCommand) {
	logger := c.logger.WithFields(log.Fields{"cmd": "insert", "arg": ws.Arg})
	logger.Debugln("-> insert ", len(ws.D), "dp")
	err := c.o.InsertStream(ws.Arg, ws.D, true)
	if err != nil {
		//TODO: Notify user of insert failure
		logger.Warn(err.Error())
	} else {
		atomic.AddUint32(&restcore.StatsInserts, uint32(len(ws.D)))
	}
}

//Subscribe to the given data stream
func (c *WebsocketConnection) Subscribe(s, transform string) {
	logger := c.logger.WithFields(log.Fields{"cmd": "subscribe", "arg": s})

	//Next check if nats is subscribed
	if _, ok := c.subscriptions[s]; !ok {
		subs, err := c.o.Subscribe(s, c.c)
		if err != nil {
			logger.Warningln(err)
		} else {

			logger.Debugln("Initializing subscription")
			c.subscriptions[s] = NewSubscription(subs)
		}
	}

	err := c.subscriptions[s].AddTransform(transform)
	if err != nil {
		logger.Warningln(err)
	}
}

//Unsubscribe from the given data stream
func (c *WebsocketConnection) Unsubscribe(s, transform string) {
	logger := c.logger.WithFields(log.Fields{"cmd": "unsubscribe", "arg": s})
	if val, ok := c.subscriptions[s]; ok {
		val.RemTransform(transform)
		if val.Size() == 0 {
			logger.Debugln("stop subscription")
			val.Close()
			delete(c.subscriptions, s)
		} else {
			logger.Debugln()
		}

	} else {
		logger.Warningln("subscription DNE")
	}
}

//UnsubscribeAll from all streams of data
func (c *WebsocketConnection) UnsubscribeAll() {
	for key, val := range c.subscriptions {
		c.logger.Debugf("Unsubscribe: %s", key)
		val.Close()
	}
	c.subscriptions = make(map[string]*Subscription)
}

//A command is a cmd and the arg operation
type websocketCommand struct {
	Cmd       string
	Arg       string
	Transform string //Allows subscribing with a transform

	D []datastream.Datapoint //If the command is "insert", it needs an additional datapoint
}

//RunReader runs the reading routine. It also maps the commands to actual subscriptions
func (c *WebsocketConnection) RunReader(readmessenger chan string) {

	//Set up the heartbeat reader(makes sure that sockets are alive)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error {
		//c.logger.WithField("cmd", "PingPong").Debugln()
		c.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	var cmd websocketCommand
	for {
		err := c.ws.ReadJSON(&cmd)
		if err != nil {
			if err == io.EOF {
				readmessenger <- webSocketClosed
				return //On EOF, do nothing - it is just a close
			}
			c.logger.Warningln(err)
			break
		}
		switch cmd.Cmd {
		default:
			c.logger.Warningln("Command not recognized:", cmd.Cmd)
			//Do nothing - the command is not recognized
		case "insert":
			c.Insert(&cmd)
		case "subscribe":
			c.Subscribe(cmd.Arg, cmd.Transform)
		case "unsubscribe":
			c.Unsubscribe(cmd.Arg, cmd.Transform)
		case "unsubscribe_all":
			c.UnsubscribeAll()
		}
	}
	//Since the reader is exiting, notify the writer to send close message
	readmessenger <- webSocketClosedNonClean
}

//RunWriter writes the subscription data as well as the heartbeat pings.
func (c *WebsocketConnection) RunWriter(readmessenger chan string, exitchan chan bool) {
	ticker := time.NewTicker(pingPeriod)
	defer ticker.Stop()
loop:
	for {
		select {
		case dp, ok := <-c.c:
			if !ok {
				c.ws.SetWriteDeadline(time.Now().Add(writeWait))
				c.ws.WriteMessage(websocket.CloseMessage, []byte{})
				break loop
			}
			logger := c.logger.WithFields(log.Fields{"stream": dp.Stream})

			//Now loop through all transforms for the datapoint array
			subs, ok := c.subscriptions[dp.Stream]
			if ok {
				subs.Lock()
				for transform, tf := range subs.transform {
					if transform == "" {
						logger.Debugln("<- send")
						if err := c.write(dp); err != nil {
							break loop
						}
					} else {
						dpa, err := query.TransformArray(tf, &dp.Data)
						logger.Debugf("<- send %s", transform)
						if err == nil && dpa.Length() > 0 {
							if err := c.write(messenger.Message{
								Stream:    dp.Stream,
								Transform: transform,
								Data:      *dpa,
							}); err != nil {
								break loop
							}
						}
					}

				}
				subs.Unlock()
			}
			if err := c.write(dp); err != nil {
				break loop
			}
		case <-ticker.C:
			//c.logger.WithField("cmd", "PING").Debugln()
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := c.ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				break loop
			}
		case msg := <-readmessenger:
			if msg == webSocketClosed {
				break loop
			} else if msg == webSocketClosedNonClean {
				c.ws.SetWriteDeadline(time.Now().Add(writeWait))
				c.ws.WriteMessage(websocket.CloseMessage, []byte{})
				break loop
			}
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			c.ws.WriteMessage(websocket.TextMessage, []byte(msg))
		case <-restcore.ShutdownChannel:
			restcore.ShutdownChannel <- true
			c.ws.SetWriteDeadline(time.Now().Add(writeWait))
			c.ws.WriteMessage(websocket.CloseMessage, []byte{})
			break loop
		}
	}
	exitchan <- true
}

//Run the websocket operations
func (c *WebsocketConnection) Run() error {
	c.logger.Debugln("Running websocket...")
	websocketWaitGroup.Add(1)

	//The reader can communicate with the writer through the channel
	msgchn := make(chan string, 1)
	exitchan := make(chan bool, 1)
	go c.RunWriter(msgchn, exitchan)
	c.RunReader(msgchn)
	//Wait for writer to exit, or for the exit timeout to happen
	go func() {
		time.Sleep(writeWait)
		exitchan <- false
	}()

	if !<-exitchan {
		c.logger.Error("writer exit timeout")
	}
	websocketWaitGroup.Done()
	return nil
}

//RunWebsocket runs the websocket handler
func RunWebsocket(o operator.Operator, writer http.ResponseWriter, request *http.Request, logger *log.Entry) (int, string) {
	conn, err := NewWebsocketConnection(o, writer, request, logger)
	if err != nil {
		writer.WriteHeader(http.StatusInternalServerError)
		return 3, err.Error()
	}
	defer conn.Close()
	err = conn.Run()
	if err != nil {
		return 2, err.Error()
	}
	return 0, "Websocket closed"
}
<|endoftext|>


<commit_before>// errorcheck

// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Issue 4468: go/defer calls may not be parenthesized.

package p

func F() {
	go (F())	// ERROR "must be function call"
	defer (F())	// ERROR "must be function call"
}
<commit_msg>test: add some tests where go/defer arg starts with parenthesis<commit_after>// errorcheck

// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Issue 4468: go/defer calls may not be parenthesized.

package p

type T int

func (t *T) F() T {
	return *t
}

type S struct {
	t T
}

func F() {
	go (F())	// ERROR "must be function call"
	defer (F())	// ERROR "must be function call"
	var s S
	(&s.t).F()
	go (&s.t).F()
	defer (&s.t).F()
}
<|endoftext|>


<commit_before>// Copyright 2016 Mesosphere, Inc.
//
// 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 agent

import (
	"time"

	"github.com/dcos/dcos-metrics/producers"
)

const (
	// Container tagging constants
	CONTAINERID  = "container_id"
	SOURCE       = "source"
	FRAMEWORKID  = "framework_id"
	EXECUTORID   = "executor_id"
	EXECUTORNAME = "executor_name"

	// Container unit constants
	SECONDS = "seconds"
	COUNT   = "count"
	BYTES   = "bytes"
)

func (c *Collector) createContainerDatapoints(container agentContainer) []producers.Datapoint {
	ts := thisTime()
	dps := []producers.Datapoint{}

	dpTags := map[string]string{
		CONTAINERID:  container.ContainerID,
		SOURCE:       container.Source,
		FRAMEWORKID:  container.FrameworkID,
		EXECUTORID:   container.ExecutorID,
		EXECUTORNAME: container.ExecutorName,
	}

	c.log.Debugf("Adding tags for container %s:\n%+v", container.ContainerID, dpTags)

	addDps := []producers.Datapoint{
		producers.Datapoint{
			Name:  "cpus.user.time",
			Value: container.Statistics.CpusUserTimeSecs,
			Unit:  SECONDS,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.system.time",
			Value: container.Statistics.CpusSystemTimeSecs,
			Unit:  SECONDS,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.limit",
			Value: container.Statistics.CpusLimit,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.throttled.time",
			Value: container.Statistics.CpusThrottledTimeSecs,
			Unit:  SECONDS,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "mem.total",
			Value: container.Statistics.MemTotalBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "mem.limit",
			Value: container.Statistics.MemLimitBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "disk.limit",
			Value: container.Statistics.DiskLimitBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "disk.used",
			Value: container.Statistics.DiskUsedBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.packets",
			Value: container.Statistics.NetRxPackets,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.bytes",
			Value: container.Statistics.NetRxBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.errors",
			Value: container.Statistics.NetRxErrors,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.dropped",
			Value: container.Statistics.NetRxDropped,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.packets",
			Value: container.Statistics.NetRxPackets,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.bytes",
			Value: container.Statistics.NetRxBytes,
			Unit:  BYTES,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.errors",
			Value: container.Statistics.NetRxErrors,
			Unit:  COUNT,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.dropped",
			Value: container.Statistics.NetRxDropped,
			Unit:  COUNT,
			Tags:  dpTags,
		},
	}

	for _, dp := range addDps {
		dp.Timestamp = ts
		dps = append(dps, dp)
	}

	return dps
}

// -- helpers

func thisTime() string {
	return time.Now().UTC().Format(time.RFC3339Nano)
}
<commit_msg>Fixed linter issues reported for collectors/mesos/agent/metrics.go.<commit_after>// Copyright 2016 Mesosphere, Inc.
//
// 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 agent

import (
	"time"

	"github.com/dcos/dcos-metrics/producers"
)

const (
	// Container tagging constants

	containerID  = "container_id"
	source       = "source"
	frameworkID  = "framework_id"
	executorID   = "executor_id"
	executorName = "executor_name"

	// Container unit constants
	seconds = "seconds"
	count   = "count"
	bytes   = "bytes"
)

func (c *Collector) createContainerDatapoints(container agentContainer) []producers.Datapoint {
	ts := thisTime()
	dps := []producers.Datapoint{}

	dpTags := map[string]string{
		containerID:  container.ContainerID,
		source:       container.Source,
		frameworkID:  container.FrameworkID,
		executorID:   container.ExecutorID,
		executorName: container.ExecutorName,
	}

	c.log.Debugf("Adding tags for container %s:\n%+v", container.ContainerID, dpTags)

	addDps := []producers.Datapoint{
		producers.Datapoint{
			Name:  "cpus.user.time",
			Value: container.Statistics.CpusUserTimeSecs,
			Unit:  seconds,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.system.time",
			Value: container.Statistics.CpusSystemTimeSecs,
			Unit:  seconds,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.limit",
			Value: container.Statistics.CpusLimit,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "cpus.throttled.time",
			Value: container.Statistics.CpusThrottledTimeSecs,
			Unit:  seconds,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "mem.total",
			Value: container.Statistics.MemTotalBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "mem.limit",
			Value: container.Statistics.MemLimitBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "disk.limit",
			Value: container.Statistics.DiskLimitBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "disk.used",
			Value: container.Statistics.DiskUsedBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.packets",
			Value: container.Statistics.NetRxPackets,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.bytes",
			Value: container.Statistics.NetRxBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.errors",
			Value: container.Statistics.NetRxErrors,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.rx.dropped",
			Value: container.Statistics.NetRxDropped,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.packets",
			Value: container.Statistics.NetRxPackets,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.bytes",
			Value: container.Statistics.NetRxBytes,
			Unit:  bytes,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.errors",
			Value: container.Statistics.NetRxErrors,
			Unit:  count,
			Tags:  dpTags,
		},
		producers.Datapoint{
			Name:  "net.tx.dropped",
			Value: container.Statistics.NetRxDropped,
			Unit:  count,
			Tags:  dpTags,
		},
	}

	for _, dp := range addDps {
		dp.Timestamp = ts
		dps = append(dps, dp)
	}

	return dps
}

// -- helpers

func thisTime() string {
	return time.Now().UTC().Format(time.RFC3339Nano)
}
<|endoftext|>


<commit_before>package client

import (
	"bytes"
	"encoding/json"
	"github.com/Clever/inter-service-api-testing/codegen-poc/generated/models"
	"golang.org/x/net/context"
	"net/http"
	"net/url"
	"strconv"
	"strings"
)

var _ = json.Marshal
var _ = strings.Replace

var _ = strconv.FormatInt

type Client struct {
	BasePath    string
	requestDoer doer
	transport   *http.Transport
	// Keep the retry doer around so that we can set the number of retries
	retryDoer retryDoer
}

// NewClient creates a new client. The base path and http transport are configurable
func NewClient(basePath string) Client {
	base := baseDoer{}
	tracing := tracingDoer{d: base}
	retry := retryDoer{d: tracing, defaultRetries: 1}

	return Client{requestDoer: retry, retryDoer: retry, transport: nil, BasePath: basePath}
}

func (c Client) WithRetries(retries int) Client {
	c.retryDoer.defaultRetries = retries
	return c
}

func (c Client) GetBooks(ctx context.Context, i *models.GetBooksInput) (models.GetBooksOutput, error) {
	path := c.BasePath + "/v1/books"
	urlVals := url.Values{}
	var body []byte

	urlVals.Add("author", i.Author)
	urlVals.Add("available", strconv.FormatBool(i.Available))
	urlVals.Add("maxPages", strconv.FormatFloat(i.MaxPages, 'E', -1, 64))
	path = path + "?" + urlVals.Encode()

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("GET", path, bytes.NewBuffer(body))

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "getBooks")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.GetBooks200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}

func (c Client) GetBookByID(ctx context.Context, i *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	path := c.BasePath + "/v1/books/{bookID}"
	urlVals := url.Values{}
	var body []byte

	path = strings.Replace(path, "{bookID}", strconv.FormatInt(i.BookID, 10), -1)
	path = path + "?" + urlVals.Encode()

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("GET", path, bytes.NewBuffer(body))
	req.Header.Set("authorization", i.Authorization)

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "getBookByID")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.GetBookByID200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 204:
		var output models.GetBookByID204Output
		return output, nil
	case 401:
		var output models.GetBookByID401Output
		return nil, output
	case 404:
		return nil, models.GetBookByID404Output{}
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}

func (c Client) CreateBook(ctx context.Context, i *models.CreateBookInput) (models.CreateBookOutput, error) {
	path := c.BasePath + "/v1/books/{bookID}"
	urlVals := url.Values{}
	var body []byte

	path = path + "?" + urlVals.Encode()

	body, _ = json.Marshal(i.NewBook)

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("POST", path, bytes.NewBuffer(body))

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "createBook")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.CreateBook200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}
<commit_msg>Just client.New not client.NewClient<commit_after>package client

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/Clever/inter-service-api-testing/codegen-poc/generated/models"
	"golang.org/x/net/context"
)

var _ = json.Marshal
var _ = strings.Replace

var _ = strconv.FormatInt

type Client struct {
	BasePath    string
	requestDoer doer
	transport   *http.Transport
	// Keep the retry doer around so that we can set the number of retries
	retryDoer retryDoer
}

// New creates a new client. The base path and http transport are configurable
func New(basePath string) Client {
	base := baseDoer{}
	tracing := tracingDoer{d: base}
	retry := retryDoer{d: tracing, defaultRetries: 1}

	return Client{requestDoer: retry, retryDoer: retry, transport: nil, BasePath: basePath}
}

func (c Client) WithRetries(retries int) Client {
	c.retryDoer.defaultRetries = retries
	return c
}

func (c Client) GetBooks(ctx context.Context, i *models.GetBooksInput) (models.GetBooksOutput, error) {
	path := c.BasePath + "/v1/books"
	urlVals := url.Values{}
	var body []byte

	urlVals.Add("author", i.Author)
	urlVals.Add("available", strconv.FormatBool(i.Available))
	urlVals.Add("maxPages", strconv.FormatFloat(i.MaxPages, 'E', -1, 64))
	path = path + "?" + urlVals.Encode()

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("GET", path, bytes.NewBuffer(body))

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "getBooks")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.GetBooks200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}

func (c Client) GetBookByID(ctx context.Context, i *models.GetBookByIDInput) (models.GetBookByIDOutput, error) {
	path := c.BasePath + "/v1/books/{bookID}"
	urlVals := url.Values{}
	var body []byte

	path = strings.Replace(path, "{bookID}", strconv.FormatInt(i.BookID, 10), -1)
	path = path + "?" + urlVals.Encode()

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("GET", path, bytes.NewBuffer(body))
	req.Header.Set("authorization", i.Authorization)

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "getBookByID")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.GetBookByID200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 204:
		var output models.GetBookByID204Output
		return output, nil
	case 401:
		var output models.GetBookByID401Output
		return nil, output
	case 404:
		return nil, models.GetBookByID404Output{}
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}

func (c Client) CreateBook(ctx context.Context, i *models.CreateBookInput) (models.CreateBookOutput, error) {
	path := c.BasePath + "/v1/books/{bookID}"
	urlVals := url.Values{}
	var body []byte

	path = path + "?" + urlVals.Encode()

	body, _ = json.Marshal(i.NewBook)

	client := &http.Client{Transport: c.transport}
	req, _ := http.NewRequest("POST", path, bytes.NewBuffer(body))

	// Add the opname for doers like tracing
	ctx = context.WithValue(ctx, opNameCtx{}, "createBook")
	resp, err := c.requestDoer.Do(ctx, client, req)
	if err != nil {
		return nil, models.DefaultInternalError{Msg: err.Error()}
	}
	switch resp.StatusCode {
	case 200:

		var output models.CreateBook200Output
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return output, nil
	case 400:

		var output models.DefaultBadRequest
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	case 500:

		var output models.DefaultInternalError
		if err := json.NewDecoder(resp.Body).Decode(&output); err != nil {
			return nil, models.DefaultInternalError{Msg: err.Error()}
		}
		return nil, output
	default:
		return nil, models.DefaultInternalError{Msg: "Unknown response"}
	}
}
<|endoftext|>