<commit_before>package main

import (
    "log"
    "time"
    "fmt"
    "math/rand"

    "menteslibres.net/gosexy/redis"
    "code.google.com/p/go.net/websocket"
)

func main() {
    pageSample()
//mapsSample()
//    pageUpdates()
}

func random(min, max int) int {
    //rand.Seed(time.Now().Nanosecond())
    return rand.Intn(max - min) + min
}

func mapsSample() {
    client := redis.New()
    err := client.Connect("localhost", 6379)

    if err != nil {
        log.Fatalf("Connect failed: %s\n", err.Error())
        return
    }

    var message string
    for {
        message =  fmt.Sprintf("{\"Event\":\"MessageAll\",\"Body\":{\"Event\": \"tweet\", \"Message\": {\"coordinates\": [%v, %v]}},\"Time\":12312}", (random(0, 123)*-1), random(0, 64))
        client.Publish("Message", message)

        time.Sleep(20 * time.Millisecond)

    }
}

var pages = []string{"image", "new", "popular", "realtime", "memes", "gifs", "cats", "dogs", "seals", "headphones"}
func pageSample() {
    shut := make(chan bool)
    store := []*websocket.Conn{}

    for i := 0; i < 26000; i++ {

            ws, err := websocket.Dial("ws://localhost:4000/socket", "", "http://localhost/")
            if err != nil {
                log.Printf("initSocketListener Test failed, Could not connect")
            }

            Auth := fmt.Sprintf("{\"Event\":\"Authenticate\",\"Body\":{\"UID\":\"%v\"},\"Time\":1376138699}", i)
            if err := websocket.Message.Send(ws, Auth); err != nil {
                log.Fatal("Authenticate Test failed, Could not send Auth message")
            }

            page := fmt.Sprintf("{\"Event\":\"SetPage\",\"Body\":{\"Page\":\"%s\"},\"Time\":1376138699}", pages[random(0, len(pages))])
            if err := websocket.Message.Send(ws, page); err != nil {
                log.Fatal("Authenticate Test failed, Could not send Auth message")
            }

            store = append(store, ws)
  //      time.Sleep(20 * time.Millisecond)
    }

                <-shut
}

func pageUpdates() {
    client := redis.New()
    err := client.Connect("localhost", 6379)

    if err != nil {
        log.Fatalf("Connect failed: %s\n", err.Error())
        return
    }

    var message string
    for {
        page := pages[random(0, len(pages))]
        message =  fmt.Sprintf("{\"Event\":\"MessagePage\",\"Body\":{\"Event\": \"update\", \"Page\": \"%s\", \"Message\": {\"page\": \"%s\"}}, \"Time\":12312}",  page, page)
        client.Publish("Message", message)
        time.Sleep(20 * time.Millisecond)

    }
}
<commit_msg>update the testApp to work with new json structure<commit_after>package main

import (
    "log"
    "time"
    "fmt"
    "math/rand"

    "menteslibres.net/gosexy/redis"
    "code.google.com/p/go.net/websocket"
)

func main() {
    pageSample()
//mapsSample()
//    pageUpdates()
}

func random(min, max int) int {
    //rand.Seed(time.Now().Nanosecond())
    return rand.Intn(max - min) + min
}

func mapsSample() {
    client := redis.New()
    err := client.Connect("localhost", 6379)

    if err != nil {
        log.Fatalf("Connect failed: %s\n", err.Error())
        return
    }

    var message string
    for {
        message =  fmt.Sprintf("{\"Event\":\"MessageAll\",\"Body\":{\"Event\": \"tweet\", \"Message\": {\"coordinates\": [%v, %v]}},\"Time\":12312}", (random(0, 123)*-1), random(0, 64))
        client.Publish("Message", message)

        time.Sleep(20 * time.Millisecond)

    }
}

var pages = []string{"image", "new", "popular", "realtime", "memes", "gifs", "cats", "dogs", "seals", "headphones"}
func pageSample() {
    shut := make(chan bool)
    store := []*websocket.Conn{}

    for i := 0; i < 26000; i++ {

            ws, err := websocket.Dial("ws://localhost:4000/socket", "", "http://localhost/")
            if err != nil {
                log.Printf("initSocketListener Test failed, Could not connect")
            }

            Auth := fmt.Sprintf("{\"command\":{\"command\":\"authenticate\",\"user\":\"%v\"},\"message\":{\"time\":1378493866}}", i)
            if err := websocket.Message.Send(ws, Auth); err != nil {
                log.Fatal("Authenticate Test failed, Could not send Auth message")
            }

            page := fmt.Sprintf("{\"command\":{\"command\":\"setpage\",\"page\":\"%v\"},\"message\":{\"time\":1378493866}}", pages[random(0, len(pages))])
            if err := websocket.Message.Send(ws, page); err != nil {
                log.Fatal("Authenticate Test failed, Could not send Auth message")
            }

            store = append(store, ws)
  //      time.Sleep(20 * time.Millisecond)
    }

                <-shut
}

func pageUpdates() {
    client := redis.New()
    err := client.Connect("localhost", 6379)

    if err != nil {
        log.Fatalf("Connect failed: %s\n", err.Error())
        return
    }

    var message string
    for {
        page := pages[random(0, len(pages))]
        message =  fmt.Sprintf("{\"Event\":\"MessagePage\",\"Body\":{\"Event\": \"update\", \"Page\": \"%s\", \"Message\": {\"page\": \"%s\"}}, \"Time\":12312}",  page, page)
        client.Publish("Message", message)
        time.Sleep(20 * time.Millisecond)

    }
}
<|endoftext|>


<commit_before>package fox

import (
	"sync"
	"gopkg.in/gcfg.v1"
	"log"
)

// Data structure for configuration
type Config struct {
	Storage struct{
		Filepath string
			 }
}

// Sanitize the configuration
func sanitize(c *Config){
	// Make sure the db path ends with a forwardslash
	s := c.Storage.Filepath
	if len(s) > 0{
		if string(s[len(s) - 1]) != "/" {
			c.Storage.Filepath = s + "/"
		}
	}
}

func LoadConfig(){
	LoadConfigByName("config.gcfg")
}

func LoadConfigByName(name string){
	var isFatal bool = (config == nil)
	var fName = name
	var tmp *Config

	tmp = new(Config)

	if err := gcfg.ReadFileInto(tmp, fName); err != nil{
		// No config to start up on
		if isFatal {
			panic(err)
		} else {
			log.Println("Failed to load configuration from " + fName)
			return
		}
	}

	sanitize(tmp)
	cLock.Lock()
	config = tmp
	cLock.Unlock()
	log.Println("Success loading configuration from " + fName)
}

func getConfig() *Config{
	cLock.RLock()
	defer cLock.RUnlock()
	return config
}

// Global to hold the conf and a lock
var (
	config *Config
	cLock = new(sync.RWMutex)
)<commit_msg>Commented the config functions, other minor changes<commit_after>package fox

import (
	"sync"
	"gopkg.in/gcfg.v1"
	"log"
)

// Config is the data structure for passing configuration info
type Config struct {
	Storage struct{
		Filepath string
			 }
}

// Sanitize the configuration
func sanitize(c *Config){
	// Make sure the db path ends with a forwardslash
	s := c.Storage.Filepath
	if len(s) > 0{
		if string(s[len(s) - 1]) != "/" {
			c.Storage.Filepath = s + "/"
		}
	}
}

// LoadConfig loads configuration using a hard-coded name
// This is what gets called during normal operation
func LoadConfig(){
	LoadConfigByName("config.gcfg")
}

// LoadConfigByName loads a config from a specific file
// Used for separating test from operational conifguration
func LoadConfigByName(name string){
	var isFatal = (config == nil)
	var fName = name
	var tmp *Config

	tmp = new(Config)

	if err := gcfg.ReadFileInto(tmp, fName); err != nil{
		// No config to start up on
		if isFatal {
			panic(err)
		} else {
			log.Println("Failed to load configuration from " + fName)
			return
		}
	}

	sanitize(tmp)
	cLock.Lock()
	config = tmp
	cLock.Unlock()
	log.Println("Success loading configuration from " + fName)
}

func getConfig() *Config{
	cLock.RLock()
	defer cLock.RUnlock()
	return config
}

// Global to hold the conf and a lock
var (
	config *Config
	cLock = new(sync.RWMutex)
)<|endoftext|>


<commit_before>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/jinzhu/now"
	"github.com/qor/qor"
	"github.com/qor/qor/media_library"
	"github.com/qor/qor/roles"
)

type Meta struct {
	Base          Resourcer
	Name          string
	Alias         string
	Type          string
	Label         string
	Value         func(interface{}, *qor.Context) interface{}
	Setter        func(resource interface{}, metaValues *MetaValues, context *qor.Context)
	Collection    interface{}
	GetCollection func(interface{}, *qor.Context) [][]string
	Resource      Resourcer
	Permission    *roles.Permission
}

type Metaor interface {
	GetMeta() *Meta
	HasPermission(roles.PermissionMode, *qor.Context) bool
}

func (meta *Meta) GetMeta() *Meta {
	return meta
}

func (meta *Meta) HasPermission(mode roles.PermissionMode, context *qor.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

func (meta *Meta) UpdateMeta() {
	if meta.Name == "" {
		qor.ExitWithMsg("Meta should have name: %v", reflect.ValueOf(meta).Type())
	} else {
		if meta.Label == "" {
			meta.Label = HumanizeString(meta.Name)
		}
		if meta.Alias == "" {
			meta.Alias = meta.Name
		}
		meta.Alias = gorm.SnakeToUpperCamel(meta.Alias)
	}

	var (
		base        = meta.Base.GetResource()
		scope       = &gorm.Scope{Value: base.Value}
		field       *gorm.Field
		hasColumn   bool
		nestedField = strings.Contains(meta.Alias, ".")
		valueType   string
	)
	if nestedField {
		submodel, name := parseNestedField(reflect.ValueOf(base.Value), meta.Alias)
		subscope := &gorm.Scope{Value: submodel.Interface()}
		field, hasColumn = subscope.FieldByName(name)
	} else {
		field, hasColumn = scope.FieldByName(meta.Alias)
	}
	if hasColumn {
		valueType = field.Field.Type().Kind().String()
	}

	// Set Meta Type
	if meta.Type == "" {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "has_one" {
				meta.Type = "single_edit"
			} else if relationship.Kind == "has_many" {
				meta.Type = "collection_edit"
			} else if relationship.Kind == "many_to_many" {
				meta.Type = "select_many"
			}
		} else {
			switch valueType {
			case "string":
				meta.Type = "string"
			case "bool":
				meta.Type = "checkbox"
			default:
				if regexp.MustCompile(`^(u)?(int|float)(\d+)?`).MatchString(valueType) {
					meta.Type = "number"
				} else if _, ok := field.Field.Interface().(time.Time); ok {
					meta.Type = "datetime"
				} else if _, ok := field.Field.Interface().(media_library.MediaLibrary); ok {
					meta.Type = "file"
				}
			}
		}
	}

	// Set Meta Resource
	if meta.Resource == nil {
		if hasColumn && (field.Relationship != nil) {
			var result interface{}
			if valueType == "struct" {
				result = reflect.New(reflect.Indirect(field.Field).Type()).Interface()
			} else if valueType == "slice" {
				result = reflect.New(reflect.Indirect(field.Field).Type().Elem()).Interface()
			}

			resource := reflect.New(reflect.Indirect(reflect.ValueOf(meta.Base)).Type()).Interface()
			if resourcer, ok := resource.(Resourcer); ok {
				res := resourcer.GetResource()
				res.Value = result
				meta.Resource = resourcer
			}
		}
	}

	// Set Meta Value
	if meta.Value == nil {
		if hasColumn {
			meta.Value = func(value interface{}, context *qor.Context) interface{} {
				scope := &gorm.Scope{Value: value}
				alias := meta.Alias
				if nestedField {
					fields := strings.Split(alias, ".")
					alias = fields[len(fields)-1]
				}

				if f, ok := scope.FieldByName(alias); ok {
					if field.Relationship != nil {
						if f.Field.CanAddr() {
							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.Alias)
						}
					}
					return f.Field.Interface()
				}

				return ""
			}
		} else {
			qor.ExitWithMsg("Unsupported meta name %v for resource %v", meta.Name, reflect.TypeOf(base.Value))
		}
	}

	// Set Meta Collection
	if meta.Collection != nil {
		if maps, ok := meta.Collection.([]string); ok {
			meta.GetCollection = func(interface{}, *qor.Context) (results [][]string) {
				for _, value := range maps {
					results = append(results, []string{value, value})
				}
				return
			}
		} else if maps, ok := meta.Collection.([][]string); ok {
			meta.GetCollection = func(interface{}, *qor.Context) [][]string {
				return maps
			}
		} else if f, ok := meta.Collection.(func(interface{}, *qor.Context) [][]string); ok {
			meta.GetCollection = f
		} else {
			qor.ExitWithMsg("Unsupported Collection format for meta %v of resource %v", meta.Name, reflect.TypeOf(base.Value))
		}
	} else if meta.Type == "select_one" || meta.Type == "select_many" {
		qor.ExitWithMsg("%v meta type %v needs Collection", meta.Name, meta.Type)
	}

	scopeField, _ := scope.FieldByName(meta.Alias)

	// TODO: also support nested fields (Phone.Num)?
	if meta.Setter == nil {
		meta.Setter = func(resource interface{}, metaValues *MetaValues, context *qor.Context) {
			metaValue := metaValues.Get(meta.Name)
			if metaValue == nil {
				return
			}

			value := metaValue.Value
			scope := &gorm.Scope{Value: resource}
			alias := meta.Alias
			if nestedField {
				fields := strings.Split(alias, ".")
				alias = fields[len(fields)-1]
			}
			field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(alias)

			if field.IsValid() && field.CanAddr() {
				var relationship string
				if scopeField != nil && scopeField.Relationship != nil {
					relationship = scopeField.Relationship.Kind
				}
				if relationship == "many_to_many" {
					context.GetDB().Where(ToArray(value)).Find(field.Addr().Interface())
					if !scope.PrimaryKeyZero() {
						context.GetDB().Model(resource).Association(meta.Alias).Replace(field.Interface())
					}
				} else {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(ToUint(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(ToFloat(value))
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							scanner.Scan(ToString(value))
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(ToArray(value)).Convert(field.Type()))
						} else if rvalue := reflect.ValueOf(value); reflect.TypeOf(rvalue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rvalue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := ToString(value); str != "" {
								if newTime, err := now.Parse(str); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							}
						} else {
							var buf = bytes.NewBufferString("")
							json.NewEncoder(buf).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buf.String())).Decode(field.Addr().Interface()); err != nil {
								qor.ExitWithMsg("Can't set value %v to %v [meta %v]", reflect.ValueOf(value).Type(), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldvalue := meta.Value
		meta.Value = func(value interface{}, context *qor.Context) interface{} {
			return oldvalue(getNestedModel(value, meta.Alias, context), context)
		}
		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValues *MetaValues, context *qor.Context) {
			oldSetter(getNestedModel(resource, meta.Alias, context), metaValues, context)
		}
	}
}

func getNestedModel(value interface{}, alias string, context *qor.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(alias, ".")
	for _, field := range fields[:len(fields)-1] {
		if model.CanAddr() {
			submodel := model.FieldByName(field)
			if key := submodel.FieldByName("id"); !key.IsValid() || key.Uint() == 0 {
				if submodel.CanAddr() {
					context.GetDB().Model(model.Interface()).Related(submodel.Addr().Interface())
					model = submodel
				} else {
					break
				}
			}
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	} else {
		return nil
	}
}

// Profile.Name
func parseNestedField(value reflect.Value, name string) (reflect.Value, string) {
	fields := strings.Split(name, ".")
	value = reflect.Indirect(value)
	for _, field := range fields[:len(fields)-1] {
		value = value.FieldByName(field)
	}

	return value, fields[len(fields)-1]
}

func ToArray(value interface{}) (values []string) {
	if v, ok := value.([]string); ok {
		return v
	} else if v, ok := value.(string); ok {
		return []string{v}
	} else if vs, ok := value.([]interface{}); ok {
		for _, v := range vs {
			values = append(values, fmt.Sprintf("%v", v))
		}
	} else {
		panic(value)
	}
	return
}

func ToString(value interface{}) string {
	if v, ok := value.([]string); ok && len(v) > 0 {
		return v[0]
	} else if v, ok := value.(string); ok {
		return v
	} else if v, ok := value.([]interface{}); ok && len(v) > 0 {
		return fmt.Sprintf("%v", v[0])
	} else {
		panic(value)
	}
}

func ToInt(value interface{}) int64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToInt(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseInt(result, 10, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parseint")
	}
}

func ToUint(value interface{}) uint64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToUint(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseUint(result, 10, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parseuint")
	}
}

func ToFloat(value interface{}) float64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToFloat(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseFloat(result, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parsefloat")
	}
}

// HumanizeString will split a string by uppercase character
// and capitablize the first character in the string
// e.g.
// 	FieldName -> Field Name
func HumanizeString(label string) string {
	var new []rune
	for _, l := range label {
		if rune('A') <= l && l <= rune('Z') {
			new = append(new, rune(' '), rune(l))
		} else {
			new = append(new, rune(l))
		}
	}

	return strings.Title(string(new))
}
<commit_msg>Fix meta setter<commit_after>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/jinzhu/now"
	"github.com/qor/qor"
	"github.com/qor/qor/media_library"
	"github.com/qor/qor/roles"
)

type Meta struct {
	Base          Resourcer
	Name          string
	Alias         string
	Type          string
	Label         string
	Value         func(interface{}, *qor.Context) interface{}
	Setter        func(resource interface{}, metaValues *MetaValues, context *qor.Context)
	Collection    interface{}
	GetCollection func(interface{}, *qor.Context) [][]string
	Resource      Resourcer
	Permission    *roles.Permission
}

type Metaor interface {
	GetMeta() *Meta
	HasPermission(roles.PermissionMode, *qor.Context) bool
}

func (meta *Meta) GetMeta() *Meta {
	return meta
}

func (meta *Meta) HasPermission(mode roles.PermissionMode, context *qor.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

func (meta *Meta) UpdateMeta() {
	if meta.Name == "" {
		qor.ExitWithMsg("Meta should have name: %v", reflect.ValueOf(meta).Type())
	} else {
		if meta.Label == "" {
			meta.Label = HumanizeString(meta.Name)
		}
		if meta.Alias == "" {
			meta.Alias = meta.Name
		}
		meta.Alias = gorm.SnakeToUpperCamel(meta.Alias)
	}

	var (
		base        = meta.Base.GetResource()
		scope       = &gorm.Scope{Value: base.Value}
		field       *gorm.Field
		hasColumn   bool
		nestedField = strings.Contains(meta.Alias, ".")
		valueType   string
	)
	if nestedField {
		submodel, name := parseNestedField(reflect.ValueOf(base.Value), meta.Alias)
		subscope := &gorm.Scope{Value: submodel.Interface()}
		field, hasColumn = subscope.FieldByName(name)
	} else {
		field, hasColumn = scope.FieldByName(meta.Alias)
	}
	if hasColumn {
		valueType = field.Field.Type().Kind().String()
	}

	// Set Meta Type
	if meta.Type == "" {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "has_one" {
				meta.Type = "single_edit"
			} else if relationship.Kind == "has_many" {
				meta.Type = "collection_edit"
			} else if relationship.Kind == "many_to_many" {
				meta.Type = "select_many"
			}
		} else {
			switch valueType {
			case "string":
				meta.Type = "string"
			case "bool":
				meta.Type = "checkbox"
			default:
				if regexp.MustCompile(`^(u)?(int|float)(\d+)?`).MatchString(valueType) {
					meta.Type = "number"
				} else if _, ok := field.Field.Interface().(time.Time); ok {
					meta.Type = "datetime"
				} else if _, ok := field.Field.Interface().(media_library.MediaLibrary); ok {
					meta.Type = "file"
				}
			}
		}
	}

	// Set Meta Resource
	if meta.Resource == nil {
		if hasColumn && (field.Relationship != nil) {
			var result interface{}
			if valueType == "struct" {
				result = reflect.New(reflect.Indirect(field.Field).Type()).Interface()
			} else if valueType == "slice" {
				result = reflect.New(reflect.Indirect(field.Field).Type().Elem()).Interface()
			}

			resource := reflect.New(reflect.Indirect(reflect.ValueOf(meta.Base)).Type()).Interface()
			if resourcer, ok := resource.(Resourcer); ok {
				res := resourcer.GetResource()
				res.Value = result
				meta.Resource = resourcer
			}
		}
	}

	// Set Meta Value
	if meta.Value == nil {
		if hasColumn {
			meta.Value = func(value interface{}, context *qor.Context) interface{} {
				scope := &gorm.Scope{Value: value}
				alias := meta.Alias
				if nestedField {
					fields := strings.Split(alias, ".")
					alias = fields[len(fields)-1]
				}

				if f, ok := scope.FieldByName(alias); ok {
					if field.Relationship != nil {
						if f.Field.CanAddr() {
							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.Alias)
						}
					}
					return f.Field.Interface()
				}

				return ""
			}
		} else {
			qor.ExitWithMsg("Unsupported meta name %v for resource %v", meta.Name, reflect.TypeOf(base.Value))
		}
	}

	// Set Meta Collection
	if meta.Collection != nil {
		if maps, ok := meta.Collection.([]string); ok {
			meta.GetCollection = func(interface{}, *qor.Context) (results [][]string) {
				for _, value := range maps {
					results = append(results, []string{value, value})
				}
				return
			}
		} else if maps, ok := meta.Collection.([][]string); ok {
			meta.GetCollection = func(interface{}, *qor.Context) [][]string {
				return maps
			}
		} else if f, ok := meta.Collection.(func(interface{}, *qor.Context) [][]string); ok {
			meta.GetCollection = f
		} else {
			qor.ExitWithMsg("Unsupported Collection format for meta %v of resource %v", meta.Name, reflect.TypeOf(base.Value))
		}
	} else if meta.Type == "select_one" || meta.Type == "select_many" {
		qor.ExitWithMsg("%v meta type %v needs Collection", meta.Name, meta.Type)
	}

	scopeField, _ := scope.FieldByName(meta.Alias)

	// TODO: also support nested fields (Phone.Num)?
	if meta.Setter == nil {
		meta.Setter = func(resource interface{}, metaValues *MetaValues, context *qor.Context) {
			metaValue := metaValues.Get(meta.Name)
			if metaValue == nil {
				return
			}

			value := metaValue.Value
			scope := &gorm.Scope{Value: resource}
			alias := meta.Alias
			if nestedField {
				fields := strings.Split(alias, ".")
				alias = fields[len(fields)-1]
			}
			field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(alias)

			if field.IsValid() && field.CanAddr() {
				var relationship string
				if scopeField != nil && scopeField.Relationship != nil {
					relationship = scopeField.Relationship.Kind
				}
				if relationship == "many_to_many" {
					context.GetDB().Where(ToArray(value)).Find(field.Addr().Interface())
					if !scope.PrimaryKeyZero() {
						context.GetDB().Model(resource).Association(meta.Alias).Replace(field.Interface())
					}
				} else {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(ToUint(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(ToFloat(value))
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							scanner.Scan(ToString(value))
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(ToArray(value)).Convert(field.Type()))
						} else if rvalue := reflect.ValueOf(value); reflect.TypeOf(rvalue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rvalue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := ToString(value); str != "" {
								if newTime, err := now.Parse(str); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							}
						} else {
							var buf = bytes.NewBufferString("")
							json.NewEncoder(buf).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buf.String())).Decode(field.Addr().Interface()); err != nil {
								qor.ExitWithMsg("Can't set value %v to %v [meta %v]", reflect.ValueOf(value).Type(), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldvalue := meta.Value
		meta.Value = func(value interface{}, context *qor.Context) interface{} {
			return oldvalue(getNestedModel(value, meta.Alias, context), context)
		}
		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValues *MetaValues, context *qor.Context) {
			oldSetter(getNestedModel(resource, meta.Alias, context), metaValues, context)
		}
	}
}

func getNestedModel(value interface{}, alias string, context *qor.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(alias, ".")
	for _, field := range fields[:len(fields)-1] {
		if model.CanAddr() {
			submodel := model.FieldByName(field)
			if key := submodel.FieldByName("Id"); !key.IsValid() || key.Uint() == 0 {
				if submodel.CanAddr() {
					context.GetDB().Model(model.Interface()).Related(submodel.Addr().Interface())
					model = submodel
				} else {
					break
				}
			} else {
				model = submodel
			}
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	} else {
		return nil
	}
}

// Profile.Name
func parseNestedField(value reflect.Value, name string) (reflect.Value, string) {
	fields := strings.Split(name, ".")
	value = reflect.Indirect(value)
	for _, field := range fields[:len(fields)-1] {
		value = value.FieldByName(field)
	}

	return value, fields[len(fields)-1]
}

func ToArray(value interface{}) (values []string) {
	if v, ok := value.([]string); ok {
		return v
	} else if v, ok := value.(string); ok {
		return []string{v}
	} else if vs, ok := value.([]interface{}); ok {
		for _, v := range vs {
			values = append(values, fmt.Sprintf("%v", v))
		}
	} else {
		panic(value)
	}
	return
}

func ToString(value interface{}) string {
	if v, ok := value.([]string); ok && len(v) > 0 {
		return v[0]
	} else if v, ok := value.(string); ok {
		return v
	} else if v, ok := value.([]interface{}); ok && len(v) > 0 {
		return fmt.Sprintf("%v", v[0])
	} else {
		panic(value)
	}
}

func ToInt(value interface{}) int64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToInt(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseInt(result, 10, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parseint")
	}
}

func ToUint(value interface{}) uint64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToUint(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseUint(result, 10, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parseuint")
	}
}

func ToFloat(value interface{}) float64 {
	var result string
	if v, ok := value.([]string); ok && len(v) > 0 {
		result = v[0]
	} else if v, ok := value.(string); ok {
		result = v
	} else {
		return ToFloat(fmt.Sprintf("%v", value))
	}

	if i, err := strconv.ParseFloat(result, 64); err == nil {
		return i
	} else if result == "" {
		return 0
	} else {
		panic("failed to parsefloat")
	}
}

// HumanizeString will split a string by uppercase character
// and capitablize the first character in the string
// e.g.
// 	FieldName -> Field Name
func HumanizeString(label string) string {
	var new []rune
	for _, l := range label {
		if rune('A') <= l && l <= rune('Z') {
			new = append(new, rune(' '), rune(l))
		} else {
			new = append(new, rune(l))
		}
	}

	return strings.Title(string(new))
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT

package rest

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/issue9/assert/v2"
)

// Response 测试请求的返回结构
type Response struct {
	resp *http.Response
	a    *assert.Assertion
	body []byte
}

// Do 执行请求操作
func (req *Request) Do() *Response {
	r, err := http.NewRequest(req.method, req.prefix+req.buildPath(), req.body)
	req.a.NotError(err).NotNil(r)

	for k, v := range req.headers {
		r.Header.Add(k, v)
	}

	resp, err := req.client.Do(r)
	req.a.NotError(err).NotNil(resp)

	bs, err := ioutil.ReadAll(resp.Body)
	req.a.NotError(err).NotNil(bs)
	req.a.NotError(resp.Body.Close())
	return &Response{
		a:    req.a,
		resp: resp,
		body: bs,
	}
}

// Success 状态码是否在 100-399 之间
func (resp *Response) Success(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	resp.a.Assert(resp.resp.StatusCode >= 100 && resp.resp.StatusCode < 400, []interface{}{"当前状态码为 %d", resp.resp.StatusCode}, msg)
	return resp
}

// Fail 状态码是否大于 399
func (resp *Response) Fail(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	resp.a.Assert(resp.resp.StatusCode >= 400, []interface{}{"当前状态为 %d", resp.resp.StatusCode}, msg)
	return resp
}

// Status 判断状态码是否与 status 相等
func (resp *Response) Status(status int, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	resp.a.Assert(resp.resp.StatusCode == status, []interface{}{"实际状态为 %d，与期望值 %d 不符合", resp.resp.StatusCode, status}, msg)
	return resp
}

// NotStatus 判断状态码是否与 status 不相等
func (resp *Response) NotStatus(status int, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	resp.a.Assert(resp.resp.StatusCode != status, []interface{}{"状态码 %d 与期望值是相同的", resp.resp.StatusCode}, msg)
	return resp
}

// Header 判断指定的报头是否与 val 相同
//
// msg 可以为空，会返回一个默认的错误提示信息
func (resp *Response) Header(key string, val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	h := resp.resp.Header.Get(key)
	resp.a.Assert(h == val, []interface{}{"报头 %s 的值 %s 与期望值 %s 不同", key, h, val}, msg)
	return resp
}

// NotHeader 指定的报头必定不与 val 相同。
func (resp *Response) NotHeader(key string, val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	h := resp.resp.Header.Get(key)
	resp.a.Assert(h != val, []interface{}{"报头 %s 与期望值 %s 相等", key, h}, msg)
	return resp
}

// Body 报文内容是否与 val 相等
func (resp *Response) Body(val []byte, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.Equal(body, val, msg...)
	})
}

// StringBody 报文内容是否与 val 相等
func (resp *Response) StringBody(val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.Equal(string(body), val, msg...)
	})
}

// BodyNotNil 报文内容是否不为 nil
func (resp *Response) BodyNotNil(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.NotNil(body, msg...)
	})
}

// BodyNil 报文内容是否为 nil
func (resp *Response) BodyNil(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.Nil(body, msg...)
	})
}

// BodyNotEmpty 报文内容是否不为空
func (resp *Response) BodyNotEmpty(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.NotEmpty(body, msg...)
	})
}

// BodyEmpty 报文内容是否为空
func (resp *Response) BodyEmpty(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.Empty(body, msg...)
	})
}

// JSONBody 将 val 转换成 JSON 对象，并与 body 作对比
func (resp *Response) JSONBody(val interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		j, err := json.Marshal(val)
		a.NotError(err).NotNil(j).Equal(body, j)
	})
}

// BodyFunc 指定对 body 内容的断言方式
func (resp *Response) BodyFunc(f func(a *assert.Assertion, body []byte)) *Response {
	resp.a.TB().Helper()

	f(resp.a, resp.body)
	return resp
}

// ReadBody 读取 Body 的内容到 w
func (resp *Response) ReadBody(w io.Writer) *Response {
	n, err := w.Write(resp.body)
	resp.a.NotError(err).Equal(n, len(resp.body))
	return resp
}
<commit_msg>fix(rest): 修正 Response 的 msg 传递顺序错误<commit_after>// SPDX-License-Identifier: MIT

package rest

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/issue9/assert/v2"
)

// Response 测试请求的返回结构
type Response struct {
	resp *http.Response
	a    *assert.Assertion
	body []byte
}

// Do 执行请求操作
func (req *Request) Do() *Response {
	r, err := http.NewRequest(req.method, req.prefix+req.buildPath(), req.body)
	req.a.NotError(err).NotNil(r)

	for k, v := range req.headers {
		r.Header.Add(k, v)
	}

	resp, err := req.client.Do(r)
	req.a.NotError(err).NotNil(resp)

	bs, err := ioutil.ReadAll(resp.Body)
	req.a.NotError(err).NotNil(bs)
	req.a.NotError(resp.Body.Close())
	return &Response{
		a:    req.a,
		resp: resp,
		body: bs,
	}
}

func (resp *Response) assert(expr bool, msg1, msg2 []interface{}) *Response {
	resp.a.TB().Helper()
	resp.a.Assert(expr, msg1, msg2)
	return resp
}

// Success 状态码是否在 100-399 之间
func (resp *Response) Success(msg ...interface{}) *Response {
	resp.a.TB().Helper()
	succ := resp.resp.StatusCode >= 100 && resp.resp.StatusCode < 400
	return resp.assert(succ, msg, []interface{}{"当前状态码为 %d", resp.resp.StatusCode})
}

// Fail 状态码是否大于 399
func (resp *Response) Fail(msg ...interface{}) *Response {
	resp.a.TB().Helper()
	fail := resp.resp.StatusCode >= 400
	return resp.assert(fail, msg, []interface{}{"当前状态为 %d", resp.resp.StatusCode})
}

// Status 判断状态码是否与 status 相等
func (resp *Response) Status(status int, msg ...interface{}) *Response {
	resp.a.TB().Helper()
	eq := resp.resp.StatusCode == status
	return resp.assert(eq, msg, []interface{}{"实际状态为 %d，与期望值 %d 不符合", resp.resp.StatusCode, status})
}

// NotStatus 判断状态码是否与 status 不相等
func (resp *Response) NotStatus(status int, msg ...interface{}) *Response {
	resp.a.TB().Helper()
	neq := resp.resp.StatusCode != status
	return resp.assert(neq, msg, []interface{}{"状态码 %d 与期望值是相同的", resp.resp.StatusCode})
}

// Header 判断指定的报头是否与 val 相同
//
// msg 可以为空，会返回一个默认的错误提示信息
func (resp *Response) Header(key string, val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()
	h := resp.resp.Header.Get(key)
	return resp.assert(h == val, msg, []interface{}{"报头 %s 的值 %s 与期望值 %s 不同", key, h, val})
}

// NotHeader 指定的报头必定不与 val 相同。
func (resp *Response) NotHeader(key string, val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()
	h := resp.resp.Header.Get(key)
	return resp.assert(h != val, msg, []interface{}{"报头 %s 与期望值 %s 相等", key, h})
}

// Body 报文内容是否与 val 相等
func (resp *Response) Body(val []byte, msg ...interface{}) *Response {
	resp.a.TB().Helper()
	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.Equal(body, val, msg...)
	})
}

// StringBody 报文内容是否与 val 相等
func (resp *Response) StringBody(val string, msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.Equal(string(body), val, msg...)
	})
}

// BodyNotNil 报文内容是否不为 nil
func (resp *Response) BodyNotNil(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.NotNil(body, msg...)
	})
}

// BodyNil 报文内容是否为 nil
func (resp *Response) BodyNil(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.Nil(body, msg...)
	})
}

// BodyNotEmpty 报文内容是否不为空
func (resp *Response) BodyNotEmpty(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.NotEmpty(body, msg...)
	})
}

// BodyEmpty 报文内容是否为空
func (resp *Response) BodyEmpty(msg ...interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		a.Empty(body, msg...)
	})
}

// JSONBody 将 val 转换成 JSON 对象，并与 body 作对比
func (resp *Response) JSONBody(val interface{}) *Response {
	resp.a.TB().Helper()

	return resp.BodyFunc(func(a *assert.Assertion, body []byte) {
		a.TB().Helper()
		j, err := json.Marshal(val)
		a.NotError(err).NotNil(j).Equal(body, j)
	})
}

// BodyFunc 指定对 body 内容的断言方式
func (resp *Response) BodyFunc(f func(a *assert.Assertion, body []byte)) *Response {
	resp.a.TB().Helper()
	f(resp.a, resp.body)
	return resp
}

// ReadBody 读取 Body 的内容到 w
func (resp *Response) ReadBody(w io.Writer) *Response {
	n, err := w.Write(resp.body)
	resp.a.NotError(err).Equal(n, len(resp.body))
	return resp
}
<|endoftext|>


<commit_before>package router

import (
	"net/http"
	"regexp"
	"strings"
)

type Handler func(http.ResponseWriter, *http.Request, map[string]string)
type Middleware func(http.ResponseWriter, *http.Request, NextHandler)

//Route struct to store path with its methods and functions
type route struct {
	path       string
	methods    []string
	funcs      []*Handler
	rgx        *regexp.Regexp
	middleware *Middleware
}

//Router struct (class abstraction)
type Router struct {
	routes []route
}

//Contructor
func New() *Router {
	var routes []route
	return &Router{routes}
}

//Abstraction to exec next function
type NextHandler struct {
	handler *Handler
	params  map[string]string
}

//Exec next function when route has a middleware
func (n NextHandler) Exec(w http.ResponseWriter, r *http.Request) {
	next := *n.handler
	next(w, r, n.params)
	return
}

//Functions to add method and function to a path

//GET
func (r *Router) GET(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("GET", path, &handler, m)
	return
}

//POST
func (r *Router) POST(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("POST", path, &handler, m)
	return
}

//PUT
func (r *Router) PUT(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("PUT", path, &handler, m)
	return
}

//DELETE
func (r *Router) DELETE(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("DELETE", path, &handler, m)
	return
}

//Add Method check if path exists to append new method-function relation or create path with it
func (r *Router) addMethod(method, path string, handler *Handler, middlewares []*Middleware) {
	var middleware *Middleware
	if len(middlewares) > 0 {
		middleware = middlewares[0]
	}

	position := -1

	for i, route := range r.routes {
		if route.path == path {
			position = i
			break
		}
	}

	var res []string

	path_strs := strings.Split(path, "/")
	for _, str := range path_strs {
		if len(str) > 0 && string(str[0]) == string(":") {
			str = "([A-Za-z0-9-_]+)"
		}
		res = append(res, str)
	}

	rgx, _ := regexp.Compile(strings.Join(res, "/"))

	if position > -1 {
		r.routes[position].methods = append(r.routes[position].methods, method)
		r.routes[position].funcs = append(r.routes[position].funcs, handler)
		r.routes[position].rgx = rgx
		r.routes[position].middleware = middleware
	} else {
		methods := []string{method}
		funcs := []*Handler{handler}
		r.routes = append(r.routes, route{path, methods, funcs, rgx, middleware})
	}

	return
}

//Extract url params and check if route match with path
func (route route) parsePath(path string) (bool, map[string]string) {
	var params []string

	attrs := make(map[string]string)

	route_strs := strings.Split(route.path, "/")
	path_strs := strings.Split(path, "/")

	if len(route_strs) == len(path_strs) {

		for _, str := range route_strs {
			if len(str) > 0 && string(str[0]) == string(":") {
				params = append(params, str[1:])
			}
		}

		if route.rgx.MatchString(path) {
			values := route.rgx.FindStringSubmatch(path)
			values = values[1:]
			for i, value := range values {
				attrs[params[i]] = value
			}

			return true, attrs
		} else {
			return false, attrs
		}

	} else {
		return false, attrs
	}
}

//Serve routes over all its methods
func (route route) handleRoute(w http.ResponseWriter, r *http.Request, params map[string]string) {
	for position, method := range route.methods {
		if method == r.Method {
			if route.middleware == nil {
				f := *route.funcs[position]
				f(w, r, params)
			} else {
				m := *route.middleware
				m(w, r, NextHandler{route.funcs[position], params})
			}
		}
	}
	return
}

func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, route := range router.routes {
		match, params := route.parsePath(r.URL.Path)
		if match {
			route.handleRoute(w, r, params)
		}
	}
}

func (r *Router) Run(port string) {
	http.ListenAndServe(":"+port, r)
}
<commit_msg>404 Error checks, comments<commit_after>package router

import (
	"net/http"
	"regexp"
	"strings"
)

type Handler func(http.ResponseWriter, *http.Request, map[string]string)
type Middleware func(http.ResponseWriter, *http.Request, NextHandler)

//Route struct to store path with its methods and functions
type route struct {
	path       string
	methods    []string
	funcs      []*Handler
	rgx        *regexp.Regexp
	middleware *Middleware
}

//Router struct (class abstraction)
type Router struct {
	routes []route
}

//Contructor
func New() *Router {
	var routes []route
	return &Router{routes}
}

//Abstraction to exec next function
type NextHandler struct {
	handler *Handler
	params  map[string]string
}

//Exec next function when route has a middleware
func (n NextHandler) Exec(w http.ResponseWriter, r *http.Request) {
	next := *n.handler
	next(w, r, n.params)
	return
}

//Functions to add method and function to a path

//GET
func (r *Router) GET(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("GET", path, &handler, m)
	return
}

//POST
func (r *Router) POST(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("POST", path, &handler, m)
	return
}

//PUT
func (r *Router) PUT(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("PUT", path, &handler, m)
	return
}

//DELETE
func (r *Router) DELETE(path string, handler Handler, middlewares ...Middleware) {
	var m []*Middleware
	for _, middleware := range middlewares {
		m = append(m, &middleware)
	}
	r.addMethod("DELETE", path, &handler, m)
	return
}

//Create route with path, functions, methods, regexp to compare and middleware if exists
func (r *Router) addMethod(method, path string, handler *Handler, middlewares []*Middleware) {
	var middleware *Middleware
	if len(middlewares) > 0 {
		middleware = middlewares[0]
	}

	position := -1

	for i, route := range r.routes {
		if route.path == path {
			position = i
			break
		}
	}

	var res []string

	path_strs := strings.Split(path, "/")
	for _, str := range path_strs {
		if len(str) > 0 && string(str[0]) == string(":") {
			str = "([A-Za-z0-9-_]+)"
		}
		res = append(res, str)
	}

	rgx, _ := regexp.Compile(strings.Join(res, "/"))

	if position > -1 {
		r.routes[position].methods = append(r.routes[position].methods, method)
		r.routes[position].funcs = append(r.routes[position].funcs, handler)
		r.routes[position].rgx = rgx
		r.routes[position].middleware = middleware
	} else {
		methods := []string{method}
		funcs := []*Handler{handler}
		r.routes = append(r.routes, route{path, methods, funcs, rgx, middleware})
	}

	return
}

//Extract url params and check if route match with path
func (route route) parsePath(path string) (bool, map[string]string) {
	var params []string

	attrs := make(map[string]string)

	route_strs := strings.Split(route.path, "/")
	path_strs := strings.Split(path, "/")

	if len(route_strs) == len(path_strs) {

		for _, str := range route_strs {
			if len(str) > 0 && string(str[0]) == string(":") {
				params = append(params, str[1:])
			}
		}

		if route.rgx.MatchString(path) {
			values := route.rgx.FindStringSubmatch(path)
			values = values[1:]
			for i, value := range values {
				attrs[params[i]] = value
			}

			return true, attrs
		} else {
			return false, attrs
		}

	} else {
		return false, attrs
	}
}

//Serve routes over all its methods
func (route route) handleRoute(w http.ResponseWriter, r *http.Request, params map[string]string) {
	for position, method := range route.methods {
		if method == r.Method {
			if route.middleware == nil {
				f := *route.funcs[position]
				f(w, r, params)
				return
			} else {
				m := *route.middleware
				m(w, r, NextHandler{route.funcs[position], params})
				return
			}
		}
	}
	http.Error(w, "Not found.", 404)
	return
}

//Listen calls and call, if exists, its function
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	for _, route := range router.routes {
		match, params := route.parsePath(r.URL.Path)
		if match {
			route.handleRoute(w, r, params)
			return
		}
	}
	http.Error(w, "Not found.", 404)
	return
}

//Run on given port
func (r *Router) Run(port string) {
	http.ListenAndServe(":"+port, r)
}
<|endoftext|>


<commit_before>/*
The router package implements wrappers around
github.com/julienschmidt/httprouter.Router to enable the use of
golang.org/x/net/context.Context in endpoint handlers.
*/
package router

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/teepark/contextual"
	"golang.org/x/net/context"
)

const paramKey = "params"

// InitFunc is a function to transform the Context before an endpoint is called.
// To short-circuit and skip the handlers entirely, return a Context that is
// already done (probably by cancelling). Be sure you also set an appropriate
// response code to the ResponseWriter.
type InitFunc func(context.Context, http.ResponseWriter, *http.Request) context.Context

// Router wraps an httprouter.Router, then for each request adds the
// httprouter's Params as the Value("params") to the context, executes a custom
// initialization function, and passes the context on to handlers that accept
// it as an argument.
type Router struct {
	router *httprouter.Router
	base context.Context
	init InitFunc
}

// NewRouter creates a new Router around a given httprouter.Router.
// All arguments may be nil, in which case the Router would wrap a Router
// created with httprouter.New(), the base context would be context.Background(),
// and the adapter would not perform any initialization of the context.
func NewRouter(router *httprouter.Router, base context.Context, init InitFunc) *Router {
	if router == nil {
		router = httprouter.New()
	}
	if base == nil {
		base = context.Background()
	}

	return &Router{router, base, init}
}

// ServeHTTP implements http.Handler
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	router.router.ServeHTTP(w, r)
}

// Handle adds a method/path handler with a context.Context argument
func (r *Router) Handle(method, path string, handle contextual.Handler) {
	r.router.Handle(method, path, handlerShim(r, handle))
}

// GET is a shortcut for Handle("GET", ...)
func (r *Router) GET(path string, handle contextual.Handler) {
	r.Handle("GET", path, handle)
}

// HEAD is a shortcut for Handle("HEAD", ...)
func (r *Router) HEAD(path string, handle contextual.Handler) {
	r.Handle("HEAD", path, handle)
}

// POST is a shortcut for Handle("POST", ...)
func (r *Router) POST(path string, handle contextual.Handler) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for Handle("PUT", ...)
func (r *Router) PUT(path string, handle contextual.Handler) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for Handle("DELETE", ...)
func (r *Router) DELETE(path string, handle contextual.Handler) {
	r.Handle("DELETE", path, handle)
}

// OPTIONS is a shortcut for Handle("OPTIONS", ...)
func (r *Router) OPTIONS(path string, handle contextual.Handler) {
	r.Handle("OPTIONS", path, handle)
}

// PATCH is a shortcut for Handle("PATCH", ...)
func (r *Router) PATCH(path string, handle contextual.Handler) {
	r.Handle("PATCH", path, handle)
}

func handlerShim(router *Router, ctxHandle contextual.Handler) httprouter.Handle {
	return httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		ctx := context.WithValue(router.base, paramKey, p)

		if router.init != nil {
			ctx = router.init(ctx, w, r)
			select {
			case <-ctx.Done():
				return
			default:
			}
		}

		ctxHandle.Serve(ctx, w, r)
	})
}

// Params retrieves the httprouter Params from a context
func Params(c context.Context) httprouter.Params {
	p := c.Value(paramKey)
	if p == nil {
		return nil
	}
	return p.(httprouter.Params)
}
<commit_msg>adds a simple example<commit_after>/*
The router package implements wrappers around
github.com/julienschmidt/httprouter.Router to enable the use of
golang.org/x/net/context.Context in endpoint handlers.

A simple example looks like this:

	package main

	import (
		"fmt"
		"log"
		"net/http"

		"github.com/teepark/contextual"
		"github.com/teepark/contextual/router"
		"golang.org/x/net/context"
	)

	func index(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Welcome!")
	}

	func hello(ctx context.Context, w http.ResponseWriter, r *http.Request) {
		params := router.Params(ctx)
		fmt.Fprintf(w, "Hello, %s!\n", params.ByName("name"))
	}

	func main() {
		router := router.NewRouter(nil, nil, nil) // take all defaults
		router.GET("/", contextual.HandlerFunc(index))
		router.GET("/hello/:name", contextual.HandlerFunc(hello))

		log.Fatal(http.ListenAndServe(":8080", router))
	}
*/
package router

import (
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/teepark/contextual"
	"golang.org/x/net/context"
)

const paramKey = "params"

// InitFunc is a function to transform the Context before an endpoint is called.
// To short-circuit and skip the handlers entirely, return a Context that is
// already done (probably by cancelling). Be sure you also set an appropriate
// response code to the ResponseWriter.
type InitFunc func(context.Context, http.ResponseWriter, *http.Request) context.Context

// Router wraps an httprouter.Router, then for each request adds the
// httprouter's Params as the Value("params") to the context, executes a custom
// initialization function, and passes the context on to handlers that accept
// it as an argument.
type Router struct {
	router *httprouter.Router
	base   context.Context
	init   InitFunc
}

// NewRouter creates a new Router around a given httprouter.Router.
// All arguments may be nil, in which case the Router would wrap a Router
// created with httprouter.New(), the base context would be context.Background(),
// and the adapter would not perform any initialization of the context.
func NewRouter(router *httprouter.Router, base context.Context, init InitFunc) *Router {
	if router == nil {
		router = httprouter.New()
	}
	if base == nil {
		base = context.Background()
	}

	return &Router{router, base, init}
}

// ServeHTTP implements http.Handler
func (router *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	router.router.ServeHTTP(w, r)
}

// Handle adds a method/path handler with a context.Context argument
func (r *Router) Handle(method, path string, handle contextual.Handler) {
	r.router.Handle(method, path, handlerShim(r, handle))
}

// GET is a shortcut for Handle("GET", ...)
func (r *Router) GET(path string, handle contextual.Handler) {
	r.Handle("GET", path, handle)
}

// HEAD is a shortcut for Handle("HEAD", ...)
func (r *Router) HEAD(path string, handle contextual.Handler) {
	r.Handle("HEAD", path, handle)
}

// POST is a shortcut for Handle("POST", ...)
func (r *Router) POST(path string, handle contextual.Handler) {
	r.Handle("POST", path, handle)
}

// PUT is a shortcut for Handle("PUT", ...)
func (r *Router) PUT(path string, handle contextual.Handler) {
	r.Handle("PUT", path, handle)
}

// DELETE is a shortcut for Handle("DELETE", ...)
func (r *Router) DELETE(path string, handle contextual.Handler) {
	r.Handle("DELETE", path, handle)
}

// OPTIONS is a shortcut for Handle("OPTIONS", ...)
func (r *Router) OPTIONS(path string, handle contextual.Handler) {
	r.Handle("OPTIONS", path, handle)
}

// PATCH is a shortcut for Handle("PATCH", ...)
func (r *Router) PATCH(path string, handle contextual.Handler) {
	r.Handle("PATCH", path, handle)
}

func handlerShim(router *Router, ctxHandle contextual.Handler) httprouter.Handle {
	return httprouter.Handle(func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
		ctx := context.WithValue(router.base, paramKey, p)

		if router.init != nil {
			ctx = router.init(ctx, w, r)
			select {
			case <-ctx.Done():
				return
			default:
			}
		}

		ctxHandle.Serve(ctx, w, r)
	})
}

// Params retrieves the httprouter Params from a context
func Params(c context.Context) httprouter.Params {
	p := c.Value(paramKey)
	if p == nil {
		return nil
	}
	return p.(httprouter.Params)
}
<|endoftext|>


<commit_before>package router

import (
	"sync"

	"github.com/apcera/nats"
	"github.com/cloudfoundry/dropsonde"
	vcap "github.com/cloudfoundry/gorouter/common"
	"github.com/cloudfoundry/gorouter/config"
	"github.com/cloudfoundry/gorouter/proxy"
	"github.com/cloudfoundry/gorouter/registry"
	"github.com/cloudfoundry/gorouter/varz"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/yagnats"
	"github.com/pivotal-golang/localip"

	"bytes"
	"compress/zlib"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"time"
)

var DrainTimeout = errors.New("router: Drain timeout")
var noDeadline = time.Time{}

type Router struct {
	config     *config.Config
	proxy      proxy.Proxy
	mbusClient yagnats.NATSConn
	registry   *registry.RouteRegistry
	varz       varz.Varz
	component  *vcap.VcapComponent

	listener         net.Listener
	tlsListener      net.Listener
	closeConnections bool
	connLock         sync.Mutex
	idleConns        map[net.Conn]struct{}
	activeConns      map[net.Conn]struct{}
	drainDone        chan struct{}
	serveDone        chan struct{}
	tlsServeDone     chan struct{}

	logger *steno.Logger
}

func NewRouter(cfg *config.Config, p proxy.Proxy, mbusClient yagnats.NATSConn, r *registry.RouteRegistry, v varz.Varz,
	logCounter *vcap.LogCounter) (*Router, error) {

	var host string
	if cfg.Status.Port != 0 {
		host = fmt.Sprintf("%s:%d", cfg.Ip, cfg.Status.Port)
	}

	varz := &vcap.Varz{
		UniqueVarz: v,
		GenericVarz: vcap.GenericVarz{
			LogCounts: logCounter,
		},
	}

	healthz := &vcap.Healthz{}

	component := &vcap.VcapComponent{
		Type:        "Router",
		Index:       cfg.Index,
		Host:        host,
		Credentials: []string{cfg.Status.User, cfg.Status.Pass},
		Config:      cfg,
		Varz:        varz,
		Healthz:     healthz,
		InfoRoutes: map[string]json.Marshaler{
			"/routes": r,
		},
	}

	router := &Router{
		config:       cfg,
		proxy:        p,
		mbusClient:   mbusClient,
		registry:     r,
		varz:         v,
		component:    component,
		serveDone:    make(chan struct{}),
		tlsServeDone: make(chan struct{}),
		idleConns:    make(map[net.Conn]struct{}),
		activeConns:  make(map[net.Conn]struct{}),
		logger:       steno.NewLogger("router"),
	}

	if err := router.component.Start(); err != nil {
		return nil, err
	}

	return router, nil
}

func (r *Router) Run() <-chan error {
	r.registry.StartPruningCycle()

	r.RegisterComponent()

	// Subscribe register/unregister router
	r.SubscribeRegister()
	r.HandleGreetings()
	r.SubscribeUnregister()

	// Kickstart sending start messages
	r.SendStartMessage()

	r.mbusClient.AddReconnectedCB(func(conn *nats.Conn) {
		r.logger.Infof("Reconnecting to NATS server %s...", conn.Opts.Url)
		r.SendStartMessage()
	})

	// Schedule flushing active app's app_id
	r.ScheduleFlushApps()

	// Wait for one start message send interval, such that the router's registry
	// can be populated before serving requests.
	if r.config.StartResponseDelayInterval != 0 {
		r.logger.Infof("Waiting %s before listening...", r.config.StartResponseDelayInterval)
		time.Sleep(r.config.StartResponseDelayInterval)
	}

	server := &http.Server{
		Handler:   dropsonde.InstrumentedHandler(r.proxy),
		ConnState: r.HandleConnState,
	}

	errChan := make(chan error, 1)

	err := r.serveHTTP(server, errChan)
	if err != nil {
		errChan <- err
		return errChan
	}
	err = r.serveHTTPS(server, errChan)
	if err != nil {
		errChan <- err
		return errChan
	}

	return errChan
}

func (r *Router) serveHTTPS(server *http.Server, errChan chan error) error {
	if r.config.EnableSSL {
		tlsConfig := &tls.Config{
			Certificates: []tls.Certificate{r.config.SSLCertificate},
			CipherSuites: r.config.CipherSuites,
		}

		tlsListener, err := tls.Listen("tcp", fmt.Sprintf(":%d", r.config.SSLPort), tlsConfig)
		if err != nil {
			r.logger.Fatalf("tls.Listen: %s", err)
			return err
		}

		r.tlsListener = tlsListener
		r.logger.Infof("Listening on %s", tlsListener.Addr())

		go func() {
			err := server.Serve(tlsListener)
			errChan <- err
			close(r.tlsServeDone)
		}()
	}
	return nil
}

func (r *Router) serveHTTP(server *http.Server, errChan chan error) error {
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", r.config.Port))
	if err != nil {
		r.logger.Fatalf("net.Listen: %s", err)
		return err
	}

	r.listener = listener
	r.logger.Infof("Listening on %s", listener.Addr())

	go func() {
		err := server.Serve(listener)
		errChan <- err
		close(r.serveDone)
	}()
	return nil
}

func (r *Router) Drain(drainTimeout time.Duration) error {
	r.stopListening()

	drained := make(chan struct{})
	r.connLock.Lock()
	r.closeIdleConns()

	if len(r.activeConns) == 0 {
		close(drained)
	} else {
		r.drainDone = drained
	}
	r.connLock.Unlock()

	select {
	case <-drained:
	case <-time.After(drainTimeout):
		r.logger.Warn("router.drain.timed-out")
		return DrainTimeout
	}
	return nil
}

func (r *Router) Stop() {
	r.stopListening()

	r.connLock.Lock()
	r.closeIdleConns()
	r.connLock.Unlock()

	r.component.Stop()
}

// connLock must be locked
func (r *Router) closeIdleConns() {
	r.closeConnections = true

	for conn, _ := range r.idleConns {
		conn.Close()
	}
}

func (r *Router) stopListening() {
	r.listener.Close()

	if r.tlsListener != nil {
		r.tlsListener.Close()
		<-r.tlsServeDone
	}

	<-r.serveDone
}

func (r *Router) RegisterComponent() {
	r.component.Register(r.mbusClient)
}

func (r *Router) SubscribeRegister() {
	r.subscribeRegistry("router.register", func(registryMessage *registryMessage) {
		r.logger.Debugf("Got router.register: %v", registryMessage)

		for _, uri := range registryMessage.Uris {
			r.registry.Register(
				uri,
				registryMessage.makeEndpoint(),
			)
		}
	})
}

func (r *Router) SubscribeUnregister() {
	r.subscribeRegistry("router.unregister", func(registryMessage *registryMessage) {
		r.logger.Debugf("Got router.unregister: %v", registryMessage)

		for _, uri := range registryMessage.Uris {
			r.registry.Unregister(
				uri,
				registryMessage.makeEndpoint(),
			)
		}
	})
}

func (r *Router) HandleGreetings() {
	r.mbusClient.Subscribe("router.greet", func(msg *nats.Msg) {
		response, _ := r.greetMessage()
		r.mbusClient.Publish(msg.Reply, response)
	})
}

func (r *Router) SendStartMessage() {
	b, err := r.greetMessage()
	if err != nil {
		panic(err)
	}

	// Send start message once at start
	err = r.mbusClient.Publish("router.start", b)
}

func (r *Router) ScheduleFlushApps() {
	if r.config.PublishActiveAppsInterval == 0 {
		return
	}

	go func() {
		t := time.NewTicker(r.config.PublishActiveAppsInterval)
		x := time.Now()

		for {
			select {
			case <-t.C:
				y := time.Now()
				r.flushApps(x)
				x = y
			}
		}
	}()
}

func (r *Router) HandleConnState(conn net.Conn, state http.ConnState) {
	endpointTimeout := r.config.EndpointTimeout

	r.connLock.Lock()

	switch state {
	case http.StateActive:
		r.activeConns[conn] = struct{}{}
		delete(r.idleConns, conn)

		conn.SetDeadline(time.Time{})
	case http.StateIdle:
		delete(r.activeConns, conn)
		r.idleConns[conn] = struct{}{}

		if r.closeConnections {
			conn.Close()
		} else {
			deadline := noDeadline
			if endpointTimeout > 0 {
				deadline = time.Now().Add(endpointTimeout)
			}

			conn.SetDeadline(deadline)
		}
	case http.StateHijacked, http.StateClosed:
		i := len(r.idleConns)
		delete(r.idleConns, conn)
		if i == len(r.idleConns) {
			delete(r.activeConns, conn)
		}
	}

	if r.drainDone != nil && len(r.activeConns) == 0 {
		close(r.drainDone)
		r.drainDone = nil
	}

	r.connLock.Unlock()
}

func (r *Router) flushApps(t time.Time) {
	x := r.varz.ActiveApps().ActiveSince(t)

	y, err := json.Marshal(x)
	if err != nil {
		r.logger.Warnf("flushApps: Error marshalling JSON: %s", err)
		return
	}

	b := bytes.Buffer{}
	w := zlib.NewWriter(&b)
	w.Write(y)
	w.Close()

	z := b.Bytes()

	r.logger.Debugf("Active apps: %d, message size: %d", len(x), len(z))

	r.mbusClient.Publish("router.active_apps", z)
}

func (r *Router) greetMessage() ([]byte, error) {
	host, err := localip.LocalIP()
	if err != nil {
		return nil, err
	}

	d := vcap.RouterStart{
		Id:    r.component.UUID,
		Hosts: []string{host},
		MinimumRegisterIntervalInSeconds: r.config.StartResponseDelayIntervalInSeconds,
		PruneThresholdInSeconds:          r.config.DropletStaleThresholdInSeconds,
	}

	return json.Marshal(d)
}

func (r *Router) subscribeRegistry(subject string, successCallback func(*registryMessage)) {
	callback := func(message *nats.Msg) {
		payload := message.Data

		var msg registryMessage

		err := json.Unmarshal(payload, &msg)
		if err != nil {
			logMessage := fmt.Sprintf("%s: Error unmarshalling JSON (%d; %s): %s", subject, len(payload), payload, err)
			r.logger.Warnd(map[string]interface{}{"payload": string(payload)}, logMessage)
		}

		logMessage := fmt.Sprintf("%s: Received message", subject)
		r.logger.Debugd(map[string]interface{}{"message": msg}, logMessage)

		successCallback(&msg)
	}

	_, err := r.mbusClient.Subscribe(subject, callback)
	if err != nil {
		r.logger.Errorf("Error subscribing to %s: %s", subject, err)
	}
}
<commit_msg>Log outstanding active and idle connections when draining<commit_after>package router

import (
	"sync"

	"github.com/apcera/nats"
	"github.com/cloudfoundry/dropsonde"
	vcap "github.com/cloudfoundry/gorouter/common"
	"github.com/cloudfoundry/gorouter/config"
	"github.com/cloudfoundry/gorouter/proxy"
	"github.com/cloudfoundry/gorouter/registry"
	"github.com/cloudfoundry/gorouter/varz"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/yagnats"
	"github.com/pivotal-golang/localip"

	"bytes"
	"compress/zlib"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"net"
	"net/http"
	"time"
)

var DrainTimeout = errors.New("router: Drain timeout")
var noDeadline = time.Time{}

type Router struct {
	config     *config.Config
	proxy      proxy.Proxy
	mbusClient yagnats.NATSConn
	registry   *registry.RouteRegistry
	varz       varz.Varz
	component  *vcap.VcapComponent

	listener         net.Listener
	tlsListener      net.Listener
	closeConnections bool
	connLock         sync.Mutex
	idleConns        map[net.Conn]struct{}
	activeConns      map[net.Conn]struct{}
	drainDone        chan struct{}
	serveDone        chan struct{}
	tlsServeDone     chan struct{}

	logger *steno.Logger
}

func NewRouter(cfg *config.Config, p proxy.Proxy, mbusClient yagnats.NATSConn, r *registry.RouteRegistry, v varz.Varz,
	logCounter *vcap.LogCounter) (*Router, error) {

	var host string
	if cfg.Status.Port != 0 {
		host = fmt.Sprintf("%s:%d", cfg.Ip, cfg.Status.Port)
	}

	varz := &vcap.Varz{
		UniqueVarz: v,
		GenericVarz: vcap.GenericVarz{
			LogCounts: logCounter,
		},
	}

	healthz := &vcap.Healthz{}

	component := &vcap.VcapComponent{
		Type:        "Router",
		Index:       cfg.Index,
		Host:        host,
		Credentials: []string{cfg.Status.User, cfg.Status.Pass},
		Config:      cfg,
		Varz:        varz,
		Healthz:     healthz,
		InfoRoutes: map[string]json.Marshaler{
			"/routes": r,
		},
	}

	router := &Router{
		config:       cfg,
		proxy:        p,
		mbusClient:   mbusClient,
		registry:     r,
		varz:         v,
		component:    component,
		serveDone:    make(chan struct{}),
		tlsServeDone: make(chan struct{}),
		idleConns:    make(map[net.Conn]struct{}),
		activeConns:  make(map[net.Conn]struct{}),
		logger:       steno.NewLogger("router"),
	}

	if err := router.component.Start(); err != nil {
		return nil, err
	}

	return router, nil
}

func (r *Router) Run() <-chan error {
	r.registry.StartPruningCycle()

	r.RegisterComponent()

	// Subscribe register/unregister router
	r.SubscribeRegister()
	r.HandleGreetings()
	r.SubscribeUnregister()

	// Kickstart sending start messages
	r.SendStartMessage()

	r.mbusClient.AddReconnectedCB(func(conn *nats.Conn) {
		r.logger.Infof("Reconnecting to NATS server %s...", conn.Opts.Url)
		r.SendStartMessage()
	})

	// Schedule flushing active app's app_id
	r.ScheduleFlushApps()

	// Wait for one start message send interval, such that the router's registry
	// can be populated before serving requests.
	if r.config.StartResponseDelayInterval != 0 {
		r.logger.Infof("Waiting %s before listening...", r.config.StartResponseDelayInterval)
		time.Sleep(r.config.StartResponseDelayInterval)
	}

	server := &http.Server{
		Handler:   dropsonde.InstrumentedHandler(r.proxy),
		ConnState: r.HandleConnState,
	}

	errChan := make(chan error, 1)

	err := r.serveHTTP(server, errChan)
	if err != nil {
		errChan <- err
		return errChan
	}
	err = r.serveHTTPS(server, errChan)
	if err != nil {
		errChan <- err
		return errChan
	}

	return errChan
}

func (r *Router) serveHTTPS(server *http.Server, errChan chan error) error {
	if r.config.EnableSSL {
		tlsConfig := &tls.Config{
			Certificates: []tls.Certificate{r.config.SSLCertificate},
			CipherSuites: r.config.CipherSuites,
		}

		tlsListener, err := tls.Listen("tcp", fmt.Sprintf(":%d", r.config.SSLPort), tlsConfig)
		if err != nil {
			r.logger.Fatalf("tls.Listen: %s", err)
			return err
		}

		r.tlsListener = tlsListener
		r.logger.Infof("Listening on %s", tlsListener.Addr())

		go func() {
			err := server.Serve(tlsListener)
			errChan <- err
			close(r.tlsServeDone)
		}()
	}
	return nil
}

func (r *Router) serveHTTP(server *http.Server, errChan chan error) error {
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", r.config.Port))
	if err != nil {
		r.logger.Fatalf("net.Listen: %s", err)
		return err
	}

	r.listener = listener
	r.logger.Infof("Listening on %s", listener.Addr())

	go func() {
		err := server.Serve(listener)
		errChan <- err
		close(r.serveDone)
	}()
	return nil
}

func (r *Router) Drain(drainTimeout time.Duration) error {
	r.stopListening()

	drained := make(chan struct{})
	r.connLock.Lock()

	r.logger.Infof("Draining with %d outstanding active connections", len(r.activeConns))
	r.logger.Infof("Draining with %d outstanding idle connections", len(r.idleConns))
	r.closeIdleConns()

	if len(r.activeConns) == 0 {
		close(drained)
	} else {
		r.drainDone = drained
	}
	r.connLock.Unlock()

	select {
	case <-drained:
	case <-time.After(drainTimeout):
		r.logger.Warn("router.drain.timed-out")
		return DrainTimeout
	}
	return nil
}

func (r *Router) Stop() {
	r.stopListening()

	r.connLock.Lock()
	r.closeIdleConns()
	r.connLock.Unlock()

	r.component.Stop()
}

// connLock must be locked
func (r *Router) closeIdleConns() {
	r.closeConnections = true

	for conn, _ := range r.idleConns {
		conn.Close()
	}
}

func (r *Router) stopListening() {
	r.listener.Close()

	if r.tlsListener != nil {
		r.tlsListener.Close()
		<-r.tlsServeDone
	}

	<-r.serveDone
}

func (r *Router) RegisterComponent() {
	r.component.Register(r.mbusClient)
}

func (r *Router) SubscribeRegister() {
	r.subscribeRegistry("router.register", func(registryMessage *registryMessage) {
		r.logger.Debugf("Got router.register: %v", registryMessage)

		for _, uri := range registryMessage.Uris {
			r.registry.Register(
				uri,
				registryMessage.makeEndpoint(),
			)
		}
	})
}

func (r *Router) SubscribeUnregister() {
	r.subscribeRegistry("router.unregister", func(registryMessage *registryMessage) {
		r.logger.Debugf("Got router.unregister: %v", registryMessage)

		for _, uri := range registryMessage.Uris {
			r.registry.Unregister(
				uri,
				registryMessage.makeEndpoint(),
			)
		}
	})
}

func (r *Router) HandleGreetings() {
	r.mbusClient.Subscribe("router.greet", func(msg *nats.Msg) {
		response, _ := r.greetMessage()
		r.mbusClient.Publish(msg.Reply, response)
	})
}

func (r *Router) SendStartMessage() {
	b, err := r.greetMessage()
	if err != nil {
		panic(err)
	}

	// Send start message once at start
	err = r.mbusClient.Publish("router.start", b)
}

func (r *Router) ScheduleFlushApps() {
	if r.config.PublishActiveAppsInterval == 0 {
		return
	}

	go func() {
		t := time.NewTicker(r.config.PublishActiveAppsInterval)
		x := time.Now()

		for {
			select {
			case <-t.C:
				y := time.Now()
				r.flushApps(x)
				x = y
			}
		}
	}()
}

func (r *Router) HandleConnState(conn net.Conn, state http.ConnState) {
	endpointTimeout := r.config.EndpointTimeout

	r.connLock.Lock()

	switch state {
	case http.StateActive:
		r.activeConns[conn] = struct{}{}
		delete(r.idleConns, conn)

		conn.SetDeadline(time.Time{})
	case http.StateIdle:
		delete(r.activeConns, conn)
		r.idleConns[conn] = struct{}{}

		if r.closeConnections {
			conn.Close()
		} else {
			deadline := noDeadline
			if endpointTimeout > 0 {
				deadline = time.Now().Add(endpointTimeout)
			}

			conn.SetDeadline(deadline)
		}
	case http.StateHijacked, http.StateClosed:
		i := len(r.idleConns)
		delete(r.idleConns, conn)
		if i == len(r.idleConns) {
			delete(r.activeConns, conn)
		}
	}

	if r.drainDone != nil && len(r.activeConns) == 0 {
		close(r.drainDone)
		r.drainDone = nil
	}

	r.connLock.Unlock()
}

func (r *Router) flushApps(t time.Time) {
	x := r.varz.ActiveApps().ActiveSince(t)

	y, err := json.Marshal(x)
	if err != nil {
		r.logger.Warnf("flushApps: Error marshalling JSON: %s", err)
		return
	}

	b := bytes.Buffer{}
	w := zlib.NewWriter(&b)
	w.Write(y)
	w.Close()

	z := b.Bytes()

	r.logger.Debugf("Active apps: %d, message size: %d", len(x), len(z))

	r.mbusClient.Publish("router.active_apps", z)
}

func (r *Router) greetMessage() ([]byte, error) {
	host, err := localip.LocalIP()
	if err != nil {
		return nil, err
	}

	d := vcap.RouterStart{
		Id:    r.component.UUID,
		Hosts: []string{host},
		MinimumRegisterIntervalInSeconds: r.config.StartResponseDelayIntervalInSeconds,
		PruneThresholdInSeconds:          r.config.DropletStaleThresholdInSeconds,
	}

	return json.Marshal(d)
}

func (r *Router) subscribeRegistry(subject string, successCallback func(*registryMessage)) {
	callback := func(message *nats.Msg) {
		payload := message.Data

		var msg registryMessage

		err := json.Unmarshal(payload, &msg)
		if err != nil {
			logMessage := fmt.Sprintf("%s: Error unmarshalling JSON (%d; %s): %s", subject, len(payload), payload, err)
			r.logger.Warnd(map[string]interface{}{"payload": string(payload)}, logMessage)
		}

		logMessage := fmt.Sprintf("%s: Received message", subject)
		r.logger.Debugd(map[string]interface{}{"message": msg}, logMessage)

		successCallback(&msg)
	}

	_, err := r.mbusClient.Subscribe(subject, callback)
	if err != nil {
		r.logger.Errorf("Error subscribing to %s: %s", subject, err)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2015 Clement 'cmc' Rey <cr.rey.clement@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package rrs

import (
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/teh-cmc/seq"
	"github.com/teh-cmc/seq/rpc"
	"github.com/teh-cmc/seq/rr_seq/pb"
)

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

// RRSeq implements a buffered `Sequencer` backed by a cluster of `RRServer`s: a
// distributed system that guarantees sequential `ID` generation by using RW
// quorums and read-repair conflict resolution strategies.
//
// You can find more information about the ideas behind such a system in the
// `README.md` file at the root of this repository.
type RRSeq struct {
	cp  *rpc.Pool
	ids chan seq.ID

	stop chan struct{}
	wg   *sync.WaitGroup
}

// NewRRSeq returns a new `RRSeq` with the specified buffer size.
//
// `RRSeq` will constantly try to keep this buffer as full as possible
// using a dedicated background routine.
//
// `bufSize` will default to 0 in case it is < 0.
func NewRRSeq(name string, bufSize int, addrs ...string) (*RRSeq, error) {
	if bufSize < 0 {
		bufSize = 0
	}

	cp, err := rpc.NewPool(addrs...) // blocks until all connections are established
	if err != nil {
		return nil, err
	}

	ids := make(chan seq.ID, bufSize)
	stop := make(chan struct{}, 0)
	wg := &sync.WaitGroup{}
	rrseq := &RRSeq{cp: cp, ids: ids, stop: stop, wg: wg}

	var curRange, nextRange [2]seq.ID // empty ranges
	wg.Add(1)
	go func() { // background buffering routine
		defer wg.Done()
		switched := false
		for {

			// if the current range has already been half (or more) consumed,
			// or if it is the empty range [0,0) (e.g. due to a previous server error),
			// fetch and store the next available range from the cluster
			if curRange[0] >= (curRange[0]+curRange[1])/2 && !switched {
				nextRange[0], nextRange[1] = rrseq.getNextRange(name, bufSize)
				switched = true
			}
			// if the current range has been entirely consumed,
			// or if it is the empty range [0,0) (e.g. due to a previous server error),
			// replace the current range by the already stored next range
			if curRange[0] >= curRange[1] {
				// NOTE: it is possible for `nextRange` to be [0,0) here,
				// this happens when the server is not able to return a new range
				// for whatever reason
				curRange = nextRange
				switched = false
			}

			select {
			case <-stop: // stream has been closed, kill routine
				return
			default:
				// make sure that `curRange` is not an empty range such as [0,0),
				// otherwise, just continue to the next iteration
				if curRange[0] < curRange[1] {
					select {
					case ids <- curRange[0]: // blocks once `seq` is full
						curRange[0]++
					case <-stop: // stream has been closed, kill routine
						return
					}
				}
			}

		}
	}()

	return rrseq, nil
}

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

// getNextRange fetches the next available range of `ID`s from the cluster
// of `RRServer`s.
//
// getNextRange returns the empty [0;0) range on failures; which means that the
// buffering routine will be retrying soon, using another peer (because round-robin).
//
// A deadline is set so that queries and reconnection attemps cannot last
// forever.
// For queries, this deadline is propagated through the various calls made
// within the cluster of `RRServer`s. This means that the time spent in
// intra-cluster RPC calls is included in this deadline.
//
// An exceeded deadline behaves as an error, and as such it returns the empty
// [0;0) range.
//
// NOTE: the deadline is hardcoded for now.
func (ss RRSeq) getNextRange(name string, rangeSize int) (seq.ID, seq.ID) {
	conn := ss.cp.ConnRoundRobin()
	if conn == nil { // no healthy connection available
		return 0, 0 // return empty range, this will toggle the retry machinery
	}

	deadline := time.Second * 4 // TODO(low-prio): make this configurable
	ctx, canceller := context.WithTimeout(context.Background(), deadline)

	idReply, err := pb.NewRRAPIClient(conn).GRPCNextID(
		ctx, // request will be cancelled if it lasts more than `deadline`,
		//      or if we've been trying to reconnect for more than `deadline`;
		//      in any case, this results in `err != nil`
		&pb.NextIDRequest{Name: name, RangeSize: int64(rangeSize)},
	)
	canceller() // we got what we came for, stop everything downstream
	if err != nil {
		return 0, 0 // return empty range, this will toggle the retry machinery
	}

	return seq.ID(idReply.FromId), seq.ID(idReply.ToId)
}

// Stream returns a pre-buffered, range-able stream of sequential `ID`s
// backed by a cluster of `RRServer`s, starting at `ID(1)`.
func (ss RRSeq) Stream() seq.IDStream { return ss.ids }

// Close closes the associated `IDStream` and stops the background buffering
// routine.
//
// It returns the first error met.
//
// Once closed, a `SimpleBufSeq` is not reusable.
func (ss *RRSeq) Close() error {
	close(ss.stop)       // kill background buffering routine..
	ss.wg.Wait()         // ..and wait for it to be fully stopped
	close(ss.ids)        // close `ID` stream
	return ss.cp.Close() // close gRPC connections
}
<commit_msg>RRSeq - package level doc<commit_after>// Copyright © 2015 Clement 'cmc' Rey <cr.rey.clement@gmail.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

// Package rrs implements a buffered `Sequencer` backed by a cluster of
// `RRServer`s: a distributed system that guarantees sequential `ID` generation
// by using RW quorums and read-repair conflict resolution strategies.
//
// You can find more information about the ideas behind such a system in the
// `README.md` file at the root of this repository.
package rrs

import (
	"sync"
	"time"

	"golang.org/x/net/context"

	"github.com/teh-cmc/seq"
	"github.com/teh-cmc/seq/rpc"
	"github.com/teh-cmc/seq/rr_seq/pb"
)

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

// RRSeq implements a buffered `Sequencer` backed by a cluster of `RRServer`s: a
// distributed system that guarantees sequential `ID` generation by using RW
// quorums and read-repair conflict resolution strategies.
//
// You can find more information about the ideas behind such a system in the
// `README.md` file at the root of this repository.
type RRSeq struct {
	cp  *rpc.Pool
	ids chan seq.ID

	stop chan struct{}
	wg   *sync.WaitGroup
}

// NewRRSeq returns a new `RRSeq` with the specified buffer size.
//
// `RRSeq` will constantly try to keep this buffer as full as possible
// using a dedicated background routine.
//
// `bufSize` will default to 0 in case it is < 0.
func NewRRSeq(name string, bufSize int, addrs ...string) (*RRSeq, error) {
	if bufSize < 0 {
		bufSize = 0
	}

	cp, err := rpc.NewPool(addrs...) // blocks until all connections are established
	if err != nil {
		return nil, err
	}

	ids := make(chan seq.ID, bufSize)
	stop := make(chan struct{}, 0)
	wg := &sync.WaitGroup{}
	rrseq := &RRSeq{cp: cp, ids: ids, stop: stop, wg: wg}

	var curRange, nextRange [2]seq.ID // empty ranges
	wg.Add(1)
	go func() { // background buffering routine
		defer wg.Done()
		switched := false
		for {

			// if the current range has already been half (or more) consumed,
			// or if it is the empty range [0,0) (e.g. due to a previous server error),
			// fetch and store the next available range from the cluster
			if curRange[0] >= (curRange[0]+curRange[1])/2 && !switched {
				nextRange[0], nextRange[1] = rrseq.getNextRange(name, bufSize)
				switched = true
			}
			// if the current range has been entirely consumed,
			// or if it is the empty range [0,0) (e.g. due to a previous server error),
			// replace the current range by the already stored next range
			if curRange[0] >= curRange[1] {
				// NOTE: it is possible for `nextRange` to be [0,0) here,
				// this happens when the server is not able to return a new range
				// for whatever reason
				curRange = nextRange
				switched = false
			}

			select {
			case <-stop: // stream has been closed, kill routine
				return
			default:
				// make sure that `curRange` is not an empty range such as [0,0),
				// otherwise, just continue to the next iteration
				if curRange[0] < curRange[1] {
					select {
					case ids <- curRange[0]: // blocks once `seq` is full
						curRange[0]++
					case <-stop: // stream has been closed, kill routine
						return
					}
				}
			}

		}
	}()

	return rrseq, nil
}

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

// getNextRange fetches the next available range of `ID`s from the cluster
// of `RRServer`s.
//
// getNextRange returns the empty [0;0) range on failures; which means that the
// buffering routine will be retrying soon, using another peer (because round-robin).
//
// A deadline is set so that queries and reconnection attemps cannot last
// forever.
// For queries, this deadline is propagated through the various calls made
// within the cluster of `RRServer`s. This means that the time spent in
// intra-cluster RPC calls is included in this deadline.
//
// An exceeded deadline behaves as an error, and as such it returns the empty
// [0;0) range.
//
// NOTE: the deadline is hardcoded for now.
func (ss RRSeq) getNextRange(name string, rangeSize int) (seq.ID, seq.ID) {
	conn := ss.cp.ConnRoundRobin()
	if conn == nil { // no healthy connection available
		return 0, 0 // return empty range, this will toggle the retry machinery
	}

	deadline := time.Second * 4 // TODO(low-prio): make this configurable
	ctx, canceller := context.WithTimeout(context.Background(), deadline)

	idReply, err := pb.NewRRAPIClient(conn).GRPCNextID(
		ctx, // request will be cancelled if it lasts more than `deadline`,
		//      or if we've been trying to reconnect for more than `deadline`;
		//      in any case, this results in `err != nil`
		&pb.NextIDRequest{Name: name, RangeSize: int64(rangeSize)},
	)
	canceller() // we got what we came for, stop everything downstream
	if err != nil {
		return 0, 0 // return empty range, this will toggle the retry machinery
	}

	return seq.ID(idReply.FromId), seq.ID(idReply.ToId)
}

// Stream returns a pre-buffered, range-able stream of sequential `ID`s
// backed by a cluster of `RRServer`s, starting at `ID(1)`.
func (ss RRSeq) Stream() seq.IDStream { return ss.ids }

// Close closes the associated `IDStream` and stops the background buffering
// routine.
//
// It returns the first error met.
//
// Once closed, a `SimpleBufSeq` is not reusable.
func (ss *RRSeq) Close() error {
	close(ss.stop)       // kill background buffering routine..
	ss.wg.Wait()         // ..and wait for it to be fully stopped
	close(ss.ids)        // close `ID` stream
	return ss.cp.Close() // close gRPC connections
}
<|endoftext|>


<commit_before>// Copyright 2011 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 cgotest

/*
#include <unistd.h>

unsigned int sleep(unsigned int seconds);

extern void BackgroundSleep(int);
void twoSleep(int);
*/
import "C"

import (
	"runtime"
	"testing"
	"time"
)

var sleepDone = make(chan bool)

func parallelSleep(n int) {
	C.twoSleep(C.int(n))
	<-sleepDone
}

//export BackgroundSleep
func BackgroundSleep(n int) {
	go func() {
		C.sleep(C.uint(n))
		sleepDone <- true
	}()
}

func testParallelSleep(t *testing.T) {
	sleepSec := 1
	if runtime.GOARCH == "arm" {
		// on ARM, the 1.3s deadline is frequently missed,
		// so increase sleep time to 2s
		sleepSec = 2
	}
	start := time.Now()
	parallelSleep(sleepSec)
	dt := time.Now().Sub(start)
	// bug used to run sleeps in serial, producing a 2*sleepSec-second delay.
	if dt >= time.Duration(sleepSec)*1300*time.Millisecond {
		t.Fatalf("parallel %d-second sleeps slept for %f seconds", sleepSec, dt.Seconds())
	}
}
<commit_msg>cgo/misc/test: burn CPU to improve sleep accuracy<commit_after>// Copyright 2011 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 cgotest

/*
#include <unistd.h>

unsigned int sleep(unsigned int seconds);

extern void BackgroundSleep(int);
void twoSleep(int);
*/
import "C"

import (
	"runtime"
	"testing"
	"time"
)

var sleepDone = make(chan bool)

func parallelSleep(n int) {
	C.twoSleep(C.int(n))
	<-sleepDone
}

//export BackgroundSleep
func BackgroundSleep(n int) {
	go func() {
		C.sleep(C.uint(n))
		sleepDone <- true
	}()
}

// wasteCPU starts a background goroutine to waste CPU
// to cause the power management to raise the CPU frequency.
// On ARM this has the side effect of making sleep more accurate.
func wasteCPU() chan struct{} {
	done := make(chan struct{})
	go func() {
		for {
			select {
			case <-done:
				return
			default:
			}
		}
	}()
	// pause for a short amount of time to allow the
	// power management to recognise load has risen.
	<-time.After(300 * time.Millisecond)
	return done
}

func testParallelSleep(t *testing.T) {
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
	defer close(wasteCPU())

	sleepSec := 1
	start := time.Now()
	parallelSleep(sleepSec)
	dt := time.Since(start)
	t.Logf("sleep(%d) slept for %v", sleepSec, dt)
	// bug used to run sleeps in serial, producing a 2*sleepSec-second delay.
	if dt >= time.Duration(sleepSec)*1300*time.Millisecond {
		t.Fatalf("parallel %d-second sleeps slept for %f seconds", sleepSec, dt.Seconds())
	}
}
<|endoftext|>