<commit_before>package jet

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
)

type mapper struct {
	conv ColumnConverter
}

func (m *mapper) unpack(keys []string, values []interface{}, out interface{}) error {
	val := reflect.ValueOf(out)
	if val.Kind() != reflect.Ptr {
		return fmt.Errorf("cannot unpack result to non-pointer (%s)", val.Type().String())
	}
	return m.unpackValue(keys, values, val)
}

func (m *mapper) unpackValue(keys []string, values []interface{}, out reflect.Value) error {
	switch out.Interface().(type) {
	case ComplexValue:
		if out.IsNil() {
			out.Set(reflect.New(out.Type().Elem()))
		}
		plain := reflect.Indirect(reflect.ValueOf(values[0]))
		return out.Interface().(ComplexValue).Decode(plain.Interface())
	}
	if out.CanAddr() {
		switch out.Addr().Interface().(type) {
		case ComplexValue:
			return m.unpackValue(keys, values, out.Addr())
		}
	}
	switch out.Kind() {
	case reflect.Ptr:
		if out.IsNil() {
			out.Set(reflect.New(out.Type().Elem()))
		}
		return m.unpackValue(keys, values, reflect.Indirect(out))
	case reflect.Slice:
		if keys == nil {
			return m.unpackSimple(nil, values, out)
		} else {
			return m.unpackSlice(keys, values, out)
		}
	case reflect.Struct:
		return m.unpackStruct(keys, values, out)
	case reflect.Map:
		if keys == nil {
			return m.unpackSimple(nil, values, out)
		} else {
			return m.unpackMap(keys, values, out)
		}
	default:
		return m.unpackSimple(nil, values, out)
	}
	return fmt.Errorf("cannot unpack result to %T (%s)", out, out.Kind())
}

func (m *mapper) unpackSlice(keys []string, values []interface{}, out reflect.Value) error {
	elemTyp := reflect.Indirect(reflect.New(out.Type().Elem()))
	m.unpackValue(keys, values, elemTyp)
	out.Set(reflect.Append(out, elemTyp))
	return nil
}

func (m *mapper) unpackStruct(keys []string, values []interface{}, out reflect.Value) error {
	// If no keys are passed in it's probably a struct field requiring
	// a simple unpack like a time.Time struct field.
	if len(keys) == 0 {
		return m.unpackSimple(nil, values, out)
	}
	for i, k := range keys {
		var convKey string
		if m.conv == nil {
			convKey = strings.ToUpper(k[:1]) + k[1:]
		} else if m.conv != nil {
			convKey = m.conv.ColumnToFieldName(k)
		}
		field := out.FieldByName(convKey)
		if field.IsValid() {
			m.unpackValue(nil, values[i:i+1], field)
		}
	}
	return nil
}

func (m *mapper) unpackMap(keys []string, values []interface{}, out reflect.Value) error {
	if out.IsNil() {
		out.Set(reflect.MakeMap(out.Type()))
	}
	for i, k := range keys {
		elemTyp := reflect.Indirect(reflect.New(out.Type().Elem()))
		m.unpackValue(nil, values[i:i+1], elemTyp)
		out.SetMapIndex(reflect.ValueOf(k), elemTyp)
	}

	return nil
}

func (m *mapper) unpackSimple(keys []string, values []interface{}, out reflect.Value) error {
	if !out.IsValid() {
		panic("cannot unpack to zero value")
	}
	if len(values) != 1 {
		panic("cannot unpack to simple value, invalid values input")
	}
	setValue(reflect.Indirect(reflect.ValueOf(values[0])), out)
	return nil
}

func convertAndSet(f interface{}, to reflect.Value) {
	from := reflect.ValueOf(f)
	if from.IsValid() {
		to.Set(from.Convert(to.Type()))
	} else {
		to.Set(reflect.Zero(to.Type()))
	}
}

func setValue(from, to reflect.Value) {
	switch t := from.Interface().(type) {
	case []uint8:
		setValueFromBytes(t, to)
	case int, int8, int16, int32, int64:
		setValueFromInt(reflect.ValueOf(t).Int(), to)
	case uint, uint8, uint16, uint32, uint64:
		setValueFromUint(reflect.ValueOf(t).Uint(), to)
	case float32, float64:
		setValueFromFloat(reflect.ValueOf(t).Float(), to)
	case time.Time:
		setValueFromTime(t, to)
	default:
		convertAndSet(t, to)
	}
}

func setValueFromBytes(t []uint8, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		n, _ := strconv.ParseInt(string(t), 10, 32)
		convertAndSet(bool(n == 1), to)
	case int, int8, int16, int32, int64:
		n, _ := strconv.ParseInt(string(t), 10, 64)
		convertAndSet(n, to)
	case uint, uint8, uint16, uint32, uint64:
		n, _ := strconv.ParseUint(string(t), 10, 64)
		convertAndSet(n, to)
	case float32:
		n, _ := strconv.ParseFloat(string(t), 32)
		convertAndSet(n, to)
	case float64:
		n, _ := strconv.ParseFloat(string(t), 64)
		convertAndSet(n, to)
	case string:
		to.SetString(string(t))
	case map[string]interface{}:
		to.Set(reflect.ValueOf(parseHstoreColumn(string(t))))
	default:
		convertAndSet(t, to)
	}
}

func setValueFromFloat(f float64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(f == 1), to)
	default:
		convertAndSet(f, to)
	}
}

func setValueFromInt(i int64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(i == 1), to)
	default:
		convertAndSet(i, to)
	}
}

func setValueFromUint(i uint64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(i == 1), to)
	default:
		convertAndSet(i, to)
	}
}

func setValueFromTime(t time.Time, to reflect.Value) {
	switch to.Interface().(type) {
	case int64:
		convertAndSet(int64(t.Unix()), to)
	case uint64:
		convertAndSet(uint64(t.Unix()), to)
	default:
		convertAndSet(t, to)
	}
}
<commit_msg>Handle some special cases<commit_after>package jet

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
)

type mapper struct {
	conv ColumnConverter
}

func (m *mapper) unpack(keys []string, values []interface{}, out interface{}) error {
	val := reflect.ValueOf(out)
	if val.Kind() != reflect.Ptr {
		return fmt.Errorf("cannot unpack result to non-pointer (%s)", val.Type().String())
	}
	return m.unpackValue(keys, values, val)
}

func (m *mapper) unpackValue(keys []string, values []interface{}, out reflect.Value) error {
	switch out.Interface().(type) {
	case ComplexValue:
		if out.IsNil() {
			out.Set(reflect.New(out.Type().Elem()))
		}
		plain := reflect.Indirect(reflect.ValueOf(values[0]))
		return out.Interface().(ComplexValue).Decode(plain.Interface())
	}
	if out.CanAddr() {
		switch out.Addr().Interface().(type) {
		case ComplexValue:
			return m.unpackValue(keys, values, out.Addr())
		}
	}
	switch out.Kind() {
	case reflect.Ptr:
		if out.IsNil() {
			out.Set(reflect.New(out.Type().Elem()))
		}
		return m.unpackValue(keys, values, reflect.Indirect(out))
	case reflect.Slice:
		if keys == nil {
			return m.unpackSimple(nil, values, out)
		} else {
			return m.unpackSlice(keys, values, out)
		}
	case reflect.Struct:
		return m.unpackStruct(keys, values, out)
	case reflect.Map:
		if keys == nil {
			return m.unpackSimple(nil, values, out)
		} else {
			return m.unpackMap(keys, values, out)
		}
	default:
		return m.unpackSimple(nil, values, out)
	}
	return fmt.Errorf("cannot unpack result to %T (%s)", out, out.Kind())
}

func (m *mapper) unpackSlice(keys []string, values []interface{}, out reflect.Value) error {
	elemTyp := reflect.Indirect(reflect.New(out.Type().Elem()))
	m.unpackValue(keys, values, elemTyp)
	out.Set(reflect.Append(out, elemTyp))
	return nil
}

func (m *mapper) unpackStruct(keys []string, values []interface{}, out reflect.Value) error {
	// If no keys are passed in it's probably a struct field requiring
	// a simple unpack like a time.Time struct field.
	if len(keys) == 0 {
		return m.unpackSimple(nil, values, out)
	}
	for i, k := range keys {
		var convKey string
		if m.conv == nil {
			convKey = strings.ToUpper(k[:1]) + k[1:]
		} else if m.conv != nil {
			convKey = m.conv.ColumnToFieldName(k)
		}
		field := out.FieldByName(convKey)

		// If the field is not found it can mean that we don't want it or that
		// we have special case like UserID, UUID, userUUID
		// So fix the name and try again
		if !field.IsValid() {
			convKey = strings.Replace(convKey, "Uuid", "UUID", -1)
			convKey = strings.Replace(convKey, "Id", "ID", -1)
			field = out.FieldByName(convKey)
		}

		if field.IsValid() {
			m.unpackValue(nil, values[i:i+1], field)
		}
	}
	return nil
}

func (m *mapper) unpackMap(keys []string, values []interface{}, out reflect.Value) error {
	if out.IsNil() {
		out.Set(reflect.MakeMap(out.Type()))
	}
	for i, k := range keys {
		elemTyp := reflect.Indirect(reflect.New(out.Type().Elem()))
		m.unpackValue(nil, values[i:i+1], elemTyp)
		out.SetMapIndex(reflect.ValueOf(k), elemTyp)
	}

	return nil
}

func (m *mapper) unpackSimple(keys []string, values []interface{}, out reflect.Value) error {
	if !out.IsValid() {
		panic("cannot unpack to zero value")
	}
	if len(values) != 1 {
		panic("cannot unpack to simple value, invalid values input")
	}
	setValue(reflect.Indirect(reflect.ValueOf(values[0])), out)
	return nil
}

func convertAndSet(f interface{}, to reflect.Value) {
	from := reflect.ValueOf(f)
	if from.IsValid() {
		to.Set(from.Convert(to.Type()))
	} else {
		to.Set(reflect.Zero(to.Type()))
	}
}

func setValue(from, to reflect.Value) {
	switch t := from.Interface().(type) {
	case []uint8:
		setValueFromBytes(t, to)
	case int, int8, int16, int32, int64:
		setValueFromInt(reflect.ValueOf(t).Int(), to)
	case uint, uint8, uint16, uint32, uint64:
		setValueFromUint(reflect.ValueOf(t).Uint(), to)
	case float32, float64:
		setValueFromFloat(reflect.ValueOf(t).Float(), to)
	case time.Time:
		setValueFromTime(t, to)
	default:
		convertAndSet(t, to)
	}
}

func setValueFromBytes(t []uint8, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		n, _ := strconv.ParseInt(string(t), 10, 32)
		convertAndSet(bool(n == 1), to)
	case int, int8, int16, int32, int64:
		n, _ := strconv.ParseInt(string(t), 10, 64)
		convertAndSet(n, to)
	case uint, uint8, uint16, uint32, uint64:
		n, _ := strconv.ParseUint(string(t), 10, 64)
		convertAndSet(n, to)
	case float32:
		n, _ := strconv.ParseFloat(string(t), 32)
		convertAndSet(n, to)
	case float64:
		n, _ := strconv.ParseFloat(string(t), 64)
		convertAndSet(n, to)
	case string:
		to.SetString(string(t))
	case map[string]interface{}:
		to.Set(reflect.ValueOf(parseHstoreColumn(string(t))))
	default:
		convertAndSet(t, to)
	}
}

func setValueFromFloat(f float64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(f == 1), to)
	default:
		convertAndSet(f, to)
	}
}

func setValueFromInt(i int64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(i == 1), to)
	default:
		convertAndSet(i, to)
	}
}

func setValueFromUint(i uint64, to reflect.Value) {
	switch to.Interface().(type) {
	case bool:
		convertAndSet(bool(i == 1), to)
	default:
		convertAndSet(i, to)
	}
}

func setValueFromTime(t time.Time, to reflect.Value) {
	switch to.Interface().(type) {
	case int64:
		convertAndSet(int64(t.Unix()), to)
	case uint64:
		convertAndSet(uint64(t.Unix()), to)
	default:
		convertAndSet(t, to)
	}
}
<|endoftext|>


<commit_before>package ecql

import (
	"reflect"
	"strings"
)

var (
	// TAG_COLUMNS is the tag used in the structs to set the column name for a field.
	// If a name is not set, the name would be the lowercase version of the field.
	// If you want to skip a field you can use `cql:"-"`
	TAG_COLUMN = "cql"

	// TAG_TABLE is the tag used in the structs to define the table for a type.
	// If the table is not set it defaults to the type name in lowercase.
	TAG_TABLE = "cqltable"

	// TAG_KEY defines the primary key for the table.
	// If the table uses a composite key you just need to define multiple columns
	// separated by a comma: `cqlkey:"id"` or `cqlkey:"partkey,id"`
	TAG_KEY = "cqlkey"
)

var registry = make(map[reflect.Type]Table)

// Delete registry cleans the registry.
// This would be mainly used in unit testing.
func DeleteRegistry() {
	registry = make(map[reflect.Type]Table)
}

// Register adds the passed struct to the registry to be able to use gocql
// MapScan methods with struct types.
//
// It maps the columns using the struct tag 'cql' or the lowercase of the
// field name. You can skip the mapping of one field using the tag `cql:"-"`
func Register(i interface{}) {
	register(i)
}

// Map creates a new map[string]interface{} where each member in the map
// is a reference to a field in the struct. This allows to assign values
// to a struct using gocql MapScan.
//
// Given a gocql session, the following code will populate the struct 't'
// with the values in the datastore.
// 	var t MyStruct
// 	query := session.Query("select * from mytable where id = ?", "my-id")
// 	m := cql.Map(&t)
// 	err := query.MapScan(m)
func Map(i interface{}) map[string]interface{} {
	columns, _ := MapTable(i)
	return columns
}

// MapTable creates a new map[string]interface{} where each member in the map
// is a reference to a field in the struct. This allows to assign values
// to a struct using gocql MapScan. MapTable also returns the Table with the
// information about the type.
//
// Given a gocql session, the following code will populate the struct 't'
// with the values in the datastore.
// 	var t MyStruct
// 	query := session.Query("select * from mytable where id = ?", "my-id")
// 	m, _ := cql.MapTable(&t)
// 	err := query.MapScan(m)
func MapTable(i interface{}) (map[string]interface{}, Table) {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	columns := make(map[string]interface{})
	for _, col := range table.Columns {
		field := v.Field(col.Position)
		if field.CanAddr() {
			columns[col.Name] = field.Addr().Interface()
		} else {
			columns[col.Name] = field.Interface()
		}
	}
	return columns, table
}

// Bind returns the values of i to bind in insert queries.
func Bind(i interface{}) []interface{} {
	columns, _ := BindTable(i)
	return columns
}

// BindTables returns the values of i to bind in insert queries and the Table
// with the information about the type.
func BindTable(i interface{}) ([]interface{}, Table) {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	columns := make([]interface{}, len(table.Columns))
	for i, col := range table.Columns {
		field := v.Field(col.Position)
		columns[i] = field.Interface()
	}
	return columns, table
}

// GetTable returns the Table with the information about the type of i.
func GetTable(i interface{}) Table {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	return table
}

func structOf(i interface{}) reflect.Value {
	v := reflect.ValueOf(i)
	switch v.Kind() {
	case reflect.Struct:
		return v
	case reflect.Ptr, reflect.Interface:
		elem := v.Elem()
		if elem.Kind() == reflect.Struct {
			return elem
		}
	}

	panic("register type is not struct")
}

func register(i interface{}) Table {
	v := structOf(i)
	t := v.Type()

	// Table name defaults to the type name.
	var table Table
	table.Name = t.Name()

	for i, n := 0, t.NumField(); i < n; i++ {
		field := t.Field(i)
		// Get table if available
		name := field.Tag.Get(TAG_TABLE)
		if name != "" {
			table.Name = name
		}

		// Get the key columns
		// FIXME: add a default behavior, ie: first field
		name = field.Tag.Get(TAG_KEY)
		if name != "" {
			table.KeyColumns = strings.Split(name, ",")
		}

		// Get columns or field name
		name = field.Tag.Get(TAG_COLUMN)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		if name != "-" {
			table.Columns = append(table.Columns, Column{name, i})
		}
	}

	// Default behaviour with no key is assume the first column is key
	if len(table.KeyColumns) == 0 {
		table.KeyColumns = append(table.KeyColumns, table.Columns[0])
	}

	registry[t] = table
	return table
}
<commit_msg>Key column is just column name.<commit_after>package ecql

import (
	"reflect"
	"strings"
)

var (
	// TAG_COLUMNS is the tag used in the structs to set the column name for a field.
	// If a name is not set, the name would be the lowercase version of the field.
	// If you want to skip a field you can use `cql:"-"`
	TAG_COLUMN = "cql"

	// TAG_TABLE is the tag used in the structs to define the table for a type.
	// If the table is not set it defaults to the type name in lowercase.
	TAG_TABLE = "cqltable"

	// TAG_KEY defines the primary key for the table.
	// If the table uses a composite key you just need to define multiple columns
	// separated by a comma: `cqlkey:"id"` or `cqlkey:"partkey,id"`
	TAG_KEY = "cqlkey"
)

var registry = make(map[reflect.Type]Table)

// Delete registry cleans the registry.
// This would be mainly used in unit testing.
func DeleteRegistry() {
	registry = make(map[reflect.Type]Table)
}

// Register adds the passed struct to the registry to be able to use gocql
// MapScan methods with struct types.
//
// It maps the columns using the struct tag 'cql' or the lowercase of the
// field name. You can skip the mapping of one field using the tag `cql:"-"`
func Register(i interface{}) {
	register(i)
}

// Map creates a new map[string]interface{} where each member in the map
// is a reference to a field in the struct. This allows to assign values
// to a struct using gocql MapScan.
//
// Given a gocql session, the following code will populate the struct 't'
// with the values in the datastore.
// 	var t MyStruct
// 	query := session.Query("select * from mytable where id = ?", "my-id")
// 	m := cql.Map(&t)
// 	err := query.MapScan(m)
func Map(i interface{}) map[string]interface{} {
	columns, _ := MapTable(i)
	return columns
}

// MapTable creates a new map[string]interface{} where each member in the map
// is a reference to a field in the struct. This allows to assign values
// to a struct using gocql MapScan. MapTable also returns the Table with the
// information about the type.
//
// Given a gocql session, the following code will populate the struct 't'
// with the values in the datastore.
// 	var t MyStruct
// 	query := session.Query("select * from mytable where id = ?", "my-id")
// 	m, _ := cql.MapTable(&t)
// 	err := query.MapScan(m)
func MapTable(i interface{}) (map[string]interface{}, Table) {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	columns := make(map[string]interface{})
	for _, col := range table.Columns {
		field := v.Field(col.Position)
		if field.CanAddr() {
			columns[col.Name] = field.Addr().Interface()
		} else {
			columns[col.Name] = field.Interface()
		}
	}
	return columns, table
}

// Bind returns the values of i to bind in insert queries.
func Bind(i interface{}) []interface{} {
	columns, _ := BindTable(i)
	return columns
}

// BindTables returns the values of i to bind in insert queries and the Table
// with the information about the type.
func BindTable(i interface{}) ([]interface{}, Table) {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	columns := make([]interface{}, len(table.Columns))
	for i, col := range table.Columns {
		field := v.Field(col.Position)
		columns[i] = field.Interface()
	}
	return columns, table
}

// GetTable returns the Table with the information about the type of i.
func GetTable(i interface{}) Table {
	v := structOf(i)
	t := v.Type()

	// Get the table or register on the fly if necessary
	table, ok := registry[t]
	if !ok {
		table = register(i)
	}

	return table
}

func structOf(i interface{}) reflect.Value {
	v := reflect.ValueOf(i)
	switch v.Kind() {
	case reflect.Struct:
		return v
	case reflect.Ptr, reflect.Interface:
		elem := v.Elem()
		if elem.Kind() == reflect.Struct {
			return elem
		}
	}

	panic("register type is not struct")
}

func register(i interface{}) Table {
	v := structOf(i)
	t := v.Type()

	// Table name defaults to the type name.
	var table Table
	table.Name = t.Name()

	for i, n := 0, t.NumField(); i < n; i++ {
		field := t.Field(i)
		// Get table if available
		name := field.Tag.Get(TAG_TABLE)
		if name != "" {
			table.Name = name
		}

		// Get the key columns
		// FIXME: add a default behavior, ie: first field
		name = field.Tag.Get(TAG_KEY)
		if name != "" {
			table.KeyColumns = strings.Split(name, ",")
		}

		// Get columns or field name
		name = field.Tag.Get(TAG_COLUMN)
		if name == "" {
			name = strings.ToLower(field.Name)
		}
		if name != "-" {
			table.Columns = append(table.Columns, Column{name, i})
		}
	}

	// Default behaviour with no key is assume the first column is key
	if len(table.KeyColumns) == 0 {
		table.KeyColumns = append(table.KeyColumns, table.Columns[0].Name)
	}

	registry[t] = table
	return table
}
<|endoftext|>


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

// Package sub implements the SUB protocol.  This protocol receives messages
// from publishers (PUB peers).  The messages are filtered based on
// subscription, such that only subscribed messages (see OptionSubscribe) are
// received.
package sub

import (
	"bytes"
	"sync"
	"time"

	"github.com/go-mangos/mangos"
)

type sub struct {
	sock mangos.ProtocolSocket
	subs [][]byte
	raw  bool
	sync.Mutex
}

func (s *sub) Init(sock mangos.ProtocolSocket) {
	s.sock = sock
	s.subs = [][]byte{}
	s.sock.SetSendError(mangos.ErrProtoOp)
}

func (*sub) Shutdown(time.Time) {} // No sender to drain.

func (s *sub) receiver(ep mangos.Endpoint) {

	rq := s.sock.RecvChannel()
	cq := s.sock.CloseChannel()

	for {
		var matched = false

		m := ep.RecvMsg()
		if m == nil {
			return
		}

		s.Lock()
		for _, sub := range s.subs {
			if bytes.HasPrefix(m.Body, sub) {
				// Matched, send it up.  Best effort.
				matched = true
				break
			}
		}
		s.Unlock()

		if !matched {
			m.Free()
			continue
		}

		select {
		case rq <- m:
		case <-cq:
			m.Free()
			return
		default: // no room, drop it
			m.Free()
		}
	}
}

func (*sub) Number() uint16 {
	return mangos.ProtoSub
}

func (*sub) PeerNumber() uint16 {
	return mangos.ProtoPub
}

func (*sub) Name() string {
	return "sub"
}

func (*sub) PeerName() string {
	return "pub"
}

func (s *sub) AddEndpoint(ep mangos.Endpoint) {
	go s.receiver(ep)
}

func (*sub) RemoveEndpoint(mangos.Endpoint) {}

func (s *sub) SetOption(name string, value interface{}) error {
	s.Lock()
	defer s.Unlock()

	var vb []byte
	var ok bool

	// Check names first, because type check below is only valid for
	// subscription options.
	switch name {
	case mangos.OptionRaw:
		if s.raw, ok = value.(bool); !ok {
			return mangos.ErrBadValue
		}
		return nil
	case mangos.OptionSubscribe:
	case mangos.OptionUnsubscribe:
	default:
		return mangos.ErrBadOption
	}

	switch v := value.(type) {
	case []byte:
		vb = v
	case string:
		vb = []byte(v)
	default:
		return mangos.ErrBadValue
	}
	switch name {
	case mangos.OptionSubscribe:
		for _, sub := range s.subs {
			if bytes.Equal(sub, vb) {
				// Already present
				return nil
			}
		}
		s.subs = append(s.subs, vb)
		return nil

	case mangos.OptionUnsubscribe:
		for i, sub := range s.subs {
			if bytes.Equal(sub, vb) {
				s.subs[i] = s.subs[len(s.subs)-1]
				s.subs = s.subs[:len(s.subs)-1]
				return nil
			}
		}
		// Subscription not present
		return mangos.ErrBadValue

	default:
		return mangos.ErrBadOption
	}
}

func (s *sub) GetOption(name string) (interface{}, error) {
	switch name {
	case mangos.OptionRaw:
		return s.raw, nil
	default:
		return nil, mangos.ErrBadOption
	}
}

// NewSocket allocates a new Socket using the SUB protocol.
func NewSocket() (mangos.Socket, error) {
	return mangos.MakeSocket(&sub{}), nil
}
<commit_msg>fixes #227 Document unsubscribed sub socket blocks<commit_after>// Copyright 2016 The Mangos Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use file except in compliance with the License.
// You may obtain a copy of the license at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package sub implements the SUB protocol.  This protocol receives messages
// from publishers (PUB peers).  The messages are filtered based on
// subscription, such that only subscribed messages (see OptionSubscribe) are
// received.
//
// Note that in order to receive any messages, at least one subscription must
// be present.  If no subscription is present (the default state), receive
// operations will block forever.
package sub

import (
	"bytes"
	"sync"
	"time"

	"github.com/go-mangos/mangos"
)

type sub struct {
	sock mangos.ProtocolSocket
	subs [][]byte
	raw  bool
	sync.Mutex
}

func (s *sub) Init(sock mangos.ProtocolSocket) {
	s.sock = sock
	s.subs = [][]byte{}
	s.sock.SetSendError(mangos.ErrProtoOp)
}

func (*sub) Shutdown(time.Time) {} // No sender to drain.

func (s *sub) receiver(ep mangos.Endpoint) {

	rq := s.sock.RecvChannel()
	cq := s.sock.CloseChannel()

	for {
		var matched = false

		m := ep.RecvMsg()
		if m == nil {
			return
		}

		s.Lock()
		for _, sub := range s.subs {
			if bytes.HasPrefix(m.Body, sub) {
				// Matched, send it up.  Best effort.
				matched = true
				break
			}
		}
		s.Unlock()

		if !matched {
			m.Free()
			continue
		}

		select {
		case rq <- m:
		case <-cq:
			m.Free()
			return
		default: // no room, drop it
			m.Free()
		}
	}
}

func (*sub) Number() uint16 {
	return mangos.ProtoSub
}

func (*sub) PeerNumber() uint16 {
	return mangos.ProtoPub
}

func (*sub) Name() string {
	return "sub"
}

func (*sub) PeerName() string {
	return "pub"
}

func (s *sub) AddEndpoint(ep mangos.Endpoint) {
	go s.receiver(ep)
}

func (*sub) RemoveEndpoint(mangos.Endpoint) {}

func (s *sub) SetOption(name string, value interface{}) error {
	s.Lock()
	defer s.Unlock()

	var vb []byte
	var ok bool

	// Check names first, because type check below is only valid for
	// subscription options.
	switch name {
	case mangos.OptionRaw:
		if s.raw, ok = value.(bool); !ok {
			return mangos.ErrBadValue
		}
		return nil
	case mangos.OptionSubscribe:
	case mangos.OptionUnsubscribe:
	default:
		return mangos.ErrBadOption
	}

	switch v := value.(type) {
	case []byte:
		vb = v
	case string:
		vb = []byte(v)
	default:
		return mangos.ErrBadValue
	}
	switch name {
	case mangos.OptionSubscribe:
		for _, sub := range s.subs {
			if bytes.Equal(sub, vb) {
				// Already present
				return nil
			}
		}
		s.subs = append(s.subs, vb)
		return nil

	case mangos.OptionUnsubscribe:
		for i, sub := range s.subs {
			if bytes.Equal(sub, vb) {
				s.subs[i] = s.subs[len(s.subs)-1]
				s.subs = s.subs[:len(s.subs)-1]
				return nil
			}
		}
		// Subscription not present
		return mangos.ErrBadValue

	default:
		return mangos.ErrBadOption
	}
}

func (s *sub) GetOption(name string) (interface{}, error) {
	switch name {
	case mangos.OptionRaw:
		return s.raw, nil
	default:
		return nil, mangos.ErrBadOption
	}
}

// NewSocket allocates a new Socket using the SUB protocol.
func NewSocket() (mangos.Socket, error) {
	return mangos.MakeSocket(&sub{}), nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"koding/kite-handler/command"
	"koding/kite-handler/fs"
	"koding/kite-handler/terminal"
	"koding/kites/klient/collaboration"
	"koding/kites/klient/protocol"
	"koding/kites/klient/usage"

	"github.com/koding/kite"
	"github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update paramters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":    true,
		"fs.glob":             true,
		"fs.readFile":         true,
		"fs.writeFile":        true,
		"fs.uniquePath":       true,
		"fs.getInfo":          true,
		"fs.setPermissions":   true,
		"fs.remove":           true,
		"fs.rename":           true,
		"fs.createDirectory":  true,
		"fs.move":             true,
		"fs.copy":             true,
		"webterm.getSessions": true,
		"webterm.connect":     true,
		"webterm.killSession": true,
		"exec":                true,
		"klient.share":        true,
		"klient.unshare":      true,
		"klient.shared":       true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	// FIXME: It's ugly I know. It's a fix for Koding local development and is
	// needed
	if !strings.Contains(k.Config.KontrolURL, "ngrok") {
		// override current kontrolURL so it talks to port 3000, this is needed
		// because ELB can forward requests based on ports. The port 80 and 443 are
		// HTTP/HTTPS only so our kite can't connect it (we use websocket). However
		// We have a TCP proxy at 3000 which allows us to connect via WebSocket.
		u, _ := url.Parse(k.Config.KontrolURL)

		host := u.Host
		if HasPort(u.Host) {
			host, _, _ = net.SplitHostPort(u.Host)
		}

		u.Host = AddPort(host, "3000")
		u.Scheme = "http"
		k.Config.KontrolURL = u.String()
	}

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		sharedUsers, err := collab.GetAll()
		if err != nil {
			k.Log.Warning("Couldn't unshare users: '%s'", err)
			return
		}

		if len(sharedUsers) == 0 {
			return // nothing to do ...
		}

		k.Log.Info("Unsharing users '%s'", sharedUsers)
		for _, user := range sharedUsers {
			if err := collab.Delete(user); err != nil {
				k.Log.Warning("Couldn't delete user from storage: '%s'", err)
			}

			// close all active sessions of the current
			term.CloseSessions(user)
		}
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<commit_msg>docker: add consructor and include handlers into Klient<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"net"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"

	"koding/kite-handler/command"
	"koding/kite-handler/docker"
	"koding/kite-handler/fs"
	"koding/kite-handler/terminal"
	"koding/kites/klient/collaboration"
	"koding/kites/klient/protocol"
	"koding/kites/klient/usage"

	"github.com/koding/kite"
	"github.com/koding/kite/config"
)

var (
	flagIP          = flag.String("ip", "", "Change public ip")
	flagPort        = flag.Int("port", 56789, "Change running port")
	flagVersion     = flag.Bool("version", false, "Show version and exit")
	flagEnvironment = flag.String("env", protocol.Environment, "Change environment")
	flagRegion      = flag.String("region", protocol.Region, "Change region")
	flagRegisterURL = flag.String("register-url", "", "Change register URL to kontrol")
	flagDebug       = flag.Bool("debug", false, "Debug mode")

	// update paramters
	flagUpdateInterval = flag.Duration("update-interval", time.Minute*5,
		"Change interval for checking for new updates")
	flagUpdateURL = flag.String("update-url",
		"https://s3.amazonaws.com/koding-klient/"+protocol.Environment+"/latest-version.txt",
		"Change update endpoint for latest version")

	VERSION = protocol.Version
	NAME    = protocol.Name

	// this is our main reference to count and measure metrics for the klient
	// we count only those methods, please add/remove methods here that will
	// reset the timer of a klient.
	usg = usage.NewUsage(map[string]bool{
		"fs.readDirectory":    true,
		"fs.glob":             true,
		"fs.readFile":         true,
		"fs.writeFile":        true,
		"fs.uniquePath":       true,
		"fs.getInfo":          true,
		"fs.setPermissions":   true,
		"fs.remove":           true,
		"fs.rename":           true,
		"fs.createDirectory":  true,
		"fs.move":             true,
		"fs.copy":             true,
		"webterm.getSessions": true,
		"webterm.connect":     true,
		"webterm.killSession": true,
		"exec":                true,
		"klient.share":        true,
		"klient.unshare":      true,
		"klient.shared":       true,
	})

	// this is used to allow other users to call any klient method.
	collab = collaboration.New()

	// we also could use an atomic boolean this is simple for now.
	updating   = false
	updatingMu sync.Mutex // protects updating
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Println(VERSION)
		os.Exit(0)
	}

	k := newKite()

	// Close the klient.db in any case. Corrupt db would be catastrophic
	defer collab.Close()

	k.Log.Info("Running as version %s", VERSION)
	k.Run()
}

func newKite() *kite.Kite {
	k := kite.New(NAME, VERSION)

	if *flagDebug {
		k.SetLogLevel(kite.DEBUG)
	}

	conf := config.MustGet()
	k.Config = conf
	k.Config.Port = *flagPort
	k.Config.Environment = *flagEnvironment
	k.Config.Region = *flagRegion
	k.Id = conf.Id // always boot up with the same id in the kite.key

	// FIXME: It's ugly I know. It's a fix for Koding local development and is
	// needed
	if !strings.Contains(k.Config.KontrolURL, "ngrok") {
		// override current kontrolURL so it talks to port 3000, this is needed
		// because ELB can forward requests based on ports. The port 80 and 443 are
		// HTTP/HTTPS only so our kite can't connect it (we use websocket). However
		// We have a TCP proxy at 3000 which allows us to connect via WebSocket.
		u, _ := url.Parse(k.Config.KontrolURL)

		host := u.Host
		if HasPort(u.Host) {
			host, _, _ = net.SplitHostPort(u.Host)
		}

		u.Host = AddPort(host, "3000")
		u.Scheme = "http"
		k.Config.KontrolURL = u.String()
	}

	if *flagUpdateInterval < time.Minute {
		k.Log.Warning("Update interval can't be less than one minute. Setting to one minute.")
		*flagUpdateInterval = time.Minute
	}

	updater := &Updater{
		Endpoint: *flagUpdateURL,
		Interval: *flagUpdateInterval,
		Log:      k.Log,
	}

	// before we register check for latest update and re-update itself before
	// we continue
	k.Log.Info("Checking for new updates")
	if err := updater.checkAndUpdate(); err != nil {
		k.Log.Warning("Self-update: %s", err)
	}

	go updater.Run()

	userIn := func(user string, users ...string) bool {
		for _, u := range users {
			if u == user {
				return true
			}
		}
		return false
	}

	// don't pass any request if the caller is outside of our scope.
	// don't allow anyone to call a method if we are during an update.
	k.PreHandleFunc(func(r *kite.Request) (interface{}, error) {
		// only authenticated methods have correct username. For example
		// kite.ping has authentication disabled so username can be empty.
		if r.Auth != nil {
			k.Log.Info("Kite '%s/%s/%s' called method: '%s'",
				r.Username, r.Client.Environment, r.Client.Name, r.Method)

			// Allow these users by default
			allowedUsers := []string{k.Config.Username, "koding"}

			// Allow collaboration users as well
			sharedUsers, err := collab.GetAll()
			if err != nil {
				return nil, fmt.Errorf("Can't read shared users from the storage. Err: %v", err)
			}
			allowedUsers = append(allowedUsers, sharedUsers...)

			if !userIn(r.Username, allowedUsers...) {
				return nil, fmt.Errorf("User '%s' is not allowed to make a call to us.", r.Username)
			}
		}

		updatingMu.Lock()
		defer updatingMu.Unlock()

		if updating {
			return nil, errors.New("Updating klient. Can't accept any method.")
		}

		return true, nil
	})

	// Metrics, is used by Kloud to get usage so Kloud can stop free VMs
	k.PreHandleFunc(usg.Counter) // we measure every incoming request
	k.HandleFunc("klient.usage", usg.Current)

	// Collaboration, is used by our Koding.com browser client
	k.HandleFunc("klient.share", collab.Share)
	k.HandleFunc("klient.unshare", collab.Unshare)
	k.HandleFunc("klient.shared", collab.Shared)

	// Filesystem
	k.HandleFunc("fs.readDirectory", fs.ReadDirectory)
	k.HandleFunc("fs.glob", fs.Glob)
	k.HandleFunc("fs.readFile", fs.ReadFile)
	k.HandleFunc("fs.writeFile", fs.WriteFile)
	k.HandleFunc("fs.uniquePath", fs.UniquePath)
	k.HandleFunc("fs.getInfo", fs.GetInfo)
	k.HandleFunc("fs.setPermissions", fs.SetPermissions)
	k.HandleFunc("fs.remove", fs.Remove)
	k.HandleFunc("fs.rename", fs.Rename)
	k.HandleFunc("fs.createDirectory", fs.CreateDirectory)
	k.HandleFunc("fs.move", fs.Move)
	k.HandleFunc("fs.copy", fs.Copy)

	// Docker
	dock := docker.New("tcp")
	k.HandleFunc("docker.build", dock.Build)
	k.HandleFunc("docker.create", dock.Create)
	k.HandleFunc("docker.connect", dock.Connect)
	k.HandleFunc("docker.stop", dock.Stop)
	k.HandleFunc("docker.start", dock.Start)
	k.HandleFunc("docker.kill", dock.Kill)
	k.HandleFunc("docker.destroy", dock.Destroy)
	k.HandleFunc("docker.list", dock.List)

	// Execution
	k.HandleFunc("exec", command.Exec)

	// Terminal
	term := terminal.New(k.Log)
	term.InputHook = usg.Reset
	k.HandleFunc("webterm.getSessions", term.GetSessions)
	k.HandleFunc("webterm.connect", term.Connect)
	k.HandleFunc("webterm.killSession", term.KillSession)
	k.HandleFunc("webterm.killSessions", term.KillSessions)

	// Unshare collab users if the klient owner disconnects
	k.OnDisconnect(func(c *kite.Client) {
		k.Log.Info("Kite '%s/%s/%s' is disconnected", c.Username, c.Environment, c.Name)
		if c.Username != k.Config.Username {
			return // we don't care for others
		}

		sharedUsers, err := collab.GetAll()
		if err != nil {
			k.Log.Warning("Couldn't unshare users: '%s'", err)
			return
		}

		if len(sharedUsers) == 0 {
			return // nothing to do ...
		}

		k.Log.Info("Unsharing users '%s'", sharedUsers)
		for _, user := range sharedUsers {
			if err := collab.Delete(user); err != nil {
				k.Log.Warning("Couldn't delete user from storage: '%s'", err)
			}

			// close all active sessions of the current
			term.CloseSessions(user)
		}
	})

	if err := register(k); err != nil {
		panic(err)
	}

	return k
}

// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
// return true if the string includes a port.
func HasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// Given a string of the form "host", "port", returns "host:port"
func AddPort(host, port string) string {
	if ok := HasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<|endoftext|>


<commit_before>// Copyright 2012 Junqing Tan <ivan@mysqlab.net> and The Go Authors
// Use of this source code is governed by a BSD-style
// Part of source code is from Go fcgi package

package fcgiclient

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"sync"
	"errors"
	"io"
	"net"
	"strconv"
  "strings"
  "net/http"
)

const FCGI_LISTENSOCK_FILENO uint8 = 0
const FCGI_HEADER_LEN uint8 = 8
const VERSION_1 uint8 = 1
const FCGI_NULL_REQUEST_ID uint8 = 0
const FCGI_KEEP_CONN uint8 = 1
const doubleCRLF = "\r\n\r\n"

const (
	FCGI_BEGIN_REQUEST uint8 = iota + 1
	FCGI_ABORT_REQUEST
	FCGI_END_REQUEST
	FCGI_PARAMS
	FCGI_STDIN
	FCGI_STDOUT
	FCGI_STDERR
	FCGI_DATA
	FCGI_GET_VALUES
	FCGI_GET_VALUES_RESULT
	FCGI_UNKNOWN_TYPE
	FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
)

const (
	FCGI_RESPONDER uint8 = iota + 1
	FCGI_AUTHORIZER
	FCGI_FILTER
)

const (
	FCGI_REQUEST_COMPLETE uint8 = iota
	FCGI_CANT_MPX_CONN
	FCGI_OVERLOADED
	FCGI_UNKNOWN_ROLE
)

const (
	FCGI_MAX_CONNS  string = "MAX_CONNS"
	FCGI_MAX_REQS   string = "MAX_REQS"
	FCGI_MPXS_CONNS string = "MPXS_CONNS"
)

const (
	maxWrite = 6553500 // maximum record body
	maxPad   = 255
)

type header struct {
	Version       uint8
	Type          uint8
	Id            uint16
	ContentLength uint16
	PaddingLength uint8
	Reserved      uint8
}

// for padding so we don't have to allocate all the time
// not synchronized because we don't care what the contents are
var pad [maxPad]byte

func (h *header) init(recType uint8, reqId uint16, contentLength int) {
	h.Version = 1
	h.Type = recType
	h.Id = reqId
	h.ContentLength = uint16(contentLength)
	h.PaddingLength = uint8(-contentLength & 7)
}

type record struct {
	h   header
	buf [maxWrite + maxPad]byte
}

func (rec *record) read(r io.Reader) (buf []byte, err error) {
	if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
		return
	}
	if rec.h.Version != 1 {
    err = errors.New("fcgi: invalid header version")
		return
	}
  if rec.h.Type == FCGI_END_REQUEST {
    err = io.EOF
    return
  }
  n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
	if n, err = io.ReadFull(r, rec.buf[:n]); err != nil {
		return
	}
  buf = rec.buf[:int(rec.h.ContentLength)]

	return
}

type FCGIClient struct {
	mutex     sync.Mutex
	rwc       io.ReadWriteCloser
	h         header
	buf 	  bytes.Buffer
	keepAlive bool
}

func New(h string, args ...interface{}) (fcgi *FCGIClient, err error) {
	var conn net.Conn
	if len(args) != 1 {
		err = errors.New("fcgi: not enough params")
		return
	}
	switch args[0].(type) {
	case int:
		addr := h + ":" + strconv.FormatInt(int64(args[0].(int)), 10)
		conn, err = net.Dial("tcp", addr)
	case string:
		addr := args[0].(string)
		conn, err = net.Dial("unix", addr)
	default:
		err = errors.New("fcgi: we only accept int (port) or string (socket) params.")
	}
	fcgi = &FCGIClient{
		rwc:       conn,
		keepAlive: false,
	}
	return
}

func (this *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) ( err error) {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	this.buf.Reset()
	this.h.init(recType, reqId, len(content))
	if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
		return err
	}
	if _, err := this.buf.Write(content); err != nil {
		return err
	}
	if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
		return err
	}
	_, err = this.rwc.Write(this.buf.Bytes())
	return err
}

func (this *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
	b := [8]byte{byte(role >> 8), byte(role), flags}
	return this.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:])
}

func (this *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
	b := make([]byte, 8)
	binary.BigEndian.PutUint32(b, uint32(appStatus))
	b[4] = protocolStatus
	return this.writeRecord(FCGI_END_REQUEST, reqId, b)
}

func (this *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error {
	w := newWriter(this, recType, reqId)
	b := make([]byte, 8)
	for k, v := range pairs {
		n := encodeSize(b, uint32(len(k)))
		n += encodeSize(b[n:], uint32(len(v)))
		if _, err := w.Write(b[:n]); err != nil {
			return err
		}
		if _, err := w.WriteString(k); err != nil {
			return err
		}
		if _, err := w.WriteString(v); err != nil {
			return err
		}
	}
	w.Close()
	return nil
}

func readSize(s []byte) (uint32, int) {
	if len(s) == 0 {
		return 0, 0
	}
	size, n := uint32(s[0]), 1
	if size&(1<<7) != 0 {
		if len(s) < 4 {
			return 0, 0
		}
		n = 4
		size = binary.BigEndian.Uint32(s)
		size &^= 1 << 31
	}
	return size, n
}

func readString(s []byte, size uint32) string {
	if size > uint32(len(s)) {
		return ""
	}
	return string(s[:size])
}

func encodeSize(b []byte, size uint32) int {
	if size > 127 {
		size |= 1 << 31
		binary.BigEndian.PutUint32(b, size)
		return 4
	}
	b[0] = byte(size)
	return 1
}

// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
// Closed.
type bufWriter struct {
	closer io.Closer
	*bufio.Writer
}

func (w *bufWriter) Close() error {
	if err := w.Writer.Flush(); err != nil {
		w.closer.Close()
		return err
	}
	return w.closer.Close()
}

func newWriter(c *FCGIClient, recType uint8, reqId uint16) *bufWriter {
	s := &streamWriter{c: c, recType: recType, reqId: reqId}
	w := bufio.NewWriterSize(s, maxWrite)
	return &bufWriter{s, w}
}

// streamWriter abstracts out the separation of a stream into discrete records.
// It only writes maxWrite bytes at a time.
type streamWriter struct {
	c       *FCGIClient
	recType uint8
	reqId   uint16
}

func (w *streamWriter) Write(p []byte) (int, error) {
	nn := 0
	for len(p) > 0 {
		n := len(p)
		if n > maxWrite {
			n = maxWrite
		}
		if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
			return nn, err
		}
		nn += n
		p = p[n:]
	}
	return nn, nil
}

func (w *streamWriter) Close() error {
	// send empty record to close the stream
	return w.c.writeRecord(w.recType, w.reqId, nil)
}

func (this *FCGIClient) Request(resp http.ResponseWriter, env map[string]string, reqStr string) (ret []byte, err error) {

	var reqId uint16 = 1

	err = this.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0)
	if err != nil {
		return
	}
	err = this.writePairs(FCGI_PARAMS, reqId, env)
	if err != nil {
		return
	}
	if len(reqStr) > 0 {
		err = this.writeRecord(FCGI_STDIN, reqId, []byte(reqStr))
		if err != nil {
			return
		}
	}

  afterheader := false
	rec := &record{}
	for {
    buf, err := rec.read(this.rwc)
  	if err != nil {
  		break
  	}

    if afterheader {
      if resp != nil {
        resp.Write(buf)
      }
      ret = append(ret, buf...)
    } else {
      z := strings.SplitN(string(buf), doubleCRLF, 2)
      switch (len(z)) {
        case 2:
          if resp != nil {
            lines := strings.Split(z[0], "\n")
            for line := range lines  {
              v := strings.SplitN(lines[line], ":",2)
              if len(v) == 2 {
                resp.Header().Set(strings.TrimSpace(v[0]), strings.TrimSpace(v[1]))
              }
            }
            resp.Write([]byte(z[1]))
          }
          ret = append(ret, []byte(z[1])...)
        default:
          if resp != nil {
            resp.Write(buf)
          }
          ret = append(ret, buf...)
      }

      afterheader = true
    }

  }

	return
}
<commit_msg>support Close connection; use standard Dail argument style to create fcgi clietn<commit_after>// Copyright 2012 Junqing Tan <ivan@mysqlab.net> and The Go Authors
// Use of this source code is governed by a BSD-style
// Part of source code is from Go fcgi package

package fcgiclient

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"sync"
	"errors"
	"io"
	"net"
  "strings"
  "net/http"
)

const FCGI_LISTENSOCK_FILENO uint8 = 0
const FCGI_HEADER_LEN uint8 = 8
const VERSION_1 uint8 = 1
const FCGI_NULL_REQUEST_ID uint8 = 0
const FCGI_KEEP_CONN uint8 = 1
const doubleCRLF = "\r\n\r\n"

const (
	FCGI_BEGIN_REQUEST uint8 = iota + 1
	FCGI_ABORT_REQUEST
	FCGI_END_REQUEST
	FCGI_PARAMS
	FCGI_STDIN
	FCGI_STDOUT
	FCGI_STDERR
	FCGI_DATA
	FCGI_GET_VALUES
	FCGI_GET_VALUES_RESULT
	FCGI_UNKNOWN_TYPE
	FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE
)

const (
	FCGI_RESPONDER uint8 = iota + 1
	FCGI_AUTHORIZER
	FCGI_FILTER
)

const (
	FCGI_REQUEST_COMPLETE uint8 = iota
	FCGI_CANT_MPX_CONN
	FCGI_OVERLOADED
	FCGI_UNKNOWN_ROLE
)

const (
	FCGI_MAX_CONNS  string = "MAX_CONNS"
	FCGI_MAX_REQS   string = "MAX_REQS"
	FCGI_MPXS_CONNS string = "MPXS_CONNS"
)

const (
	maxWrite = 6553500 // maximum record body
	maxPad   = 255
)

type header struct {
	Version       uint8
	Type          uint8
	Id            uint16
	ContentLength uint16
	PaddingLength uint8
	Reserved      uint8
}

// for padding so we don't have to allocate all the time
// not synchronized because we don't care what the contents are
var pad [maxPad]byte

func (h *header) init(recType uint8, reqId uint16, contentLength int) {
	h.Version = 1
	h.Type = recType
	h.Id = reqId
	h.ContentLength = uint16(contentLength)
	h.PaddingLength = uint8(-contentLength & 7)
}

type record struct {
	h   header
	buf [maxWrite + maxPad]byte
}

func (rec *record) read(r io.Reader) (buf []byte, err error) {
	if err = binary.Read(r, binary.BigEndian, &rec.h); err != nil {
		return
	}
	if rec.h.Version != 1 {
    err = errors.New("fcgi: invalid header version")
		return
	}
  if rec.h.Type == FCGI_END_REQUEST {
    err = io.EOF
    return
  }
  n := int(rec.h.ContentLength) + int(rec.h.PaddingLength)
	if n, err = io.ReadFull(r, rec.buf[:n]); err != nil {
		return
	}
  buf = rec.buf[:int(rec.h.ContentLength)]

	return
}

type FCGIClient struct {
	mutex     sync.Mutex
	rwc       io.ReadWriteCloser
	h         header
	buf 	  bytes.Buffer
	keepAlive bool
}

func New(t string, a string) (fcgi *FCGIClient, err error) {
	var conn net.Conn

	conn, err = net.Dial(t, a)
  if err != nil {
    return
  }

	fcgi = &FCGIClient{
		rwc:       conn,
		keepAlive: false,
	}

	return
}

func (this *FCGIClient) Close() {
  this.rwc.Close()
}

func (this *FCGIClient) writeRecord(recType uint8, reqId uint16, content []byte) ( err error) {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	this.buf.Reset()
	this.h.init(recType, reqId, len(content))
	if err := binary.Write(&this.buf, binary.BigEndian, this.h); err != nil {
		return err
	}
	if _, err := this.buf.Write(content); err != nil {
		return err
	}
	if _, err := this.buf.Write(pad[:this.h.PaddingLength]); err != nil {
		return err
	}
	_, err = this.rwc.Write(this.buf.Bytes())
	return err
}

func (this *FCGIClient) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
	b := [8]byte{byte(role >> 8), byte(role), flags}
	return this.writeRecord(FCGI_BEGIN_REQUEST, reqId, b[:])
}

func (this *FCGIClient) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
	b := make([]byte, 8)
	binary.BigEndian.PutUint32(b, uint32(appStatus))
	b[4] = protocolStatus
	return this.writeRecord(FCGI_END_REQUEST, reqId, b)
}

func (this *FCGIClient) writePairs(recType uint8, reqId uint16, pairs map[string]string) error {
	w := newWriter(this, recType, reqId)
	b := make([]byte, 8)
	for k, v := range pairs {
		n := encodeSize(b, uint32(len(k)))
		n += encodeSize(b[n:], uint32(len(v)))
		if _, err := w.Write(b[:n]); err != nil {
			return err
		}
		if _, err := w.WriteString(k); err != nil {
			return err
		}
		if _, err := w.WriteString(v); err != nil {
			return err
		}
	}
	w.Close()
	return nil
}

func readSize(s []byte) (uint32, int) {
	if len(s) == 0 {
		return 0, 0
	}
	size, n := uint32(s[0]), 1
	if size&(1<<7) != 0 {
		if len(s) < 4 {
			return 0, 0
		}
		n = 4
		size = binary.BigEndian.Uint32(s)
		size &^= 1 << 31
	}
	return size, n
}

func readString(s []byte, size uint32) string {
	if size > uint32(len(s)) {
		return ""
	}
	return string(s[:size])
}

func encodeSize(b []byte, size uint32) int {
	if size > 127 {
		size |= 1 << 31
		binary.BigEndian.PutUint32(b, size)
		return 4
	}
	b[0] = byte(size)
	return 1
}

// bufWriter encapsulates bufio.Writer but also closes the underlying stream when
// Closed.
type bufWriter struct {
	closer io.Closer
	*bufio.Writer
}

func (w *bufWriter) Close() error {
	if err := w.Writer.Flush(); err != nil {
		w.closer.Close()
		return err
	}
	return w.closer.Close()
}

func newWriter(c *FCGIClient, recType uint8, reqId uint16) *bufWriter {
	s := &streamWriter{c: c, recType: recType, reqId: reqId}
	w := bufio.NewWriterSize(s, maxWrite)
	return &bufWriter{s, w}
}

// streamWriter abstracts out the separation of a stream into discrete records.
// It only writes maxWrite bytes at a time.
type streamWriter struct {
	c       *FCGIClient
	recType uint8
	reqId   uint16
}

func (w *streamWriter) Write(p []byte) (int, error) {
	nn := 0
	for len(p) > 0 {
		n := len(p)
		if n > maxWrite {
			n = maxWrite
		}
		if err := w.c.writeRecord(w.recType, w.reqId, p[:n]); err != nil {
			return nn, err
		}
		nn += n
		p = p[n:]
	}
	return nn, nil
}

func (w *streamWriter) Close() error {
	// send empty record to close the stream
	return w.c.writeRecord(w.recType, w.reqId, nil)
}

func (this *FCGIClient) Request(resp http.ResponseWriter, env map[string]string, reqStr string) (ret []byte, err error) {

	var reqId uint16 = 1

	err = this.writeBeginRequest(reqId, uint16(FCGI_RESPONDER), 0)
	if err != nil {
		return
	}
	err = this.writePairs(FCGI_PARAMS, reqId, env)
	if err != nil {
		return
	}
	err = this.writeRecord(FCGI_STDIN, reqId, []byte(reqStr))
	if err != nil {
		return
	}

  afterheader := false
	rec := &record{}
	for {
    buf, err := rec.read(this.rwc)
  	if err != nil {
  		break
  	}

    if afterheader {
      if resp != nil {
        resp.Write(buf)
      }
      ret = append(ret, buf...)
    } else {
      z := strings.SplitN(string(buf), doubleCRLF, 2)
      switch (len(z)) {
        case 2:
          if resp != nil {
            lines := strings.Split(z[0], "\n")
            for line := range lines  {
              v := strings.SplitN(lines[line], ":",2)
              if len(v) == 2 {
                resp.Header().Set(strings.TrimSpace(v[0]), strings.TrimSpace(v[1]))
              }
            }
            resp.Write([]byte(z[1]))
          }
          ret = append(ret, []byte(z[1])...)
        default:
          if resp != nil {
            resp.Write(buf)
          }
          ret = append(ret, buf...)
      }

      afterheader = true
    }
  }

	return
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 winlin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// The PCM resample.
package aresample

import (
	"fmt"
)

type ResampleSampleRate interface {
	// Resample the pcm to npcm, which contains len(pcm)/2 samples.
	// @remark each sample is 16bits in short int.
	// @reamrk pcm must align to 2, atleast 4 samples.
	Resample(pcm []byte) (npcm []byte, err error)
}

// sample rate resampler.
type srResampler struct {
	channels int     // Channels, L or LR
	isr      int     // Transform from this sample rate.
	osr      int     // Transform to this sample rate.

					 // Always cache 16samples.
	lcache   []int16 // For channel=0
	rcache   []int16 // For channel=1

					 // Total outputed samples.
	lws      uint64  // For channel=0
	rws      uint64  // For channel=1

					 // Total consumed samples.
	lcs      uint64  // For channel=0
	rcs      uint64  // For channel=1
}

// Create resampler to transform pcm
// from sampleRate to nSampleRate, where pcm contains number of channels
// @remark each sample is 16bits in short int.
func NewPcmS16leResampler(channels, sampleRate int, nSampleRate int) (ResampleSampleRate, error) {
	if channels < 1 || channels > 2 {
		return nil,fmt.Errorf("invalid channels=%v", channels)
	}
	if sampleRate <= 0 {
		return nil,fmt.Errorf("invalid sampleRate=%v", sampleRate)
	}
	if nSampleRate <= 0 {
		return nil,fmt.Errorf("invalid nSampleRate=%v", nSampleRate)
	}

	v := &srResampler{
		channels: channels,
		isr: sampleRate,
		osr: nSampleRate,
	}

	return v,nil
}

func (v *srResampler) Resample(pcm []byte) (npcm []byte, err error) {
	if len(pcm) == 0 {
		return nil,fmt.Errorf("empty pcm")
	}
	if (len(pcm)%(2*v.channels)) != 0 {
		return nil,fmt.Errorf("invalid pcm, should mod(%v)", 2*v.channels)
	}

	if v.isr == v.osr {
		return pcm[:],nil
	}

	// Atleast 4samples when not init.
	if nbSamles := len(pcm) / 2 / v.channels; nbSamles < 4 {
		return nil,fmt.Errorf("invalid pcm, atleast 4samples, actual %vsamples", nbSamles)
	}

	// Convert pcm to int16 values
	ipcmLeft := resampler_init_channel(pcm, v.channels, 0)
	ipcmRight := resampler_init_channel(pcm, v.channels, 1)
	if ipcmRight != nil && len(ipcmLeft) != len(ipcmRight) {
		return nil,fmt.Errorf("invalid pcm, L%v!=%v", len(ipcmLeft), len(ipcmRight))
	}

	// Insert the cache at the beginning.
	if v.lcache != nil {
		ipcmLeft = append(v.lcache, ipcmLeft...)
		v.lcache = nil
	}
	if ipcmRight != nil && v.rcache != nil {
		ipcmRight = append(v.rcache, ipcmRight...)
		v.rcache = nil
	}

	// Resample all channels
	var consumed int
	var opcmLeft []int16
	if opcmLeft,consumed,err = resample_channel(ipcmLeft,v.isr,v.osr,v.lws,v.lcs); err != nil {
		return nil,err
	}
	v.lws += uint64(len(opcmLeft))
	v.lcs += uint64(consumed)
	if consumed < len(ipcmLeft) {
		v.lcache = ipcmLeft[consumed:]
	}

	var opcmRight []int16
	if ipcmRight != nil {
		if opcmRight,consumed,err = resample_channel(ipcmRight,v.isr,v.osr,v.rws,v.rcs); err != nil {
			return nil,err
		}
		v.rws += uint64(len(opcmRight))
		v.rcs += uint64(consumed)
		if consumed < len(ipcmRight) {
			v.rcache = ipcmRight[consumed:]
		}
	}

	// Convert int16 samples to bytes.
	npcm = resample_merge(opcmLeft, opcmRight)

	return
}

// merge left and right(can be nil).
func resample_merge(left,right []int16) (npcm []byte) {
	npcm = []byte{}
	for i:=0; i<len(left); i++ {
		v := left[i]
		npcm = append(npcm, byte(v))
		npcm = append(npcm, byte(v >> 8))

		if right != nil {
			v = right[i]
			npcm = append(npcm, byte(v))
			npcm = append(npcm, byte(v >> 8))
		}
	}
	return
}

// x is the position of output pcm
func resample_channel(ipcm []int16, isr,osr int, written,org uint64) (opcm []int16, consumed int, err error) {
	if len(ipcm) <= 16 {
		return nil,0,nil
	}

	// The samples we can use to resample
	available := len(ipcm) - 16
	// The resample step between new samples
	step := float64(isr)/float64(osr)
	// The first position to sample
	x0 := step*float64(written)

	// The position for the last sample.
	last := org + uint64(available)

	// Resample each position from x0
	for x:=x0; x < float64(last); x+=step {
		// Generate xi,yi,xo,yo
		xi0 := float64(uint64(x))
		xi := []float64{xi0, xi0+1, xi0+2, xi0+3}
		yi0 := int(uint64(xi0)-org)
		yi := []float64{float64(ipcm[yi0]),float64(ipcm[yi0+1]),float64(ipcm[yi0+2]),float64(ipcm[yi0+3])}
		xo := []float64{x}
		yo := []float64{0.0}
		if err = spline(xi,yi,xo,yo); err != nil {
			return
		}

		// convert yo
		opcm = append(opcm, int16(yo[0]))
		consumed = int(uint64(x)-org) + 1
	}

	return
}

// resampler_init_channel([]byte{...}, 1, 0)
// resampler_init_channel([]byte{...}, 2, 0)
// resampler_init_channel([]byte{...}, 2, 1)
func resampler_init_channel(pcm []byte, channels, channel int) (ipcm []int16) {
	if channel >= channels {
		return
	}

	ipcm = []int16{}
	for i:=2*channel; i<len(pcm); i+=2*channels {
		// 16bits le sample
		v := (int16(pcm[i])) | (int16(pcm[i + 1]) << 8)
		ipcm = append(ipcm, v)
	}

	return
}

// xi must be [x0, x1, x2, x3] which is [1, 2, 3, 4]
// yi must be [y0, y1, y2, y3] which corresponding to xi
// xo the output insert position of x, must in [x0, x3]
// yo is the inserted value corresponding to xo
// For example:
//		spline([1,2,3,4], [7,9,2,5], [1.5,2.5,3.5], [?,?,?])
// which will fill the yo with values.
func spline(xi,yi,xo,yo []float64) (err error) {
	if len(xi) != 4 {
		return fmt.Errorf("invalid xi")
	}
	if len(yi) != 4 {
		return fmt.Errorf("invalid yi")
	}
	if len(xo) == 0 {
		return fmt.Errorf("invalid xo")
	}
	if len(yo) != len(xo) {
		return fmt.Errorf("invalid yo")
	}

	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]
	y0,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	h0,h1,h2,_,u1,l2,_ := spline_lu(xi)
	c1,c2 := spline_c1(yi,h0,h1), spline_c2(yi,h1, h2)
	m1,m2 := spline_m1(c1,c2,u1,l2), spline_m2(c1,c2,u1,l2) // m0=m3=0

	for k,v := range xo {
		if v <= x1 {
			yo[k] = spline_z0(m1,h0,x0,x1,y0,y1,v)
		} else if v <= x2 {
			yo[k] = spline_z1(m1,m2,h1,x1,x2,y1,y2,v)
		} else {
			yo[k] = spline_z2(m2,h2,x2,x3,y2,y3,v)
		}
	}

	return
}

func spline_z0(m1,h0,x0,x1,y0,y1,x float64) float64 {
	v0 := 0.0
	v1 := (x-x0)*(x-x0)*(x-x0)*m1/(6*h0)
	v2 := -1.0*y0*(x-x1)/h0
	v3 := (y1 - h0*h0*m1/6)*(x-x0)/h0
	return v0+v1+v2+v3
}

func spline_z1(m1,m2,h1,x1,x2,y1,y2,x float64) float64 {
	v0 := -1.0*(x-x2)*(x-x2)*(x-x2)*m1/(6*h1)
	v1 := (x-x1)*(x-x1)*(x-x1)*m2/(6*h1)
	v2 := -1.0*(y1-h1*h1*m1/6)*(x-x2)/h1
	v3 := (y2-h1*h1*m2/6)*(x-x1)/h1
	return v0+v1+v2+v3
}

func spline_z2(m2,h2,x2,x3,y2,y3,x float64) float64 {
	v0 := -1.0*(x-x3)*(x-x3)*(x-x3)*m2/(6*h2)
	v1 := 0.0
	v2 := -1.0*(y2-h2*h2*m2/6)*(x-x3)/h2
	v3 := y3*(x-x2)/h2
	return v0+v1+v2+v3
}

func spline_m1(c1,c2,u1,l2 float64) float64 {
	return (c1/u1 - c2/2) / (2/u1 - l2/2)
}

func spline_m2(c1,c2,u1,l2 float64) float64 {
	return (c1/2 - c2/l2) / (u1/2 - 2/l2)
}

func spline_c1(yi []float64, h0,h1 float64) float64 {
	y0,y1,y2,_ := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h0 + h1) * ((y2 - y1)/h1 - (y1 - y0)/h0)
}

func spline_c2(yi []float64, h1,h2 float64) float64 {
	_,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h1 + h2) * ((y3-y2)/h2 - (y2-y1)/h1)
}

func spline_lu(xi []float64) (h0,h1,h2,l1,u1,l2,u2 float64) {
	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]

	h0,h1,h2 = x1-x0,x2-x1,x3-x2

	l1 = h0 / (h1 + h0) // lambada1
	u1 = h1 / (h1 + h0)

	l2 = h1 / (h2 + h1) // lambada2
	u2 = h2 / (h2 + h1)

	return

}
<commit_msg>refine comments<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 winlin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// The PCM resample.
package aresample

import (
	"fmt"
)

type ResampleSampleRate interface {
	// Resample the pcm to npcm, which contains len(pcm)/2 samples.
	// @remark each sample is 16bits in short int.
	// @reamrk pcm must align to 2, atleast 4 samples.
	Resample(pcm []byte) (npcm []byte, err error)
}

// sample rate resampler.
type srResampler struct {
	channels int     // Channels, L or LR
	isr      int     // Transform from this sample rate.
	osr      int     // Transform to this sample rate.

					 // Always cache 16samples.
	lcache   []int16 // For channel=0
	rcache   []int16 // For channel=1

					 // Total outputed samples.
	lws      uint64  // For channel=0
	rws      uint64  // For channel=1

					 // Total consumed samples.
	lcs      uint64  // For channel=0
	rcs      uint64  // For channel=1
}

// Create resampler to transform pcm
// from sampleRate to nSampleRate, where pcm contains number of channels
// @remark each sample is 16bits in short int.
func NewPcmS16leResampler(channels, sampleRate int, nSampleRate int) (ResampleSampleRate, error) {
	if channels < 1 || channels > 2 {
		return nil,fmt.Errorf("invalid channels=%v", channels)
	}
	if sampleRate <= 0 {
		return nil,fmt.Errorf("invalid sampleRate=%v", sampleRate)
	}
	if nSampleRate <= 0 {
		return nil,fmt.Errorf("invalid nSampleRate=%v", nSampleRate)
	}

	v := &srResampler{
		channels: channels,
		isr: sampleRate,
		osr: nSampleRate,
	}

	return v,nil
}

func (v *srResampler) Resample(pcm []byte) (npcm []byte, err error) {
	if len(pcm) == 0 {
		return nil,fmt.Errorf("empty pcm")
	}
	if (len(pcm)%(2*v.channels)) != 0 {
		return nil,fmt.Errorf("invalid pcm, should mod(%v)", 2*v.channels)
	}

	if v.isr == v.osr {
		return pcm[:],nil
	}

	// Atleast 4samples when not init.
	if nbSamles := len(pcm) / 2 / v.channels; nbSamles < 4 {
		return nil,fmt.Errorf("invalid pcm, atleast 4samples, actual %vsamples", nbSamles)
	}

	// Convert pcm to int16 values
	ipcmLeft := resampler_init_channel(pcm, v.channels, 0)
	ipcmRight := resampler_init_channel(pcm, v.channels, 1)
	if ipcmRight != nil && len(ipcmLeft) != len(ipcmRight) {
		return nil,fmt.Errorf("invalid pcm, L%v!=%v", len(ipcmLeft), len(ipcmRight))
	}

	// Insert the cache at the beginning.
	if v.lcache != nil {
		ipcmLeft = append(v.lcache, ipcmLeft...)
		v.lcache = nil
	}
	if ipcmRight != nil && v.rcache != nil {
		ipcmRight = append(v.rcache, ipcmRight...)
		v.rcache = nil
	}

	// Resample all channels
	var consumed int
	var opcmLeft []int16
	if opcmLeft,consumed,err = resample_channel(ipcmLeft,v.isr,v.osr,v.lws,v.lcs); err != nil {
		return nil,err
	}
	v.lws += uint64(len(opcmLeft))
	v.lcs += uint64(consumed)
	if consumed < len(ipcmLeft) {
		v.lcache = ipcmLeft[consumed:]
	}

	var opcmRight []int16
	if ipcmRight != nil {
		if opcmRight,consumed,err = resample_channel(ipcmRight,v.isr,v.osr,v.rws,v.rcs); err != nil {
			return nil,err
		}
		v.rws += uint64(len(opcmRight))
		v.rcs += uint64(consumed)
		if consumed < len(ipcmRight) {
			v.rcache = ipcmRight[consumed:]
		}
	}

	// Convert int16 samples to bytes.
	npcm = resample_merge(opcmLeft, opcmRight)

	return
}

// merge left and right(can be nil).
func resample_merge(left,right []int16) (npcm []byte) {
	npcm = []byte{}
	for i:=0; i<len(left); i++ {
		v := left[i]
		npcm = append(npcm, byte(v))
		npcm = append(npcm, byte(v >> 8))

		if right != nil {
			v = right[i]
			npcm = append(npcm, byte(v))
			npcm = append(npcm, byte(v >> 8))
		}
	}
	return
}

// x is the position of output pcm
func resample_channel(ipcm []int16, isr,osr int, written,org uint64) (opcm []int16, consumed int, err error) {
	if len(ipcm) <= 16 {
		return nil,0,nil
	}

	// The samples we can use to resample
	available := len(ipcm) - 16
	// The resample step between new samples
	step := float64(isr)/float64(osr)
	// The first position to sample
	x0 := step*float64(written)

	// The position for the last sample.
	last := org + uint64(available)

	// Resample each position from x0
	for x:=x0; x < float64(last); x+=step {
		// Generate xi,yi,xo,yo
		xi0 := float64(uint64(x))
		xi := []float64{xi0, xi0+1, xi0+2, xi0+3}
		yi0 := int(uint64(xi0)-org)
		yi := []float64{float64(ipcm[yi0]),float64(ipcm[yi0+1]),float64(ipcm[yi0+2]),float64(ipcm[yi0+3])}
		xo := []float64{x}
		yo := []float64{0.0}
		if err = spline(xi,yi,xo,yo); err != nil {
			return
		}

		// convert yo
		opcm = append(opcm, int16(yo[0]))
		consumed = int(uint64(x)-org) + 1
	}

	return
}

// resampler_init_channel([]byte{...}, 1, 0)
// resampler_init_channel([]byte{...}, 2, 0)
// resampler_init_channel([]byte{...}, 2, 1)
func resampler_init_channel(pcm []byte, channels, channel int) (ipcm []int16) {
	if channel >= channels {
		return
	}

	ipcm = []int16{}
	for i:=2*channel; i<len(pcm); i+=2*channels {
		// 16bits le sample
		v := (int16(pcm[i])) | (int16(pcm[i + 1]) << 8)
		ipcm = append(ipcm, v)
	}

	return
}

// xi must be [x0, x1, x2, x3] which is [1, 2, 3, 4]
// yi must be [y0, y1, y2, y3] which corresponding to xi
// xo the output insert position of x, must in [x0, x3]
// yo is the inserted value corresponding to xo
// For example:
//		spline([1,2,3,4], [7,9,2,5], [1.5,2.5,3.5], [?,?,?])
// which will fill the yo with values.
func spline(xi,yi,xo,yo []float64) (err error) {
	if len(xi) != 4 {
		return fmt.Errorf("invalid xi")
	}
	if len(yi) != 4 {
		return fmt.Errorf("invalid yi")
	}
	if len(xo) == 0 {
		return fmt.Errorf("invalid xo")
	}
	if len(yo) != len(xo) {
		return fmt.Errorf("invalid yo")
	}

	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]
	y0,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	h0,h1,h2,_,u1,l2,_ := spline_lu(xi)
	c1,c2 := spline_c1(yi,h0,h1), spline_c2(yi,h1, h2)
	m1,m2 := spline_m1(c1,c2,u1,l2), spline_m2(c1,c2,u1,l2) // m0=m3=0

	for k,v := range xo {
		if v <= x1 {
			yo[k] = spline_z0(m1,h0,x0,x1,y0,y1,v)
		} else if v <= x2 {
			yo[k] = spline_z1(m1,m2,h1,x1,x2,y1,y2,v)
		} else {
			yo[k] = spline_z2(m2,h2,x2,x3,y2,y3,v)
		}
	}

	return
}

func spline_z0(m1,h0,x0,x1,y0,y1,x float64) float64 {
	v0 := 0.0
	v1 := (x-x0)*(x-x0)*(x-x0)*m1/(6*h0)
	v2 := -1.0*y0*(x-x1)/h0
	v3 := (y1 - h0*h0*m1/6)*(x-x0)/h0
	return v0+v1+v2+v3
}

func spline_z1(m1,m2,h1,x1,x2,y1,y2,x float64) float64 {
	v0 := -1.0*(x-x2)*(x-x2)*(x-x2)*m1/(6*h1)
	v1 := (x-x1)*(x-x1)*(x-x1)*m2/(6*h1)
	v2 := -1.0*(y1-h1*h1*m1/6)*(x-x2)/h1
	v3 := (y2-h1*h1*m2/6)*(x-x1)/h1
	return v0+v1+v2+v3
}

func spline_z2(m2,h2,x2,x3,y2,y3,x float64) float64 {
	v0 := -1.0*(x-x3)*(x-x3)*(x-x3)*m2/(6*h2)
	v1 := 0.0
	v2 := -1.0*(y2-h2*h2*m2/6)*(x-x3)/h2
	v3 := y3*(x-x2)/h2
	return v0+v1+v2+v3
}

// Calculate M1 form matrix.
func spline_m1(c1,c2,u1,l2 float64) float64 {
	return (c1/u1 - c2/2) / (2/u1 - l2/2)
}

// Calculate M2 form matrix.
func spline_m2(c1,c2,u1,l2 float64) float64 {
	return (c1/2 - c2/l2) / (u1/2 - 2/l2)
}

func spline_c1(yi []float64, h0,h1 float64) float64 {
	y0,y1,y2,_ := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h0 + h1) * ((y2 - y1)/h1 - (y1 - y0)/h0)
}

func spline_c2(yi []float64, h1,h2 float64) float64 {
	_,y1,y2,y3 := yi[0],yi[1],yi[2],yi[3]
	return 6.0 / (h1 + h2) * ((y3-y2)/h2 - (y2-y1)/h1)
}

func spline_lu(xi []float64) (h0,h1,h2,l1,u1,l2,u2 float64) {
	x0,x1,x2,x3 := xi[0],xi[1],xi[2],xi[3]

	h0,h1,h2 = x1-x0,x2-x1,x3-x2

	l1 = h0 / (h1 + h0) // lambada1
	u1 = h1 / (h1 + h0)

	l2 = h1 / (h2 + h1) // lambada2
	u2 = h2 / (h2 + h1)

	return

}
<|endoftext|>


<commit_before>// +build !windows

package plugin

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

	log "github.com/sirupsen/logrus"
)

type logData struct{}

func (p *plug) deinitLogger() error {
	return p.closeLogFile()
}

// initLogger opens and sets a log file on Unix platforms
func (p *plug) initLogger() error {
	pathArray := []string{"var", "log", p.params.Name + ".log"}
	defaultPath := filepath.Join(pathArray...)

	p.l = log.New()
	p.l.Level = p.params.LogLevel

	return p.openLogFile(defaultPath)
}
<commit_msg>Fixes<commit_after>// +build !windows

package plugin

import (
	"path/filepath"

	log "github.com/sirupsen/logrus"
)

type logData struct{}

func (p *plug) deinitLogger() error {
	return p.closeLogFile()
}

// initLogger opens and sets a log file on Unix platforms
func (p *plug) initLogger() error {
	pathArray := []string{"var", "log", p.params.Name + ".log"}
	defaultPath := filepath.Join(pathArray...)

	p.l = log.New()
	p.l.Level = p.params.LogLevel

	return p.openLogFile(defaultPath)
}
<|endoftext|>


<commit_before>package provider

import (
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	fsnotify "gopkg.in/fsnotify.v1"

	"github.com/BurntSushi/toml"
	"github.com/Nitro/sidecar/catalog"
	"github.com/Nitro/sidecar/service"
	"github.com/containous/traefik/log"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
)

const (
	method         = "wrr"
	weight         = 1
	sticky         = false
	circuitBreaker = "ResponseCodeRatio(500, 600, 0, 600) > 0.3"
)

var _ Provider = (*Sidecar)(nil)

// Sidecar holds configurations of the Sidecar provider
type Sidecar struct {
	BaseProvider      `mapstructure:",squash"`
	Endpoint          string `description:"Sidecar URL"`
	Frontend          string `description:"Configuration file for frontend"`
	configurationChan chan<- types.ConfigMessage
	RefreshConn       time.Duration `description:"How often to refresh the connection to Sidecar backend"`
	connTimer         *time.Timer
}

type callback func(map[string][]*service.Service, error)

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Sidecar) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
	provider.configurationChan = configurationChan
	if provider.Watch {
		safe.Go(func() {
			provider.sidecarWatcher()
		})

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Errorln("Error creating file watcher", err)
			return err
		}

		file, err := os.Open(provider.Frontend)
		if err != nil {
			log.Errorln("Error opening file", err)
			return err
		}
		defer file.Close()
		pool.Go(func(stop chan bool) {
			defer watcher.Close()
			for {
				select {
				case <-stop:
					return
				case event := <-watcher.Events:
					if strings.Contains(event.Name, file.Name()) {
						log.Debug("Sidecar Frontend File event:", event)
						states, errState := provider.fetchState()
						if errState != nil {
							log.Errorln("Error reloading Sidecar config", errState)
						}
						provider.loadSidecarConfig(states.ByService())
					}
				case errWatcher := <-watcher.Errors:
					log.Errorln("Watcher event error", errWatcher)
				}
			}
		})
		err = watcher.Add(filepath.Dir(file.Name()))
		if err != nil {
			log.Error("Error adding file watcher", err)
			return err
		}
	}
	states, err := provider.fetchState()
	if err != nil {
		log.Fatalln("Error reloading Sidecar config", err)
	}
	err = provider.loadSidecarConfig(states.ByService())
	if err != nil {
		return err
	}
	return nil
}

func (provider *Sidecar) constructConfig(sidecarStates map[string][]*service.Service) (*types.Configuration, error) {
	log.Infoln("loading sidecar config")
	sidecarConfig := types.Configuration{Backends: provider.makeBackends(sidecarStates)}
	var err error
	sidecarConfig.Frontends, err = provider.makeFrontend()
	if err != nil {
		return nil, err
	}
	return &sidecarConfig, nil
}

func (provider *Sidecar) loadSidecarConfig(sidecarStates map[string][]*service.Service) error {
	conf, err := provider.constructConfig(sidecarStates)
	if err != nil {
		return err
	}
	provider.configurationChan <- types.ConfigMessage{
		ProviderName:  "sidecar",
		Configuration: conf,
	}
	return nil
}

func (provider *Sidecar) sidecarWatcher() error {
	//set timeout to be just a bot more than connection refresh interval
	provider.connTimer = time.NewTimer(provider.RefreshConn * time.Second)
	tr := &http.Transport{ResponseHeaderTimeout: 0}
	client := &http.Client{
		Timeout:   0,
		Transport: tr}
	log.Infof("Using %s Sidecar connection refresh interval", provider.RefreshConn*time.Second)
	provider.recycleConn(client, tr)
	return nil
}

func (provider *Sidecar) recycleConn(client *http.Client, tr *http.Transport) {
	var err error
	var resp *http.Response
	var req *http.Request
	for { //use refresh interval to occasionally reconnect to Sidecar in case the stream connection is lost
		req, err = http.NewRequest("GET", provider.Endpoint+"/watch", nil)
		if err != nil {
			log.Errorf("Error creating http request to Sidecar: %s, Error: %s", provider.Endpoint, err)
			continue
		}
		resp, err = client.Do(req)
		if err != nil {
			log.Errorf("Error connecting to Sidecar: %s, Error: %s", provider.Endpoint, err)
			time.Sleep(5 * time.Second)
			continue
		}
		safe.Go(func() { catalog.DecodeStream(resp.Body, provider.callbackLoader) })

		//wait on refresh connection timer.  If this expires we haven't seen an update in a
		//while and should cancel the request, reset the time, and reconnect just in case
		<-provider.connTimer.C
		provider.connTimer.Reset(provider.RefreshConn * time.Second)
		tr.CancelRequest(req)
	}
}

func (provider *Sidecar) callbackLoader(sidecarStates map[string][]*service.Service, err error) error {
	//load config regardless
	provider.loadSidecarConfig(sidecarStates)

	if err != nil {
		return err
	}
	//else reset connection timer
	if !provider.connTimer.Stop() {
		<-provider.connTimer.C
	}
	provider.connTimer.Reset(provider.RefreshConn * time.Second)
	return nil
}

func (provider *Sidecar) makeFrontend() (map[string]*types.Frontend, error) {
	configuration := new(types.Configuration)
	if _, err := toml.DecodeFile(provider.Frontend, configuration); err != nil {
		log.Errorf("Error reading file: %s", err)
		return nil, err
	}
	return configuration.Frontends, nil
}

func (provider *Sidecar) makeBackends(sidecarStates map[string][]*service.Service) map[string]*types.Backend {
	sidecarBacks := make(map[string]*types.Backend)
	for serviceName, services := range sidecarStates {
		newServers := make(map[string]types.Server)
		newBackend := &types.Backend{LoadBalancer: &types.LoadBalancer{Method: method, Sticky: sticky},
			CircuitBreaker: &types.CircuitBreaker{Expression: circuitBreaker},
			Servers:        newServers}
		for _, serv := range services {
			if serv.IsAlive() {
				for i := 0; i < len(serv.Ports); i++ {
					ipAddr, err := net.LookupIP(serv.Hostname)
					if err != nil {
						log.Errorln("Error resolving Ip address, ", err)
						newBackend.Servers[serv.Hostname] = types.Server{URL: "http://" + serv.Hostname + ":" + strconv.FormatInt(serv.Ports[i].Port, 10)}
					} else {
						newBackend.Servers[serv.Hostname] = types.Server{URL: "http://" + ipAddr[0].String() + ":" + strconv.FormatInt(serv.Ports[i].Port, 10)}
					}
				}
			}
		}
		sidecarBacks[serviceName] = newBackend
	}
	return sidecarBacks
}

func (provider *Sidecar) fetchState() (*catalog.ServicesState, error) {
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Get(provider.Endpoint + "/state.json")
	if err != nil {
		return nil, err
	}

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

	state, err := catalog.Decode(bytes)
	if err != nil {
		return nil, err
	}
	return state, nil
}
<commit_msg>remove callback error return value<commit_after>package provider

import (
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	fsnotify "gopkg.in/fsnotify.v1"

	"github.com/BurntSushi/toml"
	"github.com/Nitro/sidecar/catalog"
	"github.com/Nitro/sidecar/service"
	"github.com/containous/traefik/log"
	"github.com/containous/traefik/safe"
	"github.com/containous/traefik/types"
)

const (
	method         = "wrr"
	weight         = 1
	sticky         = false
	circuitBreaker = "ResponseCodeRatio(500, 600, 0, 600) > 0.3"
)

var _ Provider = (*Sidecar)(nil)

// Sidecar holds configurations of the Sidecar provider
type Sidecar struct {
	BaseProvider      `mapstructure:",squash"`
	Endpoint          string `description:"Sidecar URL"`
	Frontend          string `description:"Configuration file for frontend"`
	configurationChan chan<- types.ConfigMessage
	RefreshConn       time.Duration `description:"How often to refresh the connection to Sidecar backend"`
	connTimer         *time.Timer
}

type callback func(map[string][]*service.Service, error)

// Provide allows the provider to provide configurations to traefik
// using the given configuration channel.
func (provider *Sidecar) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
	provider.configurationChan = configurationChan
	if provider.Watch {
		safe.Go(func() {
			provider.sidecarWatcher()
		})

		watcher, err := fsnotify.NewWatcher()
		if err != nil {
			log.Errorln("Error creating file watcher", err)
			return err
		}

		file, err := os.Open(provider.Frontend)
		if err != nil {
			log.Errorln("Error opening file", err)
			return err
		}
		defer file.Close()
		pool.Go(func(stop chan bool) {
			defer watcher.Close()
			for {
				select {
				case <-stop:
					return
				case event := <-watcher.Events:
					if strings.Contains(event.Name, file.Name()) {
						log.Debug("Sidecar Frontend File event:", event)
						states, errState := provider.fetchState()
						if errState != nil {
							log.Errorln("Error reloading Sidecar config", errState)
						}
						provider.loadSidecarConfig(states.ByService())
					}
				case errWatcher := <-watcher.Errors:
					log.Errorln("Watcher event error", errWatcher)
				}
			}
		})
		err = watcher.Add(filepath.Dir(file.Name()))
		if err != nil {
			log.Error("Error adding file watcher", err)
			return err
		}
	}
	states, err := provider.fetchState()
	if err != nil {
		log.Fatalln("Error reloading Sidecar config", err)
	}
	err = provider.loadSidecarConfig(states.ByService())
	if err != nil {
		return err
	}
	return nil
}

func (provider *Sidecar) constructConfig(sidecarStates map[string][]*service.Service) (*types.Configuration, error) {
	log.Infoln("loading sidecar config")
	sidecarConfig := types.Configuration{Backends: provider.makeBackends(sidecarStates)}
	var err error
	sidecarConfig.Frontends, err = provider.makeFrontend()
	if err != nil {
		return nil, err
	}
	return &sidecarConfig, nil
}

func (provider *Sidecar) loadSidecarConfig(sidecarStates map[string][]*service.Service) error {
	conf, err := provider.constructConfig(sidecarStates)
	if err != nil {
		return err
	}
	provider.configurationChan <- types.ConfigMessage{
		ProviderName:  "sidecar",
		Configuration: conf,
	}
	return nil
}

func (provider *Sidecar) sidecarWatcher() error {
	//set timeout to be just a bot more than connection refresh interval
	provider.connTimer = time.NewTimer(provider.RefreshConn * time.Second)
	tr := &http.Transport{ResponseHeaderTimeout: 0}
	client := &http.Client{
		Timeout:   0,
		Transport: tr}
	log.Infof("Using %s Sidecar connection refresh interval", provider.RefreshConn*time.Second)
	provider.recycleConn(client, tr)
	return nil
}

func (provider *Sidecar) recycleConn(client *http.Client, tr *http.Transport) {
	var err error
	var resp *http.Response
	var req *http.Request
	for { //use refresh interval to occasionally reconnect to Sidecar in case the stream connection is lost
		req, err = http.NewRequest("GET", provider.Endpoint+"/watch", nil)
		if err != nil {
			log.Errorf("Error creating http request to Sidecar: %s, Error: %s", provider.Endpoint, err)
			continue
		}
		resp, err = client.Do(req)
		if err != nil {
			log.Errorf("Error connecting to Sidecar: %s, Error: %s", provider.Endpoint, err)
			time.Sleep(5 * time.Second)
			continue
		}
		safe.Go(func() { catalog.DecodeStream(resp.Body, provider.callbackLoader) })

		//wait on refresh connection timer.  If this expires we haven't seen an update in a
		//while and should cancel the request, reset the time, and reconnect just in case
		<-provider.connTimer.C
		provider.connTimer.Reset(provider.RefreshConn * time.Second)
		tr.CancelRequest(req)
	}
}

func (provider *Sidecar) callbackLoader(sidecarStates map[string][]*service.Service, err error) {
	//load config regardless
	provider.loadSidecarConfig(sidecarStates)

	if err != nil {
		return
	}
	//else reset connection timer
	if !provider.connTimer.Stop() {
		<-provider.connTimer.C
	}
	provider.connTimer.Reset(provider.RefreshConn * time.Second)
	return
}

func (provider *Sidecar) makeFrontend() (map[string]*types.Frontend, error) {
	configuration := new(types.Configuration)
	if _, err := toml.DecodeFile(provider.Frontend, configuration); err != nil {
		log.Errorf("Error reading file: %s", err)
		return nil, err
	}
	return configuration.Frontends, nil
}

func (provider *Sidecar) makeBackends(sidecarStates map[string][]*service.Service) map[string]*types.Backend {
	sidecarBacks := make(map[string]*types.Backend)
	for serviceName, services := range sidecarStates {
		newServers := make(map[string]types.Server)
		newBackend := &types.Backend{LoadBalancer: &types.LoadBalancer{Method: method, Sticky: sticky},
			CircuitBreaker: &types.CircuitBreaker{Expression: circuitBreaker},
			Servers:        newServers}
		for _, serv := range services {
			if serv.IsAlive() {
				for i := 0; i < len(serv.Ports); i++ {
					ipAddr, err := net.LookupIP(serv.Hostname)
					if err != nil {
						log.Errorln("Error resolving Ip address, ", err)
						newBackend.Servers[serv.Hostname] = types.Server{URL: "http://" + serv.Hostname + ":" + strconv.FormatInt(serv.Ports[i].Port, 10)}
					} else {
						newBackend.Servers[serv.Hostname] = types.Server{URL: "http://" + ipAddr[0].String() + ":" + strconv.FormatInt(serv.Ports[i].Port, 10)}
					}
				}
			}
		}
		sidecarBacks[serviceName] = newBackend
	}
	return sidecarBacks
}

func (provider *Sidecar) fetchState() (*catalog.ServicesState, error) {
	client := &http.Client{Timeout: 5 * time.Second}
	resp, err := client.Get(provider.Endpoint + "/state.json")
	if err != nil {
		return nil, err
	}

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

	state, err := catalog.Decode(bytes)
	if err != nil {
		return nil, err
	}
	return state, nil
}
<|endoftext|>


<commit_before>package cache

import (
	"io/ioutil"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

type S3Cache struct {
	cacheBucket string
	s3Client    *s3.S3
}

const (
	TemporaryCacheDir = "/tmp/risu/cache"
)

func NewS3Cache() Cache {
	if os.Getenv("AWS_ACCESS_KEY_ID") == "" || os.Getenv("AWS_SECRET_ACCESS_KEY") == "" {
		// TODO: raise error if AWS credentials are not set
		return nil
	}

	s3Client := s3.New(nil)

	if os.Getenv("RISU_CACHE_BUCKET") == "" {
		// TODO: raise error if RISU_CACHE_BUCKET is not set
		return nil
	}

	cacheBucket := os.Getenv("RISU_CACHE_BUCKET")

	_, err := s3Client.HeadBucket(
		&s3.HeadBucketInput{
			Bucket: aws.String(cacheBucket),
		})

	if err != nil {
		// TODO: raise error if bucket not found
		return nil
	}

	return &S3Cache{cacheBucket, s3Client}
}

func (c *S3Cache) Get(key string) (string, error) {
	temporaryCache := cacheFilePath(DefaultCacheDir, key)
	inflateDir := inflateDirPath(DefaultCacheDir, key)

	_, err := c.s3Client.HeadObject(
		&s3.HeadObjectInput{
			Bucket: aws.String(c.cacheBucket),
			Key:    aws.String(key),
		})

	if err != nil {
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			return "", nil
		}

		return "", err
	}

	resp, err := c.s3Client.GetObject(
		&s3.GetObjectInput{
			Bucket: aws.String(c.cacheBucket),
			Key:    aws.String(key),
		})

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

	defer resp.Body.Close()

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

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

	if err = ioutil.WriteFile(temporaryCache, data, 0644); err != nil {
		return "", err
	}

	if err = InflateTarGz(temporaryCache, inflateDir); err != nil {
		return "", err
	}

	return inflateDir, nil
}

func (c *S3Cache) Put(key, directory string) error {
	temporaryCache := cacheFilePath(DefaultCacheDir, key)

	if err := DeflateTarGz(temporaryCache, directory); err != nil {
		return err
	}

	file, err := os.Open(temporaryCache)

	if err != nil {
		return err
	}
	defer file.Close()

	_, err = c.s3Client.PutObject(
		&s3.PutObjectInput{
			ACL:    aws.String("private"),
			Bucket: aws.String(c.cacheBucket),
			Body:   file,
			Key:    aws.String(key),
		})

	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Require AWS_REGION environment variable<commit_after>package cache

import (
	"io/ioutil"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

type S3Cache struct {
	cacheBucket string
	s3Client    *s3.S3
}

const (
	TemporaryCacheDir = "/tmp/risu/cache"
)

func NewS3Cache() Cache {
	if os.Getenv("AWS_ACCESS_KEY_ID") == "" || os.Getenv("AWS_SECRET_ACCESS_KEY") == "" || os.Getenv("AWS_REGION") == "" {
		// TODO: raise error if AWS credentials are not set
		return nil
	}

	s3Client := s3.New(nil)

	if os.Getenv("RISU_CACHE_BUCKET") == "" {
		// TODO: raise error if RISU_CACHE_BUCKET is not set
		return nil
	}

	cacheBucket := os.Getenv("RISU_CACHE_BUCKET")

	_, err := s3Client.HeadBucket(
		&s3.HeadBucketInput{
			Bucket: aws.String(cacheBucket),
		})

	if err != nil {
		// TODO: raise error if bucket not found
		return nil
	}

	return &S3Cache{cacheBucket, s3Client}
}

func (c *S3Cache) Get(key string) (string, error) {
	temporaryCache := cacheFilePath(DefaultCacheDir, key)
	inflateDir := inflateDirPath(DefaultCacheDir, key)

	_, err := c.s3Client.HeadObject(
		&s3.HeadObjectInput{
			Bucket: aws.String(c.cacheBucket),
			Key:    aws.String(key),
		})

	if err != nil {
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			return "", nil
		}

		return "", err
	}

	resp, err := c.s3Client.GetObject(
		&s3.GetObjectInput{
			Bucket: aws.String(c.cacheBucket),
			Key:    aws.String(key),
		})

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

	defer resp.Body.Close()

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

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

	if err = ioutil.WriteFile(temporaryCache, data, 0644); err != nil {
		return "", err
	}

	if err = InflateTarGz(temporaryCache, inflateDir); err != nil {
		return "", err
	}

	return inflateDir, nil
}

func (c *S3Cache) Put(key, directory string) error {
	temporaryCache := cacheFilePath(DefaultCacheDir, key)

	if err := DeflateTarGz(temporaryCache, directory); err != nil {
		return err
	}

	file, err := os.Open(temporaryCache)

	if err != nil {
		return err
	}
	defer file.Close()

	_, err = c.s3Client.PutObject(
		&s3.PutObjectInput{
			ACL:    aws.String("private"),
			Bucket: aws.String(c.cacheBucket),
			Body:   file,
			Key:    aws.String(key),
		})

	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package cron

import (
	"net/http"

	"github.com/koffeinsource/kaffeeshare/data"
	"google.golang.org/appengine/search"
)

// ClearTest deletes all items in the test namespace
func ClearTest(w http.ResponseWriter, r *http.Request) {
	con := data.MakeContext(r)

	// get namespace
	namespace := "test"

	err := data.ClearNamespace(con, namespace)
	if err != nil {
		con.Log.Errorf("Error while clearing the namespace %v: %v", namespace, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	// TODO clear search index!
	index, err := search.Open("items_" + namespace)
	if err != nil {
		con.Log.Errorf("Error while opening search index item_%v: %v", namespace, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	for t := index.List(con.C, nil); ; {
		id, err := t.Next(nil)
		if err == search.Done {
			break
		}
		if err != nil {
			con.Log.Errorf("Error while deleting items from search index item_%v: %v", namespace, err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		index.Delete(con.C, id)
	}
	w.WriteHeader(http.StatusOK)
}
<commit_msg>Updated cron job that clears the test namespace to use our new search index clear.<commit_after>package cron

import (
	"net/http"

	"github.com/koffeinsource/kaffeeshare/data"
	"github.com/koffeinsource/kaffeeshare/search"
)

// ClearTest deletes all items in the test namespace
func ClearTest(w http.ResponseWriter, r *http.Request) {
	con := data.MakeContext(r)

	// get namespace
	namespace := "test"

	err := data.ClearNamespace(con, namespace)
	if err != nil {
		con.Log.Errorf("Error while clearing the namespace %v: %v", namespace, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	search.ClearSearchItemIndex(con, "test")
	if err != nil {
		con.Log.Errorf("Error while deleting items from search index item_%v: %v", namespace, err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
}
<|endoftext|>