<commit_before>// Copyright 2018 Istio 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 kubernetes

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

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/remotecommand"

	"istio.io/istio/pkg/kube"
	"istio.io/istio/pkg/version"
)

var (
	proxyContainer     = "istio-proxy"
	discoveryContainer = "discovery"
	pilotDiscoveryPath = "/usr/local/bin/pilot-discovery"
	pilotAgentPath     = "/usr/local/bin/pilot-agent"
)

// Client is a helper wrapper around the Kube RESTClient for istioctl -> Pilot/Envoy/Mesh related things
type Client struct {
	Config *rest.Config
	*rest.RESTClient
}

// ExecClient is an interface for remote execution
type ExecClient interface {
	EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error)
	AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error)
	GetIstioVersions(namespace string) (*version.MeshInfo, error)
}

// NewClient is the constructor for the client wrapper
func NewClient(kubeconfig, configContext string) (*Client, error) {
	config, err := defaultRestConfig(kubeconfig, configContext)
	if err != nil {
		return nil, err
	}
	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		return nil, err
	}
	return &Client{config, restClient}, nil
}

func defaultRestConfig(kubeconfig, configContext string) (*rest.Config, error) {
	config, err := kube.BuildClientConfig(kubeconfig, configContext)
	if err != nil {
		return nil, err
	}
	config.APIPath = "/api"
	config.GroupVersion = &v1.SchemeGroupVersion
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
	return config, nil
}

// PodExec takes a command and the pod data to run the command in the specified pod
func (client *Client) PodExec(podName, podNamespace, container string, command []string) (*bytes.Buffer, *bytes.Buffer, error) {
	req := client.Post().
		Resource("pods").
		Name(podName).
		Namespace(podNamespace).
		SubResource("exec").
		Param("container", container).
		VersionedParams(&v1.PodExecOptions{
			Container: container,
			Command:   command,
			Stdin:     false,
			Stdout:    true,
			Stderr:    true,
			TTY:       false,
		}, scheme.ParameterCodec)

	exec, err := remotecommand.NewSPDYExecutor(client.Config, "POST", req.URL())
	if err != nil {
		return nil, nil, err
	}

	var stdout, stderr bytes.Buffer
	err = exec.Stream(remotecommand.StreamOptions{
		Stdin:  nil,
		Stdout: &stdout,
		Stderr: &stderr,
		Tty:    false,
	})

	return &stdout, &stderr, err
}

// AllPilotsDiscoveryDo makes an http request to each Pilot discovery instance
func (client *Client) AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error) {
	pilots, err := client.GetIstioPods(pilotNamespace, map[string]string{"labelSelector": "istio=pilot"})
	if err != nil {
		return nil, err
	}
	if len(pilots) == 0 {
		return nil, errors.New("unable to find any Pilot instances")
	}
	cmd := []string{pilotDiscoveryPath, "request", method, path, string(body)}
	result := map[string][]byte{}
	for _, pilot := range pilots {
		res, err := client.ExtractExecResult(pilot.Name, pilot.Namespace, discoveryContainer, cmd)
		if err != nil {
			return nil, err
		}
		if len(res) > 0 {
			result[pilot.Name] = res
		}
	}
	return result, err
}

// PilotDiscoveryDo makes an http request to a single Pilot discovery instance
func (client *Client) PilotDiscoveryDo(pilotNamespace, method, path string, body []byte) ([]byte, error) {
	pilots, err := client.GetIstioPods(pilotNamespace, map[string]string{"labelSelector": "istio=pilot"})
	if err != nil {
		return nil, err
	}
	if len(pilots) == 0 {
		return nil, errors.New("unable to find any Pilot instances")
	}
	cmd := []string{pilotDiscoveryPath, "request", method, path, string(body)}
	return client.ExtractExecResult(pilots[0].Name, pilots[0].Namespace, discoveryContainer, cmd)
}

// EnvoyDo makes an http request to the Envoy in the specified pod
func (client *Client) EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error) {
	container, err := client.GetPilotAgentContainer(podName, podNamespace)
	if err != nil {
		return nil, fmt.Errorf("unable to retrieve proxy container name: %v", err)
	}
	cmd := []string{pilotAgentPath, "request", method, path, string(body)}
	return client.ExtractExecResult(podName, podNamespace, container, cmd)
}

// ExtractExecResult wraps PodExec and return the execution result and error if has any.
func (client *Client) ExtractExecResult(podName, podNamespace, container string, cmd []string) ([]byte, error) {
	stdout, stderr, err := client.PodExec(podName, podNamespace, container, cmd)
	if err != nil {
		return nil, fmt.Errorf("error execing into %v/%v %v container: %v", podName, podNamespace, container, err)
	}
	if stderr.String() != "" {
		fmt.Printf("Warning! error execing into %v/%v %v container: %v\n", podName, podNamespace, container, stderr.String())
	}
	return stdout.Bytes(), nil
}

// GetIstioPods retrieves the pod objects for Istio deployments
func (client *Client) GetIstioPods(namespace string, params map[string]string) ([]v1.Pod, error) {
	req := client.Get().
		Resource("pods").
		Namespace(namespace)
	for k, v := range params {
		req.Param(k, v)
	}

	res := req.Do()
	if res.Error() != nil {
		return nil, fmt.Errorf("unable to retrieve Pods: %v", res.Error())
	}
	list := &v1.PodList{}
	if err := res.Into(list); err != nil {
		return nil, fmt.Errorf("unable to parse PodList: %v", res.Error())
	}
	return list.Items, nil
}

// GetPilotAgentContainer retrieves the pilot-agent container name for the specified pod
func (client *Client) GetPilotAgentContainer(podName, podNamespace string) (string, error) {
	req := client.Get().
		Resource("pods").
		Namespace(podNamespace).
		Name(podName)

	res := req.Do()
	if res.Error() != nil {
		return "", fmt.Errorf("unable to retrieve Pod: %v", res.Error())
	}
	pod := &v1.Pod{}
	if err := res.Into(pod); err != nil {
		return "", fmt.Errorf("unable to parse Pod: %v", res.Error())
	}
	for _, c := range pod.Spec.Containers {
		switch c.Name {
		case "egressgateway", "ingress", "ingressgateway":
			return c.Name, nil
		}
	}
	return proxyContainer, nil
}

type podDetail struct {
	binary    string
	container string
}

// GetIstioVersions gets the version for each Istio component
func (client *Client) GetIstioVersions(namespace string) (*version.MeshInfo, error) {
	pods, err := client.GetIstioPods(namespace, map[string]string{"labelSelector": "istio"})
	if err != nil {
		return nil, err
	}
	if len(pods) == 0 {
		return nil, errors.New("unable to find any Istio pod in namespace " + namespace)
	}

	labelToPodDetail := map[string]podDetail{
		"pilot":            {"/usr/local/bin/pilot-discovery", "discovery"},
		"citadel":          {"/usr/local/bin/istio_ca", "citadel"},
		"egressgateway":    {"/usr/local/bin/pilot-agent", "istio-proxy"},
		"galley":           {"/usr/local/bin/galley", "galley"},
		"ingressgateway":   {"/usr/local/bin/pilot-agent", "istio-proxy"},
		"telemetry":        {"/usr/local/bin/mixs", "mixer"},
		"policy":           {"/usr/local/bin/mixs", "mixer"},
		"sidecar-injector": {"/usr/local/bin/sidecar-injector", "sidecar-injector-webhook"},
	}

	res := version.MeshInfo{}
	for _, pod := range pods {
		component := pod.Labels["istio"]

		// Special cases
		switch component {
		case "statsd-prom-bridge":
			continue
		case "mixer":
			component = pod.Labels["istio-mixer-type"]
		}

		server := version.ServerInfo{Component: component}

		if detail, ok := labelToPodDetail[component]; ok {
			cmd := []string{detail.binary, "version"}
			cmdJSON := append(cmd, "-o", "json")

			var info version.BuildInfo
			var v version.Version

			stdout, stderr, err := client.PodExec(pod.Name, pod.Namespace, detail.container, cmdJSON)

			if err != nil {
				return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, err)
			}

			// At first try parsing stdout
			err = json.Unmarshal(stdout.Bytes(), &v)
			if err == nil && v.ClientVersion.Version != "" {
				info = *v.ClientVersion
			} else {
				// If stdout fails, try the old behavior
				if strings.HasPrefix(stderr.String(), "Error: unknown shorthand flag") {
					stdout, err := client.ExtractExecResult(pod.Name, pod.Namespace, detail.container, cmd)
					if err != nil {
						return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, err)
					}

					info, err = version.NewBuildInfoFromOldString(string(stdout))
					if err != nil {
						return nil, fmt.Errorf("error converting server info from JSON: %v", err)
					}
				} else {
					return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, stderr.String())
				}
			}

			server.Info = info
		}
		res = append(res, server)
	}
	return &res, nil
}
<commit_msg>istioctl proxy-status should only exec into running pilot pods (#11539)<commit_after>// Copyright 2018 Istio 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 kubernetes

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

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/remotecommand"

	"istio.io/istio/pkg/kube"
	"istio.io/istio/pkg/version"
)

var (
	proxyContainer     = "istio-proxy"
	discoveryContainer = "discovery"
	pilotDiscoveryPath = "/usr/local/bin/pilot-discovery"
	pilotAgentPath     = "/usr/local/bin/pilot-agent"
)

// Client is a helper wrapper around the Kube RESTClient for istioctl -> Pilot/Envoy/Mesh related things
type Client struct {
	Config *rest.Config
	*rest.RESTClient
}

// ExecClient is an interface for remote execution
type ExecClient interface {
	EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error)
	AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error)
	GetIstioVersions(namespace string) (*version.MeshInfo, error)
}

// NewClient is the constructor for the client wrapper
func NewClient(kubeconfig, configContext string) (*Client, error) {
	config, err := defaultRestConfig(kubeconfig, configContext)
	if err != nil {
		return nil, err
	}
	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		return nil, err
	}
	return &Client{config, restClient}, nil
}

func defaultRestConfig(kubeconfig, configContext string) (*rest.Config, error) {
	config, err := kube.BuildClientConfig(kubeconfig, configContext)
	if err != nil {
		return nil, err
	}
	config.APIPath = "/api"
	config.GroupVersion = &v1.SchemeGroupVersion
	config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
	return config, nil
}

// PodExec takes a command and the pod data to run the command in the specified pod
func (client *Client) PodExec(podName, podNamespace, container string, command []string) (*bytes.Buffer, *bytes.Buffer, error) {
	req := client.Post().
		Resource("pods").
		Name(podName).
		Namespace(podNamespace).
		SubResource("exec").
		Param("container", container).
		VersionedParams(&v1.PodExecOptions{
			Container: container,
			Command:   command,
			Stdin:     false,
			Stdout:    true,
			Stderr:    true,
			TTY:       false,
		}, scheme.ParameterCodec)

	exec, err := remotecommand.NewSPDYExecutor(client.Config, "POST", req.URL())
	if err != nil {
		return nil, nil, err
	}

	var stdout, stderr bytes.Buffer
	err = exec.Stream(remotecommand.StreamOptions{
		Stdin:  nil,
		Stdout: &stdout,
		Stderr: &stderr,
		Tty:    false,
	})

	return &stdout, &stderr, err
}

// AllPilotsDiscoveryDo makes an http request to each Pilot discovery instance
func (client *Client) AllPilotsDiscoveryDo(pilotNamespace, method, path string, body []byte) (map[string][]byte, error) {
	pilots, err := client.GetIstioPods(pilotNamespace, map[string]string{
		"labelSelector": "istio=pilot",
		"fieldSelector": "status.phase=Running",
	})
	if err != nil {
		return nil, err
	}
	if len(pilots) == 0 {
		return nil, errors.New("unable to find any Pilot instances")
	}
	cmd := []string{pilotDiscoveryPath, "request", method, path, string(body)}
	result := map[string][]byte{}
	for _, pilot := range pilots {
		res, err := client.ExtractExecResult(pilot.Name, pilot.Namespace, discoveryContainer, cmd)
		if err != nil {
			return nil, err
		}
		if len(res) > 0 {
			result[pilot.Name] = res
		}
	}
	return result, err
}

// PilotDiscoveryDo makes an http request to a single Pilot discovery instance
func (client *Client) PilotDiscoveryDo(pilotNamespace, method, path string, body []byte) ([]byte, error) {
	pilots, err := client.GetIstioPods(pilotNamespace, map[string]string{
		"labelSelector": "istio=pilot",
		"fieldSelector": "status.phase=Running",
	})
	if err != nil {
		return nil, err
	}
	if len(pilots) == 0 {
		return nil, errors.New("unable to find any Pilot instances")
	}
	cmd := []string{pilotDiscoveryPath, "request", method, path, string(body)}
	return client.ExtractExecResult(pilots[0].Name, pilots[0].Namespace, discoveryContainer, cmd)
}

// EnvoyDo makes an http request to the Envoy in the specified pod
func (client *Client) EnvoyDo(podName, podNamespace, method, path string, body []byte) ([]byte, error) {
	container, err := client.GetPilotAgentContainer(podName, podNamespace)
	if err != nil {
		return nil, fmt.Errorf("unable to retrieve proxy container name: %v", err)
	}
	cmd := []string{pilotAgentPath, "request", method, path, string(body)}
	return client.ExtractExecResult(podName, podNamespace, container, cmd)
}

// ExtractExecResult wraps PodExec and return the execution result and error if has any.
func (client *Client) ExtractExecResult(podName, podNamespace, container string, cmd []string) ([]byte, error) {
	stdout, stderr, err := client.PodExec(podName, podNamespace, container, cmd)
	if err != nil {
		return nil, fmt.Errorf("error execing into %v/%v %v container: %v", podName, podNamespace, container, err)
	}
	if stderr.String() != "" {
		fmt.Printf("Warning! error execing into %v/%v %v container: %v\n", podName, podNamespace, container, stderr.String())
	}
	return stdout.Bytes(), nil
}

// GetIstioPods retrieves the pod objects for Istio deployments
func (client *Client) GetIstioPods(namespace string, params map[string]string) ([]v1.Pod, error) {
	req := client.Get().
		Resource("pods").
		Namespace(namespace)
	for k, v := range params {
		req.Param(k, v)
	}

	res := req.Do()
	if res.Error() != nil {
		return nil, fmt.Errorf("unable to retrieve Pods: %v", res.Error())
	}
	list := &v1.PodList{}
	if err := res.Into(list); err != nil {
		return nil, fmt.Errorf("unable to parse PodList: %v", res.Error())
	}
	return list.Items, nil
}

// GetPilotAgentContainer retrieves the pilot-agent container name for the specified pod
func (client *Client) GetPilotAgentContainer(podName, podNamespace string) (string, error) {
	req := client.Get().
		Resource("pods").
		Namespace(podNamespace).
		Name(podName)

	res := req.Do()
	if res.Error() != nil {
		return "", fmt.Errorf("unable to retrieve Pod: %v", res.Error())
	}
	pod := &v1.Pod{}
	if err := res.Into(pod); err != nil {
		return "", fmt.Errorf("unable to parse Pod: %v", res.Error())
	}
	for _, c := range pod.Spec.Containers {
		switch c.Name {
		case "egressgateway", "ingress", "ingressgateway":
			return c.Name, nil
		}
	}
	return proxyContainer, nil
}

type podDetail struct {
	binary    string
	container string
}

// GetIstioVersions gets the version for each Istio component
func (client *Client) GetIstioVersions(namespace string) (*version.MeshInfo, error) {
	pods, err := client.GetIstioPods(namespace, map[string]string{
		"labelSelector": "istio",
		"fieldSelector": "status.phase=Running",
	})
	if err != nil {
		return nil, err
	}
	if len(pods) == 0 {
		return nil, errors.New("unable to find any Istio pod in namespace " + namespace)
	}

	labelToPodDetail := map[string]podDetail{
		"pilot":            {"/usr/local/bin/pilot-discovery", "discovery"},
		"citadel":          {"/usr/local/bin/istio_ca", "citadel"},
		"egressgateway":    {"/usr/local/bin/pilot-agent", "istio-proxy"},
		"galley":           {"/usr/local/bin/galley", "galley"},
		"ingressgateway":   {"/usr/local/bin/pilot-agent", "istio-proxy"},
		"telemetry":        {"/usr/local/bin/mixs", "mixer"},
		"policy":           {"/usr/local/bin/mixs", "mixer"},
		"sidecar-injector": {"/usr/local/bin/sidecar-injector", "sidecar-injector-webhook"},
	}

	res := version.MeshInfo{}
	for _, pod := range pods {
		component := pod.Labels["istio"]

		// Special cases
		switch component {
		case "statsd-prom-bridge":
			continue
		case "mixer":
			component = pod.Labels["istio-mixer-type"]
		}

		server := version.ServerInfo{Component: component}

		if detail, ok := labelToPodDetail[component]; ok {
			cmd := []string{detail.binary, "version"}
			cmdJSON := append(cmd, "-o", "json")

			var info version.BuildInfo
			var v version.Version

			stdout, stderr, err := client.PodExec(pod.Name, pod.Namespace, detail.container, cmdJSON)

			if err != nil {
				return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, err)
			}

			// At first try parsing stdout
			err = json.Unmarshal(stdout.Bytes(), &v)
			if err == nil && v.ClientVersion.Version != "" {
				info = *v.ClientVersion
			} else {
				// If stdout fails, try the old behavior
				if strings.HasPrefix(stderr.String(), "Error: unknown shorthand flag") {
					stdout, err := client.ExtractExecResult(pod.Name, pod.Namespace, detail.container, cmd)
					if err != nil {
						return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, err)
					}

					info, err = version.NewBuildInfoFromOldString(string(stdout))
					if err != nil {
						return nil, fmt.Errorf("error converting server info from JSON: %v", err)
					}
				} else {
					return nil, fmt.Errorf("error execing into %v %v container: %v", pod.Name, detail.container, stderr.String())
				}
			}

			server.Info = info
		}
		res = append(res, server)
	}
	return &res, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		client := newCharmstoreClient()
		return &charmstoreClient{client}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowServiceCommand(cmd.ShowServiceDeps{
			NewClient: func(c *cmd.ShowServiceCommand) (cmd.ShowServiceClient, error) {
				return r.newClient(c)
			},
		})
	})
}

func newCharmstoreClient() charmrepo.Interface {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	client := charmrepo.NewCharmStore(args)
	return client
}

// TODO(ericsnow) Get rid of charmstoreClient one charmrepo.Interface grows the methods.

type charmstoreClient struct {
	charmrepo.Interface
}

func (charmstoreClient) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	// TODO(natefinch): this is all demo stuff and should go away afterward.
	if len(charmURLs) != 1 || charmURLs[0].Name != "starsay" {
		res := make([][]charmresource.Resource, len(charmURLs))
		return res, nil
	}
	var fingerprint = []byte("123456789012345678901234567890123456789012345678")
	fp, err := charmresource.NewFingerprint(fingerprint)
	if err != nil {
		return nil, err
	}
	res := [][]charmresource.Resource{
		{
			{
				Meta: charmresource.Meta{
					Name:    "store-resource",
					Type:    charmresource.TypeFile,
					Path:    "filename.tgz",
					Comment: "One line that is useful when operators need to push it.",
				},
				Origin:      charmresource.OriginStore,
				Revision:    1,
				Fingerprint: fp,
				Size:        1,
			},
			{
				Meta: charmresource.Meta{
					Name:    "upload-resource",
					Type:    charmresource.TypeFile,
					Path:    "somename.xml",
					Comment: "Who uses xml anymore?",
				},
				Origin: charmresource.OriginUpload,
			},
		},
	}
	return res, nil
}

func (charmstoreClient) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)
	doer, err := apiCaller.HTTPClient()
	if err != nil {
		return nil, errors.Trace(err)
	}

	return client.NewClient(caller, doer, apiCaller), nil
}
<commit_msg>Pass the env UUID to NewClient().<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package all

import (
	"io"
	"os"

	"github.com/juju/errors"
	"gopkg.in/juju/charm.v6-unstable"
	charmresource "gopkg.in/juju/charm.v6-unstable/resource"
	"gopkg.in/juju/charmrepo.v2-unstable"

	"github.com/juju/juju/api"
	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/common"
	"github.com/juju/juju/cmd/envcmd"
	"github.com/juju/juju/cmd/juju/commands"
	"github.com/juju/juju/resource"
	"github.com/juju/juju/resource/api/client"
	"github.com/juju/juju/resource/api/server"
	"github.com/juju/juju/resource/cmd"
	"github.com/juju/juju/resource/persistence"
	"github.com/juju/juju/resource/state"
	corestate "github.com/juju/juju/state"
)

// resources exposes the registration methods needed
// for the top-level component machinery.
type resources struct{}

// RegisterForServer is the top-level registration method
// for the component in a jujud context.
func (r resources) registerForServer() error {
	r.registerState()
	r.registerPublicFacade()
	return nil
}

// RegisterForClient is the top-level registration method
// for the component in a "juju" command context.
func (r resources) registerForClient() error {
	r.registerPublicCommands()
	return nil
}

// registerPublicFacade adds the resources public API facade
// to the API server.
func (r resources) registerPublicFacade() {
	if !markRegistered(resource.ComponentName, "public-facade") {
		return
	}

	common.RegisterStandardFacade(
		resource.ComponentName,
		server.Version,
		r.newPublicFacade,
	)
}

// newPublicFacade is passed into common.RegisterStandardFacade
// in registerPublicFacade.
func (resources) newPublicFacade(st *corestate.State, _ *common.Resources, authorizer common.Authorizer) (*server.Facade, error) {
	if !authorizer.AuthClient() {
		return nil, common.ErrPerm
	}

	rst, err := st.Resources()
	//rst, err := state.NewState(&resourceState{raw: st})
	if err != nil {
		return nil, errors.Trace(err)
	}

	return server.NewFacade(rst), nil
}

// resourcesApiClient adds a Close() method to the resources public API client.
type resourcesAPIClient struct {
	*client.Client
	closeConnFunc func() error
}

// Close implements io.Closer.
func (client resourcesAPIClient) Close() error {
	return client.closeConnFunc()
}

// registerState registers the state functionality for resources.
func (resources) registerState() {
	if !markRegistered(resource.ComponentName, "state") {
		return
	}

	newResources := func(persist corestate.Persistence) corestate.Resources {
		st := state.NewState(&resourceState{persist: persist})
		return st
	}

	corestate.SetResourcesComponent(newResources)
}

// resourceState is a wrapper around state.State that supports the needs
// of resources.
type resourceState struct {
	persist corestate.Persistence
}

// Persistence implements resource/state.RawState.
func (st resourceState) Persistence() state.Persistence {
	return persistence.NewPersistence(st.persist)
}

// Storage implements resource/state.RawState.
func (st resourceState) Storage() state.Storage {
	return st.persist.NewStorage()
}

// registerPublicCommands adds the resources-related commands
// to the "juju" supercommand.
func (r resources) registerPublicCommands() {
	if !markRegistered(resource.ComponentName, "public-commands") {
		return
	}

	newShowAPIClient := func(command *cmd.ShowCommand) (cmd.CharmResourceLister, error) {
		client := newCharmstoreClient()
		return &charmstoreClient{client}, nil
	}
	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowCommand(newShowAPIClient)
	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewUploadCommand(cmd.UploadDeps{
			NewClient: func(c *cmd.UploadCommand) (cmd.UploadClient, error) {
				return r.newClient(c)
			},
			OpenResource: func(s string) (io.ReadCloser, error) {
				return os.Open(s)
			},
		})

	})

	commands.RegisterEnvCommand(func() envcmd.EnvironCommand {
		return cmd.NewShowServiceCommand(cmd.ShowServiceDeps{
			NewClient: func(c *cmd.ShowServiceCommand) (cmd.ShowServiceClient, error) {
				return r.newClient(c)
			},
		})
	})
}

func newCharmstoreClient() charmrepo.Interface {
	// Also see apiserver/service/charmstore.go.
	var args charmrepo.NewCharmStoreParams
	client := charmrepo.NewCharmStore(args)
	return client
}

// TODO(ericsnow) Get rid of charmstoreClient one charmrepo.Interface grows the methods.

type charmstoreClient struct {
	charmrepo.Interface
}

func (charmstoreClient) ListResources(charmURLs []charm.URL) ([][]charmresource.Resource, error) {
	// TODO(natefinch): this is all demo stuff and should go away afterward.
	if len(charmURLs) != 1 || charmURLs[0].Name != "starsay" {
		res := make([][]charmresource.Resource, len(charmURLs))
		return res, nil
	}
	var fingerprint = []byte("123456789012345678901234567890123456789012345678")
	fp, err := charmresource.NewFingerprint(fingerprint)
	if err != nil {
		return nil, err
	}
	res := [][]charmresource.Resource{
		{
			{
				Meta: charmresource.Meta{
					Name:    "store-resource",
					Type:    charmresource.TypeFile,
					Path:    "filename.tgz",
					Comment: "One line that is useful when operators need to push it.",
				},
				Origin:      charmresource.OriginStore,
				Revision:    1,
				Fingerprint: fp,
				Size:        1,
			},
			{
				Meta: charmresource.Meta{
					Name:    "upload-resource",
					Type:    charmresource.TypeFile,
					Path:    "somename.xml",
					Comment: "Who uses xml anymore?",
				},
				Origin: charmresource.OriginUpload,
			},
		},
	}
	return res, nil
}

func (charmstoreClient) Close() error {
	return nil
}

type apicommand interface {
	NewAPIRoot() (api.Connection, error)
}

func (resources) newClient(command apicommand) (*client.Client, error) {
	apiCaller, err := command.NewAPIRoot()
	if err != nil {
		return nil, errors.Trace(err)
	}
	caller := base.NewFacadeCallerForVersion(apiCaller, resource.ComponentName, server.Version)
	doer, err := apiCaller.HTTPClient()
	if err != nil {
		return nil, errors.Trace(err)
	}

	envTag, err := apiCaller.EnvironTag()
	if err != nil {
		return nil, errors.Trace(err)
	}
	envUUID := envTag.Id()

	cl := client.NewClient(caller, doer, envUUID, apiCaller)
	return cl, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Xiaomi Corporation. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 *
 * Authors:    Yu Bo <yubo@xiaomi.com>
 */
package govs

import (
	"fmt"
	"strings"
)

type Vs_dest_user struct {
	Nic         uint8
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
}

type Vs_dest_user_r struct {
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
	Activeconns uint32
	Inactconns  uint32
	Persistent  uint32
	Conns       uint64
	Inpkts      uint64
	Outpkts     uint64
	Inbytes     uint64
	Outbytes    uint64
}

const (
	fmt_dest_t = "%5s %21s %8s %8s %15s %12s %12s %12s %7s %10s %10s %10s %10s"
	fmt_dest   = "%5s %21s %08x %8d %15s %12d %12d %12d %7d %10d %10d %10d %10d"
)

func Dest_title() string {
	return fmt.Sprintf(fmt_dest_t,
		"->", "Addr:Port", "Flags", "Weight", "threshold",
		"Activeconns", "Inactconns", "Persistent",
		"Conns", "Inpkts", "Outpkts", "Inbytes", "Outbytes")
}

func (d Vs_dest_user_r) String() string {
	return fmt.Sprintf(fmt_dest,
		"->", fmt.Sprintf("%s:%s", d.Addr.String(), d.Port.String()), d.Conn_flags,
		d.Weight, fmt.Sprintf("%d-%d", d.L_threshold, d.U_threshold),
		d.Activeconns, d.Inactconns, d.Persistent,
		d.Conns, d.Inpkts, d.Outpkts, d.Inbytes, d.Outbytes)
}

type Vs_list_dests_r struct {
	Code  int
	Msg   string
	Dests []Vs_dest_user_r
}

func (r Vs_list_dests_r) String() string {
	var s string
	if r.Code != 0 {
		return fmt.Sprintf("%s:%s", Ecode(r.Code), r.Msg)
	}
	for _, dest := range r.Dests {
		s += fmt.Sprintf("%s\n", dest)
	}

	return strings.TrimRight(s, "\n")
}

func Get_dests(o *CmdOptions) (*Vs_list_dests_r, error) {
	var reply Vs_list_dests_r
	args := Vs_list_q{
		Cmd: VS_CMD_GET_DEST,
		Service: Vs_service_user{
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
			Protocol: uint8(o.Protocol),
			Number:   o.Number,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

type Vs_dest_q struct {
	Cmd     int
	Service Vs_service_user
	Dest    Vs_dest_user
}

func Set_adddest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_NEW_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_editdest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_SET_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_deldest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_DEL_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Addr: o.Addr.Ip,
			Port: o.Addr.Port,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}
<commit_msg>fix: del realserver<commit_after>/*
 * Copyright 2016 Xiaomi Corporation. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 *
 * Authors:    Yu Bo <yubo@xiaomi.com>
 */
package govs

import (
	"fmt"
	"strings"
)

type Vs_dest_user struct {
	Nic         uint8
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
}

type Vs_dest_user_r struct {
	Addr        Be32
	Port        Be16
	Conn_flags  uint
	Weight      int
	U_threshold uint32
	L_threshold uint32
	Activeconns uint32
	Inactconns  uint32
	Persistent  uint32
	Conns       uint64
	Inpkts      uint64
	Outpkts     uint64
	Inbytes     uint64
	Outbytes    uint64
}

const (
	fmt_dest_t = "%5s %21s %8s %8s %15s %12s %12s %12s %7s %10s %10s %10s %10s"
	fmt_dest   = "%5s %21s %08x %8d %15s %12d %12d %12d %7d %10d %10d %10d %10d"
)

func Dest_title() string {
	return fmt.Sprintf(fmt_dest_t,
		"->", "Addr:Port", "Flags", "Weight", "threshold",
		"Activeconns", "Inactconns", "Persistent",
		"Conns", "Inpkts", "Outpkts", "Inbytes", "Outbytes")
}

func (d Vs_dest_user_r) String() string {
	return fmt.Sprintf(fmt_dest,
		"->", fmt.Sprintf("%s:%s", d.Addr.String(), d.Port.String()), d.Conn_flags,
		d.Weight, fmt.Sprintf("%d-%d", d.L_threshold, d.U_threshold),
		d.Activeconns, d.Inactconns, d.Persistent,
		d.Conns, d.Inpkts, d.Outpkts, d.Inbytes, d.Outbytes)
}

type Vs_list_dests_r struct {
	Code  int
	Msg   string
	Dests []Vs_dest_user_r
}

func (r Vs_list_dests_r) String() string {
	var s string
	if r.Code != 0 {
		return fmt.Sprintf("%s:%s", Ecode(r.Code), r.Msg)
	}
	for _, dest := range r.Dests {
		s += fmt.Sprintf("%s\n", dest)
	}

	return strings.TrimRight(s, "\n")
}

func Get_dests(o *CmdOptions) (*Vs_list_dests_r, error) {
	var reply Vs_list_dests_r
	args := Vs_list_q{
		Cmd: VS_CMD_GET_DEST,
		Service: Vs_service_user{
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
			Protocol: uint8(o.Protocol),
			Number:   o.Number,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

type Vs_dest_q struct {
	Cmd     int
	Service Vs_service_user
	Dest    Vs_dest_user
}

func Set_adddest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_NEW_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_editdest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_SET_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Nic:         uint8(o.Dnic),
			Addr:        o.Daddr.Ip,
			Port:        o.Daddr.Port,
			Conn_flags:  o.Conn_flags | VS_CONN_F_FULLNAT,
			Weight:      o.Weight,
			U_threshold: uint32(o.U_threshold),
			L_threshold: uint32(o.L_threshold),
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}

func Set_deldest(o *CmdOptions) (*Vs_cmd_r, error) {
	var reply Vs_cmd_r
	args := Vs_dest_q{
		Cmd: VS_CMD_DEL_DEST,
		Service: Vs_service_user{
			Protocol: uint8(o.Protocol),
			Addr:     o.Addr.Ip,
			Port:     o.Addr.Port,
		},
		Dest: Vs_dest_user{
			Addr: o.Daddr.Ip,
			Port: o.Daddr.Port,
		},
	}

	err := client.Call("api", args, &reply)
	return &reply, err
}
<|endoftext|>


<commit_before>// Example of minimal DHCP server:
package main

import (
	"encoding/binary"
	"encoding/json"
	dhcp "github.com/krolaw/dhcp4"
	"github.com/willf/bitset"
	"log"
	"net"
	"time"
)

type Subnet struct {
	Name              string
	Subnet            *MyIPNet
	NextServer        *net.IP `"json:,omitempty"`
	ActiveStart       net.IP
	ActiveEnd         net.IP
	ActiveLeaseTime   time.Duration
	ActiveBits        *bitset.BitSet
	ReservedLeaseTime time.Duration
	Leases            map[string]*Lease
	Bindings          map[string]*Binding
	Options           dhcp.Options // Options to send to DHCP Clients
}

func NewSubnet() *Subnet {
	return &Subnet{
		Leases:     make(map[string]*Lease),
		Bindings:   make(map[string]*Binding),
		Options:    make(dhcp.Options),
		ActiveBits: bitset.New(0),
	}
}

func (s *Subnet) MarshalJSON() ([]byte, error) {
	as := convertSubnetToApiSubnet(s)
	return json.Marshal(as)
}

func (s *Subnet) UnmarshalJSON(data []byte) error {
	var as ApiSubnet

	err := json.Unmarshal(data, &as)
	if err != nil {
		return err
	}

	if s.Leases == nil {
		s.Leases = make(map[string]*Lease)
	}
	if s.Bindings == nil {
		s.Bindings = make(map[string]*Binding)
	}
	if s.Options == nil {
		s.Options = make(dhcp.Options)
	}
	if s.ActiveBits == nil {
		s.ActiveBits = bitset.New(0)
	}
	_, err = convertApiSubnetToSubnet(&as, s)
	return err
}

func (subnet *Subnet) free_lease(dt *DataTracker, nic string) {
	lease := subnet.Leases[nic]
	if lease != nil {
		if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
			subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
		}
		delete(subnet.Leases, nic)
		dt.save_data()
	}
}

func (subnet *Subnet) find_info(dt *DataTracker, nic string) (*Lease, *Binding) {
	return subnet.Leases[nic], subnet.Bindings[nic]
}

func firstClearBit(bs *bitset.BitSet) (uint, bool) {
	for i := uint(0); i < bs.Len(); i++ {
		if !bs.Test(i) {
			return i, true
		}
	}
	return 0, false
}

func (subnet *Subnet) getFreeIP() (*net.IP, bool) {
	bit, success := firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// Free invalid or expired leases
	save_me := false
	now := time.Now()
	for k, lease := range subnet.Leases {
		if now.After(lease.ExpireTime) {
			if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
				subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
			}
			delete(subnet.Leases, k)
			save_me = true
		}
	}

	bit, success = firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// We got nothin'
	return nil, save_me
}

func (subnet *Subnet) find_or_get_info(dt *DataTracker, nic string, suggest net.IP) (*Lease, *Binding) {
	lease, binding := subnet.find_info(dt, nic)

	var theip *net.IP

	if binding != nil {
		theip = &binding.Ip
	}

	// Resolve potential conflicts.
	if lease != nil && binding != nil {
		if !lease.Ip.Equal(binding.Ip) {
			// Let the lease go.
			lease = nil
		}
	}

	if lease == nil {
		if theip == nil {
			var save_me bool
			theip, save_me = subnet.getFreeIP()
			if theip == nil {
				if save_me {
					dt.save_data()
				}
				return nil, nil
			}
		}
		lease = &Lease{
			Ip:    *theip,
			Mac:   nic,
			Valid: true,
		}
		subnet.Leases[nic] = lease
		dt.save_data()
	}

	return lease, binding
}

func (s *Subnet) update_lease_time(dt *DataTracker, lease *Lease, d time.Duration) {
	lease.ExpireTime = time.Now().Add(d)
	dt.save_data()
}

func (s *Subnet) build_options(lease *Lease, binding *Binding) (dhcp.Options, time.Duration) {
	var lt time.Duration
	if binding == nil {
		lt = s.ActiveLeaseTime
	} else {
		lt = s.ReservedLeaseTime
	}

	opts := make(dhcp.Options)

	// Build renewal / rebinding time options
	b := make([]byte, 4)
	binary.BigEndian.PutUint32(b, uint32(lt)/2)
	opts[dhcp.OptionRenewalTimeValue] = b
	b = make([]byte, 4)
	binary.BigEndian.PutUint32(b, uint32(lt)*3/4)
	opts[dhcp.OptionRebindingTimeValue] = b

	// fold in subnet options
	for c, v := range s.Options {
		opts[c] = v
	}

	// fold in binding options
	if binding != nil {
		for _, v := range binding.Options {
			b, err := convertOptionValueToByte(v.Code, v.Value)
			if err != nil {
				log.Println("Failed to parse option: ", v.Code, " ", v.Value)
			} else {
				opts[v.Code] = b
			}
		}
	}

	return opts, lt
}

func RunDhcpHandler(dhcpInfo *DataTracker, intf net.Interface, myIp *net.Addr) {
	log.Println("Starting on interface: ", intf.Name, " with server ip: ", *myIp)

	serverIP, _, _ := net.ParseCIDR((*myIp).String())
	serverIP = serverIP.To4()
	handler := &DHCPHandler{
		ip:   serverIP,
		intf: intf,
		info: dhcpInfo,
	}
	log.Fatal(dhcp.ListenAndServeIf(intf.Name, handler))
}

type DHCPHandler struct {
	intf          net.Interface // Interface processing on.
	ip            net.IP        // Server IP to use
	info          *DataTracker  // Subnet data
	leaseDuration time.Duration // Lease period
}

func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) {

	// First find the subnet to use. giaddr field to lookup subnet if not all zeros.
	// If all zeros, use the interfaces Addrs to find a subnet, first wins.
	var subnet *Subnet
	subnet = nil

	giaddr := p.GIAddr()
	if !giaddr.Equal(net.IPv4zero) {
		subnet = h.info.FindSubnet(giaddr)
	} else {
		log.Println("Received Broadcast/Local message on ", h.intf.Name)
		addrs, err := h.intf.Addrs()
		if err != nil {
			log.Println("Can't find addresses for ", h.intf.Name, ": ", err)
		}

		for _, a := range addrs {
			aip, _, _ := net.ParseCIDR(a.String())

			// Only operate on v4 addresses
			if aip.To4() == nil {
				continue
			}

			subnet = h.info.FindSubnet(aip)
			if subnet != nil {
				break
			}
		}
	}

	if subnet == nil {
		log.Println("Can not find subnet for packet, ignoring")
		return
	}

	nic := p.CHAddr().String()
	switch msgType {

	case dhcp.Discover:
		lease, binding := subnet.find_or_get_info(h.info, nic, p.CIAddr())
		if lease == nil {
			log.Println("Out of IPs for ", subnet.Name, ", ignoring")
			return nil
		}

		options, lease_time := subnet.build_options(lease, binding)

		reply := dhcp.ReplyPacket(p, dhcp.Offer,
			h.ip,
			lease.Ip,
			lease_time,
			subnet.Options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
		return reply

	case dhcp.Request:
		server, ok := options[dhcp.OptionServerIdentifier]
		if ok && !net.IP(server).Equal(h.ip) {
			return nil // Message not for this dhcp server
		}
		reqIP := net.IP(options[dhcp.OptionRequestedIPAddress])
		if reqIP == nil {
			reqIP = net.IP(p.CIAddr())
		}

		if len(reqIP) != 4 || reqIP.Equal(net.IPv4zero) {
			return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)
		}

		lease, binding := subnet.find_info(h.info, nic)
		if lease == nil || !lease.Ip.Equal(reqIP) {
			return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)
		}

		options, lease_time := subnet.build_options(lease, binding)

		subnet.update_lease_time(h.info, lease, h.leaseDuration)

		reply := dhcp.ReplyPacket(p, dhcp.ACK,
			h.ip,
			lease.Ip,
			lease_time,
			subnet.Options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
		if binding != nil && binding.NextServer != nil {
			reply.SetSIAddr(net.ParseIP(*binding.NextServer))
		} else if subnet.NextServer != nil {
			reply.SetSIAddr(*subnet.NextServer)
		}
		return reply

	case dhcp.Release, dhcp.Decline:
		nic := p.CHAddr().String()
		subnet.free_lease(h.info, nic)
	}
	return nil
}
<commit_msg>Missed a DHCP lease time.  Use the calculated one and not the hardcoded one.<commit_after>// Example of minimal DHCP server:
package main

import (
	"encoding/binary"
	"encoding/json"
	dhcp "github.com/krolaw/dhcp4"
	"github.com/willf/bitset"
	"log"
	"net"
	"time"
)

type Subnet struct {
	Name              string
	Subnet            *MyIPNet
	NextServer        *net.IP `"json:,omitempty"`
	ActiveStart       net.IP
	ActiveEnd         net.IP
	ActiveLeaseTime   time.Duration
	ActiveBits        *bitset.BitSet
	ReservedLeaseTime time.Duration
	Leases            map[string]*Lease
	Bindings          map[string]*Binding
	Options           dhcp.Options // Options to send to DHCP Clients
}

func NewSubnet() *Subnet {
	return &Subnet{
		Leases:     make(map[string]*Lease),
		Bindings:   make(map[string]*Binding),
		Options:    make(dhcp.Options),
		ActiveBits: bitset.New(0),
	}
}

func (s *Subnet) MarshalJSON() ([]byte, error) {
	as := convertSubnetToApiSubnet(s)
	return json.Marshal(as)
}

func (s *Subnet) UnmarshalJSON(data []byte) error {
	var as ApiSubnet

	err := json.Unmarshal(data, &as)
	if err != nil {
		return err
	}

	if s.Leases == nil {
		s.Leases = make(map[string]*Lease)
	}
	if s.Bindings == nil {
		s.Bindings = make(map[string]*Binding)
	}
	if s.Options == nil {
		s.Options = make(dhcp.Options)
	}
	if s.ActiveBits == nil {
		s.ActiveBits = bitset.New(0)
	}
	_, err = convertApiSubnetToSubnet(&as, s)
	return err
}

func (subnet *Subnet) free_lease(dt *DataTracker, nic string) {
	lease := subnet.Leases[nic]
	if lease != nil {
		if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
			subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
		}
		delete(subnet.Leases, nic)
		dt.save_data()
	}
}

func (subnet *Subnet) find_info(dt *DataTracker, nic string) (*Lease, *Binding) {
	return subnet.Leases[nic], subnet.Bindings[nic]
}

func firstClearBit(bs *bitset.BitSet) (uint, bool) {
	for i := uint(0); i < bs.Len(); i++ {
		if !bs.Test(i) {
			return i, true
		}
	}
	return 0, false
}

func (subnet *Subnet) getFreeIP() (*net.IP, bool) {
	bit, success := firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// Free invalid or expired leases
	save_me := false
	now := time.Now()
	for k, lease := range subnet.Leases {
		if now.After(lease.ExpireTime) {
			if dhcp.IPInRange(subnet.ActiveStart, subnet.ActiveEnd, lease.Ip) {
				subnet.ActiveBits.Clear(uint(dhcp.IPRange(lease.Ip, subnet.ActiveStart) - 1))
			}
			delete(subnet.Leases, k)
			save_me = true
		}
	}

	bit, success = firstClearBit(subnet.ActiveBits)
	if success {
		subnet.ActiveBits.Set(bit)
		ip := dhcp.IPAdd(subnet.ActiveStart, int(bit))
		return &ip, true
	}

	// We got nothin'
	return nil, save_me
}

func (subnet *Subnet) find_or_get_info(dt *DataTracker, nic string, suggest net.IP) (*Lease, *Binding) {
	lease, binding := subnet.find_info(dt, nic)

	var theip *net.IP

	if binding != nil {
		theip = &binding.Ip
	}

	// Resolve potential conflicts.
	if lease != nil && binding != nil {
		if !lease.Ip.Equal(binding.Ip) {
			// Let the lease go.
			lease = nil
		}
	}

	if lease == nil {
		if theip == nil {
			var save_me bool
			theip, save_me = subnet.getFreeIP()
			if theip == nil {
				if save_me {
					dt.save_data()
				}
				return nil, nil
			}
		}
		lease = &Lease{
			Ip:    *theip,
			Mac:   nic,
			Valid: true,
		}
		subnet.Leases[nic] = lease
		dt.save_data()
	}

	return lease, binding
}

func (s *Subnet) update_lease_time(dt *DataTracker, lease *Lease, d time.Duration) {
	lease.ExpireTime = time.Now().Add(d)
	dt.save_data()
}

func (s *Subnet) build_options(lease *Lease, binding *Binding) (dhcp.Options, time.Duration) {
	var lt time.Duration
	if binding == nil {
		lt = s.ActiveLeaseTime
	} else {
		lt = s.ReservedLeaseTime
	}

	opts := make(dhcp.Options)

	// Build renewal / rebinding time options
	b := make([]byte, 4)
	binary.BigEndian.PutUint32(b, uint32(lt)/2)
	opts[dhcp.OptionRenewalTimeValue] = b
	b = make([]byte, 4)
	binary.BigEndian.PutUint32(b, uint32(lt)*3/4)
	opts[dhcp.OptionRebindingTimeValue] = b

	// fold in subnet options
	for c, v := range s.Options {
		opts[c] = v
	}

	// fold in binding options
	if binding != nil {
		for _, v := range binding.Options {
			b, err := convertOptionValueToByte(v.Code, v.Value)
			if err != nil {
				log.Println("Failed to parse option: ", v.Code, " ", v.Value)
			} else {
				opts[v.Code] = b
			}
		}
	}

	return opts, lt
}

func RunDhcpHandler(dhcpInfo *DataTracker, intf net.Interface, myIp *net.Addr) {
	log.Println("Starting on interface: ", intf.Name, " with server ip: ", *myIp)

	serverIP, _, _ := net.ParseCIDR((*myIp).String())
	serverIP = serverIP.To4()
	handler := &DHCPHandler{
		ip:   serverIP,
		intf: intf,
		info: dhcpInfo,
	}
	log.Fatal(dhcp.ListenAndServeIf(intf.Name, handler))
}

type DHCPHandler struct {
	intf net.Interface // Interface processing on.
	ip   net.IP        // Server IP to use
	info *DataTracker  // Subnet data
}

func (h *DHCPHandler) ServeDHCP(p dhcp.Packet, msgType dhcp.MessageType, options dhcp.Options) (d dhcp.Packet) {

	// First find the subnet to use. giaddr field to lookup subnet if not all zeros.
	// If all zeros, use the interfaces Addrs to find a subnet, first wins.
	var subnet *Subnet
	subnet = nil

	giaddr := p.GIAddr()
	if !giaddr.Equal(net.IPv4zero) {
		subnet = h.info.FindSubnet(giaddr)
	} else {
		log.Println("Received Broadcast/Local message on ", h.intf.Name)
		addrs, err := h.intf.Addrs()
		if err != nil {
			log.Println("Can't find addresses for ", h.intf.Name, ": ", err)
		}

		for _, a := range addrs {
			aip, _, _ := net.ParseCIDR(a.String())

			// Only operate on v4 addresses
			if aip.To4() == nil {
				continue
			}

			subnet = h.info.FindSubnet(aip)
			if subnet != nil {
				break
			}
		}
	}

	if subnet == nil {
		log.Println("Can not find subnet for packet, ignoring")
		return
	}

	nic := p.CHAddr().String()
	switch msgType {

	case dhcp.Discover:
		lease, binding := subnet.find_or_get_info(h.info, nic, p.CIAddr())
		if lease == nil {
			log.Println("Out of IPs for ", subnet.Name, ", ignoring")
			return nil
		}

		options, lease_time := subnet.build_options(lease, binding)

		reply := dhcp.ReplyPacket(p, dhcp.Offer,
			h.ip,
			lease.Ip,
			lease_time,
			subnet.Options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
		return reply

	case dhcp.Request:
		server, ok := options[dhcp.OptionServerIdentifier]
		if ok && !net.IP(server).Equal(h.ip) {
			return nil // Message not for this dhcp server
		}
		reqIP := net.IP(options[dhcp.OptionRequestedIPAddress])
		if reqIP == nil {
			reqIP = net.IP(p.CIAddr())
		}

		if len(reqIP) != 4 || reqIP.Equal(net.IPv4zero) {
			return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)
		}

		lease, binding := subnet.find_info(h.info, nic)
		if lease == nil || !lease.Ip.Equal(reqIP) {
			return dhcp.ReplyPacket(p, dhcp.NAK, h.ip, nil, 0, nil)
		}

		options, lease_time := subnet.build_options(lease, binding)

		subnet.update_lease_time(h.info, lease, lease_time)

		reply := dhcp.ReplyPacket(p, dhcp.ACK,
			h.ip,
			lease.Ip,
			lease_time,
			subnet.Options.SelectOrderOrAll(options[dhcp.OptionParameterRequestList]))
		if binding != nil && binding.NextServer != nil {
			reply.SetSIAddr(net.ParseIP(*binding.NextServer))
		} else if subnet.NextServer != nil {
			reply.SetSIAddr(*subnet.NextServer)
		}
		return reply

	case dhcp.Release, dhcp.Decline:
		nic := p.CHAddr().String()
		subnet.free_lease(h.info, nic)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	dominantcolor "github.com/cenkalti/dominantcolor"
	"image"
	"image/color"
	"image/jpeg"
	"log"
	"math"
	"os"
	"strconv"
)

func main() {
	file, err := os.Open("_test/pic.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		log.Fatal(err)
	}

	screenRect := image.Rect(1350, 663, 2200, 975)
	screen := img.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(screenRect)

	/*

	   Dividing screen into 6 areas

	              A         B         A
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   0   |     2     |   4   |
	          |       |           |       |
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   1   |     3     |   5   |
	          |       |           |       |
	    ----- -----------------------------
	          |  20%  |    40%    |  20%  |

	*/
	var areas [6]image.Image

	x0 := float64(screenRect.Dx() / 100)
	xA := int(math.Floor(x0 * 20))

	y := int(math.Floor(float64(screenRect.Dy() / 2)))

	bounds := screenRect

	areaRect := image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Min.X+xA, bounds.Min.Y+y)
	areas[0] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X, bounds.Min.Y+y, bounds.Min.X+xA, bounds.Max.Y)
	areas[1] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y, bounds.Max.X-xA, bounds.Min.Y+y)
	areas[2] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y+y, bounds.Max.X-xA, bounds.Max.Y)
	areas[3] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y, bounds.Max.X, bounds.Min.Y+y)
	areas[4] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y+y, bounds.Max.X, bounds.Max.Y)
	areas[5] = screen.(interface {
		SubImage(r image.Rectangle) image.Image
	}).SubImage(areaRect)

	for i := 0; i < len(areas); i++ {
		color := dominantcolor.Find(areas[i])
		log.Println(i, color)

		out, err := os.Create("_test/output-" + strconv.Itoa(i) + ".jpg")
		if err != nil {
			log.Fatal(err)
		}
		err = jpeg.Encode(out, areas[i], nil)
		if err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>Cleanup<commit_after>package main

import (
	dominantcolor "github.com/cenkalti/dominantcolor"
	"image"
	"image/jpeg"
	"log"
	"math"
	"os"
	"strconv"
)

type SubImager interface {
	SubImage(r image.Rectangle) image.Image
}

func main() {
	file, err := os.Open("_test/pic.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		log.Fatal(err)
	}

	screen := getScreen(img)

	/*

	   Dividing screen into 6 areas

	              A         B         A
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   0   |     2     |   4   |
	          |       |           |       |
	    ----- -----------------------------
	          |       |           |       |
	    50%   |   1   |     3     |   5   |
	          |       |           |       |
	    ----- -----------------------------
	          |  20%  |    40%    |  20%  |

	*/
	var areas [6]image.Image

	bounds := screen.Bounds()
	log.Println(bounds)

	x0 := float64(bounds.Dx() / 100)
	xA := int(math.Floor(x0 * 20))

	y := int(math.Floor(float64(bounds.Dy() / 2)))

	areaRect := image.Rect(bounds.Min.X, bounds.Min.Y, bounds.Min.X+xA, bounds.Min.Y+y)
	areas[0] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X, bounds.Min.Y+y, bounds.Min.X+xA, bounds.Max.Y)
	areas[1] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y, bounds.Max.X-xA, bounds.Min.Y+y)
	areas[2] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Min.X+xA, bounds.Min.Y+y, bounds.Max.X-xA, bounds.Max.Y)
	areas[3] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y, bounds.Max.X, bounds.Min.Y+y)
	areas[4] = screen.(SubImager).SubImage(areaRect)

	areaRect = image.Rect(bounds.Max.X-xA, bounds.Min.Y+y, bounds.Max.X, bounds.Max.Y)
	areas[5] = screen.(SubImager).SubImage(areaRect)

	for i := 0; i < len(areas); i++ {
		color := dominantcolor.Find(areas[i])
		log.Println(i, color)
		areas[i].Set(0, 0, color)

		out, err := os.Create("_test/output-" + strconv.Itoa(i) + ".jpg")
		if err != nil {
			log.Fatal(err)
		}
		err = jpeg.Encode(out, areas[i], nil)

		if err != nil {
			log.Fatal(err)
		}
	}
}

func getScreen(img image.Image) image.Image {
	screenRect := image.Rect(1350, 663, 2200, 975)
	screen := img.(SubImager).SubImage(screenRect)
	return screen
}
<|endoftext|>


<commit_before><commit_msg>Refactor test for testing both Handler and HandlerWithNext<commit_after><|endoftext|>


<commit_before>//Package session is used to store user data in token based cache.
//It is normally used as user session or token.
//This package depands github.com/herb-go/herb/cache.
package session

import (
	"crypto/md5"
	"net/url"
	"time"

	"github.com/herb-go/herb/cache"
)

const (
	PrefixModeRaw     = "raw"
	PrefixModeMD5     = "md5"
	PrefixModeEmpty   = "empty"
	DefaultPrefixMode = PrefixModeRaw
)

const DefaultTokenLength = 256

var defaultUpdateActiveInterval = 5 * time.Minute

var defaultTokenMaxLifetime = 365 * 24 * time.Hour
var (
	defaultCookieName = "herb-session"
	defaultCookiePath = "/"
)

func defaultTokenGenerater(s *CacheDriver, prefix string) (token string, err error) {
	t, err := cache.RandMaskedBytes(cache.TokenMask, s.Length)
	if err != nil {
		return
	}
	prefixconverted, err := s.ConvertPrefix(prefix)
	if err != nil {
		return
	}
	if prefixconverted != "" {
		token = url.PathEscape(prefix) + "-" + string(t)
	} else {
		token = string(t)
	}
	return
}

//NewCacheDriver create new cache driver
func NewCacheDriver() *CacheDriver {
	return &CacheDriver{
		TokenGenerater: defaultTokenGenerater,
		Length:         DefaultTokenLength,
		PrefixMode:     PrefixModeRaw,
	}
}

// MustCacheStore create new cache store with given token lifetime.
//Return store created.
//Panic if any error raised.
func MustCacheStore(Cache *cache.Cache, TokenLifetime time.Duration) *Store {
	driver := NewCacheDriver()
	oc := NewCacheDriverOptionConfig()
	oc.Cache = Cache
	err := driver.Init(oc)
	if err != nil {
		panic(err)
	}
	store := New()
	soc := NewOptionConfig()
	soc.Driver = driver
	soc.TokenLifetime = TokenLifetime
	err = store.Init(soc)
	if err != nil {
		panic(err)
	}
	return store
}

//CacheDriver CacheDriver is the stuct store token data in cache.
type CacheDriver struct {
	Cache          *cache.Cache //Cache which stores token data
	Length         int
	PrefixMode     string
	TokenGenerater func(s *CacheDriver, prefix string) (token string, err error) //Token name generate func
}

//Init init cache driver with given option
func (s *CacheDriver) Init(option CacheDriverOption) error {
	return option.ApplyTo(s)
}

//Close Close cachestore and return any error if raised
func (s *CacheDriver) Close() error {
	return s.Cache.Close()
}

//GenerateToken generate new token name with given prefix.
//Return the new token name and error.
func (s *CacheDriver) GenerateToken(prefix string) (token string, err error) {
	return s.TokenGenerater(s, prefix)
}

func (s *CacheDriver) ConvertPrefix(prefix string) (output string, err error) {
	switch s.PrefixMode {
	case PrefixModeEmpty:
		return "", nil
	case PrefixModeRaw:
		return prefix, nil
	case PrefixModeMD5:
		o := md5.Sum([]byte(prefix))
		return string(o[:]), nil
	}
	return "", nil
}

//Load load a given session with token from store.
func (s *CacheDriver) Load(v *Session) (err error) {
	token := v.token
	bytes, err := s.Cache.GetBytesValue(token)
	if err == cache.ErrNotFound {
		err = ErrDataNotFound
	}
	if err != nil {
		return err
	}

	err = v.Unmarshal(token, bytes)
	if err == nil {
		v.token = token
	}
	return
}

//Save  save given session with given ttl to store.
//Return any error if raised.
func (s *CacheDriver) Save(ts *Session, ttl time.Duration) (err error) {
	bytes, err := ts.Marshal()
	if err != nil {
		return err
	}
	if ts.oldToken == ts.token {
		err = s.Cache.UpdateBytesValue(ts.token, bytes, ttl)
	} else {
		err = s.Cache.SetBytesValue(ts.token, bytes, ttl)
	}
	return
}

//Delete delete the token with given name.
//Return any error if raised.
func (s *CacheDriver) Delete(token string) error {
	return s.Cache.Del(token)
}

//GetSessionToken Get the token string from token data.
//Return token and any error raised.
func (s *CacheDriver) GetSessionToken(ts *Session) (token string, err error) {
	return ts.token, nil
}
<commit_msg>update<commit_after>//Package session is used to store user data in token based cache.
//It is normally used as user session or token.
//This package depands github.com/herb-go/herb/cache.
package session

import (
	"crypto/md5"
	"encoding/hex"
	"net/url"
	"time"

	"github.com/herb-go/herb/cache"
)

const (
	//PrefixModeRaw prefix mode which dont convert prefix
	PrefixModeRaw = "raw"
	//PrefixModeMd5 prefix mode which  convert prefix to md5 sum
	PrefixModeMd5     = "md5"
	PrefixModeEmpty   = "empty"
	DefaultPrefixMode = PrefixModeRaw
)

const DefaultTokenLength = 256

var defaultUpdateActiveInterval = 5 * time.Minute

var defaultTokenMaxLifetime = 365 * 24 * time.Hour
var (
	defaultCookieName = "herb-session"
	defaultCookiePath = "/"
)

func defaultTokenGenerater(s *CacheDriver, prefix string) (token string, err error) {
	t, err := cache.RandMaskedBytes(cache.TokenMask, s.Length)
	if err != nil {
		return
	}
	prefixconverted, err := s.ConvertPrefix(prefix)
	if err != nil {
		return
	}
	if prefixconverted != "" {
		token = url.PathEscape(prefix) + "-" + string(t)
	} else {
		token = string(t)
	}
	return
}

//NewCacheDriver create new cache driver
func NewCacheDriver() *CacheDriver {
	return &CacheDriver{
		TokenGenerater: defaultTokenGenerater,
		Length:         DefaultTokenLength,
		PrefixMode:     PrefixModeRaw,
	}
}

// MustCacheStore create new cache store with given token lifetime.
//Return store created.
//Panic if any error raised.
func MustCacheStore(Cache *cache.Cache, TokenLifetime time.Duration) *Store {
	driver := NewCacheDriver()
	oc := NewCacheDriverOptionConfig()
	oc.Cache = Cache
	err := driver.Init(oc)
	if err != nil {
		panic(err)
	}
	store := New()
	soc := NewOptionConfig()
	soc.Driver = driver
	soc.TokenLifetime = TokenLifetime
	err = store.Init(soc)
	if err != nil {
		panic(err)
	}
	return store
}

//CacheDriver CacheDriver is the stuct store token data in cache.
type CacheDriver struct {
	Cache          *cache.Cache //Cache which stores token data
	Length         int
	PrefixMode     string
	TokenGenerater func(s *CacheDriver, prefix string) (token string, err error) //Token name generate func
}

//Init init cache driver with given option
func (s *CacheDriver) Init(option CacheDriverOption) error {
	return option.ApplyTo(s)
}

//Close Close cachestore and return any error if raised
func (s *CacheDriver) Close() error {
	return s.Cache.Close()
}

//GenerateToken generate new token name with given prefix.
//Return the new token name and error.
func (s *CacheDriver) GenerateToken(prefix string) (token string, err error) {
	return s.TokenGenerater(s, prefix)
}

func (s *CacheDriver) ConvertPrefix(prefix string) (output string, err error) {
	switch s.PrefixMode {
	case PrefixModeEmpty:
		return "", nil
	case PrefixModeRaw:
		return prefix, nil
	case PrefixModeMd5:
		o := md5.Sum([]byte(prefix))
		return hex.EncodeToString(o[:]), nil
	}
	return "", nil
}

//Load load a given session with token from store.
func (s *CacheDriver) Load(v *Session) (err error) {
	token := v.token
	bytes, err := s.Cache.GetBytesValue(token)
	if err == cache.ErrNotFound {
		err = ErrDataNotFound
	}
	if err != nil {
		return err
	}

	err = v.Unmarshal(token, bytes)
	if err == nil {
		v.token = token
	}
	return
}

//Save  save given session with given ttl to store.
//Return any error if raised.
func (s *CacheDriver) Save(ts *Session, ttl time.Duration) (err error) {
	bytes, err := ts.Marshal()
	if err != nil {
		return err
	}
	if ts.oldToken == ts.token {
		err = s.Cache.UpdateBytesValue(ts.token, bytes, ttl)
	} else {
		err = s.Cache.SetBytesValue(ts.token, bytes, ttl)
	}
	return
}

//Delete delete the token with given name.
//Return any error if raised.
func (s *CacheDriver) Delete(token string) error {
	return s.Cache.Del(token)
}

//GetSessionToken Get the token string from token data.
//Return token and any error raised.
func (s *CacheDriver) GetSessionToken(ts *Session) (token string, err error) {
	return ts.token, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	"hash"
	"io"
	"os"
	"runtime"
	"strings"
	"sync"
)

var fHash = flag.String("h", "sha256", "valid hashes: md5, sha1, sha224, sha256, sha384, sha512")
var fConcurrent = flag.Int("j", runtime.NumCPU(), "Maximum number of files processed concurrently.")
var fVersion = flag.Bool("version", false, "Print the version number and exit.")

type fileInput struct {
	index    int
	fileName string
}

func main() {
	flag.Parse()

	if *fVersion {
		fmt.Println("gosum v1.0")
		fmt.Println("Copyright (c) 2014, Gregory L. Dietsche.")
		return
	}
	if *fConcurrent <= 0 {
		*fConcurrent = 1
	}

	in := make(chan fileInput, *fConcurrent*10)
	out := make(chan *string, *fConcurrent*10)

	go func() {
		for i, file := range flag.Args() {
			in <- fileInput{i, file}
		}
		close(in)
	}()

	go func() {
		var wg sync.WaitGroup
		*fHash = strings.ToLower(*fHash)
		for i := 0; i < *fConcurrent; i++ {
			var hash hash.Hash
			switch *fHash {
			case "md5":
				hash = md5.New()
			case "sha1":
				hash = sha1.New()
			case "sha224":
				hash = sha256.New224()
			case "sha256":
				hash = sha256.New()
			case "sha384":
				hash = sha512.New384()
			case "sha512":
				hash = sha512.New()
			default:
				panic("Unknown / unspported hash: " + *fHash)
			}
			wg.Add(1)
			go digester(&wg, &hash, out, in)
		}
		wg.Wait()
		close(out)
	}()

	for curResult := range out {
		fmt.Println(*curResult)
	}
}

func digester(wg *sync.WaitGroup, h *hash.Hash, out chan *string, files chan fileInput) {
	for file := range files {
		(*h).Reset()
		processFile(&file.fileName, *h)
		message := fmt.Sprintf("%d %08x\t%s", file.index, (*h).Sum(nil), file.fileName)
		out <- &message
	}
	wg.Done()
}

func processFile(filename *string, w io.Writer) (err error) {
	if file, err := os.Open(*filename); err != nil {
		return err
	} else {
		defer file.Close()
		r := bufio.NewReader(file)
		if _, err = io.Copy(w, r); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>switch to streams in prep for handling stdin<commit_after>package main

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"flag"
	"fmt"
	"hash"
	"io"
	"os"
	"runtime"
	"strings"
	"sync"
)

var fHash = flag.String("h", "sha256", "valid hashes: md5, sha1, sha224, sha256, sha384, sha512")
var fConcurrent = flag.Int("j", runtime.NumCPU(), "Maximum number of files processed concurrently.")
var fVersion = flag.Bool("version", false, "Print the version number and exit.")

type fileInput struct {
	index    int
	fileName string
	data     io.ReadCloser
}

func main() {
	flag.Parse()

	if *fVersion {
		fmt.Println("gosum v1.0")
		fmt.Println("Copyright (c) 2014, Gregory L. Dietsche.")
		return
	}
	if *fConcurrent <= 0 {
		*fConcurrent = 1
	}

	in := make(chan fileInput, *fConcurrent*10)
	out := make(chan *string, *fConcurrent*10)

	go func() {
		for i, file := range flag.Args() {
			stream, err := os.Open(file)
			if err == nil {
				in <- fileInput{i, file, stream}
			} else {
				fmt.Println(err.Error())
			}
		}
		close(in)
	}()

	go func() {
		var wg sync.WaitGroup
		*fHash = strings.ToLower(*fHash)
		for i := 0; i < *fConcurrent; i++ {
			var hash hash.Hash
			switch *fHash {
			case "md5":
				hash = md5.New()
			case "sha1":
				hash = sha1.New()
			case "sha224":
				hash = sha256.New224()
			case "sha256":
				hash = sha256.New()
			case "sha384":
				hash = sha512.New384()
			case "sha512":
				hash = sha512.New()
			default:
				panic("Unknown / unspported hash: " + *fHash)
			}
			wg.Add(1)
			go digester(&wg, &hash, out, in)
		}
		wg.Wait()
		close(out)
	}()

	for curResult := range out {
		fmt.Println(*curResult)
	}
}

func digester(wg *sync.WaitGroup, h *hash.Hash, out chan *string, streams chan fileInput) {
	for stream := range streams {
		(*h).Reset()

		io.Copy(*h, stream.data)
		stream.data.Close()

		message := fmt.Sprintf("%d %08x\t%s", stream.index, (*h).Sum(nil), stream.fileName)
		out <- &message
	}
	wg.Done()
}
<|endoftext|>


<commit_before>package gifGrabber

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
	"gifjam/config"
)

var (
	mongoURL = os.Getenv("GIFJAM_MONGO")
	session  *mgo.Session
	db       *mgo.Database
	storage  *mgo.GridFS
)

func initDB() {
	if len(config.GlobalConfig.Mongo) > 0 {
		mongoURL = config.GlobalConfig.Mongo
	}

	// making database on package init
	var err error
	session, err = mgo.Dial(mongoURL)
	if err != nil {
		log.Println("Unable to connect to MongoDB database as a storage backend at url[", mongoURL, "] -> ", err.Error())
		os.Exit(1)
	}

	session.SetMode(mgo.Monotonic, true)

	// Pinging every 1 second to keep connection alive
	go func() {
		for {
			time.Sleep(time.Second * 1)
			err = session.Ping()
			if err != nil {
				log.Println("Error while trying to ping to MongoDB, restting connection -> ", err.Error())
				os.Exit(1)
			}
		}
	}()

	db = session.DB("gifjam")
	storage = db.GridFS("fs")
}

func SaveItem(item *FeedItem) (bool, error) {
	found, err := storage.Find(bson.M{"filename": item.Link}).Count()
	if err != nil {
		return false, err
	}

	// if we already have this image, just returning
	if found > 0 {
		return false, nil
	}

	retry_count := 0

	// if we don't have it downloading it from url
	for {
		if retry_count > 20 {
			log.Println("Retry count existed for url -> ", item.Link)
			return false, nil
		}

		res, err := http.Get(strings.Replace(strings.Replace(item.Link, " ", "", -1), "\t", "", -1))
		if err != nil {
			log.Println("Unable to get Gif Image from url ", item.Link, " to save it to DB -> ", err.Error())
			retry_count++
			time.Sleep(time.Second * 1)
			continue
		}

		if !strings.Contains(res.Header.Get("Content-Type"), "image/gif") {
			return false, nil
		}

		file, err := storage.Create(item.Link)
		if err != nil {
			return false, err
		}

		file.SetMeta(item)
		_, err = io.Copy(file, res.Body)
		if err != nil {
			return false, err
		}

		file.Close()
		res.Body.Close()
		res.Close = true

		break
	}

	return true, nil
}

// Getting FileID's for downloading them from client
func GetItems(offset, limit int) (ids []string, err error) {
	files := []bson.M{}
	//err = storage.Find(bson.M{"metadata.visible": true}).Skip(offset).Limit(limit).All(&files)
	err = storage.Find(bson.M{}).Skip(offset).Limit(limit).All(&files)
	if err != nil {
		return ids, err
	}

	for _, file := range files {
		ids = append(ids, file["_id"].(bson.ObjectId).Hex())
	}

	return ids, nil
}

func GetFileIO(id string) (int64, io.ReadCloser, error) {
	file, err := storage.OpenId(bson.ObjectIdHex(id))
	if err != nil {
		return 0, nil, err
	}

	return file.Size(), file, nil
}

func SetVisibility(id string, is_visible bool) error {
	return db.C("fs.files").Update(bson.M{"_id": bson.ObjectIdHex(id)}, bson.M{"$set": bson.M{"metadata.visible": is_visible}})
}
<commit_msg>adding sort functionality<commit_after>package gifGrabber

import (
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
	"gifjam/config"
)

var (
	mongoURL = os.Getenv("GIFJAM_MONGO")
	session  *mgo.Session
	db       *mgo.Database
	storage  *mgo.GridFS
)

func initDB() {
	if len(config.GlobalConfig.Mongo) > 0 {
		mongoURL = config.GlobalConfig.Mongo
	}

	// making database on package init
	var err error
	session, err = mgo.Dial(mongoURL)
	if err != nil {
		log.Println("Unable to connect to MongoDB database as a storage backend at url[", mongoURL, "] -> ", err.Error())
		os.Exit(1)
	}

	session.SetMode(mgo.Monotonic, true)

	// Pinging every 1 second to keep connection alive
	go func() {
		for {
			time.Sleep(time.Second * 1)
			err = session.Ping()
			if err != nil {
				log.Println("Error while trying to ping to MongoDB, restting connection -> ", err.Error())
				os.Exit(1)
			}
		}
	}()

	db = session.DB("gifjam")
	storage = db.GridFS("fs")
}

func SaveItem(item *FeedItem) (bool, error) {
	found, err := storage.Find(bson.M{"filename": item.Link}).Count()
	if err != nil {
		return false, err
	}

	// if we already have this image, just returning
	if found > 0 {
		return false, nil
	}

	retry_count := 0

	// if we don't have it downloading it from url
	for {
		if retry_count > 20 {
			log.Println("Retry count existed for url -> ", item.Link)
			return false, nil
		}

		res, err := http.Get(strings.Replace(strings.Replace(item.Link, " ", "", -1), "\t", "", -1))
		if err != nil {
			log.Println("Unable to get Gif Image from url ", item.Link, " to save it to DB -> ", err.Error())
			retry_count++
			time.Sleep(time.Second * 1)
			continue
		}

		if !strings.Contains(res.Header.Get("Content-Type"), "image/gif") {
			return false, nil
		}

		file, err := storage.Create(item.Link)
		if err != nil {
			return false, err
		}

		file.SetMeta(item)
		_, err = io.Copy(file, res.Body)
		if err != nil {
			return false, err
		}

		file.Close()
		res.Body.Close()
		res.Close = true

		break
	}

	return true, nil
}

// Getting FileID's for downloading them from client
func GetItems(offset, limit int) (ids []string, err error) {
	files := []bson.M{}
	//err = storage.Find(bson.M{"metadata.visible": true}).Skip(offset).Limit(limit).All(&files)
	err = storage.Find(bson.M{}).Sort("-uploadDate").Skip(offset).Limit(limit).All(&files)
	if err != nil {
		return ids, err
	}

	for _, file := range files {
		ids = append(ids, file["_id"].(bson.ObjectId).Hex())
	}

	return ids, nil
}

func GetFileIO(id string) (int64, io.ReadCloser, error) {
	file, err := storage.OpenId(bson.ObjectIdHex(id))
	if err != nil {
		return 0, nil, err
	}

	return file.Size(), file, nil
}

func SetVisibility(id string, is_visible bool) error {
	return db.C("fs.files").Update(bson.M{"_id": bson.ObjectIdHex(id)}, bson.M{"$set": bson.M{"metadata.visible": is_visible}})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"time"
)

const (
	SEED        = 72
	WEEK        = 7
	ROWS        = 81
	MAX_COMMITS = 7 // TODO: Should be equal to ~74
	START_DATE  = ""
)

var (
	flSeed       int
	flMaxRows    int
	flMaxCommits int
	flStartDate  string
)

const (
	UsgSeed            = "sets a seed value for commits pattern range 1-100"
	UsgSeedShort       = "short hand version of --seed"
	UsgMaxRows         = "sets the value of maximum rows for contribution graph"
	UsgMaxRowsShort    = "short hand version of --max-rows"
	UsgStartDate       = "sets the starting date of contribution graph. Must be in MM/DD/YYYY format"
	UsgStartDateShort  = "short hand version of --date"
	UsgMaxCommits      = "sets the value of maximum commits for a date"
	UsgMaxCommitsShort = "short hand version of --max-commits"
)

func init() {
	flag.IntVar(&flSeed, "seed", SEED, UsgSeed)
	flag.IntVar(&flSeed, "s", SEED, UsgSeedShort)

	flag.IntVar(&flMaxRows, "max-rows", ROWS, UsgMaxRows)
	flag.IntVar(&flMaxRows, "mr", ROWS, UsgMaxRowsShort)

	flag.StringVar(&flStartDate, "date", START_DATE, UsgStartDate)
	flag.StringVar(&flStartDate, "d", START_DATE, UsgStartDateShort)

	flag.IntVar(&flMaxCommits, "commits", MAX_COMMITS, UsgMaxCommits)
	flag.IntVar(&flMaxCommits, "c", MAX_COMMITS, UsgMaxCommitsShort)

	flag.Parse()

	rand.Seed(time.Now().Unix())

	if flSeed < 1 || flSeed > 100 {
		flSeed = SEED
	}

	_, err := time.Parse("01/02/2006", value)
	if flStartDate == "" || err != nil {
		fmt.Println("please provide a valid date in MM/DD/YYYY format.")
		os.Exit(2)
	}

}

func main() {

	var pattern string

	for i := 0; i < flMaxRows; i++ {
		for j := 0; j < WEEK; j++ {
			if rand.Intn(100) > flSeed {
				pattern += "."
			} else {
				pattern += "0"
			}
		}
		pattern += "\n"
	}

	weeks := strings.Split(pattern, "\n")

	date := parseTime(flStartDate)

	for i := 0; i < len(weeks)-1; i++ {
		week := weeks[i]
		for j := range week {
			cell := (string)(week[j])
			if cell == "0" {
				doCommits(date)
			}
			date = nextDay(date)
		}
	}

}
func doCommits(date time.Time) {
	date = addRandomDuration(date)
	for i := 0; i < rand.Intn(flMaxCommits); i++ {
		formatted := formatTime(date)
		os.Setenv("GIT_AUTHOR_DATE", formatted)
		os.Setenv("GIT_COMMITTER_DATE", formatted)
		cmd := exec.Command("git", "commit", "--allow-empty", "-m "+formatted)
		out, err := cmd.Output()

		if err != nil {
			fmt.Println(err.Error())
			panic(err)
		}

		fmt.Println(string(out))
		date = addRandomDuration(date)
	}

}

func parseTime(value string) time.Time {
	val, err := time.Parse("01/02/2006", value)
	if err != nil {
		panic(err)
	}
	return val
}

func formatTime(t time.Time) string {
	return fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())

}

func nextDay(value time.Time) time.Time {
	return time.Date(value.Year(), value.Month(), value.Day()+1, 0, 0, 0, 0, time.UTC)
}

func addRandomDuration(value time.Time) time.Time {

	h := rand.Intn(24)
	m := rand.Intn(60)
	s := rand.Intn(60)

	d := parseDuration(h, m, s)

	return value.Add(d)
}

func parseDuration(h int, m int, s int) time.Duration {
	d := fmt.Sprintf("%dh%dm%ds", h, m, s)
	duration, err := time.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return duration
}
<commit_msg>Lulz, K<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"strings"
	"time"
)

const (
	SEED        = 72
	WEEK        = 7
	ROWS        = 81
	MAX_COMMITS = 74 // TODO: Should be equal to ~74
	START_DATE  = ""
)

var (
	flSeed       int
	flMaxRows    int
	flMaxCommits int
	flStartDate  string
	totalCommits int
)

const (
	UsgSeed            = "sets a seed value for commits pattern range 1-100"
	UsgSeedShort       = "short hand version of --seed"
	UsgMaxRows         = "sets the value of maximum rows for contribution graph"
	UsgMaxRowsShort    = "short hand version of --max-rows"
	UsgStartDate       = "sets the starting date of contribution graph. Must be in MM/DD/YYYY format"
	UsgStartDateShort  = "short hand version of --date"
	UsgMaxCommits      = "sets the value of maximum commits for a date"
	UsgMaxCommitsShort = "short hand version of --max-commits"
)

func init() {
	flag.IntVar(&flSeed, "seed", SEED, UsgSeed)
	flag.IntVar(&flSeed, "s", SEED, UsgSeedShort)

	flag.IntVar(&flMaxRows, "max-rows", ROWS, UsgMaxRows)
	flag.IntVar(&flMaxRows, "mr", ROWS, UsgMaxRowsShort)

	flag.StringVar(&flStartDate, "date", START_DATE, UsgStartDate)
	flag.StringVar(&flStartDate, "d", START_DATE, UsgStartDateShort)

	flag.IntVar(&flMaxCommits, "commits", MAX_COMMITS, UsgMaxCommits)
	flag.IntVar(&flMaxCommits, "c", MAX_COMMITS, UsgMaxCommitsShort)

	flag.Parse()

	if flSeed < 1 || flSeed > 100 {
		flSeed = SEED
	}

	_, err := time.Parse("01/02/2006", flStartDate)
	if flStartDate == "" || err != nil {
		fmt.Println("please provide a valid date in MM/DD/YYYY format.")
		os.Exit(2)
	}

}

func main() {
	beginTime := time.Now()
	totalCommits = 0

	rand.Seed(beginTime.Unix())

	var pattern string

	for i := 0; i < flMaxRows; i++ {
		for j := 0; j < WEEK; j++ {
			if rand.Intn(100) > flSeed {
				pattern += "."
			} else {
				pattern += "0"
			}
		}
		pattern += "\n"
	}

	weeks := strings.Split(pattern, "\n")
	date := parseTime(flStartDate)

	for i := 0; i < len(weeks)-1; i++ {
		week := weeks[i]

		for j := range week {
			cell := (string)(week[j])

			if cell == "0" {
				doCommits(date)
			}
			date = nextDay(date)
		}
	}

	endTime := time.Now()
	fmt.Println("Boom! %d commits generated in %s duration.", totalCommits, (endTime.Sub(beginTime)).String())

}
func doCommits(date time.Time) {
	date = addRandomDuration(date)
	r := rand.Intn(flMaxCommits)
	for i := 0; i < r; i++ {
		formatted := formatTime(date)

		os.Setenv("GIT_AUTHOR_DATE", formatted)
		os.Setenv("GIT_COMMITTER_DATE", formatted)

		msg := fmt.Sprintf("Commit: %02d/%02d (max: %02d) for Date: %s", i, r, flMaxCommits, date.Format(time.RFC822))
		cmd := exec.Command("git", "commit", "--allow-empty", "-m "+msg)

		out, err := cmd.Output()

		if err != nil {
			fmt.Println(err.Error())
			panic(err)
		}

		fmt.Print(string(out))
		totalCommits++

		date = addRandomDuration(date)
	}

}

func parseTime(value string) time.Time {
	val, err := time.Parse("01/02/2006", value)
	if err != nil {
		panic(err)
	}
	return val
}

func formatTime(t time.Time) string {
	return fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())

}

func nextDay(value time.Time) time.Time {
	return time.Date(value.Year(), value.Month(), value.Day()+1, 0, 0, 0, 0, time.UTC)
}

func addRandomDuration(value time.Time) time.Time {
	t := time.Date(value.Year(), value.Month(), value.Day(), 0, 0, 0, 0, time.UTC)

	h := rand.Intn(24)
	m := rand.Intn(60)
	s := rand.Intn(60)

	d := parseDuration(h, m, s)

	return t.Add(d)
}

func parseDuration(h int, m int, s int) time.Duration {
	d := fmt.Sprintf("%dh%dm%ds", h, m, s)
	duration, err := time.ParseDuration(d)
	if err != nil {
		panic(err)
	}

	return duration
}
<|endoftext|>


<commit_before>package gonorm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// The Gonorm type represents the relevant parameters of a Neo4j connection
type Gonorm struct {
	Host      string
	Port      int
	cypherUrl string
}

// The Cypher type represents the relevant parameters of a cypher query
type Cypher struct {
	Query  string                 `json:"query"`
	Params map[string]interface{} `json:"params"`
	gonorm *Gonorm
}

// The Results type represents the relevant parameters of a response from the
// Neo4j API
type Results struct {
	Columns []interface{} `json:"columns"`
	Data    []interface{} `json:"data"`
	Error   error
}

// The Node type represent the relevant parameters of a Neo4j node
type Node struct {
	Params map[string]interface{}
}

// The Relationship type represent the relevant parameters of a Neo4j
// relationship
type Relationship struct {
	Params map[string]interface{}
	Type   string
	Start  string
	End    string
}

// Neo4jError defines an error type that is populated when an erroneous query is
// executed
type Neo4jError struct {
	Message    string   `json:"message"`
	Exception  string   `json:"exception"`
	Fullname   string   `json:"fullname"`
	Stacktrace []string `json:"stacktrace"`
}

// The Error method is attached to the Neo4jError type so that it satisfies the
// Error interface
func (neo4jError *Neo4jError) Error() string {
	return neo4jError.Message
}

// New is a factory method that creates a Gonorm type. You should use this
// instead of manually creating a Gonorm type yourself
func New(host string, port int) *Gonorm {
	return &Gonorm{
		Host:      host,
		Port:      port,
		cypherUrl: fmt.Sprintf("%s:%d/db/data/cypher", host, port),
	}
}

// Cypher allows you to create a Cypher type on top of a Gonorm type
func (g *Gonorm) Cypher(query string) *Cypher {
	return &Cypher{Query: query, gonorm: g}
}

// In a function-chaining fashion, On allows you to specify parameters for a
// cypher query
func (c *Cypher) On(params map[string]interface{}) *Cypher {
	c.Params = params
	return c
}

// Execute executes the query stored in the Cypher type
func (c *Cypher) Execute() *Results {
	results := new(Results)

	requestContent, err := json.Marshal(c)
	if err != nil {
		results.Error = err
		return results
	}
	buf := bytes.NewBuffer(requestContent)

	// Create a new request with the appropriate endpoints and POST body data
	req, err := http.NewRequest("POST", c.gonorm.cypherUrl, buf)
	if err != nil {
		results.Error = err
		return results
	}
	req.Header.Add("Content-Type", "application/json")
	client := &http.Client{}

	// Execute the request
	resp, err := client.Do(req)
	if err != nil {
		results.Error = err
		return results
	}
	defer resp.Body.Close()

	// Given the response body, which is an io.Reader, return a byte slice
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		results.Error = err
		return results
	}

	if resp.StatusCode != http.StatusOK {
		neo4jError := new(Neo4jError)
		json.Unmarshal(body, &neo4jError)
		results.Error = neo4jError
		return results
	}

	// Return the results
	json.Unmarshal(body, &results)
	return results
}

// AsInt should be used when you return one integer in your cypher query
func (r *Results) AsInt() (int, error) {
	if r.Error != nil {
		return -1, r.Error
	}

	return int(r.Data[0].([]interface{})[0].(float64)), nil
}

// AsInts should be used when you return several integers in your cypher query
func (r *Results) AsInts() ([]int, error) {
	if r.Error != nil {
		return []int{}, r.Error
	}

	var ints = []int{}

	for _, value := range r.Data[0].([]interface{}) {
		i := int(value.(float64))
		ints = append(ints, i)
	}

	return ints, nil
}

// AsString should be used when you return one string in your cypher query
func (r *Results) AsString() (string, error) {
	if r.Error != nil {
		return "", r.Error
	}

	return r.Data[0].([]interface{})[0].(string), nil
}

// AsStrings should be used when you return several strings in your cypher query
func (r *Results) AsStrings() ([]string, error) {
	if r.Error != nil {
		return []string{}, r.Error
	}

	var strings = []string{}

	for _, value := range r.Data[0].([]interface{}) {
		strings = append(strings, value.(string))
	}

	return strings, nil
}

// AsNode should be used when you return one node in your cypher query
func (r *Results) AsNode() (*Node, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	nodeData := r.Data[0].([]interface{})[0].(map[string]interface{})
	node := new(Node)
	node.Params = nodeData["data"].(map[string]interface{})

	return node, nil
}

// AsNodes should be used when you return several nodes in your cypher query
func (r *Results) AsNodes() ([]*Node, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	var nodes = []*Node{}

	for _, value := range r.Data[0].([]interface{}) {
		node := new(Node)
		node.Params = value.(map[string]interface{})["data"].(map[string]interface{})
		nodes = append(nodes, node)
	}

	return nodes, nil
}

// AsRelationship should be used when you return one relationship in your cypher
// query
func (r *Results) AsRelationship() (*Relationship, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	relationshipData := r.Data[0].([]interface{})[0].(map[string]interface{})
	relationship := new(Relationship)
	relationship.Params = relationshipData["data"].(map[string]interface{})
	relationship.Type = relationshipData["type"].(string)
	relationship.Start = relationshipData["start"].(string)
	relationship.End = relationshipData["end"].(string)

	return relationship, nil
}

// AsRelationships should be used when you return several relationships in your
// cypher query
func (r *Results) AsRelationships() ([]*Relationship, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	var relationships = []*Relationship{}

	for _, value := range r.Data[0].([]interface{}) {
		relationship := new(Relationship)
		relationship.Params = value.(map[string]interface{})["data"].(map[string]interface{})
		relationship.Type = value.(map[string]interface{})["type"].(string)
		relationship.Start = value.(map[string]interface{})["start"].(string)
		relationship.End = value.(map[string]interface{})["end"].(string)
		relationships = append(relationships, relationship)
	}

	return relationships, nil
}
<commit_msg>Fixes issue #1<commit_after>package gonorm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

// The Gonorm type represents the relevant parameters of a Neo4j connection
type Gonorm struct {
	Host      string
	Port      int
	cypherUrl string
}

// The Cypher type represents the relevant parameters of a cypher query
type Cypher struct {
	Query  string                 `json:"query"`
	Params map[string]interface{} `json:"params"`
	gonorm *Gonorm
}

// The Results type represents the relevant parameters of a response from the
// Neo4j API
type Results struct {
	Columns []interface{} `json:"columns"`
	Data    []interface{} `json:"data"`
	Error   error
}

// The Node type represent the relevant parameters of a Neo4j node
type Node struct {
	Params map[string]interface{}
}

// The Relationship type represent the relevant parameters of a Neo4j
// relationship
type Relationship struct {
	Params map[string]interface{}
	Type   string
	Start  string
	End    string
}

// Neo4jError defines an error type that is populated when an erroneous query is
// executed
type Neo4jError struct {
	Message    string   `json:"message"`
	Exception  string   `json:"exception"`
	Fullname   string   `json:"fullname"`
	Stacktrace []string `json:"stacktrace"`
}

// The Error method is attached to the Neo4jError type so that it satisfies the
// Error interface
func (neo4jError *Neo4jError) Error() string {
	return neo4jError.Message
}

// New is a factory method that creates a Gonorm type. You should use this
// instead of manually creating a Gonorm type yourself
func New(host string, port int) *Gonorm {
	return &Gonorm{
		Host:      host,
		Port:      port,
		cypherUrl: fmt.Sprintf("%s:%d/db/data/cypher", host, port),
	}
}

// Cypher allows you to create a Cypher type on top of a Gonorm type
func (g *Gonorm) Cypher(query string) *Cypher {
	return &Cypher{Query: query, gonorm: g}
}

// In a function-chaining fashion, On allows you to specify parameters for a
// cypher query
func (c *Cypher) On(params map[string]interface{}) *Cypher {
	c.Params = params
	return c
}

// Execute executes the query stored in the Cypher type
func (c *Cypher) Execute() *Results {
	results := new(Results)

	requestContent, err := json.Marshal(c)
	if err != nil {
		results.Error = err
		return results
	}
	buf := bytes.NewBuffer(requestContent)

	// Create a new request with the appropriate endpoints and POST body data
	req, err := http.NewRequest("POST", c.gonorm.cypherUrl, buf)
	if err != nil {
		results.Error = err
		return results
	}
	req.Header.Add("Content-Type", "application/json")
	client := &http.Client{}

	// Execute the request
	resp, err := client.Do(req)
	if err != nil {
		results.Error = err
		return results
	}
	defer resp.Body.Close()

	// Given the response body, which is an io.Reader, return a byte slice
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		results.Error = err
		return results
	}

	if resp.StatusCode != http.StatusOK {
		neo4jError := new(Neo4jError)
		json.Unmarshal(body, &neo4jError)
		results.Error = neo4jError
		return results
	}

	// Return the results
	json.Unmarshal(body, &results)
	return results
}

// AsInt should be used when you return one integer in your cypher query
func (r *Results) AsInt() (int, error) {
	if r.Error != nil {
		return -1, r.Error
	}

	return int(r.Data[0].([]interface{})[0].(float64)), nil
}

// AsInts should be used when you return several integers in your cypher query
func (r *Results) AsInts() ([]int, error) {
	if r.Error != nil {
		return []int{}, r.Error
	}

	var ints = []int{}

	for _, value := range r.Data[0].([]interface{}) {
		i := int(value.(float64))
		ints = append(ints, i)
	}

	return ints, nil
}

// AsString should be used when you return one string in your cypher query
func (r *Results) AsString() (string, error) {
	if r.Error != nil {
		return "", r.Error
	}

	return r.Data[0].([]interface{})[0].(string), nil
}

// AsStrings should be used when you return several strings in your cypher query
func (r *Results) AsStrings() ([]string, error) {
	if r.Error != nil {
		return []string{}, r.Error
	}

	var strings = []string{}

	for _, value := range r.Data[0].([]interface{}) {
		strings = append(strings, value.(string))
	}

	return strings, nil
}

// AsNode should be used when you return one node in your cypher query
func (r *Results) AsNode() (*Node, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	nodeData := r.Data[0].([]interface{})[0].(map[string]interface{})
	node := new(Node)
	node.Params = nodeData["data"].(map[string]interface{})

	return node, nil
}

// AsNodes should be used when you return several nodes in your cypher query
func (r *Results) AsNodes() ([]*Node, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	var nodes = []*Node{}

	for _,d := range r.Data{
		for _, value := range d.([]interface{}) {
		node := new(Node)
		node.Params = value.(map[string]interface{})["data"].(map[string]interface{})
		nodes = append(nodes, node)
		}
	}

	return nodes, nil
}

// AsRelationship should be used when you return one relationship in your cypher
// query
func (r *Results) AsRelationship() (*Relationship, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	relationshipData := r.Data[0].([]interface{})[0].(map[string]interface{})
	relationship := new(Relationship)
	relationship.Params = relationshipData["data"].(map[string]interface{})
	relationship.Type = relationshipData["type"].(string)
	relationship.Start = relationshipData["start"].(string)
	relationship.End = relationshipData["end"].(string)

	return relationship, nil
}

// AsRelationships should be used when you return several relationships in your
// cypher query
func (r *Results) AsRelationships() ([]*Relationship, error) {
	if r.Error != nil {
		return nil, r.Error
	}

	var relationships = []*Relationship{}

	for _, value := range r.Data[0].([]interface{}) {
		relationship := new(Relationship)
		relationship.Params = value.(map[string]interface{})["data"].(map[string]interface{})
		relationship.Type = value.(map[string]interface{})["type"].(string)
		relationship.Start = value.(map[string]interface{})["start"].(string)
		relationship.End = value.(map[string]interface{})["end"].(string)
		relationships = append(relationships, relationship)
	}

	return relationships, nil
}
<|endoftext|>