<commit_before>package handler

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/Sirupsen/logrus"
	"github.com/jrperritt/rack/auth"
	"github.com/jrperritt/rack/internal/github.com/codegangsta/cli"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud"
	"github.com/jrperritt/rack/output"
	"github.com/jrperritt/rack/util"
)

// Command is the type that commands have.
type Command struct {
	Ctx *Context
}

// Context is a global context that `rack` uses.
type Context struct {
	// CLIContext is the context that the `cli` library uses. `rack` uses it to
	// access flags.
	CLIContext *cli.Context
	// ServiceClient is the Rackspace service client used to authenticate the user
	// and carry out the requests while processing the command.
	ServiceClient *gophercloud.ServiceClient
	// ServiceClientType is the type of Rackspace service client used (e.g. compute).
	ServiceClientType string
	// WaitGroup is used for synchronizing output.
	WaitGroup *sync.WaitGroup
	// Results is a channel into which commands send results. It allows for streaming
	// output.
	Results chan *Resource
	// OutputFormat is the format in which the user wants the output. This is obtained
	// from the `output` flag and will default to "table" if not provided.
	OutputFormat string
	// Logger is used to log information acquired while processing the command.
	Logger *logrus.Logger
}

// ListenAndReceive creates the Results channel and processes the results that
// come through it before sending them on to `Print`. It is run in a separate
// goroutine from `main`.
func (ctx *Context) ListenAndReceive() {
	ctx.Results = make(chan *Resource)
	go func() {
		for {
			select {
			case resource, ok := <-ctx.Results:

				if !ok {
					ctx.Results = nil
					continue
				}

				if resource.Err != nil {

					ctx.CLIContext.App.Writer = os.Stderr
					resource.Keys = []string{"error"}
					var errorBody string

					switch resource.Err.(type) {

					case *gophercloud.UnexpectedResponseCodeError:
						errBodyRaw := resource.Err.(*gophercloud.UnexpectedResponseCodeError).Body
						errMap := make(map[string]map[string]interface{})
						err := json.Unmarshal(errBodyRaw, &errMap)
						if err != nil {
							errorBody = string(errBodyRaw)
							break
						}
						for _, v := range errMap {
							errorBody = v["message"].(string)
							break
						}

					default:
						errorBody = resource.Err.Error()
					}

					resource.Result = map[string]interface{}{"error": errorBody}
				}

				if resource.Result == nil {
					if args := ctx.CLIContext.Parent().Parent().Args(); len(args) > 0 {
						resource.Result = fmt.Sprintf("Nothing to show. Maybe you'd like to set up some %ss?\n",
							strings.Replace(args[0], "-", " ", -1))
					} else {
						resource.Result = fmt.Sprintf("Nothing to show.\n")
					}
				}

				ctx.Print(resource)
				if resource.ErrExit1 {
					os.Exit(1)
				}
			}
		}
	}()
}

// Print returns the output to the user
func (ctx *Context) Print(resource *Resource) {
	defer ctx.WaitGroup.Done()

	// limit the returned fields if any were given in the `fields` flag
	keys := ctx.limitFields(resource)
	w := ctx.CLIContext.App.Writer

	switch resource.Result.(type) {
	case map[string]interface{}:
		m := resource.Result.(map[string]interface{})
		switch ctx.OutputFormat {
		case "json":
			output.MetadataJSON(w, m, keys)
		case "csv":
			output.MetadataCSV(w, m, keys)
		default:
			output.MetadataTable(w, m, keys)
		}
	case []map[string]interface{}:
		m := resource.Result.([]map[string]interface{})
		switch ctx.OutputFormat {
		case "json":
			output.ListJSON(w, m, keys)
		case "csv":
			output.ListCSV(w, m, keys)
		default:
			output.ListTable(w, m, keys)
		}
	case io.Reader:
		if _, ok := resource.Result.(io.ReadCloser); ok {
			defer resource.Result.(io.ReadCloser).Close()
		}
		_, err := io.Copy(w, resource.Result.(io.Reader))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error copying (io.Reader) result: %s\n", err)
		}
	default:
		switch ctx.OutputFormat {
		case "json":
			output.DefaultJSON(w, resource.Result)
		default:
			fmt.Fprintf(w, "%v", resource.Result)
		}
	}
}

func onlyNonNil(m map[string]interface{}) map[string]interface{} {
	for k, v := range m {
		if v == nil {
			m[k] = ""
		}
	}
	return m
}

// limitFields returns only the fields the user specified in the `fields` flag. If
// the flag wasn't provided, all fields are returned.
func (ctx *Context) limitFields(resource *Resource) []string {
	if ctx.CLIContext.IsSet("fields") {
		fields := strings.Split(strings.ToLower(ctx.CLIContext.String("fields")), ",")
		newKeys := []string{}
		for _, key := range resource.Keys {
			if util.Contains(fields, strings.Join(strings.Split(strings.ToLower(key), " "), "-")) {
				newKeys = append(newKeys, key)
			}
		}
		return newKeys
	}
	return resource.Keys
}

// StoreCredentials caches the users auth credentials if available and the `no-cache`
// flag was not provided.
func (ctx *Context) StoreCredentials() {
	// if serviceClient is nil, the HTTP request for the command didn't get sent.
	// don't set cache if the `no-cache` flag is provided
	if ctx.ServiceClient != nil && !ctx.CLIContext.GlobalIsSet("no-cache") && !ctx.CLIContext.IsSet("no-cache") {
		newCacheValue := &auth.CacheItem{
			TokenID:         ctx.ServiceClient.TokenID,
			ServiceEndpoint: ctx.ServiceClient.Endpoint,
		}
		// get auth credentials
		ao, region, err := auth.Credentials(ctx.CLIContext)
		if err == nil {
			// form the cache key
			cacheKey := auth.CacheKey(*ao, region, ctx.ServiceClientType)
			// initialize the cache
			cache := &auth.Cache{}
			// set the cache value to the current values
			_ = cache.SetValue(cacheKey, newCacheValue)
		}
	}
}

func (ctx *Context) handleLogging() error {
	var opt string
	if ctx.CLIContext.GlobalIsSet("log") {
		opt = ctx.CLIContext.GlobalString("log")
	} else if ctx.CLIContext.IsSet("log") {
		opt = ctx.CLIContext.String("log")
	}
	if opt != "" {
		switch strings.ToLower(opt) {
		case "debug":
			ctx.ServiceClient.Logger.Level = logrus.DebugLevel
		case "info":
			ctx.ServiceClient.Logger.Level = logrus.InfoLevel
		default:
			return fmt.Errorf("Invalid value for `log` flag: %s. Valid options are: debug, info", opt)
		}
		ctx.ServiceClient.Logger.Out = ctx.CLIContext.App.Writer
	}
	return nil
}

// ErrExit1 tells `rack` to print the error and exit.
func (ctx *Context) ErrExit1(resource *Resource) {
	resource.ErrExit1 = true
	ctx.WaitGroup.Add(1)
	ctx.Results <- resource
	ctx.WaitGroup.Wait()
}

// IDOrName is a function for retrieving a resources unique identifier based on
// whether he or she passed an `id` or a `name` flag.
func (ctx *Context) IDOrName(idFromNameFunc func(*gophercloud.ServiceClient, string) (string, error)) (string, error) {
	if ctx.CLIContext.IsSet("id") {
		if ctx.CLIContext.IsSet("name") {
			return "", fmt.Errorf("Only one of either --id or --name may be provided.")
		}
		return ctx.CLIContext.String("id"), nil
	} else if ctx.CLIContext.IsSet("name") {
		name := ctx.CLIContext.String("name")
		id, err := idFromNameFunc(ctx.ServiceClient, name)
		if err != nil {
			return "", fmt.Errorf("Error converting name [%s] to ID: %s", name, err)
		}
		return id, nil
	} else {
		return "", output.ErrMissingFlag{Msg: "One of either --id or --name must be provided."}
	}
}

// CheckArgNum checks that the provided number of arguments has the same
// cardinality as the expected number of arguments.
func (ctx *Context) CheckArgNum(expected int) error {
	argsLen := len(ctx.CLIContext.Args())
	if argsLen != expected {
		return fmt.Errorf("Expected %d args but got %d\nUsage: %s", expected, argsLen, ctx.CLIContext.Command.Usage)
	}
	return nil
}

func (ctx *Context) checkOutputFormat() error {
	var outputFormat string
	if ctx.CLIContext.GlobalIsSet("output") {
		outputFormat = ctx.CLIContext.GlobalString("output")
	} else if ctx.CLIContext.IsSet("output") {
		outputFormat = ctx.CLIContext.String("output")
	} else {
		return nil
	}

	switch outputFormat {
	case "json", "csv", "table":
		break
	default:
		return fmt.Errorf("Invalid value for `output` flag: '%s'. Options are: json, csv, table.", outputFormat)
	}
	ctx.OutputFormat = outputFormat
	return nil
}

// CheckFlagsSet checks that the given flag names are set for the command.
func (ctx *Context) CheckFlagsSet(flagNames []string) error {
	for _, flagName := range flagNames {
		if !ctx.CLIContext.IsSet(flagName) {
			return output.ErrMissingFlag{Msg: fmt.Sprintf("--%s is required.", flagName)}
		}
	}
	return nil
}

// CheckKVFlag is a function used for verifying the format of a key-value flag.
func (ctx *Context) CheckKVFlag(flagName string) (map[string]string, error) {
	kv := make(map[string]string)
	kvStrings := strings.Split(ctx.CLIContext.String(flagName), ",")
	for _, kvString := range kvStrings {
		temp := strings.Split(kvString, "=")
		if len(temp) != 2 {
			return nil, output.ErrFlagFormatting{Msg: fmt.Sprintf("Expected key1=value1,key2=value2 format but got %s for --%s.\n", kvString, flagName)}
		}
		kv[temp[0]] = temp[1]
	}
	return kv, nil
}

// CheckStructFlag is a function used for verifying the format of a struct flag.
func (ctx *Context) CheckStructFlag(flagValues []string) ([]map[string]interface{}, error) {
	valSliceMap := make([]map[string]interface{}, len(flagValues))
	for i, flagValue := range flagValues {
		kvStrings := strings.Split(flagValue, ",")
		m := make(map[string]interface{})
		for _, kvString := range kvStrings {
			temp := strings.Split(kvString, "=")
			if len(temp) != 2 {
				return nil, output.ErrFlagFormatting{Msg: fmt.Sprintf("Expected key1=value1,key2=value2 format but got %s.\n", kvString)}
			}
			m[temp[0]] = temp[1]
		}
		valSliceMap[i] = m
	}
	return valSliceMap, nil
}
<commit_msg>only print non-nil values<commit_after>package handler

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"strings"
	"sync"

	"github.com/Sirupsen/logrus"
	"github.com/jrperritt/rack/auth"
	"github.com/jrperritt/rack/internal/github.com/codegangsta/cli"
	"github.com/jrperritt/rack/internal/github.com/rackspace/gophercloud"
	"github.com/jrperritt/rack/output"
	"github.com/jrperritt/rack/util"
)

// Command is the type that commands have.
type Command struct {
	Ctx *Context
}

// Context is a global context that `rack` uses.
type Context struct {
	// CLIContext is the context that the `cli` library uses. `rack` uses it to
	// access flags.
	CLIContext *cli.Context
	// ServiceClient is the Rackspace service client used to authenticate the user
	// and carry out the requests while processing the command.
	ServiceClient *gophercloud.ServiceClient
	// ServiceClientType is the type of Rackspace service client used (e.g. compute).
	ServiceClientType string
	// WaitGroup is used for synchronizing output.
	WaitGroup *sync.WaitGroup
	// Results is a channel into which commands send results. It allows for streaming
	// output.
	Results chan *Resource
	// OutputFormat is the format in which the user wants the output. This is obtained
	// from the `output` flag and will default to "table" if not provided.
	OutputFormat string
	// Logger is used to log information acquired while processing the command.
	Logger *logrus.Logger
}

// ListenAndReceive creates the Results channel and processes the results that
// come through it before sending them on to `Print`. It is run in a separate
// goroutine from `main`.
func (ctx *Context) ListenAndReceive() {
	ctx.Results = make(chan *Resource)
	go func() {
		for {
			select {
			case resource, ok := <-ctx.Results:

				if !ok {
					ctx.Results = nil
					continue
				}

				if resource.Err != nil {

					ctx.CLIContext.App.Writer = os.Stderr
					resource.Keys = []string{"error"}
					var errorBody string

					switch resource.Err.(type) {

					case *gophercloud.UnexpectedResponseCodeError:
						errBodyRaw := resource.Err.(*gophercloud.UnexpectedResponseCodeError).Body
						errMap := make(map[string]map[string]interface{})
						err := json.Unmarshal(errBodyRaw, &errMap)
						if err != nil {
							errorBody = string(errBodyRaw)
							break
						}
						for _, v := range errMap {
							errorBody = v["message"].(string)
							break
						}

					default:
						errorBody = resource.Err.Error()
					}

					resource.Result = map[string]interface{}{"error": errorBody}
				}

				if resource.Result == nil {
					if args := ctx.CLIContext.Parent().Parent().Args(); len(args) > 0 {
						resource.Result = fmt.Sprintf("Nothing to show. Maybe you'd like to set up some %ss?\n",
							strings.Replace(args[0], "-", " ", -1))
					} else {
						resource.Result = fmt.Sprintf("Nothing to show.\n")
					}
				}

				ctx.Print(resource)
				if resource.ErrExit1 {
					os.Exit(1)
				}
			}
		}
	}()
}

// Print returns the output to the user
func (ctx *Context) Print(resource *Resource) {
	defer ctx.WaitGroup.Done()

	// limit the returned fields if any were given in the `fields` flag
	keys := ctx.limitFields(resource)
	w := ctx.CLIContext.App.Writer

	switch resource.Result.(type) {
	case map[string]interface{}:
		m := resource.Result.(map[string]interface{})
		m = onlyNonNil(m)
		switch ctx.OutputFormat {
		case "json":
			output.MetadataJSON(w, m, keys)
		case "csv":
			output.MetadataCSV(w, m, keys)
		default:
			output.MetadataTable(w, m, keys)
		}
	case []map[string]interface{}:
		ms := resource.Result.([]map[string]interface{})
		for i, m := range ms {
			ms[i] = onlyNonNil(m)
		}
		switch ctx.OutputFormat {
		case "json":
			output.ListJSON(w, ms, keys)
		case "csv":
			output.ListCSV(w, ms, keys)
		default:
			output.ListTable(w, ms, keys)
		}
	case io.Reader:
		if _, ok := resource.Result.(io.ReadCloser); ok {
			defer resource.Result.(io.ReadCloser).Close()
		}
		_, err := io.Copy(w, resource.Result.(io.Reader))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Error copying (io.Reader) result: %s\n", err)
		}
	default:
		switch ctx.OutputFormat {
		case "json":
			output.DefaultJSON(w, resource.Result)
		default:
			fmt.Fprintf(w, "%v", resource.Result)
		}
	}
}

func onlyNonNil(m map[string]interface{}) map[string]interface{} {
	for k, v := range m {
		if v == nil {
			m[k] = ""
		}
	}
	return m
}

// limitFields returns only the fields the user specified in the `fields` flag. If
// the flag wasn't provided, all fields are returned.
func (ctx *Context) limitFields(resource *Resource) []string {
	if ctx.CLIContext.IsSet("fields") {
		fields := strings.Split(strings.ToLower(ctx.CLIContext.String("fields")), ",")
		newKeys := []string{}
		for _, key := range resource.Keys {
			if util.Contains(fields, strings.Join(strings.Split(strings.ToLower(key), " "), "-")) {
				newKeys = append(newKeys, key)
			}
		}
		return newKeys
	}
	return resource.Keys
}

// StoreCredentials caches the users auth credentials if available and the `no-cache`
// flag was not provided.
func (ctx *Context) StoreCredentials() {
	// if serviceClient is nil, the HTTP request for the command didn't get sent.
	// don't set cache if the `no-cache` flag is provided
	if ctx.ServiceClient != nil && !ctx.CLIContext.GlobalIsSet("no-cache") && !ctx.CLIContext.IsSet("no-cache") {
		newCacheValue := &auth.CacheItem{
			TokenID:         ctx.ServiceClient.TokenID,
			ServiceEndpoint: ctx.ServiceClient.Endpoint,
		}
		// get auth credentials
		ao, region, err := auth.Credentials(ctx.CLIContext)
		if err == nil {
			// form the cache key
			cacheKey := auth.CacheKey(*ao, region, ctx.ServiceClientType)
			// initialize the cache
			cache := &auth.Cache{}
			// set the cache value to the current values
			_ = cache.SetValue(cacheKey, newCacheValue)
		}
	}
}

func (ctx *Context) handleLogging() error {
	var opt string
	if ctx.CLIContext.GlobalIsSet("log") {
		opt = ctx.CLIContext.GlobalString("log")
	} else if ctx.CLIContext.IsSet("log") {
		opt = ctx.CLIContext.String("log")
	}
	if opt != "" {
		switch strings.ToLower(opt) {
		case "debug":
			ctx.ServiceClient.Logger.Level = logrus.DebugLevel
		case "info":
			ctx.ServiceClient.Logger.Level = logrus.InfoLevel
		default:
			return fmt.Errorf("Invalid value for `log` flag: %s. Valid options are: debug, info", opt)
		}
		ctx.ServiceClient.Logger.Out = ctx.CLIContext.App.Writer
	}
	return nil
}

// ErrExit1 tells `rack` to print the error and exit.
func (ctx *Context) ErrExit1(resource *Resource) {
	resource.ErrExit1 = true
	ctx.WaitGroup.Add(1)
	ctx.Results <- resource
	ctx.WaitGroup.Wait()
}

// IDOrName is a function for retrieving a resources unique identifier based on
// whether he or she passed an `id` or a `name` flag.
func (ctx *Context) IDOrName(idFromNameFunc func(*gophercloud.ServiceClient, string) (string, error)) (string, error) {
	if ctx.CLIContext.IsSet("id") {
		if ctx.CLIContext.IsSet("name") {
			return "", fmt.Errorf("Only one of either --id or --name may be provided.")
		}
		return ctx.CLIContext.String("id"), nil
	} else if ctx.CLIContext.IsSet("name") {
		name := ctx.CLIContext.String("name")
		id, err := idFromNameFunc(ctx.ServiceClient, name)
		if err != nil {
			return "", fmt.Errorf("Error converting name [%s] to ID: %s", name, err)
		}
		return id, nil
	} else {
		return "", output.ErrMissingFlag{Msg: "One of either --id or --name must be provided."}
	}
}

// CheckArgNum checks that the provided number of arguments has the same
// cardinality as the expected number of arguments.
func (ctx *Context) CheckArgNum(expected int) error {
	argsLen := len(ctx.CLIContext.Args())
	if argsLen != expected {
		return fmt.Errorf("Expected %d args but got %d\nUsage: %s", expected, argsLen, ctx.CLIContext.Command.Usage)
	}
	return nil
}

func (ctx *Context) checkOutputFormat() error {
	var outputFormat string
	if ctx.CLIContext.GlobalIsSet("output") {
		outputFormat = ctx.CLIContext.GlobalString("output")
	} else if ctx.CLIContext.IsSet("output") {
		outputFormat = ctx.CLIContext.String("output")
	} else {
		return nil
	}

	switch outputFormat {
	case "json", "csv", "table":
		break
	default:
		return fmt.Errorf("Invalid value for `output` flag: '%s'. Options are: json, csv, table.", outputFormat)
	}
	ctx.OutputFormat = outputFormat
	return nil
}

// CheckFlagsSet checks that the given flag names are set for the command.
func (ctx *Context) CheckFlagsSet(flagNames []string) error {
	for _, flagName := range flagNames {
		if !ctx.CLIContext.IsSet(flagName) {
			return output.ErrMissingFlag{Msg: fmt.Sprintf("--%s is required.", flagName)}
		}
	}
	return nil
}

// CheckKVFlag is a function used for verifying the format of a key-value flag.
func (ctx *Context) CheckKVFlag(flagName string) (map[string]string, error) {
	kv := make(map[string]string)
	kvStrings := strings.Split(ctx.CLIContext.String(flagName), ",")
	for _, kvString := range kvStrings {
		temp := strings.Split(kvString, "=")
		if len(temp) != 2 {
			return nil, output.ErrFlagFormatting{Msg: fmt.Sprintf("Expected key1=value1,key2=value2 format but got %s for --%s.\n", kvString, flagName)}
		}
		kv[temp[0]] = temp[1]
	}
	return kv, nil
}

// CheckStructFlag is a function used for verifying the format of a struct flag.
func (ctx *Context) CheckStructFlag(flagValues []string) ([]map[string]interface{}, error) {
	valSliceMap := make([]map[string]interface{}, len(flagValues))
	for i, flagValue := range flagValues {
		kvStrings := strings.Split(flagValue, ",")
		m := make(map[string]interface{})
		for _, kvString := range kvStrings {
			temp := strings.Split(kvString, "=")
			if len(temp) != 2 {
				return nil, output.ErrFlagFormatting{Msg: fmt.Sprintf("Expected key1=value1,key2=value2 format but got %s.\n", kvString)}
			}
			m[temp[0]] = temp[1]
		}
		valSliceMap[i] = m
	}
	return valSliceMap, nil
}
<|endoftext|>


<commit_before>package handler

// Contains common methods used for writing appengine apps.

import (
	"crypto/md5"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/log"
)

type handlerError struct {
	AppVersion string   `json:"appVersion"`
	URL        *url.URL `json:"url"`
	Method     string   `json:"method"`
	StatusCode int      `json:"statusCode"`
	InstanceID string   `json:"instanceId"`
	VersionID  string   `json:"versionId"`
	RequestID  string   `json:"requestId"`
	ModuleName string   `json:"moduleName"`
	Err        string   `json:"message"`
}

func (e *handlerError) Error() string {
	b, err := json.MarshalIndent(e, "", "  ")
	if err != nil {
		return err.Error()
	}
	return string(b)
}

// Base struct designed to be extended by more specific url handlers
type Base struct {
	Ctx context.Context
	Req *http.Request
	Res http.ResponseWriter

	config    Config
	templates map[string]*template.Template
}

// Config contains the custom handler configuration settings
type Config struct {
	LayoutPath       string
	ViewPath         string
	ParentLayoutName string
}

var defaultConfig = Config{
	LayoutPath:       "layouts/application.html",
	ViewPath:         "views",
	ParentLayoutName: "layout",
}

// New allows one to override the default configuration settings.
//  func NewRootHandler() rootHandler {
//  	return rootHandler{Base: handler.New(&handler.Config{
//  		LayoutPath: "layouts/admin.html",
//  	})}
//  }
func New(c *Config) Base {
	if c == nil {
		c = &defaultConfig
	}
	b := Base{config: *c} // copy the passed in pointer
	b.templates = make(map[string]*template.Template)
	return b
}

// Default uses the default config settings
//  func NewRootHandler() rootHandler {
//  	return rootHandler{Base: handler.Default()}
//  }
func Default() Base {
	return New(nil)
}

// OriginMiddleware returns a middleware function that validates the origin
// header within the request matches the allowed values
func OriginMiddleware(allowed []string) func(context.Context, http.ResponseWriter, *http.Request) context.Context {
	return func(c context.Context, w http.ResponseWriter, r *http.Request) context.Context {
		origin := r.Header.Get("Origin")
		if len(origin) == 0 {
			return c
		}
		ok := validateOrigin(origin, allowed)
		if !ok {
			c2, cancel := context.WithCancel(c)
			cancel()
			return c2
		}

		w.Header().Add("Access-Control-Allow-Headers", "Content-Type, Authorization")
		w.Header().Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
		w.Header().Add("Access-Control-Allow-Origin", origin)

		return c
	}
}

// ValidateOrigin is a helper method called within the ServeHTTP method on
// OPTION requests to validate the allowed origins
func (b *Base) ValidateOrigin(allowed []string) {
	origin := b.Req.Header.Get("Origin")
	ok := validateOrigin(origin, allowed)
	if !ok {
		_, cancel := context.WithCancel(b.Ctx)
		cancel()
	}
}

func validateOrigin(origin string, allowed []string) bool {
	if allowed == nil || len(allowed) == 0 {
		return true
	}
	if len(origin) == 0 {
		return false
	}
	for _, allowedOrigin := range allowed {
		if origin == allowedOrigin {
			return true
		}
	}
	return false
}

// ToJSON encodes an interface into the response writer with a default http
// status code of 200
func (b *Base) ToJSON(data interface{}) {
	b.Res.Header().Add("Content-Type", "application/json")
	err := json.NewEncoder(b.Res).Encode(data)
	if err != nil {
		b.Abort(http.StatusInternalServerError, fmt.Errorf("Decoding JSON: %v", err))
	}
}

// ToJSONWithStatus json encodes an interface into the response writer with a
// custom http status code
func (b *Base) ToJSONWithStatus(data interface{}, status int) {
	b.Res.Header().Add("Content-Type", "application/json")
	b.Res.WriteHeader(status)
	b.ToJSON(data)
}

// SendStatus writes the passed in status to the response without any data
func (b *Base) SendStatus(status int) {
	b.Res.WriteHeader(status)
}

// Bind must be called at the beginning of every request to set the required references
func (b *Base) Bind(c context.Context, w http.ResponseWriter, r *http.Request) {
	b.Ctx, b.Res, b.Req = c, w, r
}

// Header gets the request header value
func (b *Base) Header(name string) string {
	return b.Req.Header.Get(name)
}

// SetHeader sets a response header value
func (b *Base) SetHeader(name, value string) {
	b.Res.Header().Set(name, value)
}

// Abort is called when pre-maturally exiting from a handler function due to an
// error. A detailed error is delivered to the client and logged to provide the
// details required to identify the issue.
func (b *Base) Abort(statusCode int, err error) {
	c, cancel := context.WithCancel(b.Ctx)
	defer cancel()

	// testapp is the name given to all apps when being tested
	var isTest = appengine.AppID(c) == "testapp"

	hErr := &handlerError{
		URL:        b.Req.URL,
		Method:     b.Req.Method,
		StatusCode: statusCode,
		AppVersion: appengine.AppID(c),
		RequestID:  appengine.RequestID(c),
	}
	if err != nil {
		hErr.Err = err.Error()
	}

	if !isTest {
		hErr.InstanceID = appengine.InstanceID()
		hErr.VersionID = appengine.VersionID(c)
		hErr.ModuleName = appengine.ModuleName(c)
	}

	// log method to appengine log
	log.Errorf(c, hErr.Error())

	b.Res.WriteHeader(statusCode)
	if strings.Index(b.Req.Header.Get("Accept"), "application/json") >= 0 {
		json.NewEncoder(b.Res).Encode(hErr)
	}
}

// Redirect is a simple wrapper around the core http method
func (b *Base) Redirect(str string, args ...interface{}) {
	http.Redirect(b.Res, b.Req, fmt.Sprintf(str, args...), 303)
}

// Render pre-caches and renders template.
func (b *Base) Render(template string, data interface{}, fns template.FuncMap) {
	tmpl := b.loadTemplate(template, fns)
	tmpl.ExecuteTemplate(b.Res, b.config.ParentLayoutName, data)
}

// SetLastModified sets the Last-Modified header in the RFC1123 time format
func (b *Base) SetLastModified(t time.Time) {
	b.Res.Header().Set("Last-Modified", t.Format(time.RFC1123))
}

// SetETag sets the etag with the md5 value
func (b *Base) SetETag(val interface{}) {
	var str string
	switch val.(type) {
	case string:
		str = val.(string)
	case time.Time:
		str = val.(time.Time).Format(time.RFC1123)
	case fmt.Stringer:
		str = val.(fmt.Stringer).String()
	default:
		str = fmt.Sprintf("%v", val)
	}

	h := md5.New()
	io.WriteString(h, str)
	etag := base64.StdEncoding.EncodeToString(h.Sum(nil))
	b.Res.Header().Set("ETag", etag)
}

func (b *Base) SetExpires(t time.Time) {
	b.Res.Header().Set("Expires", t.Format(time.RFC1123))
}

func (b *Base) SetExpiresIn(d time.Duration) {
	b.Res.Header().Set("Expires", time.Now().Add(d).Format(time.RFC1123))
}

func (b *Base) loadTemplate(name string, fns template.FuncMap) *template.Template {
	if b.templates[name] != nil {
		return b.templates[name]
	}

	view := fmt.Sprintf("%s/%s.html", b.config.ViewPath, name)
	t := template.New(name)
	if fns != nil {
		t.Funcs(fns)
	}
	template, err := t.ParseFiles(b.config.LayoutPath, view)
	if err != nil {
		panic(fmt.Sprintf("Failed to load template: %s => %v", view, err))
	}

	b.templates[name] = template
	return template
}
<commit_msg>provide better control when rendering tempaltes<commit_after>package handler

// Contains common methods used for writing appengine apps.

import (
	"crypto/md5"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"html/template"
	"io"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/log"
)

type handlerError struct {
	AppVersion string   `json:"appVersion"`
	URL        *url.URL `json:"url"`
	Method     string   `json:"method"`
	StatusCode int      `json:"statusCode"`
	InstanceID string   `json:"instanceId"`
	VersionID  string   `json:"versionId"`
	RequestID  string   `json:"requestId"`
	ModuleName string   `json:"moduleName"`
	Err        string   `json:"message"`
}

func (e *handlerError) Error() string {
	b, err := json.MarshalIndent(e, "", "  ")
	if err != nil {
		return err.Error()
	}
	return string(b)
}

// Base struct designed to be extended by more specific url handlers
type Base struct {
	Ctx context.Context
	Req *http.Request
	Res http.ResponseWriter

	config    Config
	templates map[string]*template.Template
}

// Config contains the custom handler configuration settings
type Config struct {
	DefaultLayout    string
	LayoutPath       string
	ViewPath         string
	ParentLayoutName string
}

var defaultConfig = Config{
	DefaultLayout:    "application.html",
	LayoutPath:       "layouts",
	ViewPath:         "views",
	ParentLayoutName: "layout",
}

// New allows one to override the default configuration settings.
//  func NewRootHandler() rootHandler {
//  	return rootHandler{Base: handler.New(&handler.Config{
//  		LayoutPath: "layouts/admin.html",
//  	})}
//  }
func New(c *Config) Base {
	if c == nil {
		c = &defaultConfig
	}
	b := Base{config: *c} // copy the passed in pointer
	b.templates = make(map[string]*template.Template)
	return b
}

// Default uses the default config settings
//  func NewRootHandler() rootHandler {
//  	return rootHandler{Base: handler.Default()}
//  }
func Default() Base {
	return New(nil)
}

// OriginMiddleware returns a middleware function that validates the origin
// header within the request matches the allowed values
func OriginMiddleware(allowed []string) func(context.Context, http.ResponseWriter, *http.Request) context.Context {
	return func(c context.Context, w http.ResponseWriter, r *http.Request) context.Context {
		origin := r.Header.Get("Origin")
		if len(origin) == 0 {
			return c
		}
		ok := validateOrigin(origin, allowed)
		if !ok {
			c2, cancel := context.WithCancel(c)
			cancel()
			return c2
		}

		w.Header().Add("Access-Control-Allow-Headers", "Content-Type, Authorization")
		w.Header().Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
		w.Header().Add("Access-Control-Allow-Origin", origin)

		return c
	}
}

// ValidateOrigin is a helper method called within the ServeHTTP method on
// OPTION requests to validate the allowed origins
func (b *Base) ValidateOrigin(allowed []string) {
	origin := b.Req.Header.Get("Origin")
	ok := validateOrigin(origin, allowed)
	if !ok {
		_, cancel := context.WithCancel(b.Ctx)
		cancel()
	}
}

func validateOrigin(origin string, allowed []string) bool {
	if allowed == nil || len(allowed) == 0 {
		return true
	}
	if len(origin) == 0 {
		return false
	}
	for _, allowedOrigin := range allowed {
		if origin == allowedOrigin {
			return true
		}
	}
	return false
}

// ToJSON encodes an interface into the response writer with a default http
// status code of 200
func (b *Base) ToJSON(data interface{}) {
	b.Res.Header().Add("Content-Type", "application/json")
	err := json.NewEncoder(b.Res).Encode(data)
	if err != nil {
		b.Abort(http.StatusInternalServerError, fmt.Errorf("Decoding JSON: %v", err))
	}
}

// ToJSONWithStatus json encodes an interface into the response writer with a
// custom http status code
func (b *Base) ToJSONWithStatus(data interface{}, status int) {
	b.Res.Header().Add("Content-Type", "application/json")
	b.Res.WriteHeader(status)
	b.ToJSON(data)
}

// SendStatus writes the passed in status to the response without any data
func (b *Base) SendStatus(status int) {
	b.Res.WriteHeader(status)
}

// Bind must be called at the beginning of every request to set the required references
func (b *Base) Bind(c context.Context, w http.ResponseWriter, r *http.Request) {
	b.Ctx, b.Res, b.Req = c, w, r
}

// Header gets the request header value
func (b *Base) Header(name string) string {
	return b.Req.Header.Get(name)
}

// SetHeader sets a response header value
func (b *Base) SetHeader(name, value string) {
	b.Res.Header().Set(name, value)
}

// Abort is called when pre-maturally exiting from a handler function due to an
// error. A detailed error is delivered to the client and logged to provide the
// details required to identify the issue.
func (b *Base) Abort(statusCode int, err error) {
	c, cancel := context.WithCancel(b.Ctx)
	defer cancel()

	// testapp is the name given to all apps when being tested
	var isTest = appengine.AppID(c) == "testapp"

	hErr := &handlerError{
		URL:        b.Req.URL,
		Method:     b.Req.Method,
		StatusCode: statusCode,
		AppVersion: appengine.AppID(c),
		RequestID:  appengine.RequestID(c),
	}
	if err != nil {
		hErr.Err = err.Error()
	}

	if !isTest {
		hErr.InstanceID = appengine.InstanceID()
		hErr.VersionID = appengine.VersionID(c)
		hErr.ModuleName = appengine.ModuleName(c)
	}

	// log method to appengine log
	log.Errorf(c, hErr.Error())

	b.Res.WriteHeader(statusCode)
	if strings.Index(b.Req.Header.Get("Accept"), "application/json") >= 0 {
		json.NewEncoder(b.Res).Encode(hErr)
	}
}

// Redirect is a simple wrapper around the core http method
func (b *Base) Redirect(str string, args ...interface{}) {
	http.Redirect(b.Res, b.Req, fmt.Sprintf(str, args...), 303)
}

// Render pre-caches and renders template.
func (b *Base) Render(path string, data interface{}, fns template.FuncMap) {
	b.RenderTemplate(path, data, &RenderOptions{
		Name:    b.config.ParentLayoutName,
		FuncMap: fns,
		Parents: []string{filepath.Join(b.config.LayoutPath, b.config.DefaultLayout)},
	})
}

// RenderOptions contain the optional data items for rendering
type RenderOptions struct {
	// http status to return in the response
	Status int

	// template functions
	FuncMap template.FuncMap

	// parent layout paths to render the defined view within
	Parents []string

	// the defined *name* to render
	// 	{{define "layout"}}...{{end}}
	Name string
}

// RenderTemplate renders the template without any layout
func (b *Base) RenderTemplate(tmplPath string, data interface{}, opts *RenderOptions) {
	name := strings.TrimPrefix(tmplPath, "/")
	tmpl := b.templates[name]
	if tmpl == nil {
		t := template.New(name)
		if opts != nil && opts.FuncMap != nil {
			t.Funcs(opts.FuncMap)
		}
		var views []string
		if opts != nil && opts.Parents != nil {
			for _, p := range opts.Parents {
				views = append(views, b.fileNameWithExt(p))
			}
		} else {
			views = make([]string, 0)
		}

		views = append(views, filepath.Join(b.config.ViewPath, b.fileNameWithExt(name)))
		tmpl = template.Must(t.ParseFiles(views...))
		b.templates[name] = tmpl
	}
	if opts != nil && opts.Status != 0 {
		b.Res.WriteHeader(opts.Status)
	} else {
		b.Res.WriteHeader(http.StatusOK)
	}

	var renderErr error
	if opts != nil && opts.Name != "" {
		renderErr = tmpl.ExecuteTemplate(b.Res, opts.Name, data)
	} else {
		renderErr = tmpl.Execute(b.Res, data)
	}
	if renderErr != nil {
		panic(renderErr)
	}
}

// SetLastModified sets the Last-Modified header in the RFC1123 time format
func (b *Base) SetLastModified(t time.Time) {
	b.Res.Header().Set("Last-Modified", t.Format(time.RFC1123))
}

// SetETag sets the etag with the md5 value
func (b *Base) SetETag(val interface{}) {
	var str string
	switch val.(type) {
	case string:
		str = val.(string)
	case time.Time:
		str = val.(time.Time).Format(time.RFC1123)
	case fmt.Stringer:
		str = val.(fmt.Stringer).String()
	default:
		str = fmt.Sprintf("%v", val)
	}

	h := md5.New()
	io.WriteString(h, str)
	etag := base64.StdEncoding.EncodeToString(h.Sum(nil))
	b.Res.Header().Set("ETag", etag)
}

func (b *Base) SetExpires(t time.Time) {
	b.Res.Header().Set("Expires", t.Format(time.RFC1123))
}

func (b *Base) SetExpiresIn(d time.Duration) {
	b.Res.Header().Set("Expires", time.Now().Add(d).Format(time.RFC1123))
}

func (b *Base) fileNameWithExt(name string) string {
	var ext string
	if strings.Index(name, ".") > 0 {
		ext = ""
	} else {
		ext = ".html"
	}
	return fmt.Sprintf("%s%s", name, ext)
}
<|endoftext|>


<commit_before>package tao

import (
  "log"
  "net"
  "sync"
  "time"
)

const (
  NTYPE = 4
  NLEN = 4
  MAXLEN = 1 << 23  // 8M
)

type TCPConnection struct {
  netid int64
  Owner *TCPServer
  conn net.Conn
  address string
  name string
  closeOnce sync.Once
  wg *sync.WaitGroup
  timing *TimingWheel
  messageSendChan chan []byte
  handlerRecvChan chan MessageHandler
  closeConnChan chan struct{}
  timeOutChan chan *OnTimeOut
  HeartBeat int64
  pendingTimers []int64
  reconnect bool
  closed *AtomicBoolean
  messageCodec Codec
  extraData interface{}
  onConnect onConnectFunc
  onMessage onMessageFunc
  onClose onCloseFunc
  onError onErrorFunc
}

func ClientTCPConnection(id int64, addr string, t *TimingWheel, reconn bool) *TCPConnection {
  c, err := net.Dial("tcp", addr)
  if err != nil {
    log.Fatalln(err)
  }
  return &TCPConnection {
    netid: id,
    conn: c,
    address: addr,
    wg: &sync.WaitGroup{},
    timing: t,
    messageSendChan: make(chan []byte, 1024),
    handlerRecvChan: make(chan MessageHandler, 1024),
    closeConnChan: make(chan struct{}),
    timeOutChan: make(chan *OnTimeOut),
    HeartBeat: time.Now().UnixNano(),
    pendingTimers: []int64{},
    reconnect: reconn,
    closed: NewAtomicBoolean(false),
    messageCodec: TypeLengthValueCodec{},
  }
}

func ServerTCPConnection(id int64, s *TCPServer, c net.Conn) *TCPConnection {
  tcpConn := &TCPConnection {
    netid: id,
    Owner: s,
    conn: c,
    wg: &sync.WaitGroup{},
    timing: s.timing,
    messageSendChan: make(chan []byte, 1024),
    handlerRecvChan: make(chan MessageHandler, 1024),
    closeConnChan: make(chan struct{}),
    timeOutChan: make(chan *OnTimeOut),
    HeartBeat: time.Now().UnixNano(),
    pendingTimers: []int64{},
    reconnect: false,
    closed: NewAtomicBoolean(false),
    messageCodec: TypeLengthValueCodec{},
  }
  tcpConn.SetOnConnectCallback(s.onConnect)
  tcpConn.SetOnMessageCallback(s.onMessage)
  tcpConn.SetOnErrorCallback(s.onError)
  tcpConn.SetOnCloseCallback(s.onClose)
  return tcpConn
}

func (client *TCPConnection)SetExtraData(data interface{}) {
  client.extraData = data
}

func (client *TCPConnection)GetExtraData() interface{} {
  return client.extraData
}

func (client *TCPConnection)NetId() int64 {
  return client.netid
}

func (client *TCPConnection)Reconnect() {
  netid := client.netid
  address := client.address
  timing := client.timing
  reconnect := client.reconnect
  client = ClientTCPConnection(netid, address, timing, reconnect)
  client.Do()
}

func (client *TCPConnection)SetCodec(cdc Codec) {
  client.messageCodec = cdc
}

func (client *TCPConnection)isServerMode() bool {
  return client.Owner != nil
}

func (client *TCPConnection)SetOnConnectCallback(cb func(*TCPConnection) bool) {
  if cb != nil {
    client.onConnect = onConnectFunc(cb)
  }
}

func (client *TCPConnection)SetOnMessageCallback(cb func(Message, *TCPConnection)) {
  if cb != nil {
    client.onMessage = onMessageFunc(cb)
  }
}

func (client *TCPConnection)SetOnErrorCallback(cb func()) {
  if cb != nil {
    client.onError = onErrorFunc(cb)
  }
}

func (client *TCPConnection)Wait() {
  client.wg.Wait()
}

func (client *TCPConnection)SetOnCloseCallback(cb func(*TCPConnection)) {
  if cb != nil {
    client.onClose = onCloseFunc(cb)
  }
}

func (client *TCPConnection)RemoteAddr() net.Addr {
  return client.conn.RemoteAddr()
}

func (client *TCPConnection)SetName(n string) {
  client.name = n
}

func (client *TCPConnection)String() string {
  return client.name
}

func (client *TCPConnection)IsClosed() bool {
  return client.closed.Get()
}

func (client *TCPConnection)Close() {
  client.closeOnce.Do(func() {
    if client.closed.CompareAndSet(false, true) {
      close(client.closeConnChan)
      close(client.messageSendChan)
      close(client.handlerRecvChan)
      close(client.timeOutChan)
      client.conn.Close()

      if (client.onClose != nil) {
        client.onClose(client)
      }

      if client.isServerMode() {
        client.Owner.connections.Remove(client.netid)
        for _, id := range client.pendingTimers {
          client.CancelTimer(id)
        }
      } else {
        client.Reconnect()
      }
    }
  })
}

func (client *TCPConnection)Write(msg Message) error {
  packet, err := client.messageCodec.Encode(msg)
  if err != nil {
    return err
  }

  select {
  case client.messageSendChan<- packet:
    return nil
  default:
    return ErrorWouldBlock
  }
}

/* If onConnect() returns true, start three go-routines for each client:
readLoop(), writeLoop() and handleLoop() */
func (client *TCPConnection)Do() {
  if client.onConnect != nil && !client.onConnect(client) {
    log.Fatalln("Error onConnect()\n")
  }

  // start read, write and handle loop
  client.startLoop(client.readLoop)
  client.startLoop(client.writeLoop)
  client.startLoop(client.handleLoop)
}

func (client *TCPConnection)RunAt(t time.Time, cb func(time.Time, interface{})) int64 {
  timeout := NewOnTimeOut(client.netid, cb)
  var id int64 = -1
  if client.timing != nil {
    id = client.timing.AddTimer(t, 0, timeout)
    if id >= 0 {
      client.pendingTimers = append(client.pendingTimers, id)
      log.Println("Pending timers ", client.pendingTimers)
    }
  }
  return id
}

func (client *TCPConnection)RunAfter(d time.Duration, cb func(time.Time, interface{})) int64 {
  delay := time.Now().Add(d)
  var id int64 = -1
  if client.timing != nil {
    id = client.RunAt(delay, cb)
  }
  return id
}

func (client *TCPConnection)RunEvery(i time.Duration, cb func(time.Time, interface{})) int64 {
  delay := time.Now().Add(i)
  timeout := NewOnTimeOut(client.netid, cb)
  var id int64 = -1
  if client.timing != nil {
    id = client.timing.AddTimer(delay, i, timeout)
    if id >= 0 {
      client.pendingTimers = append(client.pendingTimers, id)
    }
  }
  return id
}

func (client *TCPConnection)CancelTimer(timerId int64) {
  client.timing.CancelTimer(timerId)
}

func (client *TCPConnection)startLoop(looper func()) {
  client.wg.Add(1)
  go func() {
    looper()
    client.wg.Done()
  }()
}

func (client *TCPConnection) RawConn() net.Conn {
  return client.conn
}

/* readLoop() blocking read from connection, deserialize bytes into message,
then find corresponding handler, put it into channel */
func (client *TCPConnection)readLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    default:
    }

    msg, err := client.messageCodec.Decode(client)
    if err != nil {
      log.Printf("Error decoding message - %s", err)
      if err == ErrorUndefined {
        // update heart beat timestamp
        client.HeartBeat = time.Now().UnixNano()
        continue
      }
      return
    }

    // update heart beat timestamp
    client.HeartBeat = time.Now().UnixNano()
    handlerFactory := HandlerMap.Get(msg.MessageNumber())
    if handlerFactory == nil {
      if client.onMessage != nil {
        log.Printf("Message %d call onMessage()\n", msg.MessageNumber())
        client.onMessage(msg, client)
      } else {
        log.Printf("No handler or onMessage() found for message %d", msg.MessageNumber())
      }
      continue
    }

    // send handler to handleLoop
    handler := handlerFactory(client.NetId(), msg)
    client.handlerRecvChan<- handler
  }
}

/* writeLoop() receive message from channel, serialize it into bytes,
then blocking write into connection */
func (client *TCPConnection)writeLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case packet := <-client.messageSendChan:
      if _, err := client.conn.Write(packet); err != nil {
        log.Printf("Error writing data - %s\n", err)
      }
    }
  }
}

/* handleLoop() handles business logic in server or client mode:
(1) server mode - put handler or timeout callback into worker go-routines
(2) client mode - run handler or timeout callback in handleLoop() go-routine */
func (client *TCPConnection)handleLoop() {
  if client.isServerMode() {
    client.handleServerMode()
  } else {
    client.handleClientMode()
  }
}

func (client *TCPConnection)handleServerMode() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      if !isNil(handler) {
        client.Owner.workerPool.Put(client.netid, func() {
          handler.Process(client)
        })
      }

    case timeout := <-client.timeOutChan:
      if timeout != nil {
        extraData := timeout.ExtraData.(int64)
        if extraData != client.netid {
          log.Printf("[Warn] time out of %d running on client %d", extraData, client.netid)
        }
        client.Owner.workerPool.Put(client.netid, func() {
          timeout.Callback(time.Now(), client)
        })
      }
    }
  }
}

func (client *TCPConnection)handleClientMode() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      if !isNil(handler) {
        handler.Process(client)
      }

    case timeout := <-client.timing.TimeOutChan:
      if timeout != nil {
        extraData := timeout.ExtraData.(int64)
        if extraData != client.netid {
          log.Printf("[Warn] time out of %d running on client %d", extraData, client.netid)
        }
        timeout.Callback(time.Now(), client)
      }
    }
  }
}
<commit_msg>bugfix: finish writing before close<commit_after>package tao

import (
  "log"
  "net"
  "sync"
  "time"
)

const (
  NTYPE = 4
  NLEN = 4
  MAXLEN = 1 << 23  // 8M
)

type TCPConnection struct {
  netid int64
  Owner *TCPServer
  conn net.Conn
  address string
  name string
  closeOnce sync.Once
  wg *sync.WaitGroup
  timing *TimingWheel
  messageSendChan chan []byte
  handlerRecvChan chan MessageHandler
  closeConnChan chan struct{}
  timeOutChan chan *OnTimeOut
  HeartBeat int64
  pendingTimers []int64
  reconnect bool
  closed *AtomicBoolean
  messageCodec Codec
  extraData interface{}
  onConnect onConnectFunc
  onMessage onMessageFunc
  onClose onCloseFunc
  onError onErrorFunc
}

func ClientTCPConnection(id int64, addr string, t *TimingWheel, reconn bool) *TCPConnection {
  c, err := net.Dial("tcp", addr)
  if err != nil {
    log.Fatalln(err)
  }
  return &TCPConnection {
    netid: id,
    conn: c,
    address: addr,
    wg: &sync.WaitGroup{},
    timing: t,
    messageSendChan: make(chan []byte, 1024),
    handlerRecvChan: make(chan MessageHandler, 1024),
    closeConnChan: make(chan struct{}),
    timeOutChan: make(chan *OnTimeOut),
    HeartBeat: time.Now().UnixNano(),
    pendingTimers: []int64{},
    reconnect: reconn,
    closed: NewAtomicBoolean(false),
    messageCodec: TypeLengthValueCodec{},
  }
}

func ServerTCPConnection(id int64, s *TCPServer, c net.Conn) *TCPConnection {
  tcpConn := &TCPConnection {
    netid: id,
    Owner: s,
    conn: c,
    wg: &sync.WaitGroup{},
    timing: s.timing,
    messageSendChan: make(chan []byte, 1024),
    handlerRecvChan: make(chan MessageHandler, 1024),
    closeConnChan: make(chan struct{}),
    timeOutChan: make(chan *OnTimeOut),
    HeartBeat: time.Now().UnixNano(),
    pendingTimers: []int64{},
    reconnect: false,
    closed: NewAtomicBoolean(false),
    messageCodec: TypeLengthValueCodec{},
  }
  tcpConn.SetOnConnectCallback(s.onConnect)
  tcpConn.SetOnMessageCallback(s.onMessage)
  tcpConn.SetOnErrorCallback(s.onError)
  tcpConn.SetOnCloseCallback(s.onClose)
  return tcpConn
}

func (client *TCPConnection)SetExtraData(data interface{}) {
  client.extraData = data
}

func (client *TCPConnection)GetExtraData() interface{} {
  return client.extraData
}

func (client *TCPConnection)NetId() int64 {
  return client.netid
}

func (client *TCPConnection)Reconnect() {
  netid := client.netid
  address := client.address
  timing := client.timing
  reconnect := client.reconnect
  client = ClientTCPConnection(netid, address, timing, reconnect)
  client.Do()
}

func (client *TCPConnection)SetCodec(cdc Codec) {
  client.messageCodec = cdc
}

func (client *TCPConnection)isServerMode() bool {
  return client.Owner != nil
}

func (client *TCPConnection)SetOnConnectCallback(cb func(*TCPConnection) bool) {
  if cb != nil {
    client.onConnect = onConnectFunc(cb)
  }
}

func (client *TCPConnection)SetOnMessageCallback(cb func(Message, *TCPConnection)) {
  if cb != nil {
    client.onMessage = onMessageFunc(cb)
  }
}

func (client *TCPConnection)SetOnErrorCallback(cb func()) {
  if cb != nil {
    client.onError = onErrorFunc(cb)
  }
}

func (client *TCPConnection)Wait() {
  client.wg.Wait()
}

func (client *TCPConnection)SetOnCloseCallback(cb func(*TCPConnection)) {
  if cb != nil {
    client.onClose = onCloseFunc(cb)
  }
}

func (client *TCPConnection)RemoteAddr() net.Addr {
  return client.conn.RemoteAddr()
}

func (client *TCPConnection)SetName(n string) {
  client.name = n
}

func (client *TCPConnection)String() string {
  return client.name
}

func (client *TCPConnection)IsClosed() bool {
  return client.closed.Get()
}

func (client *TCPConnection)Close() {
  client.closeOnce.Do(func() {
    if client.closed.CompareAndSet(false, true) {
      close(client.closeConnChan)
      close(client.messageSendChan)
      close(client.handlerRecvChan)
      close(client.timeOutChan)
      client.wg.Wait()
      client.conn.Close()

      if (client.onClose != nil) {
        client.onClose(client)
      }

      if client.isServerMode() {
        client.Owner.connections.Remove(client.netid)
        for _, id := range client.pendingTimers {
          client.CancelTimer(id)
        }
      } else {
        client.Reconnect()
      }
    }
  })
}

func (client *TCPConnection)Write(msg Message) error {
  packet, err := client.messageCodec.Encode(msg)
  if err != nil {
    return err
  }

  select {
  case client.messageSendChan<- packet:
    return nil
  default:
    return ErrorWouldBlock
  }
}

/* If onConnect() returns true, start three go-routines for each client:
readLoop(), writeLoop() and handleLoop() */
func (client *TCPConnection)Do() {
  if client.onConnect != nil && !client.onConnect(client) {
    log.Fatalln("Error onConnect()\n")
  }

  // start read, write and handle loop
  client.startLoop(client.readLoop)
  client.startLoop(client.writeLoop)
  client.startLoop(client.handleLoop)
}

func (client *TCPConnection)RunAt(t time.Time, cb func(time.Time, interface{})) int64 {
  timeout := NewOnTimeOut(client.netid, cb)
  var id int64 = -1
  if client.timing != nil {
    id = client.timing.AddTimer(t, 0, timeout)
    if id >= 0 {
      client.pendingTimers = append(client.pendingTimers, id)
      log.Println("Pending timers ", client.pendingTimers)
    }
  }
  return id
}

func (client *TCPConnection)RunAfter(d time.Duration, cb func(time.Time, interface{})) int64 {
  delay := time.Now().Add(d)
  var id int64 = -1
  if client.timing != nil {
    id = client.RunAt(delay, cb)
  }
  return id
}

func (client *TCPConnection)RunEvery(i time.Duration, cb func(time.Time, interface{})) int64 {
  delay := time.Now().Add(i)
  timeout := NewOnTimeOut(client.netid, cb)
  var id int64 = -1
  if client.timing != nil {
    id = client.timing.AddTimer(delay, i, timeout)
    if id >= 0 {
      client.pendingTimers = append(client.pendingTimers, id)
    }
  }
  return id
}

func (client *TCPConnection)CancelTimer(timerId int64) {
  client.timing.CancelTimer(timerId)
}

func (client *TCPConnection)startLoop(looper func()) {
  client.wg.Add(1)
  go func() {
    looper()
    client.wg.Done()
  }()
}

func (client *TCPConnection) RawConn() net.Conn {
  return client.conn
}

/* readLoop() blocking read from connection, deserialize bytes into message,
then find corresponding handler, put it into channel */
func (client *TCPConnection)readLoop() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    default:
    }

    msg, err := client.messageCodec.Decode(client)
    if err != nil {
      log.Printf("Error decoding message - %s", err)
      if err == ErrorUndefined {
        // update heart beat timestamp
        client.HeartBeat = time.Now().UnixNano()
        continue
      }
      return
    }

    // update heart beat timestamp
    client.HeartBeat = time.Now().UnixNano()
    handlerFactory := HandlerMap.Get(msg.MessageNumber())
    if handlerFactory == nil {
      if client.onMessage != nil {
        log.Printf("Message %d call onMessage()\n", msg.MessageNumber())
        client.onMessage(msg, client)
      } else {
        log.Printf("No handler or onMessage() found for message %d", msg.MessageNumber())
      }
      continue
    }

    // send handler to handleLoop
    handler := handlerFactory(client.NetId(), msg)
    client.handlerRecvChan<- handler
  }
}

/* writeLoop() receive message from channel, serialize it into bytes,
then blocking write into connection */
func (client *TCPConnection)writeLoop() {
  defer func() {
    recover()
    for packet := range client.messageSendChan {
      if packet != nil {
        if _, err := client.conn.Write(packet); err != nil {
          log.Printf("Error writing data - %s\n", err)
        }
      }
    }
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case packet := <-client.messageSendChan:
      if packet != nil {
        if _, err := client.conn.Write(packet); err != nil {
          log.Printf("Error writing data - %s\n", err)
        }
      }
    }
  }
}

/* handleLoop() handles business logic in server or client mode:
(1) server mode - put handler or timeout callback into worker go-routines
(2) client mode - run handler or timeout callback in handleLoop() go-routine */
func (client *TCPConnection)handleLoop() {
  if client.isServerMode() {
    client.handleServerMode()
  } else {
    client.handleClientMode()
  }
}

func (client *TCPConnection)handleServerMode() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      if !isNil(handler) {
        client.Owner.workerPool.Put(client.netid, func() {
          handler.Process(client)
        })
      }

    case timeout := <-client.timeOutChan:
      if timeout != nil {
        extraData := timeout.ExtraData.(int64)
        if extraData != client.netid {
          log.Printf("[Warn] time out of %d running on client %d", extraData, client.netid)
        }
        client.Owner.workerPool.Put(client.netid, func() {
          timeout.Callback(time.Now(), client)
        })
      }
    }
  }
}

func (client *TCPConnection)handleClientMode() {
  defer func() {
    recover()
    client.Close()
  }()

  for {
    select {
    case <-client.closeConnChan:
      return

    case handler := <-client.handlerRecvChan:
      if !isNil(handler) {
        handler.Process(client)
      }

    case timeout := <-client.timing.TimeOutChan:
      if timeout != nil {
        extraData := timeout.ExtraData.(int64)
        if extraData != client.netid {
          log.Printf("[Warn] time out of %d running on client %d", extraData, client.netid)
        }
        timeout.Callback(time.Now(), client)
      }
    }
  }
}
<|endoftext|>


<commit_before>package handlers

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/boltdb/bolt"
	humanize "github.com/dustin/go-humanize"
	"github.com/gojp/goreportcard/check"
	"github.com/gojp/goreportcard/download"
)

func dirName(repo string) string {
	return fmt.Sprintf("_repos/src/%s", repo)
}

func getFromCache(repo string) (checksResp, error) {
	// try and fetch from boltdb
	db, err := bolt.Open(DBPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
	if err != nil {
		return checksResp{}, fmt.Errorf("failed to open bolt database during GET: %v", err)
	}
	defer db.Close()

	resp := checksResp{}
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(RepoBucket))
		if b == nil {
			return errors.New("No repo bucket")
		}
		cached := b.Get([]byte(repo))
		if cached == nil {
			return fmt.Errorf("%q not found in cache", repo)
		}

		err = json.Unmarshal(cached, &resp)
		if err != nil {
			return fmt.Errorf("failed to parse JSON for %q in cache", repo)
		}
		return nil
	})

	if err != nil {
		return resp, err
	}

	resp.LastRefresh = resp.LastRefresh.UTC()
	resp.LastRefreshFormatted = resp.LastRefresh.Format(time.UnixDate)
	resp.LastRefreshHumanized = humanize.Time(resp.LastRefresh.UTC())

	return resp, nil
}

type score struct {
	Name          string              `json:"name"`
	Description   string              `json:"description"`
	FileSummaries []check.FileSummary `json:"file_summaries"`
	Weight        float64             `json:"weight"`
	Percentage    float64             `json:"percentage"`
	Error         string              `json:"error"`
}

type checksResp struct {
	Checks               []score   `json:"checks"`
	Average              float64   `json:"average"`
	Grade                Grade     `json:"grade"`
	Files                int       `json:"files"`
	Issues               int       `json:"issues"`
	Repo                 string    `json:"repo"`
	ResolvedRepo         string    `json:"resolvedRepo"`
	LastRefresh          time.Time `json:"last_refresh"`
	LastRefreshFormatted string    `json:"formatted_last_refresh"`
	LastRefreshHumanized string    `json:"humanized_last_refresh"`
}

func newChecksResp(repo string, forceRefresh bool) (checksResp, error) {
	if !forceRefresh {
		resp, err := getFromCache(repo)
		if err != nil {
			// just log the error and continue
			log.Println(err)
		} else {
			resp.Grade = grade(resp.Average * 100) // grade is not stored for some repos, yet
			return resp, nil
		}
	}

	// fetch the repo and grade it
	repoRoot, err := download.Download(repo, "_repos/src")
	if err != nil {
		return checksResp{}, fmt.Errorf("could not clone repo: %v", err)
	}

	repo = repoRoot.Root

	dir := dirName(repo)
	filenames, skipped, err := check.GoFiles(dir)
	if err != nil {
		return checksResp{}, fmt.Errorf("could not get filenames: %v", err)
	}
	if len(filenames) == 0 {
		return checksResp{}, fmt.Errorf("no .go files found")
	}

	err = check.RenameFiles(skipped)
	if err != nil {
		log.Println("Could not remove files:", err)
	}
	defer check.RevertFiles(skipped)

	checks := []check.Check{
		check.GoFmt{Dir: dir, Filenames: filenames},
		check.GoVet{Dir: dir, Filenames: filenames},
		check.GoLint{Dir: dir, Filenames: filenames},
		check.GoCyclo{Dir: dir, Filenames: filenames},
		check.License{Dir: dir, Filenames: []string{}},
		check.Misspell{Dir: dir, Filenames: filenames},
		check.IneffAssign{Dir: dir, Filenames: filenames},
		// check.ErrCheck{Dir: dir, Filenames: filenames}, // disable errcheck for now, too slow and not finalized
	}

	ch := make(chan score)
	for _, c := range checks {
		go func(c check.Check) {
			p, summaries, err := c.Percentage()
			errMsg := ""
			if err != nil {
				log.Printf("ERROR: (%s) %v", c.Name(), err)
				errMsg = err.Error()
			}
			s := score{
				Name:          c.Name(),
				Description:   c.Description(),
				FileSummaries: summaries,
				Weight:        c.Weight(),
				Percentage:    p,
				Error:         errMsg,
			}
			ch <- s
		}(c)
	}

	t := time.Now().UTC()
	resp := checksResp{
		Repo:                 repo,
		ResolvedRepo:         repoRoot.Repo,
		Files:                len(filenames),
		LastRefresh:          t,
		LastRefreshFormatted: t.Format(time.UnixDate),
		LastRefreshHumanized: humanize.Time(t),
	}

	var total, totalWeight float64
	var issues = make(map[string]bool)
	for i := 0; i < len(checks); i++ {
		s := <-ch
		resp.Checks = append(resp.Checks, s)
		total += s.Percentage * s.Weight
		totalWeight += s.Weight
		for _, fs := range s.FileSummaries {
			issues[fs.Filename] = true
		}
	}
	total /= totalWeight

	sort.Sort(ByWeight(resp.Checks))
	resp.Average = total
	resp.Issues = len(issues)
	resp.Grade = grade(total * 100)

	return resp, nil
}

// ByWeight implements sorting for checks by weight descending
type ByWeight []score

func (a ByWeight) Len() int           { return len(a) }
func (a ByWeight) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByWeight) Less(i, j int) bool { return a[i].Weight > a[j].Weight }
<commit_msg>increase boltdb timeout<commit_after>package handlers

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/boltdb/bolt"
	humanize "github.com/dustin/go-humanize"
	"github.com/gojp/goreportcard/check"
	"github.com/gojp/goreportcard/download"
)

func dirName(repo string) string {
	return fmt.Sprintf("_repos/src/%s", repo)
}

func getFromCache(repo string) (checksResp, error) {
	// try and fetch from boltdb
	db, err := bolt.Open(DBPath, 0600, &bolt.Options{Timeout: 3 * time.Second})
	if err != nil {
		return checksResp{}, fmt.Errorf("failed to open bolt database during GET: %v", err)
	}
	defer db.Close()

	resp := checksResp{}
	err = db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(RepoBucket))
		if b == nil {
			return errors.New("No repo bucket")
		}
		cached := b.Get([]byte(repo))
		if cached == nil {
			return fmt.Errorf("%q not found in cache", repo)
		}

		err = json.Unmarshal(cached, &resp)
		if err != nil {
			return fmt.Errorf("failed to parse JSON for %q in cache", repo)
		}
		return nil
	})

	if err != nil {
		return resp, err
	}

	resp.LastRefresh = resp.LastRefresh.UTC()
	resp.LastRefreshFormatted = resp.LastRefresh.Format(time.UnixDate)
	resp.LastRefreshHumanized = humanize.Time(resp.LastRefresh.UTC())

	return resp, nil
}

type score struct {
	Name          string              `json:"name"`
	Description   string              `json:"description"`
	FileSummaries []check.FileSummary `json:"file_summaries"`
	Weight        float64             `json:"weight"`
	Percentage    float64             `json:"percentage"`
	Error         string              `json:"error"`
}

type checksResp struct {
	Checks               []score   `json:"checks"`
	Average              float64   `json:"average"`
	Grade                Grade     `json:"grade"`
	Files                int       `json:"files"`
	Issues               int       `json:"issues"`
	Repo                 string    `json:"repo"`
	ResolvedRepo         string    `json:"resolvedRepo"`
	LastRefresh          time.Time `json:"last_refresh"`
	LastRefreshFormatted string    `json:"formatted_last_refresh"`
	LastRefreshHumanized string    `json:"humanized_last_refresh"`
}

func newChecksResp(repo string, forceRefresh bool) (checksResp, error) {
	if !forceRefresh {
		resp, err := getFromCache(repo)
		if err != nil {
			// just log the error and continue
			log.Println(err)
		} else {
			resp.Grade = grade(resp.Average * 100) // grade is not stored for some repos, yet
			return resp, nil
		}
	}

	// fetch the repo and grade it
	repoRoot, err := download.Download(repo, "_repos/src")
	if err != nil {
		return checksResp{}, fmt.Errorf("could not clone repo: %v", err)
	}

	repo = repoRoot.Root

	dir := dirName(repo)
	filenames, skipped, err := check.GoFiles(dir)
	if err != nil {
		return checksResp{}, fmt.Errorf("could not get filenames: %v", err)
	}
	if len(filenames) == 0 {
		return checksResp{}, fmt.Errorf("no .go files found")
	}

	err = check.RenameFiles(skipped)
	if err != nil {
		log.Println("Could not remove files:", err)
	}
	defer check.RevertFiles(skipped)

	checks := []check.Check{
		check.GoFmt{Dir: dir, Filenames: filenames},
		check.GoVet{Dir: dir, Filenames: filenames},
		check.GoLint{Dir: dir, Filenames: filenames},
		check.GoCyclo{Dir: dir, Filenames: filenames},
		check.License{Dir: dir, Filenames: []string{}},
		check.Misspell{Dir: dir, Filenames: filenames},
		check.IneffAssign{Dir: dir, Filenames: filenames},
		// check.ErrCheck{Dir: dir, Filenames: filenames}, // disable errcheck for now, too slow and not finalized
	}

	ch := make(chan score)
	for _, c := range checks {
		go func(c check.Check) {
			p, summaries, err := c.Percentage()
			errMsg := ""
			if err != nil {
				log.Printf("ERROR: (%s) %v", c.Name(), err)
				errMsg = err.Error()
			}
			s := score{
				Name:          c.Name(),
				Description:   c.Description(),
				FileSummaries: summaries,
				Weight:        c.Weight(),
				Percentage:    p,
				Error:         errMsg,
			}
			ch <- s
		}(c)
	}

	t := time.Now().UTC()
	resp := checksResp{
		Repo:                 repo,
		ResolvedRepo:         repoRoot.Repo,
		Files:                len(filenames),
		LastRefresh:          t,
		LastRefreshFormatted: t.Format(time.UnixDate),
		LastRefreshHumanized: humanize.Time(t),
	}

	var total, totalWeight float64
	var issues = make(map[string]bool)
	for i := 0; i < len(checks); i++ {
		s := <-ch
		resp.Checks = append(resp.Checks, s)
		total += s.Percentage * s.Weight
		totalWeight += s.Weight
		for _, fs := range s.FileSummaries {
			issues[fs.Filename] = true
		}
	}
	total /= totalWeight

	sort.Sort(ByWeight(resp.Checks))
	resp.Average = total
	resp.Issues = len(issues)
	resp.Grade = grade(total * 100)

	return resp, nil
}

// ByWeight implements sorting for checks by weight descending
type ByWeight []score

func (a ByWeight) Len() int           { return len(a) }
func (a ByWeight) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a ByWeight) Less(i, j int) bool { return a[i].Weight > a[j].Weight }
<|endoftext|>


<commit_before>package solr

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

func HTTPPost(path string, data *[]byte, headers [][]string) ([]byte, error) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", path, bytes.NewReader(*data))
	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

func HTTPGet(url string, headers [][]string) ([]byte, error) {
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)

	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, err
	}
	return body, nil
}

func bytes2json(data *[]byte) (map[string]interface{}, error) {
	var container interface{}

	err := json.Unmarshal(*data, &container)

	if err != nil {
		return nil, fmt.Errorf("Response decode error")
	}

	return container.(map[string]interface{}), nil
}

func json2bytes(data map[string]interface{}) (*[]byte, error) {
	b, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode JSON")
	}

	return &b, nil
}

type SelectResponse struct {
	results *Collection
	status  int
	qtime   int
}

type UpdateResponse struct {
	success bool
}

type ErrorResponse struct {
	message string
	status  int
}

type Connection struct {
	url *url.URL
}

func NewConnection(solrUrl string) (*Connection, error) {
	u, err := url.Parse(solrUrl)
	if err != nil {
		return nil, err
	}

	return &Connection{url: u}, nil
}

func (c *Connection) Select(selectUrl string) (*SelectResponse, error) {
	return nil, nil
}

func (c *Connection) Update(data map[string]interface{}) (*UpdateResponse, error) {
	b, err := json2bytes(data)
	if err != nil {
		return nil, err
	}
	r, err := HTTPPost(c.url.String(), b, nil)
	if err != nil {
		return nil, err
	}
	resp, err := bytes2json(&r)
	if err != nil {
		return nil, err
	}
	// check error in resp
	_ = resp

	return &UpdateResponse{true}, nil
}

func (c *Connection) Commit() (*UpdateResponse, error) {
	return nil, nil
}

func (c *Connection) Optimize() (*UpdateResponse, error) {
	return nil, nil
}

func (c *Connection) Rollback() (*UpdateResponse, error) {
	return nil, nil
}
<commit_msg>Build select query<commit_after>package solr

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

func HTTPPost(path string, data *[]byte, headers [][]string) ([]byte, error) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", path, bytes.NewReader(*data))
	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	return body, nil
}

func HTTPGet(url string, headers [][]string) ([]byte, error) {
	client := &http.Client{}
	req, err := http.NewRequest("GET", url, nil)

	if len(headers) > 0 {
		for i := range headers {
			req.Header.Add(headers[i][0], headers[i][1])
		}
	}

	resp, err := client.Do(req)

	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return nil, err
	}
	return body, nil
}

func bytes2json(data *[]byte) (map[string]interface{}, error) {
	var container interface{}

	err := json.Unmarshal(*data, &container)

	if err != nil {
		return nil, fmt.Errorf("Response decode error")
	}

	return container.(map[string]interface{}), nil
}

func json2bytes(data map[string]interface{}) (*[]byte, error) {
	b, err := json.Marshal(data)
	if err != nil {
		return nil, fmt.Errorf("Failed to encode JSON")
	}

	return &b, nil
}

type SelectResponse struct {
	results *Collection
	status  int
	qtime   int
}

type UpdateResponse struct {
	success bool
}

type ErrorResponse struct {
	message string
	status  int
}

type Connection struct {
	url *url.URL
}

func NewConnection(solrUrl string) (*Connection, error) {
	u, err := url.Parse(solrUrl)
	if err != nil {
		return nil, err
	}

	return &Connection{url: u}, nil
}

func (c *Connection) Select(selectQuery string) (*SelectResponse, error) {
	r, err := HTTPGet(fmt.Sprintf("%s/select?%s", c.url.String(), selectQuery), nil)
	if err != nil {
		return nil, err
	}
	resp, err := bytes2json(&r)
	if err != nil {
		return nil, err
	}
	// check error and parse result
	_ = resp

	return nil, nil
}

func (c *Connection) Update(data map[string]interface{}) (*UpdateResponse, error) {
	b, err := json2bytes(data)
	if err != nil {
		return nil, err
	}
	r, err := HTTPPost(c.url.String(), b, nil)
	if err != nil {
		return nil, err
	}
	resp, err := bytes2json(&r)
	if err != nil {
		return nil, err
	}
	// check error in resp
	_ = resp

	return &UpdateResponse{true}, nil
}

func (c *Connection) Commit() (*UpdateResponse, error) {
	return nil, nil
}

func (c *Connection) Optimize() (*UpdateResponse, error) {
	return nil, nil
}

func (c *Connection) Rollback() (*UpdateResponse, error) {
	return nil, nil
}
<|endoftext|>


<commit_before>package handlers

import (
	"log"
	"net/http"

	"github.com/alexdmtr/www/services/eventService"
)

func events(w http.ResponseWriter, r *http.Request) {

	var eventsContext struct {
		EventGroup   *eventService.EventGroup
		HaveRightNow bool
		HaveUpcoming bool
	}
	eventGroup, err := eventService.GroupEvents()

	if err != nil {
		log.Println(err)
		errorHandler(w, r, http.StatusServiceUnavailable)
		return
	}

	eventsContext.EventGroup = eventGroup
	eventsContext.HaveRightNow = len(eventGroup.RightNow) > 0
	eventsContext.HaveUpcoming = len(eventGroup.Upcoming) > 0

	renderTemplate(w, r, "events", eventsContext)

	if err != nil {
		log.Println(err)
	}
}
<commit_msg>[refactor] Remove redunant error handling<commit_after>package handlers

import (
	"log"
	"net/http"

	"github.com/alexdmtr/www/services/eventService"
)

func events(w http.ResponseWriter, r *http.Request) {

	var eventsContext struct {
		EventGroup   *eventService.EventGroup
		HaveRightNow bool
		HaveUpcoming bool
	}
	eventGroup, err := eventService.GroupEvents()

	if err != nil {
		log.Println(err)
		errorHandler(w, r, http.StatusServiceUnavailable)
		return
	}

	eventsContext.EventGroup = eventGroup
	eventsContext.HaveRightNow = len(eventGroup.RightNow) > 0
	eventsContext.HaveUpcoming = len(eventGroup.Upcoming) > 0

	renderTemplate(w, r, "events", eventsContext)
}
<|endoftext|>


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

package text

// TODO: do we care about "\n" vs "\r" vs "\r\n"? We only recognize "\n" for
// now.

import (
	"strings"

	"golang.org/x/image/math/fixed"
)

// Caret is a location in a Frame's text, and is the mechanism for adding and
// removing bytes of text. Conceptually, a Caret and a Frame's text is like an
// int c and a []byte t such that the text before and after that Caret is t[:c]
// and t[c:]. That byte-count location remains unchanged even when a Frame is
// re-sized and laid out into a new tree of Paragraphs, Lines and Boxes.
//
// A Frame can have multiple open Carets. For example, the beginning and end of
// a text selection can be represented by two Carets. Multiple Carets for the
// one Frame are not safe to use concurrently, but it is valid to interleave
// such operations sequentially. For example, if two Carets c0 and c1 for the
// one Frame are positioned at the 10th and 20th byte, and 4 bytes are written
// to c0, inserting what becomes the equivalent of text[10:14], then c0's
// position is updated to be 14 but c1's position is also updated to be 24.
type Caret struct {
	f *Frame

	// caretsIndex is the index of this Caret in the f.carets slice.
	caretsIndex int

	// p, l and b index the Caret's Paragraph, Line and Box. None of these
	// values can be zero.
	p, l, b int32

	// pos is the Caret's position in the text, in layout order. It is the "c"
	// as in "t[:c]" in the doc comment for type Caret above. It is not valid
	// to index the Frame.text slice with pos, since the Frame.text slice does
	// not necessarily hold the textual content in layout order.
	pos int32

	// k is the Caret's position in the text, in Frame.text order. It is valid
	// to index the Frame.text slice with k, analogous to the Box.i and Box.j
	// fields. For a Caret c, letting bb := c.f.boxes[c.b], an invariant is
	// that bb.i <= c.k && c.k <= bb.j.
	k int32
}

// TODO: many Caret methods: Seek, ReadXxx, WriteXxx, Delete, maybe others.

// Close closes the Caret.
func (c *Caret) Close() error {
	i, j := c.caretsIndex, len(c.f.carets)-1

	// Swap c with the last element of c.f.carets.
	if i != j {
		other := c.f.carets[j]
		other.caretsIndex = i
		c.f.carets[i] = other
	}

	c.f.carets[j] = nil
	c.f.carets = c.f.carets[:j]
	*c = Caret{}
	return nil
}

// WriteString inserts s into the Frame's text at the Caret.
//
// The error returned is always nil.
func (c *Caret) WriteString(s string) (n int, err error) {
	n = len(s)
	for len(s) > 0 {
		i := 1 + strings.IndexByte(s, '\n')
		if i == 0 {
			i = len(s)
		}
		c.writeString(s[:i])
		s = s[i:]
	}
	return n, nil
}

// writeString inserts s into the Frame's text at the Caret.
//
// s must be non-empty, it must contain at most one '\n' and if it does contain
// one, it must be the final byte.
func (c *Caret) writeString(s string) {
	// If the Box's text is empty, move its empty i:j range to the equivalent
	// empty range at the end of c.f.text.
	if bb, n := &c.f.boxes[c.b], int32(len(c.f.text)); bb.i == bb.j && bb.i != n {
		bb.i = n
		bb.j = n
		for _, cc := range c.f.carets {
			if cc.b == c.b {
				cc.k = n
			}
		}
	}

	if c.k != int32(len(c.f.text)) {
		panic("TODO: inserting text somewhere other than at the end of the text buffer")
	}

	// Assert that the Caret c is at the end of its Box, and that Box's text is
	// at the end of the Frame's buffer.
	if c.k != c.f.boxes[c.b].j || c.k != int32(len(c.f.text)) {
		panic("text: invalid state")
	}

	c.f.text = append(c.f.text, s...)
	c.f.len += len(s)
	c.f.boxes[c.b].j += int32(len(s))
	c.k += int32(len(s))
	for _, cc := range c.f.carets {
		if cc.pos > c.pos {
			cc.pos += int32(len(s))
		}
	}
	c.pos += int32(len(s))
	oldL := c.l

	if s[len(s)-1] == '\n' {
		breakParagraph(c.f, c.p, c.l, c.b)
		c.p = c.f.paragraphs[c.p].next
		c.l = c.f.paragraphs[c.p].firstL
		c.b = c.f.lines[c.l].firstB
		c.k = c.f.boxes[c.b].i
	}

	// TODO: re-layout the new c.p paragraph, if we saw '\n'.
	layout(c.f, oldL)
}

// breakParagraph breaks the Paragraph p into two Paragraphs, just after Box b
// in Line l in Paragraph p. b's text must end with a '\n'. The new Paragraph
// is inserted after p.
func breakParagraph(f *Frame, p, l, b int32) {
	// Assert that the Box b's text ends with a '\n'.
	if j := f.boxes[b].j; j == 0 || f.text[j-1] != '\n' {
		panic("text: invalid state")
	}

	// Make a new, empty Paragraph after this Paragraph p.
	newP := f.newParagraph()
	nextP := f.paragraphs[p].next
	if nextP != 0 {
		f.paragraphs[nextP].prev = newP
	}
	f.paragraphs[newP].next = nextP
	f.paragraphs[newP].prev = p
	f.paragraphs[p].next = newP

	// Any Lines in this Paragraph after the break point's Line l move to the
	// newP Paragraph.
	if nextL := f.lines[l].next; nextL != 0 {
		f.lines[l].next = 0
		f.lines[nextL].prev = 0
		f.paragraphs[newP].firstL = nextL
	}

	// Any Boxes in this Line after the break point's Box b move to a new Line
	// at the start of the newP Paragraph.
	if nextB := f.boxes[b].next; nextB != 0 {
		f.boxes[b].next = 0
		f.boxes[nextB].prev = 0
		newL := f.newLine()
		f.lines[newL].firstB = nextB
		if newPFirstL := f.paragraphs[newP].firstL; newPFirstL != 0 {
			f.lines[newL].next = newPFirstL
			f.lines[newPFirstL].prev = newL
		}
		f.paragraphs[newP].firstL = newL
	}

	// Make the newP Paragraph's first Line and first Box explicit, since
	// Carets require an explicit p, l and b.
	{
		firstL := f.paragraphs[newP].firstLine(f)
		f.lines[firstL].firstBox(f)
	}

	// TODO: fix up other Carets's p, l and b fields.
	// TODO: re-layout the newP paragraph.
}

// breakLine breaks the Line l at text index k in Box b. The b-and-k index must
// not be at the start or end of the Line. Text to the right of b-and-k in the
// Line l will be moved to the start of the next Line in the Paragraph, with
// that next Line being created if it didn't already exist.
func breakLine(f *Frame, l, b, k int32) {
	// Split this Box into two if necessary, so that k equals a Box's j end.
	bb := &f.boxes[b]
	if k != bb.j {
		if k == bb.i {
			panic("TODO: degenerate split left, possibly adjusting the Line's firstB??")
		}
		newB := f.newBox()
		nextB := bb.next
		if nextB != 0 {
			f.boxes[nextB].prev = newB
		}
		f.boxes[newB].next = nextB
		f.boxes[newB].prev = b
		f.boxes[newB].i = k
		f.boxes[newB].j = bb.j
		bb.next = newB
		bb.j = k
	}

	// Assert that the break point isn't already at the start or end of the Line.
	if bb.next == 0 || (bb.prev == 0 && k == bb.i) {
		panic("text: invalid state")
	}

	// Insert a line after this one, if one doesn't already exist.
	ll := &f.lines[l]
	if ll.next == 0 {
		newL := f.newLine()
		f.lines[ll.next].prev = newL
		f.lines[newL].next = ll.next
		f.lines[newL].prev = l
		ll.next = newL
	}

	// Move the remaining boxes to the next line.
	nextB, nextL := bb.next, ll.next
	bb.next = 0
	f.boxes[nextB].prev = 0
	if f.lines[nextL].firstB == 0 {
		f.lines[nextL].firstB = nextB
	} else {
		panic("TODO: prepend the remaining boxes to the next Line's existing boxes")
	}

	// TODO: fix up other Carets's p, l and b fields.
}

// layout inserts a soft return in the Line l if its text measures longer than
// f.maxWidth and a suitable line break point is found. This may spill text
// onto the next line, which will also be laid out, and so on recursively.
func layout(f *Frame, l int32) {
	if f.face == nil {
		return
	}

	for ; l != 0; l = f.lines[l].next {
		var (
			firstB     = f.lines[l].firstB
			reader     = f.lineReader(firstB, f.boxes[firstB].i)
			breakPoint bAndK
			prevR      rune
			prevRValid bool
			advance    fixed.Int26_6
		)
		for {
			r, _, err := reader.ReadRune()
			if err != nil || r == '\n' {
				return
			}
			if prevRValid {
				advance += f.face.Kern(prevR, r)
			}
			// TODO: match all whitespace, not just ' '?
			if r == ' ' {
				breakPoint = reader.bAndK()
			}
			a, ok := f.face.GlyphAdvance(r)
			if !ok {
				panic("TODO: is falling back on the U+FFFD glyph the responsibility of the caller or the Face?")
			}
			advance += a
			if r != ' ' && advance > f.maxWidth && breakPoint.b != 0 {
				breakLine(f, l, breakPoint.b, breakPoint.k)
				break
			}
			prevR, prevRValid = r, true
		}
	}
}
<commit_msg>shiny/text: treat maxWidth <= 0 as infinite, as per the docs.<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package text

// TODO: do we care about "\n" vs "\r" vs "\r\n"? We only recognize "\n" for
// now.

import (
	"strings"

	"golang.org/x/image/math/fixed"
)

// Caret is a location in a Frame's text, and is the mechanism for adding and
// removing bytes of text. Conceptually, a Caret and a Frame's text is like an
// int c and a []byte t such that the text before and after that Caret is t[:c]
// and t[c:]. That byte-count location remains unchanged even when a Frame is
// re-sized and laid out into a new tree of Paragraphs, Lines and Boxes.
//
// A Frame can have multiple open Carets. For example, the beginning and end of
// a text selection can be represented by two Carets. Multiple Carets for the
// one Frame are not safe to use concurrently, but it is valid to interleave
// such operations sequentially. For example, if two Carets c0 and c1 for the
// one Frame are positioned at the 10th and 20th byte, and 4 bytes are written
// to c0, inserting what becomes the equivalent of text[10:14], then c0's
// position is updated to be 14 but c1's position is also updated to be 24.
type Caret struct {
	f *Frame

	// caretsIndex is the index of this Caret in the f.carets slice.
	caretsIndex int

	// p, l and b index the Caret's Paragraph, Line and Box. None of these
	// values can be zero.
	p, l, b int32

	// pos is the Caret's position in the text, in layout order. It is the "c"
	// as in "t[:c]" in the doc comment for type Caret above. It is not valid
	// to index the Frame.text slice with pos, since the Frame.text slice does
	// not necessarily hold the textual content in layout order.
	pos int32

	// k is the Caret's position in the text, in Frame.text order. It is valid
	// to index the Frame.text slice with k, analogous to the Box.i and Box.j
	// fields. For a Caret c, letting bb := c.f.boxes[c.b], an invariant is
	// that bb.i <= c.k && c.k <= bb.j.
	k int32
}

// TODO: many Caret methods: Seek, ReadXxx, WriteXxx, Delete, maybe others.

// Close closes the Caret.
func (c *Caret) Close() error {
	i, j := c.caretsIndex, len(c.f.carets)-1

	// Swap c with the last element of c.f.carets.
	if i != j {
		other := c.f.carets[j]
		other.caretsIndex = i
		c.f.carets[i] = other
	}

	c.f.carets[j] = nil
	c.f.carets = c.f.carets[:j]
	*c = Caret{}
	return nil
}

// WriteString inserts s into the Frame's text at the Caret.
//
// The error returned is always nil.
func (c *Caret) WriteString(s string) (n int, err error) {
	n = len(s)
	for len(s) > 0 {
		i := 1 + strings.IndexByte(s, '\n')
		if i == 0 {
			i = len(s)
		}
		c.writeString(s[:i])
		s = s[i:]
	}
	return n, nil
}

// writeString inserts s into the Frame's text at the Caret.
//
// s must be non-empty, it must contain at most one '\n' and if it does contain
// one, it must be the final byte.
func (c *Caret) writeString(s string) {
	// If the Box's text is empty, move its empty i:j range to the equivalent
	// empty range at the end of c.f.text.
	if bb, n := &c.f.boxes[c.b], int32(len(c.f.text)); bb.i == bb.j && bb.i != n {
		bb.i = n
		bb.j = n
		for _, cc := range c.f.carets {
			if cc.b == c.b {
				cc.k = n
			}
		}
	}

	if c.k != int32(len(c.f.text)) {
		panic("TODO: inserting text somewhere other than at the end of the text buffer")
	}

	// Assert that the Caret c is at the end of its Box, and that Box's text is
	// at the end of the Frame's buffer.
	if c.k != c.f.boxes[c.b].j || c.k != int32(len(c.f.text)) {
		panic("text: invalid state")
	}

	c.f.text = append(c.f.text, s...)
	c.f.len += len(s)
	c.f.boxes[c.b].j += int32(len(s))
	c.k += int32(len(s))
	for _, cc := range c.f.carets {
		if cc.pos > c.pos {
			cc.pos += int32(len(s))
		}
	}
	c.pos += int32(len(s))
	oldL := c.l

	if s[len(s)-1] == '\n' {
		breakParagraph(c.f, c.p, c.l, c.b)
		c.p = c.f.paragraphs[c.p].next
		c.l = c.f.paragraphs[c.p].firstL
		c.b = c.f.lines[c.l].firstB
		c.k = c.f.boxes[c.b].i
	}

	// TODO: re-layout the new c.p paragraph, if we saw '\n'.
	layout(c.f, oldL)
}

// breakParagraph breaks the Paragraph p into two Paragraphs, just after Box b
// in Line l in Paragraph p. b's text must end with a '\n'. The new Paragraph
// is inserted after p.
func breakParagraph(f *Frame, p, l, b int32) {
	// Assert that the Box b's text ends with a '\n'.
	if j := f.boxes[b].j; j == 0 || f.text[j-1] != '\n' {
		panic("text: invalid state")
	}

	// Make a new, empty Paragraph after this Paragraph p.
	newP := f.newParagraph()
	nextP := f.paragraphs[p].next
	if nextP != 0 {
		f.paragraphs[nextP].prev = newP
	}
	f.paragraphs[newP].next = nextP
	f.paragraphs[newP].prev = p
	f.paragraphs[p].next = newP

	// Any Lines in this Paragraph after the break point's Line l move to the
	// newP Paragraph.
	if nextL := f.lines[l].next; nextL != 0 {
		f.lines[l].next = 0
		f.lines[nextL].prev = 0
		f.paragraphs[newP].firstL = nextL
	}

	// Any Boxes in this Line after the break point's Box b move to a new Line
	// at the start of the newP Paragraph.
	if nextB := f.boxes[b].next; nextB != 0 {
		f.boxes[b].next = 0
		f.boxes[nextB].prev = 0
		newL := f.newLine()
		f.lines[newL].firstB = nextB
		if newPFirstL := f.paragraphs[newP].firstL; newPFirstL != 0 {
			f.lines[newL].next = newPFirstL
			f.lines[newPFirstL].prev = newL
		}
		f.paragraphs[newP].firstL = newL
	}

	// Make the newP Paragraph's first Line and first Box explicit, since
	// Carets require an explicit p, l and b.
	{
		firstL := f.paragraphs[newP].firstLine(f)
		f.lines[firstL].firstBox(f)
	}

	// TODO: fix up other Carets's p, l and b fields.
	// TODO: re-layout the newP paragraph.
}

// breakLine breaks the Line l at text index k in Box b. The b-and-k index must
// not be at the start or end of the Line. Text to the right of b-and-k in the
// Line l will be moved to the start of the next Line in the Paragraph, with
// that next Line being created if it didn't already exist.
func breakLine(f *Frame, l, b, k int32) {
	// Split this Box into two if necessary, so that k equals a Box's j end.
	bb := &f.boxes[b]
	if k != bb.j {
		if k == bb.i {
			panic("TODO: degenerate split left, possibly adjusting the Line's firstB??")
		}
		newB := f.newBox()
		nextB := bb.next
		if nextB != 0 {
			f.boxes[nextB].prev = newB
		}
		f.boxes[newB].next = nextB
		f.boxes[newB].prev = b
		f.boxes[newB].i = k
		f.boxes[newB].j = bb.j
		bb.next = newB
		bb.j = k
	}

	// Assert that the break point isn't already at the start or end of the Line.
	if bb.next == 0 || (bb.prev == 0 && k == bb.i) {
		panic("text: invalid state")
	}

	// Insert a line after this one, if one doesn't already exist.
	ll := &f.lines[l]
	if ll.next == 0 {
		newL := f.newLine()
		f.lines[ll.next].prev = newL
		f.lines[newL].next = ll.next
		f.lines[newL].prev = l
		ll.next = newL
	}

	// Move the remaining boxes to the next line.
	nextB, nextL := bb.next, ll.next
	bb.next = 0
	f.boxes[nextB].prev = 0
	if f.lines[nextL].firstB == 0 {
		f.lines[nextL].firstB = nextB
	} else {
		panic("TODO: prepend the remaining boxes to the next Line's existing boxes")
	}

	// TODO: fix up other Carets's p, l and b fields.
}

// layout inserts a soft return in the Line l if its text measures longer than
// f.maxWidth and a suitable line break point is found. This may spill text
// onto the next line, which will also be laid out, and so on recursively.
func layout(f *Frame, l int32) {
	if f.maxWidth <= 0 || f.face == nil {
		return
	}

	for ; l != 0; l = f.lines[l].next {
		var (
			firstB     = f.lines[l].firstB
			reader     = f.lineReader(firstB, f.boxes[firstB].i)
			breakPoint bAndK
			prevR      rune
			prevRValid bool
			advance    fixed.Int26_6
		)
		for {
			r, _, err := reader.ReadRune()
			if err != nil || r == '\n' {
				return
			}
			if prevRValid {
				advance += f.face.Kern(prevR, r)
			}
			// TODO: match all whitespace, not just ' '?
			if r == ' ' {
				breakPoint = reader.bAndK()
			}
			a, ok := f.face.GlyphAdvance(r)
			if !ok {
				panic("TODO: is falling back on the U+FFFD glyph the responsibility of the caller or the Face?")
			}
			advance += a
			if r != ' ' && advance > f.maxWidth && breakPoint.b != 0 {
				breakLine(f, l, breakPoint.b, breakPoint.k)
				break
			}
			prevR, prevRValid = r, true
		}
	}
}
<|endoftext|>


<commit_before>// +build OMIT

package main

import (
	"fmt"
	"sync"
)

// gen sends the values in nums on the returned channel, then closes it.
func gen(nums ...int) <-chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out <- n
		}
		close(out)
	}()
	return out
}

// sq receives values from in, squares them, and sends them on the returned
// channel, until in is closed.  Then sq closes the returned channel.
func sq(in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out <- n * n
		}
		close(out)
	}()
	return out
}

// merge receives values from each input channel and sends them on the returned
// channel.  merge closes the returned channel after all the input values have
// been sent.
func merge(cs ...<-chan int) <-chan int {
	var wg sync.WaitGroup
	out := make(chan int)

	// Start an output goroutine for each input channel in cs.  output
	// copies values from c to out until c is closed, then calls wg.Done.
	output := func(c <-chan int) {
		for n := range c {
			out <- n
		}
		wg.Done()
	}
	wg.Add(len(cs))
	for _, c := range cs {
		go output(c)
	}

	// Start a goroutine to close out once all the output goroutines are
	// done.  This must start after the wg.Add call.
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

func main() {
	in := gen(2, 3)

	// Distribute the sq work across two goroutines that both read from in.
	c1 := sq(in)
	c2 := sq(in)

	// Consume the first value from output.
	out := merge(c1, c2)
	fmt.Println(<-out) // 4 or 9
	return
	// Since we didn't receive the second value from out,
	// one of the output goroutines is hung attempting to send it.
}
<commit_msg>[x/blog] content: modify comment in pipelines article<commit_after>// +build OMIT

package main

import (
	"fmt"
	"sync"
)

// gen sends the values in nums on the returned channel, then closes it.
func gen(nums ...int) <-chan int {
	out := make(chan int)
	go func() {
		for _, n := range nums {
			out <- n
		}
		close(out)
	}()
	return out
}

// sq receives values from in, squares them, and sends them on the returned
// channel, until in is closed.  Then sq closes the returned channel.
func sq(in <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		for n := range in {
			out <- n * n
		}
		close(out)
	}()
	return out
}

// merge receives values from each input channel and sends them on the returned
// channel.  merge closes the returned channel after all the input values have
// been sent.
func merge(cs ...<-chan int) <-chan int {
	var wg sync.WaitGroup
	out := make(chan int)

	// Start an output goroutine for each input channel in cs.  output
	// copies values from c to out until c is closed, then calls wg.Done.
	output := func(c <-chan int) {
		for n := range c {
			out <- n
		}
		wg.Done()
	}
	wg.Add(len(cs))
	for _, c := range cs {
		go output(c)
	}

	// Start a goroutine to close out once all the output goroutines are
	// done.  This must start after the wg.Add call.
	go func() {
		wg.Wait()
		close(out)
	}()
	return out
}

func main() {
	in := gen(2, 3)

	// Distribute the sq work across two goroutines that both read from in.
	c1 := sq(in)
	c2 := sq(in)

	// Consume the first value from the output.
	out := merge(c1, c2)
	fmt.Println(<-out) // 4 or 9
	return
	// Since we didn't receive the second value from out,
	// one of the output goroutines is hung attempting to send it.
}
<|endoftext|>


<commit_before>package goRiffle

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

type websocketConnection struct {
	conn        *websocket.Conn
	connLock    sync.Mutex
	serializer  serializer
	messages    chan message
	payloadType int
	closed      bool
}

// TODO: make this just add the message to a channel so we don't block
func (ep *websocketConnection) Send(msg message) error {

	b, err := ep.serializer.serialize(msg)

	if err != nil {
		return err
	}

	ep.connLock.Lock()
	err = ep.conn.WriteMessage(ep.payloadType, b)
	ep.connLock.Unlock()

	return err
}

func (ep *websocketConnection) Receive() <-chan message {
	return ep.messages
}

func (ep *websocketConnection) Close() error {
	closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "goodbye")
	err := ep.conn.WriteControl(websocket.CloseMessage, closeMsg, time.Now().Add(5*time.Second))

	if err != nil {
		log.Println("error sending close message:", err)
	}

	ep.closed = true
	return ep.conn.Close()

	return nil
}

func (ep *websocketConnection) run() {
	for {
		if msgType, b, err := ep.conn.ReadMessage(); err != nil {
			if ep.closed {
				log.Println("peer connection closed")
			} else {
				log.Println("error reading from peer:", err)
				ep.conn.Close()
			}
			close(ep.messages)
			break
		} else if msgType == websocket.CloseMessage {
			fmt.Println("Close message recieved")
			ep.conn.Close()
			close(ep.messages)
			break
		} else {
			msg, err := ep.serializer.deserialize(b)
			if err != nil {
				log.Println("error deserializing peer message:", err)
				log.Println(b)
				// TODO: handle error
			} else {
				fmt.Println("Message received!")
				ep.messages <- msg
			}
		}
	}
}

func (c *Domain) registerListener(id uint) {
	//log.Println("register listener:", id)
	wait := make(chan message, 1)
	c.listeners[id] = wait
}

func (c *Domain) waitOnListener(id uint) (message, error) {
	if wait, ok := c.listeners[id]; !ok {
		return nil, fmt.Errorf("unknown listener uint: %v", id)
	} else {
		select {
		case msg := <-wait:
			return msg, nil
		case <-time.After(timeout):
			return nil, fmt.Errorf("timeout while waiting for message")
		}
	}
}

func (c *Domain) notifyListener(msg message, requestId uint) {
	// pass in the request uint so we don't have to do any type assertion
	if l, ok := c.listeners[requestId]; ok {
		l <- msg
	} else {
		log.Println("no listener for message", msg.messageType(), requestId)
	}
}

// Convenience function to get a single message from a peer
func getMessageTimeout(p connection, t time.Duration) (message, error) {
	select {
	case msg, open := <-p.Receive():
		if !open {
			return nil, fmt.Errorf("receive channel closed")
		}

		return msg, nil
	case <-time.After(t):
		return nil, fmt.Errorf("timeout waiting for message")
	}
}
<commit_msg>restabilizing<commit_after>package goRiffle

import (
	"fmt"
	"log"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

type websocketConnection struct {
	conn        *websocket.Conn
	connLock    sync.Mutex
	serializer  serializer
	messages    chan message
	payloadType int
	closed      bool
}

func Open() {
	dialer := websocket.Dialer{Subprotocols: []string{"wamp.2.json"}}
	conn, _, err := dialer.Dial(url, nil)

	if err != nil {
		return nil, err
	}

	connection := &websocketConnection{
		conn:        conn,
		messages:    make(chan message, 10),
		serializer:  new(jSONSerializer),
		payloadType: websocket.TextMessage,
	}

	if err != nil {
		return nil, err
	}

	go connection.run()
}

// TODO: make this just add the message to a channel so we don't block
func (ep *websocketConnection) Send(msg message) error {

	b, err := ep.serializer.serialize(msg)

	if err != nil {
		return err
	}

	ep.connLock.Lock()
	err = ep.conn.WriteMessage(ep.payloadType, b)
	ep.connLock.Unlock()

	return err
}

func (ep *websocketConnection) Receive() <-chan message {
	return ep.messages
}

func (ep *websocketConnection) Close() error {
	closeMsg := websocket.FormatCloseMessage(websocket.CloseNormalClosure, "goodbye")
	err := ep.conn.WriteControl(websocket.CloseMessage, closeMsg, time.Now().Add(5*time.Second))

	if err != nil {
		log.Println("error sending close message:", err)
	}

	ep.closed = true
	return ep.conn.Close()

	return nil
}

func (ep *websocketConnection) run() {
	for {
		if msgType, b, err := ep.conn.ReadMessage(); err != nil {
			if ep.closed {
				log.Println("peer connection closed")
			} else {
				log.Println("error reading from peer:", err)
				ep.conn.Close()
			}
			close(ep.messages)
			break
		} else if msgType == websocket.CloseMessage {
			fmt.Println("Close message recieved")
			ep.conn.Close()
			close(ep.messages)
			break
		} else {
			msg, err := ep.serializer.deserialize(b)
			if err != nil {
				log.Println("error deserializing peer message:", err)
				log.Println(b)
				// TODO: handle error
			} else {
				fmt.Println("Message received!")
				ep.messages <- msg
			}
		}
	}
}

func getMessageTimeout(p connection, t time.Duration) (message, error) {
	select {
	case msg, open := <-p.Receive():
		if !open {
			return nil, fmt.Errorf("receive channel closed")
		}

		return msg, nil
	case <-time.After(t):
		return nil, fmt.Errorf("timeout waiting for message")
	}
}
<|endoftext|>