<commit_before>package client

// transfer2go/client - Go implementation transfer2go client
//
// Author: Valentin Kuznetsov <vkuznet@gmail.com>
//

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/vkuznet/transfer2go/core"
	"github.com/vkuznet/transfer2go/utils"
)

// AgentFiles holds agent alias/url and list of files to transfer
type AgentFiles struct {
	Alias string
	Url   string
	Files []string
}

// helper function to find agent alias from its url
func findAlias(agents map[string]string, aurl string) string {
	for alias, agent := range agents {
		if agent == aurl {
			return alias
		}
	}
	return ""
}

// helper function to rearrange given AgentFiles list into new one which merge
// files from the same agent
func reArrange(agentFiles []AgentFiles) []AgentFiles {
	var out []AgentFiles
	agents := make(map[string]string)
	afiles := make(map[string][]string)
	for _, rec := range agentFiles {
		agents[rec.Alias] = rec.Url
		eFiles, ok := afiles[rec.Alias]
		if ok {
			for _, f := range rec.Files {
				eFiles = append(eFiles, f)
			}
			afiles[rec.Alias] = eFiles
		} else {
			afiles[rec.Alias] = rec.Files
		}
	}
	for alias, aurl := range agents {
		rec := AgentFiles{Alias: alias, Url: aurl, Files: afiles[alias]}
		out = append(out, rec)
	}
	return out
}

// helper function to find LFNs within in agent list
func findFiles(agents map[string]string, src string) ([]AgentFiles, error) {

	// parse the input
	var lfn, block, dataset string
	if strings.Contains(src, "#") { // it is a block name, e.g. /a/b/c#123
		arr := strings.Split(src, "#")
		dataset = arr[0]
		block = arr[1]
	} else if strings.Count(src, "/") == 3 { // it is a dataset
		dataset = src
	} else { // it is lfn
		lfn = src
	}

	out := make(chan utils.ResponseType)
	defer close(out)
	umap := map[string]int{}
	for _, aurl := range agents {
		furl := fmt.Sprintf("%s/files?lfn=%s&block=%s&dataset=%s", aurl, lfn, block, dataset)
		umap[furl] = 1 // keep track of processed urls below
		go utils.Fetch(furl, []byte{}, out)
	}
	var agentFiles []AgentFiles
	exit := false
	for {
		select {
		case r := <-out:
			if r.Error == nil {
				var files []string
				err := json.Unmarshal(r.Data, &files)
				if err == nil {
					aurl := strings.Split(r.Url, "/files")[0]
					alias := findAlias(agents, aurl)
					if aurl != "" && alias != "" && len(files) > 0 {
						agentFiles = append(agentFiles, AgentFiles{Alias: alias, Url: aurl, Files: files})
					}
				}
			}
			delete(umap, r.Url) // remove Url from map
		default:
			if len(umap) == 0 { // no more requests, merge data records
				exit = true
			}
			time.Sleep(time.Duration(10) * time.Millisecond) // wait for response
		}
		if exit {
			break
		}
	}
	return reArrange(agentFiles), nil
}

// helper function to parse source and destination parameters
func parse(agent, src, dst string) ([][]core.TransferRequest, error) {
	var tr [][]core.TransferRequest
	var dstUrl string

	// find out list of all agents
	url := fmt.Sprintf("%s/agents", agent)
	resp := utils.FetchResponse(url, []byte{})
	if resp.Error != nil {
		return tr, resp.Error
	}
	var remoteAgents map[string]string
	e := json.Unmarshal(resp.Data, &remoteAgents)
	if e != nil {
		return tr, e
	}

	// resolve source agent name/alias and identify file to transfer
	if strings.Contains(src, ":") {
		arr := strings.Split(src, ":")
		src = arr[1]
	}

	// check if destination is ok
	dstUrl, ok := remoteAgents[dst]
	if !ok {
		log.WithFields(log.Fields{
			"Destination":  dst,
			"known agents": remoteAgents,
		}).Error("Unable to resolve destination")
		return tr, fmt.Errorf("Unknown destination")
	}

	// get list of records which provide info about agent and a file
	// and construct transfer collection
	records, err := findFiles(remoteAgents, src) // src here can be either lfn/block/dataset
	if err != nil {
		return tr, err
	}
	for _, rec := range records {
		var requests []core.TransferRequest
		for _, file := range rec.Files {
			req := core.TransferRequest{SrcUrl: rec.Url, SrcAlias: rec.Alias, File: file, DstUrl: dstUrl, DstAlias: dst}
			log.Println(req.String())
			requests = append(requests, req)
		}
		tr = append(tr, requests)
	}
	return tr, nil
}

// Transfer client function is responsible to initiate transfer request from
// source to destination.
func Transfer(agent, src, dst string) error {

	// parse src/dst parameters and construct list of transfer requests
	collection, err := parse(agent, src, dst)
	if err != nil {
		return err
	}

	// send tranfer requests to agents concurrently via go-routine
	out := make(chan utils.ResponseType)
	defer close(out)
	umap := map[string]int{}
	for _, transferRequests := range collection {
		furl := fmt.Sprintf("%s/request", transferRequests[0].SrcUrl)
		d, e := json.Marshal(transferRequests)
		if e != nil {
			return e
		}
		umap[furl] = 1 // keep track of processed urls below
		go utils.Fetch(furl, d, out)
	}

	// collect request responses
	exit := false
	for {
		select {
		case r := <-out:
			if r.Error != nil {
				log.WithFields(log.Fields{
					"Url": r.Url,
				}).Error("ERROR fail with transfer request to", r.Url)
				return r.Error
			}
			delete(umap, r.Url) // remove Url from map
		default:
			if len(umap) == 0 { // no more requests, merge data records
				exit = true
			}
			time.Sleep(time.Duration(10) * time.Millisecond) // wait for response
		}
		if exit {
			break
		}
	}
	return nil

}

// Agent function call agent url
func Agent(agent string) error {
	resp := utils.FetchResponse(agent, []byte{})
	log.Println(string(resp.Data))
	return resp.Error
}

// Register function upload given meta-data to the agent and register them in its TFC
func Register(agent, fname string) error {
	// read inpuf file name which contains records meta-data (catalog entries)
	c, e := ioutil.ReadFile(fname)
	if e != nil {
		return fmt.Errorf("Unable to read %s, error=%v\n", fname, e)
	}
	var uploadRecords, records []core.CatalogEntry
	err := json.Unmarshal([]byte(c), &records)
	if err != nil {
		return fmt.Errorf("Unable to parse catalog JSON file, %v\n", err)
	}
	// TODO: so far we scan every record and read a file to get its hash
	// this work only for local filesystem, but I don't know how it will work
	// for remote storage
	for _, rec := range records {
		if rec.Lfn == "" || rec.Pfn == "" || rec.Block == "" || rec.Dataset == "" {
			e := fmt.Errorf("Record must have at least the following fields: lfn, pfn, block, dataset, instead received: %v\n", rec)
			return e
		}
		data, err := ioutil.ReadFile(rec.Pfn)
		if err != nil {
			return err
		}
		hash, bytes := utils.Hash(data)
		r := core.CatalogEntry{Lfn: rec.Lfn, Pfn: rec.Pfn, Block: rec.Block, Dataset: rec.Dataset, Hash: hash, Bytes: bytes}
		uploadRecords = append(uploadRecords, r)
	}
	d, e := json.Marshal(uploadRecords)
	if e != nil {
		return e
	}
	url := fmt.Sprintf("%s/tfc", agent)
	resp := utils.FetchResponse(url, d)
	if resp.Error != nil {
		return fmt.Errorf("Unable to upload, url=%s, data=%s, err=%v\n", url, string(resp.Data), resp.Error)
	}
	log.WithFields(log.Fields{
		"Agent": agent,
		"Size":  len(uploadRecords),
	}).Info("Registered records in")
	return nil
}
<commit_msg>Changes in client<commit_after>package client

// transfer2go/client - Go implementation transfer2go client
//
// Author: Valentin Kuznetsov <vkuznet@gmail.com>
//

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"hash/adler32"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/vkuznet/transfer2go/core"
	"github.com/vkuznet/transfer2go/utils"
)

// AgentFiles holds agent alias/url and list of files to transfer
type AgentFiles struct {
	Alias string
	Url   string
	Files []string
}

// helper function to find agent alias from its url
func findAlias(agents map[string]string, aurl string) string {
	for alias, agent := range agents {
		if agent == aurl {
			return alias
		}
	}
	return ""
}

// helper function to rearrange given AgentFiles list into new one which merge
// files from the same agent
func reArrange(agentFiles []AgentFiles) []AgentFiles {
	var out []AgentFiles
	agents := make(map[string]string)
	afiles := make(map[string][]string)
	for _, rec := range agentFiles {
		agents[rec.Alias] = rec.Url
		eFiles, ok := afiles[rec.Alias]
		if ok {
			for _, f := range rec.Files {
				eFiles = append(eFiles, f)
			}
			afiles[rec.Alias] = eFiles
		} else {
			afiles[rec.Alias] = rec.Files
		}
	}
	for alias, aurl := range agents {
		rec := AgentFiles{Alias: alias, Url: aurl, Files: afiles[alias]}
		out = append(out, rec)
	}
	return out
}

// helper function to find LFNs within in agent list
func findFiles(agents map[string]string, src string) ([]AgentFiles, error) {

	// parse the input
	var lfn, block, dataset string
	if strings.Contains(src, "#") { // it is a block name, e.g. /a/b/c#123
		arr := strings.Split(src, "#")
		dataset = arr[0]
		block = arr[1]
	} else if strings.Count(src, "/") == 3 { // it is a dataset
		dataset = src
	} else { // it is lfn
		lfn = src
	}

	out := make(chan utils.ResponseType)
	defer close(out)
	umap := map[string]int{}
	for _, aurl := range agents {
		furl := fmt.Sprintf("%s/files?lfn=%s&block=%s&dataset=%s", aurl, lfn, block, dataset)
		umap[furl] = 1 // keep track of processed urls below
		go utils.Fetch(furl, []byte{}, out)
	}
	var agentFiles []AgentFiles
	exit := false
	for {
		select {
		case r := <-out:
			if r.Error == nil {
				var files []string
				err := json.Unmarshal(r.Data, &files)
				if err == nil {
					aurl := strings.Split(r.Url, "/files")[0]
					alias := findAlias(agents, aurl)
					if aurl != "" && alias != "" && len(files) > 0 {
						agentFiles = append(agentFiles, AgentFiles{Alias: alias, Url: aurl, Files: files})
					}
				}
			}
			delete(umap, r.Url) // remove Url from map
		default:
			if len(umap) == 0 { // no more requests, merge data records
				exit = true
			}
			time.Sleep(time.Duration(10) * time.Millisecond) // wait for response
		}
		if exit {
			break
		}
	}
	return reArrange(agentFiles), nil
}

// helper function to parse source and destination parameters
func parse(agent, src, dst string) ([][]core.TransferRequest, error) {
	var tr [][]core.TransferRequest
	var dstUrl string

	// find out list of all agents
	url := fmt.Sprintf("%s/agents", agent)
	resp := utils.FetchResponse(url, []byte{})
	if resp.Error != nil {
		return tr, resp.Error
	}
	var remoteAgents map[string]string
	e := json.Unmarshal(resp.Data, &remoteAgents)
	if e != nil {
		return tr, e
	}

	// resolve source agent name/alias and identify file to transfer
	if strings.Contains(src, ":") {
		arr := strings.Split(src, ":")
		src = arr[1]
	}

	// check if destination is ok
	dstUrl, ok := remoteAgents[dst]
	if !ok {
		log.WithFields(log.Fields{
			"Destination":  dst,
			"known agents": remoteAgents,
		}).Error("Unable to resolve destination")
		return tr, fmt.Errorf("Unknown destination")
	}

	// get list of records which provide info about agent and a file
	// and construct transfer collection
	records, err := findFiles(remoteAgents, src) // src here can be either lfn/block/dataset
	if err != nil {
		return tr, err
	}
	for _, rec := range records {
		var requests []core.TransferRequest
		for _, file := range rec.Files {
			req := core.TransferRequest{SrcUrl: rec.Url, SrcAlias: rec.Alias, File: file, DstUrl: dstUrl, DstAlias: dst}
			log.Println(req.String())
			requests = append(requests, req)
		}
		tr = append(tr, requests)
	}
	return tr, nil
}

// Transfer client function is responsible to initiate transfer request from
// source to destination.
func Transfer(agent, src, dst string) error {

	// parse src/dst parameters and construct list of transfer requests
	collection, err := parse(agent, src, dst)
	if err != nil {
		return err
	}

	// send tranfer requests to agents concurrently via go-routine
	out := make(chan utils.ResponseType)
	defer close(out)
	umap := map[string]int{}
	for _, transferRequests := range collection {
		furl := fmt.Sprintf("%s/request", transferRequests[0].SrcUrl)
		d, e := json.Marshal(transferRequests)
		if e != nil {
			return e
		}
		umap[furl] = 1 // keep track of processed urls below
		go utils.Fetch(furl, d, out)
	}

	// collect request responses
	exit := false
	for {
		select {
		case r := <-out:
			if r.Error != nil {
				log.WithFields(log.Fields{
					"Url": r.Url,
				}).Error("ERROR fail with transfer request to", r.Url)
				return r.Error
			}
			delete(umap, r.Url) // remove Url from map
		default:
			if len(umap) == 0 { // no more requests, merge data records
				exit = true
			}
			time.Sleep(time.Duration(10) * time.Millisecond) // wait for response
		}
		if exit {
			break
		}
	}
	return nil

}

// Agent function call agent url
func Agent(agent string) error {
	resp := utils.FetchResponse(agent, []byte{})
	log.Println(string(resp.Data))
	return resp.Error
}

// Register function upload given meta-data to the agent and register them in its TFC
func Register(agent, fname string) error {
	// read inpuf file name which contains records meta-data (catalog entries)
	c, e := ioutil.ReadFile(fname)
	if e != nil {
		return fmt.Errorf("Unable to read %s, error=%v\n", fname, e)
	}
	var uploadRecords, records []core.CatalogEntry
	err := json.Unmarshal([]byte(c), &records)
	if err != nil {
		return fmt.Errorf("Unable to parse catalog JSON file, %v\n", err)
	}
	// TODO: so far we scan every record and read a file to get its hash
	// this work only for local filesystem, but I don't know how it will work
	// for remote storage
	for _, rec := range records {
		if rec.Lfn == "" || rec.Pfn == "" || rec.Block == "" || rec.Dataset == "" {
			e := fmt.Errorf("Record must have at least the following fields: lfn, pfn, block, dataset, instead received: %v\n", rec)
			return e
		}
		hash, bytes, err := readFile(rec.Pfn)
		if err != nil {
			return err
		}
		//hash, bytes := utils.Hash(data)
		r := core.CatalogEntry{Lfn: rec.Lfn, Pfn: rec.Pfn, Block: rec.Block, Dataset: rec.Dataset, Hash: hash, Bytes: bytes}
		uploadRecords = append(uploadRecords, r)
	}
	d, e := json.Marshal(uploadRecords)
	if e != nil {
		return e
	}
	url := fmt.Sprintf("%s/tfc", agent)
	resp := utils.FetchResponse(url, d)
	if resp.Error != nil {
		return fmt.Errorf("Unable to upload, url=%s, data=%s, err=%v\n", url, string(resp.Data), resp.Error)
	}
	log.WithFields(log.Fields{
		"Agent": agent,
		"Size":  len(uploadRecords),
	}).Info("Registered records in")
	return nil
}

func readFile(path string) (string, int64, error) {
	file, err := os.Open(path)
	if err != nil {
		return "", 0, err
	}
	var bytes int64
	// Create a synchronous in-memory pipe. This pipe will
	// allow us to use a Writer as a Reader.
	pipeReader, pipeWriter := io.Pipe()
	// create a hasher to calculate data hash
	hasher := adler32.New()
	// Wait for the reading and writing processes of the io.pipe
	done := make(chan error)
	// Create a goroutine to write chunk wise in io.pipe
	go func() {
		defer pipeWriter.Close()
		_, err = io.Copy(pipeWriter, file)
		if err != nil {
			done <- err
			return
		}
		done <- nil
	}()
	// Create a goroutine to read chunk wise from io.pipe
	go func() {
		defer pipeReader.Close()
		bytes, err = io.Copy(hasher, pipeReader)
		if err != nil {
			done <- err
			return
		}
		done <- nil
	}()
	err = <-done
	if err != nil {
		return "", 0, err
	}
	err = <-done
	if err != nil {
		return "", 0, err
	}
	hash := hex.EncodeToString(hasher.Sum(nil))
	return hash, bytes, nil
}
<|endoftext|>


<commit_before><commit_msg>add client.AppList()<commit_after><|endoftext|>


<commit_before>package medtronic

import (
	"log"
	"time"

	"github.com/ecc1/nightscout"
)

func (r HistoryRecord) NightscoutTreatment(r2 *HistoryRecord) *nightscout.Treatment {
	info := nightscout.Treatment{
		EventTime: r.Time,
		EnteredBy: "ecc",
	}
	switch r.Type() {
	case BgCapture:
		info.EventType = "BG Check"
		g := r.Glucose.NightscoutGlucose()
		info.Glucose = &g
	case TempBasalRate:
		if !nextEvent(r, r2, TempBasalDuration) {
			return nil
		}
		if *r2.Duration == 0 {
			info.EventType = "Temp Basal End"
		} else {
			info.EventType = "Temp Basal Start"
			ins := r.Insulin.NightscoutInsulin()
			info.Absolute = &ins
			min := int(*r2.Duration / time.Minute)
			info.Duration = &min
		}
	case Bolus:
		info.EventType = "Meal Bolus"
		ins := r.Bolus.Amount.NightscoutInsulin()
		info.Insulin = &ins
		min := int(r.Bolus.Duration / time.Minute)
		info.Duration = &min
	case Rewind:
		if !nextEvent(r, r2, Prime) {
			return nil
		}
		info.EventType = "Site Change"
	case ResumePump:
		info.EventType = "Temp Basal End"
	case SuspendPump:
		info.EventType = "Temp Basal Start"
		zero := Insulin(0).NightscoutInsulin()
		info.Absolute = &zero
		min := 24 * 60
		info.Duration = &min
	default:
		return nil
	}
	return &info
}

func nextEvent(r HistoryRecord, r2 *HistoryRecord, t HistoryRecordType) bool {
	if r2 == nil || r2.Type() != t {
		next := "nothing"
		if r2 != nil {
			next = r2.Type().String()
		}
		log.Printf("expected %v to be followed by %v at %v but found %s", r.Type(), t, r.Time, next)
		return false
	}
	return true
}

func (r Glucose) NightscoutGlucose() nightscout.Glucose {
	return nightscout.Glucose(r)
}

func (r Insulin) NightscoutInsulin() nightscout.Insulin {
	return nightscout.Insulin(float64(r) / 1000)
}

func (r Voltage) NightscoutVoltage() nightscout.Voltage {
	return nightscout.Voltage(float64(r) / 1000)
}

func (sched BasalRateSchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.Rate}
	}
	return tv
}

func (sched CarbRatioSchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.CarbRatio}
	}
	return tv
}

func (sched InsulinSensitivitySchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.Sensitivity}
	}
	return tv
}

func (sched GlucoseTargetSchedule) NightscoutSchedule() (nightscout.Schedule, nightscout.Schedule) {
	n := len(sched)
	low := make(nightscout.Schedule, n)
	high := make(nightscout.Schedule, n)
	for i, r := range sched {
		low[i] = nightscout.TimeValue{r.Start.String(), r.Low}
		high[i] = nightscout.TimeValue{r.Start.String(), r.High}
	}
	return low, high
}
<commit_msg>Use user name for enteredBy field in treatment<commit_after>package medtronic

import (
	"log"
	"time"

	"github.com/ecc1/nightscout"
)

func (r HistoryRecord) NightscoutTreatment(r2 *HistoryRecord) *nightscout.Treatment {
	info := nightscout.Treatment{
		EventTime: r.Time,
		EnteredBy: nightscout.Username(),
	}
	switch r.Type() {
	case BgCapture:
		info.EventType = "BG Check"
		g := r.Glucose.NightscoutGlucose()
		info.Glucose = &g
	case TempBasalRate:
		if !nextEvent(r, r2, TempBasalDuration) {
			return nil
		}
		if *r2.Duration == 0 {
			info.EventType = "Temp Basal End"
		} else {
			info.EventType = "Temp Basal Start"
			ins := r.Insulin.NightscoutInsulin()
			info.Absolute = &ins
			min := int(*r2.Duration / time.Minute)
			info.Duration = &min
		}
	case Bolus:
		info.EventType = "Meal Bolus"
		ins := r.Bolus.Amount.NightscoutInsulin()
		info.Insulin = &ins
		min := int(r.Bolus.Duration / time.Minute)
		info.Duration = &min
	case Rewind:
		if !nextEvent(r, r2, Prime) {
			return nil
		}
		info.EventType = "Site Change"
	case ResumePump:
		info.EventType = "Temp Basal End"
	case SuspendPump:
		info.EventType = "Temp Basal Start"
		zero := Insulin(0).NightscoutInsulin()
		info.Absolute = &zero
		min := 24 * 60
		info.Duration = &min
	default:
		return nil
	}
	return &info
}

func nextEvent(r HistoryRecord, r2 *HistoryRecord, t HistoryRecordType) bool {
	if r2 == nil || r2.Type() != t {
		next := "nothing"
		if r2 != nil {
			next = r2.Type().String()
		}
		log.Printf("expected %v to be followed by %v at %v but found %s", r.Type(), t, r.Time, next)
		return false
	}
	return true
}

func (r Glucose) NightscoutGlucose() nightscout.Glucose {
	return nightscout.Glucose(r)
}

func (r Insulin) NightscoutInsulin() nightscout.Insulin {
	return nightscout.Insulin(float64(r) / 1000)
}

func (r Voltage) NightscoutVoltage() nightscout.Voltage {
	return nightscout.Voltage(float64(r) / 1000)
}

func (sched BasalRateSchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.Rate}
	}
	return tv
}

func (sched CarbRatioSchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.CarbRatio}
	}
	return tv
}

func (sched InsulinSensitivitySchedule) NightscoutSchedule() nightscout.Schedule {
	n := len(sched)
	tv := make(nightscout.Schedule, n)
	for i, r := range sched {
		tv[i] = nightscout.TimeValue{r.Start.String(), r.Sensitivity}
	}
	return tv
}

func (sched GlucoseTargetSchedule) NightscoutSchedule() (nightscout.Schedule, nightscout.Schedule) {
	n := len(sched)
	low := make(nightscout.Schedule, n)
	high := make(nightscout.Schedule, n)
	for i, r := range sched {
		low[i] = nightscout.TimeValue{r.Start.String(), r.Low}
		high[i] = nightscout.TimeValue{r.Start.String(), r.High}
	}
	return low, high
}
<|endoftext|>


<commit_before>package strategy

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/gin-gonic/gin"
	h "github.com/open-falcon/falcon-plus/modules/api/app/helper"
	f "github.com/open-falcon/falcon-plus/modules/api/app/model/falcon_portal"
)

func GetStrategys(c *gin.Context) {
	var strategys []f.Strategy
	tidtmp := c.DefaultQuery("tid", "")
	if tidtmp == "" {
		h.JSONR(c, badstatus, "tid is missing")
		return
	}
	tid, err := strconv.Atoi(tidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	dt := db.Falcon.Where("tpl_id = ?", tid).Find(&strategys)
	if dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, strategys)
	return
}

type APICreateStrategyInput struct {
	Metric     string `json:"metric" binding:"required"`
	Tags       string `json:"tags"`
	MaxStep    int    `json:"max_step" binding:"required"`
	Priority   int    `json:"priority" binding:"exists"`
	Func       string `json:"func" binding:"required"`
	Op         string `json:"op" binding:"required"`
	RightValue string `json:"right_value" binding:"required"`
	Note       string `json:"note"`
	RunBegin   string `json:"run_begin"`
	RunEnd     string `json:"run_end"`
	TplId      int64  `json:"tpl_id" binding:"required"`
}

func (this APICreateStrategyInput) CheckFormat() (err error) {
	validOp := regexp.MustCompile(`^(>|=|<|!)(=)?$`)
	validRightValue := regexp.MustCompile(`^\d+$`)
	validTime := regexp.MustCompile(`^\d{2}:\d{2}$`)
	switch {
	case !validOp.MatchString(this.Op):
		err = errors.New("op's formating is not vaild")
	case !validRightValue.MatchString(this.RightValue):
		err = errors.New("right_value's formating is not vaild")
	case !validTime.MatchString(this.RunBegin) && this.RunBegin != "":
		err = errors.New("run_begin's formating is not vaild, please refer ex. 00:00")
	case !validTime.MatchString(this.RunEnd) && this.RunEnd != "":
		err = errors.New("run_end's formating is not vaild, please refer ex. 24:00")
	}
	return
}

func CreateStrategy(c *gin.Context) {
	var inputs APICreateStrategyInput
	if err := c.Bind(&inputs); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	if err := inputs.CheckFormat(); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{
		Metric:     inputs.Metric,
		Tags:       inputs.Tags,
		MaxStep:    inputs.MaxStep,
		Priority:   inputs.Priority,
		Func:       inputs.Func,
		Op:         inputs.Op,
		RightValue: inputs.RightValue,
		Note:       inputs.Note,
		RunBegin:   inputs.RunBegin,
		RunEnd:     inputs.RunEnd,
		TplId:      inputs.TplId,
	}
	dt := db.Falcon.Save(&strategy)
	if dt.Error != nil {
		h.JSONR(c, expecstatus, dt.Error)
		return
	}
	h.JSONR(c, "stragtegy created")
	return
}

func GetStrategy(c *gin.Context) {
	sidtmp := c.Params.ByName("sid")
	if sidtmp == "" {
		h.JSONR(c, badstatus, "sid is missing")
		return
	}
	sid, err := strconv.Atoi(sidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{ID: int64(sid)}
	if dt := db.Falcon.Find(&strategy); dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, strategy)
	return
}

type APIUpdateStrategyInput struct {
	ID         int64  `json:"id" binding:"required"`
	Metric     string `json:"metric" binding:"required"`
	Tags       string `json:"tags"`
	MaxStep    int    `json:"max_step" binding:"required"`
	Priority   int    `json:"priority" binding:"exists"`
	Func       string `json:"func" binding:"required"`
	Op         string `json:"op" binding:"required"`
	RightValue string `json:"right_value" binding:"required"`
	Note       string `json:"note"`
	RunBegin   string `json:"run_begin"`
	RunEnd     string `json:"run_end"`
}

func (this APIUpdateStrategyInput) CheckFormat() (err error) {
	validOp := regexp.MustCompile(`^(>|=|<|!)(=)?$`)
	validRightValue := regexp.MustCompile(`^\d+$`)
	validTime := regexp.MustCompile(`^\d{2}:\d{2}$`)
	switch {
	case !validOp.MatchString(this.Op):
		err = errors.New("op's formating is not vaild")
	case !validRightValue.MatchString(this.RightValue):
		err = errors.New("right_value's formating is not vaild")
	case !validTime.MatchString(this.RunBegin) && this.RunBegin != "":
		err = errors.New("run_begin's formating is not vaild, please refer ex. 00:00")
	case !validTime.MatchString(this.RunEnd) && this.RunEnd != "":
		err = errors.New("run_end's formating is not vaild, please refer ex. 24:00")
	}
	return
}

func UpdateStrategy(c *gin.Context) {
	var inputs APIUpdateStrategyInput
	if err := c.Bind(&inputs); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	if err := inputs.CheckFormat(); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{
		ID: inputs.ID,
	}
	if dt := db.Falcon.Find(&strategy); dt.Error != nil {
		h.JSONR(c, expecstatus, fmt.Sprintf("find strategy got error:%v", dt.Error))
		return
	}
	ustrategy := map[string]interface{}{
		"Metric":     inputs.Metric,
		"Tags":       inputs.Tags,
		"MaxStep":    inputs.MaxStep,
		"Priority":   inputs.Priority,
		"Func":       inputs.Func,
		"Op":         inputs.Op,
		"RightValue": inputs.RightValue,
		"Note":       inputs.Note,
		"RunBegin":   inputs.RunBegin,
		"RunEnd":     inputs.RunEnd}
	if dt := db.Falcon.Model(&strategy).Where("id = ?", strategy.ID).Update(ustrategy); dt.Error != nil {
		h.JSONR(c, expecstatus, dt.Error)
		return
	}
	h.JSONR(c, fmt.Sprintf("stragtegy:%d has been updated", strategy.ID))
	return
}

func DeleteStrategy(c *gin.Context) {
	sidtmp := c.Params.ByName("sid")
	if sidtmp == "" {
		h.JSONR(c, badstatus, "sid is missing")
		return
	}
	sid, err := strconv.Atoi(sidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{ID: int64(sid)}
	if dt := db.Falcon.Delete(&strategy); dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, fmt.Sprintf("strategy:%d has been deleted", sid))
	return
}

func MetricQuery(c *gin.Context) {
	data, err := ioutil.ReadFile("data/metric")
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	metrics := strings.Split(string(data), "\n")
	h.JSONR(c, metrics)
	return
}
<commit_msg>fixed static file path missing issue of api module<commit_after>package strategy

import (
	"errors"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/gin-gonic/gin"
	"github.com/spf13/viper"
	h "github.com/open-falcon/falcon-plus/modules/api/app/helper"
	f "github.com/open-falcon/falcon-plus/modules/api/app/model/falcon_portal"
)

func GetStrategys(c *gin.Context) {
	var strategys []f.Strategy
	tidtmp := c.DefaultQuery("tid", "")
	if tidtmp == "" {
		h.JSONR(c, badstatus, "tid is missing")
		return
	}
	tid, err := strconv.Atoi(tidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	dt := db.Falcon.Where("tpl_id = ?", tid).Find(&strategys)
	if dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, strategys)
	return
}

type APICreateStrategyInput struct {
	Metric     string `json:"metric" binding:"required"`
	Tags       string `json:"tags"`
	MaxStep    int    `json:"max_step" binding:"required"`
	Priority   int    `json:"priority" binding:"exists"`
	Func       string `json:"func" binding:"required"`
	Op         string `json:"op" binding:"required"`
	RightValue string `json:"right_value" binding:"required"`
	Note       string `json:"note"`
	RunBegin   string `json:"run_begin"`
	RunEnd     string `json:"run_end"`
	TplId      int64  `json:"tpl_id" binding:"required"`
}

func (this APICreateStrategyInput) CheckFormat() (err error) {
	validOp := regexp.MustCompile(`^(>|=|<|!)(=)?$`)
	validRightValue := regexp.MustCompile(`^\d+$`)
	validTime := regexp.MustCompile(`^\d{2}:\d{2}$`)
	switch {
	case !validOp.MatchString(this.Op):
		err = errors.New("op's formating is not vaild")
	case !validRightValue.MatchString(this.RightValue):
		err = errors.New("right_value's formating is not vaild")
	case !validTime.MatchString(this.RunBegin) && this.RunBegin != "":
		err = errors.New("run_begin's formating is not vaild, please refer ex. 00:00")
	case !validTime.MatchString(this.RunEnd) && this.RunEnd != "":
		err = errors.New("run_end's formating is not vaild, please refer ex. 24:00")
	}
	return
}

func CreateStrategy(c *gin.Context) {
	var inputs APICreateStrategyInput
	if err := c.Bind(&inputs); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	if err := inputs.CheckFormat(); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{
		Metric:     inputs.Metric,
		Tags:       inputs.Tags,
		MaxStep:    inputs.MaxStep,
		Priority:   inputs.Priority,
		Func:       inputs.Func,
		Op:         inputs.Op,
		RightValue: inputs.RightValue,
		Note:       inputs.Note,
		RunBegin:   inputs.RunBegin,
		RunEnd:     inputs.RunEnd,
		TplId:      inputs.TplId,
	}
	dt := db.Falcon.Save(&strategy)
	if dt.Error != nil {
		h.JSONR(c, expecstatus, dt.Error)
		return
	}
	h.JSONR(c, "stragtegy created")
	return
}

func GetStrategy(c *gin.Context) {
	sidtmp := c.Params.ByName("sid")
	if sidtmp == "" {
		h.JSONR(c, badstatus, "sid is missing")
		return
	}
	sid, err := strconv.Atoi(sidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{ID: int64(sid)}
	if dt := db.Falcon.Find(&strategy); dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, strategy)
	return
}

type APIUpdateStrategyInput struct {
	ID         int64  `json:"id" binding:"required"`
	Metric     string `json:"metric" binding:"required"`
	Tags       string `json:"tags"`
	MaxStep    int    `json:"max_step" binding:"required"`
	Priority   int    `json:"priority" binding:"exists"`
	Func       string `json:"func" binding:"required"`
	Op         string `json:"op" binding:"required"`
	RightValue string `json:"right_value" binding:"required"`
	Note       string `json:"note"`
	RunBegin   string `json:"run_begin"`
	RunEnd     string `json:"run_end"`
}

func (this APIUpdateStrategyInput) CheckFormat() (err error) {
	validOp := regexp.MustCompile(`^(>|=|<|!)(=)?$`)
	validRightValue := regexp.MustCompile(`^\d+$`)
	validTime := regexp.MustCompile(`^\d{2}:\d{2}$`)
	switch {
	case !validOp.MatchString(this.Op):
		err = errors.New("op's formating is not vaild")
	case !validRightValue.MatchString(this.RightValue):
		err = errors.New("right_value's formating is not vaild")
	case !validTime.MatchString(this.RunBegin) && this.RunBegin != "":
		err = errors.New("run_begin's formating is not vaild, please refer ex. 00:00")
	case !validTime.MatchString(this.RunEnd) && this.RunEnd != "":
		err = errors.New("run_end's formating is not vaild, please refer ex. 24:00")
	}
	return
}

func UpdateStrategy(c *gin.Context) {
	var inputs APIUpdateStrategyInput
	if err := c.Bind(&inputs); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	if err := inputs.CheckFormat(); err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{
		ID: inputs.ID,
	}
	if dt := db.Falcon.Find(&strategy); dt.Error != nil {
		h.JSONR(c, expecstatus, fmt.Sprintf("find strategy got error:%v", dt.Error))
		return
	}
	ustrategy := map[string]interface{}{
		"Metric":     inputs.Metric,
		"Tags":       inputs.Tags,
		"MaxStep":    inputs.MaxStep,
		"Priority":   inputs.Priority,
		"Func":       inputs.Func,
		"Op":         inputs.Op,
		"RightValue": inputs.RightValue,
		"Note":       inputs.Note,
		"RunBegin":   inputs.RunBegin,
		"RunEnd":     inputs.RunEnd}
	if dt := db.Falcon.Model(&strategy).Where("id = ?", strategy.ID).Update(ustrategy); dt.Error != nil {
		h.JSONR(c, expecstatus, dt.Error)
		return
	}
	h.JSONR(c, fmt.Sprintf("stragtegy:%d has been updated", strategy.ID))
	return
}

func DeleteStrategy(c *gin.Context) {
	sidtmp := c.Params.ByName("sid")
	if sidtmp == "" {
		h.JSONR(c, badstatus, "sid is missing")
		return
	}
	sid, err := strconv.Atoi(sidtmp)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	strategy := f.Strategy{ID: int64(sid)}
	if dt := db.Falcon.Delete(&strategy); dt.Error != nil {
		h.JSONR(c, badstatus, dt.Error)
		return
	}
	h.JSONR(c, fmt.Sprintf("strategy:%d has been deleted", sid))
	return
}

func MetricQuery(c *gin.Context) {
	filePath := viper.GetString("metric_list_file")
	if filePath == "" {
		filePath = "./data/metric"
	}
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		h.JSONR(c, badstatus, err)
		return
	}
	metrics := strings.Split(string(data), "\n")
	h.JSONR(c, metrics)
	return
}
<|endoftext|>


<commit_before>package goczmq

import (
	"testing"
)

func TestZproxy(t *testing.T) {
	// Create and configure our proxy
	proxy := NewProxy()
	defer proxy.Destroy()

	err := proxy.Verbose()
	if err != nil {
		t.Errorf("VERBOSE error: %s", err)
	}

	err = proxy.SetFrontend(PULL, "inproc://frontend")
	if err != nil {
		t.Errorf("FRONTEND error: %s", err)
	}

	err = proxy.SetBackend(PUSH, "inproc://backend")
	if err != nil {
		t.Errorf("BACKEND error: %s", err)
	}

	err = proxy.SetCapture("inproc://capture")
	if err != nil {
		t.Errorf("CAPTURE error: %s", err)
	}

	// connect application sockets to proxy
	faucet := NewSock(PUSH)
	err = faucet.Connect("inproc://frontend")
	if err != nil {
		t.Error(err)
	}
	defer faucet.Destroy()

	sink := NewSock(PULL)
	err = sink.Connect("inproc://backend")
	if err != nil {
		t.Error(err)
	}
	defer sink.Destroy()

	tap := NewSock(PULL)
	_, err = tap.Bind("inproc://capture")
	if err != nil {
		t.Error(err)
	}
	defer tap.Destroy()

	// send some messages and check they arrived
	faucet.SendBytes([]byte("Hello"), 0)
	faucet.SendBytes([]byte("World"), 0)

	// check the tap
	b, f, err := tap.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Hello" {
		t.Errorf("tap expected %s, received %s", "Hello", string(b))
	}

	b, f, err = tap.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "World" {
		t.Errorf("tap expected %s, received %s", "World", string(b))
	}

	// check the sink
	b, f, err = sink.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Hello" {
		t.Errorf("sink expected %s, received %s", "Hello", string(b))
	}

	b, f, err = sink.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "World" {
		t.Errorf("sink expected %s, received %s", "World", string(b))
	}

	// Test pause/resume functionality
	// FIXME: improve this test once we can receive with a nowait
	err = proxy.Pause()
	if err != nil {
		t.Error(err)
	}

	err = proxy.Resume()
	if err != nil {
		t.Error(err)
	}

	proxy.Destroy()
}
<commit_msg>more robust test of proxy pause and resume<commit_after>package goczmq

import (
	"testing"
)

func TestZproxy(t *testing.T) {
	// Create and configure our proxy
	proxy := NewProxy()
	defer proxy.Destroy()

	err := proxy.Verbose()
	if err != nil {
		t.Errorf("VERBOSE error: %s", err)
	}

	err = proxy.SetFrontend(PULL, "inproc://frontend")
	if err != nil {
		t.Errorf("FRONTEND error: %s", err)
	}

	err = proxy.SetBackend(PUSH, "inproc://backend")
	if err != nil {
		t.Errorf("BACKEND error: %s", err)
	}

	err = proxy.SetCapture("inproc://capture")
	if err != nil {
		t.Errorf("CAPTURE error: %s", err)
	}

	// connect application sockets to proxy
	faucet := NewSock(PUSH)
	err = faucet.Connect("inproc://frontend")
	if err != nil {
		t.Error(err)
	}
	defer faucet.Destroy()

	sink := NewSock(PULL)
	err = sink.Connect("inproc://backend")
	if err != nil {
		t.Error(err)
	}
	defer sink.Destroy()

	tap := NewSock(PULL)
	_, err = tap.Bind("inproc://capture")
	if err != nil {
		t.Error(err)
	}
	defer tap.Destroy()

	// send some messages and check they arrived
	faucet.SendBytes([]byte("Hello"), 0)
	faucet.SendBytes([]byte("World"), 0)

	// check the tap
	b, f, err := tap.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Hello" {
		t.Errorf("tap expected %s, received %s", "Hello", string(b))
	}

	b, f, err = tap.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "World" {
		t.Errorf("tap expected %s, received %s", "World", string(b))
	}

	// check the sink
	b, f, err = sink.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Hello" {
		t.Errorf("sink expected %s, received %s", "Hello", string(b))
	}

	b, f, err = sink.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "World" {
		t.Errorf("sink expected %s, received %s", "World", string(b))
	}

	// Test pause/resume functionality
	// FIXME: improve this test once we can receive with a nowait
	err = proxy.Pause()
	if err != nil {
		t.Error(err)
	}

	faucet.SendBytes([]byte("Belated Hello"), 0)

	if sink.Pollin() {
		t.Error("Paused proxy should not pass message but did")
	}

	if tap.Pollin() {
		t.Error("Paused proxy should not pass message but did")
	}

	err = proxy.Resume()
	if err != nil {
		t.Error(err)
	}

	b, f, err = sink.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Belated Hello" {
		t.Errorf("sink expected %s, received %s", "Belated Hello", string(b))
	}

	b, f, err = tap.RecvBytes()
	if err != nil {
		t.Error(err)
	}

	if f == MORE {
		t.Error("MORE set and should not be")
	}

	if string(b) != "Belated Hello" {
		t.Errorf("tap expected %s, received %s", "Belated Hello", string(b))
	}

	proxy.Destroy()
}
<|endoftext|>


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

package pkcs7

import (
	"fmt"
	"io"

	"encoding/asn1"

	"crypto"
	"crypto/cipher"
	"crypto/x509"
	"crypto/x509/pkix"

	"pault.ag/go/pkcs7/utils"
)

func readRand(rand io.Reader, size int) ([]byte, error) {
	data := make([]byte, size)
	n, err := io.ReadFull(rand, data)
	if err != nil {
		return nil, err
	}
	if n != size {
		return nil, fmt.Errorf("pkcs7: not enough calming entropy")
	}
	return data, nil
}

func newIssuerAndSerialNumber(cert x509.Certificate) (*IssuerAndSerialNumber, error) {
	return &IssuerAndSerialNumber{
		Issuer: asn1.RawValue{FullBytes: cert.RawIssuer},
		Serial: cert.SerialNumber,
	}, nil
}

func newRecipientInfo(rand io.Reader, cert x509.Certificate, algorithm pkix.AlgorithmIdentifier, key []byte) (*RecipientInfo, error) {
	issuerAndSerial, err := newIssuerAndSerialNumber(cert)
	if err != nil {
		return nil, err
	}

	encryptedKey, err := utils.Encrypt(rand, cert, key, nil)
	if err != nil {
		return nil, err
	}

	return &RecipientInfo{
		IssuerAndSerialNumber:  *issuerAndSerial,
		KeyEncryptionAlgorithm: algorithm,
		EncryptedKey:           encryptedKey,
	}, nil
}

func newEncryptedContentInfo(encryptedContentType asn1.ObjectIdentifier, algorithm pkix.AlgorithmIdentifier, content []byte) (*EncryptedContentInfo, error) {
	return &EncryptedContentInfo{
		Type:      encryptedContentType,
		Algorithm: algorithm,
		Content:   asn1.RawValue{Bytes: content},
	}, nil
}

func newEnvelopedData(r Recipients, eci EncryptedContentInfo) (*EnvelopedData, error) {
	return &EnvelopedData{
		Version:              0,
		Recipients:           r,
		EncryptedContentInfo: eci,
	}, nil

}

func newContentInfo(contentType asn1.ObjectIdentifier, content []byte) (*ContentInfo, error) {
	return &ContentInfo{
		Type:    contentType,
		Content: asn1.RawValue{Bytes: content},
	}, nil
}

func newRecipients(rand io.Reader, to []x509.Certificate, encryptionAlgorithm pkix.AlgorithmIdentifier, sessionKey []byte) (*Recipients, error) {
	recipients := Recipients{}
	for _, cert := range to {
		recipient, err := newRecipientInfo(rand, cert, encryptionAlgorithm, sessionKey)
		if err != nil {
			return nil, err
		}
		recipients = append(recipients, *recipient)
	}
	return &recipients, nil
}

func newRawCertificates(certs []x509.Certificate) (*RawCertificates, error) {
	rawData := []byte{}
	for _, cert := range certs {
		rawData = append(rawData, cert.Raw...)
	}

	return &RawCertificates{
		Raw: asn1.RawContent(rawData),
	}, nil

}

func newSignedData(
	digestAlgorithmIdentifiers []pkix.AlgorithmIdentifier,
	contentInfo ContentInfo,
	rawCertificates RawCertificates,
	cRLs []pkix.CertificateList,
	signerInfo SignersInfo,
) (*SignedData, error) {
	return &SignedData{
		DigestAlgorithmIdentifiers: digestAlgorithmIdentifiers,
		ContentInfo:                contentInfo,
		RawCertificates:            rawCertificates,
		CRLs:                       cRLs,
		SignerInfo:                 signerInfo,
	}, nil
}

func newSignerInfo(
	issuerAndSerialNumber IssuerAndSerialNumber,
	digestAlgorithm pkix.AlgorithmIdentifier,
	authenticatedAttributes Attributes,
	signatureAlgorithm pkix.AlgorithmIdentifier,
	digestSignature []byte,
	unauthenticatedAttributes Attributes,
) (*SignerInfo, error) {
	return &SignerInfo{
		Version:                   1,
		IssuerAndSerialNumber:     issuerAndSerialNumber,
		DigestAlgorithm:           digestAlgorithm,
		AuthenticatedAttributes:   authenticatedAttributes,
		DigestEncryptionAlgorithm: signatureAlgorithm,
		EncryptedDigest:           digestSignature,
		UnauthenticatedAttributes: unauthenticatedAttributes,
	}, nil
}

func signAttributes(rand io.Reader, attributes AttributeSet, hash crypto.Hash, signer crypto.Signer, opts crypto.SignerOpts) ([]byte, error) {
	data, err := asn1.Marshal(attributes)
	if err != nil {
		return nil, err
	}
	var raw asn1.RawValue
	asn1.Unmarshal(data, &raw)

	hasher := hash.New()
	hasher.Write(raw.Bytes)
	return hasher.Sum(nil), nil
}

func Sign(rand io.Reader, contentInfo ContentInfo, cert x509.Certificate, signer crypto.Signer, opts crypto.SignerOpts) (*ContentInfo, error) {
	signatureAlgorithm := oidSignatureAlgorithmRSA
	hashingAlgorithm := oidDigestAlgorithmSHA256

	issuerAndSerialNumber, err := newIssuerAndSerialNumber(cert)
	if err != nil {
		return nil, err
	}

	hash, err := getHashByOID(hashingAlgorithm)
	if err != nil {
		return nil, err
	}

	var rawValue asn1.RawValue
	_, err = asn1.Unmarshal(contentInfo.Content.Bytes, &rawValue)
	if err != nil {
		return nil, err
	}

	hasher := hash.New()
	hasher.Write(rawValue.Bytes)
	hashBytes := hasher.Sum(nil)

	marshaledHashBytes, err := asn1.Marshal(hashBytes)
	if err != nil {
		return nil, err
	}

	authenticatedAttributes := Attributes{
		Attribute{
			Type: oidAttributeMessageDigest,
			Value: asn1.RawValue{
				IsCompound: true,
				Tag:        17,
				Bytes:      marshaledHashBytes,
			},
		},
	}
	unauthenticatedAttributes := Attributes{}

	attributeHashSignature, err := signAttributes(rand, AttributeSet{Attributes: authenticatedAttributes}, hash, signer, opts)
	if err != nil {
		return nil, err
	}

	signerInfo, err := newSignerInfo(
		*issuerAndSerialNumber,
		pkix.AlgorithmIdentifier{Algorithm: hashingAlgorithm},
		authenticatedAttributes,
		pkix.AlgorithmIdentifier{Algorithm: signatureAlgorithm},
		attributeHashSignature,
		unauthenticatedAttributes,
	)
	if err != nil {
		return nil, err
	}

	certificates, err := newRawCertificates([]x509.Certificate{cert})
	if err != nil {
		return nil, err
	}

	signedData, err := newSignedData(
		[]pkix.AlgorithmIdentifier{
			pkix.AlgorithmIdentifier{
				Algorithm: hashingAlgorithm,
			},
		},
		contentInfo,
		*certificates,
		[]pkix.CertificateList{},
		SignersInfo{*signerInfo},
	)
	if err != nil {
		return nil, err
	}

	signedDataBytes, err := asn1.Marshal(*signedData)
	if err != nil {
		return nil, err
	}

	return newContentInfo(oidSignedData, signedDataBytes)
}

//
func Encrypt(rand io.Reader, to []x509.Certificate, plaintext []byte) (*ContentInfo, error) {
	// sessionKey and IV are tied to AES 256; change this to read the BlockSize
	// and friends.
	sessionKey, err := readRand(rand, 32)
	if err != nil {
		return nil, err
	}
	iv, err := readRand(rand, 16)
	if err != nil {
		return nil, err
	}

	algorithm := pkix.AlgorithmIdentifier{
		Algorithm:  oidEncryptionAES256CBC,
		Parameters: asn1.RawValue{Bytes: iv},
	}

	block, err := getBlockCipherByOID(algorithm.Algorithm, sessionKey)
	if err != nil {
		return nil, err
	}

	plaintext, err = Pad(plaintext, uint(block.BlockSize()))
	if err != nil {
		return nil, err
	}

	// this assumes CBC, which is hard coded above in a few places too
	blockMode := cipher.NewCBCEncrypter(block, iv)

	encryptedBytes := make([]byte, len(plaintext))
	blockMode.CryptBlocks(encryptedBytes, plaintext)

	encryptedContentInfo, err := newEncryptedContentInfo(oidData, algorithm, encryptedBytes)
	if err != nil {
		return nil, err
	}

	recipients, err := newRecipients(rand, to, algorithm, sessionKey)
	if err != nil {
		return nil, err
	}

	envelopedData, err := newEnvelopedData(*recipients, *encryptedContentInfo)
	if err != nil {
		return nil, err
	}

	envelopedDataBytes, err := asn1.Marshal(*envelopedData)
	if err != nil {
		return nil, err
	}

	return newContentInfo(oidEnvelopedData, envelopedDataBytes)
}

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

package pkcs7

import (
	"fmt"
	"io"

	"encoding/asn1"

	"crypto"
	"crypto/cipher"
	"crypto/x509"
	"crypto/x509/pkix"

	"pault.ag/go/pkcs7/utils"
)

func readRand(rand io.Reader, size int) ([]byte, error) {
	data := make([]byte, size)
	n, err := io.ReadFull(rand, data)
	if err != nil {
		return nil, err
	}
	if n != size {
		return nil, fmt.Errorf("pkcs7: not enough calming entropy")
	}
	return data, nil
}

func newIssuerAndSerialNumber(cert x509.Certificate) (*IssuerAndSerialNumber, error) {
	return &IssuerAndSerialNumber{
		Issuer: asn1.RawValue{FullBytes: cert.RawIssuer},
		Serial: cert.SerialNumber,
	}, nil
}

func newRecipientInfo(rand io.Reader, cert x509.Certificate, algorithm pkix.AlgorithmIdentifier, key []byte) (*RecipientInfo, error) {
	issuerAndSerial, err := newIssuerAndSerialNumber(cert)
	if err != nil {
		return nil, err
	}

	encryptedKey, err := utils.Encrypt(rand, cert, key, nil)
	if err != nil {
		return nil, err
	}

	return &RecipientInfo{
		IssuerAndSerialNumber:  *issuerAndSerial,
		KeyEncryptionAlgorithm: algorithm,
		EncryptedKey:           encryptedKey,
	}, nil
}

func newEncryptedContentInfo(encryptedContentType asn1.ObjectIdentifier, algorithm pkix.AlgorithmIdentifier, content []byte) (*EncryptedContentInfo, error) {
	return &EncryptedContentInfo{
		Type:      encryptedContentType,
		Algorithm: algorithm,
		Content:   asn1.RawValue{Bytes: content},
	}, nil
}

func newEnvelopedData(r Recipients, eci EncryptedContentInfo) (*EnvelopedData, error) {
	return &EnvelopedData{
		Version:              0,
		Recipients:           r,
		EncryptedContentInfo: eci,
	}, nil

}

func newContentInfo(contentType asn1.ObjectIdentifier, content []byte) (*ContentInfo, error) {
	return &ContentInfo{
		Type:    contentType,
		Content: asn1.RawValue{Bytes: content},
	}, nil
}

func newRecipients(rand io.Reader, to []x509.Certificate, encryptionAlgorithm pkix.AlgorithmIdentifier, sessionKey []byte) (*Recipients, error) {
	recipients := Recipients{}
	for _, cert := range to {
		recipient, err := newRecipientInfo(rand, cert, encryptionAlgorithm, sessionKey)
		if err != nil {
			return nil, err
		}
		recipients = append(recipients, *recipient)
	}
	return &recipients, nil
}

func newRawCertificates(certs []x509.Certificate) (*RawCertificates, error) {
	rawData := []byte{}
	for _, cert := range certs {
		rawData = append(rawData, cert.Raw...)
	}

	return &RawCertificates{
		Raw: asn1.RawContent(rawData),
	}, nil

}

func newSignedData(
	digestAlgorithmIdentifiers []pkix.AlgorithmIdentifier,
	contentInfo ContentInfo,
	rawCertificates RawCertificates,
	cRLs []pkix.CertificateList,
	signerInfo SignersInfo,
) (*SignedData, error) {
	return &SignedData{
		DigestAlgorithmIdentifiers: digestAlgorithmIdentifiers,
		ContentInfo:                contentInfo,
		RawCertificates:            rawCertificates,
		CRLs:                       cRLs,
		SignerInfo:                 signerInfo,
	}, nil
}

func newSignerInfo(
	issuerAndSerialNumber IssuerAndSerialNumber,
	digestAlgorithm pkix.AlgorithmIdentifier,
	authenticatedAttributes Attributes,
	signatureAlgorithm pkix.AlgorithmIdentifier,
	digestSignature []byte,
	unauthenticatedAttributes Attributes,
) (*SignerInfo, error) {
	return &SignerInfo{
		Version:                   1,
		IssuerAndSerialNumber:     issuerAndSerialNumber,
		DigestAlgorithm:           digestAlgorithm,
		AuthenticatedAttributes:   authenticatedAttributes,
		DigestEncryptionAlgorithm: signatureAlgorithm,
		EncryptedDigest:           digestSignature,
		UnauthenticatedAttributes: unauthenticatedAttributes,
	}, nil
}

func signAttributes(rand io.Reader, attributes AttributeSet, hash crypto.Hash, signer crypto.Signer, opts crypto.SignerOpts) ([]byte, error) {
	data, err := asn1.Marshal(attributes)
	if err != nil {
		return nil, err
	}
	var raw asn1.RawValue
	asn1.Unmarshal(data, &raw)

	hasher := hash.New()
	hasher.Write(raw.Bytes)

	return signer.Sign(rand, hasher.Sum(nil), opts)
}

func Sign(rand io.Reader, contentInfo ContentInfo, cert x509.Certificate, signer crypto.Signer, opts crypto.SignerOpts) (*ContentInfo, error) {
	signatureAlgorithm := oidSignatureAlgorithmRSA
	hashingAlgorithm := oidDigestAlgorithmSHA256

	issuerAndSerialNumber, err := newIssuerAndSerialNumber(cert)
	if err != nil {
		return nil, err
	}

	hash, err := getHashByOID(hashingAlgorithm)
	if err != nil {
		return nil, err
	}

	var rawValue asn1.RawValue
	_, err = asn1.Unmarshal(contentInfo.Content.Bytes, &rawValue)
	if err != nil {
		return nil, err
	}

	hasher := hash.New()
	hasher.Write(rawValue.Bytes)
	hashBytes := hasher.Sum(nil)

	marshaledHashBytes, err := asn1.Marshal(hashBytes)
	if err != nil {
		return nil, err
	}

	authenticatedAttributes := Attributes{
		Attribute{
			Type: oidAttributeMessageDigest,
			Value: asn1.RawValue{
				IsCompound: true,
				Tag:        17,
				Bytes:      marshaledHashBytes,
			},
		},
	}
	unauthenticatedAttributes := Attributes{}

	attributeHashSignature, err := signAttributes(
		rand,
		AttributeSet{Attributes: authenticatedAttributes},
		hash,
		signer,
		opts,
	)
	if err != nil {
		return nil, err
	}

	signerInfo, err := newSignerInfo(
		*issuerAndSerialNumber,
		pkix.AlgorithmIdentifier{Algorithm: hashingAlgorithm},
		authenticatedAttributes,
		pkix.AlgorithmIdentifier{Algorithm: signatureAlgorithm},
		attributeHashSignature,
		unauthenticatedAttributes,
	)
	if err != nil {
		return nil, err
	}

	certificates, err := newRawCertificates([]x509.Certificate{cert})
	if err != nil {
		return nil, err
	}

	signedData, err := newSignedData(
		[]pkix.AlgorithmIdentifier{
			pkix.AlgorithmIdentifier{
				Algorithm: hashingAlgorithm,
			},
		},
		contentInfo,
		*certificates,
		[]pkix.CertificateList{},
		SignersInfo{*signerInfo},
	)
	if err != nil {
		return nil, err
	}

	signedDataBytes, err := asn1.Marshal(*signedData)
	if err != nil {
		return nil, err
	}

	return newContentInfo(oidSignedData, signedDataBytes)
}

//
func Encrypt(rand io.Reader, to []x509.Certificate, plaintext []byte) (*ContentInfo, error) {
	// sessionKey and IV are tied to AES 256; change this to read the BlockSize
	// and friends.
	sessionKey, err := readRand(rand, 32)
	if err != nil {
		return nil, err
	}
	iv, err := readRand(rand, 16)
	if err != nil {
		return nil, err
	}

	algorithm := pkix.AlgorithmIdentifier{
		Algorithm:  oidEncryptionAES256CBC,
		Parameters: asn1.RawValue{Bytes: iv},
	}

	block, err := getBlockCipherByOID(algorithm.Algorithm, sessionKey)
	if err != nil {
		return nil, err
	}

	plaintext, err = Pad(plaintext, uint(block.BlockSize()))
	if err != nil {
		return nil, err
	}

	// this assumes CBC, which is hard coded above in a few places too
	blockMode := cipher.NewCBCEncrypter(block, iv)

	encryptedBytes := make([]byte, len(plaintext))
	blockMode.CryptBlocks(encryptedBytes, plaintext)

	encryptedContentInfo, err := newEncryptedContentInfo(oidData, algorithm, encryptedBytes)
	if err != nil {
		return nil, err
	}

	recipients, err := newRecipients(rand, to, algorithm, sessionKey)
	if err != nil {
		return nil, err
	}

	envelopedData, err := newEnvelopedData(*recipients, *encryptedContentInfo)
	if err != nil {
		return nil, err
	}

	envelopedDataBytes, err := asn1.Marshal(*envelopedData)
	if err != nil {
		return nil, err
	}

	return newContentInfo(oidEnvelopedData, envelopedDataBytes)
}

// vim: foldmethod=marker
<|endoftext|>


<commit_before>package veneur

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/url"
	"os"
	"sync"

	"github.com/Sirupsen/logrus"
	flock "github.com/theckman/go-flock"
)

// ResolveAddr takes a URL-style listen address specification,
// resolves it and returns a net.Addr that corresponds to the
// string. If any error (in URL decoding, destructuring or resolving)
// occurs, ResolveAddr returns the respective error.
//
// Valid address examples are:
//   udp6://127.0.0.1:8000
//   unix:///tmp/foo.sock
//   tcp://127.0.0.1:9002
func ResolveAddr(str string) (net.Addr, error) {
	u, err := url.Parse(str)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "unix", "unixgram", "unixpacket":
		addr, err := net.ResolveUnixAddr(u.Scheme, u.Path)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "tcp6", "tcp4", "tcp":
		addr, err := net.ResolveTCPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "udp6", "udp4", "udp":
		addr, err := net.ResolveUDPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	}
	return nil, fmt.Errorf("unknown address family %q on address %q", u.Scheme, u.String())
}

// StartStatsd spawns a goroutine that listens for metrics in statsd
// format on the address a. As this is a setup routine, if any error
// occurs, it panics.
func StartStatsd(s *Server, a net.Addr, packetPool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startStatsdUDP(s, addr, packetPool)
	case *net.TCPAddr:
		startStatsdTCP(s, addr, packetPool)
	default:
		panic(fmt.Sprintf("Can't listen on %v: only TCP and UDP are supported", a))
	}
}

func startStatsdUDP(s *Server, addr *net.UDPAddr, packetPool *sync.Pool) {
	for i := 0; i < s.numReaders; i++ {
		go func() {
			defer func() {
				ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
			}()
			// each goroutine gets its own socket
			// if the sockets support SO_REUSEPORT, then this will cause the
			// kernel to distribute datagrams across them, for better read
			// performance
			sock, err := NewSocket(addr, s.RcvbufBytes, s.numReaders != 1)
			if err != nil {
				// if any goroutine fails to create the socket, we can't really
				// recover, so we just blow up
				// this probably indicates a systemic issue, eg lack of
				// SO_REUSEPORT support
				panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
			}
			log.WithField("address", addr).Info("Listening for statsd metrics on UDP socket")
			s.ReadMetricSocket(sock, packetPool)
		}()
	}
}

func startStatsdTCP(s *Server, addr *net.TCPAddr, packetPool *sync.Pool) {
	var listener net.Listener
	var err error

	listener, err = net.ListenTCP("tcp", addr)
	if err != nil {
		panic(fmt.Sprintf("couldn't listen on TCP socket %v: %v", addr, err))
	}

	go func() {
		<-s.shutdown
		// TODO: the socket is in use until there are no goroutines blocked in Accept
		// we should wait until the accepting goroutine exits
		err := listener.Close()
		if err != nil {
			log.WithError(err).Warn("Ignoring error closing TCP listener")
		}
	}()

	mode := "unencrypted"
	if s.tlsConfig != nil {
		// wrap the listener with TLS
		listener = tls.NewListener(listener, s.tlsConfig)
		if s.tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
			mode = "authenticated"
		} else {
			mode = "encrypted"
		}
	}

	log.WithFields(logrus.Fields{
		"address": addr, "mode": mode,
	}).Info("Listening for statsd metrics on TCP socket")

	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadTCPSocket(listener)
	}()
}

func StartSSF(s *Server, a net.Addr, tracePool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startSSFUDP(s, addr, tracePool)
	case *net.UnixAddr:
		startSSFUnix(s, addr)
	default:
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// & unix:// are supported", a))
	}
	log.WithFields(logrus.Fields{
		"address": a.String(),
		"network": a.Network(),
	}).Info("Listening for SSF traces")
}

func startSSFUDP(s *Server, addr *net.UDPAddr, tracePool *sync.Pool) {
	// if we want to use multiple readers, make reuseport a parameter, like ReadMetricSocket.
	listener, err := NewSocket(addr, s.RcvbufBytes, false)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
	}
	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadSSFPacketSocket(listener, tracePool)
	}()
}

func startSSFUnix(s *Server, addr *net.UnixAddr) <-chan struct{} {
	done := make(chan struct{})
	if addr.Network() != "unix" {
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// and unix:// addresses are supported", addr))
	}
	// ensure we are the only ones locking this socket:
	lockname := fmt.Sprintf("%s.lock", addr.String())
	lock := flock.NewFlock(lockname)
	locked, err := lock.TryLock()
	if err != nil {
		panic(fmt.Sprintf("Could not acquire the lock %q to listen on %v: %v", lockname, addr, err))
	}
	if !locked {
		panic(fmt.Sprintf("Lock file %q for %v is in use by another process already", lockname, addr))
	}
	// We have the exclusive use of the socket, clear away any old sockets and listen:
	_ = os.Remove(addr.String())
	listener, err := net.ListenUnix(addr.Network(), addr)
	if err != nil {
		panic(fmt.Sprintf("Couldn't listen on UNIX socket %v: %v", addr, err))
	}
	go func() {
		conns := make(chan net.Conn)
		go func() {
			defer lock.Unlock()
			defer close(done)

			conn, err := listener.AcceptUnix()
			if err != nil {
				select {
				case <-s.shutdown:
					// occurs when cleanly shutting down the server e.g. in tests; ignore errors
					log.WithError(err).Info("Ignoring Accept error while shutting down")
					return
				default:
					log.WithError(err).Fatal("Unix accept failed")
				}
			}
			conns <- conn
		}()
		for {
			select {
			case conn := <-conns:
				go s.ReadSSFStreamSocket(conn)
			case <-s.shutdown:
				listener.Close()
				return
			}
		}
	}()
	return done
}
<commit_msg>Add docs for startSSFUnix<commit_after>package veneur

import (
	"crypto/tls"
	"fmt"
	"net"
	"net/url"
	"os"
	"sync"

	"github.com/Sirupsen/logrus"
	flock "github.com/theckman/go-flock"
)

// ResolveAddr takes a URL-style listen address specification,
// resolves it and returns a net.Addr that corresponds to the
// string. If any error (in URL decoding, destructuring or resolving)
// occurs, ResolveAddr returns the respective error.
//
// Valid address examples are:
//   udp6://127.0.0.1:8000
//   unix:///tmp/foo.sock
//   tcp://127.0.0.1:9002
func ResolveAddr(str string) (net.Addr, error) {
	u, err := url.Parse(str)
	if err != nil {
		return nil, err
	}
	switch u.Scheme {
	case "unix", "unixgram", "unixpacket":
		addr, err := net.ResolveUnixAddr(u.Scheme, u.Path)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "tcp6", "tcp4", "tcp":
		addr, err := net.ResolveTCPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	case "udp6", "udp4", "udp":
		addr, err := net.ResolveUDPAddr(u.Scheme, u.Host)
		if err != nil {
			return nil, err
		}
		return addr, nil
	}
	return nil, fmt.Errorf("unknown address family %q on address %q", u.Scheme, u.String())
}

// StartStatsd spawns a goroutine that listens for metrics in statsd
// format on the address a. As this is a setup routine, if any error
// occurs, it panics.
func StartStatsd(s *Server, a net.Addr, packetPool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startStatsdUDP(s, addr, packetPool)
	case *net.TCPAddr:
		startStatsdTCP(s, addr, packetPool)
	default:
		panic(fmt.Sprintf("Can't listen on %v: only TCP and UDP are supported", a))
	}
}

func startStatsdUDP(s *Server, addr *net.UDPAddr, packetPool *sync.Pool) {
	for i := 0; i < s.numReaders; i++ {
		go func() {
			defer func() {
				ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
			}()
			// each goroutine gets its own socket
			// if the sockets support SO_REUSEPORT, then this will cause the
			// kernel to distribute datagrams across them, for better read
			// performance
			sock, err := NewSocket(addr, s.RcvbufBytes, s.numReaders != 1)
			if err != nil {
				// if any goroutine fails to create the socket, we can't really
				// recover, so we just blow up
				// this probably indicates a systemic issue, eg lack of
				// SO_REUSEPORT support
				panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
			}
			log.WithField("address", addr).Info("Listening for statsd metrics on UDP socket")
			s.ReadMetricSocket(sock, packetPool)
		}()
	}
}

func startStatsdTCP(s *Server, addr *net.TCPAddr, packetPool *sync.Pool) {
	var listener net.Listener
	var err error

	listener, err = net.ListenTCP("tcp", addr)
	if err != nil {
		panic(fmt.Sprintf("couldn't listen on TCP socket %v: %v", addr, err))
	}

	go func() {
		<-s.shutdown
		// TODO: the socket is in use until there are no goroutines blocked in Accept
		// we should wait until the accepting goroutine exits
		err := listener.Close()
		if err != nil {
			log.WithError(err).Warn("Ignoring error closing TCP listener")
		}
	}()

	mode := "unencrypted"
	if s.tlsConfig != nil {
		// wrap the listener with TLS
		listener = tls.NewListener(listener, s.tlsConfig)
		if s.tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert {
			mode = "authenticated"
		} else {
			mode = "encrypted"
		}
	}

	log.WithFields(logrus.Fields{
		"address": addr, "mode": mode,
	}).Info("Listening for statsd metrics on TCP socket")

	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadTCPSocket(listener)
	}()
}

func StartSSF(s *Server, a net.Addr, tracePool *sync.Pool) {
	switch addr := a.(type) {
	case *net.UDPAddr:
		startSSFUDP(s, addr, tracePool)
	case *net.UnixAddr:
		startSSFUnix(s, addr)
	default:
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// & unix:// are supported", a))
	}
	log.WithFields(logrus.Fields{
		"address": a.String(),
		"network": a.Network(),
	}).Info("Listening for SSF traces")
}

func startSSFUDP(s *Server, addr *net.UDPAddr, tracePool *sync.Pool) {
	// if we want to use multiple readers, make reuseport a parameter, like ReadMetricSocket.
	listener, err := NewSocket(addr, s.RcvbufBytes, false)
	if err != nil {
		// if any goroutine fails to create the socket, we can't really
		// recover, so we just blow up
		// this probably indicates a systemic issue, eg lack of
		// SO_REUSEPORT support
		panic(fmt.Sprintf("couldn't listen on UDP socket %v: %v", addr, err))
	}
	go func() {
		defer func() {
			ConsumePanic(s.Sentry, s.Statsd, s.Hostname, recover())
		}()
		s.ReadSSFPacketSocket(listener, tracePool)
	}()
}

// startSSFUnix starts listening for connections that send framed SSF
// spans on a UNIX domain socket address. It does so until the
// server's shutdown socket is closed. startSSFUnix returns a channel
// that is closed once the listener has terminated.
func startSSFUnix(s *Server, addr *net.UnixAddr) <-chan struct{} {
	done := make(chan struct{})
	if addr.Network() != "unix" {
		panic(fmt.Sprintf("Can't listen for SSF on %v: only udp:// and unix:// addresses are supported", addr))
	}
	// ensure we are the only ones locking this socket:
	lockname := fmt.Sprintf("%s.lock", addr.String())
	lock := flock.NewFlock(lockname)
	locked, err := lock.TryLock()
	if err != nil {
		panic(fmt.Sprintf("Could not acquire the lock %q to listen on %v: %v", lockname, addr, err))
	}
	if !locked {
		panic(fmt.Sprintf("Lock file %q for %v is in use by another process already", lockname, addr))
	}
	// We have the exclusive use of the socket, clear away any old sockets and listen:
	_ = os.Remove(addr.String())
	listener, err := net.ListenUnix(addr.Network(), addr)
	if err != nil {
		panic(fmt.Sprintf("Couldn't listen on UNIX socket %v: %v", addr, err))
	}
	go func() {
		conns := make(chan net.Conn)
		go func() {
			defer lock.Unlock()
			defer close(done)

			conn, err := listener.AcceptUnix()
			if err != nil {
				select {
				case <-s.shutdown:
					// occurs when cleanly shutting down the server e.g. in tests; ignore errors
					log.WithError(err).Info("Ignoring Accept error while shutting down")
					return
				default:
					log.WithError(err).Fatal("Unix accept failed")
				}
			}
			conns <- conn
		}()
		for {
			select {
			case conn := <-conns:
				go s.ReadSSFStreamSocket(conn)
			case <-s.shutdown:
				listener.Close()
				return
			}
		}
	}()
	return done
}
<|endoftext|>


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

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

const (
	minimumImageSize int64 = 4096 //kB
)

type Updater interface {
	GetScheduledUpdate(server string, deviceID string) (interface{}, error)
	FetchUpdate(url string) (io.ReadCloser, int64, error)
}

type UpdateClient struct {
	client       *http.Client
	minImageSize int64
}

func NewUpdateClient(conf httpsClientConfig) (*UpdateClient, error) {
	client, err := NewHttpClient(conf)
	if client == nil {
		return nil, errors.Wrap(err, "failed to create updater HTTP client")
	}

	up := UpdateClient{
		client:       client,
		minImageSize: minimumImageSize,
	}
	return &up, nil
}

func (u *UpdateClient) GetScheduledUpdate(server string, deviceID string) (interface{}, error) {
	return u.getUpdateInfo(processUpdateResponse, buildURL(server), deviceID)
}

func (u *UpdateClient) getUpdateInfo(process RequestProcessingFunc, server string,
	deviceID string) (interface{}, error) {
	req, err := makeUpdateCheckRequest(server, deviceID)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create update check request")
	}

	r, err := u.client.Do(req)
	if err != nil {
		log.Debug("Sending request error: ", err)
		return nil, errors.Wrapf(err, "update check request failed")
	}

	defer r.Body.Close()

	return process(r)
}

// Returns a byte stream which is a download of the given link.
func (u *UpdateClient) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	req, err := makeUpdateFetchRequest(url)
	if err != nil {
		return nil, -1, errors.Wrapf(err, "failed to create update fetch request")
	}

	r, err := u.client.Do(req)
	if err != nil {
		log.Error("Can not fetch update image: ", err)
		return nil, -1, errors.Wrapf(err, "update fetch request failed")
	}

	log.Debugf("Received fetch update response %v+", r)

	if r.StatusCode != http.StatusOK {
		log.Errorf("Error fetching shcheduled update info: code (%d)", r.StatusCode)
		return nil, -1, errors.New("Error receiving scheduled update information.")
	}

	if r.ContentLength < 0 {
		return nil, -1, errors.New("Will not continue with unknown image size.")
	} else if r.ContentLength < u.minImageSize {
		log.Errorf("Image smaller than expected. Expected: %d, received: %d", u.minImageSize, r.ContentLength)
		return nil, -1, errors.New("Image size is smaller than expected. Aborting.")
	}

	return r.Body, r.ContentLength, nil
}

// possible API responses received for update request
const (
	updateResponseHaveUpdate = 200
	updateResponseNoUpdates  = 204
	updateResponseError      = 404
)

// have update for the client
type UpdateResponse struct {
	Image struct {
		URI      string
		Checksum string
		YoctoID  string `json:"yocto_id"`
		ID       string
	}
	ID string
}

func validateGetUpdate(update UpdateResponse) error {
	// check if we have JSON data correctky decoded
	if update.ID != "" && update.Image.ID != "" &&
		update.Image.URI != "" && update.Image.YoctoID != "" {
		log.Info("Correct request for getting image from: " + update.Image.URI)
		return nil
	}
	return errors.New("Missing parameters in encoded JSON response")
}

func processUpdateResponse(response *http.Response) (interface{}, error) {
	log.Debug("Received response:", response.Status)

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

	switch response.StatusCode {
	case updateResponseHaveUpdate:
		log.Debug("Have update available")

		var data UpdateResponse
		if err := json.Unmarshal(respBody, &data); err != nil {
			return nil, errors.Wrapf(err, "failed to parse response")
		}

		if err := validateGetUpdate(data); err != nil {
			return nil, err
		}

		return data, nil

	case updateResponseNoUpdates:
		log.Debug("No update available")
		return nil, nil

	case updateResponseError:
		return nil, errors.New("Client not authorized to get update schedule.")

	default:
		return nil, errors.New("Invalid response received from server")
	}
}

func makeUpdateCheckRequest(server, deviceID string) (*http.Request, error) {
	url := server + "/api/0.0.1/devices/" + deviceID + "/update"
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func makeUpdateFetchRequest(url string) (*http.Request, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	return req, nil
}
<commit_msg>client_update: use API URL build helper<commit_after>// Copyright 2016 Mender Software AS
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
package main

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"

	"github.com/mendersoftware/log"
	"github.com/pkg/errors"
)

const (
	minimumImageSize int64 = 4096 //kB
)

type Updater interface {
	GetScheduledUpdate(server string, deviceID string) (interface{}, error)
	FetchUpdate(url string) (io.ReadCloser, int64, error)
}

type UpdateClient struct {
	client       *http.Client
	minImageSize int64
}

func NewUpdateClient(conf httpsClientConfig) (*UpdateClient, error) {
	client, err := NewHttpClient(conf)
	if client == nil {
		return nil, errors.Wrap(err, "failed to create updater HTTP client")
	}

	up := UpdateClient{
		client:       client,
		minImageSize: minimumImageSize,
	}
	return &up, nil
}

func (u *UpdateClient) GetScheduledUpdate(server string, deviceID string) (interface{}, error) {
	return u.getUpdateInfo(processUpdateResponse, server, deviceID)
}

func (u *UpdateClient) getUpdateInfo(process RequestProcessingFunc, server string,
	deviceID string) (interface{}, error) {
	req, err := makeUpdateCheckRequest(server, deviceID)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to create update check request")
	}

	r, err := u.client.Do(req)
	if err != nil {
		log.Debug("Sending request error: ", err)
		return nil, errors.Wrapf(err, "update check request failed")
	}

	defer r.Body.Close()

	return process(r)
}

// Returns a byte stream which is a download of the given link.
func (u *UpdateClient) FetchUpdate(url string) (io.ReadCloser, int64, error) {
	req, err := makeUpdateFetchRequest(url)
	if err != nil {
		return nil, -1, errors.Wrapf(err, "failed to create update fetch request")
	}

	r, err := u.client.Do(req)
	if err != nil {
		log.Error("Can not fetch update image: ", err)
		return nil, -1, errors.Wrapf(err, "update fetch request failed")
	}

	log.Debugf("Received fetch update response %v+", r)

	if r.StatusCode != http.StatusOK {
		log.Errorf("Error fetching shcheduled update info: code (%d)", r.StatusCode)
		return nil, -1, errors.New("Error receiving scheduled update information.")
	}

	if r.ContentLength < 0 {
		return nil, -1, errors.New("Will not continue with unknown image size.")
	} else if r.ContentLength < u.minImageSize {
		log.Errorf("Image smaller than expected. Expected: %d, received: %d", u.minImageSize, r.ContentLength)
		return nil, -1, errors.New("Image size is smaller than expected. Aborting.")
	}

	return r.Body, r.ContentLength, nil
}

// possible API responses received for update request
const (
	updateResponseHaveUpdate = 200
	updateResponseNoUpdates  = 204
	updateResponseError      = 404
)

// have update for the client
type UpdateResponse struct {
	Image struct {
		URI      string
		Checksum string
		YoctoID  string `json:"yocto_id"`
		ID       string
	}
	ID string
}

func validateGetUpdate(update UpdateResponse) error {
	// check if we have JSON data correctky decoded
	if update.ID != "" && update.Image.ID != "" &&
		update.Image.URI != "" && update.Image.YoctoID != "" {
		log.Info("Correct request for getting image from: " + update.Image.URI)
		return nil
	}
	return errors.New("Missing parameters in encoded JSON response")
}

func processUpdateResponse(response *http.Response) (interface{}, error) {
	log.Debug("Received response:", response.Status)

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

	switch response.StatusCode {
	case updateResponseHaveUpdate:
		log.Debug("Have update available")

		var data UpdateResponse
		if err := json.Unmarshal(respBody, &data); err != nil {
			return nil, errors.Wrapf(err, "failed to parse response")
		}

		if err := validateGetUpdate(data); err != nil {
			return nil, err
		}

		return data, nil

	case updateResponseNoUpdates:
		log.Debug("No update available")
		return nil, nil

	case updateResponseError:
		return nil, errors.New("Client not authorized to get update schedule.")

	default:
		return nil, errors.New("Invalid response received from server")
	}
}

func makeUpdateCheckRequest(server, deviceID string) (*http.Request, error) {
	url := buildApiURL(server, "/devices/"+deviceID+"/update")
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	return req, nil
}

func makeUpdateFetchRequest(url string) (*http.Request, error) {
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return nil, err
	}
	return req, nil
}
<|endoftext|>


<commit_before>package clix

import (
	"fmt"
	"net/http"
	"net/http/pprof"
	"time"

	"github.com/urfave/cli"
)

var ProfilerServer = &http.Server{
	ReadTimeout:  time.Minute,
	WriteTimeout: time.Minute,
}

func RunProfiler(c *cli.Context) {
	runProfiler(c)
}

func runProfiler(c Ctx) {
	if !c.Bool(FlagProfiler) {
		return
	}

	ProfilerServer.Handler = makeProfilerMux()
	ProfilerServer.Addr = fmt.Sprintf(":%s", c.String(FlagProfilerPort))

	go func() {
		err := ProfilerServer.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			panic(err)
		}
	}()
}

func makeProfilerMux() http.Handler {
	mux := &http.ServeMux{}

	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)

	return mux
}
<commit_msg>Added a missing return value (error) (#14)<commit_after>package clix

import (
	"fmt"
	"net/http"
	"net/http/pprof"
	"time"

	"github.com/urfave/cli"
)

var ProfilerServer = &http.Server{
	ReadTimeout:  time.Minute,
	WriteTimeout: time.Minute,
}

func RunProfiler(c *cli.Context) error {
	runProfiler(c)
	return nil
}

func runProfiler(c Ctx) {
	if !c.Bool(FlagProfiler) {
		return
	}

	ProfilerServer.Handler = makeProfilerMux()
	ProfilerServer.Addr = fmt.Sprintf(":%s", c.String(FlagProfilerPort))

	go func() {
		err := ProfilerServer.ListenAndServe()
		if err != nil && err != http.ErrServerClosed {
			panic(err)
		}
	}()
}

func makeProfilerMux() http.Handler {
	mux := &http.ServeMux{}

	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)

	return mux
}
<|endoftext|>


<commit_before>package s3

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	ss "github.com/aws/aws-sdk-go/service/s3"
	"github.com/pgm/pliant/v2"
	. "gopkg.in/check.v1"
	"io/ioutil"
	"os"
	"testing"
)

type S3Suite struct {
	prefix string
	bucket string

	tempdir string
}

var _ = Suite(&S3Suite{prefix: "test/labels", bucket: "pliantdemo"})
var _ = fmt.Sprintf("hello!")

func Test(t *testing.T) { TestingT(t) }

func (s *S3Suite) SetUpSuite(c *C) {
	accessKey := os.Getenv("AWS_ACCESS_KEY_ID")
	if accessKey == "" {
		c.Skip("AWS_ACCESS_KEY_ID not set, skipping S3")
	}
}

func (s *S3Suite) TearDownTest(c *C) {
	os.RemoveAll(s.tempdir)
}

func (s *S3Suite) SetUpTest(c *C) {
	var err error
	s.tempdir, err = ioutil.TempDir("", "s3test")
	if err != nil {
		panic(err.Error())
	}

	s3c := ss.New(aws.DefaultConfig)
	listObjectsInputs := &ss.ListObjectsInput{Bucket: &s.bucket, Prefix: &s.prefix}
	s3c.ListObjectsPages(listObjectsInputs, func(page *ss.ListObjectsOutput, lastPage bool) (shouldContinue bool) {
		for _, obj := range page.Contents {
			fmt.Printf("Cleaning up test folder: Deleting %s\n", *obj.Key)
			s3c.DeleteObject(&ss.DeleteObjectInput{Bucket: &s.bucket, Key: obj.Key})
		}
		return true
	})
}

func (s *S3Suite) TestSimpleS3ChunkOps(c *C) {
	getDestFn := func() string {
		f, err := ioutil.TempFile(s.tempdir, "dest")
		if err != nil {
			panic(err.Error())
		}
		f.Close()
		return f.Name()
	}

	AccessKey := os.Getenv("AWS_ACCESS_KEY_ID")
	SecretKey := os.Getenv("AWS_SECRET_ACCESS_KEY")

	p := NewS3ChunkService(AccessKey, SecretKey, "s3.amazonaws.com", s.bucket, s.prefix, getDestFn)

	it := p.Iterate()
	c.Assert(!it.HasNext(), Equals, true)

	var testkey v2.Key = ([32]byte{1, 2, 3, 4})

	key := &testkey
	resourceContent := []byte("A")
	resource := v2.NewMemResource(resourceContent)
	p.Put(key, resource)

	fetchedResource := p.Get(key)
	c.Assert(fetchedResource.AsBytes(), DeepEquals, resourceContent)

	it = p.Iterate()
	c.Assert(it.HasNext(), Equals, true)
	nextKey := it.Next()
	c.Assert(!it.HasNext(), Equals, true)
	c.Assert(nextKey, DeepEquals, key)
}
<commit_msg>Fixed package name which appeared for updated aws sdk lib <commit_after>package s3

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"

	"github.com/aws/aws-sdk-go/aws/defaults"
	ss "github.com/aws/aws-sdk-go/service/s3"
	"github.com/pgm/pliant/v2"
	. "gopkg.in/check.v1"
)

type S3Suite struct {
	prefix string
	bucket string

	tempdir string
}

var _ = Suite(&S3Suite{prefix: "test/labels", bucket: "pliantdemo"})
var _ = fmt.Sprintf("hello!")

func Test(t *testing.T) { TestingT(t) }

func (s *S3Suite) SetUpSuite(c *C) {
	accessKey := os.Getenv("AWS_ACCESS_KEY_ID")
	if accessKey == "" {
		c.Skip("AWS_ACCESS_KEY_ID not set, skipping S3")
	}
}

func (s *S3Suite) TearDownTest(c *C) {
	os.RemoveAll(s.tempdir)
}

func (s *S3Suite) SetUpTest(c *C) {
	var err error
	s.tempdir, err = ioutil.TempDir("", "s3test")
	if err != nil {
		panic(err.Error())
	}

	s3c := ss.New(defaults.DefaultConfig)
	listObjectsInputs := &ss.ListObjectsInput{Bucket: &s.bucket, Prefix: &s.prefix}
	s3c.ListObjectsPages(listObjectsInputs, func(page *ss.ListObjectsOutput, lastPage bool) (shouldContinue bool) {
		for _, obj := range page.Contents {
			fmt.Printf("Cleaning up test folder: Deleting %s\n", *obj.Key)
			s3c.DeleteObject(&ss.DeleteObjectInput{Bucket: &s.bucket, Key: obj.Key})
		}
		return true
	})
}

func (s *S3Suite) TestSimpleS3ChunkOps(c *C) {
	getDestFn := func() string {
		f, err := ioutil.TempFile(s.tempdir, "dest")
		if err != nil {
			panic(err.Error())
		}
		f.Close()
		return f.Name()
	}

	AccessKey := os.Getenv("AWS_ACCESS_KEY_ID")
	SecretKey := os.Getenv("AWS_SECRET_ACCESS_KEY")

	p := NewS3ChunkService(AccessKey, SecretKey, "s3.amazonaws.com", s.bucket, s.prefix, getDestFn)

	it := p.Iterate()
	c.Assert(!it.HasNext(), Equals, true)

	var testkey v2.Key = ([32]byte{1, 2, 3, 4})

	key := &testkey
	resourceContent := []byte("A")
	resource := v2.NewMemResource(resourceContent)
	p.Put(key, resource)

	fetchedResource := p.Get(key)
	c.Assert(fetchedResource.AsBytes(), DeepEquals, resourceContent)

	it = p.Iterate()
	c.Assert(it.HasNext(), Equals, true)
	nextKey := it.Next()
	c.Assert(!it.HasNext(), Equals, true)
	c.Assert(nextKey, DeepEquals, key)
}
<|endoftext|>