<commit_before>package gorm

import (
	"database/sql"
	"fmt"
	"go/ast"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/qor/inflection"
)

var modelStructs = map[reflect.Type]*ModelStruct{}

var DefaultTableNameHandler = func(db *DB, defaultTableName string) string {
	return defaultTableName
}

type ModelStruct struct {
	PrimaryFields    []*StructField
	StructFields     []*StructField
	ModelType        reflect.Type
	defaultTableName string
}

func (s ModelStruct) TableName(db *DB) string {
	return DefaultTableNameHandler(db, s.defaultTableName)
}

type StructField struct {
	DBName          string
	Name            string
	Names           []string
	IsPrimaryKey    bool
	IsNormal        bool
	IsIgnored       bool
	IsScanner       bool
	HasDefaultValue bool
	Tag             reflect.StructTag
	Struct          reflect.StructField
	IsForeignKey    bool
	Relationship    *Relationship
}

func (structField *StructField) clone() *StructField {
	return &StructField{
		DBName:          structField.DBName,
		Name:            structField.Name,
		Names:           structField.Names,
		IsPrimaryKey:    structField.IsPrimaryKey,
		IsNormal:        structField.IsNormal,
		IsIgnored:       structField.IsIgnored,
		IsScanner:       structField.IsScanner,
		HasDefaultValue: structField.HasDefaultValue,
		Tag:             structField.Tag,
		Struct:          structField.Struct,
		IsForeignKey:    structField.IsForeignKey,
		Relationship:    structField.Relationship,
	}
}

type Relationship struct {
	Kind                               string
	PolymorphicType                    string
	PolymorphicDBName                  string
	ForeignFieldNames                  []string
	ForeignDBNames                     []string
	AssociationForeignFieldNames       []string
	AssociationForeignStructFieldNames []string
	AssociationForeignDBNames          []string
	JoinTableHandler                   JoinTableHandlerInterface
}

func (scope *Scope) GetModelStruct() *ModelStruct {
	var modelStruct ModelStruct

	reflectValue := reflect.Indirect(reflect.ValueOf(scope.Value))
	if !reflectValue.IsValid() {
		return &modelStruct
	}

	if reflectValue.Kind() == reflect.Slice {
		reflectValue = reflect.Indirect(reflect.New(reflectValue.Type().Elem()))
	}

	scopeType := reflectValue.Type()

	if scopeType.Kind() == reflect.Ptr {
		scopeType = scopeType.Elem()
	}

	if value, ok := modelStructs[scopeType]; ok {
		return value
	}

	modelStruct.ModelType = scopeType
	if scopeType.Kind() != reflect.Struct {
		return &modelStruct
	}

	// Set tablename
	type tabler interface {
		TableName() string
	}

	if tabler, ok := reflect.New(scopeType).Interface().(interface {
		TableName() string
	}); ok {
		modelStruct.defaultTableName = tabler.TableName()
	} else {
		name := ToDBName(scopeType.Name())
		if scope.db == nil || !scope.db.parent.singularTable {
			name = inflection.Plural(name)
		}

		modelStruct.defaultTableName = name
	}

	// Get all fields
	fields := []*StructField{}
	for i := 0; i < scopeType.NumField(); i++ {
		if fieldStruct := scopeType.Field(i); ast.IsExported(fieldStruct.Name) {
			field := &StructField{
				Struct: fieldStruct,
				Name:   fieldStruct.Name,
				Names:  []string{fieldStruct.Name},
				Tag:    fieldStruct.Tag,
			}

			if fieldStruct.Tag.Get("sql") == "-" {
				field.IsIgnored = true
			} else {
				sqlSettings := parseTagSetting(field.Tag.Get("sql"))
				gormSettings := parseTagSetting(field.Tag.Get("gorm"))
				if _, ok := gormSettings["PRIMARY_KEY"]; ok {
					field.IsPrimaryKey = true
					modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
				}

				if _, ok := sqlSettings["DEFAULT"]; ok {
					field.HasDefaultValue = true
				}

				if value, ok := gormSettings["COLUMN"]; ok {
					field.DBName = value
				} else {
					field.DBName = ToDBName(fieldStruct.Name)
				}
			}
			fields = append(fields, field)
		}
	}

	defer func() {
		for _, field := range fields {
			if !field.IsIgnored {
				fieldStruct := field.Struct
				indirectType := fieldStruct.Type
				if indirectType.Kind() == reflect.Ptr {
					indirectType = indirectType.Elem()
				}

				if _, isScanner := reflect.New(indirectType).Interface().(sql.Scanner); isScanner {
					field.IsScanner, field.IsNormal = true, true
				}

				if _, isTime := reflect.New(indirectType).Interface().(*time.Time); isTime {
					field.IsNormal = true
				}

				if !field.IsNormal {
					gormSettings := parseTagSetting(field.Tag.Get("gorm"))
					toScope := scope.New(reflect.New(fieldStruct.Type).Interface())

					getForeignField := func(column string, fields []*StructField) *StructField {
						for _, field := range fields {
							if field.Name == column || field.DBName == ToDBName(column) {
								return field
							}
						}
						return nil
					}

					var relationship = &Relationship{}

					if polymorphic := gormSettings["POLYMORPHIC"]; polymorphic != "" {
						if polymorphicField := getForeignField(polymorphic+"Id", toScope.GetStructFields()); polymorphicField != nil {
							if polymorphicType := getForeignField(polymorphic+"Type", toScope.GetStructFields()); polymorphicType != nil {
								relationship.ForeignFieldNames = []string{polymorphicField.Name}
								relationship.ForeignDBNames = []string{polymorphicField.DBName}
								relationship.AssociationForeignFieldNames = []string{scope.PrimaryField().Name}
								relationship.AssociationForeignDBNames = []string{scope.PrimaryField().DBName}
								relationship.PolymorphicType = polymorphicType.Name
								relationship.PolymorphicDBName = polymorphicType.DBName
								polymorphicType.IsForeignKey = true
								polymorphicField.IsForeignKey = true
							}
						}
					}

					var foreignKeys []string
					if foreignKey, ok := gormSettings["FOREIGNKEY"]; ok {
						foreignKeys = append(foreignKeys, foreignKey)
					}
					switch indirectType.Kind() {
					case reflect.Slice:
						elemType := indirectType.Elem()
						if elemType.Kind() == reflect.Ptr {
							elemType = elemType.Elem()
						}

						if elemType.Kind() == reflect.Struct {
							if many2many := gormSettings["MANY2MANY"]; many2many != "" {
								relationship.Kind = "many_to_many"

								// foreign keys
								if len(foreignKeys) == 0 {
									for _, field := range scope.PrimaryFields() {
										foreignKeys = append(foreignKeys, field.DBName)
									}
								}

								for _, foreignKey := range foreignKeys {
									if field, ok := scope.FieldByName(foreignKey); ok {
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, field.DBName)
										joinTableDBName := ToDBName(scopeType.Name()) + "_" + field.DBName
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBName)
									}
								}

								// association foreign keys
								var associationForeignKeys []string
								if foreignKey := gormSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
									associationForeignKeys = []string{gormSettings["ASSOCIATIONFOREIGNKEY"]}
								} else {
									for _, field := range toScope.PrimaryFields() {
										associationForeignKeys = append(associationForeignKeys, field.DBName)
									}
								}

								for _, name := range associationForeignKeys {
									if field, ok := toScope.FieldByName(name); ok {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName)
										relationship.AssociationForeignStructFieldNames = append(relationship.AssociationForeignFieldNames, field.Name)
										joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName)
									}
								}

								joinTableHandler := JoinTableHandler{}
								joinTableHandler.Setup(relationship, many2many, scopeType, elemType)
								relationship.JoinTableHandler = &joinTableHandler
								field.Relationship = relationship
							} else {
								relationship.Kind = "has_many"

								if len(foreignKeys) == 0 {
									for _, field := range scope.PrimaryFields() {
										if foreignField := getForeignField(scopeType.Name()+field.Name, toScope.GetStructFields()); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, field.DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								} else {
									for _, foreignKey := range foreignKeys {
										if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								}

								if len(relationship.ForeignFieldNames) != 0 {
									field.Relationship = relationship
								}
							}
						} else {
							field.IsNormal = true
						}
					case reflect.Struct:
						if _, ok := gormSettings["EMBEDDED"]; ok || fieldStruct.Anonymous {
							for _, toField := range toScope.GetStructFields() {
								toField = toField.clone()
								toField.Names = append([]string{fieldStruct.Name}, toField.Names...)
								modelStruct.StructFields = append(modelStruct.StructFields, toField)
								if toField.IsPrimaryKey {
									modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, toField)
								}
							}
							continue
						} else {
							if len(foreignKeys) == 0 {
								for _, f := range scope.PrimaryFields() {
									if foreignField := getForeignField(modelStruct.ModelType.Name()+f.Name, toScope.GetStructFields()); foreignField != nil {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name)
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName)
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
										foreignField.IsForeignKey = true
									}
								}
							} else {
								for _, foreignKey := range foreignKeys {
									if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name)
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName)
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
										foreignField.IsForeignKey = true
									}
								}
							}

							if len(relationship.ForeignFieldNames) != 0 {
								relationship.Kind = "has_one"
								field.Relationship = relationship
							} else {
								if len(foreignKeys) == 0 {
									for _, f := range toScope.PrimaryFields() {
										if foreignField := getForeignField(field.Name+f.Name, fields); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								} else {
									for _, foreignKey := range foreignKeys {
										if foreignField := getForeignField(foreignKey, fields); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, toScope.PrimaryField().Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, toScope.PrimaryField().DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								}

								if len(relationship.ForeignFieldNames) != 0 {
									relationship.Kind = "belongs_to"
									field.Relationship = relationship
								}
							}
						}
					default:
						field.IsNormal = true
					}
				}

				if field.IsNormal {
					if len(modelStruct.PrimaryFields) == 0 && field.DBName == "id" {
						field.IsPrimaryKey = true
						modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
					}
				}
			}
			modelStruct.StructFields = append(modelStruct.StructFields, field)
		}
	}()

	modelStructs[scopeType] = &modelStruct

	return &modelStruct
}

func (scope *Scope) GetStructFields() (fields []*StructField) {
	return scope.GetModelStruct().StructFields
}

func (scope *Scope) generateSqlTag(field *StructField) string {
	var sqlType string
	structType := field.Struct.Type
	if structType.Kind() == reflect.Ptr {
		structType = structType.Elem()
	}
	reflectValue := reflect.Indirect(reflect.New(structType))
	sqlSettings := parseTagSetting(field.Tag.Get("sql"))

	if value, ok := sqlSettings["TYPE"]; ok {
		sqlType = value
	}

	additionalType := sqlSettings["NOT NULL"] + " " + sqlSettings["UNIQUE"]
	if value, ok := sqlSettings["DEFAULT"]; ok {
		additionalType = additionalType + " DEFAULT " + value
	}

	if field.IsScanner {
		var getScannerValue func(reflect.Value)
		getScannerValue = func(value reflect.Value) {
			reflectValue = value
			if _, isScanner := reflect.New(reflectValue.Type()).Interface().(sql.Scanner); isScanner && reflectValue.Kind() == reflect.Struct {
				getScannerValue(reflectValue.Field(0))
			}
		}
		getScannerValue(reflectValue)
	}

	if sqlType == "" {
		var size = 255

		if value, ok := sqlSettings["SIZE"]; ok {
			size, _ = strconv.Atoi(value)
		}

		_, autoIncrease := sqlSettings["AUTO_INCREMENT"]
		if field.IsPrimaryKey {
			autoIncrease = true
		}

		sqlType = scope.Dialect().SqlTag(reflectValue, size, autoIncrease)
	}

	if strings.TrimSpace(additionalType) == "" {
		return sqlType
	} else {
		return fmt.Sprintf("%v %v", sqlType, additionalType)
	}
}

func parseTagSetting(str string) map[string]string {
	tags := strings.Split(str, ";")
	setting := map[string]string{}
	for _, value := range tags {
		v := strings.Split(value, ":")
		k := strings.TrimSpace(strings.ToUpper(v[0]))
		if len(v) == 2 {
			setting[k] = v[1]
		} else {
			setting[k] = k
		}
	}
	return setting
}
<commit_msg>Add a composite gorm hack to work around auto inc<commit_after>package gorm

import (
	"database/sql"
	"fmt"
	"go/ast"
	"reflect"
	"strconv"
	"strings"
	"time"

	"github.com/qor/inflection"
)

var modelStructs = map[reflect.Type]*ModelStruct{}

var DefaultTableNameHandler = func(db *DB, defaultTableName string) string {
	return defaultTableName
}

type ModelStruct struct {
	PrimaryFields    []*StructField
	StructFields     []*StructField
	ModelType        reflect.Type
	defaultTableName string
}

func (s ModelStruct) TableName(db *DB) string {
	return DefaultTableNameHandler(db, s.defaultTableName)
}

type StructField struct {
	DBName          string
	Name            string
	Names           []string
	IsPrimaryKey    bool
	IsNormal        bool
	IsIgnored       bool
	IsScanner       bool
	HasDefaultValue bool
	Tag             reflect.StructTag
	Struct          reflect.StructField
	IsForeignKey    bool
	Relationship    *Relationship
}

func (structField *StructField) clone() *StructField {
	return &StructField{
		DBName:          structField.DBName,
		Name:            structField.Name,
		Names:           structField.Names,
		IsPrimaryKey:    structField.IsPrimaryKey,
		IsNormal:        structField.IsNormal,
		IsIgnored:       structField.IsIgnored,
		IsScanner:       structField.IsScanner,
		HasDefaultValue: structField.HasDefaultValue,
		Tag:             structField.Tag,
		Struct:          structField.Struct,
		IsForeignKey:    structField.IsForeignKey,
		Relationship:    structField.Relationship,
	}
}

type Relationship struct {
	Kind                               string
	PolymorphicType                    string
	PolymorphicDBName                  string
	ForeignFieldNames                  []string
	ForeignDBNames                     []string
	AssociationForeignFieldNames       []string
	AssociationForeignStructFieldNames []string
	AssociationForeignDBNames          []string
	JoinTableHandler                   JoinTableHandlerInterface
}

func (scope *Scope) GetModelStruct() *ModelStruct {
	var modelStruct ModelStruct

	reflectValue := reflect.Indirect(reflect.ValueOf(scope.Value))
	if !reflectValue.IsValid() {
		return &modelStruct
	}

	if reflectValue.Kind() == reflect.Slice {
		reflectValue = reflect.Indirect(reflect.New(reflectValue.Type().Elem()))
	}

	scopeType := reflectValue.Type()

	if scopeType.Kind() == reflect.Ptr {
		scopeType = scopeType.Elem()
	}

	if value, ok := modelStructs[scopeType]; ok {
		return value
	}

	modelStruct.ModelType = scopeType
	if scopeType.Kind() != reflect.Struct {
		return &modelStruct
	}

	// Set tablename
	type tabler interface {
		TableName() string
	}

	if tabler, ok := reflect.New(scopeType).Interface().(interface {
		TableName() string
	}); ok {
		modelStruct.defaultTableName = tabler.TableName()
	} else {
		name := ToDBName(scopeType.Name())
		if scope.db == nil || !scope.db.parent.singularTable {
			name = inflection.Plural(name)
		}

		modelStruct.defaultTableName = name
	}

	// Get all fields
	fields := []*StructField{}
	for i := 0; i < scopeType.NumField(); i++ {
		if fieldStruct := scopeType.Field(i); ast.IsExported(fieldStruct.Name) {
			field := &StructField{
				Struct: fieldStruct,
				Name:   fieldStruct.Name,
				Names:  []string{fieldStruct.Name},
				Tag:    fieldStruct.Tag,
			}

			if fieldStruct.Tag.Get("sql") == "-" {
				field.IsIgnored = true
			} else {
				sqlSettings := parseTagSetting(field.Tag.Get("sql"))
				gormSettings := parseTagSetting(field.Tag.Get("gorm"))
				if _, ok := gormSettings["PRIMARY_KEY"]; ok {
					field.IsPrimaryKey = true
					modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
				}

				if _, ok := sqlSettings["DEFAULT"]; ok {
					field.HasDefaultValue = true
				}

				if value, ok := gormSettings["COLUMN"]; ok {
					field.DBName = value
				} else {
					field.DBName = ToDBName(fieldStruct.Name)
				}
			}
			fields = append(fields, field)
		}
	}

	defer func() {
		for _, field := range fields {
			if !field.IsIgnored {
				fieldStruct := field.Struct
				indirectType := fieldStruct.Type
				if indirectType.Kind() == reflect.Ptr {
					indirectType = indirectType.Elem()
				}

				if _, isScanner := reflect.New(indirectType).Interface().(sql.Scanner); isScanner {
					field.IsScanner, field.IsNormal = true, true
				}

				if _, isTime := reflect.New(indirectType).Interface().(*time.Time); isTime {
					field.IsNormal = true
				}

				if !field.IsNormal {
					gormSettings := parseTagSetting(field.Tag.Get("gorm"))
					toScope := scope.New(reflect.New(fieldStruct.Type).Interface())

					getForeignField := func(column string, fields []*StructField) *StructField {
						for _, field := range fields {
							if field.Name == column || field.DBName == ToDBName(column) {
								return field
							}
						}
						return nil
					}

					var relationship = &Relationship{}

					if polymorphic := gormSettings["POLYMORPHIC"]; polymorphic != "" {
						if polymorphicField := getForeignField(polymorphic+"Id", toScope.GetStructFields()); polymorphicField != nil {
							if polymorphicType := getForeignField(polymorphic+"Type", toScope.GetStructFields()); polymorphicType != nil {
								relationship.ForeignFieldNames = []string{polymorphicField.Name}
								relationship.ForeignDBNames = []string{polymorphicField.DBName}
								relationship.AssociationForeignFieldNames = []string{scope.PrimaryField().Name}
								relationship.AssociationForeignDBNames = []string{scope.PrimaryField().DBName}
								relationship.PolymorphicType = polymorphicType.Name
								relationship.PolymorphicDBName = polymorphicType.DBName
								polymorphicType.IsForeignKey = true
								polymorphicField.IsForeignKey = true
							}
						}
					}

					var foreignKeys []string
					if foreignKey, ok := gormSettings["FOREIGNKEY"]; ok {
						foreignKeys = append(foreignKeys, foreignKey)
					}
					switch indirectType.Kind() {
					case reflect.Slice:
						elemType := indirectType.Elem()
						if elemType.Kind() == reflect.Ptr {
							elemType = elemType.Elem()
						}

						if elemType.Kind() == reflect.Struct {
							if many2many := gormSettings["MANY2MANY"]; many2many != "" {
								relationship.Kind = "many_to_many"

								// foreign keys
								if len(foreignKeys) == 0 {
									for _, field := range scope.PrimaryFields() {
										foreignKeys = append(foreignKeys, field.DBName)
									}
								}

								for _, foreignKey := range foreignKeys {
									if field, ok := scope.FieldByName(foreignKey); ok {
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, field.DBName)
										joinTableDBName := ToDBName(scopeType.Name()) + "_" + field.DBName
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBName)
									}
								}

								// association foreign keys
								var associationForeignKeys []string
								if foreignKey := gormSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
									associationForeignKeys = []string{gormSettings["ASSOCIATIONFOREIGNKEY"]}
								} else {
									for _, field := range toScope.PrimaryFields() {
										associationForeignKeys = append(associationForeignKeys, field.DBName)
									}
								}

								for _, name := range associationForeignKeys {
									if field, ok := toScope.FieldByName(name); ok {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName)
										relationship.AssociationForeignStructFieldNames = append(relationship.AssociationForeignFieldNames, field.Name)
										joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName)
									}
								}

								joinTableHandler := JoinTableHandler{}
								joinTableHandler.Setup(relationship, many2many, scopeType, elemType)
								relationship.JoinTableHandler = &joinTableHandler
								field.Relationship = relationship
							} else {
								relationship.Kind = "has_many"

								if len(foreignKeys) == 0 {
									for _, field := range scope.PrimaryFields() {
										if foreignField := getForeignField(scopeType.Name()+field.Name, toScope.GetStructFields()); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, field.DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								} else {
									for _, foreignKey := range foreignKeys {
										if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								}

								if len(relationship.ForeignFieldNames) != 0 {
									field.Relationship = relationship
								}
							}
						} else {
							field.IsNormal = true
						}
					case reflect.Struct:
						if _, ok := gormSettings["EMBEDDED"]; ok || fieldStruct.Anonymous {
							for _, toField := range toScope.GetStructFields() {
								toField = toField.clone()
								toField.Names = append([]string{fieldStruct.Name}, toField.Names...)
								modelStruct.StructFields = append(modelStruct.StructFields, toField)
								if toField.IsPrimaryKey {
									modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, toField)
								}
							}
							continue
						} else {
							if len(foreignKeys) == 0 {
								for _, f := range scope.PrimaryFields() {
									if foreignField := getForeignField(modelStruct.ModelType.Name()+f.Name, toScope.GetStructFields()); foreignField != nil {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name)
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName)
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
										foreignField.IsForeignKey = true
									}
								}
							} else {
								for _, foreignKey := range foreignKeys {
									if foreignField := getForeignField(foreignKey, toScope.GetStructFields()); foreignField != nil {
										relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, scope.PrimaryField().Name)
										relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, scope.PrimaryField().DBName)
										relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
										relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
										foreignField.IsForeignKey = true
									}
								}
							}

							if len(relationship.ForeignFieldNames) != 0 {
								relationship.Kind = "has_one"
								field.Relationship = relationship
							} else {
								if len(foreignKeys) == 0 {
									for _, f := range toScope.PrimaryFields() {
										if foreignField := getForeignField(field.Name+f.Name, fields); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, f.Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, f.DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								} else {
									for _, foreignKey := range foreignKeys {
										if foreignField := getForeignField(foreignKey, fields); foreignField != nil {
											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, toScope.PrimaryField().Name)
											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, toScope.PrimaryField().DBName)
											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.Name)
											relationship.ForeignDBNames = append(relationship.ForeignDBNames, foreignField.DBName)
											foreignField.IsForeignKey = true
										}
									}
								}

								if len(relationship.ForeignFieldNames) != 0 {
									relationship.Kind = "belongs_to"
									field.Relationship = relationship
								}
							}
						}
					default:
						field.IsNormal = true
					}
				}

				if field.IsNormal {
					if len(modelStruct.PrimaryFields) == 0 && field.DBName == "id" {
						field.IsPrimaryKey = true
						modelStruct.PrimaryFields = append(modelStruct.PrimaryFields, field)
					}
				}
			}
			modelStruct.StructFields = append(modelStruct.StructFields, field)
		}
	}()

	modelStructs[scopeType] = &modelStruct

	return &modelStruct
}

func (scope *Scope) GetStructFields() (fields []*StructField) {
	return scope.GetModelStruct().StructFields
}

func (scope *Scope) generateSqlTag(field *StructField) string {
	var sqlType string
	structType := field.Struct.Type
	if structType.Kind() == reflect.Ptr {
		structType = structType.Elem()
	}
	reflectValue := reflect.Indirect(reflect.New(structType))
	sqlSettings := parseTagSetting(field.Tag.Get("sql"))

	if value, ok := sqlSettings["TYPE"]; ok {
		sqlType = value
	}

	additionalType := sqlSettings["NOT NULL"] + " " + sqlSettings["UNIQUE"]
	if value, ok := sqlSettings["DEFAULT"]; ok {
		additionalType = additionalType + " DEFAULT " + value
	}

	if field.IsScanner {
		var getScannerValue func(reflect.Value)
		getScannerValue = func(value reflect.Value) {
			reflectValue = value
			if _, isScanner := reflect.New(reflectValue.Type()).Interface().(sql.Scanner); isScanner && reflectValue.Kind() == reflect.Struct {
				getScannerValue(reflectValue.Field(0))
			}
		}
		getScannerValue(reflectValue)
	}

	if sqlType == "" {
		var size = 255

		if value, ok := sqlSettings["SIZE"]; ok {
			size, _ = strconv.Atoi(value)
		}

		_, autoIncrease := sqlSettings["AUTO_INCREMENT"]
		if field.IsPrimaryKey {
			autoIncrease = true
		}

		gormSettings := parseTagSetting(field.Tag.Get("gorm"))
		_, composite := gormSettings["COMPOSITE"]
		if composite {
			autoIncrease = false
		}

		sqlType = scope.Dialect().SqlTag(reflectValue, size, autoIncrease)
	}

	if strings.TrimSpace(additionalType) == "" {
		return sqlType
	} else {
		return fmt.Sprintf("%v %v", sqlType, additionalType)
	}
}

func parseTagSetting(str string) map[string]string {
	tags := strings.Split(str, ";")
	setting := map[string]string{}
	for _, value := range tags {
		v := strings.Split(value, ":")
		k := strings.TrimSpace(strings.ToUpper(v[0]))
		if len(v) == 2 {
			setting[k] = v[1]
		} else {
			setting[k] = k
		}
	}
	return setting
}
<|endoftext|>


<commit_before>package wsHub

import ()

//Central communitaion struct
type WsHub struct {
	// Registered connections.
	connections map[*Client]bool

	// Inbound messages from the connections.
	broadcast chan []byte

	// Register requests from the connections.
	register chan *Client

	// Unregister requests from connections.
	unregister chan *Client

	kill chan bool
}

//Create new hub
func NewHub() WsHub {
	h := WsHub{
		broadcast:   make(chan []byte),
		register:    make(chan *Client),
		unregister:  make(chan *Client),
		connections: make(map[*Client]bool),
	}

	return h
}

// Run the hub (most likely in its own goroutine)
// Handles all communitaion between connected clients
func (h *WsHub) Run() {
	for {
		select {
		case c := <-h.register:
			h.connections[c] = true
		case c := <-h.unregister:
			delete(h.connections, c)
			close(c.send)
		case m := <-h.broadcast:
			for c := range h.connections {
				select {
				case c.send <- m:
				default:
					delete(h.connections, c)
					close(c.send)
					go c.ws.Close()
				}
			}
		case <-h.kill:
			break
		}
	}
}

// Kill the running hub
func (h *WsHub) Stop() {
	h.kill <- true
}

//Register a given client object
func (h *WsHub) RegisterClient(c *Client) {
	h.register <- c
	go c.runner()
	defer func() { h.unregister <- c }()
}
<commit_msg>Forgot to remove old refs to client.runner (removed)<commit_after>package wsHub

import ()

//Central communitaion struct
type WsHub struct {
	// Registered connections.
	connections map[*Client]bool

	// Inbound messages from the connections.
	broadcast chan []byte

	// Register requests from the connections.
	register chan *Client

	// Unregister requests from connections.
	unregister chan *Client

	kill chan bool
}

//Create new hub
func NewHub() WsHub {
	h := WsHub{
		broadcast:   make(chan []byte),
		register:    make(chan *Client),
		unregister:  make(chan *Client),
		connections: make(map[*Client]bool),
	}

	return h
}

// Run the hub (most likely in its own goroutine)
// Handles all communitaion between connected clients
func (h *WsHub) Run() {
	for {
		select {
		case c := <-h.register:
			h.connections[c] = true
		case c := <-h.unregister:
			delete(h.connections, c)
			close(c.send)
		case m := <-h.broadcast:
			for c := range h.connections {
				select {
				case c.send <- m:
				default:
					delete(h.connections, c)
					close(c.send)
					go c.ws.Close()
				}
			}
		case <-h.kill:
			break
		}
	}
}

// Kill the running hub
func (h *WsHub) Stop() {
	h.kill <- true
}

//Register a given client object
func (h *WsHub) RegisterClient(c *Client) {
	h.register <- c
	defer func() { h.unregister <- c }()
}
<|endoftext|>


<commit_before>package scWriter

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

	"github.com/dh1tw/gosamplerate"
	"github.com/dh1tw/remoteAudio/audio"
	pa "github.com/gordonklaus/portaudio"
	ringBuffer "github.com/zfjagann/golang-ring"
)

// ScWriter implements the audio.Sink interface and is used to write (play)
// audio on a local audio output device (e.g. speakers).
type ScWriter struct {
	sync.RWMutex
	options    Options
	deviceInfo *pa.DeviceInfo
	stream     *pa.Stream
	ring       ringBuffer.Ring
	stash      []float32
	volume     float32
	src        src
}

// src contains a samplerate converter and its needed variables
type src struct {
	gosamplerate.Src
	samplerate float64
	ratio      float64
}

// NewScWriter returns a new soundcard writer for a specific audio output
// device. This is typically a speaker or a pair of headphones.
func NewScWriter(opts ...Option) (*ScWriter, error) {

	if err := pa.Initialize(); err != nil {
		return nil, err
	}

	info, err := pa.DefaultOutputDevice()
	if err != nil {
		return nil, err
	}

	w := &ScWriter{
		options: Options{
			DeviceName:      "default",
			Channels:        2,
			Samplerate:      48000,
			FramesPerBuffer: 480,
			RingBufferSize:  10,
			Latency:         time.Millisecond * 10,
		},
		deviceInfo: info,
		ring:       ringBuffer.Ring{},
		volume:     1.0,
	}

	for _, option := range opts {
		option(&w.options)
	}

	// setup a samplerate converter
	srConv, err := gosamplerate.New(gosamplerate.SRC_SINC_FASTEST, w.options.Channels, 65536)
	if err != nil {
		return nil, fmt.Errorf("player: %v", err)
	}

	w.src = src{
		Src:        srConv,
		samplerate: w.options.Samplerate,
		ratio:      1,
	}

	// select Playback Audio Device
	if w.options.DeviceName != "default" {
		device, err := getPaDevice(w.options.DeviceName)
		if err != nil {
			return nil, err
		}
		w.deviceInfo = device
	}

	// setup Audio Stream
	streamDeviceParam := pa.StreamDeviceParameters{
		Device:   w.deviceInfo,
		Channels: w.options.Channels,
		Latency:  w.options.Latency,
	}

	streamParm := pa.StreamParameters{
		FramesPerBuffer: w.options.FramesPerBuffer,
		Output:          streamDeviceParam,
		SampleRate:      w.options.Samplerate,
	}

	// setup ring buffer
	w.ring.SetCapacity(w.options.RingBufferSize)

	stream, err := pa.OpenStream(streamParm, w.playCb)
	if err != nil {
		return nil,
			fmt.Errorf("unable to open playback audio stream on device %s: %s",
				w.options.DeviceName, err)
	}

	w.stream = stream

	return w, nil
}

// portaudio callback which will be called continously when the stream is
// started; this function should be short and never block
func (p *ScWriter) playCb(in []float32,
	iTime pa.StreamCallbackTimeInfo,
	iFlags pa.StreamCallbackFlags) {
	switch iFlags {
	case pa.OutputUnderflow:
		log.Println("Output Underflow")
		return // move on!
	case pa.OutputOverflow:
		log.Println("Output Overflow")
		return // move on!
	}

	//pull data from Ringbuffer
	p.Lock()
	data := p.ring.Dequeue()
	p.Unlock()

	if data == nil {
		// fill with silence
		for i := 0; i < len(in); i++ {
			in[i] = 0
		}
		return
	}

	audioData := data.([]float32)

	// should never happen
	if len(audioData) != len(in) {
		log.Printf("unable to play audio frame; expected frame size %d, but got %d",
			len(in), len(audioData))
		return
	}

	//copy data into buffer
	copy(in, audioData)
}

// Start starts streaming audio to the Soundcard output device (e.g. Speaker).
func (p *ScWriter) Start() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	return p.stream.Start()
}

// Stop stops streaming audio.
func (p *ScWriter) Stop() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	return p.stream.Stop()
}

// Close shutsdown properly the soundcard audio device.
func (p *ScWriter) Close() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	p.stream.Abort()
	p.stream.Stop()
	return nil
}

// SetVolume sets the volume for all upcoming audio frames.
func (p *ScWriter) SetVolume(v float32) {
	p.Lock()
	defer p.Unlock()
	if v < 0 {
		p.volume = 0
		return
	}
	p.volume = v
}

// Volume returns the current volume.
func (p *ScWriter) Volume() float32 {
	p.RLock()
	defer p.RUnlock()
	return p.volume
}

// Write converts the frames in the audio buffer into the right format
// and queues them into a ring buffer for playing on the speaker. The token is
// used to indicate if the calling application has to wait before it can
// enqueue the next buffer.
func (p *ScWriter) Write(msg audio.Msg, token audio.Token) error {

	var aData []float32
	var err error

	// if necessary adjust the amount of audio channels
	if msg.Channels != p.options.Channels {
		aData = audio.AdjustChannels(msg.Channels, p.options.Channels, msg.Data)
	} else {
		aData = msg.Data
	}

	// if necessary, resample the audio
	if msg.Samplerate != p.options.Samplerate {
		if p.src.samplerate != msg.Samplerate {
			p.src.Reset()
			p.src.samplerate = msg.Samplerate
			p.src.ratio = p.options.Samplerate / msg.Samplerate
		}
		aData, err = p.src.Process(aData, p.src.ratio, false)
		if err != nil {
			return err
		}
	}

	// audio buffer size we want to write into our ring buffer
	// (size expected by portaudio callback)
	expBufferSize := p.options.FramesPerBuffer * p.options.Channels

	// if there is data stashed from previous calles, get it and prepend it
	// to the data received
	if len(p.stash) > 0 {
		aData = append(p.stash, aData...)
		p.stash = p.stash[:0] // empty
	}

	if msg.EOF {
		// get the stuff from the stash
		fmt.Println("EOF!!!")
		fmt.Println("stash size:", len(p.stash))
	}

	// if the audio buffer size is actually smaller than the one we need,
	// then stash it for the next time and return
	if len(aData) < expBufferSize {
		p.stash = aData
		return nil
	}

	// slice of audio buffers which will be enqueued into the ring buffer
	var bData [][]float32

	p.Lock()
	bufCap := p.ring.Capacity()
	bufAvail := bufCap - p.ring.Length()
	p.Unlock()

	// if the aData contains multiples of the expected buffer size,
	// then we chop it into (several) buffers
	if len(aData) >= expBufferSize {
		p.Lock()
		vol := p.volume
		p.Unlock()

		for len(aData) >= expBufferSize {
			if vol != 1 {
				// if necessary, adjust the volume
				audio.AdjustVolume(vol, aData[:expBufferSize])
			}
			bData = append(bData, aData[:expBufferSize])
			aData = aData[expBufferSize:]
		}
	}

	// stash the left over
	if len(aData) > 0 {
		p.stash = aData
	}

	// if the msg originates from a stream, we ignore the next statement
	// and move on (which could mean that we overwrite data in the
	// ring buffer - but thats OK to keep latency low)

	// in case we don't have a stream (e.g. writing from a file) and the
	// ring buffer might be full, we have to wait until there is some
	// space available again in the ring buffer
	if !msg.IsStream && bufAvail <= len(bData) {

		token.Add(1)

		go func() {
			for len(bData) > 0 {

				// wait until there is enough space in the ring buffer,
				// or at least 1/2 of the ring buffer is empty again

				for !(bufAvail >= len(bData) || bufAvail >= bufCap/2) {
					time.Sleep(time.Millisecond * 10)
					p.Lock()
					bufAvail = bufCap - p.ring.Length()
					p.Unlock()
				}

				// now we have the space
				p.Lock()
				counter := 0
				for _, frame := range bData {
					p.ring.Enqueue(frame)
					counter++

					bufAvail = bufCap - p.ring.Length()
					if bufAvail == 0 {
						break
					}
				}
				// remove the frames which were enqueued
				bData = bData[counter:]

				// update the available space
				bufAvail = bufCap - p.ring.Length()
				p.Unlock()
			}

			token.Done()
		}()
		return nil
	}

	p.enqueue(bData, msg.EOF)

	return nil
}

func (p *ScWriter) enqueue(bData [][]float32, EOF bool) {
	p.Lock()
	defer p.Unlock()
	for _, frame := range bData {
		p.ring.Enqueue(frame)
	}
}

// Flush clears all internal buffers
func (p *ScWriter) Flush() {
	p.Lock()
	defer p.Unlock()

	// delete the stash
	p.stash = []float32{}

	p.ring = ringBuffer.Ring{}
	p.ring.SetCapacity(p.options.RingBufferSize)
}

// getPaDevice checks if the Audio Devices actually exist and
// then returns it
func getPaDevice(name string) (*pa.DeviceInfo, error) {
	devices, _ := pa.Devices()
	for _, device := range devices {
		if device.Name == name {
			return device, nil
		}
	}
	return nil, fmt.Errorf("unknown audio device %s", name)
}
<commit_msg>changed to own fork of ring buffer<commit_after>package scWriter

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

	ringBuffer "github.com/dh1tw/golang-ring"
	"github.com/dh1tw/gosamplerate"
	"github.com/dh1tw/remoteAudio/audio"
	pa "github.com/gordonklaus/portaudio"
)

// ScWriter implements the audio.Sink interface and is used to write (play)
// audio on a local audio output device (e.g. speakers).
type ScWriter struct {
	sync.RWMutex
	options    Options
	deviceInfo *pa.DeviceInfo
	stream     *pa.Stream
	ring       ringBuffer.Ring
	stash      []float32
	volume     float32
	src        src
}

// src contains a samplerate converter and its needed variables
type src struct {
	gosamplerate.Src
	samplerate float64
	ratio      float64
}

// NewScWriter returns a new soundcard writer for a specific audio output
// device. This is typically a speaker or a pair of headphones.
func NewScWriter(opts ...Option) (*ScWriter, error) {

	if err := pa.Initialize(); err != nil {
		return nil, err
	}

	info, err := pa.DefaultOutputDevice()
	if err != nil {
		return nil, err
	}

	w := &ScWriter{
		options: Options{
			DeviceName:      "default",
			Channels:        2,
			Samplerate:      48000,
			FramesPerBuffer: 480,
			RingBufferSize:  10,
			Latency:         time.Millisecond * 10,
		},
		deviceInfo: info,
		ring:       ringBuffer.Ring{},
		volume:     1.0,
	}

	for _, option := range opts {
		option(&w.options)
	}

	// setup a samplerate converter
	srConv, err := gosamplerate.New(gosamplerate.SRC_SINC_FASTEST, w.options.Channels, 65536)
	if err != nil {
		return nil, fmt.Errorf("player: %v", err)
	}

	w.src = src{
		Src:        srConv,
		samplerate: w.options.Samplerate,
		ratio:      1,
	}

	// select Playback Audio Device
	if w.options.DeviceName != "default" {
		device, err := getPaDevice(w.options.DeviceName)
		if err != nil {
			return nil, err
		}
		w.deviceInfo = device
	}

	// setup Audio Stream
	streamDeviceParam := pa.StreamDeviceParameters{
		Device:   w.deviceInfo,
		Channels: w.options.Channels,
		Latency:  w.options.Latency,
	}

	streamParm := pa.StreamParameters{
		FramesPerBuffer: w.options.FramesPerBuffer,
		Output:          streamDeviceParam,
		SampleRate:      w.options.Samplerate,
	}

	// setup ring buffer
	w.ring.SetCapacity(w.options.RingBufferSize)

	stream, err := pa.OpenStream(streamParm, w.playCb)
	if err != nil {
		return nil,
			fmt.Errorf("unable to open playback audio stream on device %s: %s",
				w.options.DeviceName, err)
	}

	w.stream = stream

	return w, nil
}

// portaudio callback which will be called continously when the stream is
// started; this function should be short and never block
func (p *ScWriter) playCb(in []float32,
	iTime pa.StreamCallbackTimeInfo,
	iFlags pa.StreamCallbackFlags) {
	switch iFlags {
	case pa.OutputUnderflow:
		log.Println("Output Underflow")
		return // move on!
	case pa.OutputOverflow:
		log.Println("Output Overflow")
		return // move on!
	}

	//pull data from Ringbuffer
	p.Lock()
	data := p.ring.Dequeue()
	p.Unlock()

	if data == nil {
		// fill with silence
		for i := 0; i < len(in); i++ {
			in[i] = 0
		}
		return
	}

	audioData := data.([]float32)

	// should never happen
	if len(audioData) != len(in) {
		log.Printf("unable to play audio frame; expected frame size %d, but got %d",
			len(in), len(audioData))
		return
	}

	//copy data into buffer
	copy(in, audioData)
}

// Start starts streaming audio to the Soundcard output device (e.g. Speaker).
func (p *ScWriter) Start() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	return p.stream.Start()
}

// Stop stops streaming audio.
func (p *ScWriter) Stop() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	return p.stream.Stop()
}

// Close shutsdown properly the soundcard audio device.
func (p *ScWriter) Close() error {
	if p.stream == nil {
		return fmt.Errorf("portaudio stream not initialized")
	}
	p.stream.Abort()
	p.stream.Stop()
	return nil
}

// SetVolume sets the volume for all upcoming audio frames.
func (p *ScWriter) SetVolume(v float32) {
	p.Lock()
	defer p.Unlock()
	if v < 0 {
		p.volume = 0
		return
	}
	p.volume = v
}

// Volume returns the current volume.
func (p *ScWriter) Volume() float32 {
	p.RLock()
	defer p.RUnlock()
	return p.volume
}

// Write converts the frames in the audio buffer into the right format
// and queues them into a ring buffer for playing on the speaker. The token is
// used to indicate if the calling application has to wait before it can
// enqueue the next buffer.
func (p *ScWriter) Write(msg audio.Msg, token audio.Token) error {

	var aData []float32
	var err error

	// if necessary adjust the amount of audio channels
	if msg.Channels != p.options.Channels {
		aData = audio.AdjustChannels(msg.Channels, p.options.Channels, msg.Data)
	} else {
		aData = msg.Data
	}

	// if necessary, resample the audio
	if msg.Samplerate != p.options.Samplerate {
		if p.src.samplerate != msg.Samplerate {
			p.src.Reset()
			p.src.samplerate = msg.Samplerate
			p.src.ratio = p.options.Samplerate / msg.Samplerate
		}
		aData, err = p.src.Process(aData, p.src.ratio, false)
		if err != nil {
			return err
		}
	}

	// audio buffer size we want to write into our ring buffer
	// (size expected by portaudio callback)
	expBufferSize := p.options.FramesPerBuffer * p.options.Channels

	// if there is data stashed from previous calles, get it and prepend it
	// to the data received
	if len(p.stash) > 0 {
		aData = append(p.stash, aData...)
		p.stash = p.stash[:0] // empty
	}

	if msg.EOF {
		// get the stuff from the stash
		fmt.Println("EOF!!!")
		fmt.Println("stash size:", len(p.stash))
	}

	// if the audio buffer size is actually smaller than the one we need,
	// then stash it for the next time and return
	if len(aData) < expBufferSize {
		p.stash = aData
		return nil
	}

	// slice of audio buffers which will be enqueued into the ring buffer
	var bData [][]float32

	p.Lock()
	bufCap := p.ring.Capacity()
	bufAvail := bufCap - p.ring.Length()
	p.Unlock()

	// if the aData contains multiples of the expected buffer size,
	// then we chop it into (several) buffers
	if len(aData) >= expBufferSize {
		p.Lock()
		vol := p.volume
		p.Unlock()

		for len(aData) >= expBufferSize {
			if vol != 1 {
				// if necessary, adjust the volume
				audio.AdjustVolume(vol, aData[:expBufferSize])
			}
			bData = append(bData, aData[:expBufferSize])
			aData = aData[expBufferSize:]
		}
	}

	// stash the left over
	if len(aData) > 0 {
		p.stash = aData
	}

	// if the msg originates from a stream, we ignore the next statement
	// and move on (which could mean that we overwrite data in the
	// ring buffer - but thats OK to keep latency low)

	// in case we don't have a stream (e.g. writing from a file) and the
	// ring buffer might be full, we have to wait until there is some
	// space available again in the ring buffer
	if !msg.IsStream && bufAvail <= len(bData) {

		token.Add(1)

		go func() {
			for len(bData) > 0 {

				// wait until there is enough space in the ring buffer,
				// or at least 1/2 of the ring buffer is empty again

				for !(bufAvail >= len(bData) || bufAvail >= bufCap/2) {
					time.Sleep(time.Millisecond * 10)
					p.Lock()
					bufAvail = bufCap - p.ring.Length()
					p.Unlock()
				}

				// now we have the space
				p.Lock()
				counter := 0
				for _, frame := range bData {
					p.ring.Enqueue(frame)
					counter++

					bufAvail = bufCap - p.ring.Length()
					if bufAvail == 0 {
						break
					}
				}
				// remove the frames which were enqueued
				bData = bData[counter:]

				// update the available space
				bufAvail = bufCap - p.ring.Length()
				p.Unlock()
			}

			token.Done()
		}()
		return nil
	}

	p.enqueue(bData, msg.EOF)

	return nil
}

func (p *ScWriter) enqueue(bData [][]float32, EOF bool) {
	p.Lock()
	defer p.Unlock()
	for _, frame := range bData {
		p.ring.Enqueue(frame)
	}
}

// Flush clears all internal buffers
func (p *ScWriter) Flush() {
	p.Lock()
	defer p.Unlock()

	// delete the stash
	p.stash = []float32{}

	p.ring = ringBuffer.Ring{}
	p.ring.SetCapacity(p.options.RingBufferSize)
}

// getPaDevice checks if the Audio Devices actually exist and
// then returns it
func getPaDevice(name string) (*pa.DeviceInfo, error) {
	devices, _ := pa.Devices()
	for _, device := range devices {
		if device.Name == name {
			return device, nil
		}
	}
	return nil, fmt.Errorf("unknown audio device %s", name)
}
<|endoftext|>


<commit_before>package testflight_test

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"text/template"
	"time"

	"github.com/cloudfoundry-incubator/garden/warden"
	"github.com/concourse/atc/postgresrunner"
	"github.com/concourse/testflight/gardenrunner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

var (
	externalAddress string
	gardenBinPath   string
	helperRootfs    string

	builtComponents map[string]string

	atcDir              string
	atcPipelineFilePath string
	atcRunner           ifrit.Runner

	postgresRunner postgresrunner.Runner

	plumbing     ifrit.Process
	gardenClient warden.Client

	atcProcess ifrit.Process
)

var _ = SynchronizedBeforeSuite(func() []byte {
	gardenBinPath = os.Getenv("GARDEN_BINPATH")
	Ω(gardenBinPath).ShouldNot(BeEmpty(), "must provide $GARDEN_BINPATH")

	turbineBin, err := gexec.Build("github.com/concourse/turbine", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	atcBin, err := gexec.Build("github.com/concourse/atc", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	flyBin, err := gexec.Build("github.com/concourse/fly", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	gardenLinuxBin, err := buildWithGodeps("github.com/cloudfoundry-incubator/garden-linux", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	components, err := json.Marshal(map[string]string{
		"turbine":      turbineBin,
		"atc":          atcBin,
		"fly":          flyBin,
		"garden-linux": gardenLinuxBin,
	})
	Ω(err).ShouldNot(HaveOccurred())

	return components
}, func(components []byte) {
	err := json.Unmarshal(components, &builtComponents)
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	atcDir = os.Getenv("ATC_DIR")
	Ω(atcDir).ShouldNot(BeEmpty(), "must specify $ATC_DIR")

	externalAddress = os.Getenv("EXTERNAL_ADDRESS")
	Ω(externalAddress).ShouldNot(BeEmpty(), "must specify $EXTERNAL_ADDRESS")

	archiveResourceRootfs := os.Getenv("ARCHIVE_RESOURCE_ROOTFS")
	Ω(archiveResourceRootfs).ShouldNot(BeEmpty(), "must specify $ARCHIVE_RESOURCE_ROOTFS")

	gitResourceRootfs := os.Getenv("GIT_RESOURCE_ROOTFS")
	Ω(gitResourceRootfs).ShouldNot(BeEmpty(), "must specify $GIT_RESOURCE_ROOTFS")

	helperRootfs = os.Getenv("HELPER_ROOTFS")
	Ω(helperRootfs).ShouldNot(BeEmpty(), "must specify $HELPER_ROOTFS")

	gardenAddr := fmt.Sprintf("127.0.0.1:%d", 4859+GinkgoParallelNode())

	gardenRunner := gardenrunner.New(
		"tcp",
		gardenAddr,
		builtComponents["garden-linux"],
		gardenBinPath,
		"bogus/rootfs",
		"/tmp",
	)

	gardenClient = gardenRunner.NewClient()

	turbineRunner := &ginkgomon.Runner{
		Name:          "turbine",
		AnsiColorCode: "33m",
		Command: exec.Command(
			builtComponents["turbine"],
			"-gardenNetwork", "tcp",
			"-gardenAddr", gardenAddr,
			"-resourceTypes", fmt.Sprintf(`{
				"archive": "%s",
				"git": "%s"
			}`, archiveResourceRootfs, gitResourceRootfs),
		),
		StartCheck:        "listening",
		StartCheckTimeout: 30 * time.Second,
	}

	postgresRunner = postgresrunner.Runner{
		Port: 5433 + GinkgoParallelNode(),
	}

	atcPipelineFilePath = fmt.Sprintf("/tmp/atc-pipeline-%d", GinkgoParallelNode())

	atcRunner = &ginkgomon.Runner{
		Name:          "atc",
		AnsiColorCode: "34m",
		Command: exec.Command(
			builtComponents["atc"],
			"-externalAddress", externalAddress,
			"-pipeline", atcPipelineFilePath,
			"-templates", filepath.Join(atcDir, "web", "templates"),
			"-public", filepath.Join(atcDir, "web", "public"),
			"-sqlDataSource", postgresRunner.DataSourceName(),
			"-checkInterval", "5s",
		),
		StartCheck:        "listening",
		StartCheckTimeout: 5 * time.Second,
	}

	os.Setenv("ATC_URL", "http://127.0.0.1:8080")

	plumbing = grouper.EnvokeGroup(grouper.RunGroup{
		"turbine":      turbineRunner,
		"garden-linux": gardenRunner,
		"postgres":     postgresRunner,
	})

	Consistently(plumbing.Wait(), 1*time.Second).ShouldNot(Receive())

	postgresRunner.CreateTestDB()
})

var _ = AfterEach(func() {
	stopProcess(atcProcess)

	postgresRunner.DropTestDB()

	stopProcess(plumbing)

	err := os.Remove(atcPipelineFilePath)
	Ω(err).ShouldNot(HaveOccurred())
})

func TestTestFlight(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "TestFlight Suite")
}

func stopProcess(process ifrit.Process) {
	process.Signal(syscall.SIGINT)

	select {
	case <-process.Wait():
	case <-time.After(10 * time.Second):
		println("!!!!!!!!!!!!!!!!!!!!!!!!!!!! EXIT TIMEOUT")

		process.Signal(syscall.SIGQUIT)
		Eventually(process.Wait(), 10*time.Second).Should(Receive())

		Fail("processes did not exit within 10s; SIGQUIT sent")
	}
}

func writeATCPipeline(templateName string, templateData interface{}) {
	gitPipelineTemplate, err := template.ParseFiles("pipelines/" + templateName)
	Ω(err).ShouldNot(HaveOccurred())

	atcPipelineFile, err := os.Create(atcPipelineFilePath)
	Ω(err).ShouldNot(HaveOccurred())

	err = gitPipelineTemplate.Execute(atcPipelineFile, templateData)
	Ω(err).ShouldNot(HaveOccurred())

	err = atcPipelineFile.Close()
	Ω(err).ShouldNot(HaveOccurred())
}

func buildWithGodeps(pkg string, args ...string) (string, error) {
	gopath := fmt.Sprintf(
		"%s%c%s",
		filepath.Join(os.Getenv("BASE_GOPATH"), "src", pkg, "Godeps", "_workspace"),
		os.PathListSeparator,
		os.Getenv("BASE_GOPATH"),
	)

	return gexec.BuildIn(gopath, pkg, args...)
}
<commit_msg>update ifrit usage<commit_after>package testflight_test

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"syscall"
	"testing"
	"text/template"
	"time"

	"github.com/cloudfoundry-incubator/garden/warden"
	"github.com/concourse/atc/postgresrunner"
	"github.com/concourse/testflight/gardenrunner"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/ginkgomon"
	"github.com/tedsuo/ifrit/grouper"
)

var (
	externalAddress string
	gardenBinPath   string
	helperRootfs    string

	builtComponents map[string]string

	atcDir              string
	atcPipelineFilePath string
	atcRunner           ifrit.Runner

	postgresRunner postgresrunner.Runner

	plumbing     ifrit.Process
	gardenClient warden.Client

	atcProcess ifrit.Process
)

var _ = SynchronizedBeforeSuite(func() []byte {
	gardenBinPath = os.Getenv("GARDEN_BINPATH")
	Ω(gardenBinPath).ShouldNot(BeEmpty(), "must provide $GARDEN_BINPATH")

	turbineBin, err := gexec.Build("github.com/concourse/turbine", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	atcBin, err := gexec.Build("github.com/concourse/atc", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	flyBin, err := gexec.Build("github.com/concourse/fly", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	gardenLinuxBin, err := buildWithGodeps("github.com/cloudfoundry-incubator/garden-linux", "-race")
	Ω(err).ShouldNot(HaveOccurred())

	components, err := json.Marshal(map[string]string{
		"turbine":      turbineBin,
		"atc":          atcBin,
		"fly":          flyBin,
		"garden-linux": gardenLinuxBin,
	})
	Ω(err).ShouldNot(HaveOccurred())

	return components
}, func(components []byte) {
	err := json.Unmarshal(components, &builtComponents)
	Ω(err).ShouldNot(HaveOccurred())
})

var _ = BeforeEach(func() {
	atcDir = os.Getenv("ATC_DIR")
	Ω(atcDir).ShouldNot(BeEmpty(), "must specify $ATC_DIR")

	externalAddress = os.Getenv("EXTERNAL_ADDRESS")
	Ω(externalAddress).ShouldNot(BeEmpty(), "must specify $EXTERNAL_ADDRESS")

	archiveResourceRootfs := os.Getenv("ARCHIVE_RESOURCE_ROOTFS")
	Ω(archiveResourceRootfs).ShouldNot(BeEmpty(), "must specify $ARCHIVE_RESOURCE_ROOTFS")

	gitResourceRootfs := os.Getenv("GIT_RESOURCE_ROOTFS")
	Ω(gitResourceRootfs).ShouldNot(BeEmpty(), "must specify $GIT_RESOURCE_ROOTFS")

	helperRootfs = os.Getenv("HELPER_ROOTFS")
	Ω(helperRootfs).ShouldNot(BeEmpty(), "must specify $HELPER_ROOTFS")

	gardenAddr := fmt.Sprintf("127.0.0.1:%d", 4859+GinkgoParallelNode())

	gardenRunner := gardenrunner.New(
		"tcp",
		gardenAddr,
		builtComponents["garden-linux"],
		gardenBinPath,
		"bogus/rootfs",
		"/tmp",
	)

	gardenClient = gardenRunner.NewClient()

	turbineRunner := &ginkgomon.Runner{
		Name:          "turbine",
		AnsiColorCode: "33m",
		Command: exec.Command(
			builtComponents["turbine"],
			"-gardenNetwork", "tcp",
			"-gardenAddr", gardenAddr,
			"-resourceTypes", fmt.Sprintf(`{
				"archive": "%s",
				"git": "%s"
			}`, archiveResourceRootfs, gitResourceRootfs),
		),
		StartCheck:        "listening",
		StartCheckTimeout: 30 * time.Second,
	}

	postgresRunner = postgresrunner.Runner{
		Port: 5433 + GinkgoParallelNode(),
	}

	atcPipelineFilePath = fmt.Sprintf("/tmp/atc-pipeline-%d", GinkgoParallelNode())

	atcRunner = &ginkgomon.Runner{
		Name:          "atc",
		AnsiColorCode: "34m",
		Command: exec.Command(
			builtComponents["atc"],
			"-externalAddress", externalAddress,
			"-pipeline", atcPipelineFilePath,
			"-templates", filepath.Join(atcDir, "web", "templates"),
			"-public", filepath.Join(atcDir, "web", "public"),
			"-sqlDataSource", postgresRunner.DataSourceName(),
			"-checkInterval", "5s",
		),
		StartCheck:        "listening",
		StartCheckTimeout: 5 * time.Second,
	}

	os.Setenv("ATC_URL", "http://127.0.0.1:8080")

	plumbing = ifrit.Invoke(grouper.NewParallel(os.Interrupt, []grouper.Member{
		{"turbine", turbineRunner},
		{"garden-linux", gardenRunner},
		{"postgres", postgresRunner},
	}))

	Consistently(plumbing.Wait(), 1*time.Second).ShouldNot(Receive())

	postgresRunner.CreateTestDB()
})

var _ = AfterEach(func() {
	stopProcess(atcProcess)

	postgresRunner.DropTestDB()

	stopProcess(plumbing)

	err := os.Remove(atcPipelineFilePath)
	Ω(err).ShouldNot(HaveOccurred())
})

func TestTestFlight(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "TestFlight Suite")
}

func stopProcess(process ifrit.Process) {
	process.Signal(syscall.SIGINT)

	select {
	case <-process.Wait():
	case <-time.After(10 * time.Second):
		println("!!!!!!!!!!!!!!!!!!!!!!!!!!!! EXIT TIMEOUT")

		process.Signal(syscall.SIGQUIT)
		Eventually(process.Wait(), 10*time.Second).Should(Receive())

		Fail("processes did not exit within 10s; SIGQUIT sent")
	}
}

func writeATCPipeline(templateName string, templateData interface{}) {
	gitPipelineTemplate, err := template.ParseFiles("pipelines/" + templateName)
	Ω(err).ShouldNot(HaveOccurred())

	atcPipelineFile, err := os.Create(atcPipelineFilePath)
	Ω(err).ShouldNot(HaveOccurred())

	err = gitPipelineTemplate.Execute(atcPipelineFile, templateData)
	Ω(err).ShouldNot(HaveOccurred())

	err = atcPipelineFile.Close()
	Ω(err).ShouldNot(HaveOccurred())
}

func buildWithGodeps(pkg string, args ...string) (string, error) {
	gopath := fmt.Sprintf(
		"%s%c%s",
		filepath.Join(os.Getenv("BASE_GOPATH"), "src", pkg, "Godeps", "_workspace"),
		os.PathListSeparator,
		os.Getenv("BASE_GOPATH"),
	)

	return gexec.BuildIn(gopath, pkg, args...)
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"errors"

	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

type CloseModel struct {
	Id     uint
	Name   string
	Ib     uint
	Closed bool
}

// check struct validity
func (c *CloseModel) IsValid() bool {

	if c.Id == 0 {
		return false
	}

	if c.Name == "" {
		return false
	}

	if c.Ib == 0 {
		return false
	}

	return true

}

// Status will return info
func (i *CloseModel) Status() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// Check if favorite is already there
	err = dbase.QueryRow("SELECT ib_id, thread_title, thread_closed FROM threads WHERE thread_id = ? LIMIT 1", i.Id).Scan(&i.Ib, &i.Name, &i.Closed)
	if err == sql.ErrNoRows {
		return e.ErrNotFound
	} else if err != nil {
		return
	}

	return

}

// Toggle will change the thread status
func (i *CloseModel) Toggle() (err error) {

	// check model validity
	if !i.IsValid() {
		return errors.New("CloseModel is not valid")
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	ps1, err := dbase.Prepare("UPDATE threads SET thread_closed = ? WHERE thread_id = ?")
	if err != nil {
		return
	}
	defer ps1.Close()

	_, err = ps1.Exec(!i.Closed, i.Id)
	if err != nil {
		return
	}

	return

}
<commit_msg>use ib from params<commit_after>package models

import (
	"database/sql"
	"errors"

	"github.com/eirka/eirka-libs/db"
	e "github.com/eirka/eirka-libs/errors"
)

type CloseModel struct {
	Id     uint
	Name   string
	Ib     uint
	Closed bool
}

// check struct validity
func (c *CloseModel) IsValid() bool {

	if c.Id == 0 {
		return false
	}

	if c.Name == "" {
		return false
	}

	if c.Ib == 0 {
		return false
	}

	return true

}

// Status will return info
func (i *CloseModel) Status() (err error) {

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	// Check if favorite is already there
	err = dbase.QueryRow("SELECT thread_title, thread_closed FROM threads WHERE thread_id = ? AND ib_id = ? LIMIT 1", i.Id, i.Ib).Scan(&i.Name, &i.Closed)
	if err == sql.ErrNoRows {
		return e.ErrNotFound
	} else if err != nil {
		return
	}

	return

}

// Toggle will change the thread status
func (i *CloseModel) Toggle() (err error) {

	// check model validity
	if !i.IsValid() {
		return errors.New("CloseModel is not valid")
	}

	// Get Database handle
	dbase, err := db.GetDb()
	if err != nil {
		return
	}

	ps1, err := dbase.Prepare("UPDATE threads SET thread_closed = ? WHERE thread_id = ? AND ib_id = ?")
	if err != nil {
		return
	}
	defer ps1.Close()

	_, err = ps1.Exec(!i.Closed, i.Id, i.Ib)
	if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package models

import (
	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	u "github.com/techjanitor/pram-get/utils"
)

// IndexModel holds the parameters from the request and also the key for the cache
type IndexModel struct {
	Ib      uint
	Page    uint
	Threads uint
	Posts   uint
	Result  IndexType
}

// ThreadIds holds all the thread ids for the loop that gets the posts
type ThreadIds struct {
	Id       uint
	Title    string
	LastPost string
	Closed   bool
	Sticky   bool
	Total    uint
}

// IndexType is the top level of the JSON response
type IndexType struct {
	Body u.PagedResponse `json:"index"`
}

// IndexThreadHeader holds the information for the threads
type IndexThreadHeader struct {
	Id        uint          `json:"id"`
	Title     string        `json:"title"`
	Closed    bool          `json:"closed"`
	Sticky    bool          `json:"sticky"`
	OmitPosts uint          `json:"omit_posts"`
	Pages     uint          `json:"last_page"`
	Posts     []ThreadPosts `json:"posts"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *IndexModel) Get() (err error) {

	// Initialize response header
	response := IndexType{}

	// Initialize struct for pagination
	paged := u.PagedResponse{}
	// Set current page to parameter
	paged.CurrentPage = i.Page
	// Set threads per index page to config setting
	paged.PerPage = i.Threads

	// Initialize struct for all thread ids
	thread_ids := []ThreadIds{}

	// Get Database handle
	db, err := u.GetDb()
	if err != nil {
		return
	}

	var ibs uint

	// Get total imageboard count
	err = db.QueryRow("select count(*) from imageboards").Scan(&ibs)
	if err != nil {
		return
	}

	// check ib id
	switch {
	case i.Ib == 0:
		return e.ErrNotFound
	case i.Ib > ibs:
		return e.ErrNotFound
	case i.Page == 0:
		return e.ErrNotFound
	}

	// Get total thread count and put it in pagination struct
	err = db.QueryRow("select count(*) from threads where ib_id = ? AND thread_deleted != 1", i.Ib).Scan(&paged.Total)
	if err != nil {
		return
	}

	// Calculate Limit and total Pages
	paged.Get()

	// Return 404 if page requested is larger than actual pages
	if i.Page > paged.Pages {
		return e.ErrNotFound
	}

	// Get all thread ids with limit
	thread_id_rows, err := db.Query(`SELECT threads.thread_id,thread_title,thread_closed,thread_sticky,count(posts.post_id)
	FROM threads
	LEFT JOIN posts on threads.thread_id = posts.thread_id
	WHERE ib_id = ? AND thread_deleted != 1
	GROUP BY threads.thread_id
	ORDER BY thread_sticky = 1 DESC, thread_last_post DESC LIMIT ?,?`, i.Ib, paged.Limit, i.Threads)
	if err != nil {
		return
	}
	defer thread_id_rows.Close()

	for thread_id_rows.Next() {
		// Initialize posts struct
		thread_id_row := ThreadIds{}
		// Scan rows and place column into struct
		err := thread_id_rows.Scan(&thread_id_row.Id, &thread_id_row.Title, &thread_id_row.Closed, &thread_id_row.Sticky, &thread_id_row.Total)
		if err != nil {
			return err
		}
		// Append rows to info struct
		thread_ids = append(thread_ids, thread_id_row)
	}
	err = thread_id_rows.Err()
	if err != nil {
		return
	}

	//Get last thread posts
	ps1, err := db.Prepare(`SELECT * FROM
	(SELECT posts.post_id,post_num,user_name,usergroup_id,post_time,post_text,image_id,image_file,image_thumbnail,image_tn_height,image_tn_width
	FROM posts
	LEFT JOIN images on posts.post_id = images.post_id
	INNER JOIN users on posts.user_id = users.user_id
	WHERE posts.thread_id = ? AND post_deleted != 1
	ORDER BY post_num = 1 DESC, post_num DESC LIMIT ?)
	AS p ORDER BY post_num ASC`)
	if err != nil {
		return
	}
	defer ps1.Close()

	// Initialize slice for threads
	threads := []IndexThreadHeader{}

	// Loop over the values of thread_ids
	for _, id := range thread_ids {

		thread := IndexThreadHeader{}

		// Get last page from thread
		postpages := u.PagedResponse{}
		postpages.Total = id.Total
		postpages.CurrentPage = 1
		postpages.PerPage = config.Settings.Limits.PostsPerPage
		postpages.Get()

		// Set thread fields
		thread.Id = id.Id
		thread.Title = id.Title
		thread.Closed = id.Closed
		thread.Sticky = id.Sticky
		thread.Pages = postpages.Pages

		// Get omitted postcount
		if id.Total <= i.Posts {
			thread.OmitPosts = 0
		} else {
			thread.OmitPosts = (id.Total - i.Posts)
		}

		e1, err := ps1.Query(id.Id, i.Posts)
		if err != nil {
			return err
		}
		defer e1.Close()

		for e1.Next() {
			// Initialize posts struct
			post := ThreadPosts{}
			// Scan rows and place column into struct
			err := e1.Scan(&post.Id, &post.Num, &post.Name, &post.Group, &post.Time, &post.Text, &post.ImgId, &post.File, &post.Thumb, &post.ThumbHeight, &post.ThumbWidth)
			if err != nil {
				return err
			}
			// Append rows to info struct
			thread.Posts = append(thread.Posts, post)
		}
		err = e1.Err()
		if err != nil {
			return err
		}
		threads = append(threads, thread)
	}

	// Add threads slice to items interface
	paged.Items = threads

	// Add pagedresponse to the response struct
	response.Body = paged

	// This is the data we will serialize
	i.Result = response

	return

}
<commit_msg>fix thread deletion queries<commit_after>package models

import (
	"github.com/techjanitor/pram-get/config"
	e "github.com/techjanitor/pram-get/errors"
	u "github.com/techjanitor/pram-get/utils"
)

// IndexModel holds the parameters from the request and also the key for the cache
type IndexModel struct {
	Ib      uint
	Page    uint
	Threads uint
	Posts   uint
	Result  IndexType
}

// ThreadIds holds all the thread ids for the loop that gets the posts
type ThreadIds struct {
	Id       uint
	Title    string
	LastPost string
	Closed   bool
	Sticky   bool
	Total    uint
}

// IndexType is the top level of the JSON response
type IndexType struct {
	Body u.PagedResponse `json:"index"`
}

// IndexThreadHeader holds the information for the threads
type IndexThreadHeader struct {
	Id        uint          `json:"id"`
	Title     string        `json:"title"`
	Closed    bool          `json:"closed"`
	Sticky    bool          `json:"sticky"`
	OmitPosts uint          `json:"omit_posts"`
	Pages     uint          `json:"last_page"`
	Posts     []ThreadPosts `json:"posts"`
}

// Get will gather the information from the database and return it as JSON serialized data
func (i *IndexModel) Get() (err error) {

	// Initialize response header
	response := IndexType{}

	// Initialize struct for pagination
	paged := u.PagedResponse{}
	// Set current page to parameter
	paged.CurrentPage = i.Page
	// Set threads per index page to config setting
	paged.PerPage = i.Threads

	// Initialize struct for all thread ids
	thread_ids := []ThreadIds{}

	// Get Database handle
	db, err := u.GetDb()
	if err != nil {
		return
	}

	var ibs uint

	// Get total imageboard count
	err = db.QueryRow("select count(*) from imageboards").Scan(&ibs)
	if err != nil {
		return
	}

	// check ib id
	switch {
	case i.Ib == 0:
		return e.ErrNotFound
	case i.Ib > ibs:
		return e.ErrNotFound
	case i.Page == 0:
		return e.ErrNotFound
	}

	// Get total thread count and put it in pagination struct
	err = db.QueryRow("select count(*) from threads where ib_id = ? AND thread_deleted != 1", i.Ib).Scan(&paged.Total)
	if err != nil {
		return
	}

	// Calculate Limit and total Pages
	paged.Get()

	// Return 404 if page requested is larger than actual pages
	if i.Page > paged.Pages {
		return e.ErrNotFound
	}

	// Get all thread ids with limit
	thread_id_rows, err := db.Query(`SELECT threads.thread_id,thread_title,thread_closed,thread_sticky,count(posts.post_id)
	FROM threads
	LEFT JOIN posts on threads.thread_id = posts.thread_id
	WHERE ib_id = ? AND thread_deleted != 1 AND post_deleted != 1
	GROUP BY threads.thread_id
	ORDER BY thread_sticky = 1 DESC, thread_last_post DESC LIMIT ?,?`, i.Ib, paged.Limit, i.Threads)
	if err != nil {
		return
	}
	defer thread_id_rows.Close()

	for thread_id_rows.Next() {
		// Initialize posts struct
		thread_id_row := ThreadIds{}
		// Scan rows and place column into struct
		err := thread_id_rows.Scan(&thread_id_row.Id, &thread_id_row.Title, &thread_id_row.Closed, &thread_id_row.Sticky, &thread_id_row.Total)
		if err != nil {
			return err
		}
		// Append rows to info struct
		thread_ids = append(thread_ids, thread_id_row)
	}
	err = thread_id_rows.Err()
	if err != nil {
		return
	}

	//Get last thread posts
	ps1, err := db.Prepare(`SELECT * FROM
	(SELECT posts.post_id,post_num,user_name,usergroup_id,post_time,post_text,image_id,image_file,image_thumbnail,image_tn_height,image_tn_width
	FROM posts
	LEFT JOIN images on posts.post_id = images.post_id
	INNER JOIN users on posts.user_id = users.user_id
	WHERE posts.thread_id = ? AND post_deleted != 1
	ORDER BY post_num = 1 DESC, post_num DESC LIMIT ?)
	AS p ORDER BY post_num ASC`)
	if err != nil {
		return
	}
	defer ps1.Close()

	// Initialize slice for threads
	threads := []IndexThreadHeader{}

	// Loop over the values of thread_ids
	for _, id := range thread_ids {

		thread := IndexThreadHeader{}

		// Get last page from thread
		postpages := u.PagedResponse{}
		postpages.Total = id.Total
		postpages.CurrentPage = 1
		postpages.PerPage = config.Settings.Limits.PostsPerPage
		postpages.Get()

		// Set thread fields
		thread.Id = id.Id
		thread.Title = id.Title
		thread.Closed = id.Closed
		thread.Sticky = id.Sticky
		thread.Pages = postpages.Pages

		// Get omitted postcount
		if id.Total <= i.Posts {
			thread.OmitPosts = 0
		} else {
			thread.OmitPosts = (id.Total - i.Posts)
		}

		e1, err := ps1.Query(id.Id, i.Posts)
		if err != nil {
			return err
		}
		defer e1.Close()

		for e1.Next() {
			// Initialize posts struct
			post := ThreadPosts{}
			// Scan rows and place column into struct
			err := e1.Scan(&post.Id, &post.Num, &post.Name, &post.Group, &post.Time, &post.Text, &post.ImgId, &post.File, &post.Thumb, &post.ThumbHeight, &post.ThumbWidth)
			if err != nil {
				return err
			}
			// Append rows to info struct
			thread.Posts = append(thread.Posts, post)
		}
		err = e1.Err()
		if err != nil {
			return err
		}
		threads = append(threads, thread)
	}

	// Add threads slice to items interface
	paged.Items = threads

	// Add pagedresponse to the response struct
	response.Body = paged

	// This is the data we will serialize
	i.Result = response

	return

}
<|endoftext|>


<commit_before>package models

import (
	"github.com/microcosm-cc/bluemonday"
	"html"

	"github.com/techjanitor/pram-post/config"
	e "github.com/techjanitor/pram-post/errors"
	u "github.com/techjanitor/pram-post/utils"
)

type ReplyModel struct {
	Uid         uint
	Ib          uint
	Thread      uint
	PostNum     uint
	Ip          string
	Comment     string
	Filename    string
	Thumbnail   string
	MD5         string
	OrigWidth   int
	OrigHeight  int
	ThumbWidth  int
	ThumbHeight int
	Image       bool
}

// ValidateInput will make sure all the parameters are valid
func (i *ReplyModel) ValidateInput() (err error) {
	if i.Thread == 0 {
		return e.ErrInvalidParam
	}

	// Initialize bluemonday
	p := bluemonday.StrictPolicy()

	// Sanitize comment for html and xss
	i.Comment = p.Sanitize(i.Comment)

	i.Comment = html.UnescapeString(i.Comment)

	// There must either be a comment, an image, or an image with a comment
	// If theres no image a comment is required
	comment := u.Validate{Input: i.Comment, Max: config.Settings.Limits.CommentMaxLength, Min: config.Settings.Limits.CommentMinLength}

	if !i.Image {
		if comment.IsEmpty() {
			return e.ErrNoComment
		} else if comment.MinLength() {
			return e.ErrCommentShort
		} else if comment.MaxLength() {
			return e.ErrCommentLong
		}
	}

	// If theres an image and a comment validate comment
	if i.Image && !comment.IsEmpty() {
		if comment.MinLength() {
			return e.ErrCommentShort
		} else if comment.MaxLength() {
			return e.ErrCommentLong
		}
	}

	return

}

// Status will return info about the thread
func (i *ReplyModel) Status() (err error) {

	// Get Database handle
	db, err := u.GetDb()
	if err != nil {
		return
	}

	var closed bool
	var total, lastnum uint

	// Check if thread is closed and get the total amount of posts
	err = db.QueryRow(`SELECT ib_id,thread_closed,count(post_num),post_num
	FROM ( SELECT ib_id,threads.thread_id,thread_closed,post_num
	FROM threads  LEFT JOIN posts on threads.thread_id = posts.thread_id
	WHERE threads.thread_id = ?
	GROUP BY post_num DESC) AS b`, i.Thread).Scan(&i.Ib, &closed, &total, &lastnum)
	if err != nil {
		return
	}

	// Error if thread is closed
	if closed {
		return e.ErrThreadClosed
	}

	// Close thread if above max posts
	if total > config.Settings.Limits.PostsMax {
		updatestatus, err := db.Prepare("UPDATE threads SET thread_closed=1 WHERE thread_id = ?")
		if err != nil {
			return err
		}
		defer updatestatus.Close()

		_, err = updatestatus.Exec(i.Thread)
		if err != nil {
			return err
		}

		return e.ErrThreadClosed
	}

	i.PostNum = lastnum + 1

	return

}

// Post will add the reply to the database with a transaction
func (i *ReplyModel) Post() (err error) {

	// Get transaction handle
	tx, err := u.GetTransaction()
	if err != nil {
		return
	}
	defer tx.Rollback()

	// Insert data into posts table
	ps1, err := tx.Prepare("INSERT INTO posts (thread_id,user_id,post_num,post_time,post_ip,post_text) VALUES (?,?,?,NOW(),?,?)")
	if err != nil {
		return
	}
	defer ps1.Close()

	// Update thread last post time
	ps2, err := tx.Prepare("UPDATE threads SET thread_last_post = NOW() WHERE thread_id = ?")
	if err != nil {
		return
	}
	defer ps2.Close()

	e1, err := ps1.Exec(i.Thread, i.Uid, i.PostNum, i.Ip, i.Comment)
	if err != nil {
		return
	}

	_, err = ps2.Exec(i.Thread)
	if err != nil {
		return
	}

	if i.Image {

		// Insert data into images table
		ps3, err := tx.Prepare("INSERT INTO images (post_id,image_file,image_thumbnail,image_hash,image_orig_height,image_orig_width,image_tn_height,image_tn_width) VALUES (?,?,?,?,?,?,?,?)")
		if err != nil {
			return err
		}
		defer ps2.Close()

		p_id, err := e1.LastInsertId()
		if err != nil {
			return err
		}

		_, err = ps3.Exec(p_id, i.Filename, i.Thumbnail, i.MD5, i.OrigHeight, i.OrigWidth, i.ThumbHeight, i.ThumbWidth)
		if err != nil {
			return err
		}

	}

	// Commit transaction
	err = tx.Commit()
	if err != nil {
		return
	}

	return

}
<commit_msg>update reply queries<commit_after>package models

import (
	"github.com/microcosm-cc/bluemonday"
	"html"

	"github.com/techjanitor/pram-post/config"
	e "github.com/techjanitor/pram-post/errors"
	u "github.com/techjanitor/pram-post/utils"
)

type ReplyModel struct {
	Uid         uint
	Ib          uint
	Thread      uint
	PostNum     uint
	Ip          string
	Comment     string
	Filename    string
	Thumbnail   string
	MD5         string
	OrigWidth   int
	OrigHeight  int
	ThumbWidth  int
	ThumbHeight int
	Image       bool
}

// ValidateInput will make sure all the parameters are valid
func (i *ReplyModel) ValidateInput() (err error) {
	if i.Thread == 0 {
		return e.ErrInvalidParam
	}

	// Initialize bluemonday
	p := bluemonday.StrictPolicy()

	// Sanitize comment for html and xss
	i.Comment = p.Sanitize(i.Comment)

	i.Comment = html.UnescapeString(i.Comment)

	// There must either be a comment, an image, or an image with a comment
	// If theres no image a comment is required
	comment := u.Validate{Input: i.Comment, Max: config.Settings.Limits.CommentMaxLength, Min: config.Settings.Limits.CommentMinLength}

	if !i.Image {
		if comment.IsEmpty() {
			return e.ErrNoComment
		} else if comment.MinLength() {
			return e.ErrCommentShort
		} else if comment.MaxLength() {
			return e.ErrCommentLong
		}
	}

	// If theres an image and a comment validate comment
	if i.Image && !comment.IsEmpty() {
		if comment.MinLength() {
			return e.ErrCommentShort
		} else if comment.MaxLength() {
			return e.ErrCommentLong
		}
	}

	return

}

// Status will return info about the thread
func (i *ReplyModel) Status() (err error) {

	// Get Database handle
	db, err := u.GetDb()
	if err != nil {
		return
	}

	var closed bool
	var total uint

	// Check if thread is closed and get the total amount of posts
	err = db.QueryRow(`SELECT ib_id,thread_closed,count(post_num)
	FROM ( SELECT ib_id,threads.thread_id,thread_closed,post_num
	FROM threads
	INNER JOIN posts on threads.thread_id = posts.thread_id
	WHERE threads.thread_id = ? AND post_deleted != 1
	GROUP BY post_num DESC) AS b`, i.Thread).Scan(&i.Ib, &closed, &total)
	if err != nil {
		return
	}

	// Error if thread is closed
	if closed {
		return e.ErrThreadClosed
	}

	// Close thread if above max posts
	if total > config.Settings.Limits.PostsMax {
		updatestatus, err := db.Prepare("UPDATE threads SET thread_closed=1 WHERE thread_id = ?")
		if err != nil {
			return err
		}
		defer updatestatus.Close()

		_, err = updatestatus.Exec(i.Thread)
		if err != nil {
			return err
		}

		return e.ErrThreadClosed
	}

	return

}

// Post will add the reply to the database with a transaction
func (i *ReplyModel) Post() (err error) {

	// Get transaction handle
	tx, err := u.GetTransaction()
	if err != nil {
		return
	}
	defer tx.Rollback()

	// Insert data into posts table
	ps1, err := tx.Prepare(`INSERT INTO posts (thread_id,user_id,post_num,post_time,post_ip,post_text)
    SELECT ?,?,max(post_num)+1,NOW(),?,?
    FROM posts WHERE thread_id = ? AND post_deleted != 1`)
	if err != nil {
		return
	}
	defer ps1.Close()

	// Update thread last post time
	ps2, err := tx.Prepare("UPDATE threads SET thread_last_post = NOW() WHERE thread_id = ?")
	if err != nil {
		return
	}
	defer ps2.Close()

	e1, err := ps1.Exec(i.Thread, i.Uid, i.PostNum, i.Ip, i.Comment)
	if err != nil {
		return
	}

	_, err = ps2.Exec(i.Thread)
	if err != nil {
		return
	}

	if i.Image {

		// Insert data into images table
		ps3, err := tx.Prepare("INSERT INTO images (post_id,image_file,image_thumbnail,image_hash,image_orig_height,image_orig_width,image_tn_height,image_tn_width) VALUES (?,?,?,?,?,?,?,?)")
		if err != nil {
			return err
		}
		defer ps2.Close()

		p_id, err := e1.LastInsertId()
		if err != nil {
			return err
		}

		_, err = ps3.Exec(p_id, i.Filename, i.Thumbnail, i.MD5, i.OrigHeight, i.OrigWidth, i.ThumbHeight, i.ThumbWidth)
		if err != nil {
			return err
		}

	}

	// Commit transaction
	err = tx.Commit()
	if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package procfs

import (
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)

const procfsdir = "/proc"

type Filler interface {
	Fill()
}

type Lister interface {
	List(string)
}

type Getter interface {
	Get(string)
}

type ProcFS struct {
	Processes map[string]*Process
	Self      string
}

const (
	PROCFS_PROCESSES = "Processes"
	PROCFS_SELF = "Self"
)

func (pfs *ProcFS) Fill() {
	pfs.List(PROCFS_PROCESSES)
	for _, p := range pfs.Processes {
		p.Fill()
	}
	pfs.Get(PROCFS_SELF)
}

func (pfs *ProcFS) List(k string) {
	switch k {
	case PROCFS_PROCESSES:
		if !exists(procfsdir) {
			return
		}
		pfs.Processes = make(map[string]*Process)
		ds, err := ioutil.ReadDir(procfsdir)
		if err != nil {
			return
		}
		// get all numeric entries
		for _, d := range ds {
			n := d.Name
			id, err := strconv.Atoi(n)
			if isNumeric(n) && err == nil {
				proc := Process{PID: id}
				pfs.Processes[n] = &proc
			}
		}
	}
}

func (pfs *ProcFS) Get(k string) {
	switch k {
	case PROCFS_SELF:
		var selfdir = path.Join(procfsdir, "self")
		if !exists(selfdir) {
			return
		}
		fi, _ := os.Readlink(selfdir)
		pfs.Self = fi
	}
}

type Process struct {
	PID     int
	Auxv    []byte
	Cmdline []string
	Cwd     string
	Environ map[string]string
	Exe     string
	Fds     map[string]*Fd
	Root    string
	Status  map[string]string
	Threads map[string]*Thread
}
// TODO limits, maps, mem, mountinfo, mounts, mountstats, ns, smaps, stat

const (
	PROCFS_PROC_AUXV = "Process.Auxv"
	PROCFS_PROC_CMDLINE = "Process.Cmdline"
	PROCFS_PROC_CWD = "Process.Cwd"
	PROCFS_PROC_ENVIRON = "Process.Environ"
	PROCFS_PROC_EXE = "Process.Exe"
	PROCFS_PROC_ROOT = "Process.Root"
	PROCFS_PROC_STATUS = "Process.Status"

	PROCFS_PROC_FDS = "Process.Fds"
	PROCFS_PROC_THREADS = "Process.Threads"
)

func (p *Process) Fill() {
	p.Get(PROCFS_PROC_AUXV)
	p.Get(PROCFS_PROC_CMDLINE)
	p.Get(PROCFS_PROC_CWD)
	p.Get(PROCFS_PROC_ENVIRON)
	p.Get(PROCFS_PROC_EXE)
	p.Get(PROCFS_PROC_ROOT)
	p.Get(PROCFS_PROC_STATUS)

	// Fds
	p.List(PROCFS_PROC_FDS)
	for _, f := range p.Fds {
		f.Fill()
	}

	// Threads
	p.List(PROCFS_PROC_THREADS)
	for _, t := range p.Threads {
		t.Fill()
	}
}

func (p *Process) List(k string) {

}

func (p *Process) Get(k string) {
	pdir := path.Join(procfsdir, strconv.Itoa(p.PID))
	switch k {
	case PROCFS_PROC_AUXV:
		p.Auxv, _ = ioutil.ReadFile(path.Join(pdir, "auxv"))
	case PROCFS_PROC_CMDLINE:
		cl, err := ioutil.ReadFile(path.Join(pdir, "cmdline"))
		if err == nil {
			p.Cmdline = splitNull(cl)
		}
	case PROCFS_PROC_CWD:
		p.Cwd, _ = os.Readlink(path.Join(pdir, "cwd"))
	case PROCFS_PROC_ENVIRON:
		envB, err := ioutil.ReadFile(path.Join(pdir, "environ"))
		if err == nil {
			p.Environ = make(map[string]string)
			envS := splitNull(envB)
			for _, s := range envS {
				// split on =
				ss := strings.SplitN(s, "=", 2)
				p.Environ[ss[0]] = ss[1]
			}
		}
	}
}

type Fd struct {
	Path  string
	Pos   int
	Flags int
}

const (
	PROCFS_PROC_FD_PATH = "Process.Fd.Path"
	PROCFS_PROC_FD_POS = "Process.Fd.Pos"
	PROCFS_PROC_FD_FLAGS = "Process.Fd.Flags"
)

func (f *Fd) Fill() {
	f.Get(PROCFS_PROC_FD_PATH)
	f.Get(PROCFS_PROC_FD_POS)
	f.Get(PROCFS_PROC_FD_FLAGS)
}

func (f *Fd) Get(k string) {
	switch k {

	}
}

type Thread struct {
	// TODO
}

func (t *Thread) Fill() {

}

func (t *Thread) Get(k string) {

}
<commit_msg>Adding support for exe<commit_after>package procfs

import (
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)

const procfsdir = "/proc"

type Filler interface {
	Fill()
}

type Lister interface {
	List(string)
}

type Getter interface {
	Get(string)
}

type ProcFS struct {
	Processes map[string]*Process
	Self      string
}

const (
	PROCFS_PROCESSES = "Processes"
	PROCFS_SELF = "Self"
)

func (pfs *ProcFS) Fill() {
	pfs.List(PROCFS_PROCESSES)
	for _, p := range pfs.Processes {
		p.Fill()
	}
	pfs.Get(PROCFS_SELF)
}

func (pfs *ProcFS) List(k string) {
	switch k {
	case PROCFS_PROCESSES:
		if !exists(procfsdir) {
			return
		}
		pfs.Processes = make(map[string]*Process)
		ds, err := ioutil.ReadDir(procfsdir)
		if err != nil {
			return
		}
		// get all numeric entries
		for _, d := range ds {
			n := d.Name
			id, err := strconv.Atoi(n)
			if isNumeric(n) && err == nil {
				proc := Process{PID: id}
				pfs.Processes[n] = &proc
			}
		}
	}
}

func (pfs *ProcFS) Get(k string) {
	switch k {
	case PROCFS_SELF:
		var selfdir = path.Join(procfsdir, "self")
		if !exists(selfdir) {
			return
		}
		fi, _ := os.Readlink(selfdir)
		pfs.Self = fi
	}
}

type Process struct {
	PID     int
	Auxv    []byte
	Cmdline []string
	Cwd     string
	Environ map[string]string
	Exe     string
	Fds     map[string]*Fd
	Root    string
	Status  map[string]string
	Threads map[string]*Thread
}
// TODO limits, maps, mem, mountinfo, mounts, mountstats, ns, smaps, stat

const (
	PROCFS_PROC_AUXV = "Process.Auxv"
	PROCFS_PROC_CMDLINE = "Process.Cmdline"
	PROCFS_PROC_CWD = "Process.Cwd"
	PROCFS_PROC_ENVIRON = "Process.Environ"
	PROCFS_PROC_EXE = "Process.Exe"
	PROCFS_PROC_ROOT = "Process.Root"
	PROCFS_PROC_STATUS = "Process.Status"

	PROCFS_PROC_FDS = "Process.Fds"
	PROCFS_PROC_THREADS = "Process.Threads"
)

func (p *Process) Fill() {
	p.Get(PROCFS_PROC_AUXV)
	p.Get(PROCFS_PROC_CMDLINE)
	p.Get(PROCFS_PROC_CWD)
	p.Get(PROCFS_PROC_ENVIRON)
	p.Get(PROCFS_PROC_EXE)
	p.Get(PROCFS_PROC_ROOT)
	p.Get(PROCFS_PROC_STATUS)

	// Fds
	p.List(PROCFS_PROC_FDS)
	for _, f := range p.Fds {
		f.Fill()
	}

	// Threads
	p.List(PROCFS_PROC_THREADS)
	for _, t := range p.Threads {
		t.Fill()
	}
}

func (p *Process) List(k string) {

}

func (p *Process) Get(k string) {
	pdir := path.Join(procfsdir, strconv.Itoa(p.PID))
	switch k {
	case PROCFS_PROC_AUXV:
		p.Auxv, _ = ioutil.ReadFile(path.Join(pdir, "auxv"))
	case PROCFS_PROC_CMDLINE:
		cl, err := ioutil.ReadFile(path.Join(pdir, "cmdline"))
		if err == nil {
			p.Cmdline = splitNull(cl)
		}
	case PROCFS_PROC_CWD:
		p.Cwd, _ = os.Readlink(path.Join(pdir, "cwd"))
	case PROCFS_PROC_ENVIRON:
		envB, err := ioutil.ReadFile(path.Join(pdir, "environ"))
		if err == nil {
			p.Environ = make(map[string]string)
			envS := splitNull(envB)
			for _, s := range envS {
				// split on =
				ss := strings.SplitN(s, "=", 2)
				p.Environ[ss[0]] = ss[1]
			}
		}
	case PROCFS_PROC_EXE:
		p.Exe, _ = os.Readlink(path.Join(pdir, "exe"))
	}
}

type Fd struct {
	Path  string
	Pos   int
	Flags int
}

const (
	PROCFS_PROC_FD_PATH = "Process.Fd.Path"
	PROCFS_PROC_FD_POS = "Process.Fd.Pos"
	PROCFS_PROC_FD_FLAGS = "Process.Fd.Flags"
)

func (f *Fd) Fill() {
	f.Get(PROCFS_PROC_FD_PATH)
	f.Get(PROCFS_PROC_FD_POS)
	f.Get(PROCFS_PROC_FD_FLAGS)
}

func (f *Fd) Get(k string) {
	switch k {

	}
}

type Thread struct {
	// TODO
}

func (t *Thread) Fill() {

}

func (t *Thread) Get(k string) {

}
<|endoftext|>


<commit_before>package request

import (
	"context"
	"github.com/ory/fosite"
	"github.com/ory/fosite/handler/oauth2"
	"github.com/ory/fosite/handler/openid"
)

// Manager provides a generic interface to clients in order to build a DataStore
type Manager interface {
	Storer
}

// Storer conforms to fosite.Requester and provides methods
type Storer interface {
	fosite.Requester

	// OAuth2 Required Storage interfaces.
	oauth2.AuthorizeCodeGrantStorage
	oauth2.ClientCredentialsGrantStorage
	oauth2.RefreshTokenGrantStorage
	// Authenticate is required to implement the oauth2.ResourceOwnerPasswordCredentialsGrantStorage interface
	Authenticate(ctx context.Context, name string, secret string) error
	// ouath2.ResourceOwnerPasswordCredentialsGrantStorage is indirectly implemented by the interfaces presented
	// above.

	// OpenID Required Storage Interfaces
	openid.OpenIDConnectRequestStorage

	// Enable revoking of tokens
	// see: https://github.com/ory/hydra/blob/master/pkg/fosite_storer.go
	//RevokeRefreshToken(ctx context.Context, requestID string) error
	//RevokeAccessToken(ctx context.Context, requestID string) error
}
<commit_msg>:arrow_up: Add methods into the storage interface as they are now supported<commit_after>package request

import (
	"context"
	"github.com/ory/fosite"
	"github.com/ory/fosite/handler/oauth2"
	"github.com/ory/fosite/handler/openid"
)

// Manager provides a generic interface to clients in order to build a DataStore
type Manager interface {
	Storer
}

// Storer conforms to fosite.Requester and provides methods
type Storer interface {
	fosite.Requester

	// OAuth2 Required Storage interfaces.
	oauth2.AuthorizeCodeGrantStorage
	oauth2.ClientCredentialsGrantStorage
	oauth2.RefreshTokenGrantStorage
	// Authenticate is required to implement the oauth2.ResourceOwnerPasswordCredentialsGrantStorage interface
	Authenticate(ctx context.Context, name string, secret string) error
	// ouath2.ResourceOwnerPasswordCredentialsGrantStorage is indirectly implemented by the interfaces presented
	// above.

	// OpenID Required Storage Interfaces
	openid.OpenIDConnectRequestStorage

	// Enable revoking of tokens
	// see: https://github.com/ory/hydra/blob/master/pkg/fosite_storer.go
	RevokeRefreshToken(ctx context.Context, requestID string) error
	RevokeAccessToken(ctx context.Context, requestID string) error
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"

	"github.com/zenazn/goji/web"
)

type subrouter struct {
	c *web.C
	h http.Handler
}

func (s subrouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if s.c.URLParams != nil {
		if path, ok := s.c.URLParams["*"]; ok {
			oldpath := r.URL.Path
			r.URL.Path = path
			defer func() {
				r.URL.Path = oldpath
			}()
		}
	}
	s.h.ServeHTTP(w, r)
}

// SubRouter is a helper middleware that makes writing sub-routers easier.
//
// If you register a sub-router under a key like "/admin/*", Goji's router will
// automatically set c.URLParams["*"] to the unmatched path suffix. This
// middleware will help you set the request URL's Path to this unmatched suffix,
// allowing you to write sub-routers with no knowledge of what routes the parent
// router matches.
func SubRouter(c *web.C, h http.Handler) http.Handler {
	return subrouter{c, h}
}
<commit_msg>Allow regexps to take advantage of SubRouter<commit_after>package middleware

import (
	"net/http"

	"github.com/zenazn/goji/web"
)

type subrouter struct {
	c *web.C
	h http.Handler
}

func (s subrouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if s.c.URLParams != nil {
		path, ok := s.c.URLParams["*"]
		if !ok {
			path, ok = s.c.URLParams["_"]
		}
		if ok {
			oldpath := r.URL.Path
			r.URL.Path = path
			defer func() {
				r.URL.Path = oldpath
			}()
		}
	}
	s.h.ServeHTTP(w, r)
}

// SubRouter is a helper middleware that makes writing sub-routers easier.
//
// If you register a sub-router under a key like "/admin/*", Goji's router will
// automatically set c.URLParams["*"] to the unmatched path suffix. This
// middleware will help you set the request URL's Path to this unmatched suffix,
// allowing you to write sub-routers with no knowledge of what routes the parent
// router matches.
//
// Since Go's regular expressions do not allow you to create a capturing group
// named "*", SubRouter also accepts the string "_". For instance, to duplicate
// the semantics of the string pattern "/foo/*", you might use the regular
// expression "^/foo(?P<_>/.*)$".
func SubRouter(c *web.C, h http.Handler) http.Handler {
	return subrouter{c, h}
}
<|endoftext|>