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

package libkbfs

import (
	"errors"
	"fmt"

	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc"
)

const (
	// StatusCodeMDServerError is the error code for a generic server error.
	StatusCodeMDServerError = 2800
	// StatusCodeMDServerErrorBadRequest is the error code for a generic client error.
	StatusCodeMDServerErrorBadRequest = 2801
	// StatusCodeMDServerErrorConflictRevision is the error code for a revision conflict error.
	StatusCodeMDServerErrorConflictRevision = 2802
	// StatusCodeMDServerErrorConflictPrevRoot is the error code for a PrevRoot pointer conflict error.
	StatusCodeMDServerErrorConflictPrevRoot = 2803
	// StatusCodeMDServerErrorConflictDiskUsage is the error code for a disk usage conflict error.
	StatusCodeMDServerErrorConflictDiskUsage = 2804
	// StatusCodeMDServerErrorLocked is the error code to indicate the folder truncation lock is locked.
	StatusCodeMDServerErrorLocked = 2805
	// StatusCodeMDServerErrorUnauthorized is the error code to indicate the client is unauthorized to perform
	// a certain operation. This is also used to indicate an object isn't found.
	StatusCodeMDServerErrorUnauthorized = 2806
	// StatusCodeMDServerErrorThrottle is the error code to indicate the client should initiate backoff.
	StatusCodeMDServerErrorThrottle = 2807
	// StatusCodeMDServerErrorConditionFailed is the error code to indicate the write condition failed.
	StatusCodeMDServerErrorConditionFailed = 2808
	// StatusCodeMDServerErrorWriteAccess is the error code to indicate the client isn't authorized to
	// write to a TLF.
	StatusCodeMDServerErrorWriteAccess = 2809
	// StatusCodeMDServerErrorConflictFolderMapping is the error code for a folder handle to folder ID
	// mapping conflict error.
	StatusCodeMDServerErrorConflictFolderMapping = 2810
)

// MDServerError is a generic server-side error.
type MDServerError struct {
	Err error
}

// ToStatus implements the ExportableError interface for MDServerError.
func (e MDServerError) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerError
	s.Name = "SERVER_ERROR"
	s.Desc = e.Error()
	return
}

// Error implements the Error interface for MDServerError.
func (e MDServerError) Error() string {
	if e.Err != nil {
		return e.Err.Error()
	}
	return "MDServerError"
}

// MDServerErrorBadRequest is a generic client-side error.
type MDServerErrorBadRequest struct {
	Reason string
}

// ToStatus implements the ExportableError interface for MDServerErrorBadRequest.
func (e MDServerErrorBadRequest) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorBadRequest
	s.Name = "BAD_REQUEST"
	s.Desc = e.Reason
	return
}

// Error implements the Error interface for MDServerErrorBadRequest.
func (e MDServerErrorBadRequest) Error() string {
	return fmt.Sprintf("Bad MD server request: %s", e.Reason)
}

// MDServerErrorConflictRevision is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictRevision struct {
	Desc     string
	Expected MetadataRevision
	Actual   MetadataRevision
}

// Error implements the Error interface for MDServerErrorConflictRevision.
func (e MDServerErrorConflictRevision) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected revision %d, actual %d", e.Expected, e.Actual)
	}
	return "MDServerConflictRevision{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictRevision.
func (e MDServerErrorConflictRevision) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictRevision
	s.Name = "CONFLICT_REVISION"
	s.Desc = e.Error()
	return
}

// MDServerErrorConflictPrevRoot is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictPrevRoot struct {
	Desc     string
	Expected MdID
	Actual   MdID
}

// Error implements the Error interface for MDServerErrorConflictPrevRoot.
func (e MDServerErrorConflictPrevRoot) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected previous root %v, actual %v", e.Expected, e.Actual)
	}
	return "MDServerConflictPrevRoot{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictPrevRoot.
func (e MDServerErrorConflictPrevRoot) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictPrevRoot
	s.Name = "CONFLICT_PREV_ROOT"
	s.Desc = e.Error()
	return
}

// MDServerErrorConflictDiskUsage is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictDiskUsage struct {
	Desc     string
	Expected uint64
	Actual   uint64
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictDiskUsage.
func (e MDServerErrorConflictDiskUsage) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictDiskUsage
	s.Name = "CONFLICT_DISK_USAGE"
	s.Desc = e.Error()
	return
}

// Error implements the Error interface for MDServerErrorConflictDiskUsage
func (e MDServerErrorConflictDiskUsage) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected disk usage %d, actual %d", e.Expected, e.Actual)
	}
	return "MDServerConflictDiskUsage{" + e.Desc + "}"
}

// MDServerErrorLocked is returned when the folder truncation lock is acquired by someone else.
type MDServerErrorLocked struct {
}

// Error implements the Error interface for MDServerErrorLocked.
func (e MDServerErrorLocked) Error() string {
	return "MDServerErrorLocked{}"
}

// ToStatus implements the ExportableError interface for MDServerErrorLocked.
func (e MDServerErrorLocked) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorLocked
	s.Name = "LOCKED"
	s.Desc = e.Error()
	return
}

// MDServerErrorUnauthorized is returned when a device requests a key half which doesn't belong to it.
type MDServerErrorUnauthorized struct {
	Err error
}

// Error implements the Error interface for MDServerErrorUnauthorized.
func (e MDServerErrorUnauthorized) Error() string {
	msg := "MDServer Unauthorized"
	if e.Err != nil {
		msg += ": " + e.Err.Error()
	}
	return msg
}

// ToStatus implements the ExportableError interface for MDServerErrorUnauthorized.
func (e MDServerErrorUnauthorized) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorUnauthorized
	s.Name = "UNAUTHORIZED"
	s.Desc = e.Error()
	return
}

// MDServerErrorWriteAccess is returned when the client isn't authorized to
// write to a TLF.
type MDServerErrorWriteAccess struct{}

// Error implements the Error interface for MDServerErrorWriteAccess.
func (e MDServerErrorWriteAccess) Error() string {
	return "MDServerErrorWriteAccess{}"
}

// ToStatus implements the ExportableError interface for MDServerErrorWriteAccess.
func (e MDServerErrorWriteAccess) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorWriteAccess
	s.Name = "WRITE_ACCESS"
	s.Desc = e.Error()
	return
}

// MDServerErrorThrottle is returned when the server wants the client to backoff.
type MDServerErrorThrottle struct {
	Err error
}

// Error implements the Error interface for MDServerErrorThrottle.
func (e MDServerErrorThrottle) Error() string {
	return "MDServerErrorThrottle{" + e.Err.Error() + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorThrottle.
func (e MDServerErrorThrottle) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorThrottle
	s.Name = "THROTTLE"
	s.Desc = e.Err.Error()
	return
}

// MDServerErrorConditionFailed is returned when a conditonal write failed.
// This means there was a race and the caller should consider it a conflcit.
type MDServerErrorConditionFailed struct {
	Err error
}

// Error implements the Error interface for MDServerErrorConditionFailed.
func (e MDServerErrorConditionFailed) Error() string {
	return "MDServerErrorConditionFailed{" + e.Err.Error() + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConditionFailed.
func (e MDServerErrorConditionFailed) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorThrottle
	s.Name = "CONDITION_FAILED"
	s.Desc = e.Err.Error()
	return
}

// MDServerErrorConflictFolderMapping is returned when there is a folder handle to folder
// ID mapping mismatch.
type MDServerErrorConflictFolderMapping struct {
	Desc     string
	Expected TlfID
	Actual   TlfID
}

// Error implements the Error interface for MDServerErrorConflictFolderMapping.
func (e MDServerErrorConflictFolderMapping) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected folder ID %s, actual %s",
			e.Expected, e.Actual)
	}
	return "MDServerErrorConflictFolderMapping{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictFolderMapping
func (e MDServerErrorConflictFolderMapping) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictFolderMapping
	s.Name = "CONFLICT_FOLDER_MAPPING"
	s.Desc = e.Error()
	return
}

// MDServerErrorUnwrapper is an implementation of rpc.ErrorUnwrapper
// for errors coming from the MDServer.
type MDServerErrorUnwrapper struct{}

var _ rpc.ErrorUnwrapper = MDServerErrorUnwrapper{}

// MakeArg implements rpc.ErrorUnwrapper for MDServerErrorUnwrapper.
func (eu MDServerErrorUnwrapper) MakeArg() interface{} {
	return &keybase1.Status{}
}

// UnwrapError implements rpc.ErrorUnwrapper for MDServerErrorUnwrapper.
func (eu MDServerErrorUnwrapper) UnwrapError(arg interface{}) (appError error, dispatchError error) {
	s, ok := arg.(*keybase1.Status)
	if !ok {
		return nil, errors.New("Error converting arg to keybase1.Status object in MDServerErrorUnwrapper.UnwrapError")
	}

	if s == nil || s.Code == 0 {
		return nil, nil
	}

	switch s.Code {
	case StatusCodeMDServerError:
		appError = MDServerError{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorBadRequest:
		appError = MDServerErrorBadRequest{Reason: s.Desc}
		break
	case StatusCodeMDServerErrorConflictRevision:
		appError = MDServerErrorConflictRevision{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorConflictPrevRoot:
		appError = MDServerErrorConflictPrevRoot{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorConflictDiskUsage:
		appError = MDServerErrorConflictDiskUsage{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorLocked:
		appError = MDServerErrorLocked{}
		break
	case StatusCodeMDServerErrorUnauthorized:
		appError = MDServerErrorUnauthorized{}
		break
	case StatusCodeMDServerErrorThrottle:
		appError = MDServerErrorThrottle{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorConditionFailed:
		appError = MDServerErrorConditionFailed{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorWriteAccess:
		appError = MDServerErrorWriteAccess{}
		break
	case StatusCodeMDServerErrorConflictFolderMapping:
		appError = MDServerErrorConflictFolderMapping{Desc: s.Desc}
		break
	default:
		ase := libkb.AppStatusError{
			Code:   s.Code,
			Name:   s.Name,
			Desc:   s.Desc,
			Fields: make(map[string]string),
		}
		for _, f := range s.Fields {
			ase.Fields[f.Key] = f.Value
		}
		appError = ase
	}

	return appError, nil
}
<commit_msg>Added MDServer error for trying to create too many folders<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"errors"
	"fmt"

	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/go-framed-msgpack-rpc"
)

const (
	// StatusCodeMDServerError is the error code for a generic server error.
	StatusCodeMDServerError = 2800
	// StatusCodeMDServerErrorBadRequest is the error code for a generic client error.
	StatusCodeMDServerErrorBadRequest = 2801
	// StatusCodeMDServerErrorConflictRevision is the error code for a revision conflict error.
	StatusCodeMDServerErrorConflictRevision = 2802
	// StatusCodeMDServerErrorConflictPrevRoot is the error code for a PrevRoot pointer conflict error.
	StatusCodeMDServerErrorConflictPrevRoot = 2803
	// StatusCodeMDServerErrorConflictDiskUsage is the error code for a disk usage conflict error.
	StatusCodeMDServerErrorConflictDiskUsage = 2804
	// StatusCodeMDServerErrorLocked is the error code to indicate the folder truncation lock is locked.
	StatusCodeMDServerErrorLocked = 2805
	// StatusCodeMDServerErrorUnauthorized is the error code to indicate the client is unauthorized to perform
	// a certain operation. This is also used to indicate an object isn't found.
	StatusCodeMDServerErrorUnauthorized = 2806
	// StatusCodeMDServerErrorThrottle is the error code to indicate the client should initiate backoff.
	StatusCodeMDServerErrorThrottle = 2807
	// StatusCodeMDServerErrorConditionFailed is the error code to indicate the write condition failed.
	StatusCodeMDServerErrorConditionFailed = 2808
	// StatusCodeMDServerErrorWriteAccess is the error code to indicate the client isn't authorized to
	// write to a TLF.
	StatusCodeMDServerErrorWriteAccess = 2809
	// StatusCodeMDServerErrorConflictFolderMapping is the error code for a folder handle to folder ID
	// mapping conflict error.
	StatusCodeMDServerErrorConflictFolderMapping = 2810
	// StatusCodeMDServerErrorTooManyFoldersCreated is the error code to
	// indicate that the user has created more folders than their limit.
	StatusCodeMDServerErrorTooManyFoldersCreated = 2811
)

// MDServerError is a generic server-side error.
type MDServerError struct {
	Err error
}

// ToStatus implements the ExportableError interface for MDServerError.
func (e MDServerError) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerError
	s.Name = "SERVER_ERROR"
	s.Desc = e.Error()
	return
}

// Error implements the Error interface for MDServerError.
func (e MDServerError) Error() string {
	if e.Err != nil {
		return e.Err.Error()
	}
	return "MDServerError"
}

// MDServerErrorBadRequest is a generic client-side error.
type MDServerErrorBadRequest struct {
	Reason string
}

// ToStatus implements the ExportableError interface for MDServerErrorBadRequest.
func (e MDServerErrorBadRequest) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorBadRequest
	s.Name = "BAD_REQUEST"
	s.Desc = e.Reason
	return
}

// Error implements the Error interface for MDServerErrorBadRequest.
func (e MDServerErrorBadRequest) Error() string {
	return fmt.Sprintf("Bad MD server request: %s", e.Reason)
}

// MDServerErrorConflictRevision is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictRevision struct {
	Desc     string
	Expected MetadataRevision
	Actual   MetadataRevision
}

// Error implements the Error interface for MDServerErrorConflictRevision.
func (e MDServerErrorConflictRevision) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected revision %d, actual %d", e.Expected, e.Actual)
	}
	return "MDServerConflictRevision{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictRevision.
func (e MDServerErrorConflictRevision) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictRevision
	s.Name = "CONFLICT_REVISION"
	s.Desc = e.Error()
	return
}

// MDServerErrorConflictPrevRoot is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictPrevRoot struct {
	Desc     string
	Expected MdID
	Actual   MdID
}

// Error implements the Error interface for MDServerErrorConflictPrevRoot.
func (e MDServerErrorConflictPrevRoot) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected previous root %v, actual %v", e.Expected, e.Actual)
	}
	return "MDServerConflictPrevRoot{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictPrevRoot.
func (e MDServerErrorConflictPrevRoot) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictPrevRoot
	s.Name = "CONFLICT_PREV_ROOT"
	s.Desc = e.Error()
	return
}

// MDServerErrorConflictDiskUsage is returned when the passed MD block is inconsistent with current history.
type MDServerErrorConflictDiskUsage struct {
	Desc     string
	Expected uint64
	Actual   uint64
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictDiskUsage.
func (e MDServerErrorConflictDiskUsage) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictDiskUsage
	s.Name = "CONFLICT_DISK_USAGE"
	s.Desc = e.Error()
	return
}

// Error implements the Error interface for MDServerErrorConflictDiskUsage
func (e MDServerErrorConflictDiskUsage) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected disk usage %d, actual %d", e.Expected, e.Actual)
	}
	return "MDServerConflictDiskUsage{" + e.Desc + "}"
}

// MDServerErrorLocked is returned when the folder truncation lock is acquired by someone else.
type MDServerErrorLocked struct {
}

// Error implements the Error interface for MDServerErrorLocked.
func (e MDServerErrorLocked) Error() string {
	return "MDServerErrorLocked{}"
}

// ToStatus implements the ExportableError interface for MDServerErrorLocked.
func (e MDServerErrorLocked) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorLocked
	s.Name = "LOCKED"
	s.Desc = e.Error()
	return
}

// MDServerErrorUnauthorized is returned when a device requests a key half which doesn't belong to it.
type MDServerErrorUnauthorized struct {
	Err error
}

// Error implements the Error interface for MDServerErrorUnauthorized.
func (e MDServerErrorUnauthorized) Error() string {
	msg := "MDServer Unauthorized"
	if e.Err != nil {
		msg += ": " + e.Err.Error()
	}
	return msg
}

// ToStatus implements the ExportableError interface for MDServerErrorUnauthorized.
func (e MDServerErrorUnauthorized) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorUnauthorized
	s.Name = "UNAUTHORIZED"
	s.Desc = e.Error()
	return
}

// MDServerErrorWriteAccess is returned when the client isn't authorized to
// write to a TLF.
type MDServerErrorWriteAccess struct{}

// Error implements the Error interface for MDServerErrorWriteAccess.
func (e MDServerErrorWriteAccess) Error() string {
	return "MDServerErrorWriteAccess{}"
}

// ToStatus implements the ExportableError interface for MDServerErrorWriteAccess.
func (e MDServerErrorWriteAccess) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorWriteAccess
	s.Name = "WRITE_ACCESS"
	s.Desc = e.Error()
	return
}

// MDServerErrorThrottle is returned when the server wants the client to backoff.
type MDServerErrorThrottle struct {
	Err error
}

// Error implements the Error interface for MDServerErrorThrottle.
func (e MDServerErrorThrottle) Error() string {
	return "MDServerErrorThrottle{" + e.Err.Error() + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorThrottle.
func (e MDServerErrorThrottle) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorThrottle
	s.Name = "THROTTLE"
	s.Desc = e.Err.Error()
	return
}

// MDServerErrorConditionFailed is returned when a conditonal write failed.
// This means there was a race and the caller should consider it a conflcit.
type MDServerErrorConditionFailed struct {
	Err error
}

// Error implements the Error interface for MDServerErrorConditionFailed.
func (e MDServerErrorConditionFailed) Error() string {
	return "MDServerErrorConditionFailed{" + e.Err.Error() + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConditionFailed.
func (e MDServerErrorConditionFailed) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorThrottle
	s.Name = "CONDITION_FAILED"
	s.Desc = e.Err.Error()
	return
}

// MDServerErrorConflictFolderMapping is returned when there is a folder handle to folder
// ID mapping mismatch.
type MDServerErrorConflictFolderMapping struct {
	Desc     string
	Expected TlfID
	Actual   TlfID
}

// Error implements the Error interface for MDServerErrorConflictFolderMapping.
func (e MDServerErrorConflictFolderMapping) Error() string {
	if e.Desc == "" {
		return fmt.Sprintf("Conflict: expected folder ID %s, actual %s",
			e.Expected, e.Actual)
	}
	return "MDServerErrorConflictFolderMapping{" + e.Desc + "}"
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictFolderMapping
func (e MDServerErrorConflictFolderMapping) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorConflictFolderMapping
	s.Name = "CONFLICT_FOLDER_MAPPING"
	s.Desc = e.Error()
	return
}

// MDServerErrorTooManyFoldersCreated is returned when a user has created more
// folders than their limit allows.
type MDServerErrorTooManyFoldersCreated struct {
	Created uint64
	Limit   uint64
}

// Error implements the Error interface for MDServerErrorTooManyFoldersCreated.
func (e MDServerErrorTooManyFoldersCreated) Error() string {
	return fmt.Sprintf("Too many folders created. Created: %d, limit: %d",
		e.Created, e.Limit)
}

// ToStatus implements the ExportableError interface for MDServerErrorConflictFolderMapping
func (e MDServerErrorTooManyFoldersCreated) ToStatus() (s keybase1.Status) {
	s.Code = StatusCodeMDServerErrorTooManyFoldersCreated
	s.Name = "TOO_MANY_FOLDERS_CREATED"
	s.Desc = e.Error()
	return
}

// MDServerErrorUnwrapper is an implementation of rpc.ErrorUnwrapper
// for errors coming from the MDServer.
type MDServerErrorUnwrapper struct{}

var _ rpc.ErrorUnwrapper = MDServerErrorUnwrapper{}

// MakeArg implements rpc.ErrorUnwrapper for MDServerErrorUnwrapper.
func (eu MDServerErrorUnwrapper) MakeArg() interface{} {
	return &keybase1.Status{}
}

// UnwrapError implements rpc.ErrorUnwrapper for MDServerErrorUnwrapper.
func (eu MDServerErrorUnwrapper) UnwrapError(arg interface{}) (appError error, dispatchError error) {
	s, ok := arg.(*keybase1.Status)
	if !ok {
		return nil, errors.New("Error converting arg to keybase1.Status object in MDServerErrorUnwrapper.UnwrapError")
	}

	if s == nil || s.Code == 0 {
		return nil, nil
	}

	switch s.Code {
	case StatusCodeMDServerError:
		appError = MDServerError{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorBadRequest:
		appError = MDServerErrorBadRequest{Reason: s.Desc}
		break
	case StatusCodeMDServerErrorConflictRevision:
		appError = MDServerErrorConflictRevision{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorConflictPrevRoot:
		appError = MDServerErrorConflictPrevRoot{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorConflictDiskUsage:
		appError = MDServerErrorConflictDiskUsage{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorLocked:
		appError = MDServerErrorLocked{}
		break
	case StatusCodeMDServerErrorUnauthorized:
		appError = MDServerErrorUnauthorized{}
		break
	case StatusCodeMDServerErrorThrottle:
		appError = MDServerErrorThrottle{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorConditionFailed:
		appError = MDServerErrorConditionFailed{errors.New(s.Desc)}
		break
	case StatusCodeMDServerErrorWriteAccess:
		appError = MDServerErrorWriteAccess{}
		break
	case StatusCodeMDServerErrorConflictFolderMapping:
		appError = MDServerErrorConflictFolderMapping{Desc: s.Desc}
		break
	case StatusCodeMDServerErrorTooManyFoldersCreated:
		appError = MDServerErrorTooManyFoldersCreated{}
		break
	default:
		ase := libkb.AppStatusError{
			Code:   s.Code,
			Name:   s.Name,
			Desc:   s.Desc,
			Fields: make(map[string]string),
		}
		for _, f := range s.Fields {
			ase.Fields[f.Key] = f.Value
		}
		appError = ase
	}

	return appError, nil
}
<|endoftext|>


<commit_before>package builder

import (
	"strings"
)

type Query struct {
	TypeQuery     string
	Columns       []interface{}
	TableName     string
	WhereCond     []WhereStruct
	GroupByStruct []interface{}
}

type WhereStruct struct {
	Expression string
	Value      interface{}
	Delimiter  string
}

func Select(columns ...interface{}) *Query {

	return &Query{
		Columns:   columns,
		TypeQuery: "Select",
	}
}

func (query *Query) From(table string) *Query {
	query.TableName = strings.Replace(table, " ", "", -1)
	return query
}

func (query *Query) FromSubquery(table string) *Query {
	query.TableName = "(" + table + ")"
	return query
}

func (query *Query) Where(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value})
	return query
}

func (query *Query) And(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value, Delimiter: " And "})
	return query
}

func (query *Query) Or(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value, Delimiter: " Or "})
	return query
}

func (query *Query) GroupBy(values ...interface{}) *Query {
	query.GroupByStruct = values
	return query
}
<commit_msg>GroupBy - replace ...interface to interface<commit_after>package builder

import (
	"strings"
)

type Query struct {
	TypeQuery     string
	Columns       []interface{}
	TableName     string
	WhereCond     []WhereStruct
	GroupByStruct []interface{}
}

type WhereStruct struct {
	Expression string
	Value      interface{}
	Delimiter  string
}

func Select(columns ...interface{}) *Query {

	return &Query{
		Columns:   columns,
		TypeQuery: "Select",
	}
}

func (query *Query) From(table string) *Query {
	query.TableName = strings.Replace(table, " ", "", -1)
	return query
}

func (query *Query) FromSubquery(table string) *Query {
	query.TableName = "(" + table + ")"
	return query
}

func (query *Query) Where(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value})
	return query
}

func (query *Query) And(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value, Delimiter: " And "})
	return query
}

func (query *Query) Or(query_str string, value interface{}) *Query {
	query.WhereCond = append(query.WhereCond, WhereStruct{Expression: query_str, Value: value, Delimiter: " Or "})
	return query
}

func (query *Query) GroupBy(values interface{}) *Query {
	query.GroupByStruct = values
	return query
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/gophergala2016/sendto/client"
)

const (
	v = "0.1"
)

func main() {
	command := ""
	args := os.Args[1:] // remove app path from args

	// We expect either a username or a subcommand and then a set of files in args
	if len(args) > 0 {
		command = args[0]
		args = args[1:]
	}

	// Load our configuration
	err := client.LoadConfig()
	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}

	switch command {
	case "encrypt", "e":
		err = Encrypt(args)
	case "decrypt", "d":
		err = Decrypt(args)
	case "identity", "i":
		err = Identity(args)
	case "version", "v":
		Version()
	case "help", "h":
		Help()
	default:
		// Default action is to send to (if we have a username and files)
		if len(args) > 0 {
			err = SendTo(command, args)
		} else {
			Help()
		}
	}

	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}
}

// Version prints the version of this app
func Version() {
	fmt.Printf("\n\t-----\n\tSend to client - version:%s\n\t-----\n", v)
}

// Usage returns standard usage as a string
func Usage() string {
	return fmt.Sprintf("\tUsage: sendto kennygrant [files] - send files to the username kennygrant\n")
}

// Help prints the usage and commands
func Help() {
	Version()
	fmt.Printf(Usage())
	fmt.Printf("\t-----\n")
	fmt.Printf("\tCommands:\n")
	fmt.Printf("\tsendto version - display version\n")
	fmt.Printf("\tsendto [username] [files] - encrypt files for a given user\n")
	fmt.Printf("\tsendto encrypt [file] - encrypt a file\n")
	//	fmt.Printf("\tsendto decrypt [file] - decrypt a file\n")
	fmt.Printf("\tsendto identity [name] - sets default sender identity\n\n")
}

// Decrypt files specified, using the user's private key
// TODO: to support decryption we'd need access to private keys, perhaps leave this for hackathon
func Decrypt(args []string) error {
	log.Printf("Sorry, this client does not yet support decrypt")

	return nil
}

// Encrypt the files specified
func Encrypt(args []string) error {

	log.Printf("Sorry, this client does not yet support encryption")
	return nil
}

// SendTo sends files held in args to recipient
func SendTo(recipient string, args []string) error {

	// We expect at least 1 file to send
	if len(args) < 1 {
		return fmt.Errorf("Not enough arguments - %s", Usage())
	}

	// Notify the user that we're starting to send
	fmt.Printf("Sending %d %s to %s as %s...\n", len(args), filesString(len(args)), recipient, client.Config["sender"])

	// Fetch the recipient's key (from disk or server)

	// For the moment as a test, use keybase.io, should be using our server
	keyURL := fmt.Sprintf(client.Config["keyserver"], recipient)
	keyPath, err := client.LoadKey(recipient, keyURL)
	if err != nil {
		// Warn user in a nicer way here that key could not be found
		return fmt.Errorf("Failed to find key:%s", err)
	}
	fmt.Printf("Loaded key for %s:\n%s\n", recipient, keyPath)

	// Zip and Encrypt our arguments (files or folders) using key
	dataPath, err := client.EncryptFiles(args, recipient, keyPath)
	if err != nil {
		return err
	}

	// Send the file to the recipient on the server
	postURL := fmt.Sprintf("%s/files/create", client.Config["server"])

	fmt.Printf("Sending files for %s to %s\n", recipient, postURL)

	err = client.PostData(client.Config["sender"], recipient, dataPath, postURL)
	if err != nil {
		return err
	}

	return nil
}

// Identity sets the default sender identity (as opposed to username)
func Identity(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("Identity command requires a sender name")
	}

	identity := args[0]
	client.Config["sender"] = identity

	fmt.Printf("Setting sender identity to:%s\n", identity)

	return client.SaveConfig()
}

// Perhaps also allow setting default server?

// Return a nicely formatted string for the word files
func filesString(i int) string {
	if i > 1 {
		return "files"
	}
	return "file"
}
<commit_msg>Fix import<commit_after>package main

import (
	"fmt"
	"log"
	"os"

	"github.com/send-to/sendto/client"
)

const (
	v = "0.1"
)

func main() {
	command := ""
	args := os.Args[1:] // remove app path from args

	// We expect either a username or a subcommand and then a set of files in args
	if len(args) > 0 {
		command = args[0]
		args = args[1:]
	}

	// Load our configuration
	err := client.LoadConfig()
	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}

	switch command {
	case "encrypt", "e":
		err = Encrypt(args)
	case "decrypt", "d":
		err = Decrypt(args)
	case "identity", "i":
		err = Identity(args)
	case "version", "v":
		Version()
	case "help", "h":
		Help()
	default:
		// Default action is to send to (if we have a username and files)
		if len(args) > 0 {
			err = SendTo(command, args)
		} else {
			Help()
		}
	}

	if err != nil {
		log.Fatalf("Sorry, an error occurred:\n\t%s", err)
	}
}

// Version prints the version of this app
func Version() {
	fmt.Printf("\n\t-----\n\tSend to client - version:%s\n\t-----\n", v)
}

// Usage returns standard usage as a string
func Usage() string {
	return fmt.Sprintf("\tUsage: sendto kennygrant [files] - send files to the username kennygrant\n")
}

// Help prints the usage and commands
func Help() {
	Version()
	fmt.Printf(Usage())
	fmt.Printf("\t-----\n")
	fmt.Printf("\tCommands:\n")
	fmt.Printf("\tsendto version - display version\n")
	fmt.Printf("\tsendto [username] [files] - encrypt files for a given user\n")
	fmt.Printf("\tsendto encrypt [file] - encrypt a file\n")
	//	fmt.Printf("\tsendto decrypt [file] - decrypt a file\n")
	fmt.Printf("\tsendto identity [name] - sets default sender identity\n\n")
}

// Decrypt files specified, using the user's private key
// TODO: to support decryption we'd need access to private keys, perhaps leave this for hackathon
func Decrypt(args []string) error {
	log.Printf("Sorry, this client does not yet support decrypt")

	return nil
}

// Encrypt the files specified
func Encrypt(args []string) error {

	log.Printf("Sorry, this client does not yet support encryption")
	return nil
}

// SendTo sends files held in args to recipient
func SendTo(recipient string, args []string) error {

	// We expect at least 1 file to send
	if len(args) < 1 {
		return fmt.Errorf("Not enough arguments - %s", Usage())
	}

	// Notify the user that we're starting to send
	fmt.Printf("Sending %d %s to %s as %s...\n", len(args), filesString(len(args)), recipient, client.Config["sender"])

	// Fetch the recipient's key (from disk or server)

	// For the moment as a test, use keybase.io, should be using our server
	keyURL := fmt.Sprintf(client.Config["keyserver"], recipient)
	keyPath, err := client.LoadKey(recipient, keyURL)
	if err != nil {
		// Warn user in a nicer way here that key could not be found
		return fmt.Errorf("Failed to find key:%s", err)
	}
	fmt.Printf("Loaded key for %s:\n%s\n", recipient, keyPath)

	// Zip and Encrypt our arguments (files or folders) using key
	dataPath, err := client.EncryptFiles(args, recipient, keyPath)
	if err != nil {
		return err
	}

	// Send the file to the recipient on the server
	postURL := fmt.Sprintf("%s/files/create", client.Config["server"])

	fmt.Printf("Sending files for %s to %s\n", recipient, postURL)

	err = client.PostData(client.Config["sender"], recipient, dataPath, postURL)
	if err != nil {
		return err
	}

	return nil
}

// Identity sets the default sender identity (as opposed to username)
func Identity(args []string) error {
	if len(args) < 1 {
		return fmt.Errorf("Identity command requires a sender name")
	}

	identity := args[0]
	client.Config["sender"] = identity

	fmt.Printf("Setting sender identity to:%s\n", identity)

	return client.SaveConfig()
}

// Perhaps also allow setting default server?

// Return a nicely formatted string for the word files
func filesString(i int) string {
	if i > 1 {
		return "files"
	}
	return "file"
}
<|endoftext|>


<commit_before>package empire

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Decoder represents a function that can decode a request into an interface
// value.
type Decoder func(r *http.Request, v interface{}) error

func JSONDecode(r *http.Request, v interface{}) error {
	return json.NewDecoder(r.Body).Decode(v)
}

// Request wraps an http.Request for convenience.
type Request struct {
	*http.Request
	Vars map[string]string
	Decoder
}

// NewRequest parse the mux vars and returns a new Request instance.
func NewRequest(r *http.Request) *Request {
	return &Request{Request: r, Vars: mux.Vars(r)}
}

// Decode decodes the request using the Decoder.
func (r *Request) Decode(v interface{}) error {
	d := r.Decoder

	if d == nil {
		d = JSONDecode
	}

	return d(r.Request, v)
}

// Handler defines an interface for service an HTTP request.
type Handler interface {
	Serve(*Request) (int, interface{}, error)
}

// ErrorResource represents the error response format that we return.
type ErrorResource struct {
	Err string `json:"error"`
}

// Error implements error interface.
func (e *ErrorResource) Error() string {
	return e.Err
}

// Endpoint wraps a Handler to implement the http.Handler interface.
type Endpoint struct {
	Handler
}

// ServeHTTP implements the http.Handler interface. It will parse the form
// params, then serve the request, finally JSON encoding the returned value.
func (e *Endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	req := NewRequest(r)

	status, v, err := e.Handler.Serve(req)
	if err != nil {
		if _, ok := err.(*ErrorResource); ok {
			v = err
		} else {
			v = &ErrorResource{Err: err.Error()}
		}
		log.Printf("Error: %v\n", v)
	}

	w.WriteHeader(status)
	json.NewEncoder(w).Encode(v)
}

// Server represents the API.
type Server struct {
	http.Handler
}

// NewServer creates the API routes and returns a new Server instance.
func NewServer(e *Empire) *Server {
	r := newRouter()

	// Apps
	r.Handle("GET", "/apps", &GetApps{e.AppsService})   // hk apps
	r.Handle("POST", "/apps", &PostApps{e.AppsService}) // hk create

	// Deploys
	r.Handle("POST", "/deploys", &PostDeploys{e.DeploysService}) // Deploy an app

	// Releases
	r.Handle("GET", "/apps/{app}/releases", &GetReleases{e.AppsService, e.ReleasesService}) // hk releases

	// Configs
	r.Handle("GET", "/apps/{app}/config-vars", &GetConfigs{e.AppsService, e.ConfigsService})                        // hk env, hk get
	r.Handle("PATCH", "/apps/{app}/config-vars", &PatchConfigs{e.AppsService, e.ReleasesService, e.ConfigsService}) // hk set

	// Processes
	r.Handle("GET", "/apps/{app}/dynos", &GetProcesses{e.AppsService, e.Manager}) // hk dynos

	// Formations
	r.Handle("PATCH", "/apps/{app}/formation", &PatchFormation{e.AppsService, e.ReleasesService, e.Manager}) // hk scale

	n := negroni.Classic()
	n.UseHandler(r)

	return &Server{n}
}

// router is an http router for Handlers.
type router struct {
	*mux.Router
}

// newRouter returns a new router instance.
func newRouter() *router {
	return &router{Router: mux.NewRouter()}
}

// Handle sets up a route for a Handler.
func (r *router) Handle(method, path string, h Handler) {
	r.Router.Handle(path, &Endpoint{Handler: h}).Methods(method)
}

type GetApps struct {
	AppsService AppsService
}

func (h *GetApps) Serve(req *Request) (int, interface{}, error) {
	apps, err := h.AppsService.FindAll()
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, apps, nil
}

type PostAppsForm struct {
	Name string `json:"name"`
	Repo string `json:"repo"`
}

type PostApps struct {
	AppsService AppsService
}

func (h *PostApps) Serve(req *Request) (int, interface{}, error) {
	var form PostAppsForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	app, err := NewApp(AppName(form.Name), Repo(form.Repo))
	if err != nil {
		return http.StatusBadRequest, nil, err
	}

	a, err := h.AppsService.Create(app)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 201, a, nil
}

// PostDeploys is a Handler for the POST /v1/deploys endpoint.
type PostDeploys struct {
	DeploysService DeploysService
}

// PostDeployForm is the form object that represents the POST body.
type PostDeployForm struct {
	Image struct {
		ID   string `json:"id"`
		Repo string `json:"repo"`
	} `json:"image"`
}

// Serve implements the Handler interface.
func (h *PostDeploys) Serve(req *Request) (int, interface{}, error) {
	var form PostDeployForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	d, err := h.DeploysService.Deploy(&Image{
		Repo: Repo(form.Image.Repo),
		ID:   form.Image.ID,
	})
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 201, d, nil
}

type GetReleases struct {
	AppsService     AppsService
	ReleasesService ReleasesService
}

func (h *GetReleases) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	rels, err := h.ReleasesService.FindByApp(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, rels, nil
}

type GetConfigs struct {
	AppsService    AppsService
	ConfigsService ConfigsService
}

func (h *GetConfigs) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	c, err := h.ConfigsService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, c.Vars, nil
}

type PatchConfigs struct {
	AppsService     AppsService
	ReleasesService ReleasesService
	ConfigsService  ConfigsService
}

func (h *PatchConfigs) Serve(req *Request) (int, interface{}, error) {
	var configVars Vars

	if err := req.Decode(&configVars); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	name := AppName(req.Vars["app"])

	// Find app
	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	// Update the config
	c, err := h.ConfigsService.Apply(a, configVars)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// Find current release
	r, err := h.ReleasesService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// If there is an existing release, create a new one
	if r != nil {
		// Create new release based on new config and old slug
		_, err = h.ReleasesService.Create(a, c, r.Slug)
		if err != nil {
			return http.StatusInternalServerError, nil, err
		}
	}

	return 200, c.Vars, nil
}

type GetProcesses struct {
	AppsService AppsService
	Manager     Manager
}

func (h *GetProcesses) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	// Retrieve job states
	js, err := h.Manager.JobStatesByApp(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, js, nil
}

type PatchFormation struct {
	AppsService     AppsService
	ReleasesService ReleasesService
	Manager         Manager
}

type PatchFormationForm struct {
	Updates []struct {
		Process  string `json:"process"` // Refers to process type
		Quantity int    `json:"quantity"`
		Size     string `json:"size"`
	} `json:"updates"`
}

func (h *PatchFormation) Serve(req *Request) (int, interface{}, error) {
	var form PatchFormationForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	qm := ProcessQuantityMap{}
	for _, up := range form.Updates {
		qm[ProcessType(up.Process)] = up.Quantity
	}

	r, err := h.ReleasesService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if r == nil {
		return http.StatusNotFound, nil, nil
	}

	err = h.Manager.ScaleRelease(r, qm)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, nil, nil
}
<commit_msg>Add hk compat output<commit_after>package empire

import (
	"encoding/json"
	"log"
	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Decoder represents a function that can decode a request into an interface
// value.
type Decoder func(r *http.Request, v interface{}) error

func JSONDecode(r *http.Request, v interface{}) error {
	return json.NewDecoder(r.Body).Decode(v)
}

// Request wraps an http.Request for convenience.
type Request struct {
	*http.Request
	Vars map[string]string
	Decoder
}

// NewRequest parse the mux vars and returns a new Request instance.
func NewRequest(r *http.Request) *Request {
	return &Request{Request: r, Vars: mux.Vars(r)}
}

// Decode decodes the request using the Decoder.
func (r *Request) Decode(v interface{}) error {
	d := r.Decoder

	if d == nil {
		d = JSONDecode
	}

	return d(r.Request, v)
}

// Handler defines an interface for service an HTTP request.
type Handler interface {
	Serve(*Request) (int, interface{}, error)
}

// ErrorResource represents the error response format that we return.
type ErrorResource struct {
	Err string `json:"error"`
}

// Error implements error interface.
func (e *ErrorResource) Error() string {
	return e.Err
}

// Endpoint wraps a Handler to implement the http.Handler interface.
type Endpoint struct {
	Handler
}

// ServeHTTP implements the http.Handler interface. It will parse the form
// params, then serve the request, finally JSON encoding the returned value.
func (e *Endpoint) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	req := NewRequest(r)

	status, v, err := e.Handler.Serve(req)
	if err != nil {
		if _, ok := err.(*ErrorResource); ok {
			v = err
		} else {
			v = &ErrorResource{Err: err.Error()}
		}
		log.Printf("Error: %v\n", v)
	}

	w.WriteHeader(status)
	json.NewEncoder(w).Encode(v)
}

// Server represents the API.
type Server struct {
	http.Handler
}

// NewServer creates the API routes and returns a new Server instance.
func NewServer(e *Empire) *Server {
	r := newRouter()

	// Apps
	r.Handle("GET", "/apps", &GetApps{e.AppsService})   // hk apps
	r.Handle("POST", "/apps", &PostApps{e.AppsService}) // hk create

	// Deploys
	r.Handle("POST", "/deploys", &PostDeploys{e.DeploysService}) // Deploy an app

	// Releases
	r.Handle("GET", "/apps/{app}/releases", &GetReleases{e.AppsService, e.ReleasesService}) // hk releases

	// Configs
	r.Handle("GET", "/apps/{app}/config-vars", &GetConfigs{e.AppsService, e.ConfigsService})                        // hk env, hk get
	r.Handle("PATCH", "/apps/{app}/config-vars", &PatchConfigs{e.AppsService, e.ReleasesService, e.ConfigsService}) // hk set

	// Processes
	r.Handle("GET", "/apps/{app}/dynos", &GetProcesses{e.AppsService, e.Manager}) // hk dynos

	// Formations
	r.Handle("PATCH", "/apps/{app}/formation", &PatchFormation{e.AppsService, e.ReleasesService, e.Manager}) // hk scale

	n := negroni.Classic()
	n.UseHandler(r)

	return &Server{n}
}

// router is an http router for Handlers.
type router struct {
	*mux.Router
}

// newRouter returns a new router instance.
func newRouter() *router {
	return &router{Router: mux.NewRouter()}
}

// Handle sets up a route for a Handler.
func (r *router) Handle(method, path string, h Handler) {
	r.Router.Handle(path, &Endpoint{Handler: h}).Methods(method)
}

type GetApps struct {
	AppsService AppsService
}

func (h *GetApps) Serve(req *Request) (int, interface{}, error) {
	apps, err := h.AppsService.FindAll()
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, apps, nil
}

type PostAppsForm struct {
	Name string `json:"name"`
	Repo string `json:"repo"`
}

type PostApps struct {
	AppsService AppsService
}

func (h *PostApps) Serve(req *Request) (int, interface{}, error) {
	var form PostAppsForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	app, err := NewApp(AppName(form.Name), Repo(form.Repo))
	if err != nil {
		return http.StatusBadRequest, nil, err
	}

	a, err := h.AppsService.Create(app)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 201, a, nil
}

// PostDeploys is a Handler for the POST /v1/deploys endpoint.
type PostDeploys struct {
	DeploysService DeploysService
}

// PostDeployForm is the form object that represents the POST body.
type PostDeployForm struct {
	Image struct {
		ID   string `json:"id"`
		Repo string `json:"repo"`
	} `json:"image"`
}

// Serve implements the Handler interface.
func (h *PostDeploys) Serve(req *Request) (int, interface{}, error) {
	var form PostDeployForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	d, err := h.DeploysService.Deploy(&Image{
		Repo: Repo(form.Image.Repo),
		ID:   form.Image.ID,
	})
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 201, d, nil
}

type GetReleases struct {
	AppsService     AppsService
	ReleasesService ReleasesService
}

func (h *GetReleases) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	rels, err := h.ReleasesService.FindByApp(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, rels, nil
}

type GetConfigs struct {
	AppsService    AppsService
	ConfigsService ConfigsService
}

func (h *GetConfigs) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	c, err := h.ConfigsService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, c.Vars, nil
}

type PatchConfigs struct {
	AppsService     AppsService
	ReleasesService ReleasesService
	ConfigsService  ConfigsService
}

func (h *PatchConfigs) Serve(req *Request) (int, interface{}, error) {
	var configVars Vars

	if err := req.Decode(&configVars); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	name := AppName(req.Vars["app"])

	// Find app
	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	// Update the config
	c, err := h.ConfigsService.Apply(a, configVars)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// Find current release
	r, err := h.ReleasesService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// If there is an existing release, create a new one
	if r != nil {
		// Create new release based on new config and old slug
		_, err = h.ReleasesService.Create(a, c, r.Slug)
		if err != nil {
			return http.StatusInternalServerError, nil, err
		}
	}

	return 200, c.Vars, nil
}

type GetProcesses struct {
	AppsService AppsService
	Manager     Manager
}

type dyno struct {
	Command string `json:"command"`
	Name    string `json:"name"`
	State   string `json:"state"`
}

func (h *GetProcesses) Serve(req *Request) (int, interface{}, error) {
	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	// Retrieve job states
	js, err := h.Manager.JobStatesByApp(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	// Convert to hk compatible format
	dynos := make([]dyno, len(js))
	for i, j := range js {
		dynos[i] = dyno{
			Command: string(j.Job.Command),
			Name:    string(j.Name),
			State:   j.State,
		}
	}

	return 200, dynos, nil
}

type PatchFormation struct {
	AppsService     AppsService
	ReleasesService ReleasesService
	Manager         Manager
}

type PatchFormationForm struct {
	Updates []struct {
		Process  string `json:"process"` // Refers to process type
		Quantity int    `json:"quantity"`
		Size     string `json:"size"`
	} `json:"updates"`
}

func (h *PatchFormation) Serve(req *Request) (int, interface{}, error) {
	var form PatchFormationForm

	if err := req.Decode(&form); err != nil {
		return http.StatusInternalServerError, nil, err
	}

	name := AppName(req.Vars["app"])

	a, err := h.AppsService.FindByName(name)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if a == nil {
		return http.StatusNotFound, nil, nil
	}

	qm := ProcessQuantityMap{}
	for _, up := range form.Updates {
		qm[ProcessType(up.Process)] = up.Quantity
	}

	r, err := h.ReleasesService.Head(a)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	if r == nil {
		return http.StatusNotFound, nil, nil
	}

	err = h.Manager.ScaleRelease(r, qm)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	return 200, nil, nil
}
<|endoftext|>


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

import (
	"fmt"
	"net/http"
	"text/template"

	"github.com/gorilla/mux"
)

const (
	SkipCheckHttpMethod = ""
	GetMethod           = "GET"
	PutMethod           = "PUT"
	PostMethod          = "POST"
	DeleteMethod        = "DELETE"
)

type HttpServer struct {
	port             string
	address          string
	errTemplate      *template.Template
	notFoundTemplate *template.Template
	Router           HttpRouter
}

type HttpRouter interface {
	HandleFunc(string, func(http.ResponseWriter, *http.Request)) *mux.Route
	Handle(string, http.Handler) *mux.Route
	ServeHTTP(http.ResponseWriter, *http.Request)
}

func NewHttpServer(a string, p string) *HttpServer {
	router := mux.NewRouter()
	s := &HttpServer{Router: router, address: a, port: p}
	return s
}

func (s *HttpServer) SetErrTemplate(t *template.Template) {
	s.errTemplate = t
}

func (s *HttpServer) SetNotFoundTemplate(t *template.Template) {
	s.notFoundTemplate = t
}

func (s *HttpServer) errorHandler(route *Route) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if recoverErr := recover(); recoverErr != nil {
				error := NewError(fmt.Sprintf("\"%v\"", recoverErr))
				w.WriteHeader(500)
				if s.errTemplate != nil {
					s.errTemplate.Execute(w, error)
				} else {
					fmt.Fprintf(w, fmt.Sprintf("\"%v\"", recoverErr))
				}
			}
		}()
		if route.HasIncorrectHttpMethod(r.Method) {
			http.Error(w, "Method not allowed", 405)
			return
		}
		route.HandleFunc(w, r)
	}
}
func (s *HttpServer) NotFound(w http.ResponseWriter, r *http.Request) {

	w.WriteHeader(404)
	if s.notFoundTemplate != nil {
		s.notFoundTemplate.Execute(w, nil)
	} else {
		fmt.Fprintf(w, "Not found")
	}

}

func (s *HttpServer) DeployAtBase(h RouteHandler) {
	s.Deploy("", h)
}

func (s *HttpServer) Deploy(context string, h RouteHandler) {
	routes := h.GetRoutes()
	for _, r := range routes {
		s.Router.HandleFunc(fmt.Sprintf("%s/%s", context, r.Path), s.errorHandler(r))
	}
}

func (s *HttpServer) Start() error {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	http.Handle("/", s.Router)
	//s.Router.NotFoundHandler = http.HandlerFunc(s.NotFound)
	return http.ListenAndServe(fmt.Sprintf("%s:%s", s.address, s.port), nil)
}
<commit_msg>notfound handler test<commit_after>// Copyright 2015 The httpserver Authors. All rights reserved.  Use of this
// source code is governed by a MIT-style license that can be found in the
// LICENSE file.
package httpserver

import (
	"fmt"
	"net/http"
	"reflect"
	"text/template"

	"github.com/gorilla/mux"
)

const (
	SkipCheckHttpMethod = ""
	GetMethod           = "GET"
	PutMethod           = "PUT"
	PostMethod          = "POST"
	DeleteMethod        = "DELETE"
)

type HttpServer struct {
	port             string
	address          string
	errTemplate      *template.Template
	notFoundTemplate *template.Template
	Router           HttpRouter
}

type HttpRouter interface {
	HandleFunc(string, func(http.ResponseWriter, *http.Request)) *mux.Route
	Handle(string, http.Handler) *mux.Route
	ServeHTTP(http.ResponseWriter, *http.Request)
}

func NewHttpServer(a string, p string) *HttpServer {
	router := mux.NewRouter()
	s := &HttpServer{Router: router, address: a, port: p}
	return s
}

func (s *HttpServer) SetErrTemplate(t *template.Template) {
	s.errTemplate = t
}

func (s *HttpServer) SetNotFoundTemplate(t *template.Template) {
	s.notFoundTemplate = t
}

func (s *HttpServer) errorHandler(route *Route) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if recoverErr := recover(); recoverErr != nil {
				error := NewError(fmt.Sprintf("\"%v\"", recoverErr))
				w.WriteHeader(500)
				if s.errTemplate != nil {
					s.errTemplate.Execute(w, error)
				} else {
					fmt.Fprintf(w, fmt.Sprintf("\"%v\"", recoverErr))
				}
			}
		}()
		if route.HasIncorrectHttpMethod(r.Method) {
			http.Error(w, "Method not allowed", 405)
			return
		}
		route.HandleFunc(w, r)
	}
}
func (s *HttpServer) NotFound(w http.ResponseWriter, r *http.Request) {

	w.WriteHeader(404)
	if s.notFoundTemplate != nil {
		s.notFoundTemplate.Execute(w, nil)
	} else {
		fmt.Fprintf(w, "Not found")
	}

}

func (s *HttpServer) DeployAtBase(h RouteHandler) {
	s.Deploy("", h)
}

func (s *HttpServer) Deploy(context string, h RouteHandler) {
	routes := h.GetRoutes()
	for _, r := range routes {
		s.Router.HandleFunc(fmt.Sprintf("%s/%s", context, r.Path), s.errorHandler(r))
	}
}

func (s *HttpServer) Start() error {
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	http.Handle("/", s.Router)
	ss := reflect.ValueOf(&s.Router).Elem()
	typeOfT := ss.Type()
	for i := 0; i < ss.NumField(); i++ {
		f := ss.Field(i)
		fmt.Printf("%d: %s %s = %v\n", i,
			typeOfT.Field(i).Name, f.Type(), f.Interface())
	}
	fmt.Println("egi")
	//http.NotFoundHandler = http.HandlerFunc(s.NotFound)
	return http.ListenAndServe(fmt.Sprintf("%s:%s", s.address, s.port), nil)
}
<|endoftext|>


<commit_before>package osc

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"sync/atomic"
	"time"
	"unsafe"
)

// Common errors.
var (
	ErrAlreadyRunning = errors.New("server is already running")
	ErrNoDispatcher   = errors.New("no dispatcher defined")
	ErrPrematureClose = errors.New("server cannot be closed before calling Listen")
	ErrInvalidTypeTag = errors.New("invalid type tag")
)

// Server is an OSC server.
type Server struct {
	Address     string         // Address is the listening address.
	Listening   chan struct{}  // Listening is a channel used to indicate when the server is running.
	readTimeout time.Duration  // readTimeout is the timeout for reading from a connection.
	dispatcher  *OscDispatcher // Dispatcher that dispatches OSC packets/messages.
	running     bool           // Flag to store if the server is running or not.
	conn        *net.UDPConn   // conn is a UDP connection object.
}

// NewServer returns a new OSC Server.
func NewServer(addr string) (*Server, error) {
	return &Server{
		Address:     addr,
		Listening:   make(chan struct{}),
		readTimeout: 0,
		dispatcher:  NewOscDispatcher(),
	}, nil
}

// connect initializes the server's connection.
func (self *Server) connect() error {
	addr, err := net.ResolveUDPAddr("udp", self.Address)
	if err != nil {
		return err
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}

	dest := (*unsafe.Pointer)(unsafe.Pointer(&self.conn))
	if !atomic.CompareAndSwapPointer(dest, unsafe.Pointer(self.conn), unsafe.Pointer(conn)) {
		return errors.New("could not initialize connection")
	}

	return nil
}

// Close stops the OSC server and closes the connection.
func (self *Server) Close() error {
	if self.conn == nil {
		return nil
	}
	return self.conn.Close()
}

// AddMsgHandler registers a new message handler function for an OSC address. The handler
// is the function called for incoming Messages that match 'address'.
func (self *Server) AddMsgHandler(address string, handler HandlerFunc) error {
	return self.dispatcher.AddMsgHandler(address, handler)
}

// ListenAndServe retrieves incoming OSC packets and dispatches the retrieved OSC packets.
func (self *Server) ListenAndDispatch() error {
	if self.running {
		return ErrAlreadyRunning
	}

	if self.dispatcher == nil {
		return ErrNoDispatcher
	}

	if err := self.connect(); err != nil {
		return err
	}

	// Set read timeout
	if self.readTimeout != 0 {
		if err := self.conn.SetReadDeadline(time.Now().Add(self.readTimeout)); err != nil {
			return err
		}
	}

	self.running = true
	self.Listening <- struct{}{}

	for self.running {
		msg, err := self.readFromConnection()
		if err != nil {
			return err
		}
		self.dispatcher.Dispatch(msg)
	}

	return nil
}

// Listen causes the server to start listening for packets.
func (self *Server) Listen() error {
	if self.conn == nil {
		if err := self.connect(); err != nil {
			return err
		}
	}

	if self.running {
		return ErrAlreadyRunning
	}

	// Set read timeout
	if self.readTimeout != 0 {
		self.conn.SetReadDeadline(time.Now().Add(self.readTimeout))
	}

	self.running = true
	self.Listening <- struct{}{}

	return nil
}

// Listen listens for incoming OSC packets and returns the packet if one is received.
func (self *Server) ReceivePacket() (packet Packet, err error) {
	msg, err := self.readFromConnection()
	if err == nil {
		return msg, nil
	}

	return nil, err
}

// Send sends an OSC Bundle or an OSC Message.
func (self *Server) SendTo(addr net.Addr, packet Packet) (err error) {
	if self.conn == nil {
		return fmt.Errorf("connection not initialized")
	}
	data, err := packet.ToByteArray()
	if err != nil {
		self.conn.Close()
		return err
	}

	written, err := self.conn.WriteTo(data, addr)
	if err != nil {
		fmt.Println("could not write packet")
		self.conn.Close()
		return err
	}
	if written != len(data) {
		errmsg := "only wrote %d bytes of osc packet with length %d"
		return fmt.Errorf(errmsg, written, len(data))
	}

	return nil
}

// readFromConnection retrieves OSC packets.
func (self *Server) readFromConnection() (packet Packet, err error) {
	if self.conn == nil {
		return nil, fmt.Errorf("self.conn is nil")
	}
	data := make([]byte, 65535)
	var n, start int
	n, _, err = self.conn.ReadFromUDP(data)
	packet, err = self.readPacket(bufio.NewReader(bytes.NewBuffer(data)), &start, n)

	return packet, nil
}

// receivePacket receives an OSC packet from the given reader.
func (self *Server) readPacket(reader *bufio.Reader, start *int, end int) (packet Packet, err error) {
	var buf []byte
	buf, err = reader.Peek(1)
	if err != nil {
		return nil, err
	}

	// An OSC Message starts with a '/'
	if buf[0] == '/' {
		packet, err = self.readMessage(reader, start)
		if err != nil {
			return nil, err
		}
	} else if buf[0] == '#' { // An OSC bundle starts with a '#'
		packet, err = self.readBundle(reader, start, end)
		if err != nil {
			return nil, err
		}
	}

	return packet, nil
}

// readBundle reads an Bundle from reader.
func (self *Server) readBundle(reader *bufio.Reader, start *int, end int) (bundle *Bundle, err error) {
	// Read the '#bundle' OSC string
	var startTag string
	var n int
	startTag, n, err = readPaddedString(reader)
	if err != nil {
		return nil, err
	}
	*start += n

	if startTag != BundleTag {
		return nil, fmt.Errorf("Invalid bundle start tag: %s", startTag)
	}

	// Read the timetag
	var timeTag uint64
	if err := binary.Read(reader, binary.BigEndian, &timeTag); err != nil {
		return nil, err
	}
	*start += 8

	// Create a new bundle
	bundle = NewBundle(timetagToTime(timeTag))

	// Read until the end of the buffer
	for *start < end {
		// Read the size of the bundle element
		var length int32
		err = binary.Read(reader, binary.BigEndian, &length)
		*start += 4
		if err != nil {
			return nil, err
		}

		var packet Packet
		packet, err = self.readPacket(reader, start, end)
		if err != nil {
			return nil, err
		}
		bundle.Append(packet)
	}

	return bundle, nil
}

// readMessage reads one OSC Message from reader.
func (self *Server) readMessage(reader *bufio.Reader, start *int) (msg *Message, err error) {
	// First, read the OSC address
	var n int
	address, n, err := readPaddedString(reader)
	if err != nil {
		return nil, err
	}
	*start += n

	// Create a new message
	msg = &Message{address: address}

	// Read all arguments
	if err = self.readArguments(msg, reader, start); err != nil {
		return nil, err
	}

	return msg, nil
}

// readArguments reads all arguments from the reader and adds it to the OSC message.
func (self *Server) readArguments(msg *Message, reader *bufio.Reader, start *int) error {
	// Read the type tag string
	var n int
	typetags, n, err := readPaddedString(reader)
	if err != nil {
		return err
	}
	*start += n

	// If the typetag doesn't start with ',', it's not valid
	if typetags[0] != ',' {
		return ErrInvalidTypeTag
	}

	// Remove ',' from the type tag
	typetags = typetags[1:]

	for _, c := range typetags {
		switch c {
		default:
			return fmt.Errorf("Unsupported type tag: %c", c)

		// int32
		case 'i':
			var i int32
			if err = binary.Read(reader, binary.BigEndian, &i); err != nil {
				return err
			}
			*start += 4
			msg.Append(i)

		// int64
		case 'h':
			var i int64
			if err = binary.Read(reader, binary.BigEndian, &i); err != nil {
				return err
			}
			*start += 8
			msg.Append(i)

		// float32
		case 'f':
			var f float32
			if err = binary.Read(reader, binary.BigEndian, &f); err != nil {
				return err
			}
			*start += 4
			msg.Append(f)

		// float64/double
		case 'd':
			var d float64
			if err = binary.Read(reader, binary.BigEndian, &d); err != nil {
				return err
			}
			*start += 8
			msg.Append(d)

		// string
		case 's':
			// TODO: fix reading string value
			var s string
			if s, _, err = readPaddedString(reader); err != nil {
				return err
			}
			*start += len(s) + padBytesNeeded(len(s))
			msg.Append(s)

		// blob
		case 'b':
			var buf []byte
			var n int
			if buf, n, err = readBlob(reader); err != nil {
				return err
			}
			*start += n
			msg.Append(buf)

		// OSC Time Tag
		case 't':
			var tt uint64
			if err = binary.Read(reader, binary.BigEndian, &tt); err != nil {
				return nil
			}
			*start += 8
			msg.Append(Timetag(tt))

		// True
		case 'T':
			msg.Append(true)

		// False
		case 'F':
			msg.Append(false)
		}
	}

	return nil
}

// readBlob reads an OSC Blob from the blob byte array. Padding bytes are removed
// from the reader and not returned.
func readBlob(reader *bufio.Reader) (blob []byte, n int, err error) {
	// First, get the length
	var blobLen int
	if err = binary.Read(reader, binary.BigEndian, &blobLen); err != nil {
		return nil, 0, err
	}
	n = 4 + blobLen

	// Read the data
	blob = make([]byte, blobLen)
	if _, err = reader.Read(blob); err != nil {
		return nil, 0, err
	}

	// Remove the padding bytes
	numPadBytes := padBytesNeeded(blobLen)
	if numPadBytes > 0 {
		n += numPadBytes
		dummy := make([]byte, numPadBytes)
		if _, err = reader.Read(dummy); err != nil {
			return nil, 0, err
		}
	}

	return blob, n, nil
}
<commit_msg>get rid of ReceivePacket method<commit_after>package osc

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"sync/atomic"
	"time"
	"unsafe"
)

// Common errors.
var (
	ErrAlreadyRunning = errors.New("server is already running")
	ErrNoDispatcher   = errors.New("no dispatcher defined")
	ErrPrematureClose = errors.New("server cannot be closed before calling Listen")
	ErrInvalidTypeTag = errors.New("invalid type tag")
)

// Server is an OSC server.
type Server struct {
	Address     string         // Address is the listening address.
	Listening   chan struct{}  // Listening is a channel used to indicate when the server is running.
	readTimeout time.Duration  // readTimeout is the timeout for reading from a connection.
	dispatcher  *OscDispatcher // Dispatcher that dispatches OSC packets/messages.
	running     bool           // Flag to store if the server is running or not.
	conn        *net.UDPConn   // conn is a UDP connection object.
}

// NewServer returns a new OSC Server.
func NewServer(addr string) (*Server, error) {
	return &Server{
		Address:     addr,
		Listening:   make(chan struct{}),
		readTimeout: 0,
		dispatcher:  NewOscDispatcher(),
	}, nil
}

// connect initializes the server's connection.
func (self *Server) connect() error {
	addr, err := net.ResolveUDPAddr("udp", self.Address)
	if err != nil {
		return err
	}

	conn, err := net.ListenUDP("udp", addr)
	if err != nil {
		return err
	}

	dest := (*unsafe.Pointer)(unsafe.Pointer(&self.conn))
	if !atomic.CompareAndSwapPointer(dest, unsafe.Pointer(self.conn), unsafe.Pointer(conn)) {
		return errors.New("could not initialize connection")
	}

	return nil
}

// Close stops the OSC server and closes the connection.
func (self *Server) Close() error {
	if self.conn == nil {
		return nil
	}
	return self.conn.Close()
}

// AddMsgHandler registers a new message handler function for an OSC address. The handler
// is the function called for incoming Messages that match 'address'.
func (self *Server) AddMsgHandler(address string, handler HandlerFunc) error {
	return self.dispatcher.AddMsgHandler(address, handler)
}

// ListenAndServe retrieves incoming OSC packets and dispatches the retrieved OSC packets.
func (self *Server) ListenAndDispatch() error {
	if self.running {
		return ErrAlreadyRunning
	}

	if self.dispatcher == nil {
		return ErrNoDispatcher
	}

	if err := self.connect(); err != nil {
		return err
	}

	// Set read timeout
	if self.readTimeout != 0 {
		if err := self.conn.SetReadDeadline(time.Now().Add(self.readTimeout)); err != nil {
			return err
		}
	}

	self.running = true
	self.Listening <- struct{}{}

	for self.running {
		msg, err := self.readFromConnection()
		if err != nil {
			return err
		}
		self.dispatcher.Dispatch(msg)
	}

	return nil
}

// Listen causes the server to start listening for packets.
func (self *Server) Listen() error {
	if self.conn == nil {
		if err := self.connect(); err != nil {
			return err
		}
	}

	if self.running {
		return ErrAlreadyRunning
	}

	// Set read timeout
	if self.readTimeout != 0 {
		self.conn.SetReadDeadline(time.Now().Add(self.readTimeout))
	}

	self.running = true
	self.Listening <- struct{}{}

	return nil
}

// Send sends an OSC Bundle or an OSC Message.
func (self *Server) SendTo(addr net.Addr, packet Packet) (err error) {
	if self.conn == nil {
		return fmt.Errorf("connection not initialized")
	}
	data, err := packet.ToByteArray()
	if err != nil {
		self.conn.Close()
		return err
	}

	written, err := self.conn.WriteTo(data, addr)
	if err != nil {
		fmt.Println("could not write packet")
		self.conn.Close()
		return err
	}
	if written != len(data) {
		errmsg := "only wrote %d bytes of osc packet with length %d"
		return fmt.Errorf(errmsg, written, len(data))
	}

	return nil
}

// readFromConnection retrieves OSC packets.
func (self *Server) readFromConnection() (packet Packet, err error) {
	if self.conn == nil {
		return nil, fmt.Errorf("self.conn is nil")
	}
	data := make([]byte, 65535)
	var n, start int
	n, _, err = self.conn.ReadFromUDP(data)
	packet, err = self.readPacket(bufio.NewReader(bytes.NewBuffer(data)), &start, n)

	return packet, nil
}

// receivePacket receives an OSC packet from the given reader.
func (self *Server) readPacket(reader *bufio.Reader, start *int, end int) (packet Packet, err error) {
	var buf []byte
	buf, err = reader.Peek(1)
	if err != nil {
		return nil, err
	}

	// An OSC Message starts with a '/'
	if buf[0] == '/' {
		packet, err = self.readMessage(reader, start)
		if err != nil {
			return nil, err
		}
	} else if buf[0] == '#' { // An OSC bundle starts with a '#'
		packet, err = self.readBundle(reader, start, end)
		if err != nil {
			return nil, err
		}
	}

	return packet, nil
}

// readBundle reads an Bundle from reader.
func (self *Server) readBundle(reader *bufio.Reader, start *int, end int) (bundle *Bundle, err error) {
	// Read the '#bundle' OSC string
	var startTag string
	var n int
	startTag, n, err = readPaddedString(reader)
	if err != nil {
		return nil, err
	}
	*start += n

	if startTag != BundleTag {
		return nil, fmt.Errorf("Invalid bundle start tag: %s", startTag)
	}

	// Read the timetag
	var timeTag uint64
	if err := binary.Read(reader, binary.BigEndian, &timeTag); err != nil {
		return nil, err
	}
	*start += 8

	// Create a new bundle
	bundle = NewBundle(timetagToTime(timeTag))

	// Read until the end of the buffer
	for *start < end {
		// Read the size of the bundle element
		var length int32
		err = binary.Read(reader, binary.BigEndian, &length)
		*start += 4
		if err != nil {
			return nil, err
		}

		var packet Packet
		packet, err = self.readPacket(reader, start, end)
		if err != nil {
			return nil, err
		}
		bundle.Append(packet)
	}

	return bundle, nil
}

// readMessage reads one OSC Message from reader.
func (self *Server) readMessage(reader *bufio.Reader, start *int) (msg *Message, err error) {
	// First, read the OSC address
	var n int
	address, n, err := readPaddedString(reader)
	if err != nil {
		return nil, err
	}
	*start += n

	// Create a new message
	msg = &Message{address: address}

	// Read all arguments
	if err = self.readArguments(msg, reader, start); err != nil {
		return nil, err
	}

	return msg, nil
}

// readArguments reads all arguments from the reader and adds it to the OSC message.
func (self *Server) readArguments(msg *Message, reader *bufio.Reader, start *int) error {
	// Read the type tag string
	var n int
	typetags, n, err := readPaddedString(reader)
	if err != nil {
		return err
	}
	*start += n

	// If the typetag doesn't start with ',', it's not valid
	if typetags[0] != ',' {
		return ErrInvalidTypeTag
	}

	// Remove ',' from the type tag
	typetags = typetags[1:]

	for _, c := range typetags {
		switch c {
		default:
			return fmt.Errorf("Unsupported type tag: %c", c)

		// int32
		case 'i':
			var i int32
			if err = binary.Read(reader, binary.BigEndian, &i); err != nil {
				return err
			}
			*start += 4
			msg.Append(i)

		// int64
		case 'h':
			var i int64
			if err = binary.Read(reader, binary.BigEndian, &i); err != nil {
				return err
			}
			*start += 8
			msg.Append(i)

		// float32
		case 'f':
			var f float32
			if err = binary.Read(reader, binary.BigEndian, &f); err != nil {
				return err
			}
			*start += 4
			msg.Append(f)

		// float64/double
		case 'd':
			var d float64
			if err = binary.Read(reader, binary.BigEndian, &d); err != nil {
				return err
			}
			*start += 8
			msg.Append(d)

		// string
		case 's':
			// TODO: fix reading string value
			var s string
			if s, _, err = readPaddedString(reader); err != nil {
				return err
			}
			*start += len(s) + padBytesNeeded(len(s))
			msg.Append(s)

		// blob
		case 'b':
			var buf []byte
			var n int
			if buf, n, err = readBlob(reader); err != nil {
				return err
			}
			*start += n
			msg.Append(buf)

		// OSC Time Tag
		case 't':
			var tt uint64
			if err = binary.Read(reader, binary.BigEndian, &tt); err != nil {
				return nil
			}
			*start += 8
			msg.Append(Timetag(tt))

		// True
		case 'T':
			msg.Append(true)

		// False
		case 'F':
			msg.Append(false)
		}
	}

	return nil
}

// readBlob reads an OSC Blob from the blob byte array. Padding bytes are removed
// from the reader and not returned.
func readBlob(reader *bufio.Reader) (blob []byte, n int, err error) {
	// First, get the length
	var blobLen int
	if err = binary.Read(reader, binary.BigEndian, &blobLen); err != nil {
		return nil, 0, err
	}
	n = 4 + blobLen

	// Read the data
	blob = make([]byte, blobLen)
	if _, err = reader.Read(blob); err != nil {
		return nil, 0, err
	}

	// Remove the padding bytes
	numPadBytes := padBytesNeeded(blobLen)
	if numPadBytes > 0 {
		n += numPadBytes
		dummy := make([]byte, numPadBytes)
		if _, err = reader.Read(dummy); err != nil {
			return nil, 0, err
		}
	}

	return blob, n, nil
}
<|endoftext|>


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

package websocket

import (
	"bufio"
	"errors"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// HandshakeError describes an error with the handshake from the peer.
type HandshakeError struct {
	message string
}

func (e HandshakeError) Error() string { return e.message }

// Upgrader specifies parameters for upgrading an HTTP connection to a
// WebSocket connection.
type Upgrader struct {
	// HandshakeTimeout specifies the duration for the handshake to complete.
	HandshakeTimeout time.Duration

	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
	// size is zero, then a default value of 4096 is used. The I/O buffer sizes
	// do not limit the size of the messages that can be sent or received.
	ReadBufferSize, WriteBufferSize int

	// Subprotocols specifies the server's supported protocols in order of
	// preference. If this field is set, then the Upgrade method negotiates a
	// subprotocol by selecting the first match in this list with a protocol
	// requested by the client.
	Subprotocols []string

	// Error specifies the function for generating HTTP error responses. If Error
	// is nil, then http.Error is used to generate the HTTP response.
	Error func(w http.ResponseWriter, r *http.Request, status int, reason error)

	// CheckOrigin returns true if the request Origin header is acceptable. If
	// CheckOrigin is nil, the host in the Origin header must not be set or
	// must match the host of the request.
	CheckOrigin func(r *http.Request) bool
}

func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
	err := HandshakeError{reason}
	if u.Error != nil {
		u.Error(w, r, status, err)
	} else {
		http.Error(w, http.StatusText(status), status)
	}
	return nil, err
}

// checkSameOrigin returns true if the origin is not set or is equal to the request host.
func checkSameOrigin(r *http.Request) bool {
	origin := r.Header["Origin"]
	if len(origin) == 0 {
		return true
	}
	u, err := url.Parse(origin[0])
	if err != nil {
		return false
	}
	return u.Host == r.Host
}

func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
	if u.Subprotocols != nil {
		clientProtocols := Subprotocols(r)
		for _, serverProtocol := range u.Subprotocols {
			for _, clientProtocol := range clientProtocols {
				if clientProtocol == serverProtocol {
					return clientProtocol
				}
			}
		}
	} else if responseHeader != nil {
		return responseHeader.Get("Sec-Websocket-Protocol")
	}
	return ""
}

// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// application negotiated subprotocol (Sec-Websocket-Protocol).
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
	if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
	}

	if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
	}

	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
	}

	checkOrigin := u.CheckOrigin
	if checkOrigin == nil {
		checkOrigin = checkSameOrigin
	}
	if !checkOrigin(r) {
		return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
	}

	challengeKey := r.Header.Get("Sec-Websocket-Key")
	if challengeKey == "" {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
	}

	subprotocol := u.selectSubprotocol(r, responseHeader)

	var (
		netConn net.Conn
		br      *bufio.Reader
		err     error
	)

	h, ok := w.(http.Hijacker)
	if !ok {
		return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
	}
	var rw *bufio.ReadWriter
	netConn, rw, err = h.Hijack()
	if err != nil {
		return u.returnError(w, r, http.StatusInternalServerError, err.Error())
	}
	br = rw.Reader

	if br.Buffered() > 0 {
		netConn.Close()
		return nil, errors.New("websocket: client sent data before handshake is complete")
	}

	c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
	c.subprotocol = subprotocol

	p := c.writeBuf[:0]
	p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
	p = append(p, computeAcceptKey(challengeKey)...)
	p = append(p, "\r\n"...)
	if c.subprotocol != "" {
		p = append(p, "Sec-Websocket-Protocol: "...)
		p = append(p, c.subprotocol...)
		p = append(p, "\r\n"...)
	}
	for k, vs := range responseHeader {
		if k == "Sec-Websocket-Protocol" {
			continue
		}
		for _, v := range vs {
			p = append(p, k...)
			p = append(p, ": "...)
			for i := 0; i < len(v); i++ {
				b := v[i]
				if b <= 31 {
					// prevent response splitting.
					b = ' '
				}
				p = append(p, b)
			}
			p = append(p, "\r\n"...)
		}
	}
	p = append(p, "\r\n"...)

	// Clear deadlines set by HTTP server.
	netConn.SetDeadline(time.Time{})

	if u.HandshakeTimeout > 0 {
		netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
	}
	if _, err = netConn.Write(p); err != nil {
		netConn.Close()
		return nil, err
	}
	if u.HandshakeTimeout > 0 {
		netConn.SetWriteDeadline(time.Time{})
	}

	return c, nil
}

// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// This function is deprecated, use websocket.Upgrader instead.
//
// The application is responsible for checking the request origin before
// calling Upgrade. An example implementation of the same origin policy is:
//
//	if req.Header.Get("Origin") != "http://"+req.Host {
//		http.Error(w, "Origin not allowed", 403)
//		return
//	}
//
// If the endpoint supports subprotocols, then the application is responsible
// for negotiating the protocol used on the connection. Use the Subprotocols()
// function to get the subprotocols requested by the client. Use the
// Sec-Websocket-Protocol response header to specify the subprotocol selected
// by the application.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// negotiated subprotocol (Sec-Websocket-Protocol).
//
// The connection buffers IO to the underlying network connection. The
// readBufSize and writeBufSize parameters specify the size of the buffers to
// use. Messages can be larger than the buffers.
//
// If the request is not a valid WebSocket handshake, then Upgrade returns an
// error of type HandshakeError. Applications should handle this error by
// replying to the client with an HTTP error response.
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
	u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
	u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
		// don't return errors to maintain backwards compatibility
	}
	u.CheckOrigin = func(r *http.Request) bool {
		// allow all connections by default
		return true
	}
	return u.Upgrade(w, r, responseHeader)
}

// Subprotocols returns the subprotocols requested by the client in the
// Sec-Websocket-Protocol header.
func Subprotocols(r *http.Request) []string {
	h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
	if h == "" {
		return nil
	}
	protocols := strings.Split(h, ",")
	for i := range protocols {
		protocols[i] = strings.TrimSpace(protocols[i])
	}
	return protocols
}
<commit_msg>ignore other previously sent headers in upgrade<commit_after>// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package websocket

import (
	"bufio"
	"errors"
	"net"
	"net/http"
	"net/url"
	"strings"
	"time"
)

// HandshakeError describes an error with the handshake from the peer.
type HandshakeError struct {
	message string
}

func (e HandshakeError) Error() string { return e.message }

// Upgrader specifies parameters for upgrading an HTTP connection to a
// WebSocket connection.
type Upgrader struct {
	// HandshakeTimeout specifies the duration for the handshake to complete.
	HandshakeTimeout time.Duration

	// ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer
	// size is zero, then a default value of 4096 is used. The I/O buffer sizes
	// do not limit the size of the messages that can be sent or received.
	ReadBufferSize, WriteBufferSize int

	// Subprotocols specifies the server's supported protocols in order of
	// preference. If this field is set, then the Upgrade method negotiates a
	// subprotocol by selecting the first match in this list with a protocol
	// requested by the client.
	Subprotocols []string

	// Error specifies the function for generating HTTP error responses. If Error
	// is nil, then http.Error is used to generate the HTTP response.
	Error func(w http.ResponseWriter, r *http.Request, status int, reason error)

	// CheckOrigin returns true if the request Origin header is acceptable. If
	// CheckOrigin is nil, the host in the Origin header must not be set or
	// must match the host of the request.
	CheckOrigin func(r *http.Request) bool
}

func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) {
	err := HandshakeError{reason}
	if u.Error != nil {
		u.Error(w, r, status, err)
	} else {
		http.Error(w, http.StatusText(status), status)
	}
	return nil, err
}

// checkSameOrigin returns true if the origin is not set or is equal to the request host.
func checkSameOrigin(r *http.Request) bool {
	origin := r.Header["Origin"]
	if len(origin) == 0 {
		return true
	}
	u, err := url.Parse(origin[0])
	if err != nil {
		return false
	}
	return u.Host == r.Host
}

func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string {
	if u.Subprotocols != nil {
		clientProtocols := Subprotocols(r)
		for _, serverProtocol := range u.Subprotocols {
			for _, clientProtocol := range clientProtocols {
				if clientProtocol == serverProtocol {
					return clientProtocol
				}
			}
		}
	} else if responseHeader != nil {
		return responseHeader.Get("Sec-Websocket-Protocol")
	}
	return ""
}

// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// application negotiated subprotocol (Sec-Websocket-Protocol).
func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) {
	if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13")
	}

	if !tokenListContainsValue(r.Header, "Connection", "upgrade") {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'")
	}

	if !tokenListContainsValue(r.Header, "Upgrade", "websocket") {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'")
	}

	checkOrigin := u.CheckOrigin
	if checkOrigin == nil {
		checkOrigin = checkSameOrigin
	}
	if !checkOrigin(r) {
		return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed")
	}

	challengeKey := r.Header.Get("Sec-Websocket-Key")
	if challengeKey == "" {
		return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank")
	}

	subprotocol := u.selectSubprotocol(r, responseHeader)

	var (
		netConn net.Conn
		br      *bufio.Reader
		err     error
	)

	h, ok := w.(http.Hijacker)
	if !ok {
		return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker")
	}
	var rw *bufio.ReadWriter
	netConn, rw, err = h.Hijack()
	if err != nil {
		return u.returnError(w, r, http.StatusInternalServerError, err.Error())
	}
	br = rw.Reader

	if br.Buffered() > 0 {
		netConn.Close()
		return nil, errors.New("websocket: client sent data before handshake is complete")
	}

	c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize)
	c.subprotocol = subprotocol

	p := c.writeBuf[:0]
	p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...)
	p = append(p, computeAcceptKey(challengeKey)...)
	p = append(p, "\r\n"...)
	if c.subprotocol != "" {
		p = append(p, "Sec-Websocket-Protocol: "...)
		p = append(p, c.subprotocol...)
		p = append(p, "\r\n"...)
	}
	for k, vs := range responseHeader {
		if k == "Upgrade" || k == "Connection" || k == "Sec-Websocket-Accept" || k == "Sec-Websocket-Protocol" {
			continue
		}
		for _, v := range vs {
			p = append(p, k...)
			p = append(p, ": "...)
			for i := 0; i < len(v); i++ {
				b := v[i]
				if b <= 31 {
					// prevent response splitting.
					b = ' '
				}
				p = append(p, b)
			}
			p = append(p, "\r\n"...)
		}
	}
	p = append(p, "\r\n"...)

	// Clear deadlines set by HTTP server.
	netConn.SetDeadline(time.Time{})

	if u.HandshakeTimeout > 0 {
		netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout))
	}
	if _, err = netConn.Write(p); err != nil {
		netConn.Close()
		return nil, err
	}
	if u.HandshakeTimeout > 0 {
		netConn.SetWriteDeadline(time.Time{})
	}

	return c, nil
}

// Upgrade upgrades the HTTP server connection to the WebSocket protocol.
//
// This function is deprecated, use websocket.Upgrader instead.
//
// The application is responsible for checking the request origin before
// calling Upgrade. An example implementation of the same origin policy is:
//
//	if req.Header.Get("Origin") != "http://"+req.Host {
//		http.Error(w, "Origin not allowed", 403)
//		return
//	}
//
// If the endpoint supports subprotocols, then the application is responsible
// for negotiating the protocol used on the connection. Use the Subprotocols()
// function to get the subprotocols requested by the client. Use the
// Sec-Websocket-Protocol response header to specify the subprotocol selected
// by the application.
//
// The responseHeader is included in the response to the client's upgrade
// request. Use the responseHeader to specify cookies (Set-Cookie) and the
// negotiated subprotocol (Sec-Websocket-Protocol).
//
// The connection buffers IO to the underlying network connection. The
// readBufSize and writeBufSize parameters specify the size of the buffers to
// use. Messages can be larger than the buffers.
//
// If the request is not a valid WebSocket handshake, then Upgrade returns an
// error of type HandshakeError. Applications should handle this error by
// replying to the client with an HTTP error response.
func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) {
	u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize}
	u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) {
		// don't return errors to maintain backwards compatibility
	}
	u.CheckOrigin = func(r *http.Request) bool {
		// allow all connections by default
		return true
	}
	return u.Upgrade(w, r, responseHeader)
}

// Subprotocols returns the subprotocols requested by the client in the
// Sec-Websocket-Protocol header.
func Subprotocols(r *http.Request) []string {
	h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol"))
	if h == "" {
		return nil
	}
	protocols := strings.Split(h, ",")
	for i := range protocols {
		protocols[i] = strings.TrimSpace(protocols[i])
	}
	return protocols
}
<|endoftext|>


<commit_before>package main

import (
	"log"
)

var read_buf []byte = make([]byte, BUF_SIZE)

func server() {
	conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: TUNTUNTUN_SERVER_PORT})
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Server receives packets on port 71<commit_after>package main

import (
	"log"
	"net"
)

var read_buf []byte = make([]byte, BUF_SIZE)

func server() {
	conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: TUNTUNTUN_SERVER_PORT})
	if err != nil {
		log.Fatal(err)
	}

	for {
		count, remote_addr, err := conn.ReadFromUDP(read_buf)
		if err != nil {
			log.Fatal(err)
		}

		log.Printf("Got %d bytes from %s addressed to %s",
			count, remote_addr,
			get_ip_dest(read_buf[ENVELOPE_LENGTH:]))
	}
}
<|endoftext|>


<commit_before>package endly

import (
	"encoding/json"
	"fmt"
	"github.com/viant/toolbox"
	"log"
	"net/http"
)

type Request struct {
	Data           map[string]interface{}
	ServiceRequest interface{}
}

type Response struct {
	Status   string
	Error    string
	Response interface{}
	Info     *SessionInfo
}

type Server struct {
	port    string
	manager Manager
}

func (s *Server) requestService(serviceName, method string, httpRequest *http.Request, httpResponse http.ResponseWriter) (*Response, error) {
	var service Service
	var serviceRequest interface{}
	var err error
	service, err = s.manager.Service(toolbox.AsString(serviceName))
	if err != nil {
		return nil, err
	}
	serviceRequest, err = service.NewRequest(toolbox.AsString(method))
	if err != nil {
		return nil, err
	}
	request := &Request{
		ServiceRequest: serviceRequest,
	}
	err = json.NewDecoder(httpRequest.Body).Decode(request)
	if err != nil {
		return nil, err
	}
	context := s.manager.NewContext(toolbox.NewContext())
	defer context.Close()
	state := context.State()
	state.Apply(request.Data)
	serviceResponse := service.Run(context, request.ServiceRequest)

	var sessionInfo = context.SessionInfo()
	var response = &Response{
		Status:   serviceResponse.Status,
		Error:    serviceResponse.Error,
		Response: serviceResponse.Response,
		Info:     sessionInfo,
	}
	return response, nil
}

func (s *Server) routeHandler(serviceRouting *toolbox.ServiceRouting, httpRequest *http.Request, httpResponse http.ResponseWriter, uriParameters map[string]interface{}) (err error) {
	defer func() {
		if err != nil {
			serviceResponse := &Response{
				Error: fmt.Sprintf("%v", err),
			}
			err = toolbox.WriteServiceRoutingResponse(httpResponse, httpRequest, serviceRouting, serviceResponse)
		}

	}()

	serviceName, ok := uriParameters["service"]
	if !ok {
		return fmt.Errorf("Service name was missing %v", uriParameters)
	}
	method, ok := uriParameters["method"]
	if !ok {
		return fmt.Errorf("method was missing %v", uriParameters)
	}

	var response *Response
	response, err = s.requestService(toolbox.AsString(serviceName), toolbox.AsString(method), httpRequest, httpResponse)
	if err != nil {
		return err
	}

	err = toolbox.WriteServiceRoutingResponse(httpResponse, httpRequest, serviceRouting, response)

	if err != nil {
		return err
	}
	return nil

}

func (s *Server) Start() error {

	router := toolbox.NewServiceRouter(
		toolbox.ServiceRouting{
			HTTPMethod:     "POST",
			URI:            "/v1/endly/service/{service}/{method}/",
			Handler:        s.requestService,
			HandlerInvoker: s.routeHandler,
			Parameters:     []string{"service", "method", "@httpRequest", "@httpResponseWriter"},
		})

	http.HandleFunc("/v1/", func(response http.ResponseWriter, reader *http.Request) {
		err := router.Route(response, reader)
		if err != nil {
			response.WriteHeader(http.StatusInternalServerError)
		}
	})
	fmt.Printf("Started test server on port %v\n", s.port)
	log.Fatal(http.ListenAndServe(":"+s.port, nil))
	return nil
}

func NewServer(port string) *Server {
	return &Server{
		port:    port,
		manager: GetManager(),
	}
}
<commit_msg>added request state to the response<commit_after>package endly

import (
	"encoding/json"
	"fmt"
	"github.com/viant/toolbox"
	"log"
	"net/http"
)

type Request struct {
	Data           map[string]interface{}
	ServiceRequest interface{}
}

type Response struct {
	Status   string
	Error    string
	Response interface{}
	Info     *SessionInfo
	State    map[string]interface{}
}

type Server struct {
	port    string
	manager Manager
}

func (s *Server) requestService(serviceName, method string, httpRequest *http.Request, httpResponse http.ResponseWriter) (*Response, error) {
	var service Service
	var serviceRequest interface{}
	var err error
	service, err = s.manager.Service(toolbox.AsString(serviceName))
	if err != nil {
		return nil, err
	}
	serviceRequest, err = service.NewRequest(toolbox.AsString(method))
	if err != nil {
		return nil, err
	}
	request := &Request{
		ServiceRequest: serviceRequest,
	}
	err = json.NewDecoder(httpRequest.Body).Decode(request)
	if err != nil {
		return nil, err
	}
	context := s.manager.NewContext(toolbox.NewContext())
	defer context.Close()
	state := context.State()
	state.Apply(request.Data)
	serviceResponse := service.Run(context, request.ServiceRequest)
	var sessionInfo = context.SessionInfo()
	var response = &Response{
		Status:   serviceResponse.Status,
		Error:    serviceResponse.Error,
		Response: serviceResponse.Response,
		Info:     sessionInfo,
		State:    context.State(),
	}
	return response, nil
}

func (s *Server) routeHandler(serviceRouting *toolbox.ServiceRouting, httpRequest *http.Request, httpResponse http.ResponseWriter, uriParameters map[string]interface{}) (err error) {
	defer func() {
		if err != nil {
			serviceResponse := &Response{
				Error: fmt.Sprintf("%v", err),
			}
			err = toolbox.WriteServiceRoutingResponse(httpResponse, httpRequest, serviceRouting, serviceResponse)
		}

	}()

	serviceName, ok := uriParameters["service"]
	if !ok {
		return fmt.Errorf("Service name was missing %v", uriParameters)
	}
	method, ok := uriParameters["method"]
	if !ok {
		return fmt.Errorf("method was missing %v", uriParameters)
	}

	var response *Response
	response, err = s.requestService(toolbox.AsString(serviceName), toolbox.AsString(method), httpRequest, httpResponse)
	if err != nil {
		return err
	}

	err = toolbox.WriteServiceRoutingResponse(httpResponse, httpRequest, serviceRouting, response)

	if err != nil {
		return err
	}
	return nil

}

func (s *Server) Start() error {

	router := toolbox.NewServiceRouter(
		toolbox.ServiceRouting{
			HTTPMethod:     "POST",
			URI:            "/v1/endly/service/{service}/{method}/",
			Handler:        s.requestService,
			HandlerInvoker: s.routeHandler,
			Parameters:     []string{"service", "method", "@httpRequest", "@httpResponseWriter"},
		})

	http.HandleFunc("/v1/", func(response http.ResponseWriter, reader *http.Request) {
		err := router.Route(response, reader)
		if err != nil {
			response.WriteHeader(http.StatusInternalServerError)
		}
	})
	fmt.Printf("Started test server on port %v\n", s.port)
	log.Fatal(http.ListenAndServe(":"+s.port, nil))
	return nil
}

func NewServer(port string) *Server {
	return &Server{
		port:    port,
		manager: GetManager(),
	}
}
<|endoftext|>