<commit_before>// +build !windows

/*
   Copyright The containerd 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 run

import (
	gocontext "context"
	"path/filepath"
	"strings"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/contrib/nvidia"
	"github.com/containerd/containerd/contrib/seccomp"
	"github.com/containerd/containerd/oci"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/runtime/v2/runc/options"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

var platformRunFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "runc-binary",
		Usage: "specify runc-compatible binary",
	},
	cli.BoolFlag{
		Name:  "runc-systemd-cgroup",
		Usage: "start runc with systemd cgroup manager",
	},
}

// NewContainer creates a new container
func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
	var (
		id     string
		config = context.IsSet("config")
	)
	if config {
		id = context.Args().First()
	} else {
		id = context.Args().Get(1)
	}

	var (
		opts  []oci.SpecOpts
		cOpts []containerd.NewContainerOpts
		spec  containerd.NewContainerOpts
	)

	cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
	if config {
		opts = append(opts, oci.WithSpecFromFile(context.String("config")))
	} else {
		var (
			ref = context.Args().First()
			//for container's id is Args[1]
			args = context.Args()[2:]
		)
		opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices)
		if ef := context.String("env-file"); ef != "" {
			opts = append(opts, oci.WithEnvFile(ef))
		}
		opts = append(opts, oci.WithEnv(context.StringSlice("env")))
		opts = append(opts, withMounts(context))

		if context.Bool("rootfs") {
			rootfs, err := filepath.Abs(ref)
			if err != nil {
				return nil, err
			}
			opts = append(opts, oci.WithRootFSPath(rootfs))
		} else {
			snapshotter := context.String("snapshotter")
			var image containerd.Image
			i, err := client.ImageService().Get(ctx, ref)
			if err != nil {
				return nil, err
			}
			if ps := context.String("platform"); ps != "" {
				platform, err := platforms.Parse(ps)
				if err != nil {
					return nil, err
				}
				image = containerd.NewImageWithPlatform(client, i, platforms.Only(platform))
			} else {
				image = containerd.NewImage(client, i)
			}

			unpacked, err := image.IsUnpacked(ctx, snapshotter)
			if err != nil {
				return nil, err
			}
			if !unpacked {
				if err := image.Unpack(ctx, snapshotter); err != nil {
					return nil, err
				}
			}
			opts = append(opts, oci.WithImageConfig(image))
			cOpts = append(cOpts,
				containerd.WithImage(image),
				containerd.WithSnapshotter(snapshotter),
				// Even when "readonly" is set, we don't use KindView snapshot here. (#1495)
				// We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only,
				// after creating some mount points on demand.
				containerd.WithNewSnapshot(id, image),
				containerd.WithImageStopSignal(image, "SIGTERM"))
		}
		if context.Bool("readonly") {
			opts = append(opts, oci.WithRootFSReadonly())
		}
		if len(args) > 0 {
			opts = append(opts, oci.WithProcessArgs(args...))
		}
		if cwd := context.String("cwd"); cwd != "" {
			opts = append(opts, oci.WithProcessCwd(cwd))
		}
		if context.Bool("tty") {
			opts = append(opts, oci.WithTTY)
		}
		if context.Bool("privileged") {
			opts = append(opts, oci.WithPrivileged, oci.WithAllDevicesAllowed, oci.WithHostDevices)
		}
		if context.Bool("net-host") {
			opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf)
		}
		if context.Bool("seccomp") {
			opts = append(opts, seccomp.WithDefaultProfile())
		}

		joinNs := context.StringSlice("with-ns")
		for _, ns := range joinNs {
			parts := strings.Split(ns, ":")
			if len(parts) != 2 {
				return nil, errors.New("joining a Linux namespace using --with-ns requires the format 'nstype:path'")
			}
			if !validNamespace(parts[0]) {
				return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + parts[0])
			}
			opts = append(opts, oci.WithLinuxNamespace(specs.LinuxNamespace{
				Type: specs.LinuxNamespaceType(parts[0]),
				Path: parts[1],
			}))
		}
		if context.IsSet("gpus") {
			opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(context.Int("gpus")), nvidia.WithAllCapabilities))
		}
		if context.IsSet("allow-new-privs") {
			opts = append(opts, oci.WithNewPrivileges)
		}
		if context.IsSet("cgroup") {
			// NOTE: can be set to "" explicitly for disabling cgroup.
			opts = append(opts, oci.WithCgroup(context.String("cgroup")))
		}
		limit := context.Uint64("memory-limit")
		if limit != 0 {
			opts = append(opts, oci.WithMemoryLimit(limit))
		}
		for _, dev := range context.StringSlice("device") {
			opts = append(opts, oci.WithLinuxDevice(dev, "rwm"))
		}
	}

	runtimeOpts := &options.Options{}
	if runcBinary := context.String("runc-binary"); runcBinary != "" {
		if context.String("runtime") == "io.containerd.runc.v2" {
			runtimeOpts.BinaryName = runcBinary
		} else {
			return nil, errors.New("specifying runc-binary is only supported for \"io.containerd.runc.v2\" runtime")
		}
	}
	if context.Bool("runc-systemd-cgroup") {
		if context.String("runtime") == "io.containerd.runc.v2" {
			if context.String("cgroup") == "" {
				// runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope"
				return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"")
			}
			runtimeOpts.SystemdCgroup = true
		} else {
			return nil, errors.New("specifying runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime")
		}
	}
	cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), runtimeOpts))

	opts = append(opts, oci.WithAnnotations(commands.LabelArgs(context.StringSlice("label"))))
	var s specs.Spec
	spec = containerd.WithSpec(&s, opts...)

	cOpts = append(cOpts, spec)

	// oci.WithImageConfig (WithUsername, WithUserID) depends on access to rootfs for resolving via
	// the /etc/{passwd,group} files. So cOpts needs to have precedence over opts.
	return client.NewContainer(ctx, id, cOpts...)
}

func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
	if context.Bool("no-pivot") {
		return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
	}
	return nil
}

func validNamespace(ns string) bool {
	linuxNs := specs.LinuxNamespaceType(ns)
	switch linuxNs {
	case specs.PIDNamespace,
		specs.NetworkNamespace,
		specs.UTSNamespace,
		specs.MountNamespace,
		specs.UserNamespace,
		specs.IPCNamespace,
		specs.CgroupNamespace:
		return true
	default:
		return false
	}
}
<commit_msg>Modify ctr run to search for read-only flag instead of readonly<commit_after>// +build !windows

/*
   Copyright The containerd 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 run

import (
	gocontext "context"
	"path/filepath"
	"strings"

	"github.com/containerd/containerd"
	"github.com/containerd/containerd/cmd/ctr/commands"
	"github.com/containerd/containerd/contrib/nvidia"
	"github.com/containerd/containerd/contrib/seccomp"
	"github.com/containerd/containerd/oci"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/runtime/v2/runc/options"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

var platformRunFlags = []cli.Flag{
	cli.StringFlag{
		Name:  "runc-binary",
		Usage: "specify runc-compatible binary",
	},
	cli.BoolFlag{
		Name:  "runc-systemd-cgroup",
		Usage: "start runc with systemd cgroup manager",
	},
}

// NewContainer creates a new container
func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
	var (
		id     string
		config = context.IsSet("config")
	)
	if config {
		id = context.Args().First()
	} else {
		id = context.Args().Get(1)
	}

	var (
		opts  []oci.SpecOpts
		cOpts []containerd.NewContainerOpts
		spec  containerd.NewContainerOpts
	)

	cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
	if config {
		opts = append(opts, oci.WithSpecFromFile(context.String("config")))
	} else {
		var (
			ref = context.Args().First()
			//for container's id is Args[1]
			args = context.Args()[2:]
		)
		opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices)
		if ef := context.String("env-file"); ef != "" {
			opts = append(opts, oci.WithEnvFile(ef))
		}
		opts = append(opts, oci.WithEnv(context.StringSlice("env")))
		opts = append(opts, withMounts(context))

		if context.Bool("rootfs") {
			rootfs, err := filepath.Abs(ref)
			if err != nil {
				return nil, err
			}
			opts = append(opts, oci.WithRootFSPath(rootfs))
		} else {
			snapshotter := context.String("snapshotter")
			var image containerd.Image
			i, err := client.ImageService().Get(ctx, ref)
			if err != nil {
				return nil, err
			}
			if ps := context.String("platform"); ps != "" {
				platform, err := platforms.Parse(ps)
				if err != nil {
					return nil, err
				}
				image = containerd.NewImageWithPlatform(client, i, platforms.Only(platform))
			} else {
				image = containerd.NewImage(client, i)
			}

			unpacked, err := image.IsUnpacked(ctx, snapshotter)
			if err != nil {
				return nil, err
			}
			if !unpacked {
				if err := image.Unpack(ctx, snapshotter); err != nil {
					return nil, err
				}
			}
			opts = append(opts, oci.WithImageConfig(image))
			cOpts = append(cOpts,
				containerd.WithImage(image),
				containerd.WithSnapshotter(snapshotter),
				// Even when "read-only" is set, we don't use KindView snapshot here. (#1495)
				// We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only,
				// after creating some mount points on demand.
				containerd.WithNewSnapshot(id, image),
				containerd.WithImageStopSignal(image, "SIGTERM"))
		}
		if context.Bool("read-only") {
			opts = append(opts, oci.WithRootFSReadonly())
		}
		if len(args) > 0 {
			opts = append(opts, oci.WithProcessArgs(args...))
		}
		if cwd := context.String("cwd"); cwd != "" {
			opts = append(opts, oci.WithProcessCwd(cwd))
		}
		if context.Bool("tty") {
			opts = append(opts, oci.WithTTY)
		}
		if context.Bool("privileged") {
			opts = append(opts, oci.WithPrivileged, oci.WithAllDevicesAllowed, oci.WithHostDevices)
		}
		if context.Bool("net-host") {
			opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf)
		}
		if context.Bool("seccomp") {
			opts = append(opts, seccomp.WithDefaultProfile())
		}

		joinNs := context.StringSlice("with-ns")
		for _, ns := range joinNs {
			parts := strings.Split(ns, ":")
			if len(parts) != 2 {
				return nil, errors.New("joining a Linux namespace using --with-ns requires the format 'nstype:path'")
			}
			if !validNamespace(parts[0]) {
				return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + parts[0])
			}
			opts = append(opts, oci.WithLinuxNamespace(specs.LinuxNamespace{
				Type: specs.LinuxNamespaceType(parts[0]),
				Path: parts[1],
			}))
		}
		if context.IsSet("gpus") {
			opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(context.Int("gpus")), nvidia.WithAllCapabilities))
		}
		if context.IsSet("allow-new-privs") {
			opts = append(opts, oci.WithNewPrivileges)
		}
		if context.IsSet("cgroup") {
			// NOTE: can be set to "" explicitly for disabling cgroup.
			opts = append(opts, oci.WithCgroup(context.String("cgroup")))
		}
		limit := context.Uint64("memory-limit")
		if limit != 0 {
			opts = append(opts, oci.WithMemoryLimit(limit))
		}
		for _, dev := range context.StringSlice("device") {
			opts = append(opts, oci.WithLinuxDevice(dev, "rwm"))
		}
	}

	runtimeOpts := &options.Options{}
	if runcBinary := context.String("runc-binary"); runcBinary != "" {
		if context.String("runtime") == "io.containerd.runc.v2" {
			runtimeOpts.BinaryName = runcBinary
		} else {
			return nil, errors.New("specifying runc-binary is only supported for \"io.containerd.runc.v2\" runtime")
		}
	}
	if context.Bool("runc-systemd-cgroup") {
		if context.String("runtime") == "io.containerd.runc.v2" {
			if context.String("cgroup") == "" {
				// runc maps "machine.slice:foo:deadbeef" to "/machine.slice/foo-deadbeef.scope"
				return nil, errors.New("option --runc-systemd-cgroup requires --cgroup to be set, e.g. \"machine.slice:foo:deadbeef\"")
			}
			runtimeOpts.SystemdCgroup = true
		} else {
			return nil, errors.New("specifying runc-systemd-cgroup is only supported for \"io.containerd.runc.v2\" runtime")
		}
	}
	cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), runtimeOpts))

	opts = append(opts, oci.WithAnnotations(commands.LabelArgs(context.StringSlice("label"))))
	var s specs.Spec
	spec = containerd.WithSpec(&s, opts...)

	cOpts = append(cOpts, spec)

	// oci.WithImageConfig (WithUsername, WithUserID) depends on access to rootfs for resolving via
	// the /etc/{passwd,group} files. So cOpts needs to have precedence over opts.
	return client.NewContainer(ctx, id, cOpts...)
}

func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
	if context.Bool("no-pivot") {
		return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
	}
	return nil
}

func validNamespace(ns string) bool {
	linuxNs := specs.LinuxNamespaceType(ns)
	switch linuxNs {
	case specs.PIDNamespace,
		specs.NetworkNamespace,
		specs.UTSNamespace,
		specs.MountNamespace,
		specs.UserNamespace,
		specs.IPCNamespace,
		specs.CgroupNamespace:
		return true
	default:
		return false
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Skaffold 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 cmd

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// NewCmdDiagnose describes the CLI command to diagnose skaffold.
func NewCmdDiagnose(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "diagnose",
		Short: "Run a diagnostic on Skaffold",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return doDiagnose(out)
		},
	}
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	return cmd
}

func doDiagnose(out io.Writer) error {
	_, config, err := newRunner(opts)
	if err != nil {
		return errors.Wrap(err, "creating runner")
	}

	fmt.Fprintln(out, "Skaffold version:", version.Get().GitCommit)
	fmt.Fprintln(out, "Configuration version:", config.APIVersion)
	fmt.Fprintln(out, "Number of artifacts:", len(config.Build.Artifacts))

	if err := diagnoseArtifacts(out, config.Build.Artifacts); err != nil {
		return errors.Wrap(err, "running diagnostic on artifacts")
	}

	return nil
}

func diagnoseArtifacts(out io.Writer, artifacts []*latest.Artifact) error {
	ctx := context.Background()

	for _, artifact := range artifacts {
		color.Default.Fprintf(out, "\n%s: %s\n", typeOfArtifact(artifact), artifact.ImageName)

		if artifact.DockerArtifact != nil {
			size, err := sizeOfDockerContext(ctx, artifact)
			if err != nil {
				return errors.Wrap(err, "computing the size of the Docker context")
			}

			fmt.Fprintf(out, " - Size of the context: %vbytes\n", size)
		}

		timeDeps1, deps, err := timeToListDependencies(ctx, artifact)
		if err != nil {
			return errors.Wrap(err, "listing artifact dependencies")
		}
		timeDeps2, _, err := timeToListDependencies(ctx, artifact)
		if err != nil {
			return errors.Wrap(err, "listing artifact dependencies")
		}

		fmt.Fprintln(out, " - Dependencies:", len(deps), "files")
		fmt.Fprintf(out, " - Time to list dependencies: %v (2nd time: %v)\n", timeDeps1, timeDeps2)

		timeMTimes1, err := timeToComputeMTimes(deps)
		if err != nil {
			return errors.Wrap(err, "computing modTimes")
		}
		timeMTimes2, err := timeToComputeMTimes(deps)
		if err != nil {
			return errors.Wrap(err, "computing modTimes")
		}

		fmt.Fprintf(out, " - Time to compute mTimes on dependencies: %v (2nd time: %v)\n", timeMTimes1, timeMTimes2)
	}

	return nil
}

func timeToListDependencies(ctx context.Context, a *latest.Artifact) (time.Duration, []string, error) {
	start := time.Now()

	deps, err := runner.DependenciesForArtifact(ctx, a)
	if err != nil {
		return 0, nil, errors.Wrap(err, "listing artifact dependencies")
	}

	return time.Since(start), deps, nil
}

func timeToComputeMTimes(deps []string) (time.Duration, error) {
	start := time.Now()

	if _, err := watch.Stat(func() ([]string, error) { return deps, nil }); err != nil {
		return 0, errors.Wrap(err, "computing modTimes")
	}

	return time.Since(start), nil
}

func sizeOfDockerContext(ctx context.Context, a *latest.Artifact) (int64, error) {
	buildCtx, buildCtxWriter := io.Pipe()
	go func() {
		err := docker.CreateDockerTarContext(ctx, buildCtxWriter, a.Workspace, a.DockerArtifact)
		if err != nil {
			buildCtxWriter.CloseWithError(errors.Wrap(err, "creating docker context"))
			return
		}
		buildCtxWriter.Close()
	}()

	return io.Copy(ioutil.Discard, buildCtx)
}

func typeOfArtifact(a *latest.Artifact) string {
	switch {
	case a.DockerArtifact != nil:
		return "Docker artifact"
	case a.BazelArtifact != nil:
		return "Bazel artifact"
	default:
		return "Unknown artifact"
	}
}
<commit_msg>fix jib artifacts in skaffold diagnose<commit_after>/*
Copyright 2018 The Skaffold 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 cmd

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"time"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/version"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/watch"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

// NewCmdDiagnose describes the CLI command to diagnose skaffold.
func NewCmdDiagnose(out io.Writer) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "diagnose",
		Short: "Run a diagnostic on Skaffold",
		Args:  cobra.NoArgs,
		RunE: func(cmd *cobra.Command, args []string) error {
			return doDiagnose(out)
		},
	}
	cmd.Flags().StringVarP(&opts.ConfigurationFile, "filename", "f", "skaffold.yaml", "Filename or URL to the pipeline file")
	return cmd
}

func doDiagnose(out io.Writer) error {
	_, config, err := newRunner(opts)
	if err != nil {
		return errors.Wrap(err, "creating runner")
	}

	fmt.Fprintln(out, "Skaffold version:", version.Get().GitCommit)
	fmt.Fprintln(out, "Configuration version:", config.APIVersion)
	fmt.Fprintln(out, "Number of artifacts:", len(config.Build.Artifacts))

	if err := diagnoseArtifacts(out, config.Build.Artifacts); err != nil {
		return errors.Wrap(err, "running diagnostic on artifacts")
	}

	return nil
}

func diagnoseArtifacts(out io.Writer, artifacts []*latest.Artifact) error {
	ctx := context.Background()

	for _, artifact := range artifacts {
		color.Default.Fprintf(out, "\n%s: %s\n", typeOfArtifact(artifact), artifact.ImageName)

		if artifact.DockerArtifact != nil {
			size, err := sizeOfDockerContext(ctx, artifact)
			if err != nil {
				return errors.Wrap(err, "computing the size of the Docker context")
			}

			fmt.Fprintf(out, " - Size of the context: %vbytes\n", size)
		}

		timeDeps1, deps, err := timeToListDependencies(ctx, artifact)
		if err != nil {
			return errors.Wrap(err, "listing artifact dependencies")
		}
		timeDeps2, _, err := timeToListDependencies(ctx, artifact)
		if err != nil {
			return errors.Wrap(err, "listing artifact dependencies")
		}

		fmt.Fprintln(out, " - Dependencies:", len(deps), "files")
		fmt.Fprintf(out, " - Time to list dependencies: %v (2nd time: %v)\n", timeDeps1, timeDeps2)

		timeMTimes1, err := timeToComputeMTimes(deps)
		if err != nil {
			return errors.Wrap(err, "computing modTimes")
		}
		timeMTimes2, err := timeToComputeMTimes(deps)
		if err != nil {
			return errors.Wrap(err, "computing modTimes")
		}

		fmt.Fprintf(out, " - Time to compute mTimes on dependencies: %v (2nd time: %v)\n", timeMTimes1, timeMTimes2)
	}

	return nil
}

func timeToListDependencies(ctx context.Context, a *latest.Artifact) (time.Duration, []string, error) {
	start := time.Now()

	deps, err := runner.DependenciesForArtifact(ctx, a)
	if err != nil {
		return 0, nil, errors.Wrap(err, "listing artifact dependencies")
	}

	return time.Since(start), deps, nil
}

func timeToComputeMTimes(deps []string) (time.Duration, error) {
	start := time.Now()

	if _, err := watch.Stat(func() ([]string, error) { return deps, nil }); err != nil {
		return 0, errors.Wrap(err, "computing modTimes")
	}

	return time.Since(start), nil
}

func sizeOfDockerContext(ctx context.Context, a *latest.Artifact) (int64, error) {
	buildCtx, buildCtxWriter := io.Pipe()
	go func() {
		err := docker.CreateDockerTarContext(ctx, buildCtxWriter, a.Workspace, a.DockerArtifact)
		if err != nil {
			buildCtxWriter.CloseWithError(errors.Wrap(err, "creating docker context"))
			return
		}
		buildCtxWriter.Close()
	}()

	return io.Copy(ioutil.Discard, buildCtx)
}

func typeOfArtifact(a *latest.Artifact) string {
	switch {
	case a.DockerArtifact != nil:
		return "Docker artifact"
	case a.BazelArtifact != nil:
		return "Bazel artifact"
	case a.JibGradleArtifact != nil:
		return "Jib Gradle artifact"
	case a.JibMavenArtifact != nil:
		return "Jib Maven artifact"
	default:
		return "Unknown artifact"
	}
}
<|endoftext|>


<commit_before>package wav

import (
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"io"
	"time"

	"github.com/faiface/beep"
	"github.com/pkg/errors"
)

// Decode takes a Reader containing audio data in WAVE format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
//
// Do not close the supplied Reader, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) {
	d := decoder{r: r}
	defer func() { // hacky way to always close r if an error occurred
		if closer, ok := d.r.(io.Closer); ok {
			if err != nil {
				closer.Close()
			}
		}
	}()

	// READ "RIFF" header
	if err := binary.Read(r, binary.LittleEndian, d.h.RiffMark[:]); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav")
	}
	if string(d.h.RiffMark[:]) != "RIFF" {
		return nil, beep.Format{}, fmt.Errorf("wav: missing RIFF at the beginning > %s", string(d.h.RiffMark[:]))
	}

	// READ Total file size
	if err := binary.Read(r, binary.LittleEndian, &d.h.FileSize); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file size")
	}
	if err := binary.Read(r, binary.LittleEndian, d.h.WaveMark[:]); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file type")
	}
	if string(d.h.WaveMark[:]) != "WAVE" {
		return nil, beep.Format{}, errors.New("wav: unsupported file type")
	}

	// check each formtypes
	ft := [4]byte{0, 0, 0, 0}
	var fs int32
	d.hsz = 4 + 4 + 4 // add size of (RiffMark + FileSize + WaveMark)
	for string(ft[:]) != "data" {
		if err = binary.Read(r, binary.LittleEndian, ft[:]); err != nil {
			return nil, beep.Format{}, errors.Wrap(err, "wav: missing chunk type")
		}
		switch {
		case string(ft[:]) == "fmt ":
			d.h.FmtMark = ft
			if err := binary.Read(r, binary.LittleEndian, &d.h.FormatSize); err != nil {
				return nil, beep.Format{}, errors.New("wav: missing format chunk size")
			}
			d.hsz += 4 + 4 + d.h.FormatSize // add size of (FmtMark + FormatSize + its trailing size)
			if err := binary.Read(r, binary.LittleEndian, &d.h.FormatType); err != nil {
				return nil, beep.Format{}, errors.New("wav: missing format type")
			}
			if d.h.FormatType == -2 {
				// WAVEFORMATEXTENSIBLE
				fmtchunk := formatchunkextensible{
					formatchunk{0, 0, 0, 0, 0}, 0, 0, 0,
					guid{0, 0, 0, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}},
				}
				if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
					return nil, beep.Format{}, errors.New("wav: missing format chunk body")
				}
				d.h.NumChans = fmtchunk.NumChans
				d.h.SampleRate = fmtchunk.SampleRate
				d.h.ByteRate = fmtchunk.ByteRate
				d.h.BytesPerFrame = fmtchunk.BytesPerFrame
				d.h.BitsPerSample = fmtchunk.BitsPerSample

				// SubFormat is represented by GUID. Plain PCM is KSDATAFORMAT_SUBTYPE_PCM GUID.
				// See https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-waveformatextensible
				pcmguid := guid{
					0x00000001, 0x0000, 0x0010,
					[8]byte{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
				}
				if fmtchunk.SubFormat != pcmguid {
					return nil, beep.Format{}, fmt.Errorf(
						"wav: unsupported sub format type - %08x-%04x-%04x-%s",
						fmtchunk.SubFormat.Data1, fmtchunk.SubFormat.Data2, fmtchunk.SubFormat.Data3,
						hex.EncodeToString(fmtchunk.SubFormat.Data4[:]),
					)
				}
			} else {
				// WAVEFORMAT or WAVEFORMATEX
				fmtchunk := formatchunk{0, 0, 0, 0, 0}
				if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
					return nil, beep.Format{}, errors.New("wav: missing format chunk body")
				}
				d.h.NumChans = fmtchunk.NumChans
				d.h.SampleRate = fmtchunk.SampleRate
				d.h.ByteRate = fmtchunk.ByteRate
				d.h.BytesPerFrame = fmtchunk.BytesPerFrame
				d.h.BitsPerSample = fmtchunk.BitsPerSample

				// it would be skipping cbSize (WAVEFORMATEX's last member).
				if d.h.FormatSize > 16 {
					trash := make([]byte, d.h.FormatSize-16)
					if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
						return nil, beep.Format{}, errors.Wrap(err, "wav: missing extended format chunk body")
					}
				}
			}
		case string(ft[:]) == "data":
			d.h.DataMark = ft
			if err := binary.Read(r, binary.LittleEndian, &d.h.DataSize); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing data chunk size")
			}
			d.hsz += 4 + 4 //add size of (DataMark + DataSize)
		default:
			if err := binary.Read(r, binary.LittleEndian, &fs); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk size")
			}
			trash := make([]byte, fs)
			if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk body")
			}
			d.hsz += 4 + fs //add size of (Unknown formtype + formsize)
		}
	}

	if string(d.h.FmtMark[:]) != "fmt " {
		return nil, beep.Format{}, errors.New("wav: missing format chunk marker")
	}
	if string(d.h.DataMark[:]) != "data" {
		return nil, beep.Format{}, errors.New("wav: missing data chunk marker")
	}
	if d.h.FormatType != 1 && d.h.FormatType != -2 {
		return nil, beep.Format{}, fmt.Errorf("wav: unsupported format type - %d", d.h.FormatType)
	}
	if d.h.NumChans <= 0 {
		return nil, beep.Format{}, errors.New("wav: invalid number of channels (less than 1)")
	}
	if d.h.BitsPerSample != 8 && d.h.BitsPerSample != 16 && d.h.BitsPerSample != 24 {
		return nil, beep.Format{}, errors.New("wav: unsupported number of bits per sample, 8 or 16 or 24 are supported")
	}
	format = beep.Format{
		SampleRate:  beep.SampleRate(d.h.SampleRate),
		NumChannels: int(d.h.NumChans),
		Precision:   int(d.h.BitsPerSample / 8),
	}
	return &d, format, nil
}

type guid struct {
	Data1 int32
	Data2 int16
	Data3 int16
	Data4 [8]byte
}

type formatchunk struct {
	NumChans      int16
	SampleRate    int32
	ByteRate      int32
	BytesPerFrame int16
	BitsPerSample int16
}

type formatchunkextensible struct {
	formatchunk
	SubFormatSize int16
	Samples       int16 // original: union 3 types of WORD member (wValidBisPerSample, wSamplesPerBlock, wReserved)
	ChannelMask   int32
	SubFormat     guid
}

type header struct {
	RiffMark      [4]byte
	FileSize      int32
	WaveMark      [4]byte
	FmtMark       [4]byte
	FormatSize    int32
	FormatType    int16
	NumChans      int16
	SampleRate    int32
	ByteRate      int32
	BytesPerFrame int16
	BitsPerSample int16
	DataMark      [4]byte
	DataSize      int32
}

type decoder struct {
	r   io.Reader
	h   header
	hsz int32
	pos int32
	err error
}

func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
	if d.err != nil || d.pos >= d.h.DataSize {
		return 0, false
	}
	bytesPerFrame := int(d.h.BytesPerFrame)
	numBytes := int32(len(samples) * bytesPerFrame)
	if numBytes > d.h.DataSize-d.pos {
		numBytes = d.h.DataSize - d.pos
	}
	p := make([]byte, numBytes)
	n, err := d.r.Read(p)
	if err != nil && err != io.EOF {
		d.err = err
	}
	switch {
	case d.h.BitsPerSample == 8 && d.h.NumChans == 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64(p[i])/(1<<8-1)*2 - 1
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 8 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64(p[i+0])/(1<<8-1)*2 - 1
			samples[j][1] = float64(p[i+1])/(1<<8-1)*2 - 1
		}
	case d.h.BitsPerSample == 16 && d.h.NumChans == 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<15 - 1)
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 16 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<15 - 1)
			samples[j][1] = float64(int16(p[i+2])+int16(p[i+3])*(1<<8)) / (1<<15 - 1)
		}
	case d.h.BitsPerSample == 24 && d.h.NumChans >= 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64((int32(p[i+0])<<8)+(int32(p[i+1])<<16)+(int32(p[i+2])<<24)) / (1 << 8) / (1<<23 - 1)
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 24 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64((int32(p[i+0])<<8)+(int32(p[i+1])<<16)+(int32(p[i+2])<<24)) / (1 << 8) / (1<<23 - 1)
			samples[j][1] = float64((int32(p[i+3])<<8)+(int32(p[i+4])<<16)+(int32(p[i+5])<<24)) / (1 << 8) / (1<<23 - 1)
		}
	}
	d.pos += int32(n)
	return n / bytesPerFrame, true
}

func (d *decoder) Err() error {
	return d.err
}

func (d *decoder) Len() int {
	numBytes := time.Duration(d.h.DataSize)
	perFrame := time.Duration(d.h.BytesPerFrame)
	return int(numBytes / perFrame)
}

func (d *decoder) Position() int {
	return int(d.pos / int32(d.h.BytesPerFrame))
}

func (d *decoder) Seek(p int) error {
	seeker, ok := d.r.(io.Seeker)
	if !ok {
		panic(fmt.Errorf("wav: seek: resource is not io.Seeker"))
	}
	if p < 0 || d.Len() < p {
		return fmt.Errorf("wav: seek position %v out of range [%v, %v]", p, 0, d.Len())
	}
	pos := int32(p) * int32(d.h.BytesPerFrame)
	_, err := seeker.Seek(int64(pos+d.hsz), io.SeekStart) // hsz is the size of the header
	if err != nil {
		return errors.Wrap(err, "wav: seek error")
	}
	d.pos = pos
	return nil
}

func (d *decoder) Close() error {
	if closer, ok := d.r.(io.Closer); ok {
		err := closer.Close()
		if err != nil {
			return errors.Wrap(err, "wav")
		}
	}
	return nil
}
<commit_msg>wav: Resolve conversion issues<commit_after>package wav

import (
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"io"
	"time"

	"github.com/faiface/beep"
	"github.com/pkg/errors"
)

// Decode takes a Reader containing audio data in WAVE format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
//
// Do not close the supplied Reader, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) {
	d := decoder{r: r}
	defer func() { // hacky way to always close r if an error occurred
		if closer, ok := d.r.(io.Closer); ok {
			if err != nil {
				closer.Close()
			}
		}
	}()

	// READ "RIFF" header
	if err := binary.Read(r, binary.LittleEndian, d.h.RiffMark[:]); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav")
	}
	if string(d.h.RiffMark[:]) != "RIFF" {
		return nil, beep.Format{}, fmt.Errorf("wav: missing RIFF at the beginning > %s", string(d.h.RiffMark[:]))
	}

	// READ Total file size
	if err := binary.Read(r, binary.LittleEndian, &d.h.FileSize); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file size")
	}
	if err := binary.Read(r, binary.LittleEndian, d.h.WaveMark[:]); err != nil {
		return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file type")
	}
	if string(d.h.WaveMark[:]) != "WAVE" {
		return nil, beep.Format{}, errors.New("wav: unsupported file type")
	}

	// check each formtypes
	ft := [4]byte{0, 0, 0, 0}
	var fs int32
	d.hsz = 4 + 4 + 4 // add size of (RiffMark + FileSize + WaveMark)
	for string(ft[:]) != "data" {
		if err = binary.Read(r, binary.LittleEndian, ft[:]); err != nil {
			return nil, beep.Format{}, errors.Wrap(err, "wav: missing chunk type")
		}
		switch {
		case string(ft[:]) == "fmt ":
			d.h.FmtMark = ft
			if err := binary.Read(r, binary.LittleEndian, &d.h.FormatSize); err != nil {
				return nil, beep.Format{}, errors.New("wav: missing format chunk size")
			}
			d.hsz += 4 + 4 + d.h.FormatSize // add size of (FmtMark + FormatSize + its trailing size)
			if err := binary.Read(r, binary.LittleEndian, &d.h.FormatType); err != nil {
				return nil, beep.Format{}, errors.New("wav: missing format type")
			}
			if d.h.FormatType == -2 {
				// WAVEFORMATEXTENSIBLE
				fmtchunk := formatchunkextensible{
					formatchunk{0, 0, 0, 0, 0}, 0, 0, 0,
					guid{0, 0, 0, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}},
				}
				if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
					return nil, beep.Format{}, errors.New("wav: missing format chunk body")
				}
				d.h.NumChans = fmtchunk.NumChans
				d.h.SampleRate = fmtchunk.SampleRate
				d.h.ByteRate = fmtchunk.ByteRate
				d.h.BytesPerFrame = fmtchunk.BytesPerFrame
				d.h.BitsPerSample = fmtchunk.BitsPerSample

				// SubFormat is represented by GUID. Plain PCM is KSDATAFORMAT_SUBTYPE_PCM GUID.
				// See https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ksmedia/ns-ksmedia-waveformatextensible
				pcmguid := guid{
					0x00000001, 0x0000, 0x0010,
					[8]byte{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
				}
				if fmtchunk.SubFormat != pcmguid {
					return nil, beep.Format{}, fmt.Errorf(
						"wav: unsupported sub format type - %08x-%04x-%04x-%s",
						fmtchunk.SubFormat.Data1, fmtchunk.SubFormat.Data2, fmtchunk.SubFormat.Data3,
						hex.EncodeToString(fmtchunk.SubFormat.Data4[:]),
					)
				}
			} else {
				// WAVEFORMAT or WAVEFORMATEX
				fmtchunk := formatchunk{0, 0, 0, 0, 0}
				if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
					return nil, beep.Format{}, errors.New("wav: missing format chunk body")
				}
				d.h.NumChans = fmtchunk.NumChans
				d.h.SampleRate = fmtchunk.SampleRate
				d.h.ByteRate = fmtchunk.ByteRate
				d.h.BytesPerFrame = fmtchunk.BytesPerFrame
				d.h.BitsPerSample = fmtchunk.BitsPerSample

				// it would be skipping cbSize (WAVEFORMATEX's last member).
				if d.h.FormatSize > 16 {
					trash := make([]byte, d.h.FormatSize-16)
					if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
						return nil, beep.Format{}, errors.Wrap(err, "wav: missing extended format chunk body")
					}
				}
			}
		case string(ft[:]) == "data":
			d.h.DataMark = ft
			if err := binary.Read(r, binary.LittleEndian, &d.h.DataSize); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing data chunk size")
			}
			d.hsz += 4 + 4 //add size of (DataMark + DataSize)
		default:
			if err := binary.Read(r, binary.LittleEndian, &fs); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk size")
			}
			trash := make([]byte, fs)
			if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
				return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk body")
			}
			d.hsz += 4 + fs //add size of (Unknown formtype + formsize)
		}
	}

	if string(d.h.FmtMark[:]) != "fmt " {
		return nil, beep.Format{}, errors.New("wav: missing format chunk marker")
	}
	if string(d.h.DataMark[:]) != "data" {
		return nil, beep.Format{}, errors.New("wav: missing data chunk marker")
	}
	if d.h.FormatType != 1 && d.h.FormatType != -2 {
		return nil, beep.Format{}, fmt.Errorf("wav: unsupported format type - %d", d.h.FormatType)
	}
	if d.h.NumChans <= 0 {
		return nil, beep.Format{}, errors.New("wav: invalid number of channels (less than 1)")
	}
	if d.h.BitsPerSample != 8 && d.h.BitsPerSample != 16 && d.h.BitsPerSample != 24 {
		return nil, beep.Format{}, errors.New("wav: unsupported number of bits per sample, 8 or 16 or 24 are supported")
	}
	format = beep.Format{
		SampleRate:  beep.SampleRate(d.h.SampleRate),
		NumChannels: int(d.h.NumChans),
		Precision:   int(d.h.BitsPerSample / 8),
	}
	return &d, format, nil
}

type guid struct {
	Data1 int32
	Data2 int16
	Data3 int16
	Data4 [8]byte
}

type formatchunk struct {
	NumChans      int16
	SampleRate    int32
	ByteRate      int32
	BytesPerFrame int16
	BitsPerSample int16
}

type formatchunkextensible struct {
	formatchunk
	SubFormatSize int16
	Samples       int16 // original: union 3 types of WORD member (wValidBisPerSample, wSamplesPerBlock, wReserved)
	ChannelMask   int32
	SubFormat     guid
}

type header struct {
	RiffMark      [4]byte
	FileSize      int32
	WaveMark      [4]byte
	FmtMark       [4]byte
	FormatSize    int32
	FormatType    int16
	NumChans      int16
	SampleRate    int32
	ByteRate      int32
	BytesPerFrame int16
	BitsPerSample int16
	DataMark      [4]byte
	DataSize      int32
}

type decoder struct {
	r   io.Reader
	h   header
	hsz int32
	pos int32
	err error
}

func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
	if d.err != nil || d.pos >= d.h.DataSize {
		return 0, false
	}
	bytesPerFrame := int(d.h.BytesPerFrame)
	numBytes := int32(len(samples) * bytesPerFrame)
	if numBytes > d.h.DataSize-d.pos {
		numBytes = d.h.DataSize - d.pos
	}
	p := make([]byte, numBytes)
	n, err := d.r.Read(p)
	if err != nil && err != io.EOF {
		d.err = err
	}
	switch {
	case d.h.BitsPerSample == 8 && d.h.NumChans == 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64(p[i])/(1<<8-1)*2 - 1
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 8 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64(p[i+0])/(1<<8-1)*2 - 1
			samples[j][1] = float64(p[i+1])/(1<<8-1)*2 - 1
		}
	case d.h.BitsPerSample == 16 && d.h.NumChans == 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<16 - 1)
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 16 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<16 - 1)
			samples[j][1] = float64(int16(p[i+2])+int16(p[i+3])*(1<<8)) / (1<<16 - 1)
		}
	case d.h.BitsPerSample == 24 && d.h.NumChans == 1:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			val := float64((int32(p[i+0])<<8)+(int32(p[i+1])<<16)+(int32(p[i+2])<<24)) / (1 << 8) / (1<<24 - 1)
			samples[j][0] = val
			samples[j][1] = val
		}
	case d.h.BitsPerSample == 24 && d.h.NumChans >= 2:
		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
			samples[j][0] = float64((int32(p[i+0])<<8)+(int32(p[i+1])<<16)+(int32(p[i+2])<<24)) / (1 << 8) / (1<<24 - 1)
			samples[j][1] = float64((int32(p[i+3])<<8)+(int32(p[i+4])<<16)+(int32(p[i+5])<<24)) / (1 << 8) / (1<<24 - 1)
		}
	}
	d.pos += int32(n)
	return n / bytesPerFrame, true
}

func (d *decoder) Err() error {
	return d.err
}

func (d *decoder) Len() int {
	numBytes := time.Duration(d.h.DataSize)
	perFrame := time.Duration(d.h.BytesPerFrame)
	return int(numBytes / perFrame)
}

func (d *decoder) Position() int {
	return int(d.pos / int32(d.h.BytesPerFrame))
}

func (d *decoder) Seek(p int) error {
	seeker, ok := d.r.(io.Seeker)
	if !ok {
		panic(fmt.Errorf("wav: seek: resource is not io.Seeker"))
	}
	if p < 0 || d.Len() < p {
		return fmt.Errorf("wav: seek position %v out of range [%v, %v]", p, 0, d.Len())
	}
	pos := int32(p) * int32(d.h.BytesPerFrame)
	_, err := seeker.Seek(int64(pos+d.hsz), io.SeekStart) // hsz is the size of the header
	if err != nil {
		return errors.Wrap(err, "wav: seek error")
	}
	d.pos = pos
	return nil
}

func (d *decoder) Close() error {
	if closer, ok := d.r.(io.Closer); ok {
		err := closer.Close()
		if err != nil {
			return errors.Wrap(err, "wav")
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package auth

import (
	"net/url"

	"github.com/deckarep/golang-set"
)

// memory is a new in-memory set (map) of token/tag combination
type memory map[string]mapset.Set

// add "memory" to the list of supported Authenticators
func init() {
	Register("memory", NewMemory)
}

// NewMemory creates a new in-memory Authenticator
func NewMemory(url *url.URL) (Authenticator, error) {
	return memory{}, nil
}

// Add Token
func (a memory) AddToken(token string) error {

	// look for an existing token
	if _, err := a.findMemoryToken(token); err == nil {
		return ErrTokenExist
	}

	// create a new token
	a[token] = mapset.NewSet()

	return nil
}

// RemoveToken
func (a memory) RemoveToken(token string) error {
	delete(a, token)
	return nil
}

// AddTags
func (a memory) AddTags(token string, tags []string) error {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return err
	}

	// add new tags individually to avoid duplication
	for _, tag := range tags {
		entry.Add(tag)
	}

	return nil
}

// RemoveTags
func (a memory) RemoveTags(token string, tags []string) error {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return err
	}

	// remove tags
	for _, tag := range tags {
		entry.Remove(tag)
	}

	return nil
}

// GetTagsForToken
func (a memory) GetTagsForToken(token string) ([]string, error) {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return nil, err
	}

	// convert tags from map to slice
	var tags []string
	for _, tag := range entry.ToSlice() {
		tags = append(tags, tag.(string))
	}

	return tags, nil
}

// findMemoryToken attempts to find the desired token within memory
func (a memory) findMemoryToken(token string) (mapset.Set, error) {

	// look for existing token
	entry, ok := a[token]
	if !ok {
		return nil, ErrTokenNotFound
	}

	return entry, nil
}
<commit_msg>Fix function comments based on best practices from Effective Go<commit_after>package auth

import (
	"net/url"

	"github.com/deckarep/golang-set"
)

// memory is a new in-memory set (map) of token/tag combination
type memory map[string]mapset.Set

// add "memory" to the list of supported Authenticators
func init() {
	Register("memory", NewMemory)
}

// NewMemory creates a new in-memory Authenticator
func NewMemory(url *url.URL) (Authenticator, error) {
	return memory{}, nil
}

// AddToken adds Token
func (a memory) AddToken(token string) error {

	// look for an existing token
	if _, err := a.findMemoryToken(token); err == nil {
		return ErrTokenExist
	}

	// create a new token
	a[token] = mapset.NewSet()

	return nil
}

// RemoveToken
func (a memory) RemoveToken(token string) error {
	delete(a, token)
	return nil
}

// AddTags
func (a memory) AddTags(token string, tags []string) error {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return err
	}

	// add new tags individually to avoid duplication
	for _, tag := range tags {
		entry.Add(tag)
	}

	return nil
}

// RemoveTags
func (a memory) RemoveTags(token string, tags []string) error {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return err
	}

	// remove tags
	for _, tag := range tags {
		entry.Remove(tag)
	}

	return nil
}

// GetTagsForToken
func (a memory) GetTagsForToken(token string) ([]string, error) {

	// look for an existing token
	entry, err := a.findMemoryToken(token)
	if err != nil {
		return nil, err
	}

	// convert tags from map to slice
	var tags []string
	for _, tag := range entry.ToSlice() {
		tags = append(tags, tag.(string))
	}

	return tags, nil
}

// findMemoryToken attempts to find the desired token within memory
func (a memory) findMemoryToken(token string) (mapset.Set, error) {

	// look for existing token
	entry, ok := a[token]
	if !ok {
		return nil, ErrTokenNotFound
	}

	return entry, nil
}
<|endoftext|>


<commit_before>package action

import (
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/valyala/fasthttp"

	"github.com/asciimoo/filtron/types"
)

type Action interface {
	Act(string, *fasthttp.RequestCtx) error
	SetParams(map[string]string) error
	GetResponseState() types.ResponseState
}

type ActionJSON struct {
	Name   string            `json:"name"`
	Params map[string]string `json:"params"`
}

func FromJSON(j ActionJSON) (Action, error) {
	return Create(j.Name, j.Params)
}

func Create(name string, params map[string]string) (Action, error) {
	var a Action
	var e error
	switch name {
	case "log":
		a = &logAction{}
	case "block":
		a = &blockAction{}
	}
	if a != nil {
		e = a.SetParams(params)
	} else {
		e = errors.New(fmt.Sprintf("Unknown action: %v", name))
	}
	return a, e
}

type logAction struct {
	destination io.Writer
}

func (l *logAction) Act(ruleName string, ctx *fasthttp.RequestCtx) error {
	_, err := fmt.Fprintf(
		l.destination,
		"%v [%v] %s %s%s \"%s\" \"%s\"\n",
		time.Now(),
		ruleName,
		ctx.Method(),
		ctx.Host(),
		ctx.RequestURI(),
		ctx.PostBody(),
		ctx.Request.Header.UserAgent(),
	)
	return err
}

func (_ *logAction) GetResponseState() types.ResponseState {
	return types.UNTOUCHED
}

func (l *logAction) SetParams(params map[string]string) error {
	if _, found := params["destination"]; found {
		// TODO support destinations
		l.destination = os.Stderr
		return nil
	}
	return errors.New("Missing destination parameter")
}

type blockAction struct {
	message []byte
}

func (b *blockAction) Act(_ string, ctx *fasthttp.RequestCtx) error {
	ctx.SetStatusCode(429)
	ctx.Write(b.message)
	return nil
}

func (_ *blockAction) GetResponseState() types.ResponseState {
	return types.SERVED
}

func (b *blockAction) SetParams(params map[string]string) error {
	if message, found := params["message"]; found {
		b.message = []byte(message)
	} else {
		b.message = []byte("Blocked")
	}
	return nil
}
<commit_msg>[enh] better logging<commit_after>package action

import (
	"errors"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/valyala/fasthttp"

	"github.com/asciimoo/filtron/types"
)

type Action interface {
	Act(string, *fasthttp.RequestCtx) error
	SetParams(map[string]string) error
	GetResponseState() types.ResponseState
}

type ActionJSON struct {
	Name   string            `json:"name"`
	Params map[string]string `json:"params"`
}

func FromJSON(j ActionJSON) (Action, error) {
	return Create(j.Name, j.Params)
}

func Create(name string, params map[string]string) (Action, error) {
	var a Action
	var e error
	switch name {
	case "log":
		a = &logAction{}
	case "block":
		a = &blockAction{}
	}
	if a != nil {
		e = a.SetParams(params)
	} else {
		e = errors.New(fmt.Sprintf("Unknown action: %v", name))
	}
	return a, e
}

type logAction struct {
	destination io.Writer
}

func (l *logAction) Act(ruleName string, ctx *fasthttp.RequestCtx) error {
	_, err := fmt.Fprintf(
		l.destination,
		"[%v] %v %s %s %s%s \"%s\" \"%s\"\n",
		ruleName,
		time.Now().Format("2006-01-02 15:04:05.000"),
		ctx.Request.Header.Peek("X-Forwarded-For"),
		ctx.Method(),
		ctx.Host(),
		ctx.RequestURI(),
		ctx.PostBody(),
		ctx.Request.Header.UserAgent(),
	)
	return err
}

func (_ *logAction) GetResponseState() types.ResponseState {
	return types.UNTOUCHED
}

func (l *logAction) SetParams(params map[string]string) error {
	if _, found := params["destination"]; found {
		// TODO support destinations
		l.destination = os.Stderr
		return nil
	}
	return errors.New("Missing destination parameter")
}

type blockAction struct {
	message []byte
}

func (b *blockAction) Act(_ string, ctx *fasthttp.RequestCtx) error {
	ctx.SetStatusCode(429)
	ctx.Write(b.message)
	return nil
}

func (_ *blockAction) GetResponseState() types.ResponseState {
	return types.SERVED
}

func (b *blockAction) SetParams(params map[string]string) error {
	if message, found := params["message"]; found {
		b.message = []byte(message)
	} else {
		b.message = []byte("Blocked")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	// #cgo CPPFLAGS: -I/Users/csw/src/libraft
	// #cgo LDFLAGS: -L/Users/csw/src/libraft
	// #cgo CXXFLAGS: -std=c++11
	// #cgo LDFLAGS: -lraft
	// #include "raft_go_if.h"
	"C"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"reflect"
	"sync"
	"time"
	"unsafe"
	"github.com/hashicorp/raft"
	// should just be for scaffolding
	"github.com/hashicorp/go-msgpack/codec"
)

// lifted from http://bazaar.launchpad.net/~niemeyer/gommap/trunk/view/head:/gommap.go
type Shm []byte

var ri *raft.Raft
var shm Shm

func main() {
	port := flag.Int("port", 9001, "Raft port to listen on")
	single := flag.Bool("single", false, "Run in single-node mode")
	flag.Parse()

	fmt.Printf("Initializing Raft shared memory.\n")

	nshm, err := ShmInit()
	if (err != nil) {
		panic("Failed to initialize shared memory!")
	}
	shm = nshm
	fmt.Printf("Shared memory initialized.\n")

	conf := raft.DefaultConfig()
	conf.EnableSingleNode = *single
	fsm := &MockFSM{}
	logStore := raft.NewInmemStore()
	stableStore := raft.NewInmemStore()
	snapDir, err := ioutil.TempDir("", "raft")
	if err != nil {
		panic(fmt.Sprintf("err: %v ", err))
	}
	snapStore, err := raft.NewFileSnapshotStore(snapDir, 1, os.Stderr)
	if (err != nil) {
		panic(fmt.Sprintf("Creating snapshot store in %s failed: %v", snapDir, err))
	}

	bindAddr := fmt.Sprintf("127.0.0.1:%d", *port)
	trans, err := raft.NewTCPTransport(bindAddr, nil, 16, 0, nil)
	if err != nil {
		panic(fmt.Sprintf("Binding to %s failed: %v", bindAddr, err))
	}

	peerAddrs := make([]net.Addr, 0, len(flag.Args()))
	for i := 0; i < len(flag.Args()); i++ {
		peer := flag.Args()[i]
		peerAddr, err := net.ResolveTCPAddr("tcp", peer)
		if err != nil {
			panic(fmt.Sprintf("Failed to parse address %s", peer))
		}
		peerAddrs[i] = peerAddr
	}
	peers := &raft.StaticPeers{ StaticPeers: peerAddrs}

	raft, err := raft.NewRaft(conf, fsm, logStore, stableStore, snapStore, peers, trans)
	if (err != nil) {
		panic(fmt.Sprintf("Failed to create Raft instance: %v", err))
	}

	ri = raft
	if StartWorkers() != nil {
		panic(fmt.Sprintf("Failed to start workers: %v", err))
	}

	C.raft_ready()

	for {
		time.Sleep(5*time.Second)
	}
}

func StartWorkers() error {
	go ReportLeaderStatus()
	for i := 0; i < 16; i++ {
		go RunWorker(i)
	}
	return nil
}

func RunWorker(i int) {
	for {
		C.await_call(C.uint32_t(i))
	}
}

func ReportLeaderStatus() {
	leaderCh := ri.LeaderCh()
	for {
		leaderState := <-leaderCh
		C.raft_set_leader(C._Bool(leaderState))
	}
}

func ShmInit() (Shm, error) {
	shared_base := C.raft_shm_init()
	if shared_base == nil {
		panic(fmt.Sprintf("Failed to allocate shared memory!"))
	}

	shared_len := C.raft_shm_size()
	shm := Shm{}
	dh := (*reflect.SliceHeader)(unsafe.Pointer(&shm))
	dh.Data = uintptr(shared_base)
	dh.Len = int(shared_len) // make sure it's under 2^32 bits...
	dh.Cap = dh.Len
	return shm, nil
}

func exercise(r *raft.Raft) {
	if (r.State() == raft.Leader) {
		fmt.Printf("This node is the leader.\n")
		applyF := r.Apply([]byte("foo"), 1*time.Minute)
		if applyF.Error() == nil {
			fmt.Printf("Apply succeeded.\n")
		} else {
			fmt.Printf("Apply failed: %v", applyF.Error())
		}
	}
}

// Interface functions

// note: multiple return value structs have members r0, r1, ...
// errors are represented as a GoInterface struct
// typedef struct { void *data; GoInt len; GoInt cap; } GoSlice
// typedef struct { char *p; GoInt n; } GoString

//export RaftApply
func RaftApply(cmd_offset uintptr, cmd_len uintptr, timeout uint64) (unsafe.Pointer, error) {
	cmd := shm[cmd_offset:cmd_offset+cmd_len]
	fmt.Printf("Applying command (%d bytes): %q\n",
		len(cmd), cmd)
	future := ri.Apply(cmd, time.Duration(timeout))
	if future.Error() == nil {
		fmt.Printf("Command succeeded.\n")
		return nil, nil
	} else {
		fmt.Printf("Command failed: %v\n", future.Error())
		return nil, future.Error()
	}
}

//export TranslateRaftError
func TranslateRaftError(err error) C.RaftError {
	switch err {
	case nil: return C.RAFT_SUCCESS
	case raft.ErrLeader: return C.RAFT_E_LEADER
	case raft.ErrNotLeader: return C.RAFT_E_NOT_LEADER
	case raft.ErrLeadershipLost: return C.RAFT_E_LEADERSHIP_LOST
	case raft.ErrRaftShutdown: return C.RAFT_E_SHUTDOWN
	case raft.ErrEnqueueTimeout: return C.RAFT_E_ENQUEUE_TIMEOUT
	case raft.ErrKnownPeer: return C.RAFT_E_KNOWN_PEER
	case raft.ErrUnknownPeer: return C.RAFT_E_UNKNOWN_PEER
	case raft.ErrLogNotFound: return C.RAFT_E_LOG_NOT_FOUND
	case raft.ErrPipelineReplicationNotSupported: return C.RAFT_E_PIPELINE_REPLICATION_NOT_SUPP
	case raft.ErrTransportShutdown: return C.RAFT_E_TRANSPORT_SHUTDOWN
	case raft.ErrPipelineShutdown: return C.RAFT_E_PIPELINE_SHUTDOWN
	default: return C.RAFT_E_OTHER
	}
}

// Temporary scaffolding

// MockFSM is an implementation of the FSM interface, and just stores
// the logs sequentially
type MockFSM struct {
	sync.Mutex
	logs [][]byte
}

type MockSnapshot struct {
	logs     [][]byte
	maxIndex int
}

func (m *MockFSM) Apply(log *raft.Log) interface{} {
	var c_type C.RaftLogType
	var cmd_buf *C.char
	var cmd_len C.size_t

	fmt.Printf("Applying command to C FSM: %q\n", log.Data)

	switch log.Type {
	case raft.LogCommand: c_type = C.RAFT_LOG_COMMAND
	case raft.LogNoop: c_type = C.RAFT_LOG_NOOP
	case raft.LogAddPeer: c_type = C.RAFT_LOG_ADD_PEER
	case raft.LogRemovePeer: c_type = C.RAFT_LOG_REMOVE_PEER
	case raft.LogBarrier: c_type = C.RAFT_LOG_BARRIER
	default:
		panic("Unhandled log type!")
	}
	dh := (*reflect.SliceHeader)(unsafe.Pointer(&log.Data))
	cmd_buf = (*C.char)(unsafe.Pointer(dh.Data))
	cmd_len = C.size_t(dh.Len)

	rv := C.raft_fsm_apply(C.uint64_t(log.Index), C.uint64_t(log.Term), c_type, cmd_buf, cmd_len);

	return rv
}

func (m *MockFSM) Snapshot() (raft.FSMSnapshot, error) {
	m.Lock()
	defer m.Unlock()
	fmt.Printf("=== FSM snapshot requested ===\n");
	return &MockSnapshot{m.logs, len(m.logs)}, nil
}

func (m *MockFSM) Restore(inp io.ReadCloser) error {
	m.Lock()
	defer m.Unlock()
	defer inp.Close()
	fmt.Printf("=== FSM restore requested ===\n");
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(inp, &hd)

	m.logs = nil
	return dec.Decode(&m.logs)
}

func (m *MockSnapshot) Persist(sink raft.SnapshotSink) error {
	hd := codec.MsgpackHandle{}
	enc := codec.NewEncoder(sink, &hd)
	if err := enc.Encode(m.logs[:m.maxIndex]); err != nil {
		sink.Cancel()
		return err
	}
	sink.Close()
	return nil
}

func (m *MockSnapshot) Release() {
}
<commit_msg>Remove extraneous compiler flags.<commit_after>package main

import (
	// #cgo CXXFLAGS: -std=c++11
	// #cgo LDFLAGS: -lraft
	// #include "raft_go_if.h"
	"C"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"os"
	"reflect"
	"sync"
	"time"
	"unsafe"
	"github.com/hashicorp/raft"
	// should just be for scaffolding
	"github.com/hashicorp/go-msgpack/codec"
)

// lifted from http://bazaar.launchpad.net/~niemeyer/gommap/trunk/view/head:/gommap.go
type Shm []byte

var ri *raft.Raft
var shm Shm

func main() {
	port := flag.Int("port", 9001, "Raft port to listen on")
	single := flag.Bool("single", false, "Run in single-node mode")
	flag.Parse()

	fmt.Printf("Initializing Raft shared memory.\n")

	nshm, err := ShmInit()
	if (err != nil) {
		panic("Failed to initialize shared memory!")
	}
	shm = nshm
	fmt.Printf("Shared memory initialized.\n")

	conf := raft.DefaultConfig()
	conf.EnableSingleNode = *single
	fsm := &MockFSM{}
	logStore := raft.NewInmemStore()
	stableStore := raft.NewInmemStore()
	snapDir, err := ioutil.TempDir("", "raft")
	if err != nil {
		panic(fmt.Sprintf("err: %v ", err))
	}
	snapStore, err := raft.NewFileSnapshotStore(snapDir, 1, os.Stderr)
	if (err != nil) {
		panic(fmt.Sprintf("Creating snapshot store in %s failed: %v", snapDir, err))
	}

	bindAddr := fmt.Sprintf("127.0.0.1:%d", *port)
	trans, err := raft.NewTCPTransport(bindAddr, nil, 16, 0, nil)
	if err != nil {
		panic(fmt.Sprintf("Binding to %s failed: %v", bindAddr, err))
	}

	peerAddrs := make([]net.Addr, 0, len(flag.Args()))
	for i := 0; i < len(flag.Args()); i++ {
		peer := flag.Args()[i]
		peerAddr, err := net.ResolveTCPAddr("tcp", peer)
		if err != nil {
			panic(fmt.Sprintf("Failed to parse address %s", peer))
		}
		peerAddrs[i] = peerAddr
	}
	peers := &raft.StaticPeers{ StaticPeers: peerAddrs}

	raft, err := raft.NewRaft(conf, fsm, logStore, stableStore, snapStore, peers, trans)
	if (err != nil) {
		panic(fmt.Sprintf("Failed to create Raft instance: %v", err))
	}

	ri = raft
	if StartWorkers() != nil {
		panic(fmt.Sprintf("Failed to start workers: %v", err))
	}

	C.raft_ready()

	for {
		time.Sleep(5*time.Second)
	}
}

func StartWorkers() error {
	go ReportLeaderStatus()
	for i := 0; i < 16; i++ {
		go RunWorker(i)
	}
	return nil
}

func RunWorker(i int) {
	for {
		C.await_call(C.uint32_t(i))
	}
}

func ReportLeaderStatus() {
	leaderCh := ri.LeaderCh()
	for {
		leaderState := <-leaderCh
		C.raft_set_leader(C._Bool(leaderState))
	}
}

func ShmInit() (Shm, error) {
	shared_base := C.raft_shm_init()
	if shared_base == nil {
		panic(fmt.Sprintf("Failed to allocate shared memory!"))
	}

	shared_len := C.raft_shm_size()
	shm := Shm{}
	dh := (*reflect.SliceHeader)(unsafe.Pointer(&shm))
	dh.Data = uintptr(shared_base)
	dh.Len = int(shared_len) // make sure it's under 2^32 bits...
	dh.Cap = dh.Len
	return shm, nil
}

func exercise(r *raft.Raft) {
	if (r.State() == raft.Leader) {
		fmt.Printf("This node is the leader.\n")
		applyF := r.Apply([]byte("foo"), 1*time.Minute)
		if applyF.Error() == nil {
			fmt.Printf("Apply succeeded.\n")
		} else {
			fmt.Printf("Apply failed: %v", applyF.Error())
		}
	}
}

// Interface functions

// note: multiple return value structs have members r0, r1, ...
// errors are represented as a GoInterface struct
// typedef struct { void *data; GoInt len; GoInt cap; } GoSlice
// typedef struct { char *p; GoInt n; } GoString

//export RaftApply
func RaftApply(cmd_offset uintptr, cmd_len uintptr, timeout uint64) (unsafe.Pointer, error) {
	cmd := shm[cmd_offset:cmd_offset+cmd_len]
	fmt.Printf("Applying command (%d bytes): %q\n",
		len(cmd), cmd)
	future := ri.Apply(cmd, time.Duration(timeout))
	if future.Error() == nil {
		fmt.Printf("Command succeeded.\n")
		return nil, nil
	} else {
		fmt.Printf("Command failed: %v\n", future.Error())
		return nil, future.Error()
	}
}

//export TranslateRaftError
func TranslateRaftError(err error) C.RaftError {
	switch err {
	case nil: return C.RAFT_SUCCESS
	case raft.ErrLeader: return C.RAFT_E_LEADER
	case raft.ErrNotLeader: return C.RAFT_E_NOT_LEADER
	case raft.ErrLeadershipLost: return C.RAFT_E_LEADERSHIP_LOST
	case raft.ErrRaftShutdown: return C.RAFT_E_SHUTDOWN
	case raft.ErrEnqueueTimeout: return C.RAFT_E_ENQUEUE_TIMEOUT
	case raft.ErrKnownPeer: return C.RAFT_E_KNOWN_PEER
	case raft.ErrUnknownPeer: return C.RAFT_E_UNKNOWN_PEER
	case raft.ErrLogNotFound: return C.RAFT_E_LOG_NOT_FOUND
	case raft.ErrPipelineReplicationNotSupported: return C.RAFT_E_PIPELINE_REPLICATION_NOT_SUPP
	case raft.ErrTransportShutdown: return C.RAFT_E_TRANSPORT_SHUTDOWN
	case raft.ErrPipelineShutdown: return C.RAFT_E_PIPELINE_SHUTDOWN
	default: return C.RAFT_E_OTHER
	}
}

// Temporary scaffolding

// MockFSM is an implementation of the FSM interface, and just stores
// the logs sequentially
type MockFSM struct {
	sync.Mutex
	logs [][]byte
}

type MockSnapshot struct {
	logs     [][]byte
	maxIndex int
}

func (m *MockFSM) Apply(log *raft.Log) interface{} {
	var c_type C.RaftLogType
	var cmd_buf *C.char
	var cmd_len C.size_t

	fmt.Printf("Applying command to C FSM: %q\n", log.Data)

	switch log.Type {
	case raft.LogCommand: c_type = C.RAFT_LOG_COMMAND
	case raft.LogNoop: c_type = C.RAFT_LOG_NOOP
	case raft.LogAddPeer: c_type = C.RAFT_LOG_ADD_PEER
	case raft.LogRemovePeer: c_type = C.RAFT_LOG_REMOVE_PEER
	case raft.LogBarrier: c_type = C.RAFT_LOG_BARRIER
	default:
		panic("Unhandled log type!")
	}
	dh := (*reflect.SliceHeader)(unsafe.Pointer(&log.Data))
	cmd_buf = (*C.char)(unsafe.Pointer(dh.Data))
	cmd_len = C.size_t(dh.Len)

	rv := C.raft_fsm_apply(C.uint64_t(log.Index), C.uint64_t(log.Term), c_type, cmd_buf, cmd_len);

	return rv
}

func (m *MockFSM) Snapshot() (raft.FSMSnapshot, error) {
	m.Lock()
	defer m.Unlock()
	fmt.Printf("=== FSM snapshot requested ===\n");
	return &MockSnapshot{m.logs, len(m.logs)}, nil
}

func (m *MockFSM) Restore(inp io.ReadCloser) error {
	m.Lock()
	defer m.Unlock()
	defer inp.Close()
	fmt.Printf("=== FSM restore requested ===\n");
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(inp, &hd)

	m.logs = nil
	return dec.Decode(&m.logs)
}

func (m *MockSnapshot) Persist(sink raft.SnapshotSink) error {
	hd := codec.MsgpackHandle{}
	enc := codec.NewEncoder(sink, &hd)
	if err := enc.Encode(m.logs[:m.maxIndex]); err != nil {
		sink.Cancel()
		return err
	}
	sink.Close()
	return nil
}

func (m *MockSnapshot) Release() {
}
<|endoftext|>


<commit_before>package setup

import (
	"fmt"
	"io/ioutil"
	"text/template"

	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// Browse configures a new Browse middleware instance.
func Browse(c *Controller) (middleware.Middleware, error) {
	configs, err := browseParse(c)
	if err != nil {
		return nil, err
	}

	browse := browse.Browse{
		Root:          c.Root,
		Configs:       configs,
		IgnoreIndexes: false,
	}

	return func(next middleware.Handler) middleware.Handler {
		browse.Next = next
		return browse
	}, nil
}

func browseParse(c *Controller) ([]browse.Config, error) {
	var configs []browse.Config

	appendCfg := func(bc browse.Config) error {
		for _, c := range configs {
			if c.PathScope == bc.PathScope {
				return fmt.Errorf("duplicate browsing config for %s", c.PathScope)
			}
		}
		configs = append(configs, bc)
		return nil
	}

	for c.Next() {
		var bc browse.Config

		// First argument is directory to allow browsing; default is site root
		if c.NextArg() {
			bc.PathScope = c.Val()
		} else {
			bc.PathScope = "/"
		}

		// Second argument would be the template file to use
		var tplText string
		if c.NextArg() {
			tplBytes, err := ioutil.ReadFile(c.Val())
			if err != nil {
				return configs, err
			}
			tplText = string(tplBytes)
		} else {
			tplText = defaultTemplate
		}

		// Build the template
		tpl, err := template.New("listing").Parse(tplText)
		if err != nil {
			return configs, err
		}
		bc.Template = tpl

		// Save configuration
		err = appendCfg(bc)
		if err != nil {
			return configs, err
		}
	}

	return configs, nil
}

// The default template to use when serving up directory listings
const defaultTemplate = `<!DOCTYPE html>

		<title>{{.Name}}</title>
		<meta charset="utf-8">

			{{if .CanGoUp}}
			⬑
			{{else}}

			{{end}}

{{.Path}}

						{{if and (eq .Sort "name") (ne .Order "desc")}}
						Name ▲
						{{else if and (eq .Sort "name") (ne .Order "asc")}}
						Name ▼
						{{else}}
						Name
						{{end}}

						{{if and (eq .Sort "size") (ne .Order "desc")}}
						Size ▲
						{{else if and (eq .Sort "size") (ne .Order "asc")}}
						Size ▼
						{{else}}
						Size
						{{end}}

						{{if and (eq .Sort "time") (ne .Order "desc")}}
						Modified ▲
						{{else if and (eq .Sort "time") (ne .Order "asc")}}
						Modified ▼
						{{else}}
						Modified
						{{end}}

				{{range .Items}}

						{{if .IsDir}}📂{{else}}📄{{end}}
						{{.Name}}

					{{.HumanSize}}
					{{.HumanModTime "01/02/2006 3:04:05 PM -0700"}}

				{{end}}

`
<commit_msg>allow consecutive spaces for browse<commit_after>package setup

import (
	"fmt"
	"io/ioutil"
	"text/template"

	"github.com/mholt/caddy/middleware"
	"github.com/mholt/caddy/middleware/browse"
)

// Browse configures a new Browse middleware instance.
func Browse(c *Controller) (middleware.Middleware, error) {
	configs, err := browseParse(c)
	if err != nil {
		return nil, err
	}

	browse := browse.Browse{
		Root:          c.Root,
		Configs:       configs,
		IgnoreIndexes: false,
	}

	return func(next middleware.Handler) middleware.Handler {
		browse.Next = next
		return browse
	}, nil
}

func browseParse(c *Controller) ([]browse.Config, error) {
	var configs []browse.Config

	appendCfg := func(bc browse.Config) error {
		for _, c := range configs {
			if c.PathScope == bc.PathScope {
				return fmt.Errorf("duplicate browsing config for %s", c.PathScope)
			}
		}
		configs = append(configs, bc)
		return nil
	}

	for c.Next() {
		var bc browse.Config

		// First argument is directory to allow browsing; default is site root
		if c.NextArg() {
			bc.PathScope = c.Val()
		} else {
			bc.PathScope = "/"
		}

		// Second argument would be the template file to use
		var tplText string
		if c.NextArg() {
			tplBytes, err := ioutil.ReadFile(c.Val())
			if err != nil {
				return configs, err
			}
			tplText = string(tplBytes)
		} else {
			tplText = defaultTemplate
		}

		// Build the template
		tpl, err := template.New("listing").Parse(tplText)
		if err != nil {
			return configs, err
		}
		bc.Template = tpl

		// Save configuration
		err = appendCfg(bc)
		if err != nil {
			return configs, err
		}
	}

	return configs, nil
}

// The default template to use when serving up directory listings
const defaultTemplate = `<!DOCTYPE html>

		<title>{{.Name}}</title>
		<meta charset="utf-8">

			{{if .CanGoUp}}
			⬑
			{{else}}

			{{end}}

{{.Path}}

						{{if and (eq .Sort "name") (ne .Order "desc")}}
						Name ▲
						{{else if and (eq .Sort "name") (ne .Order "asc")}}
						Name ▼
						{{else}}
						Name
						{{end}}

						{{if and (eq .Sort "size") (ne .Order "desc")}}
						Size ▲
						{{else if and (eq .Sort "size") (ne .Order "asc")}}
						Size ▼
						{{else}}
						Size
						{{end}}

						{{if and (eq .Sort "time") (ne .Order "desc")}}
						Modified ▲
						{{else if and (eq .Sort "time") (ne .Order "asc")}}
						Modified ▼
						{{else}}
						Modified
						{{end}}

				{{range .Items}}

						{{if .IsDir}}📂{{else}}📄{{end}}
						{{.Name}}

					{{.HumanSize}}
					{{.HumanModTime "01/02/2006 3:04:05 PM -0700"}}

				{{end}}

`
<|endoftext|>


<commit_before>package paypal

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

// CreateWebhook - Subscribes your webhook listener to events.
// Endpoint: POST /v1/notifications/webhooks
func (c *Client) CreateWebhook(ctx context.Context, createWebhookRequest *CreateWebhookRequest) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// GetWebhook - Shows details for a webhook, by ID.
// Endpoint: GET /v1/notifications/webhooks/ID
func (c *Client) GetWebhook(ctx context.Context, webhookID string) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// UpdateWebhook - Updates a webhook to replace webhook fields with new values.
// Endpoint: PATCH /v1/notifications/webhooks/ID
func (c *Client) UpdateWebhook(ctx context.Context, webhookID string, fields []WebhookField) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// ListWebhooks - Lists webhooks for an app.
// Endpoint: GET /v1/notifications/webhooks
func (c *Client) ListWebhooks(ctx context.Context, anchorType string) (*ListWebhookResponse, error) {
	if len(anchorType) == 0 {
		anchorType = AncorTypeApplication
	}
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil)
	q := req.URL.Query()
	q.Add("anchor_type", anchorType)
	req.URL.RawQuery = q.Encode()
	resp := &ListWebhookResponse{}
	if err != nil {
		return nil, err
	}

	err = c.SendWithAuth(req, resp)
	return resp, err
}

// DeleteWebhook - Deletes a webhook, by ID.
// Endpoint: DELETE /v1/notifications/webhooks/ID
func (c *Client) DeleteWebhook(ctx context.Context, webhookID string) error {
	req, err := c.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil)
	if err != nil {
		return err
	}

	err = c.SendWithAuth(req, nil)
	return err
}

// VerifyWebhookSignature - Use this to verify the signature of a webhook recieved from paypal.
// Endpoint: POST /v1/notifications/verify-webhook-signature
func (c *Client) VerifyWebhookSignature(ctx context.Context, httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) {
	type verifyWebhookSignatureRequest struct {
		AuthAlgo         string          `json:"auth_algo,omitempty"`
		CertURL          string          `json:"cert_url,omitempty"`
		TransmissionID   string          `json:"transmission_id,omitempty"`
		TransmissionSig  string          `json:"transmission_sig,omitempty"`
		TransmissionTime string          `json:"transmission_time,omitempty"`
		WebhookID        string          `json:"webhook_id,omitempty"`
		Event            json.RawMessage `json:"webhook_event,omitempty"`
	}

	// Read the content
	var bodyBytes []byte
	if httpReq.Body != nil {
		bodyBytes, _ = ioutil.ReadAll(httpReq.Body)
	}
	else{
		return nil, errors.New("Cannot verify webhook for HTTP Request with empty body.")
	}
	// Restore the io.ReadCloser to its original state
	httpReq.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

	verifyRequest := verifyWebhookSignatureRequest{
		AuthAlgo:         httpReq.Header.Get("PAYPAL-AUTH-ALGO"),
		CertURL:          httpReq.Header.Get("PAYPAL-CERT-URL"),
		TransmissionID:   httpReq.Header.Get("PAYPAL-TRANSMISSION-ID"),
		TransmissionSig:  httpReq.Header.Get("PAYPAL-TRANSMISSION-SIG"),
		TransmissionTime: httpReq.Header.Get("PAYPAL-TRANSMISSION-TIME"),
		WebhookID:        webhookID,
		Event:            json.RawMessage(bodyBytes),
	}

	response := &VerifyWebhookResponse{}

	req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/verify-webhook-signature"), verifyRequest)
	if err != nil {
		return nil, err
	}

	if err = c.SendWithAuth(req, response); err != nil {
		return nil, err
	}

	return response, nil
}

// GetWebhookEventTypes - Lists all webhook event types.
// Endpoint: GET /v1/notifications/webhooks-event-types
func (c *Client) GetWebhookEventTypes(ctx context.Context) (*WebhookEventTypesResponse, error) {
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks-event-types"), nil)
	q := req.URL.Query()

	req.URL.RawQuery = q.Encode()
	resp := &WebhookEventTypesResponse{}
	if err != nil {
		return nil, err
	}

	err = c.SendWithAuth(req, resp)
	return resp, err
}
<commit_msg>Fixed else syntax<commit_after>package paypal

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

// CreateWebhook - Subscribes your webhook listener to events.
// Endpoint: POST /v1/notifications/webhooks
func (c *Client) CreateWebhook(ctx context.Context, createWebhookRequest *CreateWebhookRequest) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), createWebhookRequest)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// GetWebhook - Shows details for a webhook, by ID.
// Endpoint: GET /v1/notifications/webhooks/ID
func (c *Client) GetWebhook(ctx context.Context, webhookID string) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s%s", c.APIBase, "/v1/notifications/webhooks/", webhookID), nil)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// UpdateWebhook - Updates a webhook to replace webhook fields with new values.
// Endpoint: PATCH /v1/notifications/webhooks/ID
func (c *Client) UpdateWebhook(ctx context.Context, webhookID string, fields []WebhookField) (*Webhook, error) {
	req, err := c.NewRequest(ctx, http.MethodPatch, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), fields)
	webhook := &Webhook{}
	if err != nil {
		return webhook, err
	}

	err = c.SendWithAuth(req, webhook)
	return webhook, err
}

// ListWebhooks - Lists webhooks for an app.
// Endpoint: GET /v1/notifications/webhooks
func (c *Client) ListWebhooks(ctx context.Context, anchorType string) (*ListWebhookResponse, error) {
	if len(anchorType) == 0 {
		anchorType = AncorTypeApplication
	}
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks"), nil)
	q := req.URL.Query()
	q.Add("anchor_type", anchorType)
	req.URL.RawQuery = q.Encode()
	resp := &ListWebhookResponse{}
	if err != nil {
		return nil, err
	}

	err = c.SendWithAuth(req, resp)
	return resp, err
}

// DeleteWebhook - Deletes a webhook, by ID.
// Endpoint: DELETE /v1/notifications/webhooks/ID
func (c *Client) DeleteWebhook(ctx context.Context, webhookID string) error {
	req, err := c.NewRequest(ctx, http.MethodDelete, fmt.Sprintf("%s/v1/notifications/webhooks/%s", c.APIBase, webhookID), nil)
	if err != nil {
		return err
	}

	err = c.SendWithAuth(req, nil)
	return err
}

// VerifyWebhookSignature - Use this to verify the signature of a webhook recieved from paypal.
// Endpoint: POST /v1/notifications/verify-webhook-signature
func (c *Client) VerifyWebhookSignature(ctx context.Context, httpReq *http.Request, webhookID string) (*VerifyWebhookResponse, error) {
	type verifyWebhookSignatureRequest struct {
		AuthAlgo         string          `json:"auth_algo,omitempty"`
		CertURL          string          `json:"cert_url,omitempty"`
		TransmissionID   string          `json:"transmission_id,omitempty"`
		TransmissionSig  string          `json:"transmission_sig,omitempty"`
		TransmissionTime string          `json:"transmission_time,omitempty"`
		WebhookID        string          `json:"webhook_id,omitempty"`
		Event            json.RawMessage `json:"webhook_event,omitempty"`
	}

	// Read the content
	var bodyBytes []byte
	if httpReq.Body != nil {
		bodyBytes, _ = ioutil.ReadAll(httpReq.Body)
	}else{
		return nil, errors.New("Cannot verify webhook for HTTP Request with empty body.")
	}
	// Restore the io.ReadCloser to its original state
	httpReq.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

	verifyRequest := verifyWebhookSignatureRequest{
		AuthAlgo:         httpReq.Header.Get("PAYPAL-AUTH-ALGO"),
		CertURL:          httpReq.Header.Get("PAYPAL-CERT-URL"),
		TransmissionID:   httpReq.Header.Get("PAYPAL-TRANSMISSION-ID"),
		TransmissionSig:  httpReq.Header.Get("PAYPAL-TRANSMISSION-SIG"),
		TransmissionTime: httpReq.Header.Get("PAYPAL-TRANSMISSION-TIME"),
		WebhookID:        webhookID,
		Event:            json.RawMessage(bodyBytes),
	}

	response := &VerifyWebhookResponse{}

	req, err := c.NewRequest(ctx, "POST", fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/verify-webhook-signature"), verifyRequest)
	if err != nil {
		return nil, err
	}

	if err = c.SendWithAuth(req, response); err != nil {
		return nil, err
	}

	return response, nil
}

// GetWebhookEventTypes - Lists all webhook event types.
// Endpoint: GET /v1/notifications/webhooks-event-types
func (c *Client) GetWebhookEventTypes(ctx context.Context) (*WebhookEventTypesResponse, error) {
	req, err := c.NewRequest(ctx, http.MethodGet, fmt.Sprintf("%s%s", c.APIBase, "/v1/notifications/webhooks-event-types"), nil)
	q := req.URL.Query()

	req.URL.RawQuery = q.Encode()
	resp := &WebhookEventTypesResponse{}
	if err != nil {
		return nil, err
	}

	err = c.SendWithAuth(req, resp)
	return resp, err
}
<|endoftext|>


<commit_before>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.6.6"
<commit_msg>Tag release v0.6.7<commit_after>// Package aws provides core functionality for making requests to AWS services.
package aws

// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"

// SDKVersion is the version of this SDK
const SDKVersion = "0.6.7"
<|endoftext|>


<commit_before>/*
   conflux - Distributed database synchronization library
	Based on the algorithm described in
		"Set Reconciliation with Nearly Optimal	Communication Complexity",
			Yaron Minsky, Ari Trachtenberg, and Richard Zippel, 2004.

   Copyright (c) 2012-2015  Casey Marshall <cmars@cmarstech.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, version 3.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package recon

import (
	"net"
	"testing"

	gc "gopkg.in/check.v1"
)

func Test(t *testing.T) { gc.TestingT(t) }

type SettingsSuite struct{}

var _ = gc.Suite(&SettingsSuite{})

func (s *SettingsSuite) TestParse(c *gc.C) {
	testCases := []struct {
		desc     string
		toml     string
		settings *Settings
		err      string
	}{{
		"empty string",
		``,
		DefaultSettings(),
		"",
	}, {
		"field setting with some defaults",
		`
[conflux.recon]
version="2.3.4"
logname="blammo"
filters=["something","else"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     "2.3.4",
			LogName:                     "blammo",
			Filters:                     []string{"something", "else"},
			HTTPAddr:                    ":11371",
			ReconAddr:                   ":11370",
			Partners:                    PartnerMap{},
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
		},
		"",
	}, {
		"field setting override some defaults",
		`
[conflux.recon]
version="2.3.4"
logname="blammo"
httpAddr="12.23.34.45:11371"
reconAddr="[2001:db8:85a3::8a2e:370:7334]:11370"
filters=["something","else"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     "2.3.4",
			LogName:                     "blammo",
			HTTPAddr:                    "12.23.34.45:11371",
			ReconAddr:                   "[2001:db8:85a3::8a2e:370:7334]:11370",
			Filters:                     []string{"something", "else"},
			Partners:                    PartnerMap{},
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
		},
		"",
	}, {
		"invalid toml",
		`nope`,
		nil,
		`.*bare keys cannot contain.*`,
	}, {
		"invalid http net",
		`
[conflux.recon]
httpNet="ansible"
`,
		nil,
		`.*don't know how to resolve network \"ansible\" address.*`,
	}, {
		"invalid http net",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="/dev/null"
`,
		nil,
		`.*missing port in address.*`,
	}, {
		"invalid recon net",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="1.2.3.4:8080"
reconNet="floo"
reconAddr="flarb"
`,
		nil,
		`.*don't know how to resolve network \"floo\" address \"flarb\".*`,
	}, {
		"invalid recon addr",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="1.2.3.4:8080"
reconNet="tcp"
reconAddr=":nope"
`,
		nil,
		`.*unknown port.*`,
	}, {
		"new-style recon partners",
		`
[conflux.recon]
httpAddr=":11371"
reconAddr=":11370"

[conflux.recon.partner.alice]
httpAddr="1.2.3.4:11371"
reconAddr="5.6.7.8:11370"

[conflux.recon.partner.bob]
httpAddr="4.3.2.1:11371"
reconAddr="8.7.6.5:11370"
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     DefaultVersion,
			LogName:                     DefaultLogName,
			HTTPAddr:                    DefaultHTTPAddr,
			ReconAddr:                   DefaultReconAddr,
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
			Partners: map[string]Partner{
				"alice": Partner{
					HTTPAddr:  "1.2.3.4:11371",
					ReconAddr: "5.6.7.8:11370",
				},
				"bob": Partner{
					HTTPAddr:  "4.3.2.1:11371",
					ReconAddr: "8.7.6.5:11370",
				},
			},
		},
		"",
	}, {
		"compat-style config",
		`
[conflux.recon]
httpPort=11371
reconPort=11370
partners=["1.2.3.4:11370","5.6.7.8:11370"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     DefaultVersion,
			LogName:                     DefaultLogName,
			HTTPAddr:                    ":11371",
			ReconAddr:                   ":11370",
			CompatHTTPPort:              11371,
			CompatReconPort:             11370,
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
			Partners: map[string]Partner{
				"1.2.3.4": Partner{
					HTTPAddr:  "1.2.3.4:11371",
					ReconAddr: "1.2.3.4:11370",
				},
				"5.6.7.8": Partner{
					HTTPAddr:  "5.6.7.8:11371",
					ReconAddr: "5.6.7.8:11370",
				},
			},
			CompatPartnerAddrs: []string{"1.2.3.4:11370", "5.6.7.8:11370"},
		},
		"",
	}}
	for i, testCase := range testCases {
		c.Logf("test#%d: %s", i, testCase.desc)
		settings, err := ParseSettings(testCase.toml)
		if err != nil {
			c.Check(err, gc.ErrorMatches, testCase.err)
		} else {
			c.Check(settings, gc.DeepEquals, testCase.settings)
		}
	}
}

func (s *SettingsSuite) TestMatcher(c *gc.C) {
	settings := &Settings{
		AllowCIDRs: []string{"192.168.1.0/24", "10.0.0.0/8", "20.21.22.23/32"},
		Partners: map[string]Partner{
			"foo": Partner{
				HTTPAddr:  "1.2.3.4:11371",
				ReconAddr: "4.3.2.1:11370",
			},
			"bar": Partner{
				HTTPAddr:  "5.6.7.8:11371",
				ReconAddr: "5.6.7.8:11370",
			},
		},
	}

	matcher, err := settings.Matcher()
	c.Assert(err, gc.IsNil)
	testCases := []struct {
		addr   string
		expect bool
	}{
		{"10.0.0.14", true},
		{"10.1.0.14", true},
		{"11.1.0.14", false},

		{"1.2.3.4", true},
		{"1.2.3.5", false},
		{"1.3.3.5", false},
		{"4.3.2.1", true},

		{"5.6.7.8", true},
		{"5.6.7.9", false},
		{"5.7.7.8", false},

		{"20.21.22.23", true},
		{"20.21.22.11", false},

		{"147.26.10.11", false},
		{"2.2.3.4", false},
	}

	for _, tc := range testCases {
		ip := net.ParseIP(tc.addr)
		c.Assert(err, gc.IsNil)
		result := matcher.Match(ip)
		c.Check(result, gc.Equals, tc.expect, gc.Commentf("addr=%q", tc.addr))
	}
}

func (s *SettingsSuite) TestMatchAll(c *gc.C) {
	settings := &Settings{
		AllowCIDRs: []string{"0.0.0.0/0"},
	}
	matcher, err := settings.Matcher()
	c.Assert(err, gc.IsNil)
	testCases := []struct {
		addr   string
		expect bool
	}{
		{"10.0.0.1", true},
		{"192.168.1.14", true},
		{"127.0.0.1", true},
	}

	for _, tc := range testCases {
		ip := net.ParseIP(tc.addr)
		c.Assert(err, gc.IsNil)
		result := matcher.Match(ip)
		c.Check(result, gc.Equals, tc.expect, gc.Commentf("addr=%q", tc.addr))
	}
}
<commit_msg>Fix recon settings test.<commit_after>/*
   conflux - Distributed database synchronization library
	Based on the algorithm described in
		"Set Reconciliation with Nearly Optimal	Communication Complexity",
			Yaron Minsky, Ari Trachtenberg, and Richard Zippel, 2004.

   Copyright (c) 2012-2015  Casey Marshall <cmars@cmarstech.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, version 3.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package recon

import (
	"net"
	"testing"

	gc "gopkg.in/check.v1"
)

func Test(t *testing.T) { gc.TestingT(t) }

type SettingsSuite struct{}

var _ = gc.Suite(&SettingsSuite{})

func (s *SettingsSuite) TestParse(c *gc.C) {
	testCases := []struct {
		desc     string
		toml     string
		settings *Settings
		err      string
	}{{
		"empty string",
		``,
		DefaultSettings(),
		"",
	}, {
		"field setting with some defaults",
		`
[conflux.recon]
version="2.3.4"
logname="blammo"
filters=["something","else"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     "2.3.4",
			LogName:                     "blammo",
			Filters:                     []string{"something", "else"},
			HTTPAddr:                    ":11371",
			ReconAddr:                   ":11370",
			Partners:                    PartnerMap{},
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
		},
		"",
	}, {
		"field setting override some defaults",
		`
[conflux.recon]
version="2.3.4"
logname="blammo"
httpAddr="12.23.34.45:11371"
reconAddr="[2001:db8:85a3::8a2e:370:7334]:11370"
filters=["something","else"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     "2.3.4",
			LogName:                     "blammo",
			HTTPAddr:                    "12.23.34.45:11371",
			ReconAddr:                   "[2001:db8:85a3::8a2e:370:7334]:11370",
			Filters:                     []string{"something", "else"},
			Partners:                    PartnerMap{},
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
		},
		"",
	}, {
		"invalid toml",
		`nope`,
		nil,
		`.*bare keys cannot contain.*`,
	}, {
		"invalid http net",
		`
[conflux.recon]
httpNet="ansible"
`,
		nil,
		`.*don't know how to resolve network \"ansible\" address.*`,
	}, {
		"invalid http net",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="/dev/null"
`,
		nil,
		`.*missing port in address.*`,
	}, {
		"invalid recon net",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="1.2.3.4:8080"
reconNet="floo"
reconAddr="flarb"
`,
		nil,
		`.*don't know how to resolve network \"floo\" address \"flarb\".*`,
	}, {
		"invalid recon addr",
		`
[conflux.recon]
httpNet="tcp"
httpAddr="1.2.3.4:8080"
reconNet="tcp"
reconAddr=":-1"
`,
		nil,
		`.*invalid port.*`,
	}, {
		"new-style recon partners",
		`
[conflux.recon]
httpAddr=":11371"
reconAddr=":11370"

[conflux.recon.partner.alice]
httpAddr="1.2.3.4:11371"
reconAddr="5.6.7.8:11370"

[conflux.recon.partner.bob]
httpAddr="4.3.2.1:11371"
reconAddr="8.7.6.5:11370"
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     DefaultVersion,
			LogName:                     DefaultLogName,
			HTTPAddr:                    DefaultHTTPAddr,
			ReconAddr:                   DefaultReconAddr,
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
			Partners: map[string]Partner{
				"alice": Partner{
					HTTPAddr:  "1.2.3.4:11371",
					ReconAddr: "5.6.7.8:11370",
				},
				"bob": Partner{
					HTTPAddr:  "4.3.2.1:11371",
					ReconAddr: "8.7.6.5:11370",
				},
			},
		},
		"",
	}, {
		"compat-style config",
		`
[conflux.recon]
httpPort=11371
reconPort=11370
partners=["1.2.3.4:11370","5.6.7.8:11370"]
`,
		&Settings{
			PTreeConfig:                 defaultPTreeConfig,
			Version:                     DefaultVersion,
			LogName:                     DefaultLogName,
			HTTPAddr:                    ":11371",
			ReconAddr:                   ":11370",
			CompatHTTPPort:              11371,
			CompatReconPort:             11370,
			GossipIntervalSecs:          DefaultGossipIntervalSecs,
			MaxOutstandingReconRequests: DefaultMaxOutstandingReconRequests,
			Partners: map[string]Partner{
				"1.2.3.4": Partner{
					HTTPAddr:  "1.2.3.4:11371",
					ReconAddr: "1.2.3.4:11370",
				},
				"5.6.7.8": Partner{
					HTTPAddr:  "5.6.7.8:11371",
					ReconAddr: "5.6.7.8:11370",
				},
			},
			CompatPartnerAddrs: []string{"1.2.3.4:11370", "5.6.7.8:11370"},
		},
		"",
	}}
	for i, testCase := range testCases {
		c.Logf("test#%d: %s", i, testCase.desc)
		settings, err := ParseSettings(testCase.toml)
		if err != nil {
			c.Check(err, gc.ErrorMatches, testCase.err)
		} else {
			c.Check(settings, gc.DeepEquals, testCase.settings)
		}
	}
}

func (s *SettingsSuite) TestMatcher(c *gc.C) {
	settings := &Settings{
		AllowCIDRs: []string{"192.168.1.0/24", "10.0.0.0/8", "20.21.22.23/32"},
		Partners: map[string]Partner{
			"foo": Partner{
				HTTPAddr:  "1.2.3.4:11371",
				ReconAddr: "4.3.2.1:11370",
			},
			"bar": Partner{
				HTTPAddr:  "5.6.7.8:11371",
				ReconAddr: "5.6.7.8:11370",
			},
		},
	}

	matcher, err := settings.Matcher()
	c.Assert(err, gc.IsNil)
	testCases := []struct {
		addr   string
		expect bool
	}{
		{"10.0.0.14", true},
		{"10.1.0.14", true},
		{"11.1.0.14", false},

		{"1.2.3.4", true},
		{"1.2.3.5", false},
		{"1.3.3.5", false},
		{"4.3.2.1", true},

		{"5.6.7.8", true},
		{"5.6.7.9", false},
		{"5.7.7.8", false},

		{"20.21.22.23", true},
		{"20.21.22.11", false},

		{"147.26.10.11", false},
		{"2.2.3.4", false},
	}

	for _, tc := range testCases {
		ip := net.ParseIP(tc.addr)
		c.Assert(err, gc.IsNil)
		result := matcher.Match(ip)
		c.Check(result, gc.Equals, tc.expect, gc.Commentf("addr=%q", tc.addr))
	}
}

func (s *SettingsSuite) TestMatchAll(c *gc.C) {
	settings := &Settings{
		AllowCIDRs: []string{"0.0.0.0/0"},
	}
	matcher, err := settings.Matcher()
	c.Assert(err, gc.IsNil)
	testCases := []struct {
		addr   string
		expect bool
	}{
		{"10.0.0.1", true},
		{"192.168.1.14", true},
		{"127.0.0.1", true},
	}

	for _, tc := range testCases {
		ip := net.ParseIP(tc.addr)
		c.Assert(err, gc.IsNil)
		result := matcher.Match(ip)
		c.Check(result, gc.Equals, tc.expect, gc.Commentf("addr=%q", tc.addr))
	}
}
<|endoftext|>