<commit_before>package commands

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"time"

	"github.com/argoproj/gitops-engine/pkg/diff"
	"github.com/argoproj/gitops-engine/pkg/utils/errors"
	"github.com/argoproj/gitops-engine/pkg/utils/kube"
	"github.com/ghodss/yaml"
	"github.com/spf13/cobra"
	apiv1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	kubecache "k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/argoproj/argo-cd/common"
	"github.com/argoproj/argo-cd/controller"
	"github.com/argoproj/argo-cd/controller/cache"
	"github.com/argoproj/argo-cd/controller/metrics"
	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
	appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
	appinformers "github.com/argoproj/argo-cd/pkg/client/informers/externalversions"
	"github.com/argoproj/argo-cd/reposerver/apiclient"
	"github.com/argoproj/argo-cd/util/cli"
	"github.com/argoproj/argo-cd/util/config"
	"github.com/argoproj/argo-cd/util/db"
	kubeutil "github.com/argoproj/argo-cd/util/kube"
	"github.com/argoproj/argo-cd/util/settings"
)

func NewAppsCommand() *cobra.Command {
	var command = &cobra.Command{
		Use: "apps",
		Run: func(c *cobra.Command, args []string) {
			c.HelpFunc()(c, args)
		},
	}

	command.AddCommand(NewReconcileCommand())
	command.AddCommand(NewDiffReconcileResults())
	return command
}

type appReconcileResult struct {
	Name       string                          `json:"name"`
	Health     *v1alpha1.HealthStatus          `json:"health"`
	Sync       *v1alpha1.SyncStatus            `json:"sync"`
	Conditions []v1alpha1.ApplicationCondition `json:"conditions"`
}

type reconcileResults struct {
	Applications []appReconcileResult `json:"applications"`
}

func (r *reconcileResults) getAppsMap() map[string]appReconcileResult {
	res := map[string]appReconcileResult{}
	for i := range r.Applications {
		res[r.Applications[i].Name] = r.Applications[i]
	}
	return res
}

func printLine(format string, a ...interface{}) {
	_, _ = fmt.Printf(format+"\n", a...)
}

func NewDiffReconcileResults() *cobra.Command {
	var command = &cobra.Command{
		Use:   "diff-reconcile-results PATH1 PATH2",
		Short: "Compare results of two reconciliations and print diff.",
		Run: func(c *cobra.Command, args []string) {
			if len(args) != 2 {
				c.HelpFunc()(c, args)
				os.Exit(1)
			}

			path1 := args[0]
			path2 := args[1]
			var res1 reconcileResults
			var res2 reconcileResults
			errors.CheckError(config.UnmarshalLocalFile(path1, &res1))
			errors.CheckError(config.UnmarshalLocalFile(path2, &res2))
			errors.CheckError(diffReconcileResults(res1, res2))
		},
	}

	return command
}

func toUnstructured(val interface{}) (*unstructured.Unstructured, error) {
	data, err := json.Marshal(val)
	if err != nil {
		return nil, err
	}
	res := make(map[string]interface{})
	err = json.Unmarshal(data, &res)
	if err != nil {
		return nil, err
	}
	return &unstructured.Unstructured{Object: res}, nil
}

type diffPair struct {
	name   string
	first  *unstructured.Unstructured
	second *unstructured.Unstructured
}

func diffReconcileResults(res1 reconcileResults, res2 reconcileResults) error {
	var pairs []diffPair
	resMap1 := res1.getAppsMap()
	resMap2 := res2.getAppsMap()
	for k, v := range resMap1 {
		firstUn, err := toUnstructured(v)
		if err != nil {
			return err
		}
		var secondUn *unstructured.Unstructured
		second, ok := resMap2[k]
		if ok {
			secondUn, err = toUnstructured(second)
			if err != nil {
				return err
			}
			delete(resMap2, k)
		}
		pairs = append(pairs, diffPair{name: k, first: firstUn, second: secondUn})
	}
	for k, v := range resMap2 {
		secondUn, err := toUnstructured(v)
		if err != nil {
			return err
		}
		pairs = append(pairs, diffPair{name: k, first: nil, second: secondUn})
	}
	for _, item := range pairs {
		printLine(item.name)
		_ = diff.PrintDiff(item.name, item.first, item.second)
	}

	return nil
}

func NewReconcileCommand() *cobra.Command {
	var (
		clientConfig      clientcmd.ClientConfig
		selector          string
		repoServerAddress string
		outputFormat      string
		refresh           bool
	)

	var command = &cobra.Command{
		Use:   "get-reconcile-results PATH",
		Short: "Reconcile all applications and stores reconciliation summary in the specified file.",
		Run: func(c *cobra.Command, args []string) {
			// get rid of logging error handler
			runtime.ErrorHandlers = runtime.ErrorHandlers[1:]

			if len(args) != 1 {
				c.HelpFunc()(c, args)
				os.Exit(1)
			}
			outputPath := args[0]

			errors.CheckError(os.Setenv(common.EnvVarFakeInClusterConfig, "true"))
			cfg, err := clientConfig.ClientConfig()
			errors.CheckError(err)
			namespace, _, err := clientConfig.Namespace()
			errors.CheckError(err)

			var result []appReconcileResult
			if refresh {
				if repoServerAddress == "" {
					printLine("Repo server is not provided, trying to port-forward to argocd-repo-server pod.")
					repoServerPort, err := kubeutil.PortForward("app.kubernetes.io/name=argocd-repo-server", 8081, namespace)
					errors.CheckError(err)
					repoServerAddress = fmt.Sprintf("localhost:%d", repoServerPort)
				}
				repoServerClient := apiclient.NewRepoServerClientset(repoServerAddress, 60)

				appClientset := appclientset.NewForConfigOrDie(cfg)
				kubeClientset := kubernetes.NewForConfigOrDie(cfg)
				result, err = reconcileApplications(kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache)
				errors.CheckError(err)
			} else {
				appClientset := appclientset.NewForConfigOrDie(cfg)
				result, err = getReconcileResults(appClientset, namespace, selector)
			}

			errors.CheckError(saveToFile(err, outputFormat, reconcileResults{Applications: result}, outputPath))
		},
	}
	clientConfig = cli.AddKubectlFlagsToCmd(command)
	command.Flags().StringVar(&repoServerAddress, "repo-server", "", "Repo server address.")
	command.Flags().StringVar(&selector, "l", "", "Label selector")
	command.Flags().StringVar(&outputFormat, "o", "yaml", "Output format (yaml|json)")
	command.Flags().BoolVar(&refresh, "refresh", false, "If set to true then recalculates apps reconciliation")

	return command
}

func saveToFile(err error, outputFormat string, result reconcileResults, outputPath string) error {
	errors.CheckError(err)
	var data []byte
	switch outputFormat {
	case "yaml":
		if data, err = yaml.Marshal(result); err != nil {
			return err
		}
	case "json":
		if data, err = json.Marshal(result); err != nil {
			return err
		}
	default:
		return fmt.Errorf("format %s is not supported", outputFormat)
	}

	return ioutil.WriteFile(outputPath, data, 0644)
}

func getReconcileResults(appClientset appclientset.Interface, namespace string, selector string) ([]appReconcileResult, error) {
	appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(v1.ListOptions{LabelSelector: selector})
	if err != nil {
		return nil, err
	}

	var items []appReconcileResult
	for _, app := range appsList.Items {
		items = append(items, appReconcileResult{
			Name:       app.Name,
			Conditions: app.Status.Conditions,
			Health:     &app.Status.Health,
			Sync:       &app.Status.Sync,
		})
	}
	return items, nil
}

func reconcileApplications(
	kubeClientset kubernetes.Interface,
	appClientset appclientset.Interface,
	namespace string,
	repoServerClient apiclient.Clientset,
	selector string,
	createLiveStateCache func(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache,
) ([]appReconcileResult, error) {

	settingsMgr := settings.NewSettingsManager(context.Background(), kubeClientset, namespace)
	argoDB := db.NewDB(namespace, settingsMgr, kubeClientset)
	appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
		appClientset,
		1*time.Hour,
		namespace,
		func(options *v1.ListOptions) {},
	)

	appInformer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
	projInformer := appInformerFactory.Argoproj().V1alpha1().AppProjects().Informer()
	go appInformer.Run(context.Background().Done())
	go projInformer.Run(context.Background().Done())
	if !kubecache.WaitForCacheSync(context.Background().Done(), appInformer.HasSynced, projInformer.HasSynced) {
		return nil, fmt.Errorf("failed to sync cache")
	}

	appLister := appInformerFactory.Argoproj().V1alpha1().Applications().Lister()
	projLister := appInformerFactory.Argoproj().V1alpha1().AppProjects().Lister()
	server := metrics.NewMetricsServer("", appLister, func() error {
		return nil
	})
	stateCache := createLiveStateCache(argoDB, appInformer, settingsMgr, server)
	if err := stateCache.Init(); err != nil {
		return nil, err
	}

	appStateManager := controller.NewAppStateManager(
		argoDB, appClientset, repoServerClient, namespace, &kube.KubectlCmd{}, settingsMgr, stateCache, projInformer, server)

	appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(v1.ListOptions{LabelSelector: selector})
	if err != nil {
		return nil, err
	}

	sort.Slice(appsList.Items, func(i, j int) bool {
		return appsList.Items[i].Spec.Destination.Server < appsList.Items[j].Spec.Destination.Server
	})

	var items []appReconcileResult
	prevServer := ""
	for _, app := range appsList.Items {
		if prevServer != app.Spec.Destination.Server {
			if prevServer != "" {
				if clusterCache, err := stateCache.GetClusterCache(prevServer); err == nil {
					clusterCache.Invalidate()
				}
			}
			printLine("Reconciling apps of %s", app.Spec.Destination.Server)
			prevServer = app.Spec.Destination.Server
		}
		printLine(app.Name)

		proj, err := projLister.AppProjects(namespace).Get(app.Spec.Project)
		if err != nil {
			return nil, err
		}

		res := appStateManager.CompareAppState(&app, proj, app.Spec.Source.TargetRevision, app.Spec.Source, false, nil)
		items = append(items, appReconcileResult{
			Name:       app.Name,
			Conditions: app.Status.Conditions,
			Health:     res.GetHealthStatus(),
			Sync:       res.GetSyncStatus(),
		})
	}
	return items, nil
}

func newLiveStateCache(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache {
	return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, &kube.KubectlCmd{}, server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {})
}
<commit_msg>fix: argocd-util diff-reconcile-results should print app reconcile results sorted by app name (#3972)<commit_after>package commands

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"time"

	"github.com/argoproj/gitops-engine/pkg/diff"
	"github.com/argoproj/gitops-engine/pkg/utils/errors"
	"github.com/argoproj/gitops-engine/pkg/utils/kube"
	"github.com/ghodss/yaml"
	"github.com/spf13/cobra"
	apiv1 "k8s.io/api/core/v1"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/client-go/kubernetes"
	kubecache "k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/argoproj/argo-cd/common"
	"github.com/argoproj/argo-cd/controller"
	"github.com/argoproj/argo-cd/controller/cache"
	"github.com/argoproj/argo-cd/controller/metrics"
	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
	appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
	appinformers "github.com/argoproj/argo-cd/pkg/client/informers/externalversions"
	"github.com/argoproj/argo-cd/reposerver/apiclient"
	"github.com/argoproj/argo-cd/util/cli"
	"github.com/argoproj/argo-cd/util/config"
	"github.com/argoproj/argo-cd/util/db"
	kubeutil "github.com/argoproj/argo-cd/util/kube"
	"github.com/argoproj/argo-cd/util/settings"
)

func NewAppsCommand() *cobra.Command {
	var command = &cobra.Command{
		Use: "apps",
		Run: func(c *cobra.Command, args []string) {
			c.HelpFunc()(c, args)
		},
	}

	command.AddCommand(NewReconcileCommand())
	command.AddCommand(NewDiffReconcileResults())
	return command
}

type appReconcileResult struct {
	Name       string                          `json:"name"`
	Health     *v1alpha1.HealthStatus          `json:"health"`
	Sync       *v1alpha1.SyncStatus            `json:"sync"`
	Conditions []v1alpha1.ApplicationCondition `json:"conditions"`
}

type reconcileResults struct {
	Applications []appReconcileResult `json:"applications"`
}

func (r *reconcileResults) getAppsMap() map[string]appReconcileResult {
	res := map[string]appReconcileResult{}
	for i := range r.Applications {
		res[r.Applications[i].Name] = r.Applications[i]
	}
	return res
}

func printLine(format string, a ...interface{}) {
	_, _ = fmt.Printf(format+"\n", a...)
}

func NewDiffReconcileResults() *cobra.Command {
	var command = &cobra.Command{
		Use:   "diff-reconcile-results PATH1 PATH2",
		Short: "Compare results of two reconciliations and print diff.",
		Run: func(c *cobra.Command, args []string) {
			if len(args) != 2 {
				c.HelpFunc()(c, args)
				os.Exit(1)
			}

			path1 := args[0]
			path2 := args[1]
			var res1 reconcileResults
			var res2 reconcileResults
			errors.CheckError(config.UnmarshalLocalFile(path1, &res1))
			errors.CheckError(config.UnmarshalLocalFile(path2, &res2))
			errors.CheckError(diffReconcileResults(res1, res2))
		},
	}

	return command
}

func toUnstructured(val interface{}) (*unstructured.Unstructured, error) {
	data, err := json.Marshal(val)
	if err != nil {
		return nil, err
	}
	res := make(map[string]interface{})
	err = json.Unmarshal(data, &res)
	if err != nil {
		return nil, err
	}
	return &unstructured.Unstructured{Object: res}, nil
}

type diffPair struct {
	name   string
	first  *unstructured.Unstructured
	second *unstructured.Unstructured
}

func diffReconcileResults(res1 reconcileResults, res2 reconcileResults) error {
	var pairs []diffPair
	resMap1 := res1.getAppsMap()
	resMap2 := res2.getAppsMap()
	for k, v := range resMap1 {
		firstUn, err := toUnstructured(v)
		if err != nil {
			return err
		}
		var secondUn *unstructured.Unstructured
		second, ok := resMap2[k]
		if ok {
			secondUn, err = toUnstructured(second)
			if err != nil {
				return err
			}
			delete(resMap2, k)
		}
		pairs = append(pairs, diffPair{name: k, first: firstUn, second: secondUn})
	}
	for k, v := range resMap2 {
		secondUn, err := toUnstructured(v)
		if err != nil {
			return err
		}
		pairs = append(pairs, diffPair{name: k, first: nil, second: secondUn})
	}
	sort.Slice(pairs, func(i, j int) bool {
		return pairs[i].name < pairs[j].name
	})
	for _, item := range pairs {
		printLine(item.name)
		_ = diff.PrintDiff(item.name, item.first, item.second)
	}

	return nil
}

func NewReconcileCommand() *cobra.Command {
	var (
		clientConfig      clientcmd.ClientConfig
		selector          string
		repoServerAddress string
		outputFormat      string
		refresh           bool
	)

	var command = &cobra.Command{
		Use:   "get-reconcile-results PATH",
		Short: "Reconcile all applications and stores reconciliation summary in the specified file.",
		Run: func(c *cobra.Command, args []string) {
			// get rid of logging error handler
			runtime.ErrorHandlers = runtime.ErrorHandlers[1:]

			if len(args) != 1 {
				c.HelpFunc()(c, args)
				os.Exit(1)
			}
			outputPath := args[0]

			errors.CheckError(os.Setenv(common.EnvVarFakeInClusterConfig, "true"))
			cfg, err := clientConfig.ClientConfig()
			errors.CheckError(err)
			namespace, _, err := clientConfig.Namespace()
			errors.CheckError(err)

			var result []appReconcileResult
			if refresh {
				if repoServerAddress == "" {
					printLine("Repo server is not provided, trying to port-forward to argocd-repo-server pod.")
					repoServerPort, err := kubeutil.PortForward("app.kubernetes.io/name=argocd-repo-server", 8081, namespace)
					errors.CheckError(err)
					repoServerAddress = fmt.Sprintf("localhost:%d", repoServerPort)
				}
				repoServerClient := apiclient.NewRepoServerClientset(repoServerAddress, 60)

				appClientset := appclientset.NewForConfigOrDie(cfg)
				kubeClientset := kubernetes.NewForConfigOrDie(cfg)
				result, err = reconcileApplications(kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache)
				errors.CheckError(err)
			} else {
				appClientset := appclientset.NewForConfigOrDie(cfg)
				result, err = getReconcileResults(appClientset, namespace, selector)
			}

			errors.CheckError(saveToFile(err, outputFormat, reconcileResults{Applications: result}, outputPath))
		},
	}
	clientConfig = cli.AddKubectlFlagsToCmd(command)
	command.Flags().StringVar(&repoServerAddress, "repo-server", "", "Repo server address.")
	command.Flags().StringVar(&selector, "l", "", "Label selector")
	command.Flags().StringVar(&outputFormat, "o", "yaml", "Output format (yaml|json)")
	command.Flags().BoolVar(&refresh, "refresh", false, "If set to true then recalculates apps reconciliation")

	return command
}

func saveToFile(err error, outputFormat string, result reconcileResults, outputPath string) error {
	errors.CheckError(err)
	var data []byte
	switch outputFormat {
	case "yaml":
		if data, err = yaml.Marshal(result); err != nil {
			return err
		}
	case "json":
		if data, err = json.Marshal(result); err != nil {
			return err
		}
	default:
		return fmt.Errorf("format %s is not supported", outputFormat)
	}

	return ioutil.WriteFile(outputPath, data, 0644)
}

func getReconcileResults(appClientset appclientset.Interface, namespace string, selector string) ([]appReconcileResult, error) {
	appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(v1.ListOptions{LabelSelector: selector})
	if err != nil {
		return nil, err
	}

	var items []appReconcileResult
	for _, app := range appsList.Items {
		items = append(items, appReconcileResult{
			Name:       app.Name,
			Conditions: app.Status.Conditions,
			Health:     &app.Status.Health,
			Sync:       &app.Status.Sync,
		})
	}
	return items, nil
}

func reconcileApplications(
	kubeClientset kubernetes.Interface,
	appClientset appclientset.Interface,
	namespace string,
	repoServerClient apiclient.Clientset,
	selector string,
	createLiveStateCache func(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache,
) ([]appReconcileResult, error) {

	settingsMgr := settings.NewSettingsManager(context.Background(), kubeClientset, namespace)
	argoDB := db.NewDB(namespace, settingsMgr, kubeClientset)
	appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
		appClientset,
		1*time.Hour,
		namespace,
		func(options *v1.ListOptions) {},
	)

	appInformer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
	projInformer := appInformerFactory.Argoproj().V1alpha1().AppProjects().Informer()
	go appInformer.Run(context.Background().Done())
	go projInformer.Run(context.Background().Done())
	if !kubecache.WaitForCacheSync(context.Background().Done(), appInformer.HasSynced, projInformer.HasSynced) {
		return nil, fmt.Errorf("failed to sync cache")
	}

	appLister := appInformerFactory.Argoproj().V1alpha1().Applications().Lister()
	projLister := appInformerFactory.Argoproj().V1alpha1().AppProjects().Lister()
	server := metrics.NewMetricsServer("", appLister, func() error {
		return nil
	})
	stateCache := createLiveStateCache(argoDB, appInformer, settingsMgr, server)
	if err := stateCache.Init(); err != nil {
		return nil, err
	}

	appStateManager := controller.NewAppStateManager(
		argoDB, appClientset, repoServerClient, namespace, &kube.KubectlCmd{}, settingsMgr, stateCache, projInformer, server)

	appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(v1.ListOptions{LabelSelector: selector})
	if err != nil {
		return nil, err
	}

	sort.Slice(appsList.Items, func(i, j int) bool {
		return appsList.Items[i].Spec.Destination.Server < appsList.Items[j].Spec.Destination.Server
	})

	var items []appReconcileResult
	prevServer := ""
	for _, app := range appsList.Items {
		if prevServer != app.Spec.Destination.Server {
			if prevServer != "" {
				if clusterCache, err := stateCache.GetClusterCache(prevServer); err == nil {
					clusterCache.Invalidate()
				}
			}
			printLine("Reconciling apps of %s", app.Spec.Destination.Server)
			prevServer = app.Spec.Destination.Server
		}
		printLine(app.Name)

		proj, err := projLister.AppProjects(namespace).Get(app.Spec.Project)
		if err != nil {
			return nil, err
		}

		res := appStateManager.CompareAppState(&app, proj, app.Spec.Source.TargetRevision, app.Spec.Source, false, nil)
		items = append(items, appReconcileResult{
			Name:       app.Name,
			Conditions: app.Status.Conditions,
			Health:     res.GetHealthStatus(),
			Sync:       res.GetSyncStatus(),
		})
	}
	return items, nil
}

func newLiveStateCache(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache {
	return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, &kube.KubectlCmd{}, server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {})
}
<|endoftext|>


<commit_before>package graphql

import (
	"context"
	"fmt"

	"github.com/graphql-go/graphql/gqlerrors"
	"github.com/graphql-go/graphql/language/parser"
	"github.com/graphql-go/graphql/language/source"
)

// SubscribeParams parameters for subscribing
type SubscribeParams struct {
	Schema        Schema
	RequestString string
	RootValue     interface{}
	// ContextValue    context.Context
	VariableValues  map[string]interface{}
	OperationName   string
	FieldResolver   FieldResolveFn
	FieldSubscriber FieldResolveFn
}

// Subscribe performs a subscribe operation on the given query and schema
// To finish a subscription you can simply close the channel from inside the `Subscribe` function
// currently does not support extensions hooks
func Subscribe(p Params) chan *Result {

	source := source.NewSource(&source.Source{
		Body: []byte(p.RequestString),
		Name: "GraphQL request",
	})

	// TODO run extensions hooks

	// parse the source
	AST, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {

		// merge the errors from extensions and the original error from parser
		return sendOneResultAndClose(&Result{
			Errors: gqlerrors.FormatErrors(err),
		})
	}

	// validate document
	validationResult := ValidateDocument(&p.Schema, AST, nil)

	if !validationResult.IsValid {
		// run validation finish functions for extensions
		return sendOneResultAndClose(&Result{
			Errors: validationResult.Errors,
		})

	}
	return ExecuteSubscription(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           AST,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}

func sendOneResultAndClose(res *Result) chan *Result {
	resultChannel := make(chan *Result, 1)
	resultChannel <- res
	close(resultChannel)
	return resultChannel
}

// ExecuteSubscription is similar to graphql.Execute but returns a channel instead of a Result
// currently does not support extensions
func ExecuteSubscription(p ExecuteParams) chan *Result {

	if p.Context == nil {
		p.Context = context.Background()
	}

	var mapSourceToResponse = func(payload interface{}) *Result {
		return Execute(ExecuteParams{
			Schema:        p.Schema,
			Root:          payload,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})
	}
	var resultChannel = make(chan *Result)
	go func() {
		defer close(resultChannel)
		defer func() {
			if err := recover(); err != nil {
				e, ok := err.(error)
				if !ok {
					fmt.Println("strange program path")
					return
				}
				resultChannel <- &Result{
					Errors: gqlerrors.FormatErrors(e),
				}
			}
			return
		}()

		exeContext, err := buildExecutionContext(buildExecutionCtxParams{
			Schema:        p.Schema,
			Root:          p.Root,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})

		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		operationType, err := getOperationRootType(p.Schema, exeContext.Operation)
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		fields := collectFields(collectFieldsParams{
			ExeContext:   exeContext,
			RuntimeType:  operationType,
			SelectionSet: exeContext.Operation.GetSelectionSet(),
		})

		responseNames := []string{}
		for name := range fields {
			responseNames = append(responseNames, name)
		}
		responseName := responseNames[0]
		fieldNodes := fields[responseName]
		fieldNode := fieldNodes[0]
		fieldName := fieldNode.Name.Value
		fieldDef := getFieldDef(p.Schema, operationType, fieldName)

		if fieldDef == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription field %q is not defined", fieldName)),
			}

			return
		}

		resolveFn := fieldDef.Subscribe

		if resolveFn == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription function %q is not defined", fieldName)),
			}
			return
		}
		fieldPath := &ResponsePath{
			Key: responseName,
		}

		args := getArgumentValues(fieldDef.Args, fieldNode.Arguments, exeContext.VariableValues)
		info := ResolveInfo{
			FieldName:      fieldName,
			FieldASTs:      fieldNodes,
			Path:           fieldPath,
			ReturnType:     fieldDef.Type,
			ParentType:     operationType,
			Schema:         p.Schema,
			Fragments:      exeContext.Fragments,
			RootValue:      exeContext.Root,
			Operation:      exeContext.Operation,
			VariableValues: exeContext.VariableValues,
		}

		fieldResult, err := resolveFn(ResolveParams{
			Source:  p.Root,
			Args:    args,
			Info:    info,
			Context: p.Context,
		})
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		if fieldResult == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("no field result")),
			}

			return
		}

		switch fieldResult.(type) {
		case chan interface{}:
			sub := fieldResult.(chan interface{})
			for {
				select {
				case <-p.Context.Done():
					return

				case res, more := <-sub:
					if !more {
						return
					}
					resultChannel <- mapSourceToResponse(res)
				}
			}
		default:
			resultChannel <- mapSourceToResponse(fieldResult)
			return
		}
	}()

	// return a result channel
	return resultChannel
}
<commit_msg>subscription: removed a print<commit_after>package graphql

import (
	"context"
	"fmt"

	"github.com/graphql-go/graphql/gqlerrors"
	"github.com/graphql-go/graphql/language/parser"
	"github.com/graphql-go/graphql/language/source"
)

// SubscribeParams parameters for subscribing
type SubscribeParams struct {
	Schema        Schema
	RequestString string
	RootValue     interface{}
	// ContextValue    context.Context
	VariableValues  map[string]interface{}
	OperationName   string
	FieldResolver   FieldResolveFn
	FieldSubscriber FieldResolveFn
}

// Subscribe performs a subscribe operation on the given query and schema
// To finish a subscription you can simply close the channel from inside the `Subscribe` function
// currently does not support extensions hooks
func Subscribe(p Params) chan *Result {

	source := source.NewSource(&source.Source{
		Body: []byte(p.RequestString),
		Name: "GraphQL request",
	})

	// TODO run extensions hooks

	// parse the source
	AST, err := parser.Parse(parser.ParseParams{Source: source})
	if err != nil {

		// merge the errors from extensions and the original error from parser
		return sendOneResultAndClose(&Result{
			Errors: gqlerrors.FormatErrors(err),
		})
	}

	// validate document
	validationResult := ValidateDocument(&p.Schema, AST, nil)

	if !validationResult.IsValid {
		// run validation finish functions for extensions
		return sendOneResultAndClose(&Result{
			Errors: validationResult.Errors,
		})

	}
	return ExecuteSubscription(ExecuteParams{
		Schema:        p.Schema,
		Root:          p.RootObject,
		AST:           AST,
		OperationName: p.OperationName,
		Args:          p.VariableValues,
		Context:       p.Context,
	})
}

func sendOneResultAndClose(res *Result) chan *Result {
	resultChannel := make(chan *Result, 1)
	resultChannel <- res
	close(resultChannel)
	return resultChannel
}

// ExecuteSubscription is similar to graphql.Execute but returns a channel instead of a Result
// currently does not support extensions
func ExecuteSubscription(p ExecuteParams) chan *Result {

	if p.Context == nil {
		p.Context = context.Background()
	}

	var mapSourceToResponse = func(payload interface{}) *Result {
		return Execute(ExecuteParams{
			Schema:        p.Schema,
			Root:          payload,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})
	}
	var resultChannel = make(chan *Result)
	go func() {
		defer close(resultChannel)
		defer func() {
			if err := recover(); err != nil {
				e, ok := err.(error)
				if !ok {
					return
				}
				resultChannel <- &Result{
					Errors: gqlerrors.FormatErrors(e),
				}
			}
			return
		}()

		exeContext, err := buildExecutionContext(buildExecutionCtxParams{
			Schema:        p.Schema,
			Root:          p.Root,
			AST:           p.AST,
			OperationName: p.OperationName,
			Args:          p.Args,
			Context:       p.Context,
		})

		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		operationType, err := getOperationRootType(p.Schema, exeContext.Operation)
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		fields := collectFields(collectFieldsParams{
			ExeContext:   exeContext,
			RuntimeType:  operationType,
			SelectionSet: exeContext.Operation.GetSelectionSet(),
		})

		responseNames := []string{}
		for name := range fields {
			responseNames = append(responseNames, name)
		}
		responseName := responseNames[0]
		fieldNodes := fields[responseName]
		fieldNode := fieldNodes[0]
		fieldName := fieldNode.Name.Value
		fieldDef := getFieldDef(p.Schema, operationType, fieldName)

		if fieldDef == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription field %q is not defined", fieldName)),
			}

			return
		}

		resolveFn := fieldDef.Subscribe

		if resolveFn == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("the subscription function %q is not defined", fieldName)),
			}
			return
		}
		fieldPath := &ResponsePath{
			Key: responseName,
		}

		args := getArgumentValues(fieldDef.Args, fieldNode.Arguments, exeContext.VariableValues)
		info := ResolveInfo{
			FieldName:      fieldName,
			FieldASTs:      fieldNodes,
			Path:           fieldPath,
			ReturnType:     fieldDef.Type,
			ParentType:     operationType,
			Schema:         p.Schema,
			Fragments:      exeContext.Fragments,
			RootValue:      exeContext.Root,
			Operation:      exeContext.Operation,
			VariableValues: exeContext.VariableValues,
		}

		fieldResult, err := resolveFn(ResolveParams{
			Source:  p.Root,
			Args:    args,
			Info:    info,
			Context: p.Context,
		})
		if err != nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(err),
			}

			return
		}

		if fieldResult == nil {
			resultChannel <- &Result{
				Errors: gqlerrors.FormatErrors(fmt.Errorf("no field result")),
			}

			return
		}

		switch fieldResult.(type) {
		case chan interface{}:
			sub := fieldResult.(chan interface{})
			for {
				select {
				case <-p.Context.Done():
					return

				case res, more := <-sub:
					if !more {
						return
					}
					resultChannel <- mapSourceToResponse(res)
				}
			}
		default:
			resultChannel <- mapSourceToResponse(fieldResult)
			return
		}
	}()

	// return a result channel
	return resultChannel
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "flag"
    "log"
    "runtime"
    "strconv"
    "functorama.com/demo/libgodelbrot"
)

// Golang entry point
func main() {
    // Set number of cores
    runtime.GOMAXPROCS(runtime.NumCPU())

    args := parseArguments()
    request, argErr := extractRenderParameters(args)
    if argErr != nil {
        log.Fatal("Error:", argErr)
    }

    info, godelErr := libgodelbrot.AutoConf(request)

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

    text, jsonErr := libgodelbrot.ToJSON(info)
    if jsonErr == nil {
        fmt.Printf("%s", text)
    } else {
        log.Fatal("Error creating JSON:", jsonErr)
    }
}

// Structure representing our command line arguments
type commandLine struct {
    iterateLimit   uint
    divergeLimit   float64
    width          uint
    height         uint
    realMin        string
    realMax        string
    imagMin        string
    imagMax        string
    mode           string
    regionCollapse uint
    jobs  uint
    fixAspect      bool
    numerics string
    glitchSamples uint
    precision uint
}

// Parse command line arguments into a `commandLine' structure
func parseArguments() commandLine {
    args := commandLine{}

    components := []float64{
        real(libgodelbrot.MandelbrotMin),
        imag(libgodelbrot.MandelbrotMin),
        real(libgodelbrot.MandelbrotMax),
        imag(libgodelbrot.MandelbrotMax),
    }
    bounds := make([]string, len(components))
    for i, num := range components {
        bounds[i] = strconv.FormatFloat(num, 'e', -1, 64)
    }

    renderThreads := uint(runtime.NumCPU()) + 1

    flag.UintVar(&args.iterateLimit, "iterateLimit",
        uint(libgodelbrot.DefaultIterations), "Maximum number of iterations")
    flag.Float64Var(&args.divergeLimit, "divergeLimit",
        libgodelbrot.DefaultDivergeLimit, "Limit where function is said to diverge to infinity")
    flag.UintVar(&args.width, "imageWidth",
        libgodelbrot.DefaultImageWidth, "Width of output PNG")
    flag.UintVar(&args.height, "imageHeight",
        libgodelbrot.DefaultImageHeight, "Height of output PNG")
    flag.StringVar(&args.realMin, "realMin",
        bounds[0], "Leftmost position on complex plane")
    flag.StringVar(&args.imagMin, "imagMin",
        bounds[1], "Bottommost position on complex plane")
    flag.StringVar(&args.realMax, "realMax",
        bounds[2], "Rightmost position on complex plane")
    flag.StringVar(&args.imagMax, "imagMax",
        bounds[3], "Topmost position on complex plane")
    flag.StringVar(&args.mode, "mode", "auto",
        "Render mode.  (auto|sequence|region|concurrent)")
    flag.UintVar(&args.regionCollapse, "collapse",
        libgodelbrot.DefaultCollapse, "Pixel width of region at which sequential render is forced")
    flag.UintVar(&args.jobs, "jobs",
        renderThreads, "Number of rendering threads in concurrent renderer")
    flag.UintVar(&args.glitchSamples, "regionGlitchSamples",
        libgodelbrot.DefaultGlitchSamples, "Size of region render glitch-correncting sample set")
    flag.UintVar(&args.precision, "prec",
        libgodelbrot.DefaultPrecision, "Precision for big.Float render mode")
    flag.StringVar(&args.numerics, "numerics",
        "auto", "Numerical system (auto|native|bigfloat)")
    flag.BoolVar(&args.fixAspect, "fixAspect",
        true, "Resize plane window to fit image aspect ratio")
    flag.Parse()

    return args
}

// Validate and extract a render description from the command line arguments
func extractRenderParameters(args commandLine) (*libgodelbrot.Request, error) {
    const max8 = uint(^uint8(0))
    if args.iterateLimit > max8 {
        return nil, fmt.Errorf("iterateLimit out of bounds.  Valid values in range (0,%v)", max8)
    }

    if args.divergeLimit <= 0.0 {
        return nil, fmt.Errorf("divergeLimit out of bounds.  Valid values in range (0,)")
    }

    const max16 = uint(^uint16(0))
    if args.jobs > max16 {
        return nil, fmt.Errorf("jobs out of bounds.  Valid values in range (0,%v)", max16)
    }

    numerics := libgodelbrot.AutoDetectNumericsMode
    switch args.numerics {
    case "auto":
        // No change
    case "bigfloat":
        numerics = libgodelbrot.BigFloatNumericsMode
    case "native":
        numerics = libgodelbrot.NativeNumericsMode
    default:
        log.Fatal("Unknown numerics mode:", args.numerics)
    }

    renderer := libgodelbrot.AutoDetectRenderMode
    switch args.mode {
    case "auto":
        // No change
    case "sequence":
        renderer = libgodelbrot.SequenceRenderMode
    case "region":
        renderer = libgodelbrot.RegionRenderMode
    case "concurrent":
        renderer = libgodelbrot.SharedRegionRenderMode
    default:
        log.Fatal("Unknown render mode:", args.mode)
    }

    description := &libgodelbrot.Request {
        IterateLimit: uint8(args.iterateLimit),
        DivergeLimit: args.divergeLimit,
        GlitchSamples: args.glitchSamples,
        RealMin: args.realMin,
        RealMax: args.realMax,
        ImagMin: args.imagMin,
        ImagMax: args.imagMax,
        ImageWidth: args.width,
        ImageHeight: args.height,
        FixAspect: args.fixAspect,
        Numerics: numerics,
        Renderer: renderer,
        RegionCollapse: args.regionCollapse,
        Jobs: uint16(args.jobs),
    }

    return description, nil
}<commit_msg>Configbrot now reconfigures all parameters<commit_after>package main

import (
    "fmt"
    "flag"
    "log"
    "runtime"
    "strconv"
    "os"
    "functorama.com/demo/libgodelbrot"
)

// Structure representing our command line arguments
type commandLine struct {
    iterateLimit   uint
    divergeLimit   float64
    width          uint
    height         uint
    realMin        string
    realMax        string
    imagMin        string
    imagMax        string
    mode           string
    regionCollapse uint
    jobs  uint
    fixAspect      bool
    numerics string
    glitchSamples uint
    precision uint
    reconfigure bool
    palette string
}

// Parse command line arguments into a `commandLine' structure
func parseArguments() commandLine {
    args := commandLine{}

    components := []float64{
        real(libgodelbrot.MandelbrotMin),
        imag(libgodelbrot.MandelbrotMin),
        real(libgodelbrot.MandelbrotMax),
        imag(libgodelbrot.MandelbrotMax),
    }
    bounds := make([]string, len(components))
    for i, num := range components {
        bounds[i] = strconv.FormatFloat(num, 'e', -1, 64)
    }

    renderThreads := uint(runtime.NumCPU()) + 1

    flag.UintVar(&args.iterateLimit, "iterlim",
        uint(libgodelbrot.DefaultIterations), "Maximum number of iterations")
    flag.Float64Var(&args.divergeLimit, "divlim",
        libgodelbrot.DefaultDivergeLimit, "Limit where function is said to diverge to infinity")
    flag.UintVar(&args.width, "width",
        libgodelbrot.DefaultImageWidth, "Width of output PNG")
    flag.UintVar(&args.height, "height",
        libgodelbrot.DefaultImageHeight, "Height of output PNG")
    flag.StringVar(&args.realMin, "rmin",
        bounds[0], "Leftmost position on complex plane")
    flag.StringVar(&args.imagMin, "imin",
        bounds[1], "Bottommost position on complex plane")
    flag.StringVar(&args.realMax, "rmax",
        bounds[2], "Rightmost position on complex plane")
    flag.StringVar(&args.imagMax, "imax",
        bounds[3], "Topmost position on complex plane")
    flag.StringVar(&args.mode, "render", "auto",
        "Render mode.  (auto|sequence|region|concurrent)")
    flag.UintVar(&args.regionCollapse, "collapse",
        libgodelbrot.DefaultCollapse, "Pixel width of region at which sequential render is forced")
    flag.UintVar(&args.jobs, "jobs",
        renderThreads, "Number of rendering threads in concurrent renderer")
    flag.UintVar(&args.glitchSamples, "regionGlitchSamples",
        libgodelbrot.DefaultRegionSamples, "Size of region sample set")
    flag.UintVar(&args.precision, "prec",
        libgodelbrot.DefaultPrecision, "Precision for big.Float render mode")
    flag.StringVar(&args.numerics, "numerics",
        "auto", "Numerical system (auto|native|bigfloat)")
    flag.StringVar(&args.palette, "palette", "grayscale", "(redscale|grayscale|pretty)")
    flag.BoolVar(&args.fixAspect, "fix", true, "Resize plane window to fit image aspect ratio")
    flag.BoolVar(&args.reconfigure, "reconf", false,
        "Reconfigure the render spec sent to stdin")
    flag.Parse()

    return args
}

// Validate and extract a render description from the command line arguments
func newRequest(args commandLine) (*libgodelbrot.Request, error) {
    user, uerr := userReq(args)

    if uerr != nil {
        return nil, uerr
    }

    var req *libgodelbrot.Request
    if args.reconfigure {
        desc, rerr := libgodelbrot.ReadInfo(os.Stdin)
        if rerr != nil {
            return nil, rerr
        }
        req = &desc.UserRequest
    } else {
        req = libgodelbrot.DefaultRequest()
    }

    argact := map[string]func(){
        "fix": func () {req.FixAspect = user.FixAspect},
        "palette": func () {req.PaletteCode = user.PaletteCode},
        "numerics": func () {req.Numerics = user.Numerics},
        "prec": func () {req.Precision = user.Precision},
        "jobs": func () {req.Jobs = user.Jobs},
        "collapse": func () {req.RegionCollapse = user.RegionCollapse},
        "render": func () {req.Renderer = user.Renderer},
        "iterlim": func () {req.IterateLimit = user.IterateLimit},
        "divlim": func () {req.DivergeLimit = user.DivergeLimit},
        "width": func () {req.ImageWidth = user.ImageWidth},
        "height": func () {req.ImageHeight = user.ImageHeight},
        "rmin": func () {req.RealMin = user.RealMin},
        "rmax": func () {req.RealMax = user.RealMax},
        "imin": func () {req.ImagMin = user.ImagMin},
        "imax": func () {req.ImagMax = user.ImagMax},
    }

    flag.Visit(func (fl *flag.Flag) {
        act := argact[fl.Name]
        if act == nil {
            log.Fatal("BUG: unknown action ", fl.Name)
        }
        act()
    })

    return req, nil
}

func userReq(args commandLine) (*libgodelbrot.Request, error) {
    const max8 = uint(^uint8(0))
    if args.iterateLimit > max8 {
        return nil, fmt.Errorf("iterateLimit out of bounds.  Valid values in range (0,%v)", max8)
    }

    if args.divergeLimit <= 0.0 {
        return nil, fmt.Errorf("divergeLimit out of bounds.  Valid values in range (0,)")
    }

    const max16 = uint(^uint16(0))
    if args.jobs > max16 {
        return nil, fmt.Errorf("jobs out of bounds.  Valid values in range (0,%v)", max16)
    }

    numerics := libgodelbrot.AutoDetectNumericsMode
    switch args.numerics {
    case "auto":
        // No change
    case "bigfloat":
        numerics = libgodelbrot.BigFloatNumericsMode
    case "native":
        numerics = libgodelbrot.NativeNumericsMode
    default:
        return nil, fmt.Errorf("Unknown numerics mode: %v", args.numerics)
    }

    renderer := libgodelbrot.AutoDetectRenderMode
    switch args.mode {
    case "auto":
        // No change
    case "sequence":
        renderer = libgodelbrot.SequenceRenderMode
    case "region":
        renderer = libgodelbrot.RegionRenderMode
    case "concurrent":
        renderer = libgodelbrot.SharedRegionRenderMode
    default:
        return nil, fmt.Errorf("Unknown render mode: %v", args.mode)
    }

    req := &libgodelbrot.Request{}
    req.IterateLimit = uint8(args.iterateLimit)
    req.DivergeLimit = args.divergeLimit
    req.RealMin = args.realMin
    req.RealMax = args.realMax
    req.ImagMin = args.imagMin
    req.ImagMax = args.imagMax
    req.ImageWidth = args.width
    req.ImageHeight = args.height
    req.PaletteCode = args.palette
    req.FixAspect = args.fixAspect
    req.Renderer = renderer
    req.Numerics = numerics
    req.Jobs = uint16(args.jobs)
    req.RegionCollapse = args.regionCollapse
    req.RegionSamples = args.glitchSamples
    req.Precision = args.precision

    return req, nil
}

func main() {
    // Set number of cores
    runtime.GOMAXPROCS(runtime.NumCPU())

    output := os.Stdout

    args := parseArguments()
    req, inerr := newRequest(args)
    if inerr != nil {
        log.Fatal("Error forming request:", inerr)
    }

    desc, gerr := libgodelbrot.Configure(req)

    if gerr != nil {
        log.Fatal("Error configuring Info:", gerr)
    }

    outerr := libgodelbrot.WriteInfo(output, desc)
    if outerr != nil {
        log.Fatal("Error writing Info:", outerr)
    }
}<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"html"
	"log"
	"strings"
)

type wsClient struct {
	// The underlying gorilla websocket connection
	wsConnection *websocket.Conn

	// Messages intended for this client
	messagesForClient chan []byte

	// The user's id - from the database somehow
	userId int64
}

func (client *wsClient) readMessageLoop(someLobby *lobby) {
	// When our connection exits, we want to close the connection and deregister with the lobby
	// A connection exit may be e.g. a timeout
	var deregisterFunction = func() {
		someLobby.deregister <- client
		client.wsConnection.Close()
	}
	defer deregisterFunction()

	// Infinite loop
	for {
		_, msg, err := client.wsConnection.ReadMessage()
		if err != nil {
			log.Println("readMessage error:", err)
			return
		}
		incomingMessage := externalMessage{}
		err = json.Unmarshal(msg, &incomingMessage)
		if err != nil {
			log.Println("Error unmarshalling user data:", err)
			continue
		}

		// We don't allow blank messages, or messages that are just whitespace
		if strings.TrimSpace(string(incomingMessage.MessageText)) == "" {
			log.Println("Rejecting message from " + string(client.userId) + " because it contains only whitespace. ")
			continue
		}

		// Escape HTML in case the users are being nasty
		incomingMessage.MessageText = html.EscapeString(string(incomingMessage.MessageText))
		incomingMessage.MessageDisplayName = html.EscapeString(string(incomingMessage.MessageDisplayName))

		if incomingMessage.MessageDisplayName == "__ADMIN__" {
			// Don't allow the users to us magic username
			log.Println("Rejecting message from", client.userId, "because it used the magic admin username. ")
			continue
		}

		// This replaces the internal database ID with our custom ID, that is incremented
		// per room, instead of globally

		// It is unclear if there is a use of the unique global ID.
		messageId := someLobby.getNextMessageId()

		if strings.HasPrefix(incomingMessage.MessageText, "/star ") {
			messageToStar := strings.TrimPrefix(incomingMessage.MessageText, "/star ")
			go someLobby.sendStar(messageToStar, client.userId, messageId)
			// TODO: Fix this code duplication
			_, err = db.Exec("UPDATE lobbies SET last_message_id = ? WHERE id = ?", messageId, someLobby.channelId)
			// Continue because we don't want to send this message out on the channel
			continue
		}

		_, err = db.Exec("INSERT INTO messages(id, channel_id, message_text, channel_msg_id, author_display_name, author_id) VALUES(?, ?, ?, ?, ?, ?)", nil, someLobby.channelId, incomingMessage.MessageText, messageId, incomingMessage.MessageDisplayName, client.userId)
		if err != nil {
			log.Println("Error recording message to database", err)
		}

		_, err = db.Exec("UPDATE lobbies SET last_message_id = ? WHERE id = ?", messageId, someLobby.channelId)

		if strings.HasPrefix(incomingMessage.MessageText, "/gif ") {
			desiredGif := strings.TrimPrefix(incomingMessage.MessageText, "/gif ")
			go someLobby.sendGiphy(desiredGif, incomingMessage.MessageDisplayName, client.userId, messageId)
			// Continue because we don't want to send this message out on the channel
			continue
		}

		// TODO: Do magic with Slack commands

		go someLobby.linkifyMessage(incomingMessage.MessageText, client.userId, incomingMessage.MessageDisplayName, messageId)
	}

}

func (client *wsClient) writeMessageLoop(someLobby *lobby) {
	defer client.wsConnection.Close()
	// Infinite loop
	for {
		msg := <-client.messagesForClient
		err := client.wsConnection.WriteMessage(websocket.TextMessage, msg)
		if err != nil {
			log.Println("Error sending message:", err)
			// Connection gets closed automatically
			return
		}
	}
}
<commit_msg>Fix log statement<commit_after>package main

import (
	"encoding/json"
	"github.com/gorilla/websocket"
	"html"
	"log"
	"strings"
)

type wsClient struct {
	// The underlying gorilla websocket connection
	wsConnection *websocket.Conn

	// Messages intended for this client
	messagesForClient chan []byte

	// The user's id - from the database somehow
	userId int64
}

func (client *wsClient) readMessageLoop(someLobby *lobby) {
	// When our connection exits, we want to close the connection and deregister with the lobby
	// A connection exit may be e.g. a timeout
	var deregisterFunction = func() {
		someLobby.deregister <- client
		client.wsConnection.Close()
	}
	defer deregisterFunction()

	// Infinite loop
	for {
		_, msg, err := client.wsConnection.ReadMessage()
		if err != nil {
			log.Println("readMessage error:", err)
			return
		}
		incomingMessage := externalMessage{}
		err = json.Unmarshal(msg, &incomingMessage)
		if err != nil {
			log.Println("Error unmarshalling user data:", err)
			continue
		}

		// We don't allow blank messages, or messages that are just whitespace
		if strings.TrimSpace(string(incomingMessage.MessageText)) == "" {
			log.Println("Rejecting message from", client.userId, "because it contains only whitespace. ")
			continue
		}

		// Escape HTML in case the users are being nasty
		incomingMessage.MessageText = html.EscapeString(string(incomingMessage.MessageText))
		incomingMessage.MessageDisplayName = html.EscapeString(string(incomingMessage.MessageDisplayName))

		if incomingMessage.MessageDisplayName == "__ADMIN__" {
			// Don't allow the users to us magic username
			log.Println("Rejecting message from", client.userId, "because it used the magic admin username. ")
			continue
		}

		// This replaces the internal database ID with our custom ID, that is incremented
		// per room, instead of globally

		// It is unclear if there is a use of the unique global ID.
		messageId := someLobby.getNextMessageId()

		if strings.HasPrefix(incomingMessage.MessageText, "/star ") {
			messageToStar := strings.TrimPrefix(incomingMessage.MessageText, "/star ")
			go someLobby.sendStar(messageToStar, client.userId, messageId)
			// TODO: Fix this code duplication
			_, err = db.Exec("UPDATE lobbies SET last_message_id = ? WHERE id = ?", messageId, someLobby.channelId)
			// Continue because we don't want to send this message out on the channel
			continue
		}

		_, err = db.Exec("INSERT INTO messages(id, channel_id, message_text, channel_msg_id, author_display_name, author_id) VALUES(?, ?, ?, ?, ?, ?)", nil, someLobby.channelId, incomingMessage.MessageText, messageId, incomingMessage.MessageDisplayName, client.userId)
		if err != nil {
			log.Println("Error recording message to database", err)
		}

		_, err = db.Exec("UPDATE lobbies SET last_message_id = ? WHERE id = ?", messageId, someLobby.channelId)

		if strings.HasPrefix(incomingMessage.MessageText, "/gif ") {
			desiredGif := strings.TrimPrefix(incomingMessage.MessageText, "/gif ")
			go someLobby.sendGiphy(desiredGif, incomingMessage.MessageDisplayName, client.userId, messageId)
			// Continue because we don't want to send this message out on the channel
			continue
		}

		// TODO: Do magic with Slack commands

		go someLobby.linkifyMessage(incomingMessage.MessageText, client.userId, incomingMessage.MessageDisplayName, messageId)
	}

}

func (client *wsClient) writeMessageLoop(someLobby *lobby) {
	defer client.wsConnection.Close()
	// Infinite loop
	for {
		msg := <-client.messagesForClient
		err := client.wsConnection.WriteMessage(websocket.TextMessage, msg)
		if err != nil {
			log.Println("Error sending message:", err)
			// Connection gets closed automatically
			return
		}
	}
}
<|endoftext|>


<commit_before>package dirstructure

import (
	"fmt"
	"os"
	"path/filepath"

	"sphelper/config"
	"sphelper/fileutils"
)

func MkBuilddir(cfg *config.Config, srcbindir string) error {
	// build dir contains the documentation
	if false {
		fmt.Println("xx")
	}

	var err error

	destdir := filepath.Join(cfg.Builddir, "speedata-publisher")
	os.RemoveAll(destdir)
	os.MkdirAll(destdir, 0755)

	srcdir := filepath.Join(cfg.Basedir(), "src")

	mapping := []struct {
		src    string
		dest   string
		reject []string
	}{
		{src: srcbindir, dest: filepath.Join(destdir, "sdluatex")},
		{src: filepath.Join(cfg.Builddir, "manual"), dest: filepath.Join(destdir, "share", "doc")},
		{src: filepath.Join(cfg.Basedir(), "lib"), dest: filepath.Join(destdir, "share", "lib")},
		{src: filepath.Join(cfg.Basedir(), "schema"), dest: filepath.Join(destdir, "share", "schema"), reject: []string{"changelog.rng", "readme.txt"}},
		{src: filepath.Join(cfg.Basedir(), "fonts"), dest: filepath.Join(destdir, "sw", "fonts")},
		{src: filepath.Join(cfg.Basedir(), "img"), dest: filepath.Join(destdir, "sw", "img")},
		{src: filepath.Join(srcdir, "tex"), dest: filepath.Join(destdir, "sw", "tex")},
		{src: filepath.Join(srcdir, "lua"), dest: filepath.Join(destdir, "sw", "lua"), reject: []string{"viznodelist.lua", "fileutils.lua"}},
		{src: filepath.Join(srcdir, "hyphenation"), dest: filepath.Join(destdir, "sw", "hyphenation")},
	}

	for _, v := range mapping {
		reject := append(v.reject, ".DS_Store")
		err = fileutils.CpR(v.src, v.dest, reject...)
		if err != nil {
			return err
		}
	}
	exefiles, err := filepath.Glob(filepath.Join(destdir, "bin", "*"))
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	for _, v := range exefiles {
		os.Chmod(v, 0755)
	}
	return nil
}
<commit_msg>Fix distribution bug: chmod sdluatex not done<commit_after>package dirstructure

import (
	"fmt"
	"os"
	"path/filepath"

	"sphelper/config"
	"sphelper/fileutils"
)

func MkBuilddir(cfg *config.Config, srcbindir string) error {
	// build dir contains the documentation
	if false {
		fmt.Println("xx")
	}

	var err error

	destdir := filepath.Join(cfg.Builddir, "speedata-publisher")
	os.RemoveAll(destdir)
	os.MkdirAll(destdir, 0755)

	srcdir := filepath.Join(cfg.Basedir(), "src")

	mapping := []struct {
		src    string
		dest   string
		reject []string
	}{
		{src: srcbindir, dest: filepath.Join(destdir, "sdluatex")},
		{src: filepath.Join(cfg.Builddir, "manual"), dest: filepath.Join(destdir, "share", "doc")},
		{src: filepath.Join(cfg.Basedir(), "lib"), dest: filepath.Join(destdir, "share", "lib")},
		{src: filepath.Join(cfg.Basedir(), "schema"), dest: filepath.Join(destdir, "share", "schema"), reject: []string{"changelog.rng", "readme.txt"}},
		{src: filepath.Join(cfg.Basedir(), "fonts"), dest: filepath.Join(destdir, "sw", "fonts")},
		{src: filepath.Join(cfg.Basedir(), "img"), dest: filepath.Join(destdir, "sw", "img")},
		{src: filepath.Join(srcdir, "tex"), dest: filepath.Join(destdir, "sw", "tex")},
		{src: filepath.Join(srcdir, "lua"), dest: filepath.Join(destdir, "sw", "lua"), reject: []string{"viznodelist.lua", "fileutils.lua"}},
		{src: filepath.Join(srcdir, "hyphenation"), dest: filepath.Join(destdir, "sw", "hyphenation")},
	}

	for _, v := range mapping {
		reject := append(v.reject, ".DS_Store")
		err = fileutils.CpR(v.src, v.dest, reject...)
		if err != nil {
			return err
		}
	}
	exefiles, err := filepath.Glob(filepath.Join(destdir, "bin", "*"))
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	for _, v := range exefiles {
		os.Chmod(v, 0755)
	}
	exefiles, err = filepath.Glob(filepath.Join(destdir, "sdluatex", "*"))
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	for _, v := range exefiles {
		os.Chmod(v, 0755)
	}
	return nil
}
<|endoftext|>


<commit_before>package dotweb

// Global define
const (
	// Version current version
	Version = "1.6.9"
)

// Log define
const (
	LogTarget_Default        = "dotweb_default"
	LogTarget_HttpRequest    = "dotweb_request"
	LogTarget_HttpServer     = "dotweb_server"
	LogTarget_RequestTimeout = "dotweb_req_timeout"

	LogLevel_Debug = "debug"
	LogLevel_Info  = "info"
	LogLevel_Warn  = "warn"
	LogLevel_Error = "error"
)

// Http define
const (
	CharsetUTF8       = "charset=utf-8"
	DefaultServerName = "dotweb"
)

const (
	Windows = "windows"
	Linux   = "linux"
)

// MIME types
const (
	MIMEApplicationJSON                  = "application/json"
	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + CharsetUTF8
	MIMEApplicationJavaScript            = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + CharsetUTF8
	MIMEApplicationXML                   = "application/xml"
	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + CharsetUTF8
	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf              = "application/protobuf"
	MIMEApplicationMsgpack               = "application/msgpack"
	MIMETextHTML                         = "text/html"
	MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + CharsetUTF8
	MIMETextPlain                        = "text/plain"
	MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + CharsetUTF8
	MIMEMultipartForm                    = "multipart/form-data"
	MIMEOctetStream                      = "application/octet-stream"
)

// Headers
const (
	HeaderAcceptEncoding                = "Accept-Encoding"
	HeaderAllow                         = "Allow"
	HeaderAuthorization                 = "Authorization"
	HeaderContentDisposition            = "Content-Disposition"
	HeaderContentEncoding               = "Content-Encoding"
	HeaderContentLength                 = "Content-Length"
	HeaderContentType                   = "Content-Type"
	HeaderCookie                        = "Cookie"
	HeaderSetCookie                     = "Set-Cookie"
	HeaderIfModifiedSince               = "If-Modified-Since"
	HeaderLastModified                  = "Last-Modified"
	HeaderLocation                      = "Location"
	HeaderUpgrade                       = "Upgrade"
	HeaderVary                          = "Vary"
	HeaderWWWAuthenticate               = "WWW-Authenticate"
	HeaderXRequestedWith                = "X-Requested-With"
	HeaderXForwardedProto               = "X-Forwarded-Proto"
	HeaderXHTTPMethodOverride           = "X-HTTP-Method-Override"
	HeaderXForwardedFor                 = "X-Forwarded-For"
	HeaderXRealIP                       = "X-Real-IP"
	HeaderServer                        = "Server"
	HeaderOrigin                        = "Origin"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
	HeaderP3P                           = "P3P"
	HeaderCacheControl                  = "Cache-control"

	// Security
	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-XSS-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-CSRF-Token"
)

const (
	HeaderRequestID    = "d_request_id"
	HeaderResponseTime = "d_response_time"
)
<commit_msg>#### Version 1.7.0 * New Feature: 新增NotifyPlugin插件，默认集成监控配置文件变化热重启 * New Feature: 新增DotWeb.ReSetConfig用于运行时重载配置 * About NotifyPlugin：     - 通过NewDefaultNotifyPlugin创建默认集成的NotifyPlugin     - 仅当Dotweb通过配置文件启动方式下有效，监测默认的配置文件     - 当热重启配置文件时，Dotweb本身监听端口以及pprod设置不会重载     - 感谢@地蛋对该插件的支持 * 2019-07-22 14:00 at ShangHai<commit_after>package dotweb

// Global define
const (
	// Version current version
	Version = "1.7.0"
)

// Log define
const (
	LogTarget_Default        = "dotweb_default"
	LogTarget_HttpRequest    = "dotweb_request"
	LogTarget_HttpServer     = "dotweb_server"
	LogTarget_RequestTimeout = "dotweb_req_timeout"

	LogLevel_Debug = "debug"
	LogLevel_Info  = "info"
	LogLevel_Warn  = "warn"
	LogLevel_Error = "error"
)

// Http define
const (
	CharsetUTF8       = "charset=utf-8"
	DefaultServerName = "dotweb"
)

const (
	Windows = "windows"
	Linux   = "linux"
)

// MIME types
const (
	MIMEApplicationJSON                  = "application/json"
	MIMEApplicationJSONCharsetUTF8       = MIMEApplicationJSON + "; " + CharsetUTF8
	MIMEApplicationJavaScript            = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + CharsetUTF8
	MIMEApplicationXML                   = "application/xml"
	MIMEApplicationXMLCharsetUTF8        = MIMEApplicationXML + "; " + CharsetUTF8
	MIMEApplicationForm                  = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf              = "application/protobuf"
	MIMEApplicationMsgpack               = "application/msgpack"
	MIMETextHTML                         = "text/html"
	MIMETextHTMLCharsetUTF8              = MIMETextHTML + "; " + CharsetUTF8
	MIMETextPlain                        = "text/plain"
	MIMETextPlainCharsetUTF8             = MIMETextPlain + "; " + CharsetUTF8
	MIMEMultipartForm                    = "multipart/form-data"
	MIMEOctetStream                      = "application/octet-stream"
)

// Headers
const (
	HeaderAcceptEncoding                = "Accept-Encoding"
	HeaderAllow                         = "Allow"
	HeaderAuthorization                 = "Authorization"
	HeaderContentDisposition            = "Content-Disposition"
	HeaderContentEncoding               = "Content-Encoding"
	HeaderContentLength                 = "Content-Length"
	HeaderContentType                   = "Content-Type"
	HeaderCookie                        = "Cookie"
	HeaderSetCookie                     = "Set-Cookie"
	HeaderIfModifiedSince               = "If-Modified-Since"
	HeaderLastModified                  = "Last-Modified"
	HeaderLocation                      = "Location"
	HeaderUpgrade                       = "Upgrade"
	HeaderVary                          = "Vary"
	HeaderWWWAuthenticate               = "WWW-Authenticate"
	HeaderXRequestedWith                = "X-Requested-With"
	HeaderXForwardedProto               = "X-Forwarded-Proto"
	HeaderXHTTPMethodOverride           = "X-HTTP-Method-Override"
	HeaderXForwardedFor                 = "X-Forwarded-For"
	HeaderXRealIP                       = "X-Real-IP"
	HeaderServer                        = "Server"
	HeaderOrigin                        = "Origin"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"
	HeaderP3P                           = "P3P"
	HeaderCacheControl                  = "Cache-control"

	// Security
	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-XSS-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-CSRF-Token"
)

const (
	HeaderRequestID    = "d_request_id"
	HeaderResponseTime = "d_response_time"
)
<|endoftext|>


<commit_before>package protocol

type kafka struct{}

func (k *kafka) Unmarshal(payload []byte) string {
	return ""
}
<commit_msg>WIP: kafka protocol sniffer<commit_after>package protocol

import (
	"encoding/binary"
	"fmt"
)

type kafka struct{}

func (k *kafka) Unmarshal(payload []byte) string {
	// response header
	//================
	// 0-3 message_size
	// 4-7 correlation_id

	// request header
	//===============
	// 0-3 message_size
	// 4-5 api_key
	// 6-7 api_version
	// 8-11 correlation_id
	// 12-13 client_id length
	if len(payload) < 10 {
		return fmt.Sprintf("%+v", payload)
	}

	apiKey := binary.BigEndian.Uint16(payload[4:6])
	switch apiKey {
	case 0: // Produce
	case 1: // Fetch
		apiVersion := binary.BigEndian.Uint16(payload[6:8]) // 0 1 2

		clientIDLen := binary.BigEndian.Uint16(payload[12:14])
		clientID := string(payload[14 : 14+int(clientIDLen)])

		offset := int(clientIDLen + 14)
		// replica:4 max_wait:4 min_bytes:4 topicsN:4
		offset += 4 * 4
		topicLen := binary.BigEndian.Uint16(payload[offset : offset+2])
		offset += 2
		topic := string(payload[offset : offset+int(topicLen)])
		offset += int(topicLen)
		partitionN := int(binary.BigEndian.Uint32(payload[offset : offset+4]))
		offset += 4
		partition := binary.BigEndian.Uint32(payload[offset : offset+4])
		offset += 4
		msgOffset := binary.BigEndian.Uint64(payload[offset : offset+8])
		offset += 8
		maxBytes := binary.BigEndian.Uint32(payload[offset : offset+4])
		return fmt.Sprintf("Fetch-%d[%s/%2d#%d] @%-11d max:%-8d %s",
			apiVersion, topic, partition, partitionN, msgOffset, maxBytes, clientID)

	case 2: // Offsets
	case 3: // Metadata
	case 4: // LeaderAndIsr
	case 5: // StopReplica
	case 6: // UpdateMetadata
	case 7: // ControlledShutdown
	case 8: // OffsetCommit
	case 9: // OffsetFetch
	case 19: // CreateTopics
	case 20: // DeleteTopics
	}

	return ""
}
<|endoftext|>


<commit_before>package copier

import (
	"database/sql"
	"fmt"
	"reflect"
	"strings"
)

// These flags define options for tag handling
const (
	// Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
	tagMust uint8 = 1 << iota

	// Denotes that the program should not panic when the must flag is on and
	// value is not copied. The program will return an error instead.
	tagNoPanic

	// Ignore a destation field from being copied to.
	tagIgnore

	// Denotes that the value as been copied
	hasCopied
)

// Option sets copy options
type Option struct {
	IgnoreEmpty bool
	DeepCopy    bool
}

// Copy copy things
func Copy(toValue interface{}, fromValue interface{}) (err error) {
	return copier(toValue, fromValue, Option{})
}

// CopyWithOption copy with option
func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
	return copier(toValue, fromValue, opt)
}

func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
	var (
		isSlice bool
		amount  = 1
		from    = indirect(reflect.ValueOf(fromValue))
		to      = indirect(reflect.ValueOf(toValue))
	)

	if !to.CanAddr() {
		return ErrInvalidCopyDestination
	}

	// Return is from value is invalid
	if !from.IsValid() {
		return ErrInvalidCopyFrom
	}

	fromType, isPtrFrom := indirectType(from.Type())
	toType, _ := indirectType(to.Type())

	if fromType.Kind() == reflect.Interface {
		fromType = reflect.TypeOf(from.Interface())
	}

	if toType.Kind() == reflect.Interface {
		toType = reflect.TypeOf(to.Interface())
	}

	// Just set it if possible to assign for normal types
	if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
		if !isPtrFrom || !opt.DeepCopy {
			to.Set(from.Convert(to.Type()))
		} else {
			fromCopy := reflect.New(from.Type())
			fromCopy.Set(from.Elem())
			to.Set(fromCopy.Convert(to.Type()))
		}
		return
	}

	if fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
		if !fromType.Key().ConvertibleTo(toType.Key()) {
			return ErrMapKeyNotMatch
		}

		if to.IsNil() {
			to.Set(reflect.MakeMapWithSize(toType, from.Len()))
		}

		for _, k := range from.MapKeys() {
			toKey := indirect(reflect.New(toType.Key()))
			if !set(toKey, k, opt.DeepCopy) {
				return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
			}

			elemType, _ := indirectType(toType.Elem())
			toValue := indirect(reflect.New(elemType))
			if !set(toValue, from.MapIndex(k), opt.DeepCopy) {
				if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
					return err
				}
			}

			for {
				if elemType == toType.Elem() {
					to.SetMapIndex(toKey, toValue)
					break
				}
				elemType = reflect.PtrTo(elemType)
				toValue = toValue.Addr()
			}
		}
		return
	}

	if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice && fromType.ConvertibleTo(toType) {
		if to.IsNil() {
			slice := reflect.MakeSlice(reflect.SliceOf(toType), from.Len(), from.Cap())
			to.Set(slice)
		}
		for i := 0; i < from.Len(); i++ {
			toValue := indirect(reflect.New(toType))
			if !set(toValue, from.Index(i), opt.DeepCopy) {
				err = CopyWithOption(toValue.Addr().Interface(), from.Index(i).Interface(), opt)
				if err != nil {
					continue
				}
			}
			to.Index(i).Set(toValue)
		}
		return
	}

	if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
		// skip not supported type
		return
	}

	if to.Kind() == reflect.Slice {
		isSlice = true
		if from.Kind() == reflect.Slice {
			amount = from.Len()
		}
	}

	for i := 0; i < amount; i++ {
		var dest, source reflect.Value

		if isSlice {
			// source
			if from.Kind() == reflect.Slice {
				source = indirect(from.Index(i))
			} else {
				source = indirect(from)
			}
			// dest
			dest = indirect(reflect.New(toType).Elem())
		} else {
			source = indirect(from)
			dest = indirect(to)
		}

		destKind := dest.Kind()
		initDest := false
		if destKind == reflect.Interface {
			initDest = true
			dest = indirect(reflect.New(toType))
		}

		// Get tag options
		tagBitFlags := map[string]uint8{}
		if dest.IsValid() {
			tagBitFlags = getBitFlags(toType)
		}

		// check source
		if source.IsValid() {
			// Copy from source field to dest field or method
			fromTypeFields := deepFields(fromType)
			for _, field := range fromTypeFields {
				name := field.Name

				// Get bit flags for field
				fieldFlags, _ := tagBitFlags[name]

				// Check if we should ignore copying
				if (fieldFlags & tagIgnore) != 0 {
					continue
				}

				if fromField := source.FieldByName(name); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
					// has field

					// handle anonymous field
					destFieldNotSet := false
					if f, ok := dest.Type().FieldByName(name); ok {
						for _, x := range f.Index {
							destFieldKind := dest.Field(x).Kind()
							if destFieldKind != reflect.Ptr {
								continue
							}

							if !dest.Field(x).IsNil() {
								continue
							}

							if !dest.Field(x).CanSet() {
								destFieldNotSet = true
								break
							}

							newValue := reflect.New(dest.Field(x).Type().Elem())
							dest.Field(x).Set(newValue)
						}
					}

					toField := reflect.Value{}
					if !destFieldNotSet {
						toField = dest.FieldByName(name)
					}
					if toField.IsValid() {
						if toField.CanSet() {
							if !set(toField, fromField, opt.DeepCopy) {
								if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
									return err
								}
							} else {
								if fieldFlags != 0 {
									// Note that a copy was made
									tagBitFlags[name] = fieldFlags | hasCopied
								}
							}
						}
					} else {
						// try to set to method
						var toMethod reflect.Value
						if dest.CanAddr() {
							toMethod = dest.Addr().MethodByName(name)
						} else {
							toMethod = dest.MethodByName(name)
						}

						if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
							toMethod.Call([]reflect.Value{fromField})
						}
					}
				}
			}

			// Copy from from method to dest field
			for _, field := range deepFields(toType) {
				name := field.Name

				var fromMethod reflect.Value
				if source.CanAddr() {
					fromMethod = source.Addr().MethodByName(name)
				} else {
					fromMethod = source.MethodByName(name)
				}

				if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
					if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
						values := fromMethod.Call([]reflect.Value{})
						if len(values) >= 1 {
							set(toField, values[0], opt.DeepCopy)
						}
					}
				}
			}
		}

		if isSlice {
			if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
				to.Set(reflect.Append(to, dest.Addr()))
			} else if dest.Type().AssignableTo(to.Type().Elem()) {
				to.Set(reflect.Append(to, dest))
			}
		} else if initDest {
			to.Set(dest)
		}

		err = checkBitFlags(tagBitFlags)
	}

	return
}

func shouldIgnore(v reflect.Value, ignoreEmpty bool) bool {
	if !ignoreEmpty {
		return false
	}

	return v.IsZero()
}

func deepFields(reflectType reflect.Type) []reflect.StructField {
	if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
		fields := make([]reflect.StructField, 0, reflectType.NumField())

		for i := 0; i < reflectType.NumField(); i++ {
			v := reflectType.Field(i)
			if v.Anonymous {
				fields = append(fields, deepFields(v.Type)...)
			} else {
				fields = append(fields, v)
			}
		}

		return fields
	}

	return nil
}

func indirect(reflectValue reflect.Value) reflect.Value {
	for reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	return reflectValue
}

func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
	for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
		reflectType = reflectType.Elem()
		isPtr = true
	}
	return reflectType, isPtr
}

func set(to, from reflect.Value, deepCopy bool) bool {
	if from.IsValid() {
		if to.Kind() == reflect.Ptr {
			// set `to` to nil if from is nil
			if from.Kind() == reflect.Ptr && from.IsNil() {
				to.Set(reflect.Zero(to.Type()))
				return true
			} else if to.IsNil() {
				to.Set(reflect.New(to.Type().Elem()))
			}
			to = to.Elem()
		}

		if deepCopy {
			toKind := to.Kind()
			if toKind == reflect.Interface && to.IsNil() {
				to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
				toKind = reflect.TypeOf(to.Interface()).Kind()
			}
			if toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice {
				return false
			}
		}

		if from.Type().ConvertibleTo(to.Type()) {
			to.Set(from.Convert(to.Type()))
		} else if scanner, ok := to.Addr().Interface().(sql.Scanner); ok {
			if err := scanner.Scan(from.Interface()); err != nil {
				return false
			}
		} else if from.Kind() == reflect.Ptr {
			return set(to, from.Elem(), deepCopy)
		} else {
			return false
		}
	}

	return true
}

// parseTags Parses struct tags and returns uint8 bit flags.
func parseTags(tag string) (flags uint8) {
	for _, t := range strings.Split(tag, ",") {
		switch t {
		case "-":
			flags = tagIgnore
			return
		case "must":
			flags = flags | tagMust
		case "nopanic":
			flags = flags | tagNoPanic
		}
	}
	return
}

// getBitFlags Parses struct tags for bit flags.
func getBitFlags(toType reflect.Type) map[string]uint8 {
	flags := map[string]uint8{}
	toTypeFields := deepFields(toType)

	// Get a list dest of tags
	for _, field := range toTypeFields {
		tags := field.Tag.Get("copier")
		if tags != "" {
			flags[field.Name] = parseTags(tags)
		}
	}
	return flags
}

// checkBitFlags Checks flags for error or panic conditions.
func checkBitFlags(flagsList map[string]uint8) (err error) {
	// Check flag conditions were met
	for name, flags := range flagsList {
		if flags&hasCopied == 0 {
			switch {
			case flags&tagMust != 0 && flags&tagNoPanic != 0:
				err = fmt.Errorf("Field %s has must tag but was not copied", name)
				return
			case flags&(tagMust) != 0:
				panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
			}
		}
	}
	return
}
<commit_msg>Fix add support for anonymous field<commit_after>package copier

import (
	"database/sql"
	"fmt"
	"reflect"
	"strings"
)

// These flags define options for tag handling
const (
	// Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
	tagMust uint8 = 1 << iota

	// Denotes that the program should not panic when the must flag is on and
	// value is not copied. The program will return an error instead.
	tagNoPanic

	// Ignore a destation field from being copied to.
	tagIgnore

	// Denotes that the value as been copied
	hasCopied
)

// Option sets copy options
type Option struct {
	IgnoreEmpty bool
	DeepCopy    bool
}

// Copy copy things
func Copy(toValue interface{}, fromValue interface{}) (err error) {
	return copier(toValue, fromValue, Option{})
}

// CopyWithOption copy with option
func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
	return copier(toValue, fromValue, opt)
}

func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
	var (
		isSlice bool
		amount  = 1
		from    = indirect(reflect.ValueOf(fromValue))
		to      = indirect(reflect.ValueOf(toValue))
	)

	if !to.CanAddr() {
		return ErrInvalidCopyDestination
	}

	// Return is from value is invalid
	if !from.IsValid() {
		return ErrInvalidCopyFrom
	}

	fromType, isPtrFrom := indirectType(from.Type())
	toType, _ := indirectType(to.Type())

	if fromType.Kind() == reflect.Interface {
		fromType = reflect.TypeOf(from.Interface())
	}

	if toType.Kind() == reflect.Interface {
		toType = reflect.TypeOf(to.Interface())
	}

	// Just set it if possible to assign for normal types
	if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
		if !isPtrFrom || !opt.DeepCopy {
			to.Set(from.Convert(to.Type()))
		} else {
			fromCopy := reflect.New(from.Type())
			fromCopy.Set(from.Elem())
			to.Set(fromCopy.Convert(to.Type()))
		}
		return
	}

	if fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
		if !fromType.Key().ConvertibleTo(toType.Key()) {
			return ErrMapKeyNotMatch
		}

		if to.IsNil() {
			to.Set(reflect.MakeMapWithSize(toType, from.Len()))
		}

		for _, k := range from.MapKeys() {
			toKey := indirect(reflect.New(toType.Key()))
			if !set(toKey, k, opt.DeepCopy) {
				return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
			}

			elemType, _ := indirectType(toType.Elem())
			toValue := indirect(reflect.New(elemType))
			if !set(toValue, from.MapIndex(k), opt.DeepCopy) {
				if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
					return err
				}
			}

			for {
				if elemType == toType.Elem() {
					to.SetMapIndex(toKey, toValue)
					break
				}
				elemType = reflect.PtrTo(elemType)
				toValue = toValue.Addr()
			}
		}
		return
	}

	if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice && fromType.ConvertibleTo(toType) {
		if to.IsNil() {
			slice := reflect.MakeSlice(reflect.SliceOf(toType), from.Len(), from.Cap())
			to.Set(slice)
		}
		for i := 0; i < from.Len(); i++ {
			toValue := indirect(reflect.New(toType))
			if !set(toValue, from.Index(i), opt.DeepCopy) {
				err = CopyWithOption(toValue.Addr().Interface(), from.Index(i).Interface(), opt)
				if err != nil {
					continue
				}
			}
			to.Index(i).Set(toValue)
		}
		return
	}

	if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
		// skip not supported type
		return
	}

	if to.Kind() == reflect.Slice {
		isSlice = true
		if from.Kind() == reflect.Slice {
			amount = from.Len()
		}
	}

	for i := 0; i < amount; i++ {
		var dest, source reflect.Value

		if isSlice {
			// source
			if from.Kind() == reflect.Slice {
				source = indirect(from.Index(i))
			} else {
				source = indirect(from)
			}
			// dest
			dest = indirect(reflect.New(toType).Elem())
		} else {
			source = indirect(from)
			dest = indirect(to)
		}

		destKind := dest.Kind()
		initDest := false
		if destKind == reflect.Interface {
			initDest = true
			dest = indirect(reflect.New(toType))
		}

		// Get tag options
		tagBitFlags := map[string]uint8{}
		if dest.IsValid() {
			tagBitFlags = getBitFlags(toType)
		}

		// check source
		if source.IsValid() {
			// Copy from source field to dest field or method
			fromTypeFields := deepFields(fromType)
			for _, field := range fromTypeFields {
				name := field.Name

				// Get bit flags for field
				fieldFlags, _ := tagBitFlags[name]

				// Check if we should ignore copying
				if (fieldFlags & tagIgnore) != 0 {
					continue
				}

				if fromField := source.FieldByName(name); fromField.IsValid() && !shouldIgnore(fromField, opt.IgnoreEmpty) {
					// process for nested anonymous field
					destFieldNotSet := false
					if f, ok := dest.Type().FieldByName(name); ok {
						for idx, x := range f.Index {
							destFieldKind := dest.Field(x).Kind()
							if destFieldKind != reflect.Ptr {
								continue
							}

							if !dest.Field(x).IsNil() {
								continue
							}

							if !dest.Field(x).CanSet() {
								destFieldNotSet = true
								break
							}

							newValue := reflect.New(dest.FieldByIndex(f.Index[0 : idx+1]).Type().Elem())
							dest.Field(x).Set(newValue)
						}
					}

					if destFieldNotSet {
						break
					}

					toField := dest.FieldByName(name)
					if toField.IsValid() {
						if toField.CanSet() {
							if !set(toField, fromField, opt.DeepCopy) {
								if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
									return err
								}
							} else {
								if fieldFlags != 0 {
									// Note that a copy was made
									tagBitFlags[name] = fieldFlags | hasCopied
								}
							}
						}
					} else {
						// try to set to method
						var toMethod reflect.Value
						if dest.CanAddr() {
							toMethod = dest.Addr().MethodByName(name)
						} else {
							toMethod = dest.MethodByName(name)
						}

						if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
							toMethod.Call([]reflect.Value{fromField})
						}
					}
				}
			}

			// Copy from from method to dest field
			for _, field := range deepFields(toType) {
				name := field.Name

				var fromMethod reflect.Value
				if source.CanAddr() {
					fromMethod = source.Addr().MethodByName(name)
				} else {
					fromMethod = source.MethodByName(name)
				}

				if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, opt.IgnoreEmpty) {
					if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
						values := fromMethod.Call([]reflect.Value{})
						if len(values) >= 1 {
							set(toField, values[0], opt.DeepCopy)
						}
					}
				}
			}
		}

		if isSlice {
			if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
				to.Set(reflect.Append(to, dest.Addr()))
			} else if dest.Type().AssignableTo(to.Type().Elem()) {
				to.Set(reflect.Append(to, dest))
			}
		} else if initDest {
			to.Set(dest)
		}

		err = checkBitFlags(tagBitFlags)
	}

	return
}

func shouldIgnore(v reflect.Value, ignoreEmpty bool) bool {
	if !ignoreEmpty {
		return false
	}

	return v.IsZero()
}

func deepFields(reflectType reflect.Type) []reflect.StructField {
	if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
		fields := make([]reflect.StructField, 0, reflectType.NumField())

		for i := 0; i < reflectType.NumField(); i++ {
			v := reflectType.Field(i)
			if v.Anonymous {
				fields = append(fields, deepFields(v.Type)...)
			} else {
				fields = append(fields, v)
			}
		}

		return fields
	}

	return nil
}

func indirect(reflectValue reflect.Value) reflect.Value {
	for reflectValue.Kind() == reflect.Ptr {
		reflectValue = reflectValue.Elem()
	}
	return reflectValue
}

func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
	for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
		reflectType = reflectType.Elem()
		isPtr = true
	}
	return reflectType, isPtr
}

func set(to, from reflect.Value, deepCopy bool) bool {
	if from.IsValid() {
		if to.Kind() == reflect.Ptr {
			// set `to` to nil if from is nil
			if from.Kind() == reflect.Ptr && from.IsNil() {
				to.Set(reflect.Zero(to.Type()))
				return true
			} else if to.IsNil() {
				to.Set(reflect.New(to.Type().Elem()))
			}
			to = to.Elem()
		}

		if deepCopy {
			toKind := to.Kind()
			if toKind == reflect.Interface && to.IsNil() {
				to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
				toKind = reflect.TypeOf(to.Interface()).Kind()
			}
			if toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice {
				return false
			}
		}

		if from.Type().ConvertibleTo(to.Type()) {
			to.Set(from.Convert(to.Type()))
		} else if scanner, ok := to.Addr().Interface().(sql.Scanner); ok {
			if err := scanner.Scan(from.Interface()); err != nil {
				return false
			}
		} else if from.Kind() == reflect.Ptr {
			return set(to, from.Elem(), deepCopy)
		} else {
			return false
		}
	}

	return true
}

// parseTags Parses struct tags and returns uint8 bit flags.
func parseTags(tag string) (flags uint8) {
	for _, t := range strings.Split(tag, ",") {
		switch t {
		case "-":
			flags = tagIgnore
			return
		case "must":
			flags = flags | tagMust
		case "nopanic":
			flags = flags | tagNoPanic
		}
	}
	return
}

// getBitFlags Parses struct tags for bit flags.
func getBitFlags(toType reflect.Type) map[string]uint8 {
	flags := map[string]uint8{}
	toTypeFields := deepFields(toType)

	// Get a list dest of tags
	for _, field := range toTypeFields {
		tags := field.Tag.Get("copier")
		if tags != "" {
			flags[field.Name] = parseTags(tags)
		}
	}
	return flags
}

// checkBitFlags Checks flags for error or panic conditions.
func checkBitFlags(flagsList map[string]uint8) (err error) {
	// Check flag conditions were met
	for name, flags := range flagsList {
		if flags&hasCopied == 0 {
			switch {
			case flags&tagMust != 0 && flags&tagNoPanic != 0:
				err = fmt.Errorf("Field %s has must tag but was not copied", name)
				return
			case flags&(tagMust) != 0:
				panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"effe/logic"
	"flag"
	"fmt"
	"log/syslog"
	"net/http"
	"sync"
)

type complexContext struct {
	ctx logic.Context
	err error
}

func generateHandler(pool *sync.Pool, logger *syslog.Writer) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := pool.Get().(complexContext)
		defer func() {
			if r := recover(); r != nil {
				w.WriteHeader(http.StatusInternalServerError)
				logger.Crit("Logic Panicked")
			}
		}()
		err := logic.Run(ctx.ctx, ctx.err, w, r)
		if err != nil {
			logger.Debug(err.Error())
		}
		if ctx.err == nil {
			pool.Put(ctx)
		}
	}
}

func main() {
	port := flag.Int("port", 8080, "Port where serve the effe.")
	info := flag.Bool("info", false, "Print the effe information, then exit.")
	flag.Parse()
	if *info {
		fmt.Println(logic.Info)
		return
	}
	url := fmt.Sprintf(":%d", *port)
	logic.Init()
	logger, _ := syslog.New(syslog.LOG_ERR|syslog.LOG_USER, "Logs From Effe ")
	var ctxPool = &sync.Pool{New: func() interface{} {
		ctx, err := logic.Start()
		return complexContext(ctx, err)
	}}
	http.HandleFunc("/", generateHandler(ctxPool, logger))
	http.ListenAndServe(url, nil)
}
<commit_msg>fix directory structure<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/siscia/effe/logic"
	"log/syslog"
	"net/http"
	"sync"
)

type complexContext struct {
	ctx logic.Context
	err error
}

func generateHandler(pool *sync.Pool, logger *syslog.Writer) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		ctx := pool.Get().(complexContext)
		defer func() {
			if r := recover(); r != nil {
				w.WriteHeader(http.StatusInternalServerError)
				logger.Crit("Logic Panicked")
			}
		}()
		err := logic.Run(ctx.ctx, ctx.err, w, r)
		if err != nil {
			logger.Debug(err.Error())
		}
		if ctx.err == nil {
			pool.Put(ctx)
		}
	}
}

func main() {
	port := flag.Int("port", 8080, "Port where serve the effe.")
	info := flag.Bool("info", false, "Print the effe information, then exit.")
	flag.Parse()
	if *info {
		fmt.Println(logic.Info)
		return
	}
	url := fmt.Sprintf(":%d", *port)
	logic.Init()
	logger, _ := syslog.New(syslog.LOG_ERR|syslog.LOG_USER, "Logs From Effe ")
	var ctxPool = &sync.Pool{New: func() interface{} {
		ctx, err := logic.Start()
		return complexContext{ctx, err}
	}}
	http.HandleFunc("/", generateHandler(ctxPool, logger))
	http.ListenAndServe(url, nil)
}
<|endoftext|>