<commit_before>package hook

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

	"github.com/bitrise-io/bitrise-webhooks/bitriseapi"
	"github.com/bitrise-io/bitrise-webhooks/config"
	"github.com/bitrise-io/bitrise-webhooks/metrics"
	"github.com/bitrise-io/bitrise-webhooks/service"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/bitbucketv2"
	hookCommon "github.com/bitrise-io/bitrise-webhooks/service/hook/common"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/github"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/slack"
	"github.com/gorilla/mux"
)

func supportedProviders() map[string]hookCommon.Provider {
	return map[string]hookCommon.Provider{
		"github":       github.HookProvider{},
		"bitbucket-v2": bitbucketv2.HookProvider{},
		"slack":        slack.HookProvider{},
	}
}

// ----------------------------------
// --- Response handler functions ---

func respondWithErrorString(w http.ResponseWriter, provider *hookCommon.Provider, errStr string) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformErrorMessageResponse(errStr)
	httpStatusCode := 400 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

func respondWithSuccessMessage(w http.ResponseWriter, provider *hookCommon.Provider, msg string) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformSuccessMessageResponse(msg)
	httpStatusCode := 201 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

func respondWithResults(w http.ResponseWriter, provider *hookCommon.Provider, results hookCommon.TransformResponseInputModel) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformResponse(results)
	httpStatusCode := 201 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

// -------------------------
// --- Utility functions ---

func triggerBuild(triggerURL *url.URL, apiToken string, triggerAPIParams bitriseapi.TriggerAPIParamsModel) (bitriseapi.TriggerAPIResponseModel, bool, error) {
	log.Printf(" ===> trigger build: %s", triggerURL)
	isOnlyLog := !(config.SendRequestToURL != nil || config.GetServerEnvMode() == config.ServerEnvModeProd)
	if isOnlyLog {
		log.Println(" (debug) isOnlyLog: true")
	}

	responseModel, isSuccess, err := bitriseapi.TriggerBuild(triggerURL, apiToken, triggerAPIParams, isOnlyLog)
	if err != nil {
		log.Printf(" [!] Exception: failed to trigger build: %s", err)
		return bitriseapi.TriggerAPIResponseModel{}, false, fmt.Errorf("Failed to Trigger the Build: %s", err)
	}
	log.Printf(" ===> trigger build - DONE (success: %t) (%s)", isSuccess, triggerURL)
	log.Printf("      (debug) response: (%#v)", responseModel)
	return responseModel, isSuccess, nil
}

// ------------------------------
// --- Main HTTP Handler code ---

// HTTPHandler ...
func HTTPHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	serviceID := vars["service-id"]
	appSlug := vars["app-slug"]
	apiToken := vars["api-token"]

	if serviceID == "" {
		respondWithErrorString(w, nil, "No service-id defined")
		return
	}
	hookProvider, isSupported := supportedProviders()[serviceID]
	if !isSupported {
		respondWithErrorString(w, nil, fmt.Sprintf("Unsupported Webhook Type / Provider: %s", serviceID))
		return
	}

	if appSlug == "" {
		respondWithErrorString(w, &hookProvider, "No App Slug parameter defined")
		return
	}
	if apiToken == "" {
		respondWithErrorString(w, &hookProvider, "No API Token parameter defined")
		return
	}

	hookTransformResult := hookCommon.TransformResultModel{}
	metrics.Trace("Hook: Transform", func() {
		hookTransformResult = hookProvider.TransformRequest(r)
	})

	if hookTransformResult.ShouldSkip {
		respondWithSuccessMessage(w, &hookProvider, fmt.Sprintf("Acknowledged, but skipping. Reason: %s", hookTransformResult.Error))
		return
	}
	if hookTransformResult.Error != nil {
		errMsg := fmt.Sprintf("Failed to transform the webhook: %s", hookTransformResult.Error)
		log.Printf(" (debug) %s", errMsg)
		respondWithErrorString(w, &hookProvider, errMsg)
		return
	}

	// Let's Trigger a build / some builds!
	triggerURL := config.SendRequestToURL
	if triggerURL == nil {
		u, err := bitriseapi.BuildTriggerURL("https://www.bitrise.io", appSlug)
		if err != nil {
			log.Printf(" [!] Exception: hookHandler: failed to create Build Trigger URL: %s", err)
			respondWithErrorString(w, &hookProvider, fmt.Sprintf("Failed to create Build Trigger URL: %s", err))
			return
		}
		triggerURL = u
	}

	buildTriggerCount := len(hookTransformResult.TriggerAPIParams)
	if buildTriggerCount == 0 {
		respondWithErrorString(w, &hookProvider, "After processing the webhook we failed to detect any event in it which could be turned into a build.")
		return
	}

	respondWith := hookCommon.TransformResponseInputModel{
		Errors:                  []string{},
		SuccessTriggerResponses: []bitriseapi.TriggerAPIResponseModel{},
		FailedTriggerResponses:  []bitriseapi.TriggerAPIResponseModel{},
	}
	metrics.Trace("Hook: Trigger Builds", func() {
		for _, aBuildTriggerParam := range hookTransformResult.TriggerAPIParams {
			if triggerResp, isSuccess, err := triggerBuild(triggerURL, apiToken, aBuildTriggerParam); err != nil {
				respondWith.Errors = append(respondWith.Errors, fmt.Sprintf("Failed to Trigger Build: %s", err))
			} else if isSuccess {
				respondWith.SuccessTriggerResponses = append(respondWith.SuccessTriggerResponses, triggerResp)
			} else {
				respondWith.FailedTriggerResponses = append(respondWith.FailedTriggerResponses, triggerResp)
			}
		}
	})

	respondWithResults(w, &hookProvider, respondWith)
}
<commit_msg>Slack: endpoint / provider ID changed - from "slack" to "slack-webhook" -> preparing for "slack-slash-command" support<commit_after>package hook

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

	"github.com/bitrise-io/bitrise-webhooks/bitriseapi"
	"github.com/bitrise-io/bitrise-webhooks/config"
	"github.com/bitrise-io/bitrise-webhooks/metrics"
	"github.com/bitrise-io/bitrise-webhooks/service"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/bitbucketv2"
	hookCommon "github.com/bitrise-io/bitrise-webhooks/service/hook/common"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/github"
	"github.com/bitrise-io/bitrise-webhooks/service/hook/slack"
	"github.com/gorilla/mux"
)

func supportedProviders() map[string]hookCommon.Provider {
	return map[string]hookCommon.Provider{
		"github":        github.HookProvider{},
		"bitbucket-v2":  bitbucketv2.HookProvider{},
		"slack-webhook": slack.HookProvider{},
	}
}

// ----------------------------------
// --- Response handler functions ---

func respondWithErrorString(w http.ResponseWriter, provider *hookCommon.Provider, errStr string) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformErrorMessageResponse(errStr)
	httpStatusCode := 400 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

func respondWithSuccessMessage(w http.ResponseWriter, provider *hookCommon.Provider, msg string) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformSuccessMessageResponse(msg)
	httpStatusCode := 201 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

func respondWithResults(w http.ResponseWriter, provider *hookCommon.Provider, results hookCommon.TransformResponseInputModel) {
	responseProvider := hookCommon.ResponseTransformer(DefaultResponseProvider{})
	if provider != nil {
		if respTransformer, ok := (*provider).(hookCommon.ResponseTransformer); ok {
			// provider can transform responses - let it do so
			responseProvider = respTransformer
		}
	}
	//
	respInfo := responseProvider.TransformResponse(results)
	httpStatusCode := 201 // default
	if respInfo.HTTPStatusCode != 0 {
		httpStatusCode = respInfo.HTTPStatusCode
	}
	service.RespondWith(w, httpStatusCode, respInfo.Data)
}

// -------------------------
// --- Utility functions ---

func triggerBuild(triggerURL *url.URL, apiToken string, triggerAPIParams bitriseapi.TriggerAPIParamsModel) (bitriseapi.TriggerAPIResponseModel, bool, error) {
	log.Printf(" ===> trigger build: %s", triggerURL)
	isOnlyLog := !(config.SendRequestToURL != nil || config.GetServerEnvMode() == config.ServerEnvModeProd)
	if isOnlyLog {
		log.Println(" (debug) isOnlyLog: true")
	}

	responseModel, isSuccess, err := bitriseapi.TriggerBuild(triggerURL, apiToken, triggerAPIParams, isOnlyLog)
	if err != nil {
		log.Printf(" [!] Exception: failed to trigger build: %s", err)
		return bitriseapi.TriggerAPIResponseModel{}, false, fmt.Errorf("Failed to Trigger the Build: %s", err)
	}
	log.Printf(" ===> trigger build - DONE (success: %t) (%s)", isSuccess, triggerURL)
	log.Printf("      (debug) response: (%#v)", responseModel)
	return responseModel, isSuccess, nil
}

// ------------------------------
// --- Main HTTP Handler code ---

// HTTPHandler ...
func HTTPHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	serviceID := vars["service-id"]
	appSlug := vars["app-slug"]
	apiToken := vars["api-token"]

	if serviceID == "" {
		respondWithErrorString(w, nil, "No service-id defined")
		return
	}
	hookProvider, isSupported := supportedProviders()[serviceID]
	if !isSupported {
		respondWithErrorString(w, nil, fmt.Sprintf("Unsupported Webhook Type / Provider: %s", serviceID))
		return
	}

	if appSlug == "" {
		respondWithErrorString(w, &hookProvider, "No App Slug parameter defined")
		return
	}
	if apiToken == "" {
		respondWithErrorString(w, &hookProvider, "No API Token parameter defined")
		return
	}

	hookTransformResult := hookCommon.TransformResultModel{}
	metrics.Trace("Hook: Transform", func() {
		hookTransformResult = hookProvider.TransformRequest(r)
	})

	if hookTransformResult.ShouldSkip {
		respondWithSuccessMessage(w, &hookProvider, fmt.Sprintf("Acknowledged, but skipping. Reason: %s", hookTransformResult.Error))
		return
	}
	if hookTransformResult.Error != nil {
		errMsg := fmt.Sprintf("Failed to transform the webhook: %s", hookTransformResult.Error)
		log.Printf(" (debug) %s", errMsg)
		respondWithErrorString(w, &hookProvider, errMsg)
		return
	}

	// Let's Trigger a build / some builds!
	triggerURL := config.SendRequestToURL
	if triggerURL == nil {
		u, err := bitriseapi.BuildTriggerURL("https://www.bitrise.io", appSlug)
		if err != nil {
			log.Printf(" [!] Exception: hookHandler: failed to create Build Trigger URL: %s", err)
			respondWithErrorString(w, &hookProvider, fmt.Sprintf("Failed to create Build Trigger URL: %s", err))
			return
		}
		triggerURL = u
	}

	buildTriggerCount := len(hookTransformResult.TriggerAPIParams)
	if buildTriggerCount == 0 {
		respondWithErrorString(w, &hookProvider, "After processing the webhook we failed to detect any event in it which could be turned into a build.")
		return
	}

	respondWith := hookCommon.TransformResponseInputModel{
		Errors:                  []string{},
		SuccessTriggerResponses: []bitriseapi.TriggerAPIResponseModel{},
		FailedTriggerResponses:  []bitriseapi.TriggerAPIResponseModel{},
	}
	metrics.Trace("Hook: Trigger Builds", func() {
		for _, aBuildTriggerParam := range hookTransformResult.TriggerAPIParams {
			if triggerResp, isSuccess, err := triggerBuild(triggerURL, apiToken, aBuildTriggerParam); err != nil {
				respondWith.Errors = append(respondWith.Errors, fmt.Sprintf("Failed to Trigger Build: %s", err))
			} else if isSuccess {
				respondWith.SuccessTriggerResponses = append(respondWith.SuccessTriggerResponses, triggerResp)
			} else {
				respondWith.FailedTriggerResponses = append(respondWith.FailedTriggerResponses, triggerResp)
			}
		}
	})

	respondWithResults(w, &hookProvider, respondWith)
}
<|endoftext|>


<commit_before>package hh

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/influxdb/influxdb/tsdb"
)

type Processor struct {
	mu sync.RWMutex

	dir            string
	maxSize        int64
	maxAge         time.Duration
	retryRateLimit int64

	queues map[uint64]*queue
	writer shardWriter
	Logger *log.Logger
}

type ProcessorOptions struct {
	MaxSize        int64
	RetryRateLimit int64
}

func NewProcessor(dir string, writer shardWriter, options ProcessorOptions) (*Processor, error) {
	p := &Processor{
		dir:    dir,
		queues: map[uint64]*queue{},
		writer: writer,
	}
	p.setOptions(options)

	// Create the root directory if it doesn't already exist.
	if err := os.MkdirAll(dir, 0700); err != nil {
		return nil, fmt.Errorf("mkdir all: %s", err)
	}

	if err := p.loadQueues(); err != nil {
		return p, err
	}
	return p, nil
}

func (p *Processor) setOptions(options ProcessorOptions) {
	p.maxSize = DefaultMaxSize
	if options.MaxSize != 0 {
		p.maxSize = options.MaxSize
	}

	p.retryRateLimit = DefaultRetryRateLimit
	if options.RetryRateLimit != 0 {
		p.retryRateLimit = options.RetryRateLimit
	}
}

func (p *Processor) loadQueues() error {
	files, err := ioutil.ReadDir(p.dir)
	if err != nil {
		return err
	}

	for _, file := range files {
		nodeID, err := strconv.ParseUint(file.Name(), 10, 64)
		if err != nil {
			return err
		}

		if _, err := p.addQueue(nodeID); err != nil {
			return err
		}
	}
	return nil
}

func (p *Processor) addQueue(nodeID uint64) (*queue, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	path := filepath.Join(p.dir, strconv.FormatUint(nodeID, 10))
	if err := os.MkdirAll(path, 0700); err != nil {
		return nil, err
	}

	queue, err := newQueue(path, p.maxSize)
	if err != nil {
		return nil, err
	}
	if err := queue.Open(); err != nil {
		return nil, err
	}
	p.queues[nodeID] = queue
	return queue, nil
}

func (p *Processor) WriteShard(shardID, ownerID uint64, points []tsdb.Point) error {
	queue, ok := p.queues[ownerID]
	if !ok {
		var err error
		if queue, err = p.addQueue(ownerID); err != nil {
			return err
		}
	}

	b := p.marshalWrite(shardID, points)
	return queue.Append(b)
}

func (p *Processor) Process() error {
	p.mu.RLock()
	defer p.mu.RUnlock()

	res := make(chan error, len(p.queues))
	for nodeID, q := range p.queues {
		go func(nodeID uint64, q *queue) {
			for {
				// Get the current block from the queue
				buf, err := q.Current()
				if err != nil {
					res <- nil
					break
				}

				// unmarshal the byte slice back to shard ID and points
				shardID, points, err := p.unmarshalWrite(buf)
				if err != nil {
					// TODO: If we ever get and error here, we should probably drop the
					// the write and let anti-entropy resolve it.  This would be an urecoverable
					// error and could block the queue indefinitely.
					res <- err
					return
				}

				// Try to send the write to the node
				if err := p.writer.WriteShard(shardID, nodeID, points); err != nil {
					p.Logger.Printf("remote write failed: %v", err)
					res <- nil
					break
				}

				// If we get here, the write succeed to advance the queue to the next item
				if err := q.Advance(); err != nil {
					res <- err
					return
				}
			}
		}(nodeID, q)
	}

	for range p.queues {
		err := <-res
		if err != nil {
			return err
		}
	}
	return nil
}

func (p *Processor) marshalWrite(shardID uint64, points []tsdb.Point) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, shardID)
	for _, p := range points {
		b = append(b, []byte(p.String())...)
		b = append(b, '\n')
	}
	return b
}

func (p *Processor) unmarshalWrite(b []byte) (uint64, []tsdb.Point, error) {
	ownerID := binary.BigEndian.Uint64(b[:8])
	points, err := tsdb.ParsePoints(b[8:])
	return ownerID, points, err
}

func (p *Processor) PurgeOlderThan(when time.Duration) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	for _, queue := range p.queues {
		if err := queue.PurgeOlderThan(time.Now().Add(-when)); err != nil {
			return err
		}
	}
	return nil
}
<commit_msg>Fix comment in hinted handoff processor<commit_after>package hh

import (
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"github.com/influxdb/influxdb/tsdb"
)

type Processor struct {
	mu sync.RWMutex

	dir            string
	maxSize        int64
	maxAge         time.Duration
	retryRateLimit int64

	queues map[uint64]*queue
	writer shardWriter
	Logger *log.Logger
}

type ProcessorOptions struct {
	MaxSize        int64
	RetryRateLimit int64
}

func NewProcessor(dir string, writer shardWriter, options ProcessorOptions) (*Processor, error) {
	p := &Processor{
		dir:    dir,
		queues: map[uint64]*queue{},
		writer: writer,
	}
	p.setOptions(options)

	// Create the root directory if it doesn't already exist.
	if err := os.MkdirAll(dir, 0700); err != nil {
		return nil, fmt.Errorf("mkdir all: %s", err)
	}

	if err := p.loadQueues(); err != nil {
		return p, err
	}
	return p, nil
}

func (p *Processor) setOptions(options ProcessorOptions) {
	p.maxSize = DefaultMaxSize
	if options.MaxSize != 0 {
		p.maxSize = options.MaxSize
	}

	p.retryRateLimit = DefaultRetryRateLimit
	if options.RetryRateLimit != 0 {
		p.retryRateLimit = options.RetryRateLimit
	}
}

func (p *Processor) loadQueues() error {
	files, err := ioutil.ReadDir(p.dir)
	if err != nil {
		return err
	}

	for _, file := range files {
		nodeID, err := strconv.ParseUint(file.Name(), 10, 64)
		if err != nil {
			return err
		}

		if _, err := p.addQueue(nodeID); err != nil {
			return err
		}
	}
	return nil
}

func (p *Processor) addQueue(nodeID uint64) (*queue, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	path := filepath.Join(p.dir, strconv.FormatUint(nodeID, 10))
	if err := os.MkdirAll(path, 0700); err != nil {
		return nil, err
	}

	queue, err := newQueue(path, p.maxSize)
	if err != nil {
		return nil, err
	}
	if err := queue.Open(); err != nil {
		return nil, err
	}
	p.queues[nodeID] = queue
	return queue, nil
}

func (p *Processor) WriteShard(shardID, ownerID uint64, points []tsdb.Point) error {
	queue, ok := p.queues[ownerID]
	if !ok {
		var err error
		if queue, err = p.addQueue(ownerID); err != nil {
			return err
		}
	}

	b := p.marshalWrite(shardID, points)
	return queue.Append(b)
}

func (p *Processor) Process() error {
	p.mu.RLock()
	defer p.mu.RUnlock()

	res := make(chan error, len(p.queues))
	for nodeID, q := range p.queues {
		go func(nodeID uint64, q *queue) {
			for {
				// Get the current block from the queue
				buf, err := q.Current()
				if err != nil {
					res <- nil
					break
				}

				// unmarshal the byte slice back to shard ID and points
				shardID, points, err := p.unmarshalWrite(buf)
				if err != nil {
					// TODO: If we ever get and error here, we should probably drop the
					// the write and let anti-entropy resolve it.  This would be an urecoverable
					// error and could block the queue indefinitely.
					res <- err
					return
				}

				// Try to send the write to the node
				if err := p.writer.WriteShard(shardID, nodeID, points); err != nil {
					p.Logger.Printf("remote write failed: %v", err)
					res <- nil
					break
				}

				// If we get here, the write succeeded so advance the queue to the next item
				if err := q.Advance(); err != nil {
					res <- err
					return
				}
			}
		}(nodeID, q)
	}

	for range p.queues {
		err := <-res
		if err != nil {
			return err
		}
	}
	return nil
}

func (p *Processor) marshalWrite(shardID uint64, points []tsdb.Point) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, shardID)
	for _, p := range points {
		b = append(b, []byte(p.String())...)
		b = append(b, '\n')
	}
	return b
}

func (p *Processor) unmarshalWrite(b []byte) (uint64, []tsdb.Point, error) {
	ownerID := binary.BigEndian.Uint64(b[:8])
	points, err := tsdb.ParsePoints(b[8:])
	return ownerID, points, err
}

func (p *Processor) PurgeOlderThan(when time.Duration) error {
	p.mu.Lock()
	defer p.mu.Unlock()

	for _, queue := range p.queues {
		if err := queue.PurgeOlderThan(time.Now().Add(-when)); err != nil {
			return err
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package crypto

import (
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/serial"
)

// ChunkSizeDecoder is an utility class to decode size value from bytes.
type ChunkSizeDecoder interface {
	SizeBytes() int
	Decode([]byte) (uint16, error)
}

// ChunkSizeEncoder is an utility class to encode size value into bytes.
type ChunkSizeEncoder interface {
	SizeBytes() int
	Encode(uint16, []byte) []byte
}

type PlainChunkSizeParser struct{}

func (PlainChunkSizeParser) SizeBytes() int {
	return 2
}

func (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {
	return serial.Uint16ToBytes(size, b)
}

func (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {
	return serial.BytesToUint16(b), nil
}

type AEADChunkSizeParser struct {
	Auth *AEADAuthenticator
}

func (p *AEADChunkSizeParser) SizeBytes() int {
	return 2 + p.Auth.Overhead()
}

func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
	b = serial.Uint16ToBytes(size-uint16(p.Auth.Overhead()), b)
	b, err := p.Auth.Seal(b[:0], b)
	common.Must(err)
	return b
}

func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {
	b, err := p.Auth.Open(b[:0], b)
	if err != nil {
		return 0, err
	}
	return serial.BytesToUint16(b) + uint16(p.Auth.Overhead()), nil
}

type ChunkStreamReader struct {
	sizeDecoder ChunkSizeDecoder
	reader      buf.Reader

	buffer       []byte
	leftOver     buf.MultiBuffer
	leftOverSize int
}

func NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {
	return &ChunkStreamReader{
		sizeDecoder: sizeDecoder,
		reader:      buf.NewReader(reader),
		buffer:      make([]byte, sizeDecoder.SizeBytes()),
		leftOver:    buf.NewMultiBufferCap(16),
	}
}

func (r *ChunkStreamReader) readAtLeast(size int) error {
	mb := r.leftOver
	r.leftOver = nil
	for mb.Len() < size {
		extra, err := r.reader.ReadMultiBuffer()
		if err != nil {
			mb.Release()
			return err
		}
		mb.AppendMulti(extra)
	}
	r.leftOver = mb

	return nil
}

func (r *ChunkStreamReader) readSize() (uint16, error) {
	if r.sizeDecoder.SizeBytes() > r.leftOver.Len() {
		if err := r.readAtLeast(r.sizeDecoder.SizeBytes() - r.leftOver.Len()); err != nil {
			return 0, err
		}
	}
	common.Must2(io.ReadFull(&r.leftOver, r.buffer))
	return r.sizeDecoder.Decode(r.buffer)
}

func (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	size := r.leftOverSize
	if size == 0 {
		nextSize, err := r.readSize()
		if err != nil {
			return nil, err
		}
		if nextSize == 0 {
			return nil, io.EOF
		}
		size = int(nextSize)
	}

	if r.leftOver.IsEmpty() {
		if err := r.readAtLeast(1); err != nil {
			return nil, err
		}
	}

	leftOverLen := r.leftOver.Len()
	if size >= leftOverLen {
		mb := r.leftOver
		r.leftOverSize = size - leftOverLen
		r.leftOver = nil
		return mb, nil
	}

	mb := r.leftOver.SliceBySize(size)
	mbLen := mb.Len()
	if mbLen != size {
		b := buf.New()
		common.Must(b.Reset(buf.ReadFullFrom(&r.leftOver, size-mbLen)))
		mb.Append(b)
	}
	r.leftOverSize = 0

	return mb, nil
}

type ChunkStreamWriter struct {
	sizeEncoder ChunkSizeEncoder
	writer      buf.Writer
}

func NewChunkStreamWriter(sizeEncoder ChunkSizeEncoder, writer io.Writer) *ChunkStreamWriter {
	return &ChunkStreamWriter{
		sizeEncoder: sizeEncoder,
		writer:      buf.NewWriter(writer),
	}
}

func (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	const sliceSize = 8192
	mbLen := mb.Len()
	mb2Write := buf.NewMultiBufferCap(mbLen/buf.Size + mbLen/sliceSize + 2)

	for {
		slice := mb.SliceBySize(sliceSize)

		b := buf.New()
		common.Must(b.Reset(func(buffer []byte) (int, error) {
			w.sizeEncoder.Encode(uint16(slice.Len()), buffer[:0])
			return w.sizeEncoder.SizeBytes(), nil
		}))
		mb2Write.Append(b)
		mb2Write.AppendMulti(slice)

		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}
<commit_msg>simplify chunk stream reader<commit_after>package crypto

import (
	"io"

	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/serial"
)

// ChunkSizeDecoder is an utility class to decode size value from bytes.
type ChunkSizeDecoder interface {
	SizeBytes() int
	Decode([]byte) (uint16, error)
}

// ChunkSizeEncoder is an utility class to encode size value into bytes.
type ChunkSizeEncoder interface {
	SizeBytes() int
	Encode(uint16, []byte) []byte
}

type PlainChunkSizeParser struct{}

func (PlainChunkSizeParser) SizeBytes() int {
	return 2
}

func (PlainChunkSizeParser) Encode(size uint16, b []byte) []byte {
	return serial.Uint16ToBytes(size, b)
}

func (PlainChunkSizeParser) Decode(b []byte) (uint16, error) {
	return serial.BytesToUint16(b), nil
}

type AEADChunkSizeParser struct {
	Auth *AEADAuthenticator
}

func (p *AEADChunkSizeParser) SizeBytes() int {
	return 2 + p.Auth.Overhead()
}

func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
	b = serial.Uint16ToBytes(size-uint16(p.Auth.Overhead()), b)
	b, err := p.Auth.Seal(b[:0], b)
	common.Must(err)
	return b
}

func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {
	b, err := p.Auth.Open(b[:0], b)
	if err != nil {
		return 0, err
	}
	return serial.BytesToUint16(b) + uint16(p.Auth.Overhead()), nil
}

type ChunkStreamReader struct {
	sizeDecoder ChunkSizeDecoder
	reader      *buf.BufferedReader

	buffer       []byte
	leftOverSize int
}

func NewChunkStreamReader(sizeDecoder ChunkSizeDecoder, reader io.Reader) *ChunkStreamReader {
	return &ChunkStreamReader{
		sizeDecoder: sizeDecoder,
		reader:      buf.NewBufferedReader(buf.NewReader(reader)),
		buffer:      make([]byte, sizeDecoder.SizeBytes()),
	}
}

func (r *ChunkStreamReader) readSize() (uint16, error) {
	if _, err := io.ReadFull(r.reader, r.buffer); err != nil {
		return 0, err
	}
	return r.sizeDecoder.Decode(r.buffer)
}

func (r *ChunkStreamReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	size := r.leftOverSize
	if size == 0 {
		nextSize, err := r.readSize()
		if err != nil {
			return nil, err
		}
		if nextSize == 0 {
			return nil, io.EOF
		}
		size = int(nextSize)
	}
	r.leftOverSize = size

	mb, err := r.reader.ReadAtMost(size)
	if !mb.IsEmpty() {
		r.leftOverSize -= mb.Len()
		return mb, nil
	}
	return nil, err
}

type ChunkStreamWriter struct {
	sizeEncoder ChunkSizeEncoder
	writer      buf.Writer
}

func NewChunkStreamWriter(sizeEncoder ChunkSizeEncoder, writer io.Writer) *ChunkStreamWriter {
	return &ChunkStreamWriter{
		sizeEncoder: sizeEncoder,
		writer:      buf.NewWriter(writer),
	}
}

func (w *ChunkStreamWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
	const sliceSize = 8192
	mbLen := mb.Len()
	mb2Write := buf.NewMultiBufferCap(mbLen/buf.Size + mbLen/sliceSize + 2)

	for {
		slice := mb.SliceBySize(sliceSize)

		b := buf.New()
		common.Must(b.Reset(func(buffer []byte) (int, error) {
			w.sizeEncoder.Encode(uint16(slice.Len()), buffer[:0])
			return w.sizeEncoder.SizeBytes(), nil
		}))
		mb2Write.Append(b)
		mb2Write.AppendMulti(slice)

		if mb.IsEmpty() {
			break
		}
	}

	return w.writer.WriteMultiBuffer(mb2Write)
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	shortPath    = "common_context_test.go"
	commonPrefix = "github.com/hailocab/seelog."
)

var testFullPath string

func fullPath(t *testing.T) string {
	if testFullPath == "" {
		wd, err := os.Getwd()

		if err != nil {
			t.Fatalf("Cannot get working directory: %s", err.Error())
		}

		testFullPath = filepath.Join(wd, shortPath)
	}

	return testFullPath
}

func TestContext(t *testing.T) {
	context, err := currentContext()

	nameFunc := commonPrefix + "TestContext"

	if err != nil {
		t.Fatalf("Unexpected error: %s", err.Error())
	}

	if context == nil {
		t.Fatalf("Expected: context != nil")
	}

	if nf := context.Func(); nf != nameFunc {
		// Account for a case when the func full path is bigger than commonPrefix but includes it.
		if !strings.HasSuffix(nf, nameFunc) {
			t.Errorf("Expected context.Func == %s ; got %s", nameFunc, context.Func())
		}
	}

	if context.ShortPath() != shortPath {
		t.Errorf("Expected context.ShortPath == %s ; got %s", shortPath, context.ShortPath())
	}

	fp := fullPath(t)

	if context.FullPath() != fp {
		t.Errorf("Expected context.FullPath == %s ; got %s", fp, context.FullPath())
	}
}

func innerContext() (context LogContextInterface, err error) {
	return currentContext()
}

func TestInnerContext(t *testing.T) {
	context, err := innerContext()

	nameFunc := commonPrefix + "innerContext"

	if err != nil {
		t.Fatalf("Unexpected error: %s", err.Error())
	}

	if context == nil {
		t.Fatalf("Expected: context != nil")
	}

	if cf := context.Func(); cf != nameFunc {
		// Account for a case when the func full path is bigger than commonPrefix but includes it.
		if !strings.HasSuffix(cf, nameFunc) {
			t.Errorf("Expected context.Func == %s ; got %s", nameFunc, context.Func())
		}
	}

	if context.ShortPath() != shortPath {
		t.Errorf("Expected context.ShortPath == %s ; got %s", shortPath, context.ShortPath())
	}

	fp := fullPath(t)

	if context.FullPath() != fp {
		t.Errorf("Expected context.FullPath == %s ; got %s", fp, context.FullPath())
	}
}
<commit_msg>Fix function name in test for jenkins<commit_after>// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package seelog

import (
	"os"
	"path/filepath"
	"strings"
	"testing"
)

const (
	shortPath = "common_context_test.go"
	// commonPrefix = "github.com/hailocab/seelog."
)

func init() {
	_, _, funcName, _, _ := extractCallerInfo(1)

	commonPrefix = funcName[:strings.Index(funcName, "init·")]
}

var commonPrefix string
var testFullPath string

func fullPath(t *testing.T) string {
	if testFullPath == "" {
		wd, err := os.Getwd()

		if err != nil {
			t.Fatalf("Cannot get working directory: %s", err.Error())
		}

		testFullPath = filepath.Join(wd, shortPath)
	}

	return testFullPath
}

func TestContext(t *testing.T) {

	context, err := currentContext()

	nameFunc := commonPrefix + "TestContext"

	if err != nil {
		t.Fatalf("Unexpected error: %s", err.Error())
	}

	if context == nil {
		t.Fatalf("Expected: context != nil")
	}

	if nf := context.Func(); nf != nameFunc {
		// Account for a case when the func full path is bigger than commonPrefix but includes it.
		if !strings.HasSuffix(nf, nameFunc) {
			t.Errorf("Expected context.Func == %s ; got %s", nameFunc, context.Func())
		}
	}

	if context.ShortPath() != shortPath {
		t.Errorf("Expected context.ShortPath == %s ; got %s", shortPath, context.ShortPath())
	}

	fp := fullPath(t)

	if context.FullPath() != fp {
		t.Errorf("Expected context.FullPath == %s ; got %s", fp, context.FullPath())
	}
}

func innerContext() (context LogContextInterface, err error) {
	return currentContext()
}

func TestInnerContext(t *testing.T) {
	context, err := innerContext()

	nameFunc := commonPrefix + "innerContext"

	if err != nil {
		t.Fatalf("Unexpected error: %s", err.Error())
	}

	if context == nil {
		t.Fatalf("Expected: context != nil")
	}

	if cf := context.Func(); cf != nameFunc {
		// Account for a case when the func full path is bigger than commonPrefix but includes it.
		if !strings.HasSuffix(cf, nameFunc) {
			t.Errorf("Expected context.Func == %s ; got %s", nameFunc, context.Func())
		}
	}

	if context.ShortPath() != shortPath {
		t.Errorf("Expected context.ShortPath == %s ; got %s", shortPath, context.ShortPath())
	}

	fp := fullPath(t)

	if context.FullPath() != fp {
		t.Errorf("Expected context.FullPath == %s ; got %s", fp, context.FullPath())
	}
}
<|endoftext|>


<commit_before>package requesthandler

import (
	"github.com/chandanchowdhury/HSPC/dbhandler"
	"github.com/chandanchowdhury/HSPC/models"
	"github.com/chandanchowdhury/HSPC/restapi/operations/advisor"
	"github.com/go-openapi/runtime/middleware"
)

func HandleAdvisorPost(params advisor.PostAdvisorParams) middleware.Responder {
	//create the advisor
	advisor_id := dbhandler.AdvisorCreate(*params.Advisor)

	if advisor_id <= 0 {
		resp := advisor.NewPostAdvisorDefault(400)
		error := new(models.Error)
		error.Code = advisor_id

		switch advisor_id {
		case -1:
			error.Message = "Duplicate error"
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		resp.SetPayload(error)

		return resp
	}

	// create the response
	resp := advisor.NewPostAdvisorOK()
	advisor := dbhandler.AdvisorRead(advisor_id)

	//set response data
	resp.SetPayload(&advisor)

	//return the response
	return resp
}

func HandleAdvisorGet(params advisor.GetAdvisorIDParams) middleware.Responder {
	//get advisor details based on the provided id
	advisor_data := dbhandler.AdvisorRead(params.ID)

	if advisor_data.AdvisorID == 0 {
		resp := advisor.NewGetAdvisorIDDefault(404)
		error := &models.Error{Code: -1, Message: "Advisor not found"}

		resp.SetPayload(error)
		return resp
	}

	resp := advisor.NewGetAdvisorIDOK()
	resp.SetPayload(&advisor_data)

	return resp
}

func HandleAdvisorPut(params advisor.PutAdvisorParams) middleware.Responder {
	affected_count := dbhandler.AdvisorUpdate(*params.Advisor)

	error := new(models.Error)

	if affected_count != 1 {
		error.Message = "Error: Unexpected number of updates"
		error.Code = affected_count
		resp := advisor.NewPostAdvisorDefault(400)
		resp.SetPayload(error)

		switch affected_count {
		case 0:
			error.Message = "Warn: no records found for update"
			resp.SetStatusCode(404)
		case -1:
			error.Message = "Update will cause duplicate record"
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		return resp
	}

	resp := advisor.NewPutAdvisorOK()
	error.Message = "Updated"
	resp.SetPayload(error)

	//return the response
	return resp

}

func HandleAdvisorDelete(params advisor.DeleteAdvisorIDParams) middleware.Responder {
	affected_count := dbhandler.AdvisorDelete(params.ID)

	error := new(models.Error)

	if affected_count != 1 {
		error.Message = "Error: Unexpected number of deletes"
		error.Code = affected_count
		resp := advisor.NewDeleteAdvisorIDDefault(400)
		resp.SetPayload(error)

		switch affected_count {
		case 0:
			error.Message = "Warn: no records found for update"
			resp.SetStatusCode(404)
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		return resp
	}

	resp := advisor.NewDeleteAdvisorIDOK()
	error.Message = "Deleted"
	resp.SetPayload(error)

	return resp
}

func HandleAdvisorReadAll(params advisor.GetAdvisorParams) middleware.Responder {
	advisors := dbhandler.AdvisorReadAll()

	resp := advisor.NewGetAdvisorOK()
	resp.SetPayload(advisors)

	return resp
}
<commit_msg>corrected error mesaage<commit_after>package requesthandler

import (
	"github.com/chandanchowdhury/HSPC/dbhandler"
	"github.com/chandanchowdhury/HSPC/models"
	"github.com/chandanchowdhury/HSPC/restapi/operations/advisor"
	"github.com/go-openapi/runtime/middleware"
)

func HandleAdvisorPost(params advisor.PostAdvisorParams) middleware.Responder {
	//create the advisor
	advisor_id := dbhandler.AdvisorCreate(*params.Advisor)

	if advisor_id <= 0 {
		resp := advisor.NewPostAdvisorDefault(400)
		error := new(models.Error)
		error.Code = advisor_id

		switch advisor_id {
		case -1:
			error.Message = "Duplicate error"
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		resp.SetPayload(error)

		return resp
	}

	// create the response
	resp := advisor.NewPostAdvisorOK()
	advisor := dbhandler.AdvisorRead(advisor_id)

	//set response data
	resp.SetPayload(&advisor)

	//return the response
	return resp
}

func HandleAdvisorGet(params advisor.GetAdvisorIDParams) middleware.Responder {
	//get advisor details based on the provided id
	advisor_data := dbhandler.AdvisorRead(params.ID)

	if advisor_data.AdvisorID == 0 {
		resp := advisor.NewGetAdvisorIDDefault(404)
		error := &models.Error{Code: -1, Message: "Advisor not found"}

		resp.SetPayload(error)
		return resp
	}

	resp := advisor.NewGetAdvisorIDOK()
	resp.SetPayload(&advisor_data)

	return resp
}

func HandleAdvisorPut(params advisor.PutAdvisorParams) middleware.Responder {
	affected_count := dbhandler.AdvisorUpdate(*params.Advisor)

	error := new(models.Error)

	if affected_count != 1 {
		error.Message = "Error: Unexpected number of updates"
		error.Code = affected_count
		resp := advisor.NewPostAdvisorDefault(400)
		resp.SetPayload(error)

		switch affected_count {
		case 0:
			error.Message = "Warn: no records found for update"
			resp.SetStatusCode(404)
		case -1:
			error.Message = "Update will cause duplicate record"
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		return resp
	}

	resp := advisor.NewPutAdvisorOK()
	error.Message = "Updated"
	resp.SetPayload(error)

	//return the response
	return resp

}

func HandleAdvisorDelete(params advisor.DeleteAdvisorIDParams) middleware.Responder {
	affected_count := dbhandler.AdvisorDelete(params.ID)

	error := new(models.Error)

	if affected_count != 1 {
		error.Message = "Error: Unexpected number of deletes"
		error.Code = affected_count
		resp := advisor.NewDeleteAdvisorIDDefault(400)
		resp.SetPayload(error)

		switch affected_count {
		case 0:
			error.Message = "Warn: no records found for delete"
			resp.SetStatusCode(404)
		case -2:
			error.Message = "Related data error"
		default:
			error.Message = "Error: Unexpected error"
		}

		return resp
	}

	resp := advisor.NewDeleteAdvisorIDOK()
	error.Message = "Deleted"
	resp.SetPayload(error)

	return resp
}

func HandleAdvisorReadAll(params advisor.GetAdvisorParams) middleware.Responder {
	advisors := dbhandler.AdvisorReadAll()

	resp := advisor.NewGetAdvisorOK()
	resp.SetPayload(advisors)

	return resp
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package leveldb

import (
	"bytes"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/filter"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/util"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils"
	"github.com/ava-labs/avalanchego/utils/logging"
)

const (
	// minBlockCacheSize is the minimum number of bytes to use for block caching
	// in leveldb.
	minBlockCacheSize = 8 * opt.MiB

	// minWriteBufferSize is the minimum number of bytes to use for buffers in
	// leveldb.
	minWriteBufferSize = 8 * opt.MiB

	// minHandleCap is the minimum number of files descriptors to cap levelDB to
	// use
	minHandleCap = 16

	// levelDBByteOverhead is the number of bytes of constant overhead that
	// should be added to a batch size per operation.
	levelDBByteOverhead = 8
)

// Database is a persistent key-value store. Apart from basic data storage
// functionality it also supports batch writes and iterating over the keyspace
// in binary-alphabetical order.
type Database struct {
	*leveldb.DB
	log logging.Logger

	// True if there was previously an error other than "not found" or "closed"
	// while performing a db operation. If [errored] == true, Has, Get, Put,
	// Delete and batch writes fail with ErrAvoidCorruption.
	// The node should shut down.
	errored bool
}

// New returns a wrapped LevelDB object.
func New(file string, log logging.Logger, blockCacheSize, writeBufferSize, handleCap int) (*Database, error) {
	// Enforce minimums
	if blockCacheSize < minBlockCacheSize {
		blockCacheSize = minBlockCacheSize
	}
	if writeBufferSize < minWriteBufferSize {
		writeBufferSize = minWriteBufferSize
	}
	if handleCap < minHandleCap {
		handleCap = minHandleCap
	}

	// Open the db and recover any potential corruptions
	db, err := leveldb.OpenFile(file, &opt.Options{
		OpenFilesCacheCapacity: handleCap,
		BlockCacheCapacity:     blockCacheSize,
		// There are two buffers of size WriteBuffer used.
		WriteBuffer: writeBufferSize / 2,
		Filter:      filter.NewBloomFilter(10),
	})
	if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
		db, err = leveldb.RecoverFile(file, nil)
	}
	if err != nil {
		return nil, err
	}
	return &Database{
		DB:  db,
		log: log,
	}, nil
}

// Has returns if the key is set in the database
func (db *Database) Has(key []byte) (bool, error) {
	if db.errored {
		return false, database.ErrAvoidCorruption
	}
	has, err := db.DB.Has(key, nil)
	return has, db.handleError(err)
}

// Get returns the value the key maps to in the database
func (db *Database) Get(key []byte) ([]byte, error) {
	if db.errored {
		return nil, database.ErrAvoidCorruption
	}
	value, err := db.DB.Get(key, nil)
	return value, db.handleError(err)
}

// Put sets the value of the provided key to the provided value
func (db *Database) Put(key []byte, value []byte) error {
	if db.errored {
		return database.ErrAvoidCorruption
	}
	return db.handleError(db.DB.Put(key, value, nil))
}

// Delete removes the key from the database
func (db *Database) Delete(key []byte) error {
	if db.errored {
		return database.ErrAvoidCorruption
	}
	return db.handleError(db.DB.Delete(key, nil))
}

// NewBatch creates a write/delete-only buffer that is atomically committed to
// the database when write is called
func (db *Database) NewBatch() database.Batch { return &batch{db: db} }

// NewIterator creates a lexicographically ordered iterator over the database
func (db *Database) NewIterator() database.Iterator {
	return &iter{db.DB.NewIterator(new(util.Range), nil)}
}

// NewIteratorWithStart creates a lexicographically ordered iterator over the
// database starting at the provided key
func (db *Database) NewIteratorWithStart(start []byte) database.Iterator {
	return &iter{db.DB.NewIterator(&util.Range{Start: start}, nil)}
}

// NewIteratorWithPrefix creates a lexicographically ordered iterator over the
// database ignoring keys that do not start with the provided prefix
func (db *Database) NewIteratorWithPrefix(prefix []byte) database.Iterator {
	return &iter{db.DB.NewIterator(util.BytesPrefix(prefix), nil)}
}

// NewIteratorWithStartAndPrefix creates a lexicographically ordered iterator
// over the database starting at start and ignoring keys that do not start with
// the provided prefix
func (db *Database) NewIteratorWithStartAndPrefix(start, prefix []byte) database.Iterator {
	iterRange := util.BytesPrefix(prefix)
	if bytes.Compare(start, prefix) == 1 {
		iterRange.Start = start
	}
	return &iter{db.DB.NewIterator(iterRange, nil)}
}

// Stat returns a particular internal stat of the database.
func (db *Database) Stat(property string) (string, error) {
	stat, err := db.DB.GetProperty(property)
	return stat, db.handleError(err)
}

// This comment is basically copy pasted from the underlying levelDB library:

// Compact the underlying DB for the given key range.
// Specifically, deleted and overwritten versions are discarded,
// and the data is rearranged to reduce the cost of operations
// needed to access the data. This operation should typically only
// be invoked by users who understand the underlying implementation.
//
// A nil start is treated as a key before all keys in the DB.
// And a nil limit is treated as a key after all keys in the DB.
// Therefore if both are nil then it will compact entire DB.
func (db *Database) Compact(start []byte, limit []byte) error {
	return db.handleError(db.DB.CompactRange(util.Range{Start: start, Limit: limit}))
}

// Close implements the Database interface
func (db *Database) Close() error { return db.handleError(db.DB.Close()) }

func (db *Database) handleError(err error) error {
	err = updateError(err)
	// If we get an error other than "not found" or "closed", disallow future
	// database operations to avoid possible corruption
	if err != nil && err != database.ErrNotFound && err != database.ErrClosed {
		db.log.Fatal("leveldb error: %w", err)
		db.errored = true
	}
	return err
}

// batch is a wrapper around a levelDB batch to contain sizes.
type batch struct {
	leveldb.Batch
	db   *Database
	size int
}

// Put the value into the batch for later writing
func (b *batch) Put(key, value []byte) error {
	b.Batch.Put(key, value)
	b.size += len(key) + len(value) + levelDBByteOverhead
	return nil
}

// Delete the key during writing
func (b *batch) Delete(key []byte) error {
	b.Batch.Delete(key)
	b.size += len(key) + levelDBByteOverhead
	return nil
}

// Size retrieves the amount of data queued up for writing.
func (b *batch) Size() int { return b.size }

// Write flushes any accumulated data to disk.
func (b *batch) Write() error {
	if b.db.errored {
		return database.ErrAvoidCorruption
	}
	return b.db.handleError(b.db.DB.Write(&b.Batch, nil))
}

// Reset resets the batch for reuse.
func (b *batch) Reset() {
	b.Batch.Reset()
	b.size = 0
}

// Replay the batch contents.
func (b *batch) Replay(w database.KeyValueWriter) error {
	replay := &replayer{writer: w}
	if err := b.Batch.Replay(replay); err != nil {
		// Never actually returns an error, because Replay just returns nil
		return b.db.handleError(err)
	}
	return b.db.handleError(replay.err)
}

// Inner returns itself
func (b *batch) Inner() database.Batch { return b }

type replayer struct {
	writer database.KeyValueWriter
	err    error
}

func (r *replayer) Put(key, value []byte) {
	if r.err != nil {
		return
	}
	r.err = r.writer.Put(key, value)
}

func (r *replayer) Delete(key []byte) {
	if r.err != nil {
		return
	}
	r.err = r.writer.Delete(key)
}

type iter struct{ iterator.Iterator }

// Error implements the Iterator interface
func (it *iter) Error() error { return updateError(it.Iterator.Error()) }

// Key implements the Iterator interface
func (it *iter) Key() []byte { return utils.CopyBytes(it.Iterator.Key()) }

// Value implements the Iterator interface
func (it *iter) Value() []byte { return utils.CopyBytes(it.Iterator.Value()) }

func updateError(err error) error {
	switch err {
	case leveldb.ErrClosed:
		return database.ErrClosed
	case leveldb.ErrNotFound:
		return database.ErrNotFound
	default:
		return err
	}
}
<commit_msg>bump leveldb defaults<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package leveldb

import (
	"bytes"

	"github.com/syndtr/goleveldb/leveldb"
	"github.com/syndtr/goleveldb/leveldb/errors"
	"github.com/syndtr/goleveldb/leveldb/filter"
	"github.com/syndtr/goleveldb/leveldb/iterator"
	"github.com/syndtr/goleveldb/leveldb/opt"
	"github.com/syndtr/goleveldb/leveldb/util"

	"github.com/ava-labs/avalanchego/database"
	"github.com/ava-labs/avalanchego/utils"
	"github.com/ava-labs/avalanchego/utils/logging"
)

const (
	// minBlockCacheSize is the minimum number of bytes to use for block caching
	// in leveldb.
	minBlockCacheSize = 12 * opt.MiB

	// minWriteBufferSize is the minimum number of bytes to use for buffers in
	// leveldb.
	minWriteBufferSize = 12 * opt.MiB

	// minHandleCap is the minimum number of files descriptors to cap levelDB to
	// use
	minHandleCap = 64

	// levelDBByteOverhead is the number of bytes of constant overhead that
	// should be added to a batch size per operation.
	levelDBByteOverhead = 8
)

// Database is a persistent key-value store. Apart from basic data storage
// functionality it also supports batch writes and iterating over the keyspace
// in binary-alphabetical order.
type Database struct {
	*leveldb.DB
	log logging.Logger

	// True if there was previously an error other than "not found" or "closed"
	// while performing a db operation. If [errored] == true, Has, Get, Put,
	// Delete and batch writes fail with ErrAvoidCorruption.
	// The node should shut down.
	errored bool
}

// New returns a wrapped LevelDB object.
func New(file string, log logging.Logger, blockCacheSize, writeBufferSize, handleCap int) (*Database, error) {
	// Enforce minimums
	if blockCacheSize < minBlockCacheSize {
		blockCacheSize = minBlockCacheSize
	}
	if writeBufferSize < minWriteBufferSize {
		writeBufferSize = minWriteBufferSize
	}
	if handleCap < minHandleCap {
		handleCap = minHandleCap
	}

	// Open the db and recover any potential corruptions
	db, err := leveldb.OpenFile(file, &opt.Options{
		OpenFilesCacheCapacity: handleCap,
		BlockCacheCapacity:     blockCacheSize,
		// There are two buffers of size WriteBuffer used.
		WriteBuffer: writeBufferSize / 2,
		Filter:      filter.NewBloomFilter(10),
	})
	if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
		db, err = leveldb.RecoverFile(file, nil)
	}
	if err != nil {
		return nil, err
	}
	return &Database{
		DB:  db,
		log: log,
	}, nil
}

// Has returns if the key is set in the database
func (db *Database) Has(key []byte) (bool, error) {
	if db.errored {
		return false, database.ErrAvoidCorruption
	}
	has, err := db.DB.Has(key, nil)
	return has, db.handleError(err)
}

// Get returns the value the key maps to in the database
func (db *Database) Get(key []byte) ([]byte, error) {
	if db.errored {
		return nil, database.ErrAvoidCorruption
	}
	value, err := db.DB.Get(key, nil)
	return value, db.handleError(err)
}

// Put sets the value of the provided key to the provided value
func (db *Database) Put(key []byte, value []byte) error {
	if db.errored {
		return database.ErrAvoidCorruption
	}
	return db.handleError(db.DB.Put(key, value, nil))
}

// Delete removes the key from the database
func (db *Database) Delete(key []byte) error {
	if db.errored {
		return database.ErrAvoidCorruption
	}
	return db.handleError(db.DB.Delete(key, nil))
}

// NewBatch creates a write/delete-only buffer that is atomically committed to
// the database when write is called
func (db *Database) NewBatch() database.Batch { return &batch{db: db} }

// NewIterator creates a lexicographically ordered iterator over the database
func (db *Database) NewIterator() database.Iterator {
	return &iter{db.DB.NewIterator(new(util.Range), nil)}
}

// NewIteratorWithStart creates a lexicographically ordered iterator over the
// database starting at the provided key
func (db *Database) NewIteratorWithStart(start []byte) database.Iterator {
	return &iter{db.DB.NewIterator(&util.Range{Start: start}, nil)}
}

// NewIteratorWithPrefix creates a lexicographically ordered iterator over the
// database ignoring keys that do not start with the provided prefix
func (db *Database) NewIteratorWithPrefix(prefix []byte) database.Iterator {
	return &iter{db.DB.NewIterator(util.BytesPrefix(prefix), nil)}
}

// NewIteratorWithStartAndPrefix creates a lexicographically ordered iterator
// over the database starting at start and ignoring keys that do not start with
// the provided prefix
func (db *Database) NewIteratorWithStartAndPrefix(start, prefix []byte) database.Iterator {
	iterRange := util.BytesPrefix(prefix)
	if bytes.Compare(start, prefix) == 1 {
		iterRange.Start = start
	}
	return &iter{db.DB.NewIterator(iterRange, nil)}
}

// Stat returns a particular internal stat of the database.
func (db *Database) Stat(property string) (string, error) {
	stat, err := db.DB.GetProperty(property)
	return stat, db.handleError(err)
}

// This comment is basically copy pasted from the underlying levelDB library:

// Compact the underlying DB for the given key range.
// Specifically, deleted and overwritten versions are discarded,
// and the data is rearranged to reduce the cost of operations
// needed to access the data. This operation should typically only
// be invoked by users who understand the underlying implementation.
//
// A nil start is treated as a key before all keys in the DB.
// And a nil limit is treated as a key after all keys in the DB.
// Therefore if both are nil then it will compact entire DB.
func (db *Database) Compact(start []byte, limit []byte) error {
	return db.handleError(db.DB.CompactRange(util.Range{Start: start, Limit: limit}))
}

// Close implements the Database interface
func (db *Database) Close() error { return db.handleError(db.DB.Close()) }

func (db *Database) handleError(err error) error {
	err = updateError(err)
	// If we get an error other than "not found" or "closed", disallow future
	// database operations to avoid possible corruption
	if err != nil && err != database.ErrNotFound && err != database.ErrClosed {
		db.log.Fatal("leveldb error: %w", err)
		db.errored = true
	}
	return err
}

// batch is a wrapper around a levelDB batch to contain sizes.
type batch struct {
	leveldb.Batch
	db   *Database
	size int
}

// Put the value into the batch for later writing
func (b *batch) Put(key, value []byte) error {
	b.Batch.Put(key, value)
	b.size += len(key) + len(value) + levelDBByteOverhead
	return nil
}

// Delete the key during writing
func (b *batch) Delete(key []byte) error {
	b.Batch.Delete(key)
	b.size += len(key) + levelDBByteOverhead
	return nil
}

// Size retrieves the amount of data queued up for writing.
func (b *batch) Size() int { return b.size }

// Write flushes any accumulated data to disk.
func (b *batch) Write() error {
	if b.db.errored {
		return database.ErrAvoidCorruption
	}
	return b.db.handleError(b.db.DB.Write(&b.Batch, nil))
}

// Reset resets the batch for reuse.
func (b *batch) Reset() {
	b.Batch.Reset()
	b.size = 0
}

// Replay the batch contents.
func (b *batch) Replay(w database.KeyValueWriter) error {
	replay := &replayer{writer: w}
	if err := b.Batch.Replay(replay); err != nil {
		// Never actually returns an error, because Replay just returns nil
		return b.db.handleError(err)
	}
	return b.db.handleError(replay.err)
}

// Inner returns itself
func (b *batch) Inner() database.Batch { return b }

type replayer struct {
	writer database.KeyValueWriter
	err    error
}

func (r *replayer) Put(key, value []byte) {
	if r.err != nil {
		return
	}
	r.err = r.writer.Put(key, value)
}

func (r *replayer) Delete(key []byte) {
	if r.err != nil {
		return
	}
	r.err = r.writer.Delete(key)
}

type iter struct{ iterator.Iterator }

// Error implements the Iterator interface
func (it *iter) Error() error { return updateError(it.Iterator.Error()) }

// Key implements the Iterator interface
func (it *iter) Key() []byte { return utils.CopyBytes(it.Iterator.Key()) }

// Value implements the Iterator interface
func (it *iter) Value() []byte { return utils.CopyBytes(it.Iterator.Value()) }

func updateError(err error) error {
	switch err {
	case leveldb.ErrClosed:
		return database.ErrClosed
	case leveldb.ErrNotFound:
		return database.ErrNotFound
	default:
		return err
	}
}
<|endoftext|>


<commit_before>package datastore

import (
	"fmt"

	"github.com/jinzhu/gorm"
	// Initialize MySQL driver
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/torrent-viewer/backend/herr"
)

// Conn is the database connection used to store data
var Conn *gorm.DB

type Identifiable interface {
	GetID() int
}

// Init initializes the database connection
func Init(driver string, user string, password string, host string, port string, database string) error {
	var dbURI string
	if driver == "mysql" {
		dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", user, password, host, port, database)
	} else if driver == "sqlite3" {
		dbURI = database
	} else {
		dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", user, password, host, port, database)
	}
	db, err := gorm.Open(driver, dbURI)
	if err != nil {
		return err
	}
	Conn = db
	return nil
}

// FetchEntities fetch entities from the datastore with the given constraints
func FetchEntities(out interface{}, where ...interface{}) *herr.Error {
	if err := Conn.Find(out, where...).Error; err != nil {
		e := herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
		return &e
	}
	return nil
}

// FetchEntity fetch an entity based on its ID
func FetchEntity(out interface{}, id int) *herr.Error {
	d := Conn.First(out, id)
	if d.RecordNotFound() != false {
		err := d.Error
		return &herr.Error{
			ID:     "not-found",
			Status: "404",
			Title:  "Not Found",
			Detail: err.Error(),
		}
	} else if err := d.Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// StoreEntity store a new entity in the datastore.
// The stored entity is not allowed to specify an ID.
func StoreEntity(in interface{}) *herr.Error {
	if Conn.NewRecord(in) != true {
		return &herr.DuplicateEntryError;
	}
	if err := Conn.Create(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// UpdateEntity update an entity in the datastore
func UpdateEntity(in interface{}) *herr.Error {
	if err := Conn.Model(in).Update(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// DeleteEntity delete an entity in the datastore,
// using the ID property of the given model.
func DeleteEntity(in Identifiable) *herr.Error {
	var count int
	if err := Conn.Model(in).Where("id = ?", in.GetID()).Count(&count).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	if count == 0 {
		return &herr.Error{
			ID:     "not-found",
			Status: "404",
			Title:  "Not Found",
			Detail: "The requested resource was not found in the datastore.",
		}
	}
	if err := Conn.Delete(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}<commit_msg>Replace interface{} by Identifiable<commit_after>package datastore

import (
	"fmt"

	"github.com/jinzhu/gorm"
	// Initialize MySQL driver
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/torrent-viewer/backend/herr"
)

// Conn is the database connection used to store data
var Conn *gorm.DB

// Identifiable represent an entity that can be identified by its unique ID
// All of the models used with this datastore must be identifiable.
type Identifiable interface {
	GetID() int
}

// Init initializes the database connection
func Init(driver string, user string, password string, host string, port string, database string) error {
	var dbURI string
	if driver == "mysql" {
		dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", user, password, host, port, database)
	} else if driver == "sqlite3" {
		dbURI = database
	} else {
		dbURI = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", user, password, host, port, database)
	}
	db, err := gorm.Open(driver, dbURI)
	if err != nil {
		return err
	}
	Conn = db
	return nil
}

// FetchEntities fetch entities from the datastore with the given constraints
func FetchEntities(out Identifiable, where ...interface{}) *herr.Error {
	if err := Conn.Find(out, where...).Error; err != nil {
		e := herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
		return &e
	}
	return nil
}

// FetchEntity fetch an entity based on its ID
func FetchEntity(out Identifiable, id int) *herr.Error {
	d := Conn.First(out, id)
	if d.RecordNotFound() != false {
		err := d.Error
		return &herr.Error{
			ID:     "not-found",
			Status: "404",
			Title:  "Not Found",
			Detail: err.Error(),
		}
	} else if err := d.Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// StoreEntity store a new entity in the datastore.
// The stored entity is not allowed to specify an ID.
func StoreEntity(in Identifiable) *herr.Error {
	if Conn.NewRecord(in) != true {
		return &herr.DuplicateEntryError;
	}
	if err := Conn.Create(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// UpdateEntity update an entity in the datastore
func UpdateEntity(in Identifiable) *herr.Error {
	if err := Conn.Model(in).Update(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}

// DeleteEntity delete an entity in the datastore,
// using the ID property of the given model.
func DeleteEntity(in Identifiable) *herr.Error {
	var count int
	if err := Conn.Model(in).Where("id = ?", in.GetID()).Count(&count).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	if count == 0 {
		return &herr.Error{
			ID:     "not-found",
			Status: "404",
			Title:  "Not Found",
			Detail: "The requested resource was not found in the datastore.",
		}
	}
	if err := Conn.Delete(in).Error; err != nil {
		return &herr.Error{
			ID:     "database-error",
			Status: "500",
			Title:  "Database Error",
			Detail: err.Error(),
		}
	}
	return nil
}<|endoftext|>


<commit_before>package scalar

import (
	"net"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func assertParse(t *testing.T, expected interface{}, str string) {
	v := reflect.New(reflect.TypeOf(expected)).Elem()
	err := ParseValue(v, str)
	if assert.NoError(t, err) {
		assert.Equal(t, expected, v)
	}

	ptr := reflect.New(reflect.PtrTo(reflect.TypeOf(expected))).Elem()
	err = ParseValue(ptr, str)
	if assert.NoError(t, err) {
		assert.Equal(t, expected, ptr.Elem())
	}

	assert.True(t, CanParse(v.Type()))
	assert.True(t, CanParse(ptr.Type()))
}

func TestParseValue(t *testing.T) {
	// strings
	assertParse(t, "abc", "abc")

	// booleans
	assertParse(t, true, "true")
	assertParse(t, false, "false")

	// integers
	assertParse(t, int(123), "123")
	assertParse(t, int8(123), "123")
	assertParse(t, int16(123), "123")
	assertParse(t, int32(123), "123")
	assertParse(t, int64(123), "123")

	// unsigned integers
	assertParse(t, uint(123), "123")
	assertParse(t, byte(123), "123")
	assertParse(t, uint8(123), "123")
	assertParse(t, uint16(123), "123")
	assertParse(t, uint32(123), "123")
	assertParse(t, uint64(123), "123")
	assertParse(t, uintptr(123), "123")
	assertParse(t, rune(123), "123")

	// floats
	assertParse(t, float32(123), "123")
	assertParse(t, float64(123), "123")

	// durations
	assertParse(t, 3*time.Hour+15*time.Minute, "3h15m")

	// IP addresses
	assertParse(t, net.IPv4(1, 2, 3, 4), "1.2.3.4")

	// MAC addresses
	assertParse(t, net.HardwareAddr("\x01\x23\x45\x67\x89\xab"), "01:23:45:67:89:ab")

	// MAC addresses
	assertParse(t, net.HardwareAddr("\x01\x23\x45\x67\x89\xab"), "01:23:45:67:89:ab")
}

func TestParse(t *testing.T) {
	var v int
	err := Parse(&v, "123")
	require.NoError(t, err)
	assert.Equal(t, 123, v)
}
<commit_msg>fix tests<commit_after>package scalar

import (
	"net"
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func assertParse(t *testing.T, expected interface{}, str string) {
	v := reflect.New(reflect.TypeOf(expected)).Elem()
	err := ParseValue(v, str)
	if assert.NoError(t, err) {
		assert.Equal(t, expected, v.Interface())
	}

	ptr := reflect.New(reflect.PtrTo(reflect.TypeOf(expected))).Elem()
	err = ParseValue(ptr, str)
	if assert.NoError(t, err) {
		assert.Equal(t, expected, ptr.Elem().Interface())
	}

	assert.True(t, CanParse(v.Type()))
	assert.True(t, CanParse(ptr.Type()))
}

func TestParseValue(t *testing.T) {
	// strings
	assertParse(t, "abc", "abc")

	// booleans
	assertParse(t, true, "true")
	assertParse(t, false, "false")

	// integers
	assertParse(t, int(123), "123")
	assertParse(t, int8(123), "123")
	assertParse(t, int16(123), "123")
	assertParse(t, int32(123), "123")
	assertParse(t, int64(123), "123")

	// unsigned integers
	assertParse(t, uint(123), "123")
	assertParse(t, byte(123), "123")
	assertParse(t, uint8(123), "123")
	assertParse(t, uint16(123), "123")
	assertParse(t, uint32(123), "123")
	assertParse(t, uint64(123), "123")
	assertParse(t, uintptr(123), "123")
	assertParse(t, rune(123), "123")

	// floats
	assertParse(t, float32(123), "123")
	assertParse(t, float64(123), "123")

	// durations
	assertParse(t, 3*time.Hour+15*time.Minute, "3h15m")

	// IP addresses
	assertParse(t, net.IPv4(1, 2, 3, 4), "1.2.3.4")

	// MAC addresses
	assertParse(t, net.HardwareAddr("\x01\x23\x45\x67\x89\xab"), "01:23:45:67:89:ab")

	// MAC addresses
	assertParse(t, net.HardwareAddr("\x01\x23\x45\x67\x89\xab"), "01:23:45:67:89:ab")
}

func TestParse(t *testing.T) {
	var v int
	err := Parse(&v, "123")
	require.NoError(t, err)
	assert.Equal(t, 123, v)
}
<|endoftext|>


<commit_before>package main

import (
	"hash"
	"io"
	"os"
)

const (
	version    = "0.1.10"
	md5Name    = "md5"
	sha1Name   = "sha1"
	sha224Name = "sha224"
	sha256Name = "sha256"
	sha384Name = "sha384"
	sha512Name = "sha512"
	bufferSize = 2 * 1024 * 1024
)

func finalizeSegment(h hash.Hash, seg segment, out chan<- segment) segment {
	seg.hash = h.Sum(nil)
	out <- seg
	h.Reset()
	return segment{}
}

func calculateHash(hc hashContainer, in <-chan segmentChunk) <-chan segment {
	out := make(chan segment)

	go func() {
		defer close(out)
		var currentSegment segment
		for chunk := range in {
			_, err := hc.h.Write(chunk.data)
			lnCheckErr(err)

			// Setting rigth start offset for new segment
			if currentSegment.length == 0 {
				currentSegment.start = chunk.baseSegmentStart
			}

			currentSegment.length += int64(len(chunk.data))

			if chunk.isLast {
				currentSegment = finalizeSegment(hc.h, currentSegment, out)
			}
		}
		if currentSegment.length > 0 {
			finalizeSegment(hc.h, currentSegment, out)
		}
	}()

	return out
}

func readFile(input io.ReadSeeker, bufSize int64, consumersCount int, in <-chan readRange, progress func(n int64)) []chan segmentChunk {
	buffers := make([][]byte, 2)
	buffers[0] = make([]byte, bufSize)
	buffers[1] = make([]byte, bufSize)
	curBuffer := 0

	out := make([]chan segmentChunk, consumersCount)
	for i := range out {
		out[i] = make(chan segmentChunk)
	}

	go func() {
		defer func() {
			for i := range out {
				close(out[i])
			}
		}()

		var err error
		currentReadOffset := int64(0)
		for readRange := range in {
			if readRange.start != currentReadOffset {
				_, err = input.Seek(readRange.start, 0)
				lnCheckErr(err)
			}

			for left := readRange.length; left > 0; {
				bufferToRead := buffers[curBuffer]
				if left < bufSize {
					bufferToRead = buffers[curBuffer][:left]
				}
				n, err := input.Read(bufferToRead)
				if n == 0 {
					break
				}

				// Check whether last part was read
				if n < len(bufferToRead) {
					left = int64(n)
				}

				left -= int64(n)
				progress(int64(n))

				for i := range out {
					out[i] <- segmentChunk{data: bufferToRead[:n], isLast: left <= 0, baseSegmentStart: readRange.start}
				}

				// Switch buffer
				curBuffer = curBuffer ^ 1

				if err != nil {
					break
				}
			}
			if err != nil && err != io.EOF {
				lnfatal(err)
			}

			currentReadOffset = readRange.start + readRange.length
		}
	}()

	return out
}

func main() {
	calcArgs, verifyArgs := parseArgs()
	defer finalizeArgs(calcArgs, verifyArgs)

	if calcArgs != nil {
		calc(calcArgs, true)
	} else if verifyArgs != nil {
		diffs := verify(verifyArgs, true)
		if diffs > 254 {
			diffs = 254
		}
		os.Exit(diffs)
	} else {
		fatal("invalid command arguments")
	}
}
<commit_msg>Update version to 1.0.0<commit_after>package main

import (
	"hash"
	"io"
	"os"
)

const (
	version    = "1.0.0"
	md5Name    = "md5"
	sha1Name   = "sha1"
	sha224Name = "sha224"
	sha256Name = "sha256"
	sha384Name = "sha384"
	sha512Name = "sha512"
	bufferSize = 2 * 1024 * 1024
)

func finalizeSegment(h hash.Hash, seg segment, out chan<- segment) segment {
	seg.hash = h.Sum(nil)
	out <- seg
	h.Reset()
	return segment{}
}

func calculateHash(hc hashContainer, in <-chan segmentChunk) <-chan segment {
	out := make(chan segment)

	go func() {
		defer close(out)
		var currentSegment segment
		for chunk := range in {
			_, err := hc.h.Write(chunk.data)
			lnCheckErr(err)

			// Setting rigth start offset for new segment
			if currentSegment.length == 0 {
				currentSegment.start = chunk.baseSegmentStart
			}

			currentSegment.length += int64(len(chunk.data))

			if chunk.isLast {
				currentSegment = finalizeSegment(hc.h, currentSegment, out)
			}
		}
		if currentSegment.length > 0 {
			finalizeSegment(hc.h, currentSegment, out)
		}
	}()

	return out
}

func readFile(input io.ReadSeeker, bufSize int64, consumersCount int, in <-chan readRange, progress func(n int64)) []chan segmentChunk {
	buffers := make([][]byte, 2)
	buffers[0] = make([]byte, bufSize)
	buffers[1] = make([]byte, bufSize)
	curBuffer := 0

	out := make([]chan segmentChunk, consumersCount)
	for i := range out {
		out[i] = make(chan segmentChunk)
	}

	go func() {
		defer func() {
			for i := range out {
				close(out[i])
			}
		}()

		var err error
		currentReadOffset := int64(0)
		for readRange := range in {
			if readRange.start != currentReadOffset {
				_, err = input.Seek(readRange.start, 0)
				lnCheckErr(err)
			}

			for left := readRange.length; left > 0; {
				bufferToRead := buffers[curBuffer]
				if left < bufSize {
					bufferToRead = buffers[curBuffer][:left]
				}
				n, err := input.Read(bufferToRead)
				if n == 0 {
					break
				}

				// Check whether last part was read
				if n < len(bufferToRead) {
					left = int64(n)
				}

				left -= int64(n)
				progress(int64(n))

				for i := range out {
					out[i] <- segmentChunk{data: bufferToRead[:n], isLast: left <= 0, baseSegmentStart: readRange.start}
				}

				// Switch buffer
				curBuffer = curBuffer ^ 1

				if err != nil {
					break
				}
			}
			if err != nil && err != io.EOF {
				lnfatal(err)
			}

			currentReadOffset = readRange.start + readRange.length
		}
	}()

	return out
}

func main() {
	calcArgs, verifyArgs := parseArgs()
	defer finalizeArgs(calcArgs, verifyArgs)

	if calcArgs != nil {
		calc(calcArgs, true)
	} else if verifyArgs != nil {
		diffs := verify(verifyArgs, true)
		if diffs > 254 {
			diffs = 254
		}
		os.Exit(diffs)
	} else {
		fatal("invalid command arguments")
	}
}
<|endoftext|>


<commit_before>package semver_test

import (
	"fmt"
	"testing"

	"github.com/hansrodtang/semver"
)

type comparison struct {
	main     *semver.Version
	other    *semver.Version
	expected int
}

var badVersions = []string{
	"",
	".",
	"1.",
	".1",
	"a.b.c",
	"1.a.b",
	"1.1.a",
	"1.a.1",
	"a.1.1",
	"..",
	"1..",
	"1.1.",
	"1..1",
	"1.1.+123",
	"1.1.-beta",
	"-1.1.1",
	"1.-1.1",
	"1.1.-1",
	// Leading zeroes
	"01.1.1",
	"001.1.1",
	"1.01.1",
	"1.001.1",
	"1.1.01",
	"1.1.001",
	"1.1.1-01",
	"1.1.1-001",
	"1.1.1-beta.01",
	"1.1.1-beta.001",
	"0.0.0-!",
	"0.0.0+!",
	// empty prerelease
	"0.0.0-.alpha",
	// empty build metadata
	"0.0.0-alpha+",
	"0.0.0-alpha+test.",
}

var comparisons = []comparison{
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0), 0},
	{semver.Build(2, 0, 0), semver.Build(1, 0, 0), 1},
	{semver.Build(0, 1, 0), semver.Build(0, 1, 0), 0},
	{semver.Build(0, 2, 0), semver.Build(0, 1, 0), 1},
	{semver.Build(0, 0, 1), semver.Build(0, 0, 1), 0},
	{semver.Build(0, 0, 2), semver.Build(0, 0, 1), 1},
	{semver.Build(1, 2, 3), semver.Build(1, 2, 3), 0},
	{semver.Build(2, 2, 4), semver.Build(1, 2, 4), 1},
	{semver.Build(1, 3, 3), semver.Build(1, 2, 3), 1},
	{semver.Build(1, 2, 4), semver.Build(1, 2, 3), 1},

	// Spec Examples #11
	{semver.Build(1, 0, 0), semver.Build(2, 0, 0), -1},
	{semver.Build(2, 0, 0), semver.Build(2, 1, 0), -1},
	{semver.Build(2, 1, 0), semver.Build(2, 1, 1), -1},

	// Spec Examples #9
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha"}), semver.Build(1, 0, 0, []string{"alpha", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha", "beta"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "beta"}), semver.Build(1, 0, 0, []string{"beta"}), -1},
	{semver.Build(1, 0, 0, []string{"beta"}), semver.Build(1, 0, 0, []string{"beta", "2"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "2"}), semver.Build(1, 0, 0, []string{"beta", "11"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"beta", "2"}), 1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"rc", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "beta"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0), -1},
}

var badPreRelease = [][]string{
	{"alpha", "-3"},
}

func TestStringer(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	expected := "1.2.3-alpha.1+35.45"
	result := fmt.Sprint(ver)

	if result != expected {
		t.Errorf("String() => %q, wanted %q", result, expected)
	}
}

func TestGetters(t *testing.T) {
	expected_major := uint64(1)
	expected_minor := uint64(2)
	expected_patch := uint64(3)
	expected_prerelease := "alpha.1"
	expected_metadata := "35.45"

	ver := semver.Build(expected_major, expected_minor, expected_patch)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	if result := ver.Major(); result != expected_major {
		t.Errorf("%q.Major() => %q, wanted %q", ver, result, expected_major)
	}
	if result := ver.Minor(); result != expected_minor {
		t.Errorf("%q.Minor() => %q, wanted %q", ver, result, expected_minor)
	}
	if result := ver.Patch(); result != expected_patch {
		t.Errorf("%q.Patch() => %q, wanted %q", ver, result, expected_patch)
	}
	if result := ver.Prerelease(); result != expected_prerelease {
		t.Errorf("%q.Prerelease() => %q, wanted %q", ver, result, expected_prerelease)
	}
	if result := ver.Metadata(); result != expected_metadata {
		t.Errorf("%q.Metadata() => %q, wanted %q", ver, result, expected_metadata)
	}
}

func TestSetters(t *testing.T) {
	ver := semver.Build(1, 1, 1)
	ver.SetMajor(2)
	ver.SetMinor(3)
	ver.SetPatch(4)
	if err := ver.SetPrerelease("beta", "1"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}
	if err := ver.SetMetadata("22", "43"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	expected := "2.3.4-beta.1+22.43"
	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, wanted %q", result, expected)
	}
}

func TestNew(t *testing.T) {
	expected := "1.0.3-alpha.1+35.45"

	ver, err := semver.New(expected)
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, want %q", result, expected)
	}

}

func TestBadFormat(t *testing.T) {
	for _, version := range badVersions {
		_, err := semver.New(version)
		if err == nil {
			// TODO: Set up error types
			t.Errorf("New(%q) => %v, want Error", version, err)
		}
	}
}

func TestComparison(t *testing.T) {
	for _, c := range comparisons {
		result := c.main.Compare(c.other)
		if result != c.expected {
			t.Errorf("%q.Compare(%q) => %#v, want %#v", c.main, c.other, result, c.expected)
		}
	}
}

func TestSetPrerelease(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	err := ver.SetPrerelease("12", "1", "0", "43")
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}
}

func BenchmarkParseSimple(b *testing.B) {
	const VERSION = "0.0.1"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkParseComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkCompareSimple(b *testing.B) {
	const VERSION = "0.0.1"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}

func BenchmarkCompareComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}
<commit_msg>Added test with build metadata.<commit_after>package semver_test

import (
	"fmt"
	"testing"

	"github.com/hansrodtang/semver"
)

type comparison struct {
	main     *semver.Version
	other    *semver.Version
	expected int
}

var badVersions = []string{
	"",
	".",
	"1.",
	".1",
	"a.b.c",
	"1.a.b",
	"1.1.a",
	"1.a.1",
	"a.1.1",
	"..",
	"1..",
	"1.1.",
	"1..1",
	"1.1.+123",
	"1.1.-beta",
	"-1.1.1",
	"1.-1.1",
	"1.1.-1",
	// Leading zeroes
	"01.1.1",
	"001.1.1",
	"1.01.1",
	"1.001.1",
	"1.1.01",
	"1.1.001",
	"1.1.1-01",
	"1.1.1-001",
	"1.1.1-beta.01",
	"1.1.1-beta.001",
	"0.0.0-!",
	"0.0.0+!",
	// empty prerelease
	"0.0.0-.alpha",
	// empty build metadata
	"0.0.0-alpha+",
	"0.0.0-alpha+test.",
}

var comparisons = []comparison{
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0), 0},
	{semver.Build(2, 0, 0), semver.Build(1, 0, 0), 1},
	{semver.Build(0, 1, 0), semver.Build(0, 1, 0), 0},
	{semver.Build(0, 2, 0), semver.Build(0, 1, 0), 1},
	{semver.Build(0, 0, 1), semver.Build(0, 0, 1), 0},
	{semver.Build(0, 0, 2), semver.Build(0, 0, 1), 1},
	{semver.Build(1, 2, 3), semver.Build(1, 2, 3), 0},
	{semver.Build(2, 2, 4), semver.Build(1, 2, 4), 1},
	{semver.Build(1, 3, 3), semver.Build(1, 2, 3), 1},
	{semver.Build(1, 2, 4), semver.Build(1, 2, 3), 1},

	// Spec Examples #11
	{semver.Build(1, 0, 0), semver.Build(2, 0, 0), -1},
	{semver.Build(2, 0, 0), semver.Build(2, 1, 0), -1},
	{semver.Build(2, 1, 0), semver.Build(2, 1, 1), -1},

	// Spec Examples #9
	{semver.Build(1, 0, 0), semver.Build(1, 0, 0, []string{"alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"alpha"}), semver.Build(1, 0, 0, []string{"alpha", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "1"}), semver.Build(1, 0, 0, []string{"alpha", "beta"}), -1},
	{semver.Build(1, 0, 0, []string{"alpha", "beta"}), semver.Build(1, 0, 0, []string{"beta"}), -1},
	{semver.Build(1, 0, 0, []string{"beta"}), semver.Build(1, 0, 0, []string{"beta", "2"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "2"}), semver.Build(1, 0, 0, []string{"beta", "11"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"beta", "2"}), 1},
	{semver.Build(1, 0, 0, []string{"beta", "11"}), semver.Build(1, 0, 0, []string{"rc", "1"}), -1},
	{semver.Build(1, 0, 0, []string{"beta", "beta"}), semver.Build(1, 0, 0, []string{"beta", "alpha"}), 1},
	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0), -1},

	{semver.Build(1, 0, 0, []string{"rc", "1"}), semver.Build(1, 0, 0, []string{"rc", "1"}, []string{"435345345"}), -1},
}

var badPreRelease = [][]string{
	{"alpha", "-3"},
}

func TestStringer(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	expected := "1.2.3-alpha.1+35.45"
	result := fmt.Sprint(ver)

	if result != expected {
		t.Errorf("String() => %q, wanted %q", result, expected)
	}
}

func TestGetters(t *testing.T) {
	expected_major := uint64(1)
	expected_minor := uint64(2)
	expected_patch := uint64(3)
	expected_prerelease := "alpha.1"
	expected_metadata := "35.45"

	ver := semver.Build(expected_major, expected_minor, expected_patch)
	ver.SetPrerelease("alpha", "1")
	ver.SetMetadata("35", "45")

	if result := ver.Major(); result != expected_major {
		t.Errorf("%q.Major() => %q, wanted %q", ver, result, expected_major)
	}
	if result := ver.Minor(); result != expected_minor {
		t.Errorf("%q.Minor() => %q, wanted %q", ver, result, expected_minor)
	}
	if result := ver.Patch(); result != expected_patch {
		t.Errorf("%q.Patch() => %q, wanted %q", ver, result, expected_patch)
	}
	if result := ver.Prerelease(); result != expected_prerelease {
		t.Errorf("%q.Prerelease() => %q, wanted %q", ver, result, expected_prerelease)
	}
	if result := ver.Metadata(); result != expected_metadata {
		t.Errorf("%q.Metadata() => %q, wanted %q", ver, result, expected_metadata)
	}
}

func TestSetters(t *testing.T) {
	ver := semver.Build(1, 1, 1)
	ver.SetMajor(2)
	ver.SetMinor(3)
	ver.SetPatch(4)
	if err := ver.SetPrerelease("beta", "1"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}
	if err := ver.SetMetadata("22", "43"); err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	expected := "2.3.4-beta.1+22.43"
	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, wanted %q", result, expected)
	}
}

func TestNew(t *testing.T) {
	expected := "1.0.3-alpha.1+35.45"

	ver, err := semver.New(expected)
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}

	result := fmt.Sprint(ver)
	if result != expected {
		t.Errorf("Stringer() => %q, want %q", result, expected)
	}

}

func TestBadFormat(t *testing.T) {
	for _, version := range badVersions {
		_, err := semver.New(version)
		if err == nil {
			// TODO: Set up error types
			t.Errorf("New(%q) => %v, want Error", version, err)
		}
	}
}

func TestComparison(t *testing.T) {
	for _, c := range comparisons {
		result := c.main.Compare(c.other)
		if result != c.expected {
			t.Errorf("%q.Compare(%q) => %#v, want %#v", c.main, c.other, result, c.expected)
		}
	}
}

func TestSetPrerelease(t *testing.T) {
	ver := semver.Build(1, 2, 3)
	err := ver.SetPrerelease("12", "1", "0", "43")
	if err != nil {
		t.Errorf(fmt.Sprint(err))
	}
}

func BenchmarkParseSimple(b *testing.B) {
	const VERSION = "0.0.1"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkParseComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		semver.New(VERSION)
	}
}

func BenchmarkCompareSimple(b *testing.B) {
	const VERSION = "0.0.1"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}

func BenchmarkCompareComplex(b *testing.B) {
	const VERSION = "0.0.1-alpha.preview+123.456"
	v, _ := semver.New(VERSION)
	b.ResetTimer()
	for n := 0; n < b.N; n++ {
		v.Compare(v)
	}
}
<|endoftext|>


<commit_before>package send

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"

	hec "github.com/fuyufjh/splunk-hec-go"
	"github.com/mongodb/grip/level"
	"github.com/mongodb/grip/message"
)

const (
	splunkServerURL   = "GRIP_SPLUNK_SERVER_URL"
	splunkClientToken = "GRIP_SPLUNK_CLIENT_TOKEN"
	splunkChannel     = "GRIP_SPLUNK_CHANNEL"
)

type splunkLogger struct {
	info   SplunkConnectionInfo
	client splunkClient
	*Base
}

// SplunkConnectionInfo stores all information needed to connect
// to a splunk server to send log messsages.
type SplunkConnectionInfo struct {
	ServerURL string `bson:"url" json:"url" yaml:"url"`
	Token     string `bson:"token" json:"token" yaml:"token"`
	Channel   string `bson:"channel" json:"channel" yaml:"channel"`
}

// GetSplunkConnectionInfo builds a SplunkConnectionInfo structure
// reading default values from the following environment variables:
//
// 		GRIP_SPLUNK_SERVER_URL
//		GRIP_SPLUNK_CLIENT_TOKEN
//		GRIP_SPLUNK_CHANNEL
func GetSplunkConnectionInfo() SplunkConnectionInfo {
	return SplunkConnectionInfo{
		ServerURL: os.Getenv(splunkServerURL),
		Token:     os.Getenv(splunkClientToken),
		Channel:   os.Getenv(splunkChannel),
	}
}

func (info SplunkConnectionInfo) Populated() bool {
	return info.ServerURL != "" && info.Token != "" && info.Channel != ""
}

func (s *splunkLogger) Send(m message.Composer) {
	if s.level.ShouldLog(m) {
		g, ok := m.(*message.GroupComposer)
		if ok {
			batch := make([]*hec.Event, 0)
			for _, c := range g.Messages() {
				if s.level.ShouldLog(c) {
					batch = append(batch, hec.NewEvent(c.Raw()))
				}
			}
			if err := s.client.WriteBatch(batch); err != nil {
				s.errHandler(err, m)
			}
			return
		}

		if err := s.client.WriteEvent(hec.NewEvent(m.Raw())); err != nil {
			s.errHandler(err, m)
		}
	}
}

// NewSplunkLogger constructs a new Sender implementation that sends
// messages to a Splunk event collector using the credentials specified
// in the SplunkConnectionInfo struct.
func NewSplunkLogger(name string, info SplunkConnectionInfo, l LevelInfo) (Sender, error) {
	s := &splunkLogger{
		info:   info,
		client: &splunkClientImpl{},
		Base:   NewBase(name),
	}

	if err := s.client.Create(info.ServerURL, info.Token, info.Channel); err != nil {
		return nil, err
	}

	if err := s.SetLevel(l); err != nil {
		return nil, err
	}

	return s, nil
}

// MakeSplunkLogger constructs a new Sender implementation that reads
// the hostname, username, and password from environment variables:
//
// 		GRIP_SPLUNK_SERVER_URL
//		GRIP_SPLUNK_CLIENT_TOKEN
//		GRIP_SPLUNK_CLIENT_CHANNEL
func MakeSplunkLogger(name string) (Sender, error) {
	info := GetSplunkConnectionInfo()
	if info.ServerURL == "" {
		return nil, fmt.Errorf("environment variable %s not defined, cannot create splunk client",
			splunkServerURL)
	}
	if info.Token == "" {
		return nil, fmt.Errorf("environment variable %s not defined, cannot create splunk client",
			splunkClientToken)
	}
	return NewSplunkLogger(name, info, LevelInfo{level.Trace, level.Trace})
}

////////////////////////////////////////////////////////////////////////
//
// interface wrapper for the splunk client so that we can mock things out
//
////////////////////////////////////////////////////////////////////////

type splunkClient interface {
	Create(string, string, string) error
	WriteEvent(*hec.Event) error
	WriteBatch([]*hec.Event) error
}

type splunkClientImpl struct {
	hec.HEC
}

func (c *splunkClientImpl) Create(serverURL string, token string, channel string) error {
	c.HEC = hec.NewClient(serverURL, token)
	c.HEC.SetHTTPClient(&http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}})
	if channel != "" {
		c.HEC.SetChannel(channel)
	}
	return nil
}
<commit_msg>make splunk channel optional<commit_after>package send

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"

	hec "github.com/fuyufjh/splunk-hec-go"
	"github.com/mongodb/grip/level"
	"github.com/mongodb/grip/message"
)

const (
	splunkServerURL   = "GRIP_SPLUNK_SERVER_URL"
	splunkClientToken = "GRIP_SPLUNK_CLIENT_TOKEN"
	splunkChannel     = "GRIP_SPLUNK_CHANNEL"
)

type splunkLogger struct {
	info   SplunkConnectionInfo
	client splunkClient
	*Base
}

// SplunkConnectionInfo stores all information needed to connect
// to a splunk server to send log messsages.
type SplunkConnectionInfo struct {
	ServerURL string `bson:"url" json:"url" yaml:"url"`
	Token     string `bson:"token" json:"token" yaml:"token"`
	Channel   string `bson:"channel" json:"channel" yaml:"channel"`
}

// GetSplunkConnectionInfo builds a SplunkConnectionInfo structure
// reading default values from the following environment variables:
//
//		GRIP_SPLUNK_SERVER_URL
//		GRIP_SPLUNK_CLIENT_TOKEN
//		GRIP_SPLUNK_CHANNEL
func GetSplunkConnectionInfo() SplunkConnectionInfo {
	return SplunkConnectionInfo{
		ServerURL: os.Getenv(splunkServerURL),
		Token:     os.Getenv(splunkClientToken),
		Channel:   os.Getenv(splunkChannel),
	}
}

func (info SplunkConnectionInfo) Populated() bool {
	return info.ServerURL != "" && info.Token != ""
}

func (s *splunkLogger) Send(m message.Composer) {
	if s.level.ShouldLog(m) {
		g, ok := m.(*message.GroupComposer)
		if ok {
			batch := make([]*hec.Event, 0)
			for _, c := range g.Messages() {
				if s.level.ShouldLog(c) {
					batch = append(batch, hec.NewEvent(c.Raw()))
				}
			}
			if err := s.client.WriteBatch(batch); err != nil {
				s.errHandler(err, m)
			}
			return
		}

		if err := s.client.WriteEvent(hec.NewEvent(m.Raw())); err != nil {
			s.errHandler(err, m)
		}
	}
}

// NewSplunkLogger constructs a new Sender implementation that sends
// messages to a Splunk event collector using the credentials specified
// in the SplunkConnectionInfo struct.
func NewSplunkLogger(name string, info SplunkConnectionInfo, l LevelInfo) (Sender, error) {
	s := &splunkLogger{
		info:   info,
		client: &splunkClientImpl{},
		Base:   NewBase(name),
	}

	if err := s.client.Create(info.ServerURL, info.Token, info.Channel); err != nil {
		return nil, err
	}

	if err := s.SetLevel(l); err != nil {
		return nil, err
	}

	return s, nil
}

// MakeSplunkLogger constructs a new Sender implementation that reads
// the hostname, username, and password from environment variables:
//
//		GRIP_SPLUNK_SERVER_URL
//		GRIP_SPLUNK_CLIENT_TOKEN
//		GRIP_SPLUNK_CLIENT_CHANNEL
func MakeSplunkLogger(name string) (Sender, error) {
	info := GetSplunkConnectionInfo()
	if info.ServerURL == "" {
		return nil, fmt.Errorf("environment variable %s not defined, cannot create splunk client",
			splunkServerURL)
	}
	if info.Token == "" {
		return nil, fmt.Errorf("environment variable %s not defined, cannot create splunk client",
			splunkClientToken)
	}
	return NewSplunkLogger(name, info, LevelInfo{level.Trace, level.Trace})
}

////////////////////////////////////////////////////////////////////////
//
// interface wrapper for the splunk client so that we can mock things out
//
////////////////////////////////////////////////////////////////////////

type splunkClient interface {
	Create(string, string, string) error
	WriteEvent(*hec.Event) error
	WriteBatch([]*hec.Event) error
}

type splunkClientImpl struct {
	hec.HEC
}

func (c *splunkClientImpl) Create(serverURL string, token string, channel string) error {
	c.HEC = hec.NewClient(serverURL, token)
	c.HEC.SetHTTPClient(&http.Client{Transport: &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}})
	if channel != "" {
		c.HEC.SetChannel(channel)
	}
	return nil
}
<|endoftext|>