<commit_before>// Copyright 2020-2022 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package export

import (
	"context"
	"errors"
	"os"

	"github.com/bufbuild/buf/private/buf/bufcli"
	"github.com/bufbuild/buf/private/buf/buffetch"
	"github.com/bufbuild/buf/private/bufpkg/bufanalysis"
	"github.com/bufbuild/buf/private/bufpkg/bufimage"
	"github.com/bufbuild/buf/private/bufpkg/bufimage/bufimagebuild"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmodulebuild"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref"
	"github.com/bufbuild/buf/private/pkg/app/appcmd"
	"github.com/bufbuild/buf/private/pkg/app/appflag"
	"github.com/bufbuild/buf/private/pkg/command"
	"github.com/bufbuild/buf/private/pkg/storage"
	"github.com/bufbuild/buf/private/pkg/storage/storageos"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"go.uber.org/multierr"
)

const (
	excludeImportsFlagName  = "exclude-imports"
	pathsFlagName           = "path"
	outputFlagName          = "output"
	outputFlagShortName     = "o"
	configFlagName          = "config"
	excludePathsFlagName    = "exclude-path"
	disableSymlinksFlagName = "disable-symlinks"
)

// NewCommand returns a new Command.
func NewCommand(
	name string,
	builder appflag.Builder,
) *appcmd.Command {
	flags := newFlags()
	return &appcmd.Command{
		Use:   name + " <input>",
		Short: "Export the files from the input location to an output location.",
		Long:  bufcli.GetInputLong(`the source or module to export`),
		Args:  cobra.MaximumNArgs(1),
		Run: builder.NewRunFunc(
			func(ctx context.Context, container appflag.Container) error {
				return run(ctx, container, flags)
			},
			bufcli.NewErrorInterceptor(),
		),
		BindFlags: flags.Bind,
	}
}

type flags struct {
	ExcludeImports  bool
	Paths           []string
	Output          string
	Config          string
	ExcludePaths    []string
	DisableSymlinks bool

	// special
	InputHashtag string
}

func newFlags() *flags {
	return &flags{}
}

func (f *flags) Bind(flagSet *pflag.FlagSet) {
	bufcli.BindDisableSymlinks(flagSet, &f.DisableSymlinks, disableSymlinksFlagName)
	bufcli.BindInputHashtag(flagSet, &f.InputHashtag)
	bufcli.BindExcludeImports(flagSet, &f.ExcludeImports, excludeImportsFlagName)
	bufcli.BindPaths(flagSet, &f.Paths, pathsFlagName)
	bufcli.BindExcludePaths(flagSet, &f.ExcludePaths, excludePathsFlagName)
	flagSet.StringVarP(
		&f.Output,
		outputFlagName,
		outputFlagShortName,
		"",
		`The output directory for exported files.`,
	)
	_ = cobra.MarkFlagRequired(flagSet, outputFlagName)
	flagSet.StringVar(
		&f.Config,
		configFlagName,
		"",
		`The file or data to use for configuration.`,
	)
}

func run(
	ctx context.Context,
	container appflag.Container,
	flags *flags,
) error {
	input, err := bufcli.GetInputValue(container, flags.InputHashtag, ".")
	if err != nil {
		return err
	}
	sourceOrModuleRef, err := buffetch.NewRefParser(container.Logger(), buffetch.RefParserWithProtoFileRefAllowed()).GetSourceOrModuleRef(ctx, input)
	if err != nil {
		return err
	}
	storageosProvider := bufcli.NewStorageosProvider(flags.DisableSymlinks)
	runner := command.NewRunner()
	clientConfig, err := bufcli.NewConnectClientConfig(container)
	if err != nil {
		return err
	}
	moduleReader, err := bufcli.NewModuleReaderAndCreateCacheDirs(container, clientConfig)
	if err != nil {
		return err
	}
	moduleConfigReader, err := bufcli.NewWireModuleConfigReaderForModuleReader(
		container,
		storageosProvider,
		runner,
		clientConfig,
		moduleReader,
	)
	if err != nil {
		return err
	}
	moduleConfigs, err := moduleConfigReader.GetModuleConfigs(
		ctx,
		container,
		sourceOrModuleRef,
		flags.Config,
		flags.Paths,
		flags.ExcludePaths,
		false,
	)
	if err != nil {
		return err
	}
	moduleFileSetBuilder := bufmodulebuild.NewModuleFileSetBuilder(
		container.Logger(),
		moduleReader,
	)
	moduleFileSets := make([]bufmodule.ModuleFileSet, len(moduleConfigs))
	for i, moduleConfig := range moduleConfigs {
		moduleFileSet, err := moduleFileSetBuilder.Build(
			ctx,
			moduleConfig.Module(),
			bufmodulebuild.WithWorkspace(moduleConfig.Workspace()),
		)
		if err != nil {
			return err
		}
		moduleFileSets[i] = moduleFileSet
	}
	// There are two cases where we need an image to filter the output:
	//   1) the input is a proto file reference
	//   2) ensuring that we are including the relevant imports
	//
	// In the first scenario, the imageConfigReader returns imageCongfigs that handle the filtering
	// for the proto file ref.
	//
	// To handle imports for all other references, unless we are excluding imports, we only want
	// to export those imports that are actually used. To figure this out, we build an image of images
	// and use the fact that something is in an image to determine if it is actually used.
	var images []bufimage.Image
	_, isProtoFileRef := sourceOrModuleRef.(buffetch.ProtoFileRef)
	// We gate on flags.ExcludeImports/buffetch.ProtoFileRef so that we don't waste time building if the
	// result of the build is not relevant.
	if !flags.ExcludeImports {
		imageBuilder := bufimagebuild.NewBuilder(container.Logger())
		for _, moduleFileSet := range moduleFileSets {
			targetFileInfos, err := moduleFileSet.TargetFileInfos(ctx)
			if err != nil {
				return err
			}
			if len(targetFileInfos) == 0 {
				// This ModuleFileSet doesn't have any targets, so we shouldn't build
				// an image for it.
				continue
			}
			image, fileAnnotations, err := imageBuilder.Build(
				ctx,
				moduleFileSet,
				bufimagebuild.WithExcludeSourceCodeInfo(),
			)
			if err != nil {
				return err
			}
			if len(fileAnnotations) > 0 {
				// stderr since we do output to stdout potentially
				if err := bufanalysis.PrintFileAnnotations(
					container.Stderr(),
					fileAnnotations,
					bufanalysis.FormatText.String(),
				); err != nil {
					return err
				}
				return bufcli.ErrFileAnnotation
			}
			images = append(images, image)
		}
	} else if isProtoFileRef {
		// If the reference is a ProtoFileRef, we need to resolve the image for the reference,
		// since the image config reader distills down the reference to the file and its dependencies,
		// and also handles the #include_package_files option.
		imageConfigReader, err := bufcli.NewWireImageConfigReader(
			container,
			storageosProvider,
			runner,
			clientConfig,
		)
		if err != nil {
			return err
		}
		imageConfigs, fileAnnotations, err := imageConfigReader.GetImageConfigs(
			ctx,
			container,
			sourceOrModuleRef,
			flags.Config,
			flags.Paths,
			flags.ExcludePaths,
			false,
			true, // SourceCodeInfo is not needed here for outputting the source code
		)
		if err != nil {
			return err
		}
		if len(fileAnnotations) > 0 {
			if err := bufanalysis.PrintFileAnnotations(
				container.Stderr(),
				fileAnnotations,
				bufanalysis.FormatText.String(),
			); err != nil {
				return err
			}
		}
		for _, imageConfig := range imageConfigs {
			images = append(images, imageConfig.Image())
		}
	}
	// images will only be non-empty if !flags.ExcludeImports || isProtoFileRef
	// mergedImage will be nil if images is empty
	// therefore, we must gate on mergedImage != nil below
	mergedImage, err := bufimage.MergeImages(images...)
	if err != nil {
		return err
	}
	if err := os.MkdirAll(flags.Output, 0755); err != nil {
		return err
	}
	readWriteBucket, err := storageosProvider.NewReadWriteBucket(
		flags.Output,
		storageos.ReadWriteBucketWithSymlinksIfSupported(),
	)
	if err != nil {
		return err
	}
	fileInfosFunc := bufmodule.ModuleFileSet.AllFileInfos
	// If we filtered on some paths, only use the targets.
	// Otherwise, we want to print everything, including potentially imports.
	// We can have duplicates across the ModuleFileSets and that's OK - they will
	// only be written once via writtenPaths, and we aren't building here.
	if len(flags.Paths) > 0 {
		fileInfosFunc = func(
			moduleFileSet bufmodule.ModuleFileSet,
			ctx context.Context,
		) ([]bufmoduleref.FileInfo, error) {
			return moduleFileSet.TargetFileInfos(ctx)
		}
	}
	writtenPaths := make(map[string]struct{})
	for _, moduleFileSet := range moduleFileSets {
		// If the reference was a proto file reference, we will use the image files as the basis
		// for outputting source files.
		// We do an extra mergedImage != nil check even though this must be true
		if isProtoFileRef && mergedImage != nil {
			for _, protoFileRefImageFile := range mergedImage.Files() {
				path := protoFileRefImageFile.Path()
				if _, ok := writtenPaths[path]; ok {
					continue
				}
				if flags.ExcludeImports && protoFileRefImageFile.IsImport() {
					continue
				}
				moduleFile, err := moduleFileSet.GetModuleFile(ctx, path)
				if err != nil {
					return err
				}
				if err := storage.CopyReadObject(ctx, readWriteBucket, moduleFile); err != nil {
					return multierr.Append(err, moduleFile.Close())
				}
				if err := moduleFile.Close(); err != nil {
					return err
				}
				writtenPaths[path] = struct{}{}
			}
			if len(writtenPaths) == 0 {
				return errors.New("no .proto target files found")
			}
			return nil
		}
		fileInfos, err := fileInfosFunc(moduleFileSet, ctx)
		if err != nil {
			return err
		}
		for _, fileInfo := range fileInfos {
			path := fileInfo.Path()
			if _, ok := writtenPaths[path]; ok {
				continue
			}
			// If the file is not an import in some ModuleFileSet, it will
			// eventually be written via the iteration over moduleFileSets.
			if fileInfo.IsImport() {
				if flags.ExcludeImports {
					// Exclude imports, don't output here
					continue
				} else if mergedImage == nil || mergedImage.GetFile(path) == nil {
					// We check the merged image to see if the path exists. If it does,
					// we use this import, so we want to output the file. If it doesn't,
					// continue.
					continue
				}
			}
			moduleFile, err := moduleFileSet.GetModuleFile(ctx, path)
			if err != nil {
				return err
			}
			if err := storage.CopyReadObject(ctx, readWriteBucket, moduleFile); err != nil {
				return multierr.Append(err, moduleFile.Close())
			}
			if err := moduleFile.Close(); err != nil {
				return err
			}
			writtenPaths[path] = struct{}{}
		}
	}
	if len(writtenPaths) == 0 {
		return errors.New("no .proto target files found")
	}
	return nil
}
<commit_msg>Add more export description (#1577)<commit_after>// Copyright 2020-2022 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package export

import (
	"context"
	"errors"
	"os"

	"github.com/bufbuild/buf/private/buf/bufcli"
	"github.com/bufbuild/buf/private/buf/buffetch"
	"github.com/bufbuild/buf/private/bufpkg/bufanalysis"
	"github.com/bufbuild/buf/private/bufpkg/bufimage"
	"github.com/bufbuild/buf/private/bufpkg/bufimage/bufimagebuild"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmodulebuild"
	"github.com/bufbuild/buf/private/bufpkg/bufmodule/bufmoduleref"
	"github.com/bufbuild/buf/private/pkg/app/appcmd"
	"github.com/bufbuild/buf/private/pkg/app/appflag"
	"github.com/bufbuild/buf/private/pkg/command"
	"github.com/bufbuild/buf/private/pkg/storage"
	"github.com/bufbuild/buf/private/pkg/storage/storageos"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	"go.uber.org/multierr"
)

const (
	excludeImportsFlagName  = "exclude-imports"
	pathsFlagName           = "path"
	outputFlagName          = "output"
	outputFlagShortName     = "o"
	configFlagName          = "config"
	excludePathsFlagName    = "exclude-path"
	disableSymlinksFlagName = "disable-symlinks"
)

// NewCommand returns a new Command.
func NewCommand(
	name string,
	builder appflag.Builder,
) *appcmd.Command {
	flags := newFlags()
	return &appcmd.Command{
		Use:   name + " <input>",
		Short: "Export the files from the input location to an output location.",
		Long: bufcli.GetInputLong(`the source or module to export`) + `

Examples:

$ buf export <input> --output=<output-dir>

input can be of the format [dir,git,mod,protofile,tar,targz,zip].

output will be a directory with all of the .proto files in the <input>.

# Export current directory to another local directory.
$ buf export . --output=<output-dir>

# Export the latest remote module to a local directory.
$ buf export buf.build/<owner>/<repo> --output=<output-dir>

# Export a specific version of a remote module to a local directory.
$ buf export buf.build/<owner>/<repo>:<version> --output=<output-dir>

# Export a git repo to a local directory.
$ buf export https://<git-server>/<owner>/<repo>.git --output=<output-dir>

`,
		Args: cobra.MaximumNArgs(1),
		Run: builder.NewRunFunc(
			func(ctx context.Context, container appflag.Container) error {
				return run(ctx, container, flags)
			},
			bufcli.NewErrorInterceptor(),
		),
		BindFlags: flags.Bind,
	}
}

type flags struct {
	ExcludeImports  bool
	Paths           []string
	Output          string
	Config          string
	ExcludePaths    []string
	DisableSymlinks bool

	// special
	InputHashtag string
}

func newFlags() *flags {
	return &flags{}
}

func (f *flags) Bind(flagSet *pflag.FlagSet) {
	bufcli.BindDisableSymlinks(flagSet, &f.DisableSymlinks, disableSymlinksFlagName)
	bufcli.BindInputHashtag(flagSet, &f.InputHashtag)
	bufcli.BindExcludeImports(flagSet, &f.ExcludeImports, excludeImportsFlagName)
	bufcli.BindPaths(flagSet, &f.Paths, pathsFlagName)
	bufcli.BindExcludePaths(flagSet, &f.ExcludePaths, excludePathsFlagName)
	flagSet.StringVarP(
		&f.Output,
		outputFlagName,
		outputFlagShortName,
		"",
		`The output directory for exported files.`,
	)
	_ = cobra.MarkFlagRequired(flagSet, outputFlagName)
	flagSet.StringVar(
		&f.Config,
		configFlagName,
		"",
		`The file or data to use for configuration.`,
	)
}

func run(
	ctx context.Context,
	container appflag.Container,
	flags *flags,
) error {
	input, err := bufcli.GetInputValue(container, flags.InputHashtag, ".")
	if err != nil {
		return err
	}
	sourceOrModuleRef, err := buffetch.NewRefParser(container.Logger(), buffetch.RefParserWithProtoFileRefAllowed()).GetSourceOrModuleRef(ctx, input)
	if err != nil {
		return err
	}
	storageosProvider := bufcli.NewStorageosProvider(flags.DisableSymlinks)
	runner := command.NewRunner()
	clientConfig, err := bufcli.NewConnectClientConfig(container)
	if err != nil {
		return err
	}
	moduleReader, err := bufcli.NewModuleReaderAndCreateCacheDirs(container, clientConfig)
	if err != nil {
		return err
	}
	moduleConfigReader, err := bufcli.NewWireModuleConfigReaderForModuleReader(
		container,
		storageosProvider,
		runner,
		clientConfig,
		moduleReader,
	)
	if err != nil {
		return err
	}
	moduleConfigs, err := moduleConfigReader.GetModuleConfigs(
		ctx,
		container,
		sourceOrModuleRef,
		flags.Config,
		flags.Paths,
		flags.ExcludePaths,
		false,
	)
	if err != nil {
		return err
	}
	moduleFileSetBuilder := bufmodulebuild.NewModuleFileSetBuilder(
		container.Logger(),
		moduleReader,
	)
	moduleFileSets := make([]bufmodule.ModuleFileSet, len(moduleConfigs))
	for i, moduleConfig := range moduleConfigs {
		moduleFileSet, err := moduleFileSetBuilder.Build(
			ctx,
			moduleConfig.Module(),
			bufmodulebuild.WithWorkspace(moduleConfig.Workspace()),
		)
		if err != nil {
			return err
		}
		moduleFileSets[i] = moduleFileSet
	}
	// There are two cases where we need an image to filter the output:
	//   1) the input is a proto file reference
	//   2) ensuring that we are including the relevant imports
	//
	// In the first scenario, the imageConfigReader returns imageCongfigs that handle the filtering
	// for the proto file ref.
	//
	// To handle imports for all other references, unless we are excluding imports, we only want
	// to export those imports that are actually used. To figure this out, we build an image of images
	// and use the fact that something is in an image to determine if it is actually used.
	var images []bufimage.Image
	_, isProtoFileRef := sourceOrModuleRef.(buffetch.ProtoFileRef)
	// We gate on flags.ExcludeImports/buffetch.ProtoFileRef so that we don't waste time building if the
	// result of the build is not relevant.
	if !flags.ExcludeImports {
		imageBuilder := bufimagebuild.NewBuilder(container.Logger())
		for _, moduleFileSet := range moduleFileSets {
			targetFileInfos, err := moduleFileSet.TargetFileInfos(ctx)
			if err != nil {
				return err
			}
			if len(targetFileInfos) == 0 {
				// This ModuleFileSet doesn't have any targets, so we shouldn't build
				// an image for it.
				continue
			}
			image, fileAnnotations, err := imageBuilder.Build(
				ctx,
				moduleFileSet,
				bufimagebuild.WithExcludeSourceCodeInfo(),
			)
			if err != nil {
				return err
			}
			if len(fileAnnotations) > 0 {
				// stderr since we do output to stdout potentially
				if err := bufanalysis.PrintFileAnnotations(
					container.Stderr(),
					fileAnnotations,
					bufanalysis.FormatText.String(),
				); err != nil {
					return err
				}
				return bufcli.ErrFileAnnotation
			}
			images = append(images, image)
		}
	} else if isProtoFileRef {
		// If the reference is a ProtoFileRef, we need to resolve the image for the reference,
		// since the image config reader distills down the reference to the file and its dependencies,
		// and also handles the #include_package_files option.
		imageConfigReader, err := bufcli.NewWireImageConfigReader(
			container,
			storageosProvider,
			runner,
			clientConfig,
		)
		if err != nil {
			return err
		}
		imageConfigs, fileAnnotations, err := imageConfigReader.GetImageConfigs(
			ctx,
			container,
			sourceOrModuleRef,
			flags.Config,
			flags.Paths,
			flags.ExcludePaths,
			false,
			true, // SourceCodeInfo is not needed here for outputting the source code
		)
		if err != nil {
			return err
		}
		if len(fileAnnotations) > 0 {
			if err := bufanalysis.PrintFileAnnotations(
				container.Stderr(),
				fileAnnotations,
				bufanalysis.FormatText.String(),
			); err != nil {
				return err
			}
		}
		for _, imageConfig := range imageConfigs {
			images = append(images, imageConfig.Image())
		}
	}
	// images will only be non-empty if !flags.ExcludeImports || isProtoFileRef
	// mergedImage will be nil if images is empty
	// therefore, we must gate on mergedImage != nil below
	mergedImage, err := bufimage.MergeImages(images...)
	if err != nil {
		return err
	}
	if err := os.MkdirAll(flags.Output, 0755); err != nil {
		return err
	}
	readWriteBucket, err := storageosProvider.NewReadWriteBucket(
		flags.Output,
		storageos.ReadWriteBucketWithSymlinksIfSupported(),
	)
	if err != nil {
		return err
	}
	fileInfosFunc := bufmodule.ModuleFileSet.AllFileInfos
	// If we filtered on some paths, only use the targets.
	// Otherwise, we want to print everything, including potentially imports.
	// We can have duplicates across the ModuleFileSets and that's OK - they will
	// only be written once via writtenPaths, and we aren't building here.
	if len(flags.Paths) > 0 {
		fileInfosFunc = func(
			moduleFileSet bufmodule.ModuleFileSet,
			ctx context.Context,
		) ([]bufmoduleref.FileInfo, error) {
			return moduleFileSet.TargetFileInfos(ctx)
		}
	}
	writtenPaths := make(map[string]struct{})
	for _, moduleFileSet := range moduleFileSets {
		// If the reference was a proto file reference, we will use the image files as the basis
		// for outputting source files.
		// We do an extra mergedImage != nil check even though this must be true
		if isProtoFileRef && mergedImage != nil {
			for _, protoFileRefImageFile := range mergedImage.Files() {
				path := protoFileRefImageFile.Path()
				if _, ok := writtenPaths[path]; ok {
					continue
				}
				if flags.ExcludeImports && protoFileRefImageFile.IsImport() {
					continue
				}
				moduleFile, err := moduleFileSet.GetModuleFile(ctx, path)
				if err != nil {
					return err
				}
				if err := storage.CopyReadObject(ctx, readWriteBucket, moduleFile); err != nil {
					return multierr.Append(err, moduleFile.Close())
				}
				if err := moduleFile.Close(); err != nil {
					return err
				}
				writtenPaths[path] = struct{}{}
			}
			if len(writtenPaths) == 0 {
				return errors.New("no .proto target files found")
			}
			return nil
		}
		fileInfos, err := fileInfosFunc(moduleFileSet, ctx)
		if err != nil {
			return err
		}
		for _, fileInfo := range fileInfos {
			path := fileInfo.Path()
			if _, ok := writtenPaths[path]; ok {
				continue
			}
			// If the file is not an import in some ModuleFileSet, it will
			// eventually be written via the iteration over moduleFileSets.
			if fileInfo.IsImport() {
				if flags.ExcludeImports {
					// Exclude imports, don't output here
					continue
				} else if mergedImage == nil || mergedImage.GetFile(path) == nil {
					// We check the merged image to see if the path exists. If it does,
					// we use this import, so we want to output the file. If it doesn't,
					// continue.
					continue
				}
			}
			moduleFile, err := moduleFileSet.GetModuleFile(ctx, path)
			if err != nil {
				return err
			}
			if err := storage.CopyReadObject(ctx, readWriteBucket, moduleFile); err != nil {
				return multierr.Append(err, moduleFile.Close())
			}
			if err := moduleFile.Close(); err != nil {
				return err
			}
			writtenPaths[path] = struct{}{}
		}
	}
	if len(writtenPaths) == 0 {
		return errors.New("no .proto target files found")
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	_ "net/http/pprof"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/tsaikd/KDGoLib/env"

	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/version"
)

var (
	FlDebug = flag.Bool(
		[]string{"-DEBUG"},
		env.GetBool("DEBUG", false),
		"Show DEBUG messages",
	)
	FlConfig = flag.String(
		[]string{"-CONFIG"},
		env.GetString("Config", "config.json"),
		"Path to configuration file",
	)
	FlVersion = flag.Bool(
		[]string{"V", "-VERSION"},
		false,
		"Show version information",
	)
	FlProfile = flag.String(
		[]string{"-PROFILE"},
		env.GetString("PROFILE", ""),
		"Listen http profiling interface, e.g. localhost:6060",
	)
)

func main() {
	flag.Parse()
	mainBody()
}

func mainBody() {
	var (
		conf      config.Config
		err       error
		eventChan = make(chan config.LogEvent, 100)
	)

	if *FlDebug {
		log.SetLevel(log.DebugLevel)
	}

	if *FlVersion {
		version.ShowVersion(os.Stdout)
		return
	}

	if conf, err = config.LoadConfig(*FlConfig); err != nil {
		log.Errorf("Load config failed: %q", *FlConfig)
		return
	}

	if *FlProfile != "" {
		go func() {
			log.Infof("Profile listen http: %q", *FlProfile)
			if err := http.ListenAndServe(*FlProfile, nil); err != nil {
				log.Errorf("Profile listen http failed: %q\n%v", *FlProfile, err)
			}
		}()
	}

	for _, input := range conf.Input() {
		log.Debugf("Init input %q", input.Type())
		if err = input.Event(eventChan); err != nil {
			log.Errorf("input failed: %v", err)
		}
	}

	go func() {
		outputs := conf.Output()
		for {
			select {
			case event := <-eventChan:
				for _, output := range outputs {
					if err = output.Event(event); err != nil {
						log.Errorf("output failed: %v", err)
					}
				}
			}
		}
	}()

	for {
		// infinite sleep
		time.Sleep(1 * time.Hour)
	}
}
<commit_msg>warning if GOMAXPROCS == 1 in multicore CPU<commit_after>package main

import (
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime"
	"time"

	log "github.com/Sirupsen/logrus"
	flag "github.com/docker/docker/pkg/mflag"
	"github.com/tsaikd/KDGoLib/env"

	"github.com/tsaikd/gogstash/config"
	"github.com/tsaikd/gogstash/version"
)

var (
	FlDebug = flag.Bool(
		[]string{"-DEBUG"},
		env.GetBool("DEBUG", false),
		"Show DEBUG messages",
	)
	FlConfig = flag.String(
		[]string{"-CONFIG"},
		env.GetString("Config", "config.json"),
		"Path to configuration file",
	)
	FlVersion = flag.Bool(
		[]string{"V", "-VERSION"},
		false,
		"Show version information",
	)
	FlProfile = flag.String(
		[]string{"-PROFILE"},
		env.GetString("PROFILE", ""),
		"Listen http profiling interface, e.g. localhost:6060",
	)
)

func main() {
	flag.Parse()
	mainBody()
}

func mainBody() {
	var (
		conf      config.Config
		err       error
		eventChan = make(chan config.LogEvent, 100)
	)

	if *FlDebug {
		log.SetLevel(log.DebugLevel)
	}

	if *FlVersion {
		version.ShowVersion(os.Stdout)
		return
	}

	if runtime.GOMAXPROCS(0) == 1 && runtime.NumCPU() > 1 {
		log.Warnf("set GOMAXPROCS = %d to get better performance", runtime.NumCPU())
	}

	if conf, err = config.LoadConfig(*FlConfig); err != nil {
		log.Errorf("Load config failed: %q", *FlConfig)
		return
	}

	if *FlProfile != "" {
		go func() {
			log.Infof("Profile listen http: %q", *FlProfile)
			if err := http.ListenAndServe(*FlProfile, nil); err != nil {
				log.Errorf("Profile listen http failed: %q\n%v", *FlProfile, err)
			}
		}()
	}

	for _, input := range conf.Input() {
		log.Debugf("Init input %q", input.Type())
		if err = input.Event(eventChan); err != nil {
			log.Errorf("input failed: %v", err)
		}
	}

	go func() {
		outputs := conf.Output()
		for {
			select {
			case event := <-eventChan:
				for _, output := range outputs {
					if err = output.Event(event); err != nil {
						log.Errorf("output failed: %v", err)
					}
				}
			}
		}
	}()

	for {
		// infinite sleep
		time.Sleep(1 * time.Hour)
	}
}
<|endoftext|>


<commit_before>package gopnsapp

import (
	"github.com/emicklei/go-restful"
	"github.com/gopns/gopns/aws/dynamodb"
	"github.com/gopns/gopns/aws/sns"
	"github.com/gopns/gopns/aws/sqs"
	"github.com/gopns/gopns/device"
	config "github.com/gopns/gopns/gopnsconfig"
	"github.com/gopns/gopns/metrics"
	"github.com/gopns/gopns/notification"
	"github.com/gopns/gopns/rest"
	"github.com/stefantalpalaru/pool"
	"log"
	"net/http"
	"runtime"
	"time"
)

type GopnsApp interface {
	Start() error
}

type GopnsApplication struct {
	DynamoClient         dynamodb.DynamoClient
	SQSClient            sqs.SQSClient
	SNSClient            sns.SNSClient
	WorkerPool           pool.Pool
	NotificationSender   notification.NotificationSender
	NotificationConsumer notification.NotificationConsumer
	AppMode              config.APPLICATION_MODE
	BaseConfig           config.BaseConfig
	AWSConfig            config.AWSConfig
	DeviceManager        device.DeviceManager
	WsContainer          restful.Container
}

func New() (GopnsApp, error) {

	gopnasapp_ := &GopnsApplication{}

	gopnasapp_.AppMode, gopnasapp_.BaseConfig, gopnasapp_.AWSConfig = config.ParseConfig()

	err := gopnasapp_.setupDynamoDB()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.setupSQS()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.setupSNS()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.createWorkerPool()
	if err != nil {
		return nil, err
	}

	//setup notification sender
	gopnasapp_.NotificationSender = notification.NotificationSender{
		SnsClient:    gopnasapp_.SNSClient,
		WorkerPool:   &gopnasapp_.WorkerPool,
		PlatformApps: gopnasapp_.AWSConfig.PlatformAppsMap()}

	//create a notification consumer
	gopnasapp_.NotificationConsumer = notification.NewSQSNotifictionConsumer(
		gopnasapp_.AWSConfig.SqsQueueUrl(),
		gopnasapp_.SQSClient,
		&gopnasapp_.NotificationSender)

	//create a device manager
	gopnasapp_.DeviceManager = device.New(
		gopnasapp_.SNSClient,
		gopnasapp_.DynamoClient,
		gopnasapp_.AWSConfig.DynamoTable(),
		gopnasapp_.AWSConfig.PlatformAppsMap())

	//

	gopnasapp_.setupMetrics()

	return gopnasapp_, nil
}

// ToDo return appropriate errors
func (this *GopnsApplication) Start() error {

	err := this.runWorkerPool()
	if err != nil {
		return err
	}

	err = this.NotificationConsumer.Start()
	if err != nil {
		return err
	}

	if this.AppMode == config.SERVER_MODE {
		this.setupRestServices()
	} else if this.AppMode == config.REGISTER_MODE {

	} else if this.AppMode == config.SEND_MODE {

	}

	return nil
}

func (this *GopnsApplication) setupDynamoDB() error {
	var err error
	this.DynamoClient, err = dynamodb.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if err != nil {
		return err
	}

	if found, err := this.DynamoClient.FindTable(this.AWSConfig.DynamoTable()); err != nil {
		return err
	} else if found {
		return nil
	} else {

		createTableRequest := dynamodb.CreateTableRequest{
			[]dynamodb.AttributeDefinition{dynamodb.AttributeDefinition{"alias", "S"}},
			this.AWSConfig.DynamoTable(),
			[]dynamodb.KeySchema{dynamodb.KeySchema{"alias", "HASH"}},
			dynamodb.ProvisionedThroughput{
				this.AWSConfig.InitialReadCapacity(),
				this.AWSConfig.InitialWriteCapacity()}}
		return this.DynamoClient.CreateTable(createTableRequest)
	}

	return err
}

func (this *GopnsApplication) setupSQS() error {
	var err error
	this.SQSClient = sqs.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if sqsQueue, err := this.SQSClient.CreateQueue(this.AWSConfig.SqsQueueName()); err != nil {
		log.Fatalf("Unable to initilize SQS %s", err.Error())
	} else {
		log.Printf("Using SQS Queue %s", sqsQueue.QueueUrl)
		this.AWSConfig.SetSqsQueueUrl(sqsQueue.QueueUrl)
	}

	return err
}

func (this *GopnsApplication) setupSNS() error {
	var err error
	this.SNSClient, err = sns.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if err != nil {
		return err
	} else {
		return nil
	}
}

func (this *GopnsApplication) setupMetrics() error {

	metrics.StartGraphiteReporter(
		this.BaseConfig.MetricsServer(),
		this.BaseConfig.MetricsAPIKey(),
		this.BaseConfig.MetricsPrefix())

	return nil
}

func (this *GopnsApplication) createWorkerPool() error {
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	this.WorkerPool = *pool.New(cpus)
	log.Println("Worker pool created with", cpus, "workers")
	return nil
}

func (this *GopnsApplication) runWorkerPool() error {
	this.WorkerPool.Run()
	log.Println("Worker pool started")
	ticker := time.NewTicker(time.Second * 60)
	go func() {
		for _ = range ticker.C {
			status := this.WorkerPool.Status()
			log.Println(status.Submitted, "submitted jobs,", status.Running, "running,", status.Completed, "completed.")
		}
	}()

	return nil
}

func (this *GopnsApplication) setupRestServices() {

	//setup a new services container for gopns rest services
	this.WsContainer = *restful.NewContainer()
	//ToDo read the gopns rest root path from config (re: embeddable app)
	rootPath := "/rest" //without the last slash

	notificationService := new(rest.NotificationService)
	notificationService.NotificationSender = &this.NotificationSender
	notificationService.DeviceManager = this.DeviceManager
	// register notification service with our services container
	notificationService.Register(&this.WsContainer, rootPath)

	//deviceService := new(rest.DeviceService)
	//deviceService.DeviceManager = this.DeviceManager

	http.ListenAndServe(":"+this.BaseConfig.Port(), nil)
}
<commit_msg>hook up restful container<commit_after>package gopnsapp

import (
	"github.com/emicklei/go-restful"
	"github.com/gopns/gopns/aws/dynamodb"
	"github.com/gopns/gopns/aws/sns"
	"github.com/gopns/gopns/aws/sqs"
	"github.com/gopns/gopns/device"
	config "github.com/gopns/gopns/gopnsconfig"
	"github.com/gopns/gopns/metrics"
	"github.com/gopns/gopns/notification"
	"github.com/gopns/gopns/rest"
	"github.com/stefantalpalaru/pool"
	"log"
	"net/http"
	"runtime"
	"time"
)

type GopnsApp interface {
	Start() error
}

type GopnsApplication struct {
	DynamoClient         dynamodb.DynamoClient
	SQSClient            sqs.SQSClient
	SNSClient            sns.SNSClient
	WorkerPool           pool.Pool
	NotificationSender   notification.NotificationSender
	NotificationConsumer notification.NotificationConsumer
	AppMode              config.APPLICATION_MODE
	BaseConfig           config.BaseConfig
	AWSConfig            config.AWSConfig
	DeviceManager        device.DeviceManager
	WsContainer          restful.Container
}

func New() (GopnsApp, error) {

	gopnasapp_ := &GopnsApplication{}

	gopnasapp_.AppMode, gopnasapp_.BaseConfig, gopnasapp_.AWSConfig = config.ParseConfig()

	err := gopnasapp_.setupDynamoDB()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.setupSQS()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.setupSNS()
	if err != nil {
		return nil, err
	}

	err = gopnasapp_.createWorkerPool()
	if err != nil {
		return nil, err
	}

	//setup notification sender
	gopnasapp_.NotificationSender = notification.NotificationSender{
		SnsClient:    gopnasapp_.SNSClient,
		WorkerPool:   &gopnasapp_.WorkerPool,
		PlatformApps: gopnasapp_.AWSConfig.PlatformAppsMap()}

	//create a notification consumer
	gopnasapp_.NotificationConsumer = notification.NewSQSNotifictionConsumer(
		gopnasapp_.AWSConfig.SqsQueueUrl(),
		gopnasapp_.SQSClient,
		&gopnasapp_.NotificationSender)

	//create a device manager
	gopnasapp_.DeviceManager = device.New(
		gopnasapp_.SNSClient,
		gopnasapp_.DynamoClient,
		gopnasapp_.AWSConfig.DynamoTable(),
		gopnasapp_.AWSConfig.PlatformAppsMap())

	//

	gopnasapp_.setupMetrics()

	return gopnasapp_, nil
}

// ToDo return appropriate errors
func (this *GopnsApplication) Start() error {

	err := this.runWorkerPool()
	if err != nil {
		return err
	}

	err = this.NotificationConsumer.Start()
	if err != nil {
		return err
	}

	if this.AppMode == config.SERVER_MODE {
		this.setupRestServices()
	} else if this.AppMode == config.REGISTER_MODE {

	} else if this.AppMode == config.SEND_MODE {

	}

	return nil
}

func (this *GopnsApplication) setupDynamoDB() error {
	var err error
	this.DynamoClient, err = dynamodb.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if err != nil {
		return err
	}

	if found, err := this.DynamoClient.FindTable(this.AWSConfig.DynamoTable()); err != nil {
		return err
	} else if found {
		return nil
	} else {

		createTableRequest := dynamodb.CreateTableRequest{
			[]dynamodb.AttributeDefinition{dynamodb.AttributeDefinition{"alias", "S"}},
			this.AWSConfig.DynamoTable(),
			[]dynamodb.KeySchema{dynamodb.KeySchema{"alias", "HASH"}},
			dynamodb.ProvisionedThroughput{
				this.AWSConfig.InitialReadCapacity(),
				this.AWSConfig.InitialWriteCapacity()}}
		return this.DynamoClient.CreateTable(createTableRequest)
	}

	return err
}

func (this *GopnsApplication) setupSQS() error {
	var err error
	this.SQSClient = sqs.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if sqsQueue, err := this.SQSClient.CreateQueue(this.AWSConfig.SqsQueueName()); err != nil {
		log.Fatalf("Unable to initilize SQS %s", err.Error())
	} else {
		log.Printf("Using SQS Queue %s", sqsQueue.QueueUrl)
		this.AWSConfig.SetSqsQueueUrl(sqsQueue.QueueUrl)
	}

	return err
}

func (this *GopnsApplication) setupSNS() error {
	var err error
	this.SNSClient, err = sns.New(
		this.AWSConfig.UserID(),
		this.AWSConfig.UserSecret(),
		this.AWSConfig.Region())

	if err != nil {
		return err
	} else {
		return nil
	}
}

func (this *GopnsApplication) setupMetrics() error {

	metrics.StartGraphiteReporter(
		this.BaseConfig.MetricsServer(),
		this.BaseConfig.MetricsAPIKey(),
		this.BaseConfig.MetricsPrefix())

	return nil
}

func (this *GopnsApplication) createWorkerPool() error {
	cpus := runtime.NumCPU()
	runtime.GOMAXPROCS(cpus)
	this.WorkerPool = *pool.New(cpus)
	log.Println("Worker pool created with", cpus, "workers")
	return nil
}

func (this *GopnsApplication) runWorkerPool() error {
	this.WorkerPool.Run()
	log.Println("Worker pool started")
	ticker := time.NewTicker(time.Second * 60)
	go func() {
		for _ = range ticker.C {
			status := this.WorkerPool.Status()
			log.Println(status.Submitted, "submitted jobs,", status.Running, "running,", status.Completed, "completed.")
		}
	}()

	return nil
}

func (this *GopnsApplication) setupRestServices() {

	//setup a new services container for gopns rest services
	this.WsContainer = *restful.NewContainer()
	//ToDo read the gopns rest root path from config (re: embeddable app)
	rootPath := "/rest" //without the last slash (e.g., /rest/gopns)

	notificationService := new(rest.NotificationService)
	notificationService.NotificationSender = &this.NotificationSender
	notificationService.DeviceManager = this.DeviceManager
	// register notification service with our services container
	notificationService.Register(&this.WsContainer, rootPath)

	//deviceService := new(rest.DeviceService)
	//deviceService.DeviceManager = this.DeviceManager
	log.Printf("start listening on localhost:8080")
	server := &http.Server{Addr: ":" + this.BaseConfig.Port(), Handler: &this.WsContainer}
	log.Fatal(server.ListenAndServe())
}
<|endoftext|>


<commit_before>/*
Package graceful implements graceful shutdown for HTTP servers by closing idle
connections after receiving a signal. By default, this package listens for
interrupts (i.e., SIGINT), but when it detects that it is running under Einhorn
it will additionally listen for SIGUSR2 as well, giving your application
automatic support for graceful restarts/code upgrades.
*/
package graceful

import (
	"net"
	"runtime"
	"sync/atomic"

	"github.com/zenazn/goji/graceful/listener"
)

// WrapListener wraps an arbitrary net.Listener for use with graceful shutdowns.
// In the background, it uses the listener sub-package to Wrap the listener in
// Deadline mode. If another mode of operation is desired, you should call
// listener.Wrap yourself: this function is smart enough to not double-wrap
// listeners.
func WrapListener(l net.Listener) net.Listener {
	if lt, ok := l.(*listener.T); ok {
		appendListener(lt)
		return lt
	}

	lt := listener.Wrap(l, listener.Deadline)
	appendListener(lt)
	return lt
}

func appendListener(l *listener.T) {
	mu.Lock()
	defer mu.Unlock()

	listeners = append(listeners, l)
}

const errClosing = "use of closed network connection"

// During graceful shutdown, calls to Accept will start returning errors. This
// is inconvenient, since we know these sorts of errors are peaceful, so we
// silently swallow them.
func peacefulError(err error) error {
	if atomic.LoadInt32(&closing) == 0 {
		return err
	}
	// Unfortunately Go doesn't really give us a better way to select errors
	// than this, so *shrug*.
	if oe, ok := err.(*net.OpError); ok {
		errOp := "accept"
		if runtime.GOOS == "windows" {
			errOp = "AcceptEx"
		}
		if oe.Op == errOp && oe.Err.Error() == errClosing {
			return nil
		}
	}
	return err
}
<commit_msg>fix an error at shutdown on Windows.<commit_after>/*
Package graceful implements graceful shutdown for HTTP servers by closing idle
connections after receiving a signal. By default, this package listens for
interrupts (i.e., SIGINT), but when it detects that it is running under Einhorn
it will additionally listen for SIGUSR2 as well, giving your application
automatic support for graceful restarts/code upgrades.
*/
package graceful

import (
	"net"
	"sync/atomic"

	"github.com/zenazn/goji/graceful/listener"
)

// WrapListener wraps an arbitrary net.Listener for use with graceful shutdowns.
// In the background, it uses the listener sub-package to Wrap the listener in
// Deadline mode. If another mode of operation is desired, you should call
// listener.Wrap yourself: this function is smart enough to not double-wrap
// listeners.
func WrapListener(l net.Listener) net.Listener {
	if lt, ok := l.(*listener.T); ok {
		appendListener(lt)
		return lt
	}

	lt := listener.Wrap(l, listener.Deadline)
	appendListener(lt)
	return lt
}

func appendListener(l *listener.T) {
	mu.Lock()
	defer mu.Unlock()

	listeners = append(listeners, l)
}

const errClosing = "use of closed network connection"

// During graceful shutdown, calls to Accept will start returning errors. This
// is inconvenient, since we know these sorts of errors are peaceful, so we
// silently swallow them.
func peacefulError(err error) error {
	if atomic.LoadInt32(&closing) == 0 {
		return err
	}
	// Unfortunately Go doesn't really give us a better way to select errors
	// than this, so *shrug*.
	if oe, ok := err.(*net.OpError); ok {
		switch oe.Op {
		// backward compatibility: older golang returns AcceptEx on Windows.
		// Current golang returns "accept" consistently. It's platform independent.
		// See https://github.com/golang/go/commit/b0f4ee533a875c258ac1030ee382f0ffe2de304b
		case "AcceptEx":
			fallthrough
		case "accept":
			if oe.Err.Error() == errClosing {
				return nil
			}
		}
	}
	return err
}
<|endoftext|>


<commit_before>package gengateway

import (
	"errors"
	"fmt"
	"go/format"
	"path"
	"path/filepath"
	"strings"

	"github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
	"github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)

var (
	errNoTargetService = errors.New("no target service defined in the file")
)

type generator struct {
	reg         *descriptor.Registry
	baseImports []descriptor.GoPackage
}

// New returns a new generator which generates grpc gateway files.
func New(reg *descriptor.Registry) *generator {
	var imports []descriptor.GoPackage
	for _, pkgpath := range []string{
		"encoding/json",
		"io",
		"net/http",
		"github.com/gengo/grpc-gateway/runtime",
		"github.com/gengo/grpc-gateway/internal",
		"github.com/golang/glog",
		"github.com/golang/protobuf/proto",
		"golang.org/x/net/context",
		"google.golang.org/grpc",
		"google.golang.org/grpc/codes",
	} {
		pkg := descriptor.GoPackage{
			Path: pkgpath,
			Name: path.Base(pkgpath),
		}
		if err := reg.ReserveGoPackageAlias(pkg.Name, pkg.Path); err != nil {
			for i := 0; ; i++ {
				alias := fmt.Sprintf("%s_%d", pkg.Name, i)
				if err := reg.ReserveGoPackageAlias(pkg.Name, pkg.Path); err != nil {
					continue
				}
				pkg.Alias = alias
				break
			}
		}
		imports = append(imports, pkg)
	}
	return &generator{reg: reg, baseImports: imports}
}

func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) {
	var files []*plugin.CodeGeneratorResponse_File
	for _, file := range targets {
		glog.V(1).Infof("Processing %s", file.GetName())
		code, err := g.generate(file)
		if err == errNoTargetService {
			glog.V(1).Infof("%s: %v", file.GetName(), err)
			continue
		}
		if err != nil {
			return nil, err
		}
		formatted, err := format.Source([]byte(code))
		if err != nil {
			glog.Errorf("%v: %s", err, code)
			return nil, err
		}
		name := file.GetName()
		ext := filepath.Ext(name)
		base := strings.TrimSuffix(name, ext)
		output := fmt.Sprintf("%s.pb.gw.go", base)
		files = append(files, &plugin.CodeGeneratorResponse_File{
			Name:    proto.String(output),
			Content: proto.String(string(formatted)),
		})
		glog.V(1).Infof("Will emit %s", output)
	}
	return files, nil
}

func (g *generator) generate(file *descriptor.File) (string, error) {
	pkgSeen := make(map[string]bool)
	var imports []descriptor.GoPackage
	for _, pkg := range g.baseImports {
		pkgSeen[pkg.Path] = true
		imports = append(imports, pkg)
	}
	for _, svc := range file.Services {
		for _, m := range svc.Methods {
			pkg := m.RequestType.File.GoPkg
			if pkg == file.GoPkg {
				continue
			}
			if pkgSeen[pkg.Path] {
				continue
			}
			pkgSeen[pkg.Path] = true
			imports = append(imports, pkg)
		}
	}
	return applyTemplate(param{File: file, Imports: imports})
}
<commit_msg>Prevent infinite loop on package name collision<commit_after>package gengateway

import (
	"errors"
	"fmt"
	"go/format"
	"path"
	"path/filepath"
	"strings"

	"github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
	"github.com/golang/glog"
	"github.com/golang/protobuf/proto"
	plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)

var (
	errNoTargetService = errors.New("no target service defined in the file")
)

type generator struct {
	reg         *descriptor.Registry
	baseImports []descriptor.GoPackage
}

// New returns a new generator which generates grpc gateway files.
func New(reg *descriptor.Registry) *generator {
	var imports []descriptor.GoPackage
	for _, pkgpath := range []string{
		"encoding/json",
		"io",
		"net/http",
		"github.com/gengo/grpc-gateway/runtime",
		"github.com/gengo/grpc-gateway/internal",
		"github.com/golang/glog",
		"github.com/golang/protobuf/proto",
		"golang.org/x/net/context",
		"google.golang.org/grpc",
		"google.golang.org/grpc/codes",
	} {
		pkg := descriptor.GoPackage{
			Path: pkgpath,
			Name: path.Base(pkgpath),
		}
		if err := reg.ReserveGoPackageAlias(pkg.Name, pkg.Path); err != nil {
			for i := 0; ; i++ {
				alias := fmt.Sprintf("%s_%d", pkg.Name, i)
				if err := reg.ReserveGoPackageAlias(alias, pkg.Path); err != nil {
					continue
				}
				pkg.Alias = alias
				break
			}
		}
		imports = append(imports, pkg)
	}
	return &generator{reg: reg, baseImports: imports}
}

func (g *generator) Generate(targets []*descriptor.File) ([]*plugin.CodeGeneratorResponse_File, error) {
	var files []*plugin.CodeGeneratorResponse_File
	for _, file := range targets {
		glog.V(1).Infof("Processing %s", file.GetName())
		code, err := g.generate(file)
		if err == errNoTargetService {
			glog.V(1).Infof("%s: %v", file.GetName(), err)
			continue
		}
		if err != nil {
			return nil, err
		}
		formatted, err := format.Source([]byte(code))
		if err != nil {
			glog.Errorf("%v: %s", err, code)
			return nil, err
		}
		name := file.GetName()
		ext := filepath.Ext(name)
		base := strings.TrimSuffix(name, ext)
		output := fmt.Sprintf("%s.pb.gw.go", base)
		files = append(files, &plugin.CodeGeneratorResponse_File{
			Name:    proto.String(output),
			Content: proto.String(string(formatted)),
		})
		glog.V(1).Infof("Will emit %s", output)
	}
	return files, nil
}

func (g *generator) generate(file *descriptor.File) (string, error) {
	pkgSeen := make(map[string]bool)
	var imports []descriptor.GoPackage
	for _, pkg := range g.baseImports {
		pkgSeen[pkg.Path] = true
		imports = append(imports, pkg)
	}
	for _, svc := range file.Services {
		for _, m := range svc.Methods {
			pkg := m.RequestType.File.GoPkg
			if pkg == file.GoPkg {
				continue
			}
			if pkgSeen[pkg.Path] {
				continue
			}
			pkgSeen[pkg.Path] = true
			imports = append(imports, pkg)
		}
	}
	return applyTemplate(param{File: file, Imports: imports})
}
<|endoftext|>


<commit_before>// +build !wasm

package writer

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/Jeffail/benthos/v3/lib/bloblang/x/field"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
)

//------------------------------------------------------------------------------

// AzureTableStorage is a benthos writer. Type implementation that writes messages to an
// Azure Table Storage table.
type AzureTableStorage struct {
	conf         AzureTableStorageConfig
	tableName    field.Expression
	partitionKey field.Expression
	rowKey       field.Expression
	properties   map[string]field.Expression
	client       storage.TableServiceClient
	timeout      time.Duration
	log          log.Modular
	stats        metrics.Type
}

// NewAzureTableStorage creates a new Azure Table Storage writer Type.
func NewAzureTableStorage(
	conf AzureTableStorageConfig,
	log log.Modular,
	stats metrics.Type,
) (*AzureTableStorage, error) {
	var timeout time.Duration
	var err error
	if tout := conf.Timeout; len(tout) > 0 {
		if timeout, err = time.ParseDuration(tout); err != nil {
			return nil, fmt.Errorf("failed to parse timeout period string: %v", err)
		}
	}
	if len(conf.StorageAccount) == 0 {
		return nil, fmt.Errorf("invalid azure storage account")
	}
	basicClient, err := storage.NewBasicClient(conf.StorageAccount, conf.StorageAccessKey)
	if err != nil {
		return nil, fmt.Errorf("invalid azure storage account credentials: %v", err)
	}
	a := &AzureTableStorage{
		conf:    conf,
		log:     log,
		stats:   stats,
		timeout: timeout,
		client:  basicClient.GetTableService(),
	}
	if a.tableName, err = field.New(conf.TableName); err != nil {
		return nil, fmt.Errorf("failed to parse table name expression: %v", err)
	}
	if a.partitionKey, err = field.New(conf.PartitionKey); err != nil {
		return nil, fmt.Errorf("failed to parse partition key expression: %v", err)
	}
	if a.rowKey, err = field.New(conf.RowKey); err != nil {
		return nil, fmt.Errorf("failed to parse row key expression: %v", err)
	}
	a.properties = make(map[string]field.Expression)
	for property, value := range conf.Properties {
		if a.properties[property], err = field.New(value); err != nil {
			return nil, fmt.Errorf("failed to parse property expression: %v", err)
		}
	}

	return a, nil
}

// ConnectWithContext attempts to establish a connection to the target Table Storage Account.
func (a *AzureTableStorage) ConnectWithContext(ctx context.Context) error {
	return a.Connect()
}

// Connect attempts to establish a connection to the target Table Storage Account.
func (a *AzureTableStorage) Connect() error {
	return nil
}

// Write attempts to write message contents to a target Azure Table Storage container as files.
func (a *AzureTableStorage) Write(msg types.Message) error {
	return a.WriteWithContext(context.Background(), msg)
}

// WriteWithContext attempts to write message contents to a target storage account as files.
func (a *AzureTableStorage) WriteWithContext(wctx context.Context, msg types.Message) error {
	writeReqs := make(map[string]map[string][]*storage.Entity)

	if err := IterateBatchedSend(msg, func(i int, p types.Part) error {
		entity := &storage.Entity{}
		tableName := a.tableName.String(i, msg)
		partitionKey := a.partitionKey.String(i, msg)
		entity.PartitionKey = a.partitionKey.String(i, msg)
		entity.RowKey = a.rowKey.String(i, msg)
		entity.TimeStamp = time.Now()

		jsonMap := make(map[string]interface{})
		if len(a.properties) == 0 {
			err := json.Unmarshal(p.Get(), &jsonMap)
			if err != nil {
				a.log.Errorf("error unmarshalling message: %v.", err)
			}
			for property, v := range jsonMap {
				switch v.(type) {
				case []interface{}, map[string]interface{}:
					m, err := json.Marshal(v)
					if err != nil {
						a.log.Errorf("error marshalling property: %v.", property)
					}
					jsonMap[property] = string(m)
				}
			}
		} else {
			for property, value := range a.properties {
				jsonMap[property] = value.String(i, msg)
			}
		}
		entity.Properties = jsonMap

		if writeReqs[tableName] == nil {
			writeReqs[tableName] = make(map[string][]*storage.Entity)
		}
		writeReqs[tableName][partitionKey] = append(writeReqs[tableName][partitionKey], entity)
		return nil
	}); err != nil {
		return err
	}

	for tn, pks := range writeReqs {
		table := a.client.GetTableReference(tn)
		for _, entities := range pks {
			tableBatch := table.NewBatch()
			for _, entity := range entities {
				entity.Table = table
				if err := a.createBatch(tableBatch, a.conf.InsertType, entity); err != nil {
					return err
				}
			}
			if err := tableBatch.ExecuteBatch(); err != nil {
				if cerr, ok := err.(storage.AzureStorageServiceError); ok {
					if cerr.Code == "TableNotFound" {
						if cerr := table.Create(uint(10), storage.FullMetadata, nil); cerr != nil {
							a.log.Errorf("error creating table: %v.", cerr)
						}
						// retry
						err = tableBatch.ExecuteBatch()
					}
				}
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (a *AzureTableStorage) insert(insertType string, entity *storage.Entity) error {
	switch insertType {
	case "INSERT":
		return entity.Insert(storage.FullMetadata, nil)
	case "INSERT_MERGE":
		return entity.InsertOrMerge(nil)
	case "INSERT_REPLACE":
		return entity.InsertOrReplace(nil)
	default:
		return fmt.Errorf("invalid insert type")
	}
}

func (a *AzureTableStorage) createBatch(tableBatch *storage.TableBatch, insertType string, entity *storage.Entity) error {
	switch insertType {
	case "INSERT":
		tableBatch.InsertEntity(entity)
	case "INSERT_MERGE":
		tableBatch.InsertOrMergeEntity(entity, true)
	case "INSERT_REPLACE":
		tableBatch.InsertOrReplaceEntity(entity, true)
	default:
		return fmt.Errorf("invalid insert type")
	}
	return nil
}

// CloseAsync begins cleaning up resources used by this reader asynchronously.
func (a *AzureTableStorage) CloseAsync() {
}

// WaitForClose will block until either the reader is closed or a specified
// timeout occurs.
func (a *AzureTableStorage) WaitForClose(time.Duration) error {
	return nil
}

//------------------------------------------------------------------------------
<commit_msg>Remove legacy `insert` func<commit_after>// +build !wasm

package writer

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/Azure/azure-sdk-for-go/storage"
	"github.com/Jeffail/benthos/v3/lib/bloblang/x/field"
	"github.com/Jeffail/benthos/v3/lib/log"
	"github.com/Jeffail/benthos/v3/lib/metrics"
	"github.com/Jeffail/benthos/v3/lib/types"
)

//------------------------------------------------------------------------------

// AzureTableStorage is a benthos writer. Type implementation that writes messages to an
// Azure Table Storage table.
type AzureTableStorage struct {
	conf         AzureTableStorageConfig
	tableName    field.Expression
	partitionKey field.Expression
	rowKey       field.Expression
	properties   map[string]field.Expression
	client       storage.TableServiceClient
	timeout      time.Duration
	log          log.Modular
	stats        metrics.Type
}

// NewAzureTableStorage creates a new Azure Table Storage writer Type.
func NewAzureTableStorage(
	conf AzureTableStorageConfig,
	log log.Modular,
	stats metrics.Type,
) (*AzureTableStorage, error) {
	var timeout time.Duration
	var err error
	if tout := conf.Timeout; len(tout) > 0 {
		if timeout, err = time.ParseDuration(tout); err != nil {
			return nil, fmt.Errorf("failed to parse timeout period string: %v", err)
		}
	}
	if len(conf.StorageAccount) == 0 {
		return nil, fmt.Errorf("invalid azure storage account")
	}
	basicClient, err := storage.NewBasicClient(conf.StorageAccount, conf.StorageAccessKey)
	if err != nil {
		return nil, fmt.Errorf("invalid azure storage account credentials: %v", err)
	}
	a := &AzureTableStorage{
		conf:    conf,
		log:     log,
		stats:   stats,
		timeout: timeout,
		client:  basicClient.GetTableService(),
	}
	if a.tableName, err = field.New(conf.TableName); err != nil {
		return nil, fmt.Errorf("failed to parse table name expression: %v", err)
	}
	if a.partitionKey, err = field.New(conf.PartitionKey); err != nil {
		return nil, fmt.Errorf("failed to parse partition key expression: %v", err)
	}
	if a.rowKey, err = field.New(conf.RowKey); err != nil {
		return nil, fmt.Errorf("failed to parse row key expression: %v", err)
	}
	a.properties = make(map[string]field.Expression)
	for property, value := range conf.Properties {
		if a.properties[property], err = field.New(value); err != nil {
			return nil, fmt.Errorf("failed to parse property expression: %v", err)
		}
	}

	return a, nil
}

// ConnectWithContext attempts to establish a connection to the target Table Storage Account.
func (a *AzureTableStorage) ConnectWithContext(ctx context.Context) error {
	return a.Connect()
}

// Connect attempts to establish a connection to the target Table Storage Account.
func (a *AzureTableStorage) Connect() error {
	return nil
}

// Write attempts to write message contents to a target Azure Table Storage container as files.
func (a *AzureTableStorage) Write(msg types.Message) error {
	return a.WriteWithContext(context.Background(), msg)
}

// WriteWithContext attempts to write message contents to a target storage account as files.
func (a *AzureTableStorage) WriteWithContext(wctx context.Context, msg types.Message) error {
	writeReqs := make(map[string]map[string][]*storage.Entity)

	if err := IterateBatchedSend(msg, func(i int, p types.Part) error {
		entity := &storage.Entity{}
		tableName := a.tableName.String(i, msg)
		partitionKey := a.partitionKey.String(i, msg)
		entity.PartitionKey = a.partitionKey.String(i, msg)
		entity.RowKey = a.rowKey.String(i, msg)
		entity.TimeStamp = time.Now()

		jsonMap := make(map[string]interface{})
		if len(a.properties) == 0 {
			err := json.Unmarshal(p.Get(), &jsonMap)
			if err != nil {
				a.log.Errorf("error unmarshalling message: %v.", err)
			}
			for property, v := range jsonMap {
				switch v.(type) {
				case []interface{}, map[string]interface{}:
					m, err := json.Marshal(v)
					if err != nil {
						a.log.Errorf("error marshalling property: %v.", property)
					}
					jsonMap[property] = string(m)
				}
			}
		} else {
			for property, value := range a.properties {
				jsonMap[property] = value.String(i, msg)
			}
		}
		entity.Properties = jsonMap

		if writeReqs[tableName] == nil {
			writeReqs[tableName] = make(map[string][]*storage.Entity)
		}
		writeReqs[tableName][partitionKey] = append(writeReqs[tableName][partitionKey], entity)
		return nil
	}); err != nil {
		return err
	}

	for tn, pks := range writeReqs {
		table := a.client.GetTableReference(tn)
		for _, entities := range pks {
			tableBatch := table.NewBatch()
			for _, entity := range entities {
				entity.Table = table
				if err := a.createBatch(tableBatch, a.conf.InsertType, entity); err != nil {
					return err
				}
			}
			if err := tableBatch.ExecuteBatch(); err != nil {
				if cerr, ok := err.(storage.AzureStorageServiceError); ok {
					if cerr.Code == "TableNotFound" {
						if cerr := table.Create(uint(10), storage.FullMetadata, nil); cerr != nil {
							a.log.Errorf("error creating table: %v.", cerr)
						}
						// retry
						err = tableBatch.ExecuteBatch()
					}
				}
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

func (a *AzureTableStorage) createBatch(tableBatch *storage.TableBatch, insertType string, entity *storage.Entity) error {
	switch insertType {
	case "INSERT":
		tableBatch.InsertEntity(entity)
	case "INSERT_MERGE":
		tableBatch.InsertOrMergeEntity(entity, true)
	case "INSERT_REPLACE":
		tableBatch.InsertOrReplaceEntity(entity, true)
	default:
		return fmt.Errorf("invalid insert type")
	}
	return nil
}

// CloseAsync begins cleaning up resources used by this reader asynchronously.
func (a *AzureTableStorage) CloseAsync() {
}

// WaitForClose will block until either the reader is closed or a specified
// timeout occurs.
func (a *AzureTableStorage) WaitForClose(time.Duration) error {
	return nil
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>package main

import (
	//"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/julienschmidt/httprouter"
)

//"github.com/tsenart/vegeta/lib"

// func Test_something(t *testing.T) { //test function starts with "Test" and takes a pointer to type testing.T
// 	if shit() != "did it work?" { //try a unit test on function
// 		t.Error("shit did not work as expected.") // log error if it did not work as expected
// 	} else {
// 		t.Log("one test passed.") // log some info if you want
// 	}
// }

// func testrate(t *testing.T) {
//
// 	rate := uint64(100) // per second
// 	duration := 4 * time.Second
// 	targeter := vegeta.NewStaticTargeter(&vegeta.Target{
// 		Method: "GET",
// 		URL:    "http://localhost:9100/",
// 	})
// 	attacker := vegeta.NewAttacker()
//
// 	var results vegeta.Results
// 	for res := range attacker.Attack(targeter, rate, duration) {
// 		results = append(results, res)
// 	}
//
// 	metrics := vegeta.NewMetrics(results)
// 	fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
// }

func TestGetRecords(t *testing.T) { //not printing to logs

	// DBName = "test.db"
	//
	// boltClient, err := bolt.Open(DBName, 0600, nil) //maybe change the 600 to a read only value
	// errLog(err)
	// defer boltClient.Close()
	//
	// boltClient.Update(func(tx *bolt.Tx) error {
	// 	tx.CreateBucketIfNotExists([]byte("historicData"))
	// 	return nil
	// })

	//need to put some fake data into test.db with the ticker
	err := GetRecords()
	if err != nil {
		t.Error("checkForRecords returned an error:", err)
	} else {
		fmt.Println("GetRecords found DB and unmarshalled data successfully")
	}

}

type MockURL struct {
	urlStr        string
	expectedWCode int
}

func TestGetHandler(t *testing.T) {

	router := httprouter.New()
	router.GET("/count/:page", countHandler)

	inputHTTP := [3]MockURL{
		//test case 0: add "test1" to the counter
		{"/count/test1", 200},
		//test case 1: add a second "test1" to the counter
		{"/count/test1", 200},
		//test case 2: add "test2" to the counter
		{"/count/test2", 200},
	}

	for i := range inputHTTP {
		w := httptest.NewRecorder()

		req, _ := http.NewRequest("GET", inputHTTP[i].urlStr, nil)

		router.ServeHTTP(w, req)
		fmt.Println(w.Code)
		if w.Code != inputHTTP[i].expectedWCode {
			t.Error("PutHandler test case", i, "returned", w.Code, "instead of", inputHTTP[i].expectedWCode)
		}
	}
}
<commit_msg>updated tests<commit_after>package main

import (
	//"errors"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/boltdb/bolt"
	"github.com/julienschmidt/httprouter"
)

//"github.com/tsenart/vegeta/lib"

// func Test_something(t *testing.T) { //test function starts with "Test" and takes a pointer to type testing.T
// 	if shit() != "did it work?" { //try a unit test on function
// 		t.Error("shit did not work as expected.") // log error if it did not work as expected
// 	} else {
// 		t.Log("one test passed.") // log some info if you want
// 	}
// }

// func testrate(t *testing.T) {
//
// 	rate := uint64(100) // per second
// 	duration := 4 * time.Second
// 	targeter := vegeta.NewStaticTargeter(&vegeta.Target{
// 		Method: "GET",
// 		URL:    "http://localhost:9100/",
// 	})
// 	attacker := vegeta.NewAttacker()
//
// 	var results vegeta.Results
// 	for res := range attacker.Attack(targeter, rate, duration) {
// 		results = append(results, res)
// 	}
//
// 	metrics := vegeta.NewMetrics(results)
// 	fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
// }

func TestGetRecords(t *testing.T) { //not printing to logs

	DBName = "test.db"

	boltClient, err := bolt.Open(DBName, 0600, nil) //maybe change the 600 to a read only value
	errLog(err)

	boltClient.Update(func(tx *bolt.Tx) error {
		tx.CreateBucketIfNotExists([]byte("historicData"))
		return nil
	})

	//******************************************************
	ips.m["123.456.789.0"] = true
	counter.m["test1"]++
	counter.m["test1"]++
	counter.m["test2"]++

	m1 := SavePoint{
		PageCounts:  counter.m,  //2 test1 and 1 test2
		UniqueViews: len(ips.m), //number 1
	}

	m2 := IPList{
		IPs: ips.m, //make map with single IPs
	}

	m1json, err := json.Marshal(m1)
	errLog(err)
	m2json, err := json.Marshal(m2)
	errLog(err)
	boltClient.Update(func(tx *bolt.Tx) error {

		err = tx.Bucket([]byte("historicData")).Put([]byte("current"), []byte(m1json))
		errLog(err)

		err = tx.Bucket([]byte("historicData")).Put([]byte("IPs"), []byte(m2json))
		errLog(err)
		return nil
	})
	boltClient.Close()
	//****************************************************

	//need to put some fake data into test.db with the ticker
	err = GetRecords()
	if err != nil {
		t.Error("checkForRecords returned an error:", err)
	} else {
		fmt.Println("GetRecords found DB and unmarshalled data successfully")
	}

}

type MockURL struct {
	urlStr        string
	expectedWCode int
}

func TestGetHandler(t *testing.T) {

	router := httprouter.New()
	router.GET("/count/:page", countHandler)

	inputHTTP := [3]MockURL{
		//test case 0: add "test1" to the counter
		{"/count/test1", 200},
		//test case 1: add a second "test1" to the counter
		{"/count/test1", 200},
		//test case 2: add "test2" to the counter
		{"/count/test2", 200},
	}

	for i := range inputHTTP {
		w := httptest.NewRecorder()

		req, _ := http.NewRequest("GET", inputHTTP[i].urlStr, nil)

		router.ServeHTTP(w, req)
		fmt.Println(w.Code)
		if w.Code != inputHTTP[i].expectedWCode {
			t.Error("PutHandler test case", i, "returned", w.Code, "instead of", inputHTTP[i].expectedWCode)
		}
	}
}
<|endoftext|>


<commit_before>package radix

import (
	"net"
	. "testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestPipeliner(t *T) {
	dialOpts := []DialOpt{DialReadTimeout(time.Second)}

	testNonRecoverableError := func(t *T, p *pipeliner) {
		key := randStr()

		setCmd := getPipelinerCmd(Cmd(nil, "SET", key, key))

		var firstGetResult string
		firstGetCmd := getPipelinerCmd(Cmd(&firstGetResult, "GET", key))

		invalidCmd := getPipelinerCmd(Cmd(nil, "RADIXISAWESOME"))

		var secondGetResult string
		secondGetCmd := getPipelinerCmd(Cmd(&secondGetResult, "GET", key))

		p.flush([]CmdAction{setCmd, firstGetCmd, invalidCmd, secondGetCmd})

		require.Nil(t, <-setCmd.resCh)

		require.Nil(t, <-firstGetCmd.resCh)
		require.Equal(t, key, firstGetResult)

		invalidCmdErr := <-invalidCmd.resCh
		require.NotNil(t, invalidCmdErr)

		require.Equal(t, invalidCmdErr, <-secondGetCmd.resCh)
		require.Empty(t, secondGetResult)
	}

	testTimeout := func(t *T, p *pipeliner) {
		key := randStr()

		delCmd := getPipelinerCmd(Cmd(nil, "DEL", key))
		pushCmd := getPipelinerCmd(Cmd(nil, "LPUSH", key, "3", "2", "1"))
		p.flush([]CmdAction{delCmd, pushCmd})
		require.Nil(t, <-delCmd.resCh)
		require.Nil(t, <-pushCmd.resCh)

		var firstPopResult string
		firstPopCmd := getPipelinerCmd(Cmd(&firstPopResult, "LPOP", key))

		var pauseResult string
		pauseCmd := getPipelinerCmd(Cmd(&pauseResult, "CLIENT", "PAUSE", "1100"))

		var secondPopResult string
		secondPopCmd := getPipelinerCmd(Cmd(&secondPopResult, "LPOP", key))

		var thirdPopResult string
		thirdPopCmd := getPipelinerCmd(Cmd(&thirdPopResult, "LPOP", key))

		p.flush([]CmdAction{firstPopCmd, pauseCmd, secondPopCmd, thirdPopCmd})

		require.Nil(t, <-firstPopCmd.resCh)
		require.Equal(t, "1", firstPopResult)

		require.Nil(t, <-pauseCmd.resCh)
		require.Equal(t, "OK", pauseResult)

		secondPopErr := <-secondPopCmd.resCh
		require.IsType(t, (*net.OpError)(nil), secondPopErr)
		require.True(t, secondPopErr.(net.Error).Temporary())
		require.True(t, secondPopErr.(net.Error).Timeout())
		assert.Empty(t, secondPopResult)

		thirdPopErr := <-thirdPopCmd.resCh
		require.IsType(t, (*net.OpError)(nil), thirdPopErr)
		require.True(t, thirdPopErr.(net.Error).Temporary())
		require.True(t, thirdPopErr.(net.Error).Timeout())
		assert.Empty(t, thirdPopResult)
	}

	t.Run("Conn", func(t *T) {
		t.Run("NonRecoverableError", func(t *T) {
			conn := dial(dialOpts...)
			defer conn.Close()

			p := newPipeliner(conn, 0, 0, 0)
			defer p.Close()

			testNonRecoverableError(t, p)
		})

		t.Run("Timeout", func(t *T) {
			conn := dial(dialOpts...)
			defer conn.Close()

			p := newPipeliner(conn, 0, 0, 0)
			defer p.Close()

			testTimeout(t, p)
		})
	})

	// Pool has potentially different semantics because it uses ioErrConn,
	// so we test it separately.
	t.Run("Pool", func(t *T) {
		poolOpts := []PoolOpt{
			PoolConnFunc(func(string, string) (Conn, error) {
				return dial(dialOpts...), nil
			}),
			PoolPipelineConcurrency(1),
			PoolPipelineWindow(time.Hour, 0),
		}
		t.Run("NonRecoverableError", func(t *T) {
			pool := testPool(1, poolOpts...)
			defer pool.Close()

			testNonRecoverableError(t, pool.pipeliner)
		})

		t.Run("Timeout", func(t *T) {
			pool := testPool(1, poolOpts...)
			defer pool.Close()

			testTimeout(t, pool.pipeliner)
		})
	})
}
<commit_msg>Update comment about Pool and ioErrConn in pipeliner test<commit_after>package radix

import (
	"net"
	. "testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestPipeliner(t *T) {
	dialOpts := []DialOpt{DialReadTimeout(time.Second)}

	testNonRecoverableError := func(t *T, p *pipeliner) {
		key := randStr()

		setCmd := getPipelinerCmd(Cmd(nil, "SET", key, key))

		var firstGetResult string
		firstGetCmd := getPipelinerCmd(Cmd(&firstGetResult, "GET", key))

		invalidCmd := getPipelinerCmd(Cmd(nil, "RADIXISAWESOME"))

		var secondGetResult string
		secondGetCmd := getPipelinerCmd(Cmd(&secondGetResult, "GET", key))

		p.flush([]CmdAction{setCmd, firstGetCmd, invalidCmd, secondGetCmd})

		require.Nil(t, <-setCmd.resCh)

		require.Nil(t, <-firstGetCmd.resCh)
		require.Equal(t, key, firstGetResult)

		invalidCmdErr := <-invalidCmd.resCh
		require.NotNil(t, invalidCmdErr)

		require.Equal(t, invalidCmdErr, <-secondGetCmd.resCh)
		require.Empty(t, secondGetResult)
	}

	testTimeout := func(t *T, p *pipeliner) {
		key := randStr()

		delCmd := getPipelinerCmd(Cmd(nil, "DEL", key))
		pushCmd := getPipelinerCmd(Cmd(nil, "LPUSH", key, "3", "2", "1"))
		p.flush([]CmdAction{delCmd, pushCmd})
		require.Nil(t, <-delCmd.resCh)
		require.Nil(t, <-pushCmd.resCh)

		var firstPopResult string
		firstPopCmd := getPipelinerCmd(Cmd(&firstPopResult, "LPOP", key))

		var pauseResult string
		pauseCmd := getPipelinerCmd(Cmd(&pauseResult, "CLIENT", "PAUSE", "1100"))

		var secondPopResult string
		secondPopCmd := getPipelinerCmd(Cmd(&secondPopResult, "LPOP", key))

		var thirdPopResult string
		thirdPopCmd := getPipelinerCmd(Cmd(&thirdPopResult, "LPOP", key))

		p.flush([]CmdAction{firstPopCmd, pauseCmd, secondPopCmd, thirdPopCmd})

		require.Nil(t, <-firstPopCmd.resCh)
		require.Equal(t, "1", firstPopResult)

		require.Nil(t, <-pauseCmd.resCh)
		require.Equal(t, "OK", pauseResult)

		secondPopErr := <-secondPopCmd.resCh
		require.IsType(t, (*net.OpError)(nil), secondPopErr)
		require.True(t, secondPopErr.(net.Error).Temporary())
		require.True(t, secondPopErr.(net.Error).Timeout())
		assert.Empty(t, secondPopResult)

		thirdPopErr := <-thirdPopCmd.resCh
		require.IsType(t, (*net.OpError)(nil), thirdPopErr)
		require.True(t, thirdPopErr.(net.Error).Temporary())
		require.True(t, thirdPopErr.(net.Error).Timeout())
		assert.Empty(t, thirdPopResult)
	}

	t.Run("Conn", func(t *T) {
		t.Run("NonRecoverableError", func(t *T) {
			conn := dial(dialOpts...)
			defer conn.Close()

			p := newPipeliner(conn, 0, 0, 0)
			defer p.Close()

			testNonRecoverableError(t, p)
		})

		t.Run("Timeout", func(t *T) {
			conn := dial(dialOpts...)
			defer conn.Close()

			p := newPipeliner(conn, 0, 0, 0)
			defer p.Close()

			testTimeout(t, p)
		})
	})

	// Pool may have potentially different semantics because it uses ioErrConn
	// directly, so we test it separately.
	t.Run("Pool", func(t *T) {
		poolOpts := []PoolOpt{
			PoolConnFunc(func(string, string) (Conn, error) {
				return dial(dialOpts...), nil
			}),
			PoolPipelineConcurrency(1),
			PoolPipelineWindow(time.Hour, 0),
		}
		t.Run("NonRecoverableError", func(t *T) {
			pool := testPool(1, poolOpts...)
			defer pool.Close()

			testNonRecoverableError(t, pool.pipeliner)
		})

		t.Run("Timeout", func(t *T) {
			pool := testPool(1, poolOpts...)
			defer pool.Close()

			testTimeout(t, pool.pipeliner)
		})
	})
}
<|endoftext|>


<commit_before>package pixelgl

import (
	"fmt"
	"image/color"

	"github.com/faiface/glhf"
	"github.com/faiface/mainthread"
	"github.com/faiface/pixel"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Canvas is an off-screen rectangular BasicTarget and Picture at the same time, that you can draw
// onto.
//
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct {
	gf     *GLFrame
	shader *glhf.Shader

	cmp    pixel.ComposeMethod
	mat    mgl32.Mat3
	col    mgl32.Vec4
	smooth bool
}

var _ pixel.ComposeTarget = (*Canvas)(nil)

// NewCanvas creates a new empty, fully transparent Canvas with given bounds. If the smooth flag is
// set, then stretched Pictures will be smoothed and will not be drawn pixely onto this Canvas.
func NewCanvas(bounds pixel.Rect, smooth bool) *Canvas {
	c := &Canvas{
		gf:     NewGLFrame(bounds),
		mat:    mgl32.Ident3(),
		col:    mgl32.Vec4{1, 1, 1, 1},
		smooth: smooth,
	}

	c.SetBounds(bounds)

	var shader *glhf.Shader
	mainthread.Call(func() {
		var err error
		shader, err = glhf.NewShader(
			canvasVertexFormat,
			canvasUniformFormat,
			canvasVertexShader,
			canvasFragmentShader,
		)
		if err != nil {
			panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader"))
		}
	})
	c.shader = shader

	return c
}

// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
//
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
	return &canvasTriangles{
		GLTriangles: NewGLTriangles(c.shader, t),
		dst:         c,
	}
}

// MakePicture create a specialized copy of the supplied Picture that draws onto this Canvas.
//
// PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
	if cp, ok := p.(*canvasPicture); ok {
		return &canvasPicture{
			GLPicture: cp.GLPicture,
			dst:       c,
		}
	}
	if gp, ok := p.(GLPicture); ok {
		return &canvasPicture{
			GLPicture: gp,
			dst:       c,
		}
	}
	return &canvasPicture{
		GLPicture: NewGLPicture(p),
		dst:       c,
	}
}

// SetMatrix sets a Matrix that every point will be projected by.
func (c *Canvas) SetMatrix(m pixel.Matrix) {
	for i := range m {
		c.mat[i] = float32(m[i])
	}
}

// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
	rgba := pixel.RGBA{R: 1, G: 1, B: 1, A: 1}
	if col != nil {
		rgba = pixel.ToRGBA(col)
	}
	c.col = mgl32.Vec4{
		float32(rgba.R),
		float32(rgba.G),
		float32(rgba.B),
		float32(rgba.A),
	}
}

// SetComposeMethod sets a Porter-Duff composition method to be used in the following draws onto
// this Canvas.
func (c *Canvas) SetComposeMethod(cmp pixel.ComposeMethod) {
	c.cmp = cmp
}

// SetBounds resizes the Canvas to the new bounds. Old content will be preserved.
func (c *Canvas) SetBounds(bounds pixel.Rect) {
	c.gf.SetBounds(bounds)
}

// Bounds returns the rectangular bounds of the Canvas.
func (c *Canvas) Bounds() pixel.Rect {
	return c.gf.Bounds()
}

// SetSmooth sets whether stretched Pictures drawn onto this Canvas should be drawn smooth or
// pixely.
func (c *Canvas) SetSmooth(smooth bool) {
	c.smooth = smooth
}

// Smooth returns whether stretched Pictures drawn onto this Canvas are set to be drawn smooth or
// pixely.
func (c *Canvas) Smooth() bool {
	return c.smooth
}

// must be manually called inside mainthread
func (c *Canvas) setGlhfBounds() {
	bx, by, bw, bh := intBounds(c.gf.Bounds())
	glhf.Bounds(bx, by, bw, bh)
}

// must be manually called inside mainthread
func (c *Canvas) setBlendFunc() {
	switch c.cmp {
	case pixel.ComposeOver:
		glhf.BlendFunc(glhf.One, glhf.OneMinusSrcAlpha)
	case pixel.ComposeIn:
		glhf.BlendFunc(glhf.DstAlpha, glhf.Zero)
	case pixel.ComposeOut:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.Zero)
	case pixel.ComposeAtop:
		glhf.BlendFunc(glhf.DstAlpha, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstOver:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.One)
	case pixel.ComposeDstIn:
		glhf.BlendFunc(glhf.Zero, glhf.SrcAlpha)
	case pixel.ComposeDstOut:
		glhf.BlendFunc(glhf.Zero, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstAtop:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.SrcAlpha)
	case pixel.ComposeXor:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.OneMinusSrcAlpha)
	default:
		panic(errors.New("Canvas: invalid compose method"))
	}
}

// Clear fills the whole Canvas with a single color.
func (c *Canvas) Clear(color color.Color) {
	c.gf.Dirty()

	rgba := pixel.ToRGBA(color)

	// color masking
	rgba = rgba.Mul(pixel.RGBA{
		R: float64(c.col[0]),
		G: float64(c.col[1]),
		B: float64(c.col[2]),
		A: float64(c.col[3]),
	})

	mainthread.CallNonBlock(func() {
		c.setGlhfBounds()
		c.gf.Frame().Begin()
		glhf.Clear(
			float32(rgba.R),
			float32(rgba.G),
			float32(rgba.B),
			float32(rgba.A),
		)
		c.gf.Frame().End()
	})
}

// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
	return c.gf.Color(at)
}

// Texture returns the underlying OpenGL Texture of this Canvas.
//
// Implements GLPicture interface.
func (c *Canvas) Texture() *glhf.Texture {
	return c.gf.Texture()
}

type canvasTriangles struct {
	*GLTriangles
	dst *Canvas
}

func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
	ct.dst.gf.Dirty()

	// save the current state vars to avoid race condition
	mat := ct.dst.mat
	col := ct.dst.col

	mainthread.CallNonBlock(func() {
		ct.dst.setGlhfBounds()
		ct.dst.setBlendFunc()

		frame := ct.dst.gf.Frame()
		shader := ct.dst.shader

		frame.Begin()
		shader.Begin()

		dstBounds := ct.dst.Bounds()
		shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
			float32(dstBounds.Min.X()),
			float32(dstBounds.Min.Y()),
			float32(dstBounds.W()),
			float32(dstBounds.H()),
		})
		shader.SetUniformAttr(canvasTransform, mat)
		shader.SetUniformAttr(canvasColorMask, col)

		if tex == nil {
			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()
		} else {
			tex.Begin()

			bx, by, bw, bh := intBounds(bounds)
			shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
				float32(bx),
				float32(by),
				float32(bw),
				float32(bh),
			})

			if tex.Smooth() != ct.dst.smooth {
				tex.SetSmooth(ct.dst.smooth)
			}

			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()

			tex.End()
		}

		shader.End()
		frame.End()
	})
}

func (ct *canvasTriangles) Draw() {
	ct.draw(nil, pixel.Rect{})
}

type canvasPicture struct {
	GLPicture
	dst *Canvas
}

func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
	ct := t.(*canvasTriangles)
	if cp.dst != ct.dst {
		panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Canvas", cp))
	}
	ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
}

const (
	canvasPosition int = iota
	canvasColor
	canvasTexture
	canvasIntensity
)

var canvasVertexFormat = glhf.AttrFormat{
	canvasPosition:  {Name: "position", Type: glhf.Vec2},
	canvasColor:     {Name: "color", Type: glhf.Vec4},
	canvasTexture:   {Name: "texture", Type: glhf.Vec2},
	canvasIntensity: {Name: "intensity", Type: glhf.Float},
}

const (
	canvasTransform int = iota
	canvasColorMask
	canvasBounds
	canvasTexBounds
)

var canvasUniformFormat = glhf.AttrFormat{
	canvasTransform: {Name: "transform", Type: glhf.Mat3},
	canvasColorMask: {Name: "colorMask", Type: glhf.Vec4},
	canvasBounds:    {Name: "bounds", Type: glhf.Vec4},
	canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4},
}

var canvasVertexShader = `
#version 330 core

in vec2 position;
in vec4 color;
in vec2 texture;
in float intensity;

out vec4 Color;
out vec2 Texture;
out float Intensity;

uniform mat3 transform;
uniform vec4 bounds;

void main() {
	vec2 transPos = (transform * vec3(position, 1.0)).xy;
	vec2 normPos = (transPos - bounds.xy) / (bounds.zw) * 2 - vec2(1, 1);
	gl_Position = vec4(normPos, 0.0, 1.0);
	Color = color;
	Texture = texture;
	Intensity = intensity;
}
`

var canvasFragmentShader = `
#version 330 core

in vec4 Color;
in vec2 Texture;
in float Intensity;

out vec4 color;

uniform vec4 colorMask;
uniform vec4 texBounds;
uniform sampler2D tex;

void main() {
	if (Intensity == 0) {
		color = colorMask * Color;
	} else {
		color = vec4(0, 0, 0, 0);
		color += (1 - Intensity) * Color;
		vec2 t = (Texture - texBounds.xy) / texBounds.zw;
		color += Intensity * Color * texture(tex, t);
		color *= colorMask;
	}
}
`
<commit_msg>fix drawing onto Canvas<commit_after>package pixelgl

import (
	"fmt"
	"image/color"

	"github.com/faiface/glhf"
	"github.com/faiface/mainthread"
	"github.com/faiface/pixel"
	"github.com/go-gl/mathgl/mgl32"
	"github.com/pkg/errors"
)

// Canvas is an off-screen rectangular BasicTarget and Picture at the same time, that you can draw
// onto.
//
// It supports TrianglesPosition, TrianglesColor, TrianglesPicture and PictureColor.
type Canvas struct {
	gf     *GLFrame
	shader *glhf.Shader

	cmp    pixel.ComposeMethod
	mat    mgl32.Mat3
	col    mgl32.Vec4
	smooth bool
}

var _ pixel.ComposeTarget = (*Canvas)(nil)

// NewCanvas creates a new empty, fully transparent Canvas with given bounds. If the smooth flag is
// set, then stretched Pictures will be smoothed and will not be drawn pixely onto this Canvas.
func NewCanvas(bounds pixel.Rect, smooth bool) *Canvas {
	c := &Canvas{
		gf:     NewGLFrame(bounds),
		mat:    mgl32.Ident3(),
		col:    mgl32.Vec4{1, 1, 1, 1},
		smooth: smooth,
	}

	c.SetBounds(bounds)

	var shader *glhf.Shader
	mainthread.Call(func() {
		var err error
		shader, err = glhf.NewShader(
			canvasVertexFormat,
			canvasUniformFormat,
			canvasVertexShader,
			canvasFragmentShader,
		)
		if err != nil {
			panic(errors.Wrap(err, "failed to create Canvas, there's a bug in the shader"))
		}
	})
	c.shader = shader

	return c
}

// MakeTriangles creates a specialized copy of the supplied Triangles that draws onto this Canvas.
//
// TrianglesPosition, TrianglesColor and TrianglesPicture are supported.
func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
	return &canvasTriangles{
		GLTriangles: NewGLTriangles(c.shader, t),
		dst:         c,
	}
}

// MakePicture create a specialized copy of the supplied Picture that draws onto this Canvas.
//
// PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
	if cp, ok := p.(*canvasPicture); ok {
		return &canvasPicture{
			GLPicture: cp.GLPicture,
			dst:       c,
		}
	}
	if gp, ok := p.(GLPicture); ok {
		return &canvasPicture{
			GLPicture: gp,
			dst:       c,
		}
	}
	return &canvasPicture{
		GLPicture: NewGLPicture(p),
		dst:       c,
	}
}

// SetMatrix sets a Matrix that every point will be projected by.
func (c *Canvas) SetMatrix(m pixel.Matrix) {
	for i := range m {
		c.mat[i] = float32(m[i])
	}
}

// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
func (c *Canvas) SetColorMask(col color.Color) {
	rgba := pixel.RGBA{R: 1, G: 1, B: 1, A: 1}
	if col != nil {
		rgba = pixel.ToRGBA(col)
	}
	c.col = mgl32.Vec4{
		float32(rgba.R),
		float32(rgba.G),
		float32(rgba.B),
		float32(rgba.A),
	}
}

// SetComposeMethod sets a Porter-Duff composition method to be used in the following draws onto
// this Canvas.
func (c *Canvas) SetComposeMethod(cmp pixel.ComposeMethod) {
	c.cmp = cmp
}

// SetBounds resizes the Canvas to the new bounds. Old content will be preserved.
func (c *Canvas) SetBounds(bounds pixel.Rect) {
	c.gf.SetBounds(bounds)
}

// Bounds returns the rectangular bounds of the Canvas.
func (c *Canvas) Bounds() pixel.Rect {
	return c.gf.Bounds()
}

// SetSmooth sets whether stretched Pictures drawn onto this Canvas should be drawn smooth or
// pixely.
func (c *Canvas) SetSmooth(smooth bool) {
	c.smooth = smooth
}

// Smooth returns whether stretched Pictures drawn onto this Canvas are set to be drawn smooth or
// pixely.
func (c *Canvas) Smooth() bool {
	return c.smooth
}

// must be manually called inside mainthread
func (c *Canvas) setGlhfBounds() {
	bx, by, bw, bh := intBounds(c.gf.Bounds())
	glhf.Bounds(bx, by, bw, bh)
}

// must be manually called inside mainthread
func setBlendFunc(cmp pixel.ComposeMethod) {
	switch cmp {
	case pixel.ComposeOver:
		glhf.BlendFunc(glhf.One, glhf.OneMinusSrcAlpha)
	case pixel.ComposeIn:
		glhf.BlendFunc(glhf.DstAlpha, glhf.Zero)
	case pixel.ComposeOut:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.Zero)
	case pixel.ComposeAtop:
		glhf.BlendFunc(glhf.DstAlpha, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstOver:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.One)
	case pixel.ComposeDstIn:
		glhf.BlendFunc(glhf.Zero, glhf.SrcAlpha)
	case pixel.ComposeDstOut:
		glhf.BlendFunc(glhf.Zero, glhf.OneMinusSrcAlpha)
	case pixel.ComposeDstAtop:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.SrcAlpha)
	case pixel.ComposeXor:
		glhf.BlendFunc(glhf.OneMinusDstAlpha, glhf.OneMinusSrcAlpha)
	default:
		panic(errors.New("Canvas: invalid compose method"))
	}
}

// Clear fills the whole Canvas with a single color.
func (c *Canvas) Clear(color color.Color) {
	c.gf.Dirty()

	rgba := pixel.ToRGBA(color)

	// color masking
	rgba = rgba.Mul(pixel.RGBA{
		R: float64(c.col[0]),
		G: float64(c.col[1]),
		B: float64(c.col[2]),
		A: float64(c.col[3]),
	})

	mainthread.CallNonBlock(func() {
		c.setGlhfBounds()
		c.gf.Frame().Begin()
		glhf.Clear(
			float32(rgba.R),
			float32(rgba.G),
			float32(rgba.B),
			float32(rgba.A),
		)
		c.gf.Frame().End()
	})
}

// Color returns the color of the pixel over the given position inside the Canvas.
func (c *Canvas) Color(at pixel.Vec) pixel.RGBA {
	return c.gf.Color(at)
}

// Texture returns the underlying OpenGL Texture of this Canvas.
//
// Implements GLPicture interface.
func (c *Canvas) Texture() *glhf.Texture {
	return c.gf.Texture()
}

type canvasTriangles struct {
	*GLTriangles
	dst *Canvas
}

func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
	ct.dst.gf.Dirty()

	// save the current state vars to avoid race condition
	cmp := ct.dst.cmp
	mat := ct.dst.mat
	col := ct.dst.col
	smt := ct.dst.smooth

	mainthread.CallNonBlock(func() {
		ct.dst.setGlhfBounds()
		setBlendFunc(cmp)

		frame := ct.dst.gf.Frame()
		shader := ct.dst.shader

		frame.Begin()
		shader.Begin()

		dstBounds := ct.dst.Bounds()
		shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
			float32(dstBounds.Min.X()),
			float32(dstBounds.Min.Y()),
			float32(dstBounds.W()),
			float32(dstBounds.H()),
		})
		shader.SetUniformAttr(canvasTransform, mat)
		shader.SetUniformAttr(canvasColorMask, col)

		if tex == nil {
			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()
		} else {
			tex.Begin()

			bx, by, bw, bh := intBounds(bounds)
			shader.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
				float32(bx),
				float32(by),
				float32(bw),
				float32(bh),
			})

			if tex.Smooth() != smt {
				tex.SetSmooth(smt)
			}

			ct.vs.Begin()
			ct.vs.Draw()
			ct.vs.End()

			tex.End()
		}

		shader.End()
		frame.End()
	})
}

func (ct *canvasTriangles) Draw() {
	ct.draw(nil, pixel.Rect{})
}

type canvasPicture struct {
	GLPicture
	dst *Canvas
}

func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
	ct := t.(*canvasTriangles)
	if cp.dst != ct.dst {
		panic(fmt.Errorf("(%T).Draw: TargetTriangles generated by different Canvas", cp))
	}
	ct.draw(cp.GLPicture.Texture(), cp.GLPicture.Bounds())
}

const (
	canvasPosition int = iota
	canvasColor
	canvasTexture
	canvasIntensity
)

var canvasVertexFormat = glhf.AttrFormat{
	canvasPosition:  {Name: "position", Type: glhf.Vec2},
	canvasColor:     {Name: "color", Type: glhf.Vec4},
	canvasTexture:   {Name: "texture", Type: glhf.Vec2},
	canvasIntensity: {Name: "intensity", Type: glhf.Float},
}

const (
	canvasTransform int = iota
	canvasColorMask
	canvasBounds
	canvasTexBounds
)

var canvasUniformFormat = glhf.AttrFormat{
	canvasTransform: {Name: "transform", Type: glhf.Mat3},
	canvasColorMask: {Name: "colorMask", Type: glhf.Vec4},
	canvasBounds:    {Name: "bounds", Type: glhf.Vec4},
	canvasTexBounds: {Name: "texBounds", Type: glhf.Vec4},
}

var canvasVertexShader = `
#version 330 core

in vec2 position;
in vec4 color;
in vec2 texture;
in float intensity;

out vec4 Color;
out vec2 Texture;
out float Intensity;

uniform mat3 transform;
uniform vec4 bounds;

void main() {
	vec2 transPos = (transform * vec3(position, 1.0)).xy;
	vec2 normPos = (transPos - bounds.xy) / (bounds.zw) * 2 - vec2(1, 1);
	gl_Position = vec4(normPos, 0.0, 1.0);
	Color = color;
	Texture = texture;
	Intensity = intensity;
}
`

var canvasFragmentShader = `
#version 330 core

in vec4 Color;
in vec2 Texture;
in float Intensity;

out vec4 color;

uniform vec4 colorMask;
uniform vec4 texBounds;
uniform sampler2D tex;

void main() {
	if (Intensity == 0) {
		color = colorMask * Color;
	} else {
		color = vec4(0, 0, 0, 0);
		color += (1 - Intensity) * Color;
		vec2 t = (Texture - texBounds.xy) / texBounds.zw;
		color += Intensity * Color * texture(tex, t);
		color *= colorMask;
	}
}
`
<|endoftext|>


<commit_before>// Copyright 2015 Davis Webb
// Copyright 2015 Luke Shumaker

package store

import (
	"fmt"
	"github.com/jinzhu/gorm"
	he "httpentity"
	"httpentity/util"
	"io"
	"strings"
)

var _ he.Entity = &Group{}
var _ he.NetEntity = &Group{}
var dirGroups he.Entity = newDirGroups()

// Model /////////////////////////////////////////////////////////////

type Group struct {
	Id        string
	Addresses []GroupAddress
}

func (o Group) schema(db *gorm.DB) {
	db.CreateTable(&o)
}

type GroupAddress struct {
	Id      int64
	GroupId string
	Medium  string
	Address string
}

func (o GroupAddress) schema(db *gorm.DB) {
	table := db.CreateTable(&o)
	table.AddForeignKey("group_id", "groups(id)", "RESTRICT", "RESTRICT")
	table.AddForeignKey("medium", "media(id)", "RESTRICT", "RESTRICT")
	table.AddUniqueIndex("uniqueness_idx", "medium", "address")
}

func GetGroupById(db *gorm.DB, id string) *Group {
	var o Group
	if result := db.First(&o, "id = ?", id); result.Error != nil {
		if result.RecordNotFound() {
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func GetGroupByAddress(db *gorm.DB, medium string, address string) *Group {
	panic("TODO: ORM")
}

func getGroupAddressesByMedium(db *gorm.DB, medium string) *GroupAddress {
	var o GroupAddress
	if result := db.Where("medium =?", medium).Find(&o); result.Error != nil {
		if result.RecordNotFound(){
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func NewGroup(db *gorm.DB, name string) *Group {
	o := Group{Id: name}
	if err := db.Create(&o).Error; err != nil {
		panic(err)
	}
	return &o
}

func (o *Group) Subentity(name string, req he.Request) he.Entity {
	panic("TODO: API: (*Group).Subentity()")
}

func (o *Group) Methods() map[string]func(he.Request) he.Response {
	return map[string]func(he.Request) he.Response{
		"GET": func(req he.Request) he.Response {
			// TODO: permission check
			return req.StatusOK(o)
		},
		"PUT": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"PUT\"]")
		},
		"PATCH": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"PATCH\"]")
		},
		"DELETE": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"DELETE\"]")
		},
	}
}

// View //////////////////////////////////////////////////////////////

func (o *Group) Encoders() map[string]func(io.Writer) error {
	return defaultEncoders(o)
}

// Directory ("Controller") //////////////////////////////////////////

type t_dirGroups struct {
	methods map[string]func(he.Request) he.Response
}

func newDirGroups() t_dirGroups {
	r := t_dirGroups{}
	r.methods = map[string]func(he.Request) he.Response{
		"POST": func(req he.Request) he.Response {
			db := req.Things["db"].(*gorm.DB)
			badbody := req.StatusBadRequest(heutil.NetString(fmt.Sprintf("submitted body not what expected")))
			hash, ok := req.Entity.(map[string]interface{}); if !ok { return badbody }
			groupname, ok := hash["groupname"].(string)    ; if !ok { return badbody }

			groupname = strings.ToLower(groupname)

			group := NewGroup(db, groupname)
			if group == nil {
				return req.StatusConflict(heutil.NetString("a group with that name already exists"))
			} else {
				return req.StatusCreated(r, groupname)
			}
		},
	}
	return r
}

func (d t_dirGroups) Methods() map[string]func(he.Request) he.Response {
	return d.methods
}

func (d t_dirGroups) Subentity(name string, req he.Request) he.Entity {
	db := req.Things["db"].(*gorm.DB)
	return GetGroupById(db, name)
}
<commit_msg>DavisLWebb & guntasgrewal: GetGroupAddressesByMedium<commit_after>// Copyright 2015 Davis Webb
// Copyright 2015 Luke Shumaker
// Copyright 2015 Guntas Grewal

package store

import (
	"fmt"
	"github.com/jinzhu/gorm"
	he "httpentity"
	"httpentity/util"
	"io"
	"strings"
)

var _ he.Entity = &Group{}
var _ he.NetEntity = &Group{}
var dirGroups he.Entity = newDirGroups()

// Model /////////////////////////////////////////////////////////////

type Group struct {
	Id        string
	Addresses []GroupAddress
}

func (o Group) schema(db *gorm.DB) {
	db.CreateTable(&o)
}

type GroupAddress struct {
	Id      int64
	GroupId string
	Medium  string
	Address string
}

func (o GroupAddress) schema(db *gorm.DB) {
	table := db.CreateTable(&o)
	table.AddForeignKey("group_id", "groups(id)", "RESTRICT", "RESTRICT")
	table.AddForeignKey("medium", "media(id)", "RESTRICT", "RESTRICT")
	table.AddUniqueIndex("uniqueness_idx", "medium", "address")
}

func GetGroupById(db *gorm.DB, id string) *Group {
	var o Group
	if result := db.First(&o, "id = ?", id); result.Error != nil {
		if result.RecordNotFound() {
			return nil
		}
		panic(result.Error)
	}
	return &o
}

// NOT TESTED
func GetGroupByAddress(db *gorm.DB, medium string, address string) *Group {
	var o Group
	if result := db.Where("address =?", medium).Find(&o); result.Error != nil {
		if result.RecordNotFound(){
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func getGroupAddressesByMedium(db *gorm.DB, medium string, groupId string) *GroupAddress {
	var o GroupAddress
	if result := db.Where("medium =? and group_id =?", medium, groupId).Find(&o); result.Error != nil {
		if result.RecordNotFound(){
			return nil
		}
		panic(result.Error)
	}
	return &o
}

func NewGroup(db *gorm.DB, name string) *Group {
	o := Group{Id: name}
	if err := db.Create(&o).Error; err != nil {
		panic(err)
	}
	return &o
}

func (o *Group) Subentity(name string, req he.Request) he.Entity {
	panic("TODO: API: (*Group).Subentity()")
}

func (o *Group) Methods() map[string]func(he.Request) he.Response {
	return map[string]func(he.Request) he.Response{
		"GET": func(req he.Request) he.Response {
			// TODO: permission check
			return req.StatusOK(o)
		},
		"PUT": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"PUT\"]")
		},
		"PATCH": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"PATCH\"]")
		},
		"DELETE": func(req he.Request) he.Response {
			panic("TODO: API: (*Group).Methods()[\"DELETE\"]")
		},
	}
}

// View //////////////////////////////////////////////////////////////

func (o *Group) Encoders() map[string]func(io.Writer) error {
	return defaultEncoders(o)
}

// Directory ("Controller") //////////////////////////////////////////

type t_dirGroups struct {
	methods map[string]func(he.Request) he.Response
}

func newDirGroups() t_dirGroups {
	r := t_dirGroups{}
	r.methods = map[string]func(he.Request) he.Response{
		"POST": func(req he.Request) he.Response {
			db := req.Things["db"].(*gorm.DB)
			badbody := req.StatusBadRequest(heutil.NetString(fmt.Sprintf("submitted body not what expected")))
			hash, ok := req.Entity.(map[string]interface{}); if !ok { return badbody }
			groupname, ok := hash["groupname"].(string)    ; if !ok { return badbody }

			groupname = strings.ToLower(groupname)

			group := NewGroup(db, groupname)
			if group == nil {
				return req.StatusConflict(heutil.NetString("a group with that name already exists"))
			} else {
				return req.StatusCreated(r, groupname)
			}
		},
	}
	return r
}

func (d t_dirGroups) Methods() map[string]func(he.Request) he.Response {
	return d.methods
}

func (d t_dirGroups) Subentity(name string, req he.Request) he.Entity {
	db := req.Things["db"].(*gorm.DB)
	return GetGroupById(db, name)
}
<|endoftext|>