<commit_before>package s3api

import (
	"encoding/xml"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/google/uuid"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type InitiateMultipartUploadResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult"`
	s3.CreateMultipartUploadOutput
}

func (s3a *S3ApiServer) createMultipartUpload(input *s3.CreateMultipartUploadInput) (output *InitiateMultipartUploadResult, code s3err.ErrorCode) {

	glog.V(2).Infof("createMultipartUpload input %v", input)

	uploadId, _ := uuid.NewRandom()
	uploadIdString := uploadId.String()

	if err := s3a.mkdir(s3a.genUploadsFolder(*input.Bucket), uploadIdString, func(entry *filer_pb.Entry) {
		if entry.Extended == nil {
			entry.Extended = make(map[string][]byte)
		}
		entry.Extended["key"] = []byte(*input.Key)
		for k, v := range input.Metadata {
			entry.Extended[k] = []byte(*v)
		}
		if input.ContentType != nil {
			entry.Attributes.Mime = *input.ContentType
		}
	}); err != nil {
		glog.Errorf("NewMultipartUpload error: %v", err)
		return nil, s3err.ErrInternalError
	}

	output = &InitiateMultipartUploadResult{
		CreateMultipartUploadOutput: s3.CreateMultipartUploadOutput{
			Bucket:   input.Bucket,
			Key:      objectKey(input.Key),
			UploadId: aws.String(uploadIdString),
		},
	}

	return
}

type CompleteMultipartUploadResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult"`
	s3.CompleteMultipartUploadOutput
}

func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput) (output *CompleteMultipartUploadResult, code s3err.ErrorCode) {

	glog.V(2).Infof("completeMultipartUpload input %v", input)

	uploadDirectory := s3a.genUploadsFolder(*input.Bucket) + "/" + *input.UploadId

	entries, _, err := s3a.list(uploadDirectory, "", "", false, maxPartsList)
	if err != nil || len(entries) == 0 {
		glog.Errorf("completeMultipartUpload %s %s error: %v, entries:%d", *input.Bucket, *input.UploadId, err, len(entries))
		return nil, s3err.ErrNoSuchUpload
	}

	pentry, err := s3a.getEntry(s3a.genUploadsFolder(*input.Bucket), *input.UploadId)
	if err != nil {
		glog.Errorf("completeMultipartUpload %s %s error: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}

	var finalParts []*filer_pb.FileChunk
	var offset int64
	var mime string

	for _, entry := range entries {
		if strings.HasSuffix(entry.Name, ".part") && !entry.IsDirectory {
			if entry.Name == "0001.part" && entry.Attributes.Mime != "" {
				mime = entry.Attributes.Mime
			}
			for _, chunk := range entry.Chunks {
				p := &filer_pb.FileChunk{
					FileId:    chunk.GetFileIdString(),
					Offset:    offset,
					Size:      chunk.Size,
					Mtime:     chunk.Mtime,
					CipherKey: chunk.CipherKey,
					ETag:      chunk.ETag,
				}
				finalParts = append(finalParts, p)
				offset += int64(chunk.Size)
			}
		}
	}

	entryName := filepath.Base(*input.Key)
	dirName := filepath.Dir(*input.Key)
	if dirName == "." {
		dirName = ""
	}
	if strings.HasPrefix(dirName, "/") {
		dirName = dirName[1:]
	}
	dirName = fmt.Sprintf("%s/%s/%s", s3a.option.BucketsPath, *input.Bucket, dirName)

	// remove suffix '/'
	if strings.HasSuffix(dirName, "/") {
		dirName = dirName[:len(dirName)-1]
	}

	err = s3a.mkFile(dirName, entryName, finalParts, func(entry *filer_pb.Entry) {
		if entry.Extended == nil {
			entry.Extended = make(map[string][]byte)
		}
		for k, v := range pentry.Extended {
			if k != "key" {
				entry.Extended[k] = v
			}
		}
		if pentry.Attributes.Mime != "" {
			entry.Attributes.Mime = pentry.Attributes.Mime
		} else if mime != "" {
			entry.Attributes.Mime = mime
		}
	})

	if err != nil {
		glog.Errorf("completeMultipartUpload %s/%s error: %v", dirName, entryName, err)
		return nil, s3err.ErrInternalError
	}

	output = &CompleteMultipartUploadResult{
		CompleteMultipartUploadOutput: s3.CompleteMultipartUploadOutput{
			Location: aws.String(fmt.Sprintf("http://%s%s/%s", s3a.option.Filer.ToHttpAddress(), urlPathEscape(dirName), urlPathEscape(entryName))),
			Bucket:   input.Bucket,
			ETag:     aws.String("\"" + filer.ETagChunks(finalParts) + "\""),
			Key:      objectKey(input.Key),
		},
	}

	if err = s3a.rm(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, false, true); err != nil {
		glog.V(1).Infof("completeMultipartUpload cleanup %s upload %s: %v", *input.Bucket, *input.UploadId, err)
	}

	return
}

func (s3a *S3ApiServer) abortMultipartUpload(input *s3.AbortMultipartUploadInput) (output *s3.AbortMultipartUploadOutput, code s3err.ErrorCode) {

	glog.V(2).Infof("abortMultipartUpload input %v", input)

	exists, err := s3a.exists(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true)
	if err != nil {
		glog.V(1).Infof("bucket %s abort upload %s: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}
	if exists {
		err = s3a.rm(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true, true)
	}
	if err != nil {
		glog.V(1).Infof("bucket %s remove upload %s: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrInternalError
	}

	return &s3.AbortMultipartUploadOutput{}, s3err.ErrNone
}

type ListMultipartUploadsResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult"`

	// copied from s3.ListMultipartUploadsOutput, the Uploads is not converting to <Upload></Upload>
	Bucket             *string               `type:"string"`
	Delimiter          *string               `type:"string"`
	EncodingType       *string               `type:"string" enum:"EncodingType"`
	IsTruncated        *bool                 `type:"boolean"`
	KeyMarker          *string               `type:"string"`
	MaxUploads         *int64                `type:"integer"`
	NextKeyMarker      *string               `type:"string"`
	NextUploadIdMarker *string               `type:"string"`
	Prefix             *string               `type:"string"`
	UploadIdMarker     *string               `type:"string"`
	Upload             []*s3.MultipartUpload `locationName:"Upload" type:"list" flattened:"true"`
}

func (s3a *S3ApiServer) listMultipartUploads(input *s3.ListMultipartUploadsInput) (output *ListMultipartUploadsResult, code s3err.ErrorCode) {
	// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html

	glog.V(2).Infof("listMultipartUploads input %v", input)

	output = &ListMultipartUploadsResult{
		Bucket:       input.Bucket,
		Delimiter:    input.Delimiter,
		EncodingType: input.EncodingType,
		KeyMarker:    input.KeyMarker,
		MaxUploads:   input.MaxUploads,
		Prefix:       input.Prefix,
	}

	entries, isLast, err := s3a.list(s3a.genUploadsFolder(*input.Bucket), "", *input.UploadIdMarker, false, uint32(*input.MaxUploads))
	if err != nil {
		glog.Errorf("listMultipartUploads %s error: %v", *input.Bucket, err)
		return
	}
	output.IsTruncated = aws.Bool(!isLast)

	for _, entry := range entries {
		if entry.Extended != nil {
			key := string(entry.Extended["key"])
			if *input.KeyMarker != "" && *input.KeyMarker != key {
				continue
			}
			if *input.Prefix != "" && !strings.HasPrefix(key, *input.Prefix) {
				continue
			}
			output.Upload = append(output.Upload, &s3.MultipartUpload{
				Key:      objectKey(aws.String(key)),
				UploadId: aws.String(entry.Name),
			})
			if !isLast {
				output.NextUploadIdMarker = aws.String(entry.Name)
			}
		}
	}

	return
}

type ListPartsResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult"`

	// copied from s3.ListPartsOutput, the Parts is not converting to <Part></Part>
	Bucket               *string    `type:"string"`
	IsTruncated          *bool      `type:"boolean"`
	Key                  *string    `min:"1" type:"string"`
	MaxParts             *int64     `type:"integer"`
	NextPartNumberMarker *int64     `type:"integer"`
	PartNumberMarker     *int64     `type:"integer"`
	Part                 []*s3.Part `locationName:"Part" type:"list" flattened:"true"`
	StorageClass         *string    `type:"string" enum:"StorageClass"`
	UploadId             *string    `type:"string"`
}

func (s3a *S3ApiServer) listObjectParts(input *s3.ListPartsInput) (output *ListPartsResult, code s3err.ErrorCode) {
	// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html

	glog.V(2).Infof("listObjectParts input %v", input)

	output = &ListPartsResult{
		Bucket:           input.Bucket,
		Key:              objectKey(input.Key),
		UploadId:         input.UploadId,
		MaxParts:         input.MaxParts,         // the maximum number of parts to return.
		PartNumberMarker: input.PartNumberMarker, // the part number starts after this, exclusive
		StorageClass:     aws.String("STANDARD"),
	}

	entries, isLast, err := s3a.list(s3a.genUploadsFolder(*input.Bucket)+"/"+*input.UploadId, "", fmt.Sprintf("%04d.part", *input.PartNumberMarker), false, uint32(*input.MaxParts))
	if err != nil {
		glog.Errorf("listObjectParts %s %s error: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}
	if len(entries) == 0 {
		glog.Errorf("listObjectParts %s %s not found", *input.Bucket, *input.UploadId)
		return nil, s3err.ErrNoSuchUpload
	}

	output.IsTruncated = aws.Bool(!isLast)

	for _, entry := range entries {
		if strings.HasSuffix(entry.Name, ".part") && !entry.IsDirectory {
			partNumberString := entry.Name[:len(entry.Name)-len(".part")]
			partNumber, err := strconv.Atoi(partNumberString)
			if err != nil {
				glog.Errorf("listObjectParts %s %s parse %s: %v", *input.Bucket, *input.UploadId, entry.Name, err)
				continue
			}
			output.Part = append(output.Part, &s3.Part{
				PartNumber:   aws.Int64(int64(partNumber)),
				LastModified: aws.Time(time.Unix(entry.Attributes.Mtime, 0).UTC()),
				Size:         aws.Int64(int64(filer.FileSize(entry))),
				ETag:         aws.String("\"" + filer.ETag(entry) + "\""),
			})
			if !isLast {
				output.NextPartNumberMarker = aws.Int64(int64(partNumber))
			}
		}
	}

	return
}
<commit_msg>Revert "s3: listObjectParts return ErrNoSuchUpload if does not exist"<commit_after>package s3api

import (
	"encoding/xml"
	"fmt"
	"github.com/chrislusf/seaweedfs/weed/s3api/s3err"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/google/uuid"

	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
)

type InitiateMultipartUploadResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult"`
	s3.CreateMultipartUploadOutput
}

func (s3a *S3ApiServer) createMultipartUpload(input *s3.CreateMultipartUploadInput) (output *InitiateMultipartUploadResult, code s3err.ErrorCode) {

	glog.V(2).Infof("createMultipartUpload input %v", input)

	uploadId, _ := uuid.NewRandom()
	uploadIdString := uploadId.String()

	if err := s3a.mkdir(s3a.genUploadsFolder(*input.Bucket), uploadIdString, func(entry *filer_pb.Entry) {
		if entry.Extended == nil {
			entry.Extended = make(map[string][]byte)
		}
		entry.Extended["key"] = []byte(*input.Key)
		for k, v := range input.Metadata {
			entry.Extended[k] = []byte(*v)
		}
		if input.ContentType != nil {
			entry.Attributes.Mime = *input.ContentType
		}
	}); err != nil {
		glog.Errorf("NewMultipartUpload error: %v", err)
		return nil, s3err.ErrInternalError
	}

	output = &InitiateMultipartUploadResult{
		CreateMultipartUploadOutput: s3.CreateMultipartUploadOutput{
			Bucket:   input.Bucket,
			Key:      objectKey(input.Key),
			UploadId: aws.String(uploadIdString),
		},
	}

	return
}

type CompleteMultipartUploadResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUploadResult"`
	s3.CompleteMultipartUploadOutput
}

func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput) (output *CompleteMultipartUploadResult, code s3err.ErrorCode) {

	glog.V(2).Infof("completeMultipartUpload input %v", input)

	uploadDirectory := s3a.genUploadsFolder(*input.Bucket) + "/" + *input.UploadId

	entries, _, err := s3a.list(uploadDirectory, "", "", false, maxPartsList)
	if err != nil || len(entries) == 0 {
		glog.Errorf("completeMultipartUpload %s %s error: %v, entries:%d", *input.Bucket, *input.UploadId, err, len(entries))
		return nil, s3err.ErrNoSuchUpload
	}

	pentry, err := s3a.getEntry(s3a.genUploadsFolder(*input.Bucket), *input.UploadId)
	if err != nil {
		glog.Errorf("completeMultipartUpload %s %s error: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}

	var finalParts []*filer_pb.FileChunk
	var offset int64
	var mime string

	for _, entry := range entries {
		if strings.HasSuffix(entry.Name, ".part") && !entry.IsDirectory {
			if entry.Name == "0001.part" && entry.Attributes.Mime != "" {
				mime = entry.Attributes.Mime
			}
			for _, chunk := range entry.Chunks {
				p := &filer_pb.FileChunk{
					FileId:    chunk.GetFileIdString(),
					Offset:    offset,
					Size:      chunk.Size,
					Mtime:     chunk.Mtime,
					CipherKey: chunk.CipherKey,
					ETag:      chunk.ETag,
				}
				finalParts = append(finalParts, p)
				offset += int64(chunk.Size)
			}
		}
	}

	entryName := filepath.Base(*input.Key)
	dirName := filepath.Dir(*input.Key)
	if dirName == "." {
		dirName = ""
	}
	if strings.HasPrefix(dirName, "/") {
		dirName = dirName[1:]
	}
	dirName = fmt.Sprintf("%s/%s/%s", s3a.option.BucketsPath, *input.Bucket, dirName)

	// remove suffix '/'
	if strings.HasSuffix(dirName, "/") {
		dirName = dirName[:len(dirName)-1]
	}

	err = s3a.mkFile(dirName, entryName, finalParts, func(entry *filer_pb.Entry) {
		if entry.Extended == nil {
			entry.Extended = make(map[string][]byte)
		}
		for k, v := range pentry.Extended {
			if k != "key" {
				entry.Extended[k] = v
			}
		}
		if pentry.Attributes.Mime != "" {
			entry.Attributes.Mime = pentry.Attributes.Mime
		} else if mime != "" {
			entry.Attributes.Mime = mime
		}
	})

	if err != nil {
		glog.Errorf("completeMultipartUpload %s/%s error: %v", dirName, entryName, err)
		return nil, s3err.ErrInternalError
	}

	output = &CompleteMultipartUploadResult{
		CompleteMultipartUploadOutput: s3.CompleteMultipartUploadOutput{
			Location: aws.String(fmt.Sprintf("http://%s%s/%s", s3a.option.Filer.ToHttpAddress(), urlPathEscape(dirName), urlPathEscape(entryName))),
			Bucket:   input.Bucket,
			ETag:     aws.String("\"" + filer.ETagChunks(finalParts) + "\""),
			Key:      objectKey(input.Key),
		},
	}

	if err = s3a.rm(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, false, true); err != nil {
		glog.V(1).Infof("completeMultipartUpload cleanup %s upload %s: %v", *input.Bucket, *input.UploadId, err)
	}

	return
}

func (s3a *S3ApiServer) abortMultipartUpload(input *s3.AbortMultipartUploadInput) (output *s3.AbortMultipartUploadOutput, code s3err.ErrorCode) {

	glog.V(2).Infof("abortMultipartUpload input %v", input)

	exists, err := s3a.exists(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true)
	if err != nil {
		glog.V(1).Infof("bucket %s abort upload %s: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}
	if exists {
		err = s3a.rm(s3a.genUploadsFolder(*input.Bucket), *input.UploadId, true, true)
	}
	if err != nil {
		glog.V(1).Infof("bucket %s remove upload %s: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrInternalError
	}

	return &s3.AbortMultipartUploadOutput{}, s3err.ErrNone
}

type ListMultipartUploadsResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListMultipartUploadsResult"`

	// copied from s3.ListMultipartUploadsOutput, the Uploads is not converting to <Upload></Upload>
	Bucket             *string               `type:"string"`
	Delimiter          *string               `type:"string"`
	EncodingType       *string               `type:"string" enum:"EncodingType"`
	IsTruncated        *bool                 `type:"boolean"`
	KeyMarker          *string               `type:"string"`
	MaxUploads         *int64                `type:"integer"`
	NextKeyMarker      *string               `type:"string"`
	NextUploadIdMarker *string               `type:"string"`
	Prefix             *string               `type:"string"`
	UploadIdMarker     *string               `type:"string"`
	Upload             []*s3.MultipartUpload `locationName:"Upload" type:"list" flattened:"true"`
}

func (s3a *S3ApiServer) listMultipartUploads(input *s3.ListMultipartUploadsInput) (output *ListMultipartUploadsResult, code s3err.ErrorCode) {
	// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html

	glog.V(2).Infof("listMultipartUploads input %v", input)

	output = &ListMultipartUploadsResult{
		Bucket:       input.Bucket,
		Delimiter:    input.Delimiter,
		EncodingType: input.EncodingType,
		KeyMarker:    input.KeyMarker,
		MaxUploads:   input.MaxUploads,
		Prefix:       input.Prefix,
	}

	entries, isLast, err := s3a.list(s3a.genUploadsFolder(*input.Bucket), "", *input.UploadIdMarker, false, uint32(*input.MaxUploads))
	if err != nil {
		glog.Errorf("listMultipartUploads %s error: %v", *input.Bucket, err)
		return
	}
	output.IsTruncated = aws.Bool(!isLast)

	for _, entry := range entries {
		if entry.Extended != nil {
			key := string(entry.Extended["key"])
			if *input.KeyMarker != "" && *input.KeyMarker != key {
				continue
			}
			if *input.Prefix != "" && !strings.HasPrefix(key, *input.Prefix) {
				continue
			}
			output.Upload = append(output.Upload, &s3.MultipartUpload{
				Key:      objectKey(aws.String(key)),
				UploadId: aws.String(entry.Name),
			})
			if !isLast {
				output.NextUploadIdMarker = aws.String(entry.Name)
			}
		}
	}

	return
}

type ListPartsResult struct {
	XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ ListPartsResult"`

	// copied from s3.ListPartsOutput, the Parts is not converting to <Part></Part>
	Bucket               *string    `type:"string"`
	IsTruncated          *bool      `type:"boolean"`
	Key                  *string    `min:"1" type:"string"`
	MaxParts             *int64     `type:"integer"`
	NextPartNumberMarker *int64     `type:"integer"`
	PartNumberMarker     *int64     `type:"integer"`
	Part                 []*s3.Part `locationName:"Part" type:"list" flattened:"true"`
	StorageClass         *string    `type:"string" enum:"StorageClass"`
	UploadId             *string    `type:"string"`
}

func (s3a *S3ApiServer) listObjectParts(input *s3.ListPartsInput) (output *ListPartsResult, code s3err.ErrorCode) {
	// https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html

	glog.V(2).Infof("listObjectParts input %v", input)

	output = &ListPartsResult{
		Bucket:           input.Bucket,
		Key:              objectKey(input.Key),
		UploadId:         input.UploadId,
		MaxParts:         input.MaxParts,         // the maximum number of parts to return.
		PartNumberMarker: input.PartNumberMarker, // the part number starts after this, exclusive
		StorageClass:     aws.String("STANDARD"),
	}

	entries, isLast, err := s3a.list(s3a.genUploadsFolder(*input.Bucket)+"/"+*input.UploadId, "", fmt.Sprintf("%04d.part", *input.PartNumberMarker), false, uint32(*input.MaxParts))
	if err != nil {
		glog.Errorf("listObjectParts %s %s error: %v", *input.Bucket, *input.UploadId, err)
		return nil, s3err.ErrNoSuchUpload
	}

	output.IsTruncated = aws.Bool(!isLast)

	for _, entry := range entries {
		if strings.HasSuffix(entry.Name, ".part") && !entry.IsDirectory {
			partNumberString := entry.Name[:len(entry.Name)-len(".part")]
			partNumber, err := strconv.Atoi(partNumberString)
			if err != nil {
				glog.Errorf("listObjectParts %s %s parse %s: %v", *input.Bucket, *input.UploadId, entry.Name, err)
				continue
			}
			output.Part = append(output.Part, &s3.Part{
				PartNumber:   aws.Int64(int64(partNumber)),
				LastModified: aws.Time(time.Unix(entry.Attributes.Mtime, 0).UTC()),
				Size:         aws.Int64(int64(filer.FileSize(entry))),
				ETag:         aws.String("\"" + filer.ETag(entry) + "\""),
			})
			if !isLast {
				output.NextPartNumberMarker = aws.Int64(int64(partNumber))
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>package shadowsocks

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"

	"github.com/shadowsocks/shadowsocks-go/encrypt"
)

// SecureConn is a secured connection with shadowsocks protocol
// also implements net.Conn interface
type SecureConn struct {
	net.Conn
	*encrypt.Cipher
	readBuf      []byte
	writeBuf     []byte
	chunkID      uint32
	isServerSide bool
	ota          bool
}

// NewSecureConn creates a SecureConn
func NewSecureConn(c net.Conn, cipher *encrypt.Cipher, ota bool, isServerSide bool) *SecureConn {
	return &SecureConn{
		Conn:         c,
		Cipher:       cipher,
		readBuf:      leakyBuf.Get(),
		writeBuf:     leakyBuf.Get(),
		isServerSide: isServerSide,
		ota:          ota,
	}
}

// Close closes the connection.
func (c *SecureConn) Close() error {
	leakyBuf.Put(c.readBuf)
	leakyBuf.Put(c.writeBuf)
	return c.Conn.Close()
}

// IsOta returns true if the connection is OTA enabled
func (c *SecureConn) IsOta() bool {
	return c.ota
}

// EnableOta enables OTA for the connection
func (c *SecureConn) EnableOta() {
	c.ota = true
}

func (c *SecureConn) getAndIncrChunkID() (chunkID uint32) {
	chunkID = c.chunkID
	c.chunkID++
	return
}

func (c *SecureConn) Read(b []byte) (n int, err error) {
	if c.ota && c.isServerSide {
		header := make([]byte, lenDataLen+lenHmacSha1)
		if n, err = readFull(c, header); err != nil {
			return 0, err
		}

		dataLen := binary.BigEndian.Uint16(header[:lenDataLen])
		expectedHmacSha1 := header[lenDataLen : lenDataLen+lenHmacSha1]

		if len(b) < int(dataLen) {
			err = errBufferTooSmall
			return 0, err
		}
		if n, err = readFull(c, b[:dataLen]); err != nil {
			return 0, err
		}
		chunkIDBytes := make([]byte, 4)
		chunkID := c.getAndIncrChunkID()
		binary.BigEndian.PutUint32(chunkIDBytes, chunkID)
		actualHmacSha1 := HmacSha1(append(c.GetIV(), chunkIDBytes...), b[:dataLen])
		if !bytes.Equal(expectedHmacSha1, actualHmacSha1) {
			return 0, errPacketOtaFailed
		}
		return int(dataLen), nil
	}
	return c.read(b)
}

func (c *SecureConn) read(b []byte) (n int, err error) {
	if c.DecInited() {
		iv := make([]byte, c.GetIVLen())
		if _, err = io.ReadFull(c.Conn, iv); err != nil {
			return
		}
		if err = c.InitDecrypt(iv); err != nil {
			return
		}
		if len(c.GetIV()) == 0 {
			c.SetIV(iv)
		}
	}

	cipherData := c.readBuf
	if len(b) > len(cipherData) {
		cipherData = make([]byte, len(b))
	} else {
		cipherData = cipherData[:len(b)]
	}

	n, err = c.Conn.Read(cipherData)
	if n > 0 {
		c.Decrypt(b[0:n], cipherData[0:n])
	}
	return
}

func (c *SecureConn) Write(b []byte) (n int, err error) {
	if c.ota && !c.isServerSide {
		chunkID := c.getAndIncrChunkID()
		header := otaReqChunkAuth(c.GetIV(), chunkID, b)
		headerLen := len(header)
		n, err = c.write(append(header, b...))
		// Make sure <= 0 <= len(b), where b is the slice passed in.
		if n >= headerLen {
			n -= headerLen
		}
		return
	}
	return c.write(b)
}

func (c *SecureConn) write(b []byte) (n int, err error) {
	var iv []byte
	if c.EncInited() {
		iv, err = c.InitEncrypt()
		if err != nil {
			return
		}
	}

	cipherData := c.writeBuf
	dataSize := len(b) + len(iv)
	if dataSize > len(cipherData) {
		cipherData = make([]byte, dataSize)
	} else {
		cipherData = cipherData[:dataSize]
	}

	if iv != nil {
		// Put initialization vector in buffer, do a single write to send both
		// iv and data.
		copy(cipherData, iv)
	}

	c.Encrypt(cipherData[len(iv):], b)
	n, err = c.Conn.Write(cipherData)
	return
}

// Listener is like net.Listener, but a little different
type Listener struct {
	net.Listener
	cipher *encrypt.Cipher
	ota    bool
}

// Accept just like net.Listener.Accept(), but with additional return variable host.
// It will handle the request header for you.
func (ln *Listener) Accept() (conn net.Conn, host string, err error) {
	conn, err = ln.Listener.Accept()
	if err != nil {
		return nil, "", err
	}
	ss := NewSecureConn(conn, ln.cipher.Copy(), false, true)
	host, err = getRequets(ss, ln.ota)
	if err != nil {
		return nil, host, err
	}
	return ss, host, nil
}

// Close stops listening on the TCP address. Already Accepted connections are not closed.
func (ln *Listener) Close() error {
	return ln.Listener.Close()
}

// Addr returns the listener's network address, a *TCPAddr.
// The Addr returned is shared by all invocations of Addr, so do not modify it.
func (ln *Listener) Addr() net.Addr {
	return ln.Listener.Addr()
}

// Listen announces on the TCP address laddr and returns a TCP listener.
// Net must be "tcp", "tcp4", or "tcp6".
// If laddr has a port of 0, ListenTCP will choose an available port.
// The caller can use the Addr method of TCPListener to retrieve the chosen address.
func Listen(network, laddr string, config *Config) (*Listener, error) {
	cipher, err := encrypt.NewCipher(config.Method, config.Password)
	if err != nil {
		return nil, err
	}
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return &Listener{ln, cipher, config.Auth}, nil
}

func readFull(c *SecureConn, b []byte) (n int, err error) {
	min := len(b)
	for n < min {
		var nn int
		nn, err = c.read(b[n:])
		n += nn
	}
	if n >= min {
		err = nil
	} else if n > 0 && err == io.EOF {
		err = io.ErrUnexpectedEOF
	}
	return
}

func getRequets(ss *SecureConn, auth bool) (host string, err error) {
	buf := make([]byte, 269)
	// read till we get possible domain length field
	if _, err = readFull(ss, buf[:idType+1]); err != nil {
		return
	}
	var reqStart, reqEnd int
	addrType := buf[idType]
	switch addrType & AddrMask {
	case typeIPv4:
		reqStart, reqEnd = idIP0, idIP0+headerLenIPv4-1
	case typeIPv6:
		reqStart, reqEnd = idIP0, idIP0+headerLenIPv6-1
	case typeDm:
		if _, err = readFull(ss, buf[idType+1:idDmLen+1]); err != nil {
			return
		}
		reqStart, reqEnd = idDm0, idDm0+int(buf[idDmLen])+headerLenDmBase-2
	default:
		err = fmt.Errorf("addr type %d not supported", addrType&AddrMask)
		return
	}
	if _, err = readFull(ss, buf[reqStart:reqEnd]); err != nil {
		return
	}

	switch addrType & AddrMask {
	case typeIPv4:
		host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
	case typeIPv6:
		host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
	case typeDm:
		host = string(buf[idDm0 : idDm0+int(buf[idDmLen])])
		if strings.ContainsRune(host, 0x00) {
			return "", errInvalidHostname
		}
	}

	port := binary.BigEndian.Uint16(buf[reqEnd-2 : reqEnd])
	host = net.JoinHostPort(host, strconv.Itoa(int(port)))
	ota := addrType&OneTimeAuthMask > 0
	if auth {
		if !ota {
			err = errPacketOtaFailed
			return
		}
	}
	if ota {
		if _, err = readFull(ss, buf[reqEnd:reqEnd+lenHmacSha1]); err != nil {
			return
		}
		iv := ss.GetIV()
		key := ss.GetKey()
		actualHmacSha1Buf := HmacSha1(append(iv, key...), buf[:reqEnd])
		if !bytes.Equal(buf[reqEnd:reqEnd+lenHmacSha1], actualHmacSha1Buf) {
			err = errPacketOtaFailed
			return
		}
		ss.EnableOta()
	}
	return
}
<commit_msg>Handle the invalid connections correctly.<commit_after>package shadowsocks

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"

	"github.com/shadowsocks/shadowsocks-go/encrypt"
)

// SecureConn is a secured connection with shadowsocks protocol
// also implements net.Conn interface
type SecureConn struct {
	net.Conn
	*encrypt.Cipher
	readBuf      []byte
	writeBuf     []byte
	chunkID      uint32
	isServerSide bool
	ota          bool
}

// NewSecureConn creates a SecureConn
func NewSecureConn(c net.Conn, cipher *encrypt.Cipher, ota bool, isServerSide bool) *SecureConn {
	return &SecureConn{
		Conn:         c,
		Cipher:       cipher,
		readBuf:      leakyBuf.Get(),
		writeBuf:     leakyBuf.Get(),
		isServerSide: isServerSide,
		ota:          ota,
	}
}

// Close closes the connection.
func (c *SecureConn) Close() error {
	leakyBuf.Put(c.readBuf)
	leakyBuf.Put(c.writeBuf)
	return c.Conn.Close()
}

// IsOta returns true if the connection is OTA enabled
func (c *SecureConn) IsOta() bool {
	return c.ota
}

// EnableOta enables OTA for the connection
func (c *SecureConn) EnableOta() {
	c.ota = true
}

func (c *SecureConn) getAndIncrChunkID() (chunkID uint32) {
	chunkID = c.chunkID
	c.chunkID++
	return
}

func (c *SecureConn) Read(b []byte) (n int, err error) {
	if c.ota && c.isServerSide {
		header := make([]byte, lenDataLen+lenHmacSha1)
		if n, err = readFull(c, header); err != nil {
			return 0, err
		}

		dataLen := binary.BigEndian.Uint16(header[:lenDataLen])
		expectedHmacSha1 := header[lenDataLen : lenDataLen+lenHmacSha1]

		if len(b) < int(dataLen) {
			err = errBufferTooSmall
			return 0, err
		}
		if n, err = readFull(c, b[:dataLen]); err != nil {
			return 0, err
		}
		chunkIDBytes := make([]byte, 4)
		chunkID := c.getAndIncrChunkID()
		binary.BigEndian.PutUint32(chunkIDBytes, chunkID)
		actualHmacSha1 := HmacSha1(append(c.GetIV(), chunkIDBytes...), b[:dataLen])
		if !bytes.Equal(expectedHmacSha1, actualHmacSha1) {
			return 0, errPacketOtaFailed
		}
		return int(dataLen), nil
	}
	return c.read(b)
}

func (c *SecureConn) read(b []byte) (n int, err error) {
	if c.DecInited() {
		iv := make([]byte, c.GetIVLen())
		if _, err = io.ReadFull(c.Conn, iv); err != nil {
			return
		}
		if err = c.InitDecrypt(iv); err != nil {
			return
		}
		if len(c.GetIV()) == 0 {
			c.SetIV(iv)
		}
	}

	cipherData := c.readBuf
	if len(b) > len(cipherData) {
		cipherData = make([]byte, len(b))
	} else {
		cipherData = cipherData[:len(b)]
	}

	n, err = c.Conn.Read(cipherData)
	if n > 0 {
		c.Decrypt(b[0:n], cipherData[0:n])
	}
	return
}

func (c *SecureConn) Write(b []byte) (n int, err error) {
	if c.ota && !c.isServerSide {
		chunkID := c.getAndIncrChunkID()
		header := otaReqChunkAuth(c.GetIV(), chunkID, b)
		headerLen := len(header)
		n, err = c.write(append(header, b...))
		// Make sure <= 0 <= len(b), where b is the slice passed in.
		if n >= headerLen {
			n -= headerLen
		}
		return
	}
	return c.write(b)
}

func (c *SecureConn) write(b []byte) (n int, err error) {
	var iv []byte
	if c.EncInited() {
		iv, err = c.InitEncrypt()
		if err != nil {
			return
		}
	}

	cipherData := c.writeBuf
	dataSize := len(b) + len(iv)
	if dataSize > len(cipherData) {
		cipherData = make([]byte, dataSize)
	} else {
		cipherData = cipherData[:dataSize]
	}

	if iv != nil {
		// Put initialization vector in buffer, do a single write to send both
		// iv and data.
		copy(cipherData, iv)
	}

	c.Encrypt(cipherData[len(iv):], b)
	n, err = c.Conn.Write(cipherData)
	return
}

// Listener is like net.Listener, but a little different
type Listener struct {
	net.Listener
	cipher *encrypt.Cipher
	ota    bool
}

// Accept just like net.Listener.Accept(), but with additional return variable host.
// It will handle the request header for you.
func (ln *Listener) Accept() (conn net.Conn, host string, err error) {
	conn, err = ln.Listener.Accept()
	if err != nil {
		return nil, "", err
	}
	ss := NewSecureConn(conn, ln.cipher.Copy(), false, true)
	host, err = getRequets(ss, ln.ota)
	if err != nil {
		ss.Close()
		return nil, host, err
	}
	return ss, host, nil
}

// Close stops listening on the TCP address. Already Accepted connections are not closed.
func (ln *Listener) Close() error {
	return ln.Listener.Close()
}

// Addr returns the listener's network address, a *TCPAddr.
// The Addr returned is shared by all invocations of Addr, so do not modify it.
func (ln *Listener) Addr() net.Addr {
	return ln.Listener.Addr()
}

// Listen announces on the TCP address laddr and returns a TCP listener.
// Net must be "tcp", "tcp4", or "tcp6".
// If laddr has a port of 0, ListenTCP will choose an available port.
// The caller can use the Addr method of TCPListener to retrieve the chosen address.
func Listen(network, laddr string, config *Config) (*Listener, error) {
	cipher, err := encrypt.NewCipher(config.Method, config.Password)
	if err != nil {
		return nil, err
	}
	ln, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return &Listener{ln, cipher, config.Auth}, nil
}

func readFull(c *SecureConn, b []byte) (n int, err error) {
	min := len(b)
	for n < min {
		var nn int
		nn, err = c.read(b[n:])
		n += nn
	}
	if n >= min {
		err = nil
	} else if n > 0 && err == io.EOF {
		err = io.ErrUnexpectedEOF
	}
	return
}

func getRequets(ss *SecureConn, auth bool) (host string, err error) {
	buf := make([]byte, 269)
	// read till we get possible domain length field
	if _, err = readFull(ss, buf[:idType+1]); err != nil {
		return
	}
	var reqStart, reqEnd int
	addrType := buf[idType]
	switch addrType & AddrMask {
	case typeIPv4:
		reqStart, reqEnd = idIP0, idIP0+headerLenIPv4-1
	case typeIPv6:
		reqStart, reqEnd = idIP0, idIP0+headerLenIPv6-1
	case typeDm:
		if _, err = readFull(ss, buf[idType+1:idDmLen+1]); err != nil {
			return
		}
		reqStart, reqEnd = idDm0, idDm0+int(buf[idDmLen])+headerLenDmBase-2
	default:
		err = fmt.Errorf("addr type %d not supported", addrType&AddrMask)
		return
	}
	if _, err = readFull(ss, buf[reqStart:reqEnd]); err != nil {
		return
	}

	switch addrType & AddrMask {
	case typeIPv4:
		host = net.IP(buf[idIP0 : idIP0+net.IPv4len]).String()
	case typeIPv6:
		host = net.IP(buf[idIP0 : idIP0+net.IPv6len]).String()
	case typeDm:
		host = string(buf[idDm0 : idDm0+int(buf[idDmLen])])
		if strings.ContainsRune(host, 0x00) {
			return "", errInvalidHostname
		}
	}

	port := binary.BigEndian.Uint16(buf[reqEnd-2 : reqEnd])
	host = net.JoinHostPort(host, strconv.Itoa(int(port)))
	ota := addrType&OneTimeAuthMask > 0
	if auth {
		if !ota {
			err = errPacketOtaFailed
			return
		}
	}
	if ota {
		if _, err = readFull(ss, buf[reqEnd:reqEnd+lenHmacSha1]); err != nil {
			return
		}
		iv := ss.GetIV()
		key := ss.GetKey()
		actualHmacSha1Buf := HmacSha1(append(iv, key...), buf[:reqEnd])
		if !bytes.Equal(buf[reqEnd:reqEnd+lenHmacSha1], actualHmacSha1Buf) {
			err = errPacketOtaFailed
			return
		}
		ss.EnableOta()
	}
	return
}
<|endoftext|>


<commit_before>package sqlbuilder

import "strconv"

// DBMS represents a DBMS.
type DBMS int

const (
	MySQL    DBMS = iota // MySQL
	Postgres             // Postgres
)

// Placeholder returns the placeholder string for the given index.
func (dbms DBMS) Placeholder(idx int) string {
	switch dbms {
	case MySQL:
		return "?"
	case Postgres:
		return "$" + strconv.Itoa(idx+1)
	default:
		panic("unknown DBMS")
	}
}

// Select returns a SELECT statement.
func (dbms DBMS) Select(table string) *SelectStatement {
	return &SelectStatement{
		dbms:  dbms,
		table: table,
	}
}

// Insert returns an INSERT statement.
func (dbms DBMS) Insert(table string) *InsertStatement {
	return &InsertStatement{
		dbms:  dbms,
		table: table,
	}
}

// Update returns an UPDATE statement.
func (dbms DBMS) Update(table string) *UpdateStatement {
	return &UpdateStatement{
		dbms:  dbms,
		table: table,
	}
}

// DefaultDBMS is the DBMS used by the package-level Select, Insert and Update functions.
var DefaultDBMS = MySQL

// Select returns a SELECT statement using the default Database.
func Select(table string) *SelectStatement {
	return DefaultDBMS.Select(table)
}

// Insert returns an INSERT statement using the default Database.
func Insert(table string) *InsertStatement {
	return DefaultDBMS.Insert(table)
}

// Update returns an UPDATE statement using the default Database.
func Update(table string) *UpdateStatement {
	return DefaultDBMS.Update(table)
}
<commit_msg>Prefix panic message with package name<commit_after>package sqlbuilder

import "strconv"

// DBMS represents a DBMS.
type DBMS int

const (
	MySQL    DBMS = iota // MySQL
	Postgres             // Postgres
)

// Placeholder returns the placeholder string for the given index.
func (dbms DBMS) Placeholder(idx int) string {
	switch dbms {
	case MySQL:
		return "?"
	case Postgres:
		return "$" + strconv.Itoa(idx+1)
	default:
		panic("sqlbuilder: unknown DBMS")
	}
}

// Select returns a SELECT statement.
func (dbms DBMS) Select(table string) *SelectStatement {
	return &SelectStatement{
		dbms:  dbms,
		table: table,
	}
}

// Insert returns an INSERT statement.
func (dbms DBMS) Insert(table string) *InsertStatement {
	return &InsertStatement{
		dbms:  dbms,
		table: table,
	}
}

// Update returns an UPDATE statement.
func (dbms DBMS) Update(table string) *UpdateStatement {
	return &UpdateStatement{
		dbms:  dbms,
		table: table,
	}
}

// DefaultDBMS is the DBMS used by the package-level Select, Insert and Update functions.
var DefaultDBMS = MySQL

// Select returns a SELECT statement using the default Database.
func Select(table string) *SelectStatement {
	return DefaultDBMS.Select(table)
}

// Insert returns an INSERT statement using the default Database.
func Insert(table string) *InsertStatement {
	return DefaultDBMS.Insert(table)
}

// Update returns an UPDATE statement using the default Database.
func Update(table string) *UpdateStatement {
	return DefaultDBMS.Update(table)
}
<|endoftext|>


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

package sqlbase

import (
	"testing"

	"github.com/cockroachdb/cockroach/sql/parser"
	"github.com/cockroachdb/cockroach/util/encoding"
	"github.com/cockroachdb/cockroach/util/randutil"
)

func TestEncDatum(t *testing.T) {
	a := &DatumAlloc{}
	x := &EncDatum{}
	if !x.IsUnset() {
		t.Errorf("empty EncDatum should be unset")
	}

	if _, ok := x.Encoding(); ok {
		t.Errorf("empty EncDatum has an encoding")
	}

	x.SetDatum(ColumnType_INT, parser.NewDInt(5))
	if x.IsUnset() {
		t.Errorf("unset after SetDatum()")
	}

	encoded, err := x.Encode(a, DatumEncoding_ASCENDING_KEY, nil)
	if err != nil {
		t.Fatal(err)
	}

	y := &EncDatum{}
	y.SetEncoded(ColumnType_INT, DatumEncoding_ASCENDING_KEY, encoded)

	if y.IsUnset() {
		t.Errorf("unset after SetEncoded()")
	}
	if enc, ok := y.Encoding(); !ok {
		t.Error("no encoding after SetEncoded")
	} else if enc != DatumEncoding_ASCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	err = y.Decode(a)
	if err != nil {
		t.Fatal(err)
	}
	if cmp := y.Datum.Compare(x.Datum); cmp != 0 {
		t.Errorf("Datums should be equal, cmp = %d", cmp)
	}

	enc2, err := y.Encode(a, DatumEncoding_DESCENDING_KEY, nil)
	if err != nil {
		t.Fatal(err)
	}
	// y's encoding should not change.
	if enc, ok := y.Encoding(); !ok {
		t.Error("no encoding")
	} else if enc != DatumEncoding_ASCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	x.SetEncoded(ColumnType_INT, DatumEncoding_DESCENDING_KEY, enc2)
	if enc, ok := x.Encoding(); !ok {
		t.Error("no encoding")
	} else if enc != DatumEncoding_DESCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	err = x.Decode(a)
	if err != nil {
		t.Fatal(err)
	}
	if cmp := y.Datum.Compare(x.Datum); cmp != 0 {
		t.Errorf("Datums should be equal, cmp = %d", cmp)
	}
}

// checkEncDatumCmp encodes the given values using the given encodings,
// creates EncDatums from those encodings and verifies the Compare result on
// those encodings. It also checks if the Compare resulted in decoding or not.
func checkEncDatumCmp(
	t *testing.T,
	a *DatumAlloc,
	v1, v2 *EncDatum,
	enc1, enc2 DatumEncoding,
	expectedCmp int,
	requiresDecode bool,
) {
	buf1, err := v1.Encode(a, enc1, nil)
	if err != nil {
		t.Fatal(err)
	}
	buf2, err := v2.Encode(a, enc2, nil)
	if err != nil {
		t.Fatal(err)
	}
	dec1 := &EncDatum{}
	dec1.SetEncoded(v1.Type, enc1, buf1)

	dec2 := &EncDatum{}
	dec2.SetEncoded(v2.Type, enc2, buf2)

	if val, err := dec1.Compare(a, dec2); err != nil {
		t.Fatal(err)
	} else if val != expectedCmp {
		t.Errorf("comparing %s (%s), %s (%s) resulted in %d, expected %d",
			v1, enc1, v2, enc2, val, expectedCmp)
	}

	if requiresDecode {
		if dec1.Datum == nil || dec2.Datum == nil {
			t.Errorf("comparing %s (%s), %s (%s) did not require decoding", v1, enc1, v2, enc2)
		}
	} else {
		if dec1.Datum != nil || dec2.Datum != nil {
			t.Errorf("comparing %s (%s), %s (%s) required decoding", v1, enc1, v2, enc2)
		}
	}
}

func TestEncDatumCompare(t *testing.T) {
	a := &DatumAlloc{}
	v1 := &EncDatum{}
	v1.SetDatum(ColumnType_INT, parser.NewDInt(1))
	v2 := &EncDatum{}
	v2.SetDatum(ColumnType_INT, parser.NewDInt(2))

	if val, err := v1.Compare(a, v2); err != nil {
		t.Fatal(err)
	} else if val != -1 {
		t.Errorf("compare(1, 2) = %d", val)
	}

	asc := DatumEncoding_ASCENDING_KEY
	desc := DatumEncoding_DESCENDING_KEY
	noncmp := DatumEncoding_VALUE

	checkEncDatumCmp(t, a, v1, v2, asc, asc, -1, false)
	checkEncDatumCmp(t, a, v2, v1, asc, asc, +1, false)
	checkEncDatumCmp(t, a, v1, v1, asc, asc, 0, false)
	checkEncDatumCmp(t, a, v2, v2, asc, asc, 0, false)

	checkEncDatumCmp(t, a, v1, v2, desc, desc, -1, false)
	checkEncDatumCmp(t, a, v2, v1, desc, desc, +1, false)
	checkEncDatumCmp(t, a, v1, v1, desc, desc, 0, false)
	checkEncDatumCmp(t, a, v2, v2, desc, desc, 0, false)

	checkEncDatumCmp(t, a, v1, v2, noncmp, noncmp, -1, true)
	checkEncDatumCmp(t, a, v2, v1, desc, noncmp, +1, true)
	checkEncDatumCmp(t, a, v1, v1, asc, desc, 0, true)
	checkEncDatumCmp(t, a, v2, v2, desc, asc, 0, true)
}

func TestEncDatumFromBuffer(t *testing.T) {
	var alloc DatumAlloc
	rng, _ := randutil.NewPseudoRand()
	for test := 0; test < 20; test++ {
		var err error
		// Generate a set of random datums.
		ed := make([]EncDatum, 1+rng.Intn(10))
		for i := range ed {
			ed[i] = RandEncDatum(rng)
		}
		// Encode them in a single buffer.
		var buf []byte
		enc := make([]DatumEncoding, len(ed))
		for i := range ed {
			enc[i] = RandDatumEncoding(rng)
			buf, err = ed[i].Encode(&alloc, enc[i], buf)
			if err != nil {
				t.Fatal(err)
			}
		}
		// Decode the buffer.
		b := buf
		for i := range ed {
			if len(b) == 0 {
				t.Fatal("buffer ended early")
			}
			var decoded EncDatum
			b, err = decoded.SetFromBuffer(ed[i].Type, enc[i], b)
			if err != nil {
				t.Fatal(err)
			}
			err = decoded.Decode(&alloc)
			if err != nil {
				t.Fatal(err)
			}
			if decoded.Datum.Compare(ed[i].Datum) != 0 {
				t.Errorf("decoded datum %s doesn't equal original %s", decoded.Datum, ed[i].Datum)
			}
		}
		if len(b) != 0 {
			t.Errorf("%d leftover bytes", len(b))
		}
	}
}

func TestEncDatumRowCompare(t *testing.T) {
	v := [5]EncDatum{}
	for i := range v {
		v[i].SetDatum(ColumnType_INT, parser.NewDInt(parser.DInt(i)))
	}

	asc := encoding.Ascending
	desc := encoding.Descending

	testCases := []struct {
		row1, row2 EncDatumRow
		ord        ColumnOrdering
		cmp        int
	}{
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{1, desc}},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{0, asc}, {1, desc}},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{2, asc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[3]},
			row2: EncDatumRow{v[0], v[1], v[2]},
			ord:  ColumnOrdering{{2, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{2, asc}, {0, asc}, {1, asc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{0, asc}, {2, desc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{1, desc}, {0, asc}, {2, desc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, desc}, {0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, asc}, {0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, asc}, {0, desc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{0, desc}, {1, asc}},
			cmp:  -1,
		},
	}

	a := &DatumAlloc{}
	for _, c := range testCases {
		cmp, err := c.row1.Compare(a, c.ord, c.row2)
		if err != nil {
			t.Error(err)
		} else if cmp != c.cmp {
			t.Errorf("%s cmp %s ordering %v got %d, expected %d",
				c.row1, c.row2, c.ord, cmp, c.cmp)
		}
	}
}

func TestEncDatumRowAlloc(t *testing.T) {
	rng, _ := randutil.NewPseudoRand()
	for _, cols := range []int{1, 2, 4, 10, 40, 100} {
		for _, rows := range []int{1, 2, 3, 5, 10, 20} {
			var in, out EncDatumRows
			in = make(EncDatumRows, rows)
			for i := 0; i < rows; i++ {
				in[i] = make(EncDatumRow, cols)
				for j := 0; j < cols; j++ {
					in[i][j] = RandEncDatum(rng)
				}
			}
			var alloc EncDatumRowAlloc
			out = make(EncDatumRows, rows)
			for i := 0; i < rows; i++ {
				out[i] = alloc.CopyRow(in[i])
				if len(out[i]) != cols {
					t.Fatalf("allocated row has invalid length %d (expected %d)", len(out[i]), cols)
				}
			}
			// Do some random appends to make sure the buffers never overlap.
			for x := 0; x < 10; x++ {
				i := rng.Intn(rows)
				j := rng.Intn(rows)
				out[i] = append(out[i], out[j]...)
				out[i] = out[i][:cols]
			}
			for i := 0; i < rows; i++ {
				for j := 0; j < cols; j++ {
					if a, b := in[i][j].Datum, out[i][j].Datum; a.Compare(b) != 0 {
						t.Errorf("copied datum %s doesn't equal original %s", b, a)
					}
				}
			}
		}
	}
}
<commit_msg>sqlbase: improving EncDatumCompare test<commit_after>// Copyright 2016 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Radu Berinde (radu@cockroachlabs.com)

package sqlbase

import (
	"testing"

	"github.com/cockroachdb/cockroach/sql/parser"
	"github.com/cockroachdb/cockroach/util/encoding"
	"github.com/cockroachdb/cockroach/util/randutil"
)

func TestEncDatum(t *testing.T) {
	a := &DatumAlloc{}
	x := &EncDatum{}
	if !x.IsUnset() {
		t.Errorf("empty EncDatum should be unset")
	}

	if _, ok := x.Encoding(); ok {
		t.Errorf("empty EncDatum has an encoding")
	}

	x.SetDatum(ColumnType_INT, parser.NewDInt(5))
	if x.IsUnset() {
		t.Errorf("unset after SetDatum()")
	}

	encoded, err := x.Encode(a, DatumEncoding_ASCENDING_KEY, nil)
	if err != nil {
		t.Fatal(err)
	}

	y := &EncDatum{}
	y.SetEncoded(ColumnType_INT, DatumEncoding_ASCENDING_KEY, encoded)

	if y.IsUnset() {
		t.Errorf("unset after SetEncoded()")
	}
	if enc, ok := y.Encoding(); !ok {
		t.Error("no encoding after SetEncoded")
	} else if enc != DatumEncoding_ASCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	err = y.Decode(a)
	if err != nil {
		t.Fatal(err)
	}
	if cmp := y.Datum.Compare(x.Datum); cmp != 0 {
		t.Errorf("Datums should be equal, cmp = %d", cmp)
	}

	enc2, err := y.Encode(a, DatumEncoding_DESCENDING_KEY, nil)
	if err != nil {
		t.Fatal(err)
	}
	// y's encoding should not change.
	if enc, ok := y.Encoding(); !ok {
		t.Error("no encoding")
	} else if enc != DatumEncoding_ASCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	x.SetEncoded(ColumnType_INT, DatumEncoding_DESCENDING_KEY, enc2)
	if enc, ok := x.Encoding(); !ok {
		t.Error("no encoding")
	} else if enc != DatumEncoding_DESCENDING_KEY {
		t.Errorf("invalid encoding %d", enc)
	}
	err = x.Decode(a)
	if err != nil {
		t.Fatal(err)
	}
	if cmp := y.Datum.Compare(x.Datum); cmp != 0 {
		t.Errorf("Datums should be equal, cmp = %d", cmp)
	}
}

// checkEncDatumCmp encodes the given values using the given encodings,
// creates EncDatums from those encodings and verifies the Compare result on
// those encodings. It also checks if the Compare resulted in decoding or not.
func checkEncDatumCmp(
	t *testing.T,
	a *DatumAlloc,
	v1, v2 *EncDatum,
	enc1, enc2 DatumEncoding,
	expectedCmp int,
	requiresDecode bool,
) {
	buf1, err := v1.Encode(a, enc1, nil)
	if err != nil {
		t.Fatal(err)
	}
	buf2, err := v2.Encode(a, enc2, nil)
	if err != nil {
		t.Fatal(err)
	}
	dec1 := &EncDatum{}
	dec1.SetEncoded(v1.Type, enc1, buf1)

	dec2 := &EncDatum{}
	dec2.SetEncoded(v2.Type, enc2, buf2)

	if val, err := dec1.Compare(a, dec2); err != nil {
		t.Fatal(err)
	} else if val != expectedCmp {
		t.Errorf("comparing %s (%s), %s (%s) resulted in %d, expected %d",
			v1, enc1, v2, enc2, val, expectedCmp)
	}

	if requiresDecode {
		if dec1.Datum == nil || dec2.Datum == nil {
			t.Errorf("comparing %s (%s), %s (%s) did not require decoding", v1, enc1, v2, enc2)
		}
	} else {
		if dec1.Datum != nil || dec2.Datum != nil {
			t.Errorf("comparing %s (%s), %s (%s) required decoding", v1, enc1, v2, enc2)
		}
	}
}

func TestEncDatumCompare(t *testing.T) {
	a := &DatumAlloc{}
	rng, _ := randutil.NewPseudoRand()

	for typ := ColumnType_Kind(0); int(typ) < len(ColumnType_Kind_value); typ++ {
		// Generate two datums d1 < d2
		var d1, d2 parser.Datum
		for {
			d1 = RandDatum(rng, typ, false)
			d2 = RandDatum(rng, typ, false)
			if cmp := d1.Compare(d2); cmp < 0 {
				break
			}
		}
		v1 := &EncDatum{}
		v1.SetDatum(typ, d1)
		v2 := &EncDatum{}
		v2.SetDatum(typ, d2)

		if val, err := v1.Compare(a, v2); err != nil {
			t.Fatal(err)
		} else if val != -1 {
			t.Errorf("compare(1, 2) = %d", val)
		}

		asc := DatumEncoding_ASCENDING_KEY
		desc := DatumEncoding_DESCENDING_KEY
		noncmp := DatumEncoding_VALUE

		checkEncDatumCmp(t, a, v1, v2, asc, asc, -1, false)
		checkEncDatumCmp(t, a, v2, v1, asc, asc, +1, false)
		checkEncDatumCmp(t, a, v1, v1, asc, asc, 0, false)
		checkEncDatumCmp(t, a, v2, v2, asc, asc, 0, false)

		checkEncDatumCmp(t, a, v1, v2, desc, desc, -1, false)
		checkEncDatumCmp(t, a, v2, v1, desc, desc, +1, false)
		checkEncDatumCmp(t, a, v1, v1, desc, desc, 0, false)
		checkEncDatumCmp(t, a, v2, v2, desc, desc, 0, false)

		checkEncDatumCmp(t, a, v1, v2, noncmp, noncmp, -1, true)
		checkEncDatumCmp(t, a, v2, v1, desc, noncmp, +1, true)
		checkEncDatumCmp(t, a, v1, v1, asc, desc, 0, true)
		checkEncDatumCmp(t, a, v2, v2, desc, asc, 0, true)
	}
}

func TestEncDatumFromBuffer(t *testing.T) {
	var alloc DatumAlloc
	rng, _ := randutil.NewPseudoRand()
	for test := 0; test < 20; test++ {
		var err error
		// Generate a set of random datums.
		ed := make([]EncDatum, 1+rng.Intn(10))
		for i := range ed {
			ed[i] = RandEncDatum(rng)
		}
		// Encode them in a single buffer.
		var buf []byte
		enc := make([]DatumEncoding, len(ed))
		for i := range ed {
			enc[i] = RandDatumEncoding(rng)
			buf, err = ed[i].Encode(&alloc, enc[i], buf)
			if err != nil {
				t.Fatal(err)
			}
		}
		// Decode the buffer.
		b := buf
		for i := range ed {
			if len(b) == 0 {
				t.Fatal("buffer ended early")
			}
			var decoded EncDatum
			b, err = decoded.SetFromBuffer(ed[i].Type, enc[i], b)
			if err != nil {
				t.Fatal(err)
			}
			err = decoded.Decode(&alloc)
			if err != nil {
				t.Fatal(err)
			}
			if decoded.Datum.Compare(ed[i].Datum) != 0 {
				t.Errorf("decoded datum %s doesn't equal original %s", decoded.Datum, ed[i].Datum)
			}
		}
		if len(b) != 0 {
			t.Errorf("%d leftover bytes", len(b))
		}
	}
}

func TestEncDatumRowCompare(t *testing.T) {
	v := [5]EncDatum{}
	for i := range v {
		v[i].SetDatum(ColumnType_INT, parser.NewDInt(parser.DInt(i)))
	}

	asc := encoding.Ascending
	desc := encoding.Descending

	testCases := []struct {
		row1, row2 EncDatumRow
		ord        ColumnOrdering
		cmp        int
	}{
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{1, desc}},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{0, asc}, {1, desc}},
			cmp:  0,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{2, asc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[3]},
			row2: EncDatumRow{v[0], v[1], v[2]},
			ord:  ColumnOrdering{{2, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{2, asc}, {0, asc}, {1, asc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{0, asc}, {2, desc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[0], v[1], v[2]},
			row2: EncDatumRow{v[0], v[1], v[3]},
			ord:  ColumnOrdering{{1, desc}, {0, asc}, {2, desc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, desc}, {0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, asc}, {0, asc}},
			cmp:  1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{1, asc}, {0, desc}},
			cmp:  -1,
		},
		{
			row1: EncDatumRow{v[2], v[3]},
			row2: EncDatumRow{v[1], v[3], v[0]},
			ord:  ColumnOrdering{{0, desc}, {1, asc}},
			cmp:  -1,
		},
	}

	a := &DatumAlloc{}
	for _, c := range testCases {
		cmp, err := c.row1.Compare(a, c.ord, c.row2)
		if err != nil {
			t.Error(err)
		} else if cmp != c.cmp {
			t.Errorf("%s cmp %s ordering %v got %d, expected %d",
				c.row1, c.row2, c.ord, cmp, c.cmp)
		}
	}
}

func TestEncDatumRowAlloc(t *testing.T) {
	rng, _ := randutil.NewPseudoRand()
	for _, cols := range []int{1, 2, 4, 10, 40, 100} {
		for _, rows := range []int{1, 2, 3, 5, 10, 20} {
			var in, out EncDatumRows
			in = make(EncDatumRows, rows)
			for i := 0; i < rows; i++ {
				in[i] = make(EncDatumRow, cols)
				for j := 0; j < cols; j++ {
					in[i][j] = RandEncDatum(rng)
				}
			}
			var alloc EncDatumRowAlloc
			out = make(EncDatumRows, rows)
			for i := 0; i < rows; i++ {
				out[i] = alloc.CopyRow(in[i])
				if len(out[i]) != cols {
					t.Fatalf("allocated row has invalid length %d (expected %d)", len(out[i]), cols)
				}
			}
			// Do some random appends to make sure the buffers never overlap.
			for x := 0; x < 10; x++ {
				i := rng.Intn(rows)
				j := rng.Intn(rows)
				out[i] = append(out[i], out[j]...)
				out[i] = out[i][:cols]
			}
			for i := 0; i < rows; i++ {
				for j := 0; j < cols; j++ {
					if a, b := in[i][j].Datum, out[i][j].Datum; a.Compare(b) != 0 {
						t.Errorf("copied datum %s doesn't equal original %s", b, a)
					}
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"log"
	"time"
	"strings"
	"strconv"
	"encoding/json"
	"github.com/astaxie/beego"
	"./../models"
	"./../requests"
	"github.com/astaxie/beego/orm"
)

const (
	FilesDir = "./files"
	FilesField = "file"
)

//##########################################################

type BaseController struct {
	beego.Controller
}

func (this *BaseController) getRequest() *requests.ApiRequest {
	return requests.NewApiRequest(this.Ctx.Input.RequestBody)
}

func (this *BaseController) respond(entity interface{}) {
	this.Data["json"] = entity
	this.ServeJson()
}

func (this *BaseController) upsert(query interface{}, entity interface{}) {
	o := orm.NewOrm()
	err := o.Read(query)
	if err == orm.ErrNoRows || err == orm.ErrMissPK {
		if id, err := o.Insert(entity); err == nil {
			log.Println("Entity inserted: ", id)
		} else {
			log.Fatal("ERROR: inserting", err)
		}
	} else {
		if id, err := o.Update(entity); err == nil {
			log.Println("Entity updated: ", id)
		} else {
			log.Fatal("ERROR: updating id ", id, err)
		}
	}
	o.Read(entity)
}

//##########################################################

type IdeaController struct {
	BaseController
}

func (this *IdeaController) Post() {
	var ideas []*models.Idea
	this.getRequest().GetQuery("idea").All(&ideas)
	this.respond(&ideas)
}

func (this *IdeaController) Put() {
	idea := models.Idea{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &idea)
	query := models.Idea{Id:idea.Id}

	this.upsert(&query, &idea)
	this.respond(&idea)
}

//##########################################################

type UserController struct {
	BaseController
}

func (this *UserController) Post() {
	var users []*models.User
	this.getRequest().GetQuery("user").All(&users)
	this.respond(&users)
}

func (this *UserController) Put() {
	user := models.User{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &user)
	query := models.User{Id:user.Id}

	this.upsert(&query, &user)
	this.respond(&user)
}

//##########################################################

type CommentController struct {
	BaseController
}

func (this *CommentController) Post() {
	var comments []*models.Comment
	this.getRequest().GetQuery("comment").All(&comments)
	this.respond(&comments)
}

func (this *CommentController) Put() {
	comment := models.Comment{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &comment)
	query := models.Comment{Id:comment.Id}

	this.upsert(&query, &comment)
	this.respond(&comment)
}

//##########################################################

type FileController struct {
	BaseController
}

func (this *FileController) Post() {
	_, header, _ := this.GetFile(FilesField);
	filename := strings.Replace(strconv.FormatInt(time.Now().Unix(), 10) + " " + header.Filename, " ", "_", -1);
	errorSave := this.SaveToFile(FilesField, FilesDir + "/" + filename);
	if errorSave != nil {
		log.Fatal(errorSave)
	}

	o := orm.NewOrm()
	file := models.File{}
	file.Title = header.Filename
	file.Filename = filename
	_, errorInsert := o.Insert(&file)
	if errorInsert != nil {
		log.Fatal(errorInsert)
	}

	o.Read(&file)
	this.Data["json"] = &file
	this.ServeJson()
}

//##########################################################
<commit_msg>abort on wrong model<commit_after>package controllers

import (
	"log"
	"time"
	"strings"
	"strconv"
	"encoding/json"
	"github.com/astaxie/beego"
	"./../models"
	"./../requests"
	"github.com/astaxie/beego/orm"
)

const (
	FilesDir = "./files"
	FilesField = "file"
)

//##########################################################

type BaseController struct {
	beego.Controller
}

func (this *BaseController) getRequest() *requests.ApiRequest {
	return requests.NewApiRequest(this.Ctx.Input.RequestBody)
}

func (this *BaseController) respond(entity interface{}) {
	this.Data["json"] = entity
	this.ServeJson()
}

func (this *BaseController) upsert(query interface{}, entity interface{}) {
	o := orm.NewOrm()
	err := o.Read(query)
	if err == orm.ErrNoRows || err == orm.ErrMissPK {
		if id, err := o.Insert(entity); err == nil {
			log.Println("Entity inserted: ", id)
		} else {
			log.Println("ERROR: inserting", err)
			this.Abort("400")
		}
	} else {
		if id, err := o.Update(entity); err == nil {
			log.Println("Entity updated: ", id)
		} else {
			log.Println("ERROR: updating id ", id, err)
			this.Abort("400")
		}
	}
	o.Read(entity)
}

//##########################################################

type IdeaController struct {
	BaseController
}

func (this *IdeaController) Post() {
	var ideas []*models.Idea
	this.getRequest().GetQuery("idea").All(&ideas)
	this.respond(&ideas)
}

func (this *IdeaController) Put() {
	idea := models.Idea{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &idea)
	query := models.Idea{Id:idea.Id}

	this.upsert(&query, &idea)
	this.respond(&idea)
}

//##########################################################

type UserController struct {
	BaseController
}

func (this *UserController) Post() {
	var users []*models.User
	this.getRequest().GetQuery("user").All(&users)
	this.respond(&users)
}

func (this *UserController) Put() {
	user := models.User{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &user)
	query := models.User{Id:user.Id}

	this.upsert(&query, &user)
	this.respond(&user)
}

//##########################################################

type CommentController struct {
	BaseController
}

func (this *CommentController) Post() {
	var comments []*models.Comment
	this.getRequest().GetQuery("comment").All(&comments)
	this.respond(&comments)
}

func (this *CommentController) Put() {
	comment := models.Comment{}
	json.Unmarshal(this.Ctx.Input.RequestBody, &comment)
	query := models.Comment{Id:comment.Id}

	this.upsert(&query, &comment)
	this.respond(&comment)
}

//##########################################################

type FileController struct {
	BaseController
}

func (this *FileController) Post() {
	_, header, _ := this.GetFile(FilesField);
	filename := strings.Replace(strconv.FormatInt(time.Now().Unix(), 10) + " " + header.Filename, " ", "_", -1);
	errorSave := this.SaveToFile(FilesField, FilesDir + "/" + filename);
	if errorSave != nil {
		log.Fatal(errorSave)
	}

	o := orm.NewOrm()
	file := models.File{}
	file.Title = header.Filename
	file.Filename = filename
	_, errorInsert := o.Insert(&file)
	if errorInsert != nil {
		log.Fatal(errorInsert)
	}

	o.Read(&file)
	this.Data["json"] = &file
	this.ServeJson()
}

//##########################################################
<|endoftext|>


<commit_before>package version

// Version contains the LXD version number
var Version = "4.8"
<commit_msg>Release LXD 4.9<commit_after>package version

// Version contains the LXD version number
var Version = "4.9"
<|endoftext|>


<commit_before>package testing

import (
	"errors"
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"github.com/pachyderm/pachyderm/src/pfs/drive/btrfs"
	"github.com/pachyderm/pachyderm/src/pfs/route"
	"github.com/pachyderm/pachyderm/src/pfs/server"
	"github.com/pachyderm/pachyderm/src/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/pkg/grpctest"
	"github.com/pachyderm/pachyderm/src/pkg/grpcutil"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
)

const (
	// TODO(pedge): large numbers of shards takes forever because
	// we are doing tons of btrfs operations on init, is there anything
	// we can do about that?
	testShardsPerServer = 8
	testNumServers      = 8
)

var (
	counter int32
)

func TestRepositoryName() string {
	// TODO could be nice to add callee to this string to make it easy to
	// recover results for debugging
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}

func RunTest(
	t *testing.T,
	f func(t *testing.T, apiClient pfs.ApiClient, internalAPIClient pfs.InternalApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(t, err)
	grpctest.Run(
		t,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(t, discoveryClient, servers)
		},
		func(t *testing.T, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				t,
				pfs.NewApiClient(
					clientConn,
				),
				pfs.NewInternalApiClient(
					clientConn,
				),
			)
		},
	)
}

func RunBench(
	b *testing.B,
	f func(b *testing.B, apiClient pfs.ApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(b, err)
	grpctest.RunB(
		b,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(b, discoveryClient, servers)
		},
		func(b *testing.B, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				b,
				pfs.NewApiClient(
					clientConn,
				),
			)
		},
	)
}

func registerFunc(tb testing.TB, discoveryClient discovery.Client, servers map[string]*grpc.Server) {
	addresser := route.NewDiscoveryAddresser(
		discoveryClient,
		testNamespace(),
	)
	i := 0
	for address := range servers {
		for j := 0; j < testShardsPerServer; j++ {
			// TODO(pedge): error
			_ = addresser.SetMasterAddress((i*testShardsPerServer)+j, address, 0)
			_ = addresser.SetSlaveAddress((((i+1)%len(servers))*testShardsPerServer)+j, address, 0)
			_ = addresser.SetSlaveAddress((((i+2)%len(servers))*testShardsPerServer)+j, address, 0)
		}
		i++
	}
	for address, s := range servers {
		combinedAPIServer := server.NewCombinedAPIServer(
			route.NewSharder(
				testShardsPerServer*testNumServers,
			),
			route.NewRouter(
				addresser,
				grpcutil.NewDialer(),
				address,
			),
			getDriver(tb, address),
		)
		pfs.RegisterApiServer(s, combinedAPIServer)
		pfs.RegisterInternalApiServer(s, combinedAPIServer)
	}
}

func getDriver(tb testing.TB, namespace string) drive.Driver {
	driver, err := btrfs.NewDriver(getBtrfsRootDir(tb), namespace)
	require.NoError(tb, err)
	return driver
}

func getBtrfsRootDir(tb testing.TB) string {
	// TODO(pedge)
	rootDir := os.Getenv("PFS_DRIVER_ROOT")
	if rootDir == "" {
		tb.Fatal("PFS_DRIVER_ROOT not set")
	}
	return rootDir
}

func getEtcdClient() (discovery.Client, error) {
	etcdAddress, err := getEtcdAddress()
	if err != nil {
		return nil, err
	}
	return discovery.NewEtcdClient(etcdAddress), nil
}

func getEtcdAddress() (string, error) {
	etcdAddr := os.Getenv("ETCD_PORT_2379_TCP_ADDR")
	if etcdAddr == "" {
		return "", errors.New("ETCD_PORT_2379_TCP_ADDR not set")
	}
	return fmt.Sprintf("http://%s:2379", etcdAddr), nil
}

func testNamespace() string {
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}
<commit_msg>Fix a TODO by returning errors.<commit_after>package testing

import (
	"errors"
	"fmt"
	"os"
	"sync/atomic"
	"testing"

	"github.com/pachyderm/pachyderm/src/pfs"
	"github.com/pachyderm/pachyderm/src/pfs/drive"
	"github.com/pachyderm/pachyderm/src/pfs/drive/btrfs"
	"github.com/pachyderm/pachyderm/src/pfs/route"
	"github.com/pachyderm/pachyderm/src/pfs/server"
	"github.com/pachyderm/pachyderm/src/pkg/discovery"
	"github.com/pachyderm/pachyderm/src/pkg/grpctest"
	"github.com/pachyderm/pachyderm/src/pkg/grpcutil"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc"
)

const (
	// TODO(pedge): large numbers of shards takes forever because
	// we are doing tons of btrfs operations on init, is there anything
	// we can do about that?
	testShardsPerServer = 8
	testNumServers      = 8
)

var (
	counter int32
)

func TestRepositoryName() string {
	// TODO could be nice to add callee to this string to make it easy to
	// recover results for debugging
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}

func RunTest(
	t *testing.T,
	f func(t *testing.T, apiClient pfs.ApiClient, internalAPIClient pfs.InternalApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(t, err)
	grpctest.Run(
		t,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(t, discoveryClient, servers)
		},
		func(t *testing.T, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				t,
				pfs.NewApiClient(
					clientConn,
				),
				pfs.NewInternalApiClient(
					clientConn,
				),
			)
		},
	)
}

func RunBench(
	b *testing.B,
	f func(b *testing.B, apiClient pfs.ApiClient),
) {
	discoveryClient, err := getEtcdClient()
	require.NoError(b, err)
	grpctest.RunB(
		b,
		testNumServers,
		func(servers map[string]*grpc.Server) {
			registerFunc(b, discoveryClient, servers)
		},
		func(b *testing.B, clientConns map[string]*grpc.ClientConn) {
			var clientConn *grpc.ClientConn
			for _, c := range clientConns {
				clientConn = c
				break
			}
			f(
				b,
				pfs.NewApiClient(
					clientConn,
				),
			)
		},
	)
}

func registerFunc(tb testing.TB, discoveryClient discovery.Client, servers map[string]*grpc.Server) error {
	addresser := route.NewDiscoveryAddresser(
		discoveryClient,
		testNamespace(),
	)
	i := 0
	for address := range servers {
		for j := 0; j < testShardsPerServer; j++ {
			if err := addresser.SetMasterAddress((i*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
			if err := addresser.SetSlaveAddress((((i+1)%len(servers))*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
			if err := addresser.SetSlaveAddress((((i+2)%len(servers))*testShardsPerServer)+j, address, 0); err != nil {
				return err
			}
		}
		i++
	}
	for address, s := range servers {
		combinedAPIServer := server.NewCombinedAPIServer(
			route.NewSharder(
				testShardsPerServer*testNumServers,
			),
			route.NewRouter(
				addresser,
				grpcutil.NewDialer(),
				address,
			),
			getDriver(tb, address),
		)
		pfs.RegisterApiServer(s, combinedAPIServer)
		pfs.RegisterInternalApiServer(s, combinedAPIServer)
	}
	return nil
}

func getDriver(tb testing.TB, namespace string) drive.Driver {
	driver, err := btrfs.NewDriver(getBtrfsRootDir(tb), namespace)
	require.NoError(tb, err)
	return driver
}

func getBtrfsRootDir(tb testing.TB) string {
	// TODO(pedge)
	rootDir := os.Getenv("PFS_DRIVER_ROOT")
	if rootDir == "" {
		tb.Fatal("PFS_DRIVER_ROOT not set")
	}
	return rootDir
}

func getEtcdClient() (discovery.Client, error) {
	etcdAddress, err := getEtcdAddress()
	if err != nil {
		return nil, err
	}
	return discovery.NewEtcdClient(etcdAddress), nil
}

func getEtcdAddress() (string, error) {
	etcdAddr := os.Getenv("ETCD_PORT_2379_TCP_ADDR")
	if etcdAddr == "" {
		return "", errors.New("ETCD_PORT_2379_TCP_ADDR not set")
	}
	return fmt.Sprintf("http://%s:2379", etcdAddr), nil
}

func testNamespace() string {
	return fmt.Sprintf("test-%d", atomic.AddInt32(&counter, 1))
}
<|endoftext|>


<commit_before>package controllers

import (
	"strings"
	"net/url"
	"strconv"
	"fmt"

	"github.com/shwinpiocess/cc/models"
)

type AppController struct {
	BaseController
}

func (this *AppController) Index() {
	fmt.Println("--------------------------------------------->")
	fmt.Println(this.Data)
	if this.appCount > 0 {
		this.TplName = "app/index.html"
	} else {
		this.TplName = "app/help.html"
	}
}

func (this *AppController) NewApp() {
	this.TplName = "app/newapp.html"
}

func (this *AppController) AddApp() {
	if this.isPost() {
		app := new(models.App)
		app.Type, _ = this.GetInt8("Type")
		app.Level, _ = this.GetInt8("Level")
		app.ApplicationName = strings.TrimSpace(this.GetString("ApplicationName"))
		app.LifeCycle = strings.TrimSpace(this.GetString("LifeCycle"))
		app.OwnerId = this.userId

		out := make(map[string]interface{})

		if Id, err := models.AddApp(app); err != nil {
			fmt.Println("err=", err)
			out["errInfo"] = "同名的业务已经存在！"
			out["success"] = false
			out["errCode"] = "0006"
			this.jsonResult(out)
		} else {
			this.Ctx.SetCookie("defaultAppId", strconv.Itoa(Id))
			this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))

			var fields []string
			var sortby []string
			var order []string
			var query map[string]string = make(map[string]string)
			var limit int64 = 0
			var offset int64 = 0

			query["owner_id"] = strconv.Itoa(this.userId)

			apps, _ := models.GetAllApp(query, fields, sortby, order, offset, limit)
			if len(apps) > 1 {
				out["success"] = true
				out["gotopo"] = 0
				this.jsonResult(out)
			} else {
				out["success"] = true
				out["gotopo"] = 1
				this.jsonResult(out)
			}
		}

//		this.Ctx.SetCookie("defaultAppId", strconv.Itoa(app.Id))
//		this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))

//		cnt, err := models.GetAppCountByUserId(this.userId)
//		fmt.Println("cnt=", cnt, "err=", err)
//		if err == nil {
//			if cnt > 1 {
//				out["success"] = true
//				out["gotopo"] = 0
//				this.jsonResult(out)
//			}

//			out["success"] = true
//			out["gotopo"] = 1
//			this.jsonResult(out)
//		}
//		out["success"] = false
//		out["errInfo"] = err.Error()
//		out["errCode"] = "0008"
//		this.jsonResult(out)
	}
}

func (this *AppController) DeleteApp() {
	out := make(map[string]interface{})
	applicationId, _ := this.GetInt("ApplicationID")
	if err := models.DeleteApp(applicationId); err == nil {
		out["success"] = true
		this.jsonResult(out)
	} else {
		out["success"] = false
		out["errInfo"] = err.Error()
		this.jsonResult(out)
	}
}

func (this *AppController) TopologyIndex() {
	this.TplName = "topology/set.html"
}

// 切换默认业务
func (this *AppController) SetDefaultApp() {
	out := make(map[string]interface{})
	if applicationId, err := this.GetInt("ApplicationID"); err != nil {
		out["success"] = false
		this.jsonResult(out)
	} else {
		if app, err := models.GetAppById(applicationId); err != nil {
			out["success"] = false
			this.jsonResult(out)
		} else {
			this.Ctx.SetCookie("defaultAppId", strconv.Itoa(applicationId))
			this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))
			fmt.Println("-------->", app.ApplicationName)
			out["success"] = true
			out["message"] = "业务切换成功"
			this.jsonResult(out)
		}
	}
}

// 快速分配
func (this *AppController) QuickImport() {
	this.TplName = "host/quickImport.html"
}
<commit_msg>修改Index函数判断方式，修改SetDefaultApp函数的cookie设置问题<commit_after>package controllers

import (
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"github.com/shwinpiocess/cc/models"
)

type AppController struct {
	BaseController
}

func (this *AppController) Index() {
	fmt.Println("--------------------------------------------->")
	fmt.Println(this.Data)
	if this.firstApp {
		this.TplName = "app/help.html"
	} else {
		this.TplName = "app/index.html"
	}
}

func (this *AppController) NewApp() {
	this.TplName = "app/newapp.html"
}

func (this *AppController) AddApp() {
	if this.isPost() {
		app := new(models.App)
		app.Type, _ = this.GetInt8("Type")
		app.Level, _ = this.GetInt8("Level")
		app.ApplicationName = strings.TrimSpace(this.GetString("ApplicationName"))
		app.LifeCycle = strings.TrimSpace(this.GetString("LifeCycle"))
		app.OwnerId = this.userId

		out := make(map[string]interface{})

		if Id, err := models.AddApp(app); err != nil {
			fmt.Println("err=", err)
			out["errInfo"] = "同名的业务已经存在！"
			out["success"] = false
			out["errCode"] = "0006"
			this.jsonResult(out)
		} else {
			this.Ctx.SetCookie("defaultAppId", strconv.FormatInt(Id, 10))
			this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))

			var fields []string
			var sortby []string
			var order []string
			var query map[string]string = make(map[string]string)
			var limit int64 = 0
			var offset int64 = 0

			query["owner_id"] = strconv.Itoa(this.userId)

			apps, _ := models.GetAllApp(query, fields, sortby, order, offset, limit)
			if len(apps) > 1 {
				out["success"] = true
				out["gotopo"] = 0
				this.jsonResult(out)
			} else {
				out["success"] = true
				out["gotopo"] = 1
				this.jsonResult(out)
			}
		}

		//		this.Ctx.SetCookie("defaultAppId", strconv.Itoa(app.Id))
		//		this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))

		//		cnt, err := models.GetAppCountByUserId(this.userId)
		//		fmt.Println("cnt=", cnt, "err=", err)
		//		if err == nil {
		//			if cnt > 1 {
		//				out["success"] = true
		//				out["gotopo"] = 0
		//				this.jsonResult(out)
		//			}

		//			out["success"] = true
		//			out["gotopo"] = 1
		//			this.jsonResult(out)
		//		}
		//		out["success"] = false
		//		out["errInfo"] = err.Error()
		//		out["errCode"] = "0008"
		//		this.jsonResult(out)
	}
}

func (this *AppController) DeleteApp() {
	out := make(map[string]interface{})
	applicationId, _ := this.GetInt("ApplicationID")
	if err := models.DeleteApp(applicationId); err == nil {
		out["success"] = true
		this.jsonResult(out)
	} else {
		out["success"] = false
		out["errInfo"] = err.Error()
		this.jsonResult(out)
	}
}

func (this *AppController) TopologyIndex() {
	this.TplName = "topology/set.html"
}

// 切换默认业务
func (this *AppController) SetDefaultApp() {
	out := make(map[string]interface{})
	if applicationId, err := this.GetInt("ApplicationID"); err != nil {
		out["success"] = false
		this.jsonResult(out)
	} else {
		if app, err := models.GetAppById(applicationId); err != nil {
			out["success"] = false
			this.jsonResult(out)
		} else {
			this.Ctx.SetCookie("defaultAppId", strconv.Itoa(applicationId))
			this.Ctx.SetCookie("defaultAppName", url.QueryEscape(app.ApplicationName))
			fmt.Println("-------->", app.ApplicationName)
			out["success"] = true
			out["message"] = "业务切换成功"
			this.jsonResult(out)
		}
	}
}

// 快速分配
func (this *AppController) QuickImport() {
	this.TplName = "host/quickImport.html"
}
<|endoftext|>


<commit_before>package webcontrollers

import (
	routes "github.com/byrnedo/apibase/routes"
	"net/http"
)

type PostsController struct {
}

func (pC *PostsController) GetRoutes() []*routes.WebRoute {
	return []*routes.WebRoute{
		routes.NewWebRoute("NewPost", "/api/v1/posts/:postId", routes.POST, pC.List),
		routes.NewWebRoute("ReplacePost", "/api/v1/posts/:postId", routes.PUT, pC.List),
		routes.NewWebRoute("GetPosts", "/api/v1/posts", routes.GET, pC.List),
		routes.NewWebRoute("DeletePost", "/api/v1/posts/:postId", routes.DELETE, pC.List),
	}
}

func (pC *PostsController) List(http.ResponseWriter, *http.Request) {

}
<commit_msg>Added controller body.<commit_after>package webcontrollers

import (
	routes "github.com/byrnedo/apibase/routes"
	"net/http"
	"github.com/julienschmidt/httprouter"
	"encoding/json"
"github.com/byrnedo/blogsvc/msgspec/webmsgspec"
	"github.com/byrnedo/svccommon/validate"
"gopkg.in/mgo.v2/bson"
	"github.com/byrnedo/apibase/controllers"
"github.com/byrnedo/blogsvc/daos"
	"github.com/byrnedo/apibase/db/mongo/defaultmongo"
	. "github.com/byrnedo/apibase/logger"
	svcSpec "github.com/byrnedo/svccommon/msgspec/web"

"github.com/byrnedo/blogsvc/models"
)

type PostsController struct {
	*controllers.JsonController
	postModel daos.PostDAO
}

func NewPostsController() *PostsController {
	return &PostsController{
		JsonController: &controllers.JsonController{},
		postModel:      daos.NewDefaulPostDAO(defaultmongo.Conn()),
	}
}

func (pC *PostsController) GetRoutes() []*routes.WebRoute {
	return []*routes.WebRoute{
		routes.NewWebRoute("NewPost", "/v1/posts/:postId", routes.POST, pC.Create),
		routes.NewWebRoute("ReplacePost", "/v1/posts/:postId", routes.PUT, pC.Replace),
		routes.NewWebRoute("GetPost", "/v1/posts/:postId", routes.GET, pC.GetOne),
		routes.NewWebRoute("GetPosts", "/v1/posts", routes.GET, pC.List),
		routes.NewWebRoute("DeletePost", "/v1/posts/:postId", routes.DELETE, pC.Delete),
	}
}

func (pC *PostsController) Create(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	decoder := json.NewDecoder(r.Body)
	var u webmsgspec.NewPostResource

	if err := decoder.Decode(&u); err != nil {
		Error.Println(err)
		panic("Failed to decode json:" + err.Error())
	}

	if valErrs := validate.ValidateStruct(u); len(valErrs) != 0 {
		errResponse := svcSpec.NewValidationErrorResonse(valErrs)
		pC.ServeWithStatus(w, errResponse, 400)
		return
	}

	inserted, err := pC.postModel.Create(u.Data)
	if err != nil {
		Error.Println("Error creating post:" + err.Error())
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(500), 500)
		return
	}
	pC.ServeWithStatus(w, inserted, 201)
}

func (pC *PostsController) Replace(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	id := ps.ByName("postId")
	if !bson.IsObjectIdHex(id) {
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}

	decoder := json.NewDecoder(r.Body)
	var u webmsgspec.UpdatedPostResource

	if err := decoder.Decode(&u); err != nil {
		Error.Println(err)
		panic("Failed to decode json:" + err.Error())
	}

	u.Data.ID = id

	if valErrs := validate.ValidateStruct(u); len(valErrs) != 0 {
		errResponse := svcSpec.NewValidationErrorResonse(valErrs)
		pC.ServeWithStatus(w, errResponse, 400)
		return
	}

	inserted, err := pC.postModel.Replace(u.Data)
	if err != nil {
		Error.Println("Error updating post:" + err.Error())
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(500), 500)
		return
	}
	pC.ServeWithStatus(w, inserted, 200)
}

func (pC *PostsController) GetOne(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	var (
		id    string
		err   error
		objId bson.ObjectId
		post  *models.PostModel
	)

	id = ps.ByName("postId")
	if !bson.IsObjectIdHex(id) {
		Error.Println("Id is not object id")
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}

	objId = bson.ObjectIdHex(id)

	if post, err = pC.postModel.Find(objId); err != nil {
		Error.Println("Failed to find post:" + err.Error())
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}

	pC.Serve(w, &webmsgspec.PostResource{post})
}

func (pC *PostsController) List(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	query := pC.QueryInterfaceMap(r, "query", &models.PostModel{})
	order, _ := r.URL.Query()["order"]
	offset, _ := pC.QueryInt(r, "offset")
	limit, _ := pC.QueryInt(r, "limit")

	posts, err := pC.postModel.FindMany(query, order, offset, limit)
	if err != nil {
		Error.Println("Failed to find posts:", err)
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}
	pC.Serve(w, &webmsgspec.PostsResource{posts})
}

func (pC *PostsController) Delete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

	id := ps.ByName("postId")

	if !bson.IsObjectIdHex(id) {
		Error.Println("Not an object id:", id)
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}

	if err := pC.postModel.Delete(bson.ObjectIdHex(id)); err != nil {
		Error.Println("Error deleting:", err)
		pC.ServeWithStatus(w, svcSpec.NewErrorResponse().AddCodeError(404), 404)
		return
	}

	pC.Serve(w, &webmsgspec.PostsResource{nil})
}

<|endoftext|>


<commit_before>package core

import (
	"encoding/json"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type ReferentialId string
type ReferentialSlug string

type Referential struct {
	id   ReferentialId
	slug ReferentialSlug

	collectManager CollectManagerInterface
	manager        Referentials
	model          model.Model
	modelGuardian  *ModelGuardian
	partners       Partners
}

type Referentials interface {
	New(slug ReferentialSlug) *Referential
	Find(id ReferentialId) *Referential
	FindBySlug(slug ReferentialSlug) *Referential
	FindAll() []*Referential
	Save(stopArea *Referential) bool
	Delete(stopArea *Referential) bool
	Load() error
}

var referentials = NewMemoryReferentials()

type APIReferential struct {
	Id     ReferentialId `json:"Id,omitempty"`
	Slug   ReferentialSlug
	Errors Errors `json:"Errors,omitempty"`
}

func (referential *APIReferential) Validate() bool {
	valid := true
	if referential.Slug == "" {
		referential.Errors.Add("Slug", ERROR_BLANK)
		valid = false
	}
	return valid
}

func (referential *Referential) Id() ReferentialId {
	return referential.id
}

func (referential *Referential) Slug() ReferentialSlug {
	return referential.slug
}

// WIP: Interface ?
func (referential *Referential) CollectManager() CollectManagerInterface {
	return referential.collectManager
}

func (referential *Referential) Model() model.Model {
	return referential.model
}

func (referential *Referential) ModelGuardian() *ModelGuardian {
	return referential.modelGuardian
}

func (referential *Referential) Partners() Partners {
	return referential.partners
}

func (referential *Referential) Start() {
	referential.partners.Start()
	referential.modelGuardian.Start()
}

func (referential *Referential) Stop() {
	referential.partners.Stop()
	referential.modelGuardian.Stop()
}

func (referential *Referential) Save() (ok bool) {
	ok = referential.manager.Save(referential)
	return
}

func (referential *Referential) NewTransaction() *model.Transaction {
	return model.NewTransaction(referential.model)
}

func (referential *Referential) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
		"Id":   referential.id,
		"Slug": referential.slug,
	})
}

func (referential *Referential) Definition() *APIReferential {
	return &APIReferential{
		Id:     referential.id,
		Slug:   referential.slug,
		Errors: NewErrors(),
	}
}

func (referential *Referential) SetDefinition(apiReferential *APIReferential) {
	referential.id = apiReferential.Id
	referential.slug = apiReferential.Slug
}

type MemoryReferentials struct {
	model.UUIDConsumer

	byId map[ReferentialId]*Referential
}

func NewMemoryReferentials() *MemoryReferentials {
	return &MemoryReferentials{
		byId: make(map[ReferentialId]*Referential),
	}
}

func CurrentReferentials() Referentials {
	return referentials
}

func (manager *MemoryReferentials) New(slug ReferentialSlug) *Referential {
	referential := manager.new()
	referential.slug = slug
	referential.modelGuardian = NewModelGuardian(referential)
	return referential
}

func (manager *MemoryReferentials) new() *Referential {
	model := model.NewMemoryModel()
	partners := NewPartnerManager(model)
	return &Referential{
		manager:        manager,
		model:          model,
		partners:       partners,
		collectManager: NewCollectManager(partners),
	}
}

func (manager *MemoryReferentials) Find(id ReferentialId) *Referential {
	referential, _ := manager.byId[id]
	return referential
}

func (manager *MemoryReferentials) FindBySlug(slug ReferentialSlug) *Referential {
	for _, referential := range manager.byId {
		if referential.slug == slug {
			return referential
		}
	}
	return nil
}

func (manager *MemoryReferentials) FindAll() (referentials []*Referential) {
	for _, referential := range manager.byId {
		referentials = append(referentials, referential)
	}
	return
}

func (manager *MemoryReferentials) Save(referential *Referential) bool {
	if referential.id == "" {
		referential.id = ReferentialId(manager.NewUUID())
	}
	referential.manager = manager
	manager.byId[referential.id] = referential
	return true
}

func (manager *MemoryReferentials) Delete(referential *Referential) bool {
	delete(manager.byId, referential.id)
	return true
}

func (manager *MemoryReferentials) Load() error {
	var selectReferentials []struct {
		Referential_id string
		Slug           string
	}
	_, err := model.Database.Select(&selectReferentials, "select * from referentials")
	if err != nil {
		return err
	}

	for _, r := range selectReferentials {
		referential := manager.new()
		referential.id = ReferentialId(r.Referential_id)
		referential.slug = ReferentialSlug(r.Slug)
		manager.Save(referential)
	}

	logger.Log.Debugf("Loaded Referentials from database")
	return nil
}

type ReferentialsConsumer struct {
	referentials Referentials
}

func (consumer *ReferentialsConsumer) SetReferentials(referentials Referentials) {
	consumer.referentials = referentials
}

func (consumer *ReferentialsConsumer) CurrentReferentials() Referentials {
	if consumer.referentials == nil {
		consumer.referentials = CurrentReferentials()
	}
	return consumer.referentials
}
<commit_msg>Referential: Cleanup New function, move Guardian start<commit_after>package core

import (
	"encoding/json"

	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
)

type ReferentialId string
type ReferentialSlug string

type Referential struct {
	id   ReferentialId
	slug ReferentialSlug

	collectManager CollectManagerInterface
	manager        Referentials
	model          model.Model
	modelGuardian  *ModelGuardian
	partners       Partners
}

type Referentials interface {
	New(slug ReferentialSlug) *Referential
	Find(id ReferentialId) *Referential
	FindBySlug(slug ReferentialSlug) *Referential
	FindAll() []*Referential
	Save(stopArea *Referential) bool
	Delete(stopArea *Referential) bool
	Load() error
}

var referentials = NewMemoryReferentials()

type APIReferential struct {
	Id     ReferentialId `json:"Id,omitempty"`
	Slug   ReferentialSlug
	Errors Errors `json:"Errors,omitempty"`
}

func (referential *APIReferential) Validate() bool {
	valid := true
	if referential.Slug == "" {
		referential.Errors.Add("Slug", ERROR_BLANK)
		valid = false
	}
	return valid
}

func (referential *Referential) Id() ReferentialId {
	return referential.id
}

func (referential *Referential) Slug() ReferentialSlug {
	return referential.slug
}

// WIP: Interface ?
func (referential *Referential) CollectManager() CollectManagerInterface {
	return referential.collectManager
}

func (referential *Referential) Model() model.Model {
	return referential.model
}

func (referential *Referential) ModelGuardian() *ModelGuardian {
	return referential.modelGuardian
}

func (referential *Referential) Partners() Partners {
	return referential.partners
}

func (referential *Referential) Start() {
	referential.partners.Start()
	referential.modelGuardian.Start()
}

func (referential *Referential) Stop() {
	referential.partners.Stop()
	referential.modelGuardian.Stop()
}

func (referential *Referential) Save() (ok bool) {
	ok = referential.manager.Save(referential)
	return
}

func (referential *Referential) NewTransaction() *model.Transaction {
	return model.NewTransaction(referential.model)
}

func (referential *Referential) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
		"Id":   referential.id,
		"Slug": referential.slug,
	})
}

func (referential *Referential) Definition() *APIReferential {
	return &APIReferential{
		Id:     referential.id,
		Slug:   referential.slug,
		Errors: NewErrors(),
	}
}

func (referential *Referential) SetDefinition(apiReferential *APIReferential) {
	referential.id = apiReferential.Id
	referential.slug = apiReferential.Slug
}

type MemoryReferentials struct {
	model.UUIDConsumer

	byId map[ReferentialId]*Referential
}

func NewMemoryReferentials() *MemoryReferentials {
	return &MemoryReferentials{
		byId: make(map[ReferentialId]*Referential),
	}
}

func CurrentReferentials() Referentials {
	return referentials
}

func (manager *MemoryReferentials) New(slug ReferentialSlug) *Referential {
	referential := manager.new()
	referential.slug = slug
	return referential
}

func (manager *MemoryReferentials) new() *Referential {
	model := model.NewMemoryModel()
	partners := NewPartnerManager(model)
	referential := &Referential{
		manager:        manager,
		model:          model,
		partners:       partners,
		collectManager: NewCollectManager(partners),
	}
	referential.modelGuardian = NewModelGuardian(referential)
	return referential
}

func (manager *MemoryReferentials) Find(id ReferentialId) *Referential {
	referential, _ := manager.byId[id]
	return referential
}

func (manager *MemoryReferentials) FindBySlug(slug ReferentialSlug) *Referential {
	for _, referential := range manager.byId {
		if referential.slug == slug {
			return referential
		}
	}
	return nil
}

func (manager *MemoryReferentials) FindAll() (referentials []*Referential) {
	for _, referential := range manager.byId {
		referentials = append(referentials, referential)
	}
	return
}

func (manager *MemoryReferentials) Save(referential *Referential) bool {
	if referential.id == "" {
		referential.id = ReferentialId(manager.NewUUID())
	}
	referential.manager = manager
	manager.byId[referential.id] = referential
	return true
}

func (manager *MemoryReferentials) Delete(referential *Referential) bool {
	delete(manager.byId, referential.id)
	return true
}

func (manager *MemoryReferentials) Load() error {
	var selectReferentials []struct {
		Referential_id string
		Slug           string
	}
	_, err := model.Database.Select(&selectReferentials, "select * from referentials")
	if err != nil {
		return err
	}

	for _, r := range selectReferentials {
		referential := manager.new()
		referential.id = ReferentialId(r.Referential_id)
		referential.slug = ReferentialSlug(r.Slug)
		manager.Save(referential)
	}

	logger.Log.Debugf("Loaded Referentials from database")
	return nil
}

type ReferentialsConsumer struct {
	referentials Referentials
}

func (consumer *ReferentialsConsumer) SetReferentials(referentials Referentials) {
	consumer.referentials = referentials
}

func (consumer *ReferentialsConsumer) CurrentReferentials() Referentials {
	if consumer.referentials == nil {
		consumer.referentials = CurrentReferentials()
	}
	return consumer.referentials
}
<|endoftext|>


<commit_before>package controllers
import (
	"github.com/byrnedo/apibase/routes"
	"github.com/gorilla/mux"
	"net/http"
	"encoding/json"
	. "github.com/byrnedo/apibase/logger"
)

type WebController interface {
	GetRoutes() []*routes.WebRoute
}

// Registers an array of route handlers to gorilla/mux
func RegisterMuxRoutes(rtr *mux.Router, controller WebController) {
	for _, route := range controller.GetRoutes() {
		rtr.
		Methods(route.GetMethod()).
		Path(route.GetPath()).
		Name(route.GetName()).
		Handler(route.GetHandler())
	}
}

// Custom handler to transform error into
// json
// TODO use func type instead
type JsonErrorHandler interface {
	ToJson(message string, status int) []byte
}

// Controller with json helpers
type JsonController struct {
	errorHandler JsonErrorHandler
}

// Creates new controller using supplied error handler
func NewJsonController(errorHandler JsonErrorHandler) *JsonController {
	return &JsonController{
		errorHandler: errorHandler,
	}
}

// Serve standard 200
func (jC *JsonController) ServeJson(w http.ResponseWriter, data interface{}) {
	jC.ServeJsonStatus(w, data, 200)
}

// Serve with custom status
func (jC *JsonController) ServeJsonStatus(w http.ResponseWriter, data interface{}, status int) {
	dataBytes, err := json.Marshal(data)
	if err != nil {
		Error.Println("Failed to marshal payload:" + err.Error())
		jC.JsonError(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)
	w.Write(dataBytes)
}

// Serve error
func (jC *JsonController) JsonError(w http.ResponseWriter, message string, status int) {
	jsonErr := jC.errorHandler.ToJson(message, status)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(status)
	w.Write(jsonErr)
}<commit_msg>Updated documentation.<commit_after>package controllers
import (
	"github.com/byrnedo/apibase/routes"
	"github.com/gorilla/mux"
	"net/http"
	"encoding/json"
	. "github.com/byrnedo/apibase/logger"
)

type WebController interface {
	GetRoutes() []*routes.WebRoute
}

// Registers an array of route handlers to gorilla/mux
func RegisterMuxRoutes(rtr *mux.Router, controller WebController) {
	for _, route := range controller.GetRoutes() {
		rtr.
		Methods(route.GetMethod()).
		Path(route.GetPath()).
		Name(route.GetName()).
		Handler(route.GetHandler())
	}
}

// Custom handler to transform error into
// json
// TODO use func type instead
type JsonErrorHandler interface {
	ToJson(message string, status int) []byte
}

// Controller with json helpers
type JsonController struct {
	errorHandler JsonErrorHandler
}

// Creates new controller using supplied error handler
func NewJsonController(errorHandler JsonErrorHandler) *JsonController {
	return &JsonController{
		errorHandler: errorHandler,
	}
}

// Serve standard 200
func (jC *JsonController) ServeJson(w http.ResponseWriter, data interface{}) {
	jC.ServeJsonStatus(w, data, 200)
}

// Serve with custom status
func (jC *JsonController) ServeJsonStatus(w http.ResponseWriter, data interface{}, status int) {
	dataBytes, err := json.Marshal(data)
	if err != nil {
		Error.Println("Failed to marshal payload:" + err.Error())
		jC.ServeError(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)
	w.Write(dataBytes)
}

// Serve error
func (jC *JsonController) ServeError(w http.ResponseWriter, message string, status int) {
	jsonErr := jC.errorHandler.ToJson(message, status)
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(status)
	w.Write(jsonErr)
}<|endoftext|>