<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package netext

import (
	"net"
	"net/http/httptrace"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
)

// A Trail represents detailed information about an HTTP request.
// You'd typically get one from a Tracer.
type Trail struct {
	StartTime time.Time
	EndTime   time.Time

	// Total request duration, excluding DNS lookup and connect time.
	Duration time.Duration

	Blocked    time.Duration // Waiting to acquire a connection.
	LookingUp  time.Duration // Looking up DNS records.
	Connecting time.Duration // Connecting to remote host.
	Sending    time.Duration // Writing request.
	Waiting    time.Duration // Waiting for first byte.
	Receiving  time.Duration // Receiving response.

	// Detailed connection information.
	ConnReused     bool
	ConnRemoteAddr net.Addr

	// Bandwidth usage.
	BytesRead, BytesWritten int64
}

func (tr Trail) Samples(tags map[string]string) []stats.Sample {
	return []stats.Sample{
		{Metric: metrics.HTTPReqs, Time: tr.EndTime, Tags: tags, Value: 1},
		{Metric: metrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Duration)},
		{Metric: metrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Blocked)},
		{Metric: metrics.HTTPReqLookingUp, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.LookingUp)},
		{Metric: metrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Connecting)},
		{Metric: metrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Sending)},
		{Metric: metrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Waiting)},
		{Metric: metrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Receiving)},
		{Metric: metrics.DataReceived, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesRead)},
		{Metric: metrics.DataSent, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesWritten)},
	}
}

// A Tracer wraps "net/http/httptrace" to collect granular timings for HTTP requests.
// Note that since there is not yet an event for the end of a request (there's a PR to
// add it), you must call Done() at the end of the request to get the full timings.
// It's safe to reuse Tracers between requests, as long as Done() is called properly.
// Cheers, love, the cavalry's here.
type Tracer struct {
	getConn              time.Time
	gotConn              time.Time
	gotFirstResponseByte time.Time
	dnsStart             time.Time
	dnsDone              time.Time
	connectStart         time.Time
	connectDone          time.Time
	wroteRequest         time.Time

	connReused     bool
	connRemoteAddr net.Addr

	protoError error

	bytesRead, bytesWritten int64
}

// Trace() returns a premade ClientTrace that calls all of the Tracer's hooks.
func (t *Tracer) Trace() *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GetConn:              t.GetConn,
		GotConn:              t.GotConn,
		GotFirstResponseByte: t.GotFirstResponseByte,
		DNSStart:             t.DNSStart,
		DNSDone:              t.DNSDone,
		ConnectStart:         t.ConnectStart,
		ConnectDone:          t.ConnectDone,
		WroteRequest:         t.WroteRequest,
	}
}

// Call when the request is finished. Calculates metrics and resets the tracer.
func (t *Tracer) Done() Trail {
	done := time.Now()

	// Cover for if the server closed the connection without a response.
	if t.gotFirstResponseByte.IsZero() {
		t.gotFirstResponseByte = done
	}

	// GotConn is not guaranteed to be called in all cases.
	if t.gotConn.IsZero() {
		t.gotConn = t.getConn
	}

	trail := Trail{
		Blocked:    t.gotConn.Sub(t.getConn),
		LookingUp:  t.dnsDone.Sub(t.dnsStart),
		Connecting: t.connectDone.Sub(t.connectStart),
		Sending:    t.wroteRequest.Sub(t.connectDone),
		Waiting:    t.gotFirstResponseByte.Sub(t.wroteRequest),
		Receiving:  done.Sub(t.gotFirstResponseByte),

		ConnReused:     t.connReused,
		ConnRemoteAddr: t.connRemoteAddr,

		BytesRead:    t.bytesRead,
		BytesWritten: t.bytesWritten,
	}

	// If the connection was reused, it never blocked.
	if t.connReused {
		trail.Blocked = 0
		trail.LookingUp = 0
		trail.Connecting = 0
	}

	// If the connection failed, we'll never get any (meaningful) data for these.
	if t.protoError != nil {
		trail.Sending = 0
		trail.Waiting = 0
		trail.Receiving = 0

		// URL is invalid/unroutable.
		if trail.Blocked < 0 {
			trail.Blocked = 0
		}
	}

	// Calculate total times using adjusted values.
	trail.EndTime = done
	trail.Duration = trail.Blocked + trail.LookingUp + trail.Connecting + trail.Sending + trail.Waiting + trail.Receiving
	trail.StartTime = trail.EndTime.Add(-trail.Duration)

	if trail.StartTime.IsZero() {
		panic("no start time")
	}
	if trail.EndTime.IsZero() {
		panic("no end time")
	}
	if trail.Blocked < 0 {
		panic("impossible block time")
	}
	if trail.LookingUp < 0 {
		panic("impossible lookup time")
	}
	if trail.Connecting < 0 {
		panic("impossible connection time")
	}
	if trail.Sending < 0 {
		panic("impossible send time")
	}
	if trail.Waiting < 0 {
		panic("impossible wait time")
	}
	if trail.Receiving < 0 {
		panic("impossible read time time")
	}
	if trail.Duration < 0 {
		panic("impossible duration")
	}
	if trail.BytesRead < 0 {
		panic("impossible read bytes")
	}
	if trail.BytesWritten < 0 {
		panic("impossible written bytes")
	}

	*t = Tracer{}
	return trail
}

// GetConn event hook.
func (t *Tracer) GetConn(hostPort string) {
	t.getConn = time.Now()
}

// GotConn event hook.
func (t *Tracer) GotConn(info httptrace.GotConnInfo) {
	t.gotConn = time.Now()
	t.connReused = info.Reused
	t.connRemoteAddr = info.Conn.RemoteAddr()

	if t.connReused {
		t.connectStart = t.gotConn
		t.connectDone = t.gotConn

		// If the connection was reused, patch it to use this tracer's data counters.
		if conn, ok := info.Conn.(*Conn); ok {
			conn.BytesRead = &t.bytesRead
			conn.BytesWritten = &t.bytesWritten
		}
	}
}

// GotFirstResponseByte hook.
func (t *Tracer) GotFirstResponseByte() {
	t.gotFirstResponseByte = time.Now()
}

// DNSStart hook.
func (t *Tracer) DNSStart(info httptrace.DNSStartInfo) {
	t.dnsStart = time.Now()
	t.dnsDone = t.dnsStart
}

// DNSDone hook.
func (t *Tracer) DNSDone(info httptrace.DNSDoneInfo) {
	t.dnsDone = time.Now()
	if t.dnsStart.IsZero() {
		t.dnsStart = t.dnsDone
	}
	if info.Err != nil {
		t.protoError = info.Err
	}
}

// ConnectStart hook.
func (t *Tracer) ConnectStart(network, addr string) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectStart.IsZero() {
		return
	}
	t.connectStart = time.Now()
}

// ConnectDone hook.
func (t *Tracer) ConnectDone(network, addr string, err error) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectDone.IsZero() {
		return
	}

	t.connectDone = time.Now()
	if t.gotConn.IsZero() {
		t.gotConn = t.connectDone
	}

	if err != nil {
		t.protoError = err
	}
}

// WroteRequest hook.
func (t *Tracer) WroteRequest(info httptrace.WroteRequestInfo) {
	t.wroteRequest = time.Now()
	if info.Err != nil {
		t.protoError = info.Err
	}
}
<commit_msg>Dropping the panics, they now only happen on cancelled contexts<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package netext

import (
	"net"
	"net/http/httptrace"
	"time"

	"github.com/loadimpact/k6/lib/metrics"
	"github.com/loadimpact/k6/stats"
)

// A Trail represents detailed information about an HTTP request.
// You'd typically get one from a Tracer.
type Trail struct {
	StartTime time.Time
	EndTime   time.Time

	// Total request duration, excluding DNS lookup and connect time.
	Duration time.Duration

	Blocked    time.Duration // Waiting to acquire a connection.
	LookingUp  time.Duration // Looking up DNS records.
	Connecting time.Duration // Connecting to remote host.
	Sending    time.Duration // Writing request.
	Waiting    time.Duration // Waiting for first byte.
	Receiving  time.Duration // Receiving response.

	// Detailed connection information.
	ConnReused     bool
	ConnRemoteAddr net.Addr

	// Bandwidth usage.
	BytesRead, BytesWritten int64
}

func (tr Trail) Samples(tags map[string]string) []stats.Sample {
	return []stats.Sample{
		{Metric: metrics.HTTPReqs, Time: tr.EndTime, Tags: tags, Value: 1},
		{Metric: metrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Duration)},
		{Metric: metrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Blocked)},
		{Metric: metrics.HTTPReqLookingUp, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.LookingUp)},
		{Metric: metrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Connecting)},
		{Metric: metrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Sending)},
		{Metric: metrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Waiting)},
		{Metric: metrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Receiving)},
		{Metric: metrics.DataReceived, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesRead)},
		{Metric: metrics.DataSent, Time: tr.EndTime, Tags: tags, Value: float64(tr.BytesWritten)},
	}
}

// A Tracer wraps "net/http/httptrace" to collect granular timings for HTTP requests.
// Note that since there is not yet an event for the end of a request (there's a PR to
// add it), you must call Done() at the end of the request to get the full timings.
// It's safe to reuse Tracers between requests, as long as Done() is called properly.
// Cheers, love, the cavalry's here.
type Tracer struct {
	getConn              time.Time
	gotConn              time.Time
	gotFirstResponseByte time.Time
	dnsStart             time.Time
	dnsDone              time.Time
	connectStart         time.Time
	connectDone          time.Time
	wroteRequest         time.Time

	connReused     bool
	connRemoteAddr net.Addr

	protoError error

	bytesRead, bytesWritten int64
}

// Trace() returns a premade ClientTrace that calls all of the Tracer's hooks.
func (t *Tracer) Trace() *httptrace.ClientTrace {
	return &httptrace.ClientTrace{
		GetConn:              t.GetConn,
		GotConn:              t.GotConn,
		GotFirstResponseByte: t.GotFirstResponseByte,
		DNSStart:             t.DNSStart,
		DNSDone:              t.DNSDone,
		ConnectStart:         t.ConnectStart,
		ConnectDone:          t.ConnectDone,
		WroteRequest:         t.WroteRequest,
	}
}

// Call when the request is finished. Calculates metrics and resets the tracer.
func (t *Tracer) Done() Trail {
	done := time.Now()

	// Cover for if the server closed the connection without a response.
	if t.gotFirstResponseByte.IsZero() {
		t.gotFirstResponseByte = done
	}

	// GotConn is not guaranteed to be called in all cases.
	if t.gotConn.IsZero() {
		t.gotConn = t.getConn
	}

	trail := Trail{
		Blocked:    t.gotConn.Sub(t.getConn),
		LookingUp:  t.dnsDone.Sub(t.dnsStart),
		Connecting: t.connectDone.Sub(t.connectStart),
		Sending:    t.wroteRequest.Sub(t.connectDone),
		Waiting:    t.gotFirstResponseByte.Sub(t.wroteRequest),
		Receiving:  done.Sub(t.gotFirstResponseByte),

		ConnReused:     t.connReused,
		ConnRemoteAddr: t.connRemoteAddr,

		BytesRead:    t.bytesRead,
		BytesWritten: t.bytesWritten,
	}

	// If the connection was reused, it never blocked.
	if t.connReused {
		trail.Blocked = 0
		trail.LookingUp = 0
		trail.Connecting = 0
	}

	// If the connection failed, we'll never get any (meaningful) data for these.
	if t.protoError != nil {
		trail.Sending = 0
		trail.Waiting = 0
		trail.Receiving = 0

		// URL is invalid/unroutable.
		if trail.Blocked < 0 {
			trail.Blocked = 0
		}
	}

	// Calculate total times using adjusted values.
	trail.EndTime = done
	trail.Duration = trail.Blocked + trail.LookingUp + trail.Connecting + trail.Sending + trail.Waiting + trail.Receiving
	trail.StartTime = trail.EndTime.Add(-trail.Duration)

	*t = Tracer{}
	return trail
}

// GetConn event hook.
func (t *Tracer) GetConn(hostPort string) {
	t.getConn = time.Now()
}

// GotConn event hook.
func (t *Tracer) GotConn(info httptrace.GotConnInfo) {
	t.gotConn = time.Now()
	t.connReused = info.Reused
	t.connRemoteAddr = info.Conn.RemoteAddr()

	if t.connReused {
		t.connectStart = t.gotConn
		t.connectDone = t.gotConn

		// If the connection was reused, patch it to use this tracer's data counters.
		if conn, ok := info.Conn.(*Conn); ok {
			conn.BytesRead = &t.bytesRead
			conn.BytesWritten = &t.bytesWritten
		}
	}
}

// GotFirstResponseByte hook.
func (t *Tracer) GotFirstResponseByte() {
	t.gotFirstResponseByte = time.Now()
}

// DNSStart hook.
func (t *Tracer) DNSStart(info httptrace.DNSStartInfo) {
	t.dnsStart = time.Now()
	t.dnsDone = t.dnsStart
}

// DNSDone hook.
func (t *Tracer) DNSDone(info httptrace.DNSDoneInfo) {
	t.dnsDone = time.Now()
	if t.dnsStart.IsZero() {
		t.dnsStart = t.dnsDone
	}
	if info.Err != nil {
		t.protoError = info.Err
	}
}

// ConnectStart hook.
func (t *Tracer) ConnectStart(network, addr string) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectStart.IsZero() {
		return
	}
	t.connectStart = time.Now()
}

// ConnectDone hook.
func (t *Tracer) ConnectDone(network, addr string, err error) {
	// If using dual-stack dialing, it's possible to get this multiple times.
	if !t.connectDone.IsZero() {
		return
	}

	t.connectDone = time.Now()
	if t.gotConn.IsZero() {
		t.gotConn = t.connectDone
	}

	if err != nil {
		t.protoError = err
	}
}

// WroteRequest hook.
func (t *Tracer) WroteRequest(info httptrace.WroteRequestInfo) {
	t.wroteRequest = time.Now()
	if info.Err != nil {
		t.protoError = info.Err
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"encoding/json"
	"fmt"
	"unicode"
	"strings"
	"log"
)

var (
	tmpgostructs map[string]GoStruct
	gostructs map[string]GoStruct
)

type Models struct {
	JSON interface{} `json:"models"`
}

type Field struct {
	Name string
	Type string
	JSONName string
}
type GoStruct struct {
	Name string
	Fields []Field
	SubTypes []string
	Parent string
}
func Canonicalize(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	for index, _ := range a {
		if index == 0 {
			a[0] = unicode.ToUpper(a[0])
			continue
		}
		if a[index-1] == '_' {
			a[index] = unicode.ToUpper(a[index])
		}
		if a[index] == 'I' && a[index+1] == 'd' {
			a[index+1] = unicode.ToUpper(a[index+1])
		}
	}
	return string(a)
}

func ParseModels(m map[string]interface{}) {
	for key, value := range m {
		s := GoStruct{Name: key, Parent: ""}
		v := value.(map[string]interface{})
		tmpgostructs[key] = BuildStruct(s, v)
	}
	for _, t := range tmpgostructs {
		for _, st := range t.SubTypes {
			sub := tmpgostructs[st]
			sub.Parent = t.Name
			tmpgostructs[st] = sub
		}
	}
	for ParentsExist() {
		ProcessSubTypes()
	}
	for _, t := range tmpgostructs {
		gostructs[t.Name] = t
	}
}

func ParentsExist() bool {
	for _, t := range tmpgostructs {
		if t.Parent != "" {
			return true
		}
	}
	return false
}

func ProcessSubTypes() {
	for _, t := range tmpgostructs {
		if t.Parent == "" {
			for _, subtype := range t.SubTypes {
				st := tmpgostructs[subtype]
				parent := tmpgostructs[st.Parent]
				for _, f := range parent.Fields {
					st.Fields = append(st.Fields, f)
				}
				st.Parent = ""
				tmpgostructs[subtype] = st
			}
			gostructs[t.Name] = t
			delete(tmpgostructs, t.Name)
		}
	}
}
func BuildStruct(s GoStruct, m map[string]interface{}) GoStruct {
	for key, value := range m {
		switch value.(type) {
		case string:
			continue
		case []interface{}:
			switch key {
			case "subTypes":
				v := value.([]interface{})
				s.SubTypes = BuildSubTypes(v)
			}
		case interface{}:
			v := value.(map[string]interface{})
			switch key {
			case "properties":
				s.Fields = BuildFields(v)
			}
		}
	}
	return s
}

func BuildSubTypes(st []interface{}) []string {
	subtypes := make([]string, 0, 50)
	for _, value := range st {
		subtypes = append(subtypes, value.(string))
	}
	return subtypes
}

func BuildFields(m map[string]interface{}) []Field {
	fields := make([]Field, 0, 5)
	for key, value := range m {
		f := Field{Name: Canonicalize(key)}
		v := value.(map[string]interface{})
		f = BuildField(f, v)
		f.JSONName = key
		fields = append(fields, f)
	}
	return fields
}
func BuildField(f Field, m map[string]interface{}) Field {
	for key, value := range m {
		switch key {
		case "type":
			var typestring string
			v := value.(string)
			if strings.HasPrefix(v, "List[") {
				typestring = strings.TrimPrefix(v, "List[")
				typestring = strings.TrimSuffix(typestring, "]")
				typestring = strings.Join([]string{"[]", typestring}, "")
			} else if v == "object" {
				typestring = "string"
			} else if v == "long" {
				typestring = "uint64"
			} else if v == "double" {
				typestring = "float64"
			} else if v == "Date" {
				typestring = "string"
			} else if v== "boolean" {
				typestring = "bool"
			} else {
				typestring = v
			}
			f.Type = typestring
		}
	}
	return f
}

func OutputStructs() {
	for _, s := range gostructs {
		fmt.Printf("type %s struct {\n", s.Name)
		for _, field := range s.Fields {
			fmt.Printf("	%s %s `json:\"%s\"`\n", field.Name, field.Type, field.JSONName)
		}
		fmt.Println("}\n")
	}
}

func BuildConstructors() {
	for _, s := range gostructs {
		fmt.Printf("func New%s() interface{} {\n", s.Name)
		fmt.Printf("	return %s{}\n", s.Name)
		fmt.Printf("}\n\n")
	}
}

func BuildVar() {
	fmt.Printf("var (\n")
	fmt.Printf("	NewStruct map[string]func() interface{}\n")
	fmt.Printf(")\n\n")
}
func BuildInit() {
	fmt.Printf("func init() {\n")
	fmt.Printf("NewStruct = make(map[string]func() interface{})\n")
	for _, s := range gostructs {
		fmt.Printf("	NewStruct[\"%s\"] = New%s\n", s.Name, s.Name)
	}
	fmt.Printf("}\n\n")
}

func init() {
	gostructs = make(map[string]GoStruct)
	tmpgostructs = make(map[string]GoStruct)
}
func main() {
	modeldir := flag.String("models", "", "Path to model files")
	flag.Parse()
	files, err := ioutil.ReadDir(*modeldir)
	if err != nil {
		log.Fatal(err)
	}
	for _, modelfile := range files {
		if !modelfile.IsDir() {
			modelpath := strings.Join([]string{*modeldir, modelfile.Name()}, "/")
			modelstring, err := ioutil.ReadFile(modelpath)
			if err != nil {
				continue
			}
			var m Models
			json.Unmarshal(modelstring, &m)
			ParseModels(m.JSON.(map[string]interface{}))
		}
	}

	fmt.Println("package nv\n")
	BuildConstructors()
	BuildVar()
	BuildInit()
	OutputStructs()
}<commit_msg>Initial work to prep for API generation<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strings"
	"unicode"
)

var (
	tmpgostructs map[string]GoStruct
	gostructs    map[string]GoStruct
)

type Swagger struct {
	APIVersion string      `json:"apiVersion"`
	BasePath   string      `json:"basePath"`
	APIs       []API       `json:"apis"`
	Models     interface{} `json:"models"`
}

type API struct {
	Path        string      `json:"path"`
	Description string      `json:"description"`
	Operations  []Operation `json:"operations"`
}

type Operation struct {
	HTTPMethod    string      `json:"httpMethod"`
	Summary       string      `json:"summary"`
	Notes         string      `json:"notes"`
	Nickname      string      `json:"nickname"`
	ResponseClass string      `json:"responseClass"`
	Parameters    []Parameter `json:"parameters"`
}

type Parameter struct {
	Name          string `json:"name"`
	Description   string `json:"description"`
	ParamType     string `json:"paramType"`
	Required      bool   `json:"required"`
	AllowMultiple bool   `json:"allowMultiple"`
	Datatype      string `json:"dataType"`
}

type Models struct {
	JSON interface{} `json:"models"`
}

type Field struct {
	Name     string
	Type     string
	JSONName string
}
type GoStruct struct {
	Name     string
	Fields   []Field
	SubTypes []string
	Parent   string
}

func Canonicalize(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	for index, _ := range a {
		if index == 0 {
			a[0] = unicode.ToUpper(a[0])
			continue
		}
		if a[index-1] == '_' {
			a[index] = unicode.ToUpper(a[index])
		}
		if a[index] == 'I' && a[index+1] == 'd' {
			a[index+1] = unicode.ToUpper(a[index+1])
		}
	}
	return string(a)
}

func ParseModels(m map[string]interface{}) {
	for key, value := range m {
		s := GoStruct{Name: key, Parent: ""}
		v := value.(map[string]interface{})
		tmpgostructs[key] = BuildStruct(s, v)
	}
	for _, t := range tmpgostructs {
		for _, st := range t.SubTypes {
			sub := tmpgostructs[st]
			sub.Parent = t.Name
			tmpgostructs[st] = sub
		}
	}
	for ParentsExist() {
		ProcessSubTypes()
	}
	for _, t := range tmpgostructs {
		gostructs[t.Name] = t
	}
}

func ParentsExist() bool {
	for _, t := range tmpgostructs {
		if t.Parent != "" {
			return true
		}
	}
	return false
}

func ProcessSubTypes() {
	for _, t := range tmpgostructs {
		if t.Parent == "" {
			for _, subtype := range t.SubTypes {
				st := tmpgostructs[subtype]
				parent := tmpgostructs[st.Parent]
				for _, f := range parent.Fields {
					st.Fields = append(st.Fields, f)
				}
				st.Parent = ""
				tmpgostructs[subtype] = st
			}
			gostructs[t.Name] = t
			delete(tmpgostructs, t.Name)
		}
	}
}
func BuildStruct(s GoStruct, m map[string]interface{}) GoStruct {
	for key, value := range m {
		switch value.(type) {
		case string:
			continue
		case []interface{}:
			switch key {
			case "subTypes":
				v := value.([]interface{})
				s.SubTypes = BuildSubTypes(v)
			}
		case interface{}:
			v := value.(map[string]interface{})
			switch key {
			case "properties":
				s.Fields = BuildFields(v)
			}
		}
	}
	return s
}

func BuildSubTypes(st []interface{}) []string {
	subtypes := make([]string, 0, 50)
	for _, value := range st {
		subtypes = append(subtypes, value.(string))
	}
	return subtypes
}

func BuildFields(m map[string]interface{}) []Field {
	fields := make([]Field, 0, 5)
	for key, value := range m {
		f := Field{Name: Canonicalize(key)}
		v := value.(map[string]interface{})
		f = BuildField(f, v)
		f.JSONName = key
		fields = append(fields, f)
	}
	return fields
}
func BuildField(f Field, m map[string]interface{}) Field {
	for key, value := range m {
		switch key {
		case "type":
			var typestring string
			v := value.(string)
			if strings.HasPrefix(v, "List[") {
				typestring = strings.TrimPrefix(v, "List[")
				typestring = strings.TrimSuffix(typestring, "]")
				typestring = strings.Join([]string{"[]", typestring}, "")
			} else if v == "object" {
				typestring = "string"
			} else if v == "long" {
				typestring = "uint64"
			} else if v == "double" {
				typestring = "float64"
			} else if v == "Date" {
				typestring = "string"
			} else if v == "boolean" {
				typestring = "bool"
			} else {
				typestring = v
			}
			f.Type = typestring
		}
	}
	return f
}

func OutputStructs() {
	for _, s := range gostructs {
		fmt.Printf("type %s struct {\n", s.Name)
		for _, field := range s.Fields {
			fmt.Printf("	%s %s `json:\"%s\"`\n", field.Name, field.Type, field.JSONName)
		}
		fmt.Println("}\n")
	}
}

func BuildConstructors() {
	for _, s := range gostructs {
		fmt.Printf("func New%s() interface{} {\n", s.Name)
		fmt.Printf("	return %s{}\n", s.Name)
		fmt.Printf("}\n\n")
	}
}

func BuildVar() {
	fmt.Printf("var (\n")
	fmt.Printf("	NewStruct map[string]func() interface{}\n")
	fmt.Printf(")\n\n")
}
func BuildInit() {
	fmt.Printf("func init() {\n")
	fmt.Printf("NewStruct = make(map[string]func() interface{})\n")
	for _, s := range gostructs {
		fmt.Printf("	NewStruct[\"%s\"] = New%s\n", s.Name, s.Name)
	}
	fmt.Printf("}\n\n")
}

func init() {
	gostructs = make(map[string]GoStruct)
	tmpgostructs = make(map[string]GoStruct)
}
func main() {
	swaggerdir := flag.String("path", "", "Path to model files")
	buildStructs := flag.Bool("structs", true, "Whether or not to build structs")
	buildAPI := flag.Bool("api", true, "Whether or not to build the API")
	flag.Parse()
	files, err := ioutil.ReadDir(*swaggerdir)
	if err != nil {
		log.Fatal(err)
	}
	for _, swaggerfile := range files {
		if !swaggerfile.IsDir() {
			swaggerpath := strings.Join([]string{*swaggerdir, swaggerfile.Name()}, "/")
			swaggerstring, err := ioutil.ReadFile(swaggerpath)
			if err != nil {
				continue
			}
			//fmt.Println(string(swaggerstring))
			var s Swagger
			json.Unmarshal(swaggerstring, &s)
			ParseModels(s.Models.(map[string]interface{}))
		}
	}

	fmt.Println("package nv\n")
	if *buildStructs {
		BuildConstructors()
		BuildVar()
		BuildInit()
		OutputStructs()
	}

	if *buildAPI {
		fmt.Println("API stuff here\n")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Google Inc. All rights reserved.
//
// 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 mixnet

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/jlmucb/cloudproxy/go/tao"
)

// RouterContext stores the runtime environment for a Tao-delegated router.
type RouterContext struct {
	keys           *tao.Keys    // Signing keys of this hosted program.
	domain         *tao.Domain  // Policy guard and public key.
	proxyListener  net.Listener // Socket where server listens for proxies.
	routerListener net.Listener // Socket where server listens for proxies.

	// Data structures for queueing and batching messages from sender to
	// recipient and recipient to sender respectively.
	sendQueue  *Queue
	replyQueue *Queue

	conns map[string]*Conn
	exit  map[uint64]bool

	// The queues and error handlers are instantiated as go routines; these
	// channels are for tearing them down.
	killQueue             chan bool
	killQueueErrorHandler chan bool

	network string        // Network protocol, e.g. "tcp"
	timeout time.Duration // Timeout on read/write/dial.

	errs chan error
}

// NewRouterContext generates new keys, loads a local domain configuration from
// path and binds an anonymous listener socket to addr using network protocol.
// It also creates a regular listener socket for other routers to connect to.
// A delegation is requested from the Tao t which is  nominally
// the parent of this hosted program.
func NewRouterContext(path, network, addr1, addr2 string, batchSize int, timeout time.Duration,
	x509Identity *pkix.Name, t tao.Tao) (hp *RouterContext, err error) {

	hp = new(RouterContext)
	hp.network = network
	hp.timeout = timeout

	hp.conns = make(map[string]*Conn)
	hp.exit = make(map[uint64]bool)
	hp.errs = make(chan error)

	// Generate keys and get attestation from parent.
	if hp.keys, err = tao.NewTemporaryTaoDelegatedKeys(tao.Signing|tao.Crypting, t); err != nil {
		return nil, err
	}

	// Create a certificate.
	if hp.keys.Cert, err = hp.keys.SigningKey.CreateSelfSignedX509(x509Identity); err != nil {
		return nil, err
	}

	// Load domain from local configuration.
	if hp.domain, err = tao.LoadDomain(path, nil); err != nil {
		return nil, err
	}

	// Encode TLS certificate.
	cert, err := tao.EncodeTLSCert(hp.keys)
	if err != nil {
		return nil, err
	}

	tlsConfigProxy := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*cert},
		InsecureSkipVerify: true,
	}

	tlsConfigRouter := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*cert},
		InsecureSkipVerify: true,
	}

	// Bind address to socket.
	if hp.proxyListener, err = tao.ListenAnonymous(network, addr1, tlsConfigProxy,
		hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys.Delegation); err != nil {
		return nil, err
	}

	// Different listener, since mixes should be authenticated
	if hp.routerListener, err = tao.Listen(network, addr2, tlsConfigRouter,
		hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys.Delegation); err != nil {
		return nil, err
	}

	// Instantiate the queues.
	hp.sendQueue = NewQueue(network, batchSize, timeout)
	hp.replyQueue = NewQueue(network, batchSize, timeout)
	hp.killQueue = make(chan bool)
	hp.killQueueErrorHandler = make(chan bool)
	go hp.sendQueue.DoQueue(hp.killQueue)
	go hp.replyQueue.DoQueue(hp.killQueue)
	go hp.sendQueue.DoQueueErrorHandler(hp.replyQueue, hp.killQueueErrorHandler)
	go hp.replyQueue.DoQueueErrorHandlerLog("reply queue", hp.killQueueErrorHandler)

	return hp, nil
}

// AcceptProxy Waits for connectons from proxies.
func (hp *RouterContext) AcceptProxy() (*Conn, error) {
	c, err := hp.proxyListener.Accept()
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	go hp.handleConn(conn)
	return conn, nil
}

// AcceptRouter Waits for connectons from other routers.
func (hp *RouterContext) AcceptRouter() (*Conn, error) {
	c, err := hp.routerListener.Accept()
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	go hp.handleConn(conn)
	return conn, nil
}

// DialRouter connects to a remote Tao-delegated mixnet router.
func (hp *RouterContext) DialRouter(network, addr string) (*Conn, error) {
	c, err := tao.Dial(network, addr, hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys)
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	hp.conns[addr] = conn
	return conn, nil
}

// Close releases any resources held by the hosted program.
func (hp *RouterContext) Close() {
	hp.killQueue <- true
	hp.killQueue <- true
	hp.killQueueErrorHandler <- true
	hp.killQueueErrorHandler <- true
	if hp.proxyListener != nil {
		hp.proxyListener.Close()
	}
	if hp.routerListener != nil {
		hp.routerListener.Close()
	}
	for _, conn := range hp.conns {
		for _, circuit := range conn.circuits {
			close(circuit.cells)
		}
		conn.Close()
	}
}

// Return a random circuit ID
// TODO(kwonalbert): probably won't happen, but should check for duplicates
func (p *RouterContext) newID() (uint64, error) {
	b := make([]byte, 8)
	if _, err := rand.Read(b); err != nil {
		return 0, err
	}
	id, _ := binary.Uvarint(b)
	return id, nil
}

func (hp *RouterContext) HandleErr(c *Conn) {
	err := <-hp.errs
	if err != nil {
		// TODO(kwonalbert) Handle errors properly
	}
}

// handleConn reads a directive or a message from a proxy.
// Handling directives is done here, but actually receiving the messages
// is done in handleCircuit
func (hp *RouterContext) handleConn(c *Conn) {
	for {
		var err error
		cell := make([]byte, CellBytes)
		if _, err = c.Read(cell); err != nil {
			hp.errs <- err
			if err == io.EOF {
				hp.errs <- err
				return
			}
		}

		id := getID(cell)

		hp.replyQueue.SetConn(id, c)
		hp.replyQueue.SetAddr(id, c.RemoteAddr().String())

		if cell[TYPE] == msgCell {
			c.circuits[id].cells <- Cell{cell, err}
		} else if cell[TYPE] == dirCell { // Handle a directive.
			var d Directive
			if err = unmarshalDirective(cell, &d); err != nil {
				hp.errs <- err
				return
			}
			if *d.Type == DirectiveType_ERROR {
				hp.errs <- errors.New("router error: " + (*d.Error))
				return
			}

			if *d.Type == DirectiveType_CREATE {
				// Add next hop for this circuit to sendQueue and send a CREATED
				// directive to sender to inform the sender.
				if len(d.Addrs) == 0 {
					if err = hp.SendError(id, errBadDirective); err != nil {
						hp.errs <- err
					}
					return
				}

				c.circuits[id] = Circuit{make(chan Cell)}
				go hp.handleCircuit(c.circuits[id])

				// Relay the CREATE message
				// Since we assume Tao routers, this router can recreate the message
				// without worrying about security
				hp.sendQueue.SetAddr(id, d.Addrs[0])

				hp.exit[id] = true
				if len(d.Addrs) > 1 {
					var nextConn *Conn
					if _, ok := hp.conns[d.Addrs[0]]; !ok {
						nextConn, err = hp.DialRouter(hp.network, d.Addrs[0])
						if err != nil {
							if e := hp.SendError(id, err); e != nil {
								hp.errs <- e
							}
							return
						}
					} else {
						nextConn = hp.conns[d.Addrs[0]]
					}
					hp.sendQueue.SetConn(id, nextConn)

					dir := &Directive{
						Type:  DirectiveType_CREATE.Enum(),
						Addrs: d.Addrs[1:],
					}
					nextCell, err := marshalDirective(id, dir)
					if err != nil {
						hp.errs <- err
						return
					}

					hp.sendQueue.EnqueueMsg(id, nextCell)
					hp.exit[id] = false
				}

				// Tell the previous hop (proxy or router) it's created
				cell, err = marshalDirective(id, dirCreated)
				if err != nil {
					hp.errs <- err
					return
				}
				hp.replyQueue.EnqueueMsg(id, cell)
			} else if *d.Type == DirectiveType_DESTROY {
				// TODO(cjpatton) when multi-hop circuits are implemented, send
				// a DESTROY directive to the next hop and wait for DESTROYED in
				// response. For now, just close the connection to the circuit.

				// TODO(kwonalbert) Check that this circuit is
				// actually on this conn
				close(c.circuits[id].cells)
				delete(c.circuits, id)

				hp.sendQueue.Close(id, hp.exit[id])
				sid := <-hp.sendQueue.destroyed
				for sid != id {
					sid = <-hp.sendQueue.destroyed
				}

				c.SendDirective(id, dirDestroyed)
				hp.replyQueue.Close(id, len(c.circuits) == 0)

				rid := <-hp.replyQueue.destroyed
				for rid != id {
					rid = <-hp.replyQueue.destroyed
				}

				if len(c.circuits) > 0 {
					hp.errs <- nil
					continue
				} else {
					hp.errs <- io.EOF
					return
				}
			}

		} else { // Unknown cell type, return an error.
			if err = hp.SendError(id, errBadCellType); err != nil {
				hp.errs <- err
				return
			}
		}
		// (kwonalbert) This is done to make testing easier;
		// Easier to count cells by getting the number of errs
		hp.errs <- nil
	}
}

// Handles messages coming in on a circuit.
// The directives are handled in handleConn
func (hp *RouterContext) handleCircuit(circ Circuit) {
	for {
		read, ok := <-circ.cells
		if !ok {
			return
		}
		cell := read.cell
		err := read.err

		if err != nil {
			return
		}

		id := getID(cell)

		// If this router is an exit point, then read cells until the whole
		// message is assembled and add it to sendQueue. If this router is
		// a relay (not implemented), then just add the cell to the
		// sendQueue.
		msgBytes, n := binary.Uvarint(cell[BODY:])
		if msgBytes > MaxMsgBytes {
			if err = hp.SendError(id, errMsgLength); err != nil {
				// TODO(kwonalbert) handle this error
				return
			}
			return
		}

		msg := make([]byte, msgBytes)
		bytes := copy(msg, cell[BODY+n:])

		// While the connection is open and the message is incomplete, read
		// the next cell.
		for err != io.EOF && uint64(bytes) < msgBytes {
			read, ok = <-circ.cells
			if !ok {
				return
			}
			cell = read.cell
			err = read.err
			if err != nil {
				return
			} else if cell[TYPE] != msgCell {
				if err = hp.SendError(id, errCellType); err != nil {
					// TODO(kwonalbert) handle this error
					return
				}
			}
			bytes += copy(msg[bytes:], cell[BODY:])
		}

		// Wait for a message from the destination, divide it into cells,
		// and add the cells to replyQueue.
		reply := make(chan []byte)
		hp.sendQueue.EnqueueMsgReply(id, msg, reply)

		msg = <-reply
		if msg != nil {
			tao.ZeroBytes(cell)
			binary.PutUvarint(cell[ID:], id)
			msgBytes := len(msg)

			cell[TYPE] = msgCell
			n := binary.PutUvarint(cell[BODY:], uint64(msgBytes))
			bytes := copy(cell[BODY+n:], msg)
			hp.replyQueue.EnqueueMsg(id, cell)

			for bytes < msgBytes {
				tao.ZeroBytes(cell)
				binary.PutUvarint(cell[ID:], id)
				cell[TYPE] = msgCell
				bytes += copy(cell[BODY:], msg[bytes:])
				hp.replyQueue.EnqueueMsg(id, cell)
			}
		}
	}
}

// SendError sends an error message to a client.
func (hp *RouterContext) SendError(id uint64, err error) error {
	var d Directive
	d.Type = DirectiveType_ERROR.Enum()
	d.Error = proto.String(err.Error())
	cell, err := marshalDirective(id, &d)
	if err != nil {
		return err
	}
	hp.replyQueue.EnqueueMsg(id, cell)
	return nil
}
<commit_msg>adding comments to the router<commit_after>// Copyright (c) 2015, Google Inc. All rights reserved.
//
// 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 mixnet

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/jlmucb/cloudproxy/go/tao"
)

// RouterContext stores the runtime environment for a Tao-delegated router.
type RouterContext struct {
	keys           *tao.Keys    // Signing keys of this hosted program.
	domain         *tao.Domain  // Policy guard and public key.
	proxyListener  net.Listener // Socket where server listens for proxies.
	routerListener net.Listener // Socket where server listens for proxies.

	// Data structures for queueing and batching messages from sender to
	// recipient and recipient to sender respectively.
	sendQueue  *Queue
	replyQueue *Queue

	// Connections to next hop routers
	conns map[string]*Conn
	// Indicates if this server is an exit or not
	exit map[uint64]bool

	// The queues and error handlers are instantiated as go routines; these
	// channels are for tearing them down.
	killQueue             chan bool
	killQueueErrorHandler chan bool

	network string        // Network protocol, e.g. "tcp"
	timeout time.Duration // Timeout on read/write/dial.

	errs chan error
}

// NewRouterContext generates new keys, loads a local domain configuration from
// path and binds an anonymous listener socket to addr using network protocol.
// It also creates a regular listener socket for other routers to connect to.
// A delegation is requested from the Tao t which is  nominally
// the parent of this hosted program.
func NewRouterContext(path, network, addr1, addr2 string, batchSize int, timeout time.Duration,
	x509Identity *pkix.Name, t tao.Tao) (hp *RouterContext, err error) {

	hp = new(RouterContext)
	hp.network = network
	hp.timeout = timeout

	hp.conns = make(map[string]*Conn)
	hp.exit = make(map[uint64]bool)
	hp.errs = make(chan error)

	// Generate keys and get attestation from parent.
	if hp.keys, err = tao.NewTemporaryTaoDelegatedKeys(tao.Signing|tao.Crypting, t); err != nil {
		return nil, err
	}

	// Create a certificate.
	if hp.keys.Cert, err = hp.keys.SigningKey.CreateSelfSignedX509(x509Identity); err != nil {
		return nil, err
	}

	// Load domain from local configuration.
	if hp.domain, err = tao.LoadDomain(path, nil); err != nil {
		return nil, err
	}

	// Encode TLS certificate.
	cert, err := tao.EncodeTLSCert(hp.keys)
	if err != nil {
		return nil, err
	}

	tlsConfigProxy := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*cert},
		InsecureSkipVerify: true,
	}

	tlsConfigRouter := &tls.Config{
		RootCAs:            x509.NewCertPool(),
		Certificates:       []tls.Certificate{*cert},
		InsecureSkipVerify: true,
	}

	// Bind address to socket.
	if hp.proxyListener, err = tao.ListenAnonymous(network, addr1, tlsConfigProxy,
		hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys.Delegation); err != nil {
		return nil, err
	}

	// Different listener, since mixes should be authenticated
	if hp.routerListener, err = tao.Listen(network, addr2, tlsConfigRouter,
		hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys.Delegation); err != nil {
		return nil, err
	}

	// Instantiate the queues.
	hp.sendQueue = NewQueue(network, batchSize, timeout)
	hp.replyQueue = NewQueue(network, batchSize, timeout)
	hp.killQueue = make(chan bool)
	hp.killQueueErrorHandler = make(chan bool)
	go hp.sendQueue.DoQueue(hp.killQueue)
	go hp.replyQueue.DoQueue(hp.killQueue)
	go hp.sendQueue.DoQueueErrorHandler(hp.replyQueue, hp.killQueueErrorHandler)
	go hp.replyQueue.DoQueueErrorHandlerLog("reply queue", hp.killQueueErrorHandler)

	return hp, nil
}

// AcceptProxy Waits for connectons from proxies.
func (hp *RouterContext) AcceptProxy() (*Conn, error) {
	c, err := hp.proxyListener.Accept()
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	go hp.handleConn(conn)
	return conn, nil
}

// AcceptRouter Waits for connectons from other routers.
func (hp *RouterContext) AcceptRouter() (*Conn, error) {
	c, err := hp.routerListener.Accept()
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	go hp.handleConn(conn)
	return conn, nil
}

// DialRouter connects to a remote Tao-delegated mixnet router.
func (hp *RouterContext) DialRouter(network, addr string) (*Conn, error) {
	c, err := tao.Dial(network, addr, hp.domain.Guard, hp.domain.Keys.VerifyingKey, hp.keys)
	if err != nil {
		return nil, err
	}
	conn := &Conn{c, hp.timeout, make(map[uint64]Circuit)}
	hp.conns[addr] = conn
	return conn, nil
}

// Close releases any resources held by the hosted program.
func (hp *RouterContext) Close() {
	hp.killQueue <- true
	hp.killQueue <- true
	hp.killQueueErrorHandler <- true
	hp.killQueueErrorHandler <- true
	if hp.proxyListener != nil {
		hp.proxyListener.Close()
	}
	if hp.routerListener != nil {
		hp.routerListener.Close()
	}
	for _, conn := range hp.conns {
		for _, circuit := range conn.circuits {
			close(circuit.cells)
		}
		conn.Close()
	}
}

// Return a random circuit ID
// TODO(kwonalbert): probably won't happen, but should check for duplicates
func (p *RouterContext) newID() (uint64, error) {
	b := make([]byte, 8)
	if _, err := rand.Read(b); err != nil {
		return 0, err
	}
	id, _ := binary.Uvarint(b)
	return id, nil
}

// Handle errors internal to the router
// When instantiating a real router (not for testing),
// one start this function as well to handle the errors
func (hp *RouterContext) HandleErr() {
	for {
		err := <-hp.errs
		if err != nil {
			// TODO(kwonalbert) Handle errors properly
		}
	}
}

// handleConn reads a directive or a message from a proxy.
// Handling directives is done here, but actually receiving the messages
// is done in handleCircuit
func (hp *RouterContext) handleConn(c *Conn) {
	for {
		var err error
		cell := make([]byte, CellBytes)
		if _, err = c.Read(cell); err != nil {
			hp.errs <- err
			if err == io.EOF {
				hp.errs <- err
				return
			}
		}

		id := getID(cell)

		hp.replyQueue.SetConn(id, c)
		hp.replyQueue.SetAddr(id, c.RemoteAddr().String())

		if cell[TYPE] == msgCell {
			c.circuits[id].cells <- Cell{cell, err}
		} else if cell[TYPE] == dirCell { // Handle a directive.
			var d Directive
			if err = unmarshalDirective(cell, &d); err != nil {
				hp.errs <- err
				return
			}
			if *d.Type == DirectiveType_ERROR {
				hp.errs <- errors.New("router error: " + (*d.Error))
				return
			}

			if *d.Type == DirectiveType_CREATE {
				// Add next hop for this circuit to sendQueue and send a CREATED
				// directive to sender to inform the sender.
				if len(d.Addrs) == 0 {
					if err = hp.SendError(id, errBadDirective); err != nil {
						hp.errs <- err
					}
					return
				}

				c.circuits[id] = Circuit{make(chan Cell)}
				go hp.handleCircuit(c.circuits[id])

				// Relay the CREATE message
				// Since we assume Tao routers, this router can recreate the message
				// without worrying about security
				hp.sendQueue.SetAddr(id, d.Addrs[0])

				hp.exit[id] = true
				if len(d.Addrs) > 1 {
					var nextConn *Conn
					if _, ok := hp.conns[d.Addrs[0]]; !ok {
						nextConn, err = hp.DialRouter(hp.network, d.Addrs[0])
						if err != nil {
							if e := hp.SendError(id, err); e != nil {
								hp.errs <- e
							}
							return
						}
					} else {
						nextConn = hp.conns[d.Addrs[0]]
					}
					hp.sendQueue.SetConn(id, nextConn)

					dir := &Directive{
						Type:  DirectiveType_CREATE.Enum(),
						Addrs: d.Addrs[1:],
					}
					nextCell, err := marshalDirective(id, dir)
					if err != nil {
						hp.errs <- err
						return
					}

					hp.sendQueue.EnqueueMsg(id, nextCell)
					hp.exit[id] = false
				}

				// Tell the previous hop (proxy or router) it's created
				cell, err = marshalDirective(id, dirCreated)
				if err != nil {
					hp.errs <- err
					return
				}
				hp.replyQueue.EnqueueMsg(id, cell)
			} else if *d.Type == DirectiveType_DESTROY {
				// TODO(cjpatton) when multi-hop circuits are implemented, send
				// a DESTROY directive to the next hop and wait for DESTROYED in
				// response. For now, just close the connection to the circuit.

				// TODO(kwonalbert) Check that this circuit is
				// actually on this conn
				close(c.circuits[id].cells)
				delete(c.circuits, id)

				// Close the connection if you are an exit for this circuit
				// TODO(kwonalbert) Also close the conn if there are no more
				// circuits using this conn
				hp.sendQueue.Close(id, hp.exit[id])
				sid := <-hp.sendQueue.destroyed
				for sid != id {
					sid = <-hp.sendQueue.destroyed
				}

				c.SendDirective(id, dirDestroyed)
				// TODO(kwonalbert) Closing the connection immediately
				// after sending back DESTROYED leaves to a race condition..
				hp.replyQueue.Close(id, len(c.circuits) == 0)

				rid := <-hp.replyQueue.destroyed
				for rid != id {
					rid = <-hp.replyQueue.destroyed
				}

				if len(c.circuits) > 0 {
					hp.errs <- nil
					continue
				} else {
					hp.errs <- io.EOF
					return
				}
			}

		} else { // Unknown cell type, return an error.
			if err = hp.SendError(id, errBadCellType); err != nil {
				hp.errs <- err
				return
			}
		}
		// (kwonalbert) This is done to make testing easier;
		// Easier to count cells by getting the number of errs
		hp.errs <- nil
	}
}

// Handles messages coming in on a circuit.
// The directives are handled in handleConn
func (hp *RouterContext) handleCircuit(circ Circuit) {
	for {
		read, ok := <-circ.cells
		if !ok {
			return
		}
		cell := read.cell
		err := read.err

		if err != nil {
			return
		}

		id := getID(cell)

		// If this router is an exit point, then read cells until the whole
		// message is assembled and add it to sendQueue. If this router is
		// a relay (not implemented), then just add the cell to the
		// sendQueue.
		msgBytes, n := binary.Uvarint(cell[BODY:])
		if msgBytes > MaxMsgBytes {
			if err = hp.SendError(id, errMsgLength); err != nil {
				// TODO(kwonalbert) handle this error
				return
			}
			return
		}

		msg := make([]byte, msgBytes)
		bytes := copy(msg, cell[BODY+n:])

		// While the connection is open and the message is incomplete, read
		// the next cell.
		for err != io.EOF && uint64(bytes) < msgBytes {
			read, ok = <-circ.cells
			if !ok {
				return
			}
			cell = read.cell
			err = read.err
			if err != nil {
				return
			} else if cell[TYPE] != msgCell {
				if err = hp.SendError(id, errCellType); err != nil {
					// TODO(kwonalbert) handle this error
					return
				}
			}
			bytes += copy(msg[bytes:], cell[BODY:])
		}

		// Wait for a message from the destination, divide it into cells,
		// and add the cells to replyQueue.
		reply := make(chan []byte)
		hp.sendQueue.EnqueueMsgReply(id, msg, reply)

		msg = <-reply
		if msg != nil {
			tao.ZeroBytes(cell)
			binary.PutUvarint(cell[ID:], id)
			msgBytes := len(msg)

			cell[TYPE] = msgCell
			n := binary.PutUvarint(cell[BODY:], uint64(msgBytes))
			bytes := copy(cell[BODY+n:], msg)
			hp.replyQueue.EnqueueMsg(id, cell)

			for bytes < msgBytes {
				tao.ZeroBytes(cell)
				binary.PutUvarint(cell[ID:], id)
				cell[TYPE] = msgCell
				bytes += copy(cell[BODY:], msg[bytes:])
				hp.replyQueue.EnqueueMsg(id, cell)
			}
		}
	}
}

// SendError sends an error message to a client.
func (hp *RouterContext) SendError(id uint64, err error) error {
	var d Directive
	d.Type = DirectiveType_ERROR.Enum()
	d.Error = proto.String(err.Error())
	cell, err := marshalDirective(id, &d)
	if err != nil {
		return err
	}
	hp.replyQueue.EnqueueMsg(id, cell)
	return nil
}
<|endoftext|>


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

// Package typeutil defines various utilities for types, such as Map,
// a mapping from types.Type to interface{} values.
package typeutil

import (
	"bytes"
	"fmt"
	"unsafe"

	"code.google.com/p/go.tools/go/types"
)

// Map is a hash-table-based mapping from types (types.Type) to
// arbitrary interface{} values.  The concrete types that implement
// the Type interface are pointers.  Since they are not canonicalized,
// == cannot be used to check for equivalence, and thus we cannot
// simply use a Go map.
//
// Just as with map[K]V, a nil *Map is a valid empty map.
//
// Not thread-safe.
//
type Map struct {
	hasher Hasher             // shared by many Maps
	table  map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
	length int                // number of map entries
}

// entry is an entry (key/value association) in a hash bucket.
type entry struct {
	key   types.Type
	value interface{}
}

// SetHasher sets the hasher used by Map.
//
// All Hashers are functionally equivalent but contain internal state
// used to cache the results of hashing previously seen types.
//
// A single Hasher created by MakeHasher() may be shared among many
// Maps.  This is recommended if the instances have many keys in
// common, as it will amortize the cost of hash computation.
//
// A Hasher may grow without bound as new types are seen.  Even when a
// type is deleted from the map, the Hasher never shrinks, since other
// types in the map may reference the deleted type indirectly.
//
// Hashers are not thread-safe, and read-only operations such as
// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
// read-lock) is require around all Map operations if a shared
// hasher is accessed from multiple threads.
//
// If SetHasher is not called, the Map will create a private hasher at
// the first call to Insert.
//
func (m *Map) SetHasher(hasher Hasher) {
	m.hasher = hasher
}

// Delete removes the entry with the given key, if any.
// It returns true if the entry was found.
//
func (m *Map) Delete(key types.Type) bool {
	if m != nil && m.table != nil {
		hash := m.hasher.Hash(key)
		bucket := m.table[hash]
		for i, e := range bucket {
			if e.key != nil && types.Identical(key, e.key) {
				// We can't compact the bucket as it
				// would disturb iterators.
				bucket[i] = entry{}
				m.length--
				return true
			}
		}
	}
	return false
}

// At returns the map entry for the given key.
// The result is nil if the entry is not present.
//
func (m *Map) At(key types.Type) interface{} {
	if m != nil && m.table != nil {
		for _, e := range m.table[m.hasher.Hash(key)] {
			if e.key != nil && types.Identical(key, e.key) {
				return e.value
			}
		}
	}
	return nil
}

// Set sets the map entry for key to val,
// and returns the previous entry, if any.
func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) {
	if m.table != nil {
		hash := m.hasher.Hash(key)
		bucket := m.table[hash]
		var hole *entry
		for i, e := range bucket {
			if e.key == nil {
				hole = &bucket[i]
			} else if types.Identical(key, e.key) {
				prev = e.value
				bucket[i].value = value
				return
			}
		}

		if hole != nil {
			*hole = entry{key, value} // overwrite deleted entry
		} else {
			m.table[hash] = append(bucket, entry{key, value})
		}
	} else {
		if m.hasher.memo == nil {
			m.hasher = MakeHasher()
		}
		hash := m.hasher.Hash(key)
		m.table = map[uint32][]entry{hash: {entry{key, value}}}
	}

	m.length++
	return
}

// Len returns the number of map entries.
func (m *Map) Len() int {
	if m != nil {
		return m.length
	}
	return 0
}

// Iterate calls function f on each entry in the map in unspecified order.
//
// If f should mutate the map, Iterate provides the same guarantees as
// Go maps: if f deletes a map entry that Iterate has not yet reached,
// f will not be invoked for it, but if f inserts a map entry that
// Iterate has not yet reached, whether or not f will be invoked for
// it is unspecified.
//
func (m *Map) Iterate(f func(key types.Type, value interface{})) {
	if m != nil {
		for _, bucket := range m.table {
			for _, e := range bucket {
				if e.key != nil {
					f(e.key, e.value)
				}
			}
		}
	}
}

// Keys returns a new slice containing the set of map keys.
// The order is unspecified.
func (m *Map) Keys() []types.Type {
	keys := make([]types.Type, 0, m.Len())
	m.Iterate(func(key types.Type, _ interface{}) {
		keys = append(keys, key)
	})
	return keys
}

func (m *Map) toString(values bool) string {
	if m == nil {
		return "{}"
	}
	var buf bytes.Buffer
	fmt.Fprint(&buf, "{")
	sep := ""
	m.Iterate(func(key types.Type, value interface{}) {
		fmt.Fprint(&buf, sep)
		sep = ", "
		fmt.Fprint(&buf, key)
		if values {
			fmt.Fprintf(&buf, ": %q", value)
		}
	})
	fmt.Fprint(&buf, "}")
	return buf.String()
}

// String returns a string representation of the map's entries.
// Values are printed using fmt.Sprintf("%v", v).
// Order is unspecified.
//
func (m *Map) String() string {
	return m.toString(true)
}

// KeysString returns a string representation of the map's key set.
// Order is unspecified.
//
func (m *Map) KeysString() string {
	return m.toString(false)
}

////////////////////////////////////////////////////////////////////////
// Hasher

// A Hasher maps each type to its hash value.
// For efficiency, a hasher uses memoization; thus its memory
// footprint grows monotonically over time.
// Hashers are not thread-safe.
// Hashers have reference semantics.
// Call MakeHasher to create a Hasher.
type Hasher struct {
	memo map[types.Type]uint32
}

// MakeHasher returns a new Hasher instance.
func MakeHasher() Hasher {
	return Hasher{make(map[types.Type]uint32)}
}

// Hash computes a hash value for the given type t such that
// Identical(t, t') => Hash(t) == Hash(t').
func (h Hasher) Hash(t types.Type) uint32 {
	hash, ok := h.memo[t]
	if !ok {
		hash = h.hashFor(t)
		h.memo[t] = hash
	}
	return hash
}

// hashString computes the Fowler–Noll–Vo hash of s.
func hashString(s string) uint32 {
	var h uint32
	for i := 0; i < len(s); i++ {
		h ^= uint32(s[i])
		h *= 16777619
	}
	return h
}

// hashFor computes the hash of t.
func (h Hasher) hashFor(t types.Type) uint32 {
	// See Identical for rationale.
	switch t := t.(type) {
	case *types.Basic:
		return uint32(t.Kind())

	case *types.Array:
		return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())

	case *types.Slice:
		return 9049 + 2*h.Hash(t.Elem())

	case *types.Struct:
		var hash uint32 = 9059
		for i, n := 0, t.NumFields(); i < n; i++ {
			f := t.Field(i)
			if f.Anonymous() {
				hash += 8861
			}
			hash += hashString(t.Tag(i))
			hash += hashString(f.Name()) // (ignore f.Pkg)
			hash += h.Hash(f.Type())
		}
		return hash

	case *types.Pointer:
		return 9067 + 2*h.Hash(t.Elem())

	case *types.Signature:
		var hash uint32 = 9091
		if t.Variadic() {
			hash *= 8863
		}
		return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())

	case *types.Interface:
		var hash uint32 = 9103
		for i, n := 0, t.NumMethods(); i < n; i++ {
			// See go/types.identicalMethods for rationale.
			// Method order is not significant.
			// Ignore m.Pkg().
			m := t.Method(i)
			hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type())
		}
		return hash

	case *types.Map:
		return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())

	case *types.Chan:
		return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())

	case *types.Named:
		// Not safe with a copying GC; objects may move.
		return uint32(uintptr(unsafe.Pointer(t.Obj())))

	case *types.Tuple:
		return h.hashTuple(t)
	}
	panic(t)
}

func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
	// See go/types.identicalTypes for rationale.
	n := tuple.Len()
	var hash uint32 = 9137 + 2*uint32(n)
	for i := 0; i < n; i++ {
		hash += 3 * h.Hash(tuple.At(i).Type())
	}
	return hash
}
<commit_msg>go.tools/go/types/typeutil: use reflect instead of unsafe<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package typeutil defines various utilities for types, such as Map,
// a mapping from types.Type to interface{} values.
package typeutil

import (
	"bytes"
	"fmt"
	"reflect"

	"code.google.com/p/go.tools/go/types"
)

// Map is a hash-table-based mapping from types (types.Type) to
// arbitrary interface{} values.  The concrete types that implement
// the Type interface are pointers.  Since they are not canonicalized,
// == cannot be used to check for equivalence, and thus we cannot
// simply use a Go map.
//
// Just as with map[K]V, a nil *Map is a valid empty map.
//
// Not thread-safe.
//
type Map struct {
	hasher Hasher             // shared by many Maps
	table  map[uint32][]entry // maps hash to bucket; entry.key==nil means unused
	length int                // number of map entries
}

// entry is an entry (key/value association) in a hash bucket.
type entry struct {
	key   types.Type
	value interface{}
}

// SetHasher sets the hasher used by Map.
//
// All Hashers are functionally equivalent but contain internal state
// used to cache the results of hashing previously seen types.
//
// A single Hasher created by MakeHasher() may be shared among many
// Maps.  This is recommended if the instances have many keys in
// common, as it will amortize the cost of hash computation.
//
// A Hasher may grow without bound as new types are seen.  Even when a
// type is deleted from the map, the Hasher never shrinks, since other
// types in the map may reference the deleted type indirectly.
//
// Hashers are not thread-safe, and read-only operations such as
// Map.Lookup require updates to the hasher, so a full Mutex lock (not a
// read-lock) is require around all Map operations if a shared
// hasher is accessed from multiple threads.
//
// If SetHasher is not called, the Map will create a private hasher at
// the first call to Insert.
//
func (m *Map) SetHasher(hasher Hasher) {
	m.hasher = hasher
}

// Delete removes the entry with the given key, if any.
// It returns true if the entry was found.
//
func (m *Map) Delete(key types.Type) bool {
	if m != nil && m.table != nil {
		hash := m.hasher.Hash(key)
		bucket := m.table[hash]
		for i, e := range bucket {
			if e.key != nil && types.Identical(key, e.key) {
				// We can't compact the bucket as it
				// would disturb iterators.
				bucket[i] = entry{}
				m.length--
				return true
			}
		}
	}
	return false
}

// At returns the map entry for the given key.
// The result is nil if the entry is not present.
//
func (m *Map) At(key types.Type) interface{} {
	if m != nil && m.table != nil {
		for _, e := range m.table[m.hasher.Hash(key)] {
			if e.key != nil && types.Identical(key, e.key) {
				return e.value
			}
		}
	}
	return nil
}

// Set sets the map entry for key to val,
// and returns the previous entry, if any.
func (m *Map) Set(key types.Type, value interface{}) (prev interface{}) {
	if m.table != nil {
		hash := m.hasher.Hash(key)
		bucket := m.table[hash]
		var hole *entry
		for i, e := range bucket {
			if e.key == nil {
				hole = &bucket[i]
			} else if types.Identical(key, e.key) {
				prev = e.value
				bucket[i].value = value
				return
			}
		}

		if hole != nil {
			*hole = entry{key, value} // overwrite deleted entry
		} else {
			m.table[hash] = append(bucket, entry{key, value})
		}
	} else {
		if m.hasher.memo == nil {
			m.hasher = MakeHasher()
		}
		hash := m.hasher.Hash(key)
		m.table = map[uint32][]entry{hash: {entry{key, value}}}
	}

	m.length++
	return
}

// Len returns the number of map entries.
func (m *Map) Len() int {
	if m != nil {
		return m.length
	}
	return 0
}

// Iterate calls function f on each entry in the map in unspecified order.
//
// If f should mutate the map, Iterate provides the same guarantees as
// Go maps: if f deletes a map entry that Iterate has not yet reached,
// f will not be invoked for it, but if f inserts a map entry that
// Iterate has not yet reached, whether or not f will be invoked for
// it is unspecified.
//
func (m *Map) Iterate(f func(key types.Type, value interface{})) {
	if m != nil {
		for _, bucket := range m.table {
			for _, e := range bucket {
				if e.key != nil {
					f(e.key, e.value)
				}
			}
		}
	}
}

// Keys returns a new slice containing the set of map keys.
// The order is unspecified.
func (m *Map) Keys() []types.Type {
	keys := make([]types.Type, 0, m.Len())
	m.Iterate(func(key types.Type, _ interface{}) {
		keys = append(keys, key)
	})
	return keys
}

func (m *Map) toString(values bool) string {
	if m == nil {
		return "{}"
	}
	var buf bytes.Buffer
	fmt.Fprint(&buf, "{")
	sep := ""
	m.Iterate(func(key types.Type, value interface{}) {
		fmt.Fprint(&buf, sep)
		sep = ", "
		fmt.Fprint(&buf, key)
		if values {
			fmt.Fprintf(&buf, ": %q", value)
		}
	})
	fmt.Fprint(&buf, "}")
	return buf.String()
}

// String returns a string representation of the map's entries.
// Values are printed using fmt.Sprintf("%v", v).
// Order is unspecified.
//
func (m *Map) String() string {
	return m.toString(true)
}

// KeysString returns a string representation of the map's key set.
// Order is unspecified.
//
func (m *Map) KeysString() string {
	return m.toString(false)
}

////////////////////////////////////////////////////////////////////////
// Hasher

// A Hasher maps each type to its hash value.
// For efficiency, a hasher uses memoization; thus its memory
// footprint grows monotonically over time.
// Hashers are not thread-safe.
// Hashers have reference semantics.
// Call MakeHasher to create a Hasher.
type Hasher struct {
	memo map[types.Type]uint32
}

// MakeHasher returns a new Hasher instance.
func MakeHasher() Hasher {
	return Hasher{make(map[types.Type]uint32)}
}

// Hash computes a hash value for the given type t such that
// Identical(t, t') => Hash(t) == Hash(t').
func (h Hasher) Hash(t types.Type) uint32 {
	hash, ok := h.memo[t]
	if !ok {
		hash = h.hashFor(t)
		h.memo[t] = hash
	}
	return hash
}

// hashString computes the Fowler–Noll–Vo hash of s.
func hashString(s string) uint32 {
	var h uint32
	for i := 0; i < len(s); i++ {
		h ^= uint32(s[i])
		h *= 16777619
	}
	return h
}

// hashFor computes the hash of t.
func (h Hasher) hashFor(t types.Type) uint32 {
	// See Identical for rationale.
	switch t := t.(type) {
	case *types.Basic:
		return uint32(t.Kind())

	case *types.Array:
		return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())

	case *types.Slice:
		return 9049 + 2*h.Hash(t.Elem())

	case *types.Struct:
		var hash uint32 = 9059
		for i, n := 0, t.NumFields(); i < n; i++ {
			f := t.Field(i)
			if f.Anonymous() {
				hash += 8861
			}
			hash += hashString(t.Tag(i))
			hash += hashString(f.Name()) // (ignore f.Pkg)
			hash += h.Hash(f.Type())
		}
		return hash

	case *types.Pointer:
		return 9067 + 2*h.Hash(t.Elem())

	case *types.Signature:
		var hash uint32 = 9091
		if t.Variadic() {
			hash *= 8863
		}
		return hash + 3*h.hashTuple(t.Params()) + 5*h.hashTuple(t.Results())

	case *types.Interface:
		var hash uint32 = 9103
		for i, n := 0, t.NumMethods(); i < n; i++ {
			// See go/types.identicalMethods for rationale.
			// Method order is not significant.
			// Ignore m.Pkg().
			m := t.Method(i)
			hash += 3*hashString(m.Name()) + 5*h.Hash(m.Type())
		}
		return hash

	case *types.Map:
		return 9109 + 2*h.Hash(t.Key()) + 3*h.Hash(t.Elem())

	case *types.Chan:
		return 9127 + 2*uint32(t.Dir()) + 3*h.Hash(t.Elem())

	case *types.Named:
		// Not safe with a copying GC; objects may move.
		return uint32(reflect.ValueOf(t.Obj()).Pointer())

	case *types.Tuple:
		return h.hashTuple(t)
	}
	panic(t)
}

func (h Hasher) hashTuple(tuple *types.Tuple) uint32 {
	// See go/types.identicalTypes for rationale.
	n := tuple.Len()
	var hash uint32 = 9137 + 2*uint32(n)
	for i := 0; i < n; i++ {
		hash += 3 * h.Hash(tuple.At(i).Type())
	}
	return hash
}
<|endoftext|>


<commit_before>package db

import "strconv"

// The SessionInfo struct represents a session announcement fetched from the database
// It is also used to insert new entries.
// When inserting, the "Started" field is ignored and the current timestamp is used
type SessionInfo struct {
	Host      string   `json:"host"`
	Port      int      `json:"port"`
	Id        string   `json:"id"`
	Protocol  string   `json:"protocol"`
	Title     string   `json:"title"`
	Users     int      `json:"users"`
	Usernames []string `json:"usernames"`
	Password  bool     `json:"password"`
	Nsfm      bool     `json:"nsfm"`
	Owner     string   `json:"owner"`
	Started   string   `json:"started"`
	Roomcode  string   `json:"roomcode,omitempty"`
	Private   bool     `json:"private,omitempty"`
}

func (info SessionInfo) HostAddress() string {
	return info.Host + ":" + strconv.Itoa(info.Port)
}

// Minimum info needed to join a session
type JoinSessionInfo struct {
	Host      string   `json:"host"`
	Port      int      `json:"port"`
	Id        string   `json:"id"`
}

// Info about a newly inserted session
type NewSessionInfo struct {
	ListingId int    `json:"id"`
	UpdateKey string `json:"key"`
	Private   bool   `json:"private"`
	Roomcode  string `json:"roomcode,omitempty"`
}
<commit_msg>Fix formatting of IPv6 addresses<commit_after>package db

import (
	"fmt"
	"strings"
)

// The SessionInfo struct represents a session announcement fetched from the database
// It is also used to insert new entries.
// When inserting, the "Started" field is ignored and the current timestamp is used
type SessionInfo struct {
	Host      string   `json:"host"`
	Port      int      `json:"port"`
	Id        string   `json:"id"`
	Protocol  string   `json:"protocol"`
	Title     string   `json:"title"`
	Users     int      `json:"users"`
	Usernames []string `json:"usernames"`
	Password  bool     `json:"password"`
	Nsfm      bool     `json:"nsfm"`
	Owner     string   `json:"owner"`
	Started   string   `json:"started"`
	Roomcode  string   `json:"roomcode,omitempty"`
	Private   bool     `json:"private,omitempty"`
}

func (info SessionInfo) HostAddress() string {
	if strings.ContainsRune(info.Host, ':') {
		return fmt.Sprintf("[%s]:%d", info.Host, info.Port)
	} else {
		return fmt.Sprintf("%s:%d", info.Host, info.Port)
	}
}

// Minimum info needed to join a session
type JoinSessionInfo struct {
	Host      string   `json:"host"`
	Port      int      `json:"port"`
	Id        string   `json:"id"`
}

// Info about a newly inserted session
type NewSessionInfo struct {
	ListingId int    `json:"id"`
	UpdateKey string `json:"key"`
	Private   bool   `json:"private"`
	Roomcode  string `json:"roomcode,omitempty"`
}
<|endoftext|>


<commit_before>package gerrit

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func (g GerritInstance) GetChangeInformation(changeID string) (*ChangeInfo, error) {
	urlToCall := fmt.Sprintf("%s/changes/%s/?o=CURRENT_REVISION", g.getAPIUrl(false), changeID)
	log.Printf("Calling %s\n", urlToCall)

	client := &http.Client{}
	req, _ := http.NewRequest("GET", urlToCall, nil)
	req.SetBasicAuth(g.Username, g.Password)
	req.Header.Add("Content-Type", "application/json;charset=UTF-8")

	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
		log.Printf("> Change-details for change id \"%s\" received", changeID)

	} else {
		log.Printf("> Call success, but the status code doesn`t match ~200: %s - %s", resp.Status, err)
		return nil, errors.New("Call success, but the status code doesn`t match ~200")
	}

	var change ChangeInfo

	respBody, err := ioutil.ReadAll(resp.Body)
	// Every Gerrit response starts with ")]}'"
	jsonBody := string(respBody)[4:]

	err = json.Unmarshal([]byte(jsonBody), &change)
	if err != nil {
		return nil, err
	}

	return &change, nil
}

// https://review.typo3.org/Documentation/rest-api-changes.html#set-review
func (g GerritInstance) PostCommentOnChangeset(m *Message, vote int, msg string) {
	log.Printf("> Start posting review for %s (%s)", m.Change.URL, m.Patchset.Ref)

	changeID := m.Change.ID
	revisionID := m.Patchset.Revision
	urlToCall := fmt.Sprintf("%s/changes/%s/revisions/%s/review", g.getAPIUrl(true), changeID, revisionID)

	log.Printf("> Calling %s", urlToCall)

	bodyStruct := &ReviewInput{
		Message: msg,
		Labels: map[string]int{
			// Code-Review
			"Verified": vote,
		},
	}

	body, _ := json.Marshal(bodyStruct)

	client := &http.Client{}
	req, _ := http.NewRequest("POST", urlToCall, strings.NewReader(string(body)))
	req.SetBasicAuth(g.Username, g.Password)
	req.Header.Add("Content-Type", "application/json;charset=UTF-8")

	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		log.Println("> Call failed", err)
	}

	if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
		log.Printf("> Call success: %s", resp.Status)
	} else {
		log.Printf("> Call success, but the status code doesn`t match ~200: %s", resp.Status)
	}
}
<commit_msg>Added "> " as log prefix<commit_after>package gerrit

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func (g GerritInstance) GetChangeInformation(changeID string) (*ChangeInfo, error) {
	urlToCall := fmt.Sprintf("%s/changes/%s/?o=CURRENT_REVISION", g.getAPIUrl(false), changeID)
	log.Printf("> Calling %s\n", urlToCall)

	client := &http.Client{}
	req, _ := http.NewRequest("GET", urlToCall, nil)
	req.SetBasicAuth(g.Username, g.Password)
	req.Header.Add("Content-Type", "application/json;charset=UTF-8")

	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		return nil, err
	}

	if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
		log.Printf("> Change-details for change id \"%s\" received", changeID)

	} else {
		log.Printf("> Call success, but the status code doesn`t match ~200: %s - %s", resp.Status, err)
		return nil, errors.New("Call success, but the status code doesn`t match ~200")
	}

	var change ChangeInfo

	respBody, err := ioutil.ReadAll(resp.Body)
	// Every Gerrit response starts with ")]}'"
	jsonBody := string(respBody)[4:]

	err = json.Unmarshal([]byte(jsonBody), &change)
	if err != nil {
		return nil, err
	}

	return &change, nil
}

// https://review.typo3.org/Documentation/rest-api-changes.html#set-review
func (g GerritInstance) PostCommentOnChangeset(m *Message, vote int, msg string) {
	log.Printf("> Start posting review for %s (%s)", m.Change.URL, m.Patchset.Ref)

	changeID := m.Change.ID
	revisionID := m.Patchset.Revision
	urlToCall := fmt.Sprintf("%s/changes/%s/revisions/%s/review", g.getAPIUrl(true), changeID, revisionID)

	log.Printf("> Calling %s", urlToCall)

	bodyStruct := &ReviewInput{
		Message: msg,
		Labels: map[string]int{
			// Code-Review
			"Verified": vote,
		},
	}

	body, _ := json.Marshal(bodyStruct)

	client := &http.Client{}
	req, _ := http.NewRequest("POST", urlToCall, strings.NewReader(string(body)))
	req.SetBasicAuth(g.Username, g.Password)
	req.Header.Add("Content-Type", "application/json;charset=UTF-8")

	resp, err := client.Do(req)
	defer resp.Body.Close()

	if err != nil {
		log.Println("> Call failed", err)
	}

	if resp.StatusCode >= 200 && resp.StatusCode <= 299 {
		log.Printf("> Call success: %s", resp.Status)
	} else {
		log.Printf("> Call success, but the status code doesn`t match ~200: %s", resp.Status)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"fmt"
	"sync"

	"k8s.io/apimachinery/pkg/util/sets"
)

// ThreadSafeStore is an interface that allows concurrent indexed
// access to a storage backend.  It is like Indexer but does not
// (necessarily) know how to extract the Store key from a given
// object.
//
// TL;DR caveats: you must not modify anything returned by Get or List as it will break
// the indexing feature in addition to not being thread safe.
//
// The guarantees of thread safety provided by List/Get are only valid if the caller
// treats returned items as read-only. For example, a pointer inserted in the store
// through `Add` will be returned as is by `Get`. Multiple clients might invoke `Get`
// on the same key and modify the pointer in a non-thread-safe way. Also note that
// modifying objects stored by the indexers (if any) will *not* automatically lead
// to a re-index. So it's not a good idea to directly modify the objects returned by
// Get/List, in general.
type ThreadSafeStore interface {
	Add(key string, obj interface{})
	Update(key string, obj interface{})
	Delete(key string)
	Get(key string) (item interface{}, exists bool)
	List() []interface{}
	ListKeys() []string
	Replace(map[string]interface{}, string)
	Index(indexName string, obj interface{}) ([]interface{}, error)
	IndexKeys(indexName, indexKey string) ([]string, error)
	ListIndexFuncValues(name string) []string
	ByIndex(indexName, indexKey string) ([]interface{}, error)
	GetIndexers() Indexers

	// AddIndexers adds more indexers to this store.  If you call this after you already have data
	// in the store, the results are undefined.
	AddIndexers(newIndexers Indexers) error
	// Resync is a no-op and is deprecated
	Resync() error
}

// threadSafeMap implements ThreadSafeStore
type threadSafeMap struct {
	lock  sync.RWMutex
	items map[string]interface{}

	// indexers maps a name to an IndexFunc
	indexers Indexers
	// indices maps a name to an Index
	indices Indices
}

func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Delete(key string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if obj, exists := c.items[key]; exists {
		c.updateIndices(obj, nil, key)
		delete(c.items, key)
	}
}

func (c *threadSafeMap) Get(key string) (item interface{}, exists bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	item, exists = c.items[key]
	return item, exists
}

func (c *threadSafeMap) List() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]interface{}, 0, len(c.items))
	for _, item := range c.items {
		list = append(list, item)
	}
	return list
}

// ListKeys returns a list of all the keys of the objects currently
// in the threadSafeMap.
func (c *threadSafeMap) ListKeys() []string {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]string, 0, len(c.items))
	for key := range c.items {
		list = append(list, key)
	}
	return list
}

func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = items

	// rebuild any index
	c.indices = Indices{}
	for key, item := range c.items {
		c.updateIndices(nil, item, key)
	}
}

// Index returns a list of items that match the given object on the index function.
// Index is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) Index(indexName string, obj interface{}) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	indexedValues, err := indexFunc(obj)
	if err != nil {
		return nil, err
	}
	index := c.indices[indexName]

	var storeKeySet sets.String
	if len(indexedValues) == 1 {
		// In majority of cases, there is exactly one value matching.
		// Optimize the most common path - deduping is not needed here.
		storeKeySet = index[indexedValues[0]]
	} else {
		// Need to de-dupe the return list.
		// Since multiple keys are allowed, this can happen.
		storeKeySet = sets.String{}
		for _, indexedValue := range indexedValues {
			for key := range index[indexedValue] {
				storeKeySet.Insert(key)
			}
		}
	}

	list := make([]interface{}, 0, storeKeySet.Len())
	for storeKey := range storeKeySet {
		list = append(list, c.items[storeKey])
	}
	return list, nil
}

// ByIndex returns a list of the items whose indexed values in the given index include the given indexed value
func (c *threadSafeMap) ByIndex(indexName, indexedValue string) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := c.indices[indexName]

	set := index[indexedValue]
	list := make([]interface{}, 0, set.Len())
	for key := range set {
		list = append(list, c.items[key])
	}

	return list, nil
}

// IndexKeys returns a list of the Store keys of the objects whose indexed values in the given index include the given indexed value.
// IndexKeys is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) IndexKeys(indexName, indexedValue string) ([]string, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := c.indices[indexName]

	set := index[indexedValue]
	return set.List(), nil
}

func (c *threadSafeMap) ListIndexFuncValues(indexName string) []string {
	c.lock.RLock()
	defer c.lock.RUnlock()

	index := c.indices[indexName]
	names := make([]string, 0, len(index))
	for key := range index {
		names = append(names, key)
	}
	return names
}

func (c *threadSafeMap) GetIndexers() Indexers {
	return c.indexers
}

func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	if len(c.items) > 0 {
		return fmt.Errorf("cannot add indexers to running index")
	}

	oldKeys := sets.StringKeySet(c.indexers)
	newKeys := sets.StringKeySet(newIndexers)

	if oldKeys.HasAny(newKeys.List()...) {
		return fmt.Errorf("indexer conflict: %v", oldKeys.Intersection(newKeys))
	}

	for k, v := range newIndexers {
		c.indexers[k] = v
	}
	return nil
}

// updateIndices modifies the objects location in the managed indexes:
// - for create you must provide only the newObj
// - for update you must provide both the oldObj and the newObj
// - for delete you must provide only the oldObj
// updateIndices must be called from a function that already has a lock on the cache
func (c *threadSafeMap) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	var oldIndexValues, indexValues []string
	var err error
	for name, indexFunc := range c.indexers {
		if oldObj != nil {
			oldIndexValues, err = indexFunc(oldObj)
		} else {
			oldIndexValues = oldIndexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		if newObj != nil {
			indexValues, err = indexFunc(newObj)
		} else {
			indexValues = indexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		index := c.indices[name]
		if index == nil {
			index = Index{}
			c.indices[name] = index
		}

		for _, value := range oldIndexValues {
			// We optimize for the most common case where index returns a single value.
			if len(indexValues) == 1 && value == indexValues[0] {
				continue
			}
			c.deleteKeyFromIndex(key, value, index)
		}
		for _, value := range indexValues {
			// We optimize for the most common case where index returns a single value.
			if len(oldIndexValues) == 1 && value == oldIndexValues[0] {
				continue
			}
			c.addKeyToIndex(key, value, index)
		}
	}
}

func (c *threadSafeMap) addKeyToIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		set = sets.String{}
		index[indexValue] = set
	}
	set.Insert(key)
}

func (c *threadSafeMap) deleteKeyFromIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		return
	}
	set.Delete(key)
	// If we don't delete the set when zero, indices with high cardinality
	// short lived resources can cause memory to increase over time from
	// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
	if len(set) == 0 {
		delete(index, indexValue)
	}
}

func (c *threadSafeMap) Resync() error {
	// Nothing to do
	return nil
}

// NewThreadSafeStore creates a new instance of ThreadSafeStore.
func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore {
	return &threadSafeMap{
		items:    map[string]interface{}{},
		indexers: indexers,
		indices:  indices,
	}
}
<commit_msg>refactor: remove dup code<commit_after>/*
Copyright 2014 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"fmt"
	"sync"

	"k8s.io/apimachinery/pkg/util/sets"
)

// ThreadSafeStore is an interface that allows concurrent indexed
// access to a storage backend.  It is like Indexer but does not
// (necessarily) know how to extract the Store key from a given
// object.
//
// TL;DR caveats: you must not modify anything returned by Get or List as it will break
// the indexing feature in addition to not being thread safe.
//
// The guarantees of thread safety provided by List/Get are only valid if the caller
// treats returned items as read-only. For example, a pointer inserted in the store
// through `Add` will be returned as is by `Get`. Multiple clients might invoke `Get`
// on the same key and modify the pointer in a non-thread-safe way. Also note that
// modifying objects stored by the indexers (if any) will *not* automatically lead
// to a re-index. So it's not a good idea to directly modify the objects returned by
// Get/List, in general.
type ThreadSafeStore interface {
	Add(key string, obj interface{})
	Update(key string, obj interface{})
	Delete(key string)
	Get(key string) (item interface{}, exists bool)
	List() []interface{}
	ListKeys() []string
	Replace(map[string]interface{}, string)
	Index(indexName string, obj interface{}) ([]interface{}, error)
	IndexKeys(indexName, indexKey string) ([]string, error)
	ListIndexFuncValues(name string) []string
	ByIndex(indexName, indexKey string) ([]interface{}, error)
	GetIndexers() Indexers

	// AddIndexers adds more indexers to this store.  If you call this after you already have data
	// in the store, the results are undefined.
	AddIndexers(newIndexers Indexers) error
	// Resync is a no-op and is deprecated
	Resync() error
}

// threadSafeMap implements ThreadSafeStore
type threadSafeMap struct {
	lock  sync.RWMutex
	items map[string]interface{}

	// indexers maps a name to an IndexFunc
	indexers Indexers
	// indices maps a name to an Index
	indices Indices
}

func (c *threadSafeMap) Add(key string, obj interface{}) {
	c.Update(key, obj)
}

func (c *threadSafeMap) Update(key string, obj interface{}) {
	c.lock.Lock()
	defer c.lock.Unlock()
	oldObject := c.items[key]
	c.items[key] = obj
	c.updateIndices(oldObject, obj, key)
}

func (c *threadSafeMap) Delete(key string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	if obj, exists := c.items[key]; exists {
		c.updateIndices(obj, nil, key)
		delete(c.items, key)
	}
}

func (c *threadSafeMap) Get(key string) (item interface{}, exists bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()
	item, exists = c.items[key]
	return item, exists
}

func (c *threadSafeMap) List() []interface{} {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]interface{}, 0, len(c.items))
	for _, item := range c.items {
		list = append(list, item)
	}
	return list
}

// ListKeys returns a list of all the keys of the objects currently
// in the threadSafeMap.
func (c *threadSafeMap) ListKeys() []string {
	c.lock.RLock()
	defer c.lock.RUnlock()
	list := make([]string, 0, len(c.items))
	for key := range c.items {
		list = append(list, key)
	}
	return list
}

func (c *threadSafeMap) Replace(items map[string]interface{}, resourceVersion string) {
	c.lock.Lock()
	defer c.lock.Unlock()
	c.items = items

	// rebuild any index
	c.indices = Indices{}
	for key, item := range c.items {
		c.updateIndices(nil, item, key)
	}
}

// Index returns a list of items that match the given object on the index function.
// Index is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) Index(indexName string, obj interface{}) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	indexedValues, err := indexFunc(obj)
	if err != nil {
		return nil, err
	}
	index := c.indices[indexName]

	var storeKeySet sets.String
	if len(indexedValues) == 1 {
		// In majority of cases, there is exactly one value matching.
		// Optimize the most common path - deduping is not needed here.
		storeKeySet = index[indexedValues[0]]
	} else {
		// Need to de-dupe the return list.
		// Since multiple keys are allowed, this can happen.
		storeKeySet = sets.String{}
		for _, indexedValue := range indexedValues {
			for key := range index[indexedValue] {
				storeKeySet.Insert(key)
			}
		}
	}

	list := make([]interface{}, 0, storeKeySet.Len())
	for storeKey := range storeKeySet {
		list = append(list, c.items[storeKey])
	}
	return list, nil
}

// ByIndex returns a list of the items whose indexed values in the given index include the given indexed value
func (c *threadSafeMap) ByIndex(indexName, indexedValue string) ([]interface{}, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := c.indices[indexName]

	set := index[indexedValue]
	list := make([]interface{}, 0, set.Len())
	for key := range set {
		list = append(list, c.items[key])
	}

	return list, nil
}

// IndexKeys returns a list of the Store keys of the objects whose indexed values in the given index include the given indexed value.
// IndexKeys is thread-safe so long as you treat all items as immutable.
func (c *threadSafeMap) IndexKeys(indexName, indexedValue string) ([]string, error) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	indexFunc := c.indexers[indexName]
	if indexFunc == nil {
		return nil, fmt.Errorf("Index with name %s does not exist", indexName)
	}

	index := c.indices[indexName]

	set := index[indexedValue]
	return set.List(), nil
}

func (c *threadSafeMap) ListIndexFuncValues(indexName string) []string {
	c.lock.RLock()
	defer c.lock.RUnlock()

	index := c.indices[indexName]
	names := make([]string, 0, len(index))
	for key := range index {
		names = append(names, key)
	}
	return names
}

func (c *threadSafeMap) GetIndexers() Indexers {
	return c.indexers
}

func (c *threadSafeMap) AddIndexers(newIndexers Indexers) error {
	c.lock.Lock()
	defer c.lock.Unlock()

	if len(c.items) > 0 {
		return fmt.Errorf("cannot add indexers to running index")
	}

	oldKeys := sets.StringKeySet(c.indexers)
	newKeys := sets.StringKeySet(newIndexers)

	if oldKeys.HasAny(newKeys.List()...) {
		return fmt.Errorf("indexer conflict: %v", oldKeys.Intersection(newKeys))
	}

	for k, v := range newIndexers {
		c.indexers[k] = v
	}
	return nil
}

// updateIndices modifies the objects location in the managed indexes:
// - for create you must provide only the newObj
// - for update you must provide both the oldObj and the newObj
// - for delete you must provide only the oldObj
// updateIndices must be called from a function that already has a lock on the cache
func (c *threadSafeMap) updateIndices(oldObj interface{}, newObj interface{}, key string) {
	var oldIndexValues, indexValues []string
	var err error
	for name, indexFunc := range c.indexers {
		if oldObj != nil {
			oldIndexValues, err = indexFunc(oldObj)
		} else {
			oldIndexValues = oldIndexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		if newObj != nil {
			indexValues, err = indexFunc(newObj)
		} else {
			indexValues = indexValues[:0]
		}
		if err != nil {
			panic(fmt.Errorf("unable to calculate an index entry for key %q on index %q: %v", key, name, err))
		}

		index := c.indices[name]
		if index == nil {
			index = Index{}
			c.indices[name] = index
		}

		for _, value := range oldIndexValues {
			// We optimize for the most common case where index returns a single value.
			if len(indexValues) == 1 && value == indexValues[0] {
				continue
			}
			c.deleteKeyFromIndex(key, value, index)
		}
		for _, value := range indexValues {
			// We optimize for the most common case where index returns a single value.
			if len(oldIndexValues) == 1 && value == oldIndexValues[0] {
				continue
			}
			c.addKeyToIndex(key, value, index)
		}
	}
}

func (c *threadSafeMap) addKeyToIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		set = sets.String{}
		index[indexValue] = set
	}
	set.Insert(key)
}

func (c *threadSafeMap) deleteKeyFromIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		return
	}
	set.Delete(key)
	// If we don't delete the set when zero, indices with high cardinality
	// short lived resources can cause memory to increase over time from
	// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
	if len(set) == 0 {
		delete(index, indexValue)
	}
}

func (c *threadSafeMap) Resync() error {
	// Nothing to do
	return nil
}

// NewThreadSafeStore creates a new instance of ThreadSafeStore.
func NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore {
	return &threadSafeMap{
		items:    map[string]interface{}{},
		indexers: indexers,
		indices:  indices,
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 CoreOS, Inc.
//
// 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 aws

import (
	"fmt"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/coreos/pkg/capnslog"

	"github.com/coreos/mantle/platform"
)

var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "platform/api/aws")

type Options struct {
	*platform.Options
	// The AWS region regional api calls should use
	Region string

	// The path to the shared credentials file, if not ~/.aws/credentials
	CredentialsFile string
	// The profile to use when resolving credentials, if applicable
	Profile string

	// AccessKeyID is the optional access key to use. It will override all other sources
	AccessKeyID string
	// SecretKey is the optional secret key to use. It will override all other sources
	SecretKey string

	AMI           string
	InstanceType  string
	SecurityGroup string
}

type API struct {
	session client.ConfigProvider
	ec2     *ec2.EC2
	s3      *s3.S3
	opts    *Options
}

// New creates a new AWS API wrapper. It uses credentials from any of the
// standard credentials sources, including the environment and the profile
// configured in ~/.aws.
// No validation is done that credentials exist and before using the API a
// preflight check is recommended via api.PreflightCheck
func New(opts *Options) (*API, error) {
	if opts.CredentialsFile != "" {
		// Not exposed via the API. Ick.
		if err := os.Setenv("AWS_SHARED_CREDENTIALS_FILE", opts.CredentialsFile); err != nil {
			return nil, fmt.Errorf("couldn't set credentials file: %v", err)
		}
	}

	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: opts.Profile,
		Config:  aws.Config{Region: aws.String(opts.Region)},
	})
	if err != nil {
		return nil, err
	}

	if opts.AccessKeyID != "" {
		sess.Config.WithCredentials(credentials.NewStaticCredentials(opts.AccessKeyID, opts.SecretKey, ""))
	}

	api := &API{
		session: sess,
		ec2:     ec2.New(sess),
		s3:      s3.New(sess),
		opts:    opts,
	}

	return api, nil
}

// PreflightCheck validates that the aws configuration provided has valid
// credentials
func (a *API) PreflightCheck() error {
	stsClient := sts.New(a.session)
	_, err := stsClient.GetCallerIdentity(&sts.GetCallerIdentityInput{})

	return err
}
<commit_msg>platform/aws: fix handling of credential file<commit_after>// Copyright 2016 CoreOS, Inc.
//
// 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 aws

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/aws/aws-sdk-go/service/sts"
	"github.com/coreos/pkg/capnslog"

	"github.com/coreos/mantle/platform"
)

var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "platform/api/aws")

type Options struct {
	*platform.Options
	// The AWS region regional api calls should use
	Region string

	// The path to the shared credentials file, if not ~/.aws/credentials
	CredentialsFile string
	// The profile to use when resolving credentials, if applicable
	Profile string

	// AccessKeyID is the optional access key to use. It will override all other sources
	AccessKeyID string
	// SecretKey is the optional secret key to use. It will override all other sources
	SecretKey string

	AMI           string
	InstanceType  string
	SecurityGroup string
}

type API struct {
	session client.ConfigProvider
	ec2     *ec2.EC2
	s3      *s3.S3
	opts    *Options
}

// New creates a new AWS API wrapper. It uses credentials from any of the
// standard credentials sources, including the environment and the profile
// configured in ~/.aws.
// No validation is done that credentials exist and before using the API a
// preflight check is recommended via api.PreflightCheck
func New(opts *Options) (*API, error) {
	awsCfg := aws.Config{Region: aws.String(opts.Region)}
	if opts.AccessKeyID != "" {
		awsCfg.Credentials = credentials.NewStaticCredentials(opts.AccessKeyID, opts.SecretKey, "")
	} else if opts.CredentialsFile != "" {
		awsCfg.Credentials = credentials.NewSharedCredentials(opts.CredentialsFile, opts.Profile)
	}

	sess, err := session.NewSessionWithOptions(session.Options{
		Profile: opts.Profile,
		Config:  awsCfg,
	})
	if err != nil {
		return nil, err
	}

	api := &API{
		session: sess,
		ec2:     ec2.New(sess),
		s3:      s3.New(sess),
		opts:    opts,
	}

	return api, nil
}

// PreflightCheck validates that the aws configuration provided has valid
// credentials
func (a *API) PreflightCheck() error {
	stsClient := sts.New(a.session)
	_, err := stsClient.GetCallerIdentity(&sts.GetCallerIdentityInput{})

	return err
}
<|endoftext|>


<commit_before>package secret

func Handshake(code uint) []string {
	panic("Please implement the Handshake function")
}
<commit_msg>Pass first few cases<commit_after>package secret

import (
	"fmt"
	"strconv"
)

var operations = []string{"wink", "double blink", "close your eyes", "jump"}

func Handshake(code uint) (handshake []string) {
	binary := strconv.FormatInt(int64(code), 2)
	fmt.Printf("code %v in binary %v\n", code, binary)
	for i, v := range reverse(binary) {
		if v == '1' {
			handshake = append(handshake, operations[i])
		}
	}
	return handshake
}

func reverse(input string) (result string) {
	for _, v := range input {
		result = string(v) + result
	}
	return result
}
<|endoftext|>