<commit_before>// +build unit

// Copyright 2016 Mesosphere, 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 framework

import (
	"testing"

	"github.com/dcos/dcos-metrics/producers"
	"github.com/dcos/dcos-metrics/schema/metrics_schema"
	"github.com/linkedin/goavro"
	. "github.com/smartystreets/goconvey/convey"
)

var (
	testDatapoint = record{
		Name: "dcos.metrics.Datapoint",
		Fields: []field{
			{
				Name:  "test-name",
				Datum: "name-field-test",
			},
			{
				Name:  "test-value",
				Datum: "value-field-test",
			},
			{
				Name:  "test-unit",
				Datum: "unit-field-test",
			},
		},
	}
	testTag = record{
		Name: "dcos.metrics.Tag",
		Fields: []field{
			{
				Name:  "test-tag-name",
				Datum: "tag-name-field-test",
			},
			{
				Name:  "test-tag-value",
				Datum: "tag-value-field-test",
			},
		},
	}
)

func TestExtract(t *testing.T) {
	Convey("When extracting a datapoint from an Avro record", t, func() {
		avroDatapoint := avroRecord{testDatapoint}
		pmmTest := producers.MetricsMessage{}
		err := avroDatapoint.extract(&pmmTest)

		Convey("Should extract the datapoint without errors", func() {
			So(err, ShouldBeNil)
			So(len(pmmTest.Datapoints), ShouldEqual, 1)
		})

		Convey("Should return the expected name and values from the datapoint", func() {
			So(pmmTest.Datapoints[0].Name, ShouldEqual, "name-field-test")
			So(pmmTest.Datapoints[0].Value, ShouldEqual, "value-field-test")
			So(pmmTest.Datapoints[0].Unit, ShouldEqual, "unit-field-test")
		})
	})

	Convey("When extracting tags from an Avro record", t, func() {
		avroDatapoint := avroRecord{testTag}
		pmmTest := producers.MetricsMessage{
			Dimensions: producers.Dimensions{
				Labels: make(map[string]string),
			},
		}

		Convey("Should extract the tag without errors", func() {
			err := avroDatapoint.extract(&pmmTest)
			value, ok := pmmTest.Dimensions.Labels["tag-name-field-test"]

			So(err, ShouldBeNil)
			So(ok, ShouldBeTrue)
			So(value, ShouldEqual, "tag-value-field-test")
		})
	})
}

func TestCreateObjectFromRecord(t *testing.T) {
	// Create a test record
	var (
		metricListNamespace = goavro.RecordEnclosingNamespace(metrics_schema.MetricListNamespace)
		metricListSchema    = goavro.RecordSchema(metrics_schema.MetricListSchema)
		datapointNamespace  = goavro.RecordEnclosingNamespace(metrics_schema.DatapointNamespace)
		datapointSchema     = goavro.RecordSchema(metrics_schema.DatapointSchema)
		tagNamespace        = goavro.RecordEnclosingNamespace(metrics_schema.TagNamespace)
		tagSchema           = goavro.RecordSchema(metrics_schema.TagSchema)
	)

	recDps, err := goavro.NewRecord(datapointNamespace, datapointSchema)
	if err != nil {
		panic(err)
	}
	recDps.Set("name", "some-name")
	recDps.Set("time_ms", 1000)
	recDps.Set("value", 42.0)

	recTags, err := goavro.NewRecord(tagNamespace, tagSchema)
	if err != nil {
		panic(err)
	}
	recTags.Set("key", "some-key")
	recTags.Set("value", "some-val")

	rec, err := goavro.NewRecord(metricListNamespace, metricListSchema)
	if err != nil {
		panic(err)
	}
	rec.Set("topic", "some-topic")
	rec.Set("tags", []interface{}{recTags})
	rec.Set("datapoints", []interface{}{recDps})

	// Run the test
	Convey("When creating an avroRecord object from an actual Avro record", t, func() {
		Convey("Should return the provided data in the expected structure without errors", func() {
			ar := avroRecord{}
			tags, err := rec.Get("tags")
			if err != nil {
				panic(err)
			}

			err = ar.createObjectFromRecord(tags)
			So(err, ShouldBeNil)
			So(ar, ShouldResemble, avroRecord{
				record{
					Name: "dcos.metrics.Tag",
					Fields: []field{
						field{
							Name:  "dcos.metrics.key",
							Datum: "some-key",
						},
						field{
							Name:  "dcos.metrics.value",
							Datum: "some-val",
						},
					},
				},
			})
		})

		Convey("Should return an error if the transformation failed", func() {
			type badData struct {
				SomeKey string
				SomeVal string
			}
			bd := badData{
				SomeKey: "foo-key",
				SomeVal: "foo-val",
			}
			ar := avroRecord{}
			err := ar.createObjectFromRecord(bd)
			So(err, ShouldNotBeNil)
		})
	})
}
<commit_msg>add additional test cases for extract()<commit_after>// +build unit

// Copyright 2016 Mesosphere, 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 framework

import (
	"testing"

	"github.com/dcos/dcos-metrics/producers"
	"github.com/dcos/dcos-metrics/schema/metrics_schema"
	"github.com/linkedin/goavro"
	. "github.com/smartystreets/goconvey/convey"
)

var (
	testDatapoint = record{
		Name: "dcos.metrics.Datapoint",
		Fields: []field{
			{
				Name:  "test-name",
				Datum: "name-field-test",
			},
			{
				Name:  "test-value",
				Datum: "value-field-test",
			},
			{
				Name:  "test-unit",
				Datum: "unit-field-test",
			},
		},
	}
	testTag = record{
		Name: "dcos.metrics.Tag",
		Fields: []field{
			{
				Name:  "test-tag-name",
				Datum: "tag-name-field-test",
			},
			{
				Name:  "test-tag-value",
				Datum: "tag-value-field-test",
			},
		},
	}
)

func TestExtract(t *testing.T) {
	Convey("When calling extract() on an avroRecord", t, func() {
		Convey("Should return an error if length of ar is 0", func() {
			ar := avroRecord{}
			err := ar.extract(&producers.MetricsMessage{})
			So(err, ShouldNotBeNil)
		})
	})

	Convey("When extracting a datapoint from an Avro record", t, func() {
		avroDatapoint := avroRecord{testDatapoint}
		pmmTest := producers.MetricsMessage{}
		err := avroDatapoint.extract(&pmmTest)

		Convey("Should extract the datapoint without errors", func() {
			So(err, ShouldBeNil)
			So(len(pmmTest.Datapoints), ShouldEqual, 1)
		})

		Convey("Should return the expected name and values from the datapoint", func() {
			So(pmmTest.Datapoints[0].Name, ShouldEqual, "name-field-test")
			So(pmmTest.Datapoints[0].Value, ShouldEqual, "value-field-test")
			So(pmmTest.Datapoints[0].Unit, ShouldEqual, "unit-field-test")
		})
	})

	Convey("When extracting tags from an Avro record", t, func() {
		avroDatapoint := avroRecord{testTag}
		pmmTest := producers.MetricsMessage{
			Dimensions: producers.Dimensions{
				Labels: make(map[string]string),
			},
		}

		Convey("Should extract the tag without errors", func() {
			err := avroDatapoint.extract(&pmmTest)
			value, ok := pmmTest.Dimensions.Labels["tag-name-field-test"]

			So(err, ShouldBeNil)
			So(ok, ShouldBeTrue)
			So(value, ShouldEqual, "tag-value-field-test")
		})
	})

	Convey("When analyzing the field types in a record", t, func() {
		Convey("Should return an error if the field type was empty", func() {
			ar := avroRecord{record{Name: ""}}
			err := ar.extract(&producers.MetricsMessage{})
			So(err, ShouldNotBeNil)
		})

		Convey("Should return an error for an unknown field type", func() {
			ar := avroRecord{record{Name: "not-dcos.not-metrics.not-Type"}}
			err := ar.extract(&producers.MetricsMessage{})
			So(err, ShouldNotBeNil)
		})
	})
}

func TestCreateObjectFromRecord(t *testing.T) {
	// Create a test record
	var (
		metricListNamespace = goavro.RecordEnclosingNamespace(metrics_schema.MetricListNamespace)
		metricListSchema    = goavro.RecordSchema(metrics_schema.MetricListSchema)
		datapointNamespace  = goavro.RecordEnclosingNamespace(metrics_schema.DatapointNamespace)
		datapointSchema     = goavro.RecordSchema(metrics_schema.DatapointSchema)
		tagNamespace        = goavro.RecordEnclosingNamespace(metrics_schema.TagNamespace)
		tagSchema           = goavro.RecordSchema(metrics_schema.TagSchema)
	)

	recDps, err := goavro.NewRecord(datapointNamespace, datapointSchema)
	if err != nil {
		panic(err)
	}
	recDps.Set("name", "some-name")
	recDps.Set("time_ms", 1000)
	recDps.Set("value", 42.0)

	recTags, err := goavro.NewRecord(tagNamespace, tagSchema)
	if err != nil {
		panic(err)
	}
	recTags.Set("key", "some-key")
	recTags.Set("value", "some-val")

	rec, err := goavro.NewRecord(metricListNamespace, metricListSchema)
	if err != nil {
		panic(err)
	}
	rec.Set("topic", "some-topic")
	rec.Set("tags", []interface{}{recTags})
	rec.Set("datapoints", []interface{}{recDps})

	// Run the test
	Convey("When creating an avroRecord object from an actual Avro record", t, func() {
		Convey("Should return the provided data in the expected structure without errors", func() {
			ar := avroRecord{}
			tags, err := rec.Get("tags")
			if err != nil {
				panic(err)
			}

			err = ar.createObjectFromRecord(tags)
			So(err, ShouldBeNil)
			So(ar, ShouldResemble, avroRecord{
				record{
					Name: "dcos.metrics.Tag",
					Fields: []field{
						field{
							Name:  "dcos.metrics.key",
							Datum: "some-key",
						},
						field{
							Name:  "dcos.metrics.value",
							Datum: "some-val",
						},
					},
				},
			})
		})

		Convey("Should return an error if the transformation failed", func() {
			type badData struct {
				SomeKey string
				SomeVal string
			}
			bd := badData{
				SomeKey: "foo-key",
				SomeVal: "foo-val",
			}
			ar := avroRecord{}
			err := ar.createObjectFromRecord(bd)
			So(err, ShouldNotBeNil)
		})
	})
}
<|endoftext|>


<commit_before>package changesCmd

import (
	// Stdlib
	"errors"
	"fmt"
	"os"

	// Internal
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/changes"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/version"

	// Other
	"gopkg.in/tchap/gocli.v2"
)

var Command = &gocli.Command{
	UsageLine: "changes [-porcelain] [-to_cherrypick]",
	Short: "list the changes associated with the current release",
	Long: `
  List the change sets (the commits with the same change ID)
  associated with the current release together with some details,
  e.g. the commit SHA, the source ref and the commit title.

  The 'porcelain' flag will make the output more script-friendly,
  e.g. it will fill the change ID in every column.

  The 'to_cherrypick' flag can be used to list the changes that are assigned
  to the release but haven't been cherry-picked onto the release branch yet.
	`,
	Action: run,
}

var (
	flagPorcelain    bool
	flagToCherryPick bool
)

func init() {
	Command.Flags.BoolVar(&flagPorcelain, "porcelain", flagPorcelain,
		"enable script-friendly output")
	Command.Flags.BoolVar(&flagToCherryPick, "to_cherrypick", flagToCherryPick,
		"list the changes to cherry-pick")
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if flagPorcelain {
		log.Disable()
	}
	err := runMain()
	if err != nil {
		errs.Fatal(err)
	}
}

func runMain() error {
	// Load repo config.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return err
	}

	var (
		remoteName    = gitConfig.RemoteName()
		releaseBranch = gitConfig.ReleaseBranchName()
	)

	// Make sure that the local release branch exists.
	task := "Make sure that the local release branch exists"
	err = git.CreateTrackingBranchUnlessExists(releaseBranch, remoteName)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the current release version string.
	task = "Get the release branch version string"
	releaseVersion, err := version.GetByBranch(releaseBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the stories associated with the current release.
	task = "Fetch the stories associated with the current release"
	log.Run(task)
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	release, err := tracker.RunningRelease(releaseVersion)
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	stories, err := release.Stories()
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	if len(stories) == 0 {
		return errs.NewError(task, errors.New("no relevant stories found"), nil)
	}

	// Get the story changes.
	task = "Collect the story changes"
	log.Run(task)
	groups, err := changes.StoryChanges(stories)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Just return in case there are no relevant commits found.
	if len(groups) == 0 {
		return errs.NewError(task, errors.New("no relevant commits found"), nil)
	}

	// Sort the change groups.
	groups = changes.SortStoryChanges(groups, stories)

	if flagToCherryPick {
		groups, err = groupsToCherryPick(groups)
		if err != nil {
			return errs.NewError(task, err, nil)
		}
	}

	// Dump the change details into the console.
	if !flagPorcelain {
		fmt.Println()
	}
	changes.DumpStoryChanges(groups, os.Stdout, flagPorcelain)
	if !flagPorcelain {
		fmt.Println()
	}

	return nil
}

func groupsToCherryPick(groups []*changes.StoryChangeGroup) ([]*changes.StoryChangeGroup, error) {
	// Get the commits that are reachable from the release branch.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return nil, err
	}
	releaseBranch := gitConfig.ReleaseBranchName()

	reachableCommits, err := git.ShowCommitRange(releaseBranch)
	if err != nil {
		return nil, err
	}

	reachableCommitMap := make(map[string]struct{}, len(reachableCommits))
	for _, commit := range reachableCommits {
		reachableCommitMap[commit.SHA] = struct{}{}
	}

	// Get the changes that needs to be cherry-picked.
	var toCherryPick []*changes.StoryChangeGroup

	for _, group := range groups {
		// Prepare a new StoryChangeGroup to hold missing changes.
		storyGroup := &changes.StoryChangeGroup{
			StoryId: group.StoryId,
		}

	ChangesLoop:
		// Loop over the story changes and the commits associated with
		// these changes. A change needs cherry-picking in case there are
		// some commits left when we drop the commits reachable from
		// the release branch.
		for _, change := range group.Changes {
			for _, commit := range change.Commits {
				if _, ok := reachableCommitMap[commit.SHA]; ok {
					continue ChangesLoop
				}
			}

			storyGroup.Changes = append(storyGroup.Changes, change)
		}

		if len(storyGroup.Changes) != 0 {
			toCherryPick = append(toCherryPick, storyGroup)
		}
	}

	return toCherryPick, nil
}
<commit_msg>Commit changes by go fmt<commit_after>package changesCmd

import (
	// Stdlib
	"errors"
	"fmt"
	"os"

	// Internal
	"github.com/salsaflow/salsaflow/app"
	"github.com/salsaflow/salsaflow/changes"
	"github.com/salsaflow/salsaflow/errs"
	"github.com/salsaflow/salsaflow/git"
	"github.com/salsaflow/salsaflow/log"
	"github.com/salsaflow/salsaflow/modules"
	"github.com/salsaflow/salsaflow/version"

	// Other
	"gopkg.in/tchap/gocli.v2"
)

var Command = &gocli.Command{
	UsageLine: "changes [-porcelain] [-to_cherrypick]",
	Short:     "list the changes associated with the current release",
	Long: `
  List the change sets (the commits with the same change ID)
  associated with the current release together with some details,
  e.g. the commit SHA, the source ref and the commit title.

  The 'porcelain' flag will make the output more script-friendly,
  e.g. it will fill the change ID in every column.

  The 'to_cherrypick' flag can be used to list the changes that are assigned
  to the release but haven't been cherry-picked onto the release branch yet.
	`,
	Action: run,
}

var (
	flagPorcelain    bool
	flagToCherryPick bool
)

func init() {
	Command.Flags.BoolVar(&flagPorcelain, "porcelain", flagPorcelain,
		"enable script-friendly output")
	Command.Flags.BoolVar(&flagToCherryPick, "to_cherrypick", flagToCherryPick,
		"list the changes to cherry-pick")
}

func run(cmd *gocli.Command, args []string) {
	if len(args) != 0 {
		cmd.Usage()
		os.Exit(2)
	}

	app.InitOrDie()

	if flagPorcelain {
		log.Disable()
	}
	err := runMain()
	if err != nil {
		errs.Fatal(err)
	}
}

func runMain() error {
	// Load repo config.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return err
	}

	var (
		remoteName    = gitConfig.RemoteName()
		releaseBranch = gitConfig.ReleaseBranchName()
	)

	// Make sure that the local release branch exists.
	task := "Make sure that the local release branch exists"
	err = git.CreateTrackingBranchUnlessExists(releaseBranch, remoteName)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the current release version string.
	task = "Get the release branch version string"
	releaseVersion, err := version.GetByBranch(releaseBranch)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Get the stories associated with the current release.
	task = "Fetch the stories associated with the current release"
	log.Run(task)
	tracker, err := modules.GetIssueTracker()
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	release, err := tracker.RunningRelease(releaseVersion)
	if err != nil {
		return errs.NewError(task, err, nil)
	}
	stories, err := release.Stories()
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	if len(stories) == 0 {
		return errs.NewError(task, errors.New("no relevant stories found"), nil)
	}

	// Get the story changes.
	task = "Collect the story changes"
	log.Run(task)
	groups, err := changes.StoryChanges(stories)
	if err != nil {
		return errs.NewError(task, err, nil)
	}

	// Just return in case there are no relevant commits found.
	if len(groups) == 0 {
		return errs.NewError(task, errors.New("no relevant commits found"), nil)
	}

	// Sort the change groups.
	groups = changes.SortStoryChanges(groups, stories)

	if flagToCherryPick {
		groups, err = groupsToCherryPick(groups)
		if err != nil {
			return errs.NewError(task, err, nil)
		}
	}

	// Dump the change details into the console.
	if !flagPorcelain {
		fmt.Println()
	}
	changes.DumpStoryChanges(groups, os.Stdout, flagPorcelain)
	if !flagPorcelain {
		fmt.Println()
	}

	return nil
}

func groupsToCherryPick(groups []*changes.StoryChangeGroup) ([]*changes.StoryChangeGroup, error) {
	// Get the commits that are reachable from the release branch.
	gitConfig, err := git.LoadConfig()
	if err != nil {
		return nil, err
	}
	releaseBranch := gitConfig.ReleaseBranchName()

	reachableCommits, err := git.ShowCommitRange(releaseBranch)
	if err != nil {
		return nil, err
	}

	reachableCommitMap := make(map[string]struct{}, len(reachableCommits))
	for _, commit := range reachableCommits {
		reachableCommitMap[commit.SHA] = struct{}{}
	}

	// Get the changes that needs to be cherry-picked.
	var toCherryPick []*changes.StoryChangeGroup

	for _, group := range groups {
		// Prepare a new StoryChangeGroup to hold missing changes.
		storyGroup := &changes.StoryChangeGroup{
			StoryId: group.StoryId,
		}

	ChangesLoop:
		// Loop over the story changes and the commits associated with
		// these changes. A change needs cherry-picking in case there are
		// some commits left when we drop the commits reachable from
		// the release branch.
		for _, change := range group.Changes {
			for _, commit := range change.Commits {
				if _, ok := reachableCommitMap[commit.SHA]; ok {
					continue ChangesLoop
				}
			}

			storyGroup.Changes = append(storyGroup.Changes, change)
		}

		if len(storyGroup.Changes) != 0 {
			toCherryPick = append(toCherryPick, storyGroup)
		}
	}

	return toCherryPick, nil
}
<|endoftext|>


<commit_before>package irmago

import "strings"

type objectIdentifier string

// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type SchemeManagerIdentifier struct {
	objectIdentifier
}

// IssuerIdentifier identifies an inssuer. For example "irma-demo.RU".
type IssuerIdentifier struct {
	objectIdentifier
}

// CredentialTypeIdentifier identifies a credentialtype. For example "irma-demo.RU.studentCard".
type CredentialTypeIdentifier struct {
	objectIdentifier
}

// AttributeIdentifier identifies an attribute. For example "irma-demo.RU.studentCard.studentID".
type AttributeIdentifier struct {
	objectIdentifier
}

func (oi objectIdentifier) Parent() string {
	str := string(oi)
	return str[:strings.LastIndex(str, "/")]
}

func (oi objectIdentifier) Name() string {
	str := string(oi)
	return str[strings.LastIndex(str, "/")+1:]
}

func (oi objectIdentifier) String() string {
	return string(oi)
}

// NewSchemeManagerIdentifier converts the specified identifier to a SchemeManagerIdentifier.
func NewSchemeManagerIdentifier(id string) SchemeManagerIdentifier {
	return SchemeManagerIdentifier{objectIdentifier(id)}
}

// NewIssuerIdentifier converts the specified identifier to a IssuerIdentifier.
func NewIssuerIdentifier(id string) IssuerIdentifier {
	return IssuerIdentifier{objectIdentifier(id)}
}

// NewCredentialTypeIdentifier converts the specified identifier to a CredentialTypeIdentifier.
func NewCredentialTypeIdentifier(id string) CredentialTypeIdentifier {
	return CredentialTypeIdentifier{objectIdentifier(id)}
}

// NewAttributeIdentifier converts the specified identifier to a AttributeIdentifier.
func NewAttributeIdentifier(id string) AttributeIdentifier {
	return AttributeIdentifier{objectIdentifier(id)}
}

// SchemeManagerIdentifier returns the scheme manager identifer of the issuer.
func (id IssuerIdentifier) SchemeManagerIdentifier() SchemeManagerIdentifier {
	return NewSchemeManagerIdentifier(id.Parent())
}

// IssuerIdentifier returns the IssuerIdentifier of the credential identifier.
func (id CredentialTypeIdentifier) IssuerIdentifier() IssuerIdentifier {
	return NewIssuerIdentifier(id.Parent())
}

// CredentialTypeIdentifier returns the CredentialTypeIdentifier of the attribute identifier.
func (id AttributeIdentifier) CredentialTypeIdentifier() CredentialTypeIdentifier {
	return NewCredentialTypeIdentifier(id.Parent())
}
<commit_msg>Fix silly mistake<commit_after>package irmago

import "strings"

type objectIdentifier string

// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type SchemeManagerIdentifier struct {
	objectIdentifier
}

// IssuerIdentifier identifies an inssuer. For example "irma-demo.RU".
type IssuerIdentifier struct {
	objectIdentifier
}

// CredentialTypeIdentifier identifies a credentialtype. For example "irma-demo.RU.studentCard".
type CredentialTypeIdentifier struct {
	objectIdentifier
}

// AttributeIdentifier identifies an attribute. For example "irma-demo.RU.studentCard.studentID".
type AttributeIdentifier struct {
	objectIdentifier
}

func (oi objectIdentifier) Parent() string {
	str := string(oi)
	return str[:strings.LastIndex(str, ".")]
}

func (oi objectIdentifier) Name() string {
	str := string(oi)
	return str[strings.LastIndex(str, ".")+1:]
}

func (oi objectIdentifier) String() string {
	return string(oi)
}

// NewSchemeManagerIdentifier converts the specified identifier to a SchemeManagerIdentifier.
func NewSchemeManagerIdentifier(id string) SchemeManagerIdentifier {
	return SchemeManagerIdentifier{objectIdentifier(id)}
}

// NewIssuerIdentifier converts the specified identifier to a IssuerIdentifier.
func NewIssuerIdentifier(id string) IssuerIdentifier {
	return IssuerIdentifier{objectIdentifier(id)}
}

// NewCredentialTypeIdentifier converts the specified identifier to a CredentialTypeIdentifier.
func NewCredentialTypeIdentifier(id string) CredentialTypeIdentifier {
	return CredentialTypeIdentifier{objectIdentifier(id)}
}

// NewAttributeIdentifier converts the specified identifier to a AttributeIdentifier.
func NewAttributeIdentifier(id string) AttributeIdentifier {
	return AttributeIdentifier{objectIdentifier(id)}
}

// SchemeManagerIdentifier returns the scheme manager identifer of the issuer.
func (id IssuerIdentifier) SchemeManagerIdentifier() SchemeManagerIdentifier {
	return NewSchemeManagerIdentifier(id.Parent())
}

// IssuerIdentifier returns the IssuerIdentifier of the credential identifier.
func (id CredentialTypeIdentifier) IssuerIdentifier() IssuerIdentifier {
	return NewIssuerIdentifier(id.Parent())
}

// CredentialTypeIdentifier returns the CredentialTypeIdentifier of the attribute identifier.
func (id AttributeIdentifier) CredentialTypeIdentifier() CredentialTypeIdentifier {
	return NewCredentialTypeIdentifier(id.Parent())
}
<|endoftext|>


<commit_before>package irmago

import "strings"

type objectIdentifier string

// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type SchemeManagerIdentifier struct {
	objectIdentifier
}

// IssuerIdentifier identifies an inssuer. For example "irma-demo.RU".
type IssuerIdentifier struct {
	objectIdentifier
}

// CredentialTypeIdentifier identifies a credentialtype. For example "irma-demo.RU.studentCard".
type CredentialTypeIdentifier struct {
	objectIdentifier
}

// AttributeTypeIdentifier identifies an attribute. For example "irma-demo.RU.studentCard.studentID".
type AttributeTypeIdentifier struct {
	objectIdentifier
}

func (oi objectIdentifier) Parent() string {
	str := string(oi)
	return str[:strings.LastIndex(str, ".")]
}

func (oi objectIdentifier) Name() string {
	str := string(oi)
	return str[strings.LastIndex(str, ".")+1:]
}

func (oi objectIdentifier) String() string {
	return string(oi)
}

// NewSchemeManagerIdentifier converts the specified identifier to a SchemeManagerIdentifier.
func NewSchemeManagerIdentifier(id string) SchemeManagerIdentifier {
	return SchemeManagerIdentifier{objectIdentifier(id)}
}

// NewIssuerIdentifier converts the specified identifier to a IssuerIdentifier.
func NewIssuerIdentifier(id string) IssuerIdentifier {
	return IssuerIdentifier{objectIdentifier(id)}
}

// NewCredentialTypeIdentifier converts the specified identifier to a CredentialTypeIdentifier.
func NewCredentialTypeIdentifier(id string) CredentialTypeIdentifier {
	return CredentialTypeIdentifier{objectIdentifier(id)}
}

// NewAttributeTypeIdentifier converts the specified identifier to a AttributeTypeIdentifier.
func NewAttributeTypeIdentifier(id string) AttributeTypeIdentifier {
	return AttributeTypeIdentifier{objectIdentifier(id)}
}

// SchemeManagerIdentifier returns the scheme manager identifer of the issuer.
func (id IssuerIdentifier) SchemeManagerIdentifier() SchemeManagerIdentifier {
	return NewSchemeManagerIdentifier(id.Parent())
}

// IssuerIdentifier returns the IssuerIdentifier of the credential identifier.
func (id CredentialTypeIdentifier) IssuerIdentifier() IssuerIdentifier {
	return NewIssuerIdentifier(id.Parent())
}

// CredentialTypeIdentifier returns the CredentialTypeIdentifier of the attribute identifier.
func (id AttributeTypeIdentifier) CredentialTypeIdentifier() CredentialTypeIdentifier {
	return NewCredentialTypeIdentifier(id.Parent())
}
<commit_msg>More renaming<commit_after>package irmago

import "strings"

type metaObjectIdentifier string

// SchemeManagerIdentifier identifies a scheme manager. Equal to its ID. For example "irma-demo".
type SchemeManagerIdentifier struct {
	metaObjectIdentifier
}

// IssuerIdentifier identifies an inssuer. For example "irma-demo.RU".
type IssuerIdentifier struct {
	metaObjectIdentifier
}

// CredentialTypeIdentifier identifies a credentialtype. For example "irma-demo.RU.studentCard".
type CredentialTypeIdentifier struct {
	metaObjectIdentifier
}

// AttributeTypeIdentifier identifies an attribute. For example "irma-demo.RU.studentCard.studentID".
type AttributeTypeIdentifier struct {
	metaObjectIdentifier
}

func (oi metaObjectIdentifier) Parent() string {
	str := string(oi)
	return str[:strings.LastIndex(str, ".")]
}

func (oi metaObjectIdentifier) Name() string {
	str := string(oi)
	return str[strings.LastIndex(str, ".")+1:]
}

func (oi metaObjectIdentifier) String() string {
	return string(oi)
}

// NewSchemeManagerIdentifier converts the specified identifier to a SchemeManagerIdentifier.
func NewSchemeManagerIdentifier(id string) SchemeManagerIdentifier {
	return SchemeManagerIdentifier{metaObjectIdentifier(id)}
}

// NewIssuerIdentifier converts the specified identifier to a IssuerIdentifier.
func NewIssuerIdentifier(id string) IssuerIdentifier {
	return IssuerIdentifier{metaObjectIdentifier(id)}
}

// NewCredentialTypeIdentifier converts the specified identifier to a CredentialTypeIdentifier.
func NewCredentialTypeIdentifier(id string) CredentialTypeIdentifier {
	return CredentialTypeIdentifier{metaObjectIdentifier(id)}
}

// NewAttributeTypeIdentifier converts the specified identifier to a AttributeTypeIdentifier.
func NewAttributeTypeIdentifier(id string) AttributeTypeIdentifier {
	return AttributeTypeIdentifier{metaObjectIdentifier(id)}
}

// SchemeManagerIdentifier returns the scheme manager identifer of the issuer.
func (id IssuerIdentifier) SchemeManagerIdentifier() SchemeManagerIdentifier {
	return NewSchemeManagerIdentifier(id.Parent())
}

// IssuerIdentifier returns the IssuerIdentifier of the credential identifier.
func (id CredentialTypeIdentifier) IssuerIdentifier() IssuerIdentifier {
	return NewIssuerIdentifier(id.Parent())
}

// CredentialTypeIdentifier returns the CredentialTypeIdentifier of the attribute identifier.
func (id AttributeTypeIdentifier) CredentialTypeIdentifier() CredentialTypeIdentifier {
	return NewCredentialTypeIdentifier(id.Parent())
}
<|endoftext|>


<commit_before>package kdtree

import (
	"alg"
	"ellipsoid"
	"errors"
	"fmt"
	"geo"
	"graph"
	"log"
	"math"
	"mm"
	"path"
)

var (
	e             ellipsoid.Ellipsoid
	clusterKdTree ClusterKdTree
)

func init() {
	e = ellipsoid.Init("WGS84", ellipsoid.Degrees, ellipsoid.Meter, ellipsoid.Longitude_is_symmetric, ellipsoid.Bearing_is_symmetric)
}

func LoadKdTree(clusterGraph *graph.ClusterGraph, base string) error {
	// TODO Does the precomputation of the coordinates lead to faster live queries?
	// It is not yet clear whether this pays off. The downside is increased memory usage.
	dummyCoordinates := make([]geo.Coordinate, 0)

	// Load the k-d tree of all clusters
	clusterKdTrees := make([]*KdTree, len(clusterGraph.Cluster))
	for i, g := range clusterGraph.Cluster {
		clusterDir := fmt.Sprintf("cluster%d/kdtree.ftf", i+1)
		var encodedSteps []uint64
		err := mm.Open(path.Join(base, clusterDir), &encodedSteps)
		if err != nil {
			return err
		}
		clusterKdTrees[i] = &KdTree{Graph: g, EncodedSteps: encodedSteps, Coordinates: dummyCoordinates}
	}

	// Load the k-d tree of the overlay graph
	var encodedSteps []uint64
	err := mm.Open(path.Join(base, "/overlay/kdtree.ftf"), &encodedSteps)
	if err != nil {
		return err
	}
	overlayKdTree := &KdTree{Graph: clusterGraph.Overlay, EncodedSteps: encodedSteps, Coordinates: dummyCoordinates}

	// Load the bounding boxes of the clusters
	var bboxesFile []int32
	err = mm.Open(path.Join(base, "bboxes.ftf"), &bboxesFile)
	if err != nil {
		return err
	}
	if len(bboxesFile)/4 != clusterGraph.Overlay.ClusterCount() {
		return errors.New("size of bboxes file does not match cluster count")
	}
	bboxes := make([]geo.BBox, len(bboxesFile)/4)
	for i, _ := range bboxes {
		bboxes[i] = geo.DecodeBBox(bboxesFile[4*i : 4*i+4])
	}

	clusterKdTree = ClusterKdTree{Overlay: overlayKdTree, Cluster: clusterKdTrees, BBoxes: bboxes}
	return nil
}

// NearestNeighbor returns -1 if the way is on the overlay graph
// No fail strategy: a nearest point on the overlay graph is always returned if no point
// is found in the clusters.
func NearestNeighbor(x geo.Coordinate, forward bool, trans graph.Transport) (int, []graph.Way) {
	fmt.Printf("nearest neighbor for (%v, %v)\n", x.Lat, x.Lng)

	edges := []graph.Edge(nil)

	// first search on the overlay graph
	overlay := clusterKdTree.Overlay
	bestStepIndex, coordOverlay, foundPoint := binarySearch(overlay, x, 0, overlay.EncodedStepLen()-1,
		true /* compareLat */, trans, &edges)
	minDistance, _ := e.To(x.Lat, x.Lng, coordOverlay.Lat, coordOverlay.Lng)

	fmt.Printf("overlay (%v, %v) -> %v, %v\n", coordOverlay.Lat, coordOverlay.Lng, minDistance, foundPoint)

	// then search on all clusters where the point is inside the bounding box of the cluster
	clusterIndex := -1
	for i, b := range clusterKdTree.BBoxes {
		if b.Contains(x) {
			fmt.Printf("cluster %d\n", i)

			kdTree := clusterKdTree.Cluster[i]
			stepIndex, coord, ok := binarySearch(kdTree, x, 0, kdTree.EncodedStepLen()-1, true /* compareLat */, trans, &edges)
			dist, _ := e.To(x.Lat, x.Lng, coord.Lat, coord.Lng)

			fmt.Printf("cluster %d (%v, %v) -> %v, %v\n", i, coord.Lat, coord.Lng, dist, ok)

			if ok && (!foundPoint || dist < minDistance) {
				foundPoint = true
				minDistance = dist
				bestStepIndex = stepIndex
				clusterIndex = i
			}
		}
	}

	if clusterIndex >= 0 {
		kdTree := clusterKdTree.Cluster[clusterIndex]
		return clusterIndex, decodeWays(kdTree.Graph, kdTree.EncodedStep(bestStepIndex), forward, trans, &edges)
	}
	log.Printf("no matching bounding box found for (%v, %v)", x.Lat, x.Lng)
	return clusterIndex, decodeWays(overlay.Graph, overlay.EncodedStep(bestStepIndex), forward, trans, &edges)
}

// binarySearch in one k-d tree. The index, the coordinate, and if the returned step/vertex
// is accessible are returned.
func binarySearch(kdTree *KdTree, x geo.Coordinate, start, end int, compareLat bool,
	trans graph.Transport, edges *[]graph.Edge) (int, geo.Coordinate, bool) {
	g := kdTree.Graph

	if end-start <= 0 {
		startCoord, startAccessible := decodeCoordinate(g, kdTree.EncodedStep(start), trans, edges)
		return start, startCoord, startAccessible
	}

	/*if end-start < 0 {
		panic("nearestNeighbor: recursion to dead end")
	} else if end-start == 0 {
		startCoord, startAccessible := decodeCoordinate(g, kdTree.EncodedStep(start), trans, edges)
		return start, startCoord, startAccessible
	}*/
	middle := (end-start)/2 + start

	// exact hit
	middleCoord, middleAccessible := decodeCoordinate(g, kdTree.EncodedStep(middle), trans, edges)
	if middleAccessible && x.Lat == middleCoord.Lat && x.Lng == middleCoord.Lng {
		return middle, middleCoord, middleAccessible
	}

	// corner case where the nearest point can be on both sides of the middle
	if !middleAccessible || (compareLat && x.Lat == middleCoord.Lat) || (!compareLat && x.Lng == middleCoord.Lng) {
		// recursion on both halfs
		leftRecIndex, leftCoord, leftAccessible := binarySearch(kdTree, x, start, middle-1, !compareLat, trans, edges)
		rightRecIndex, rightCoord, rightAccessible := binarySearch(kdTree, x, middle+1, end, !compareLat, trans, edges)

		if !middleAccessible && !leftAccessible && !rightAccessible {
			return middle, middleCoord, middleAccessible
		}

		// Infinity is used if a vertex/step it is not accessible as we know that at least one is accessible.
		distMiddle := math.Inf(1)
		distRecursionLeft := math.Inf(1)
		distRecursionRight := math.Inf(1)
		if middleAccessible {
			distMiddle, _ = e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
		}
		if leftAccessible {
			distRecursionLeft, _ = e.To(x.Lat, x.Lng, leftCoord.Lat, leftCoord.Lng)
		}
		if rightAccessible {
			distRecursionRight, _ = e.To(x.Lat, x.Lng, rightCoord.Lat, rightCoord.Lng)
		}

		if distRecursionLeft < distRecursionRight {
			if distRecursionLeft < distMiddle {
				return leftRecIndex, leftCoord, leftAccessible
			}
			return middle, middleCoord, middleAccessible
		}
		if distRecursionRight < distMiddle {
			return rightRecIndex, rightCoord, rightAccessible
		}
		return middle, middleCoord, middleAccessible
	}

	var left bool
	if compareLat {
		left = x.Lat < middleCoord.Lat
	} else {
		left = x.Lng < middleCoord.Lng
	}
	if left {
		// stop if there is nothing left of the middle
		if middle == start {
			return middle, middleCoord, middleAccessible
		}
		// recursion on the left half
		recIndex, recCoord, recAccessible := binarySearch(kdTree, x, start, middle-1, !compareLat, trans, edges)

		// compare middle and result from the left
		distMiddle, _ := e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
		distRecursion, _ := e.To(x.Lat, x.Lng, recCoord.Lat, recCoord.Lng)
		if !recAccessible || distMiddle < distRecursion {
			return middle, middleCoord, middleAccessible
		}
		return recIndex, recCoord, recAccessible
	}
	// stop if there is nothing right of the middle
	if middle == end {
		return middle, middleCoord, middleAccessible
	}
	// recursion on the right half
	recIndex, recCoord, recAccessible := binarySearch(kdTree, x, middle+1, end, !compareLat, trans, edges)

	// compare middle and result from the right
	distMiddle, _ := e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
	distRecursion, _ := e.To(x.Lat, x.Lng, recCoord.Lat, recCoord.Lng)
	if !recAccessible || distMiddle < distRecursion {
		return middle, middleCoord, middleAccessible
	}
	return recIndex, recCoord, recAccessible
}

// decodeCoordinate returns the coordinate of the encoded vertex/step and if it is accessible by the
// given transport mode
func decodeCoordinate(g graph.Graph, ec uint64, trans graph.Transport, edges *[]graph.Edge) (geo.Coordinate, bool) {
	vertexIndex := ec >> (EdgeOffsetBits + StepOffsetBits)
	edgeOffset := (ec >> StepOffsetBits) & MaxEdgeOffset
	stepOffset := ec & MaxStepOffset
	vertex := graph.Vertex(vertexIndex)
	if edgeOffset == MaxEdgeOffset && stepOffset == MaxStepOffset {
		// it is a vertex and not a step
		return g.VertexCoordinate(vertex), g.VertexAccessible(vertex, trans)
	}

	var edge graph.Edge
	var edgeAccessible bool
	switch t := g.(type) {
	case *graph.GraphFile:
	case *graph.OverlayGraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		edge = (*edges)[edgeOffset]
		edgeAccessible = t.EdgeAccessible(edge, trans)
	default:
		panic("unexpected graph implementation")
	}
	steps := g.EdgeSteps(edge, vertex)
	if int(stepOffset) >= len(steps) {
		fmt.Printf("step out of bound (%v, %v, %v) len steps %v\n", vertexIndex, edgeOffset, stepOffset, len(steps))
	}
	return steps[stepOffset], edgeAccessible
}

// decodeWays returns one or two partital edges that are therefore called ways. Even for a vertex a
// way is returned so that later code only has to consider ways. The other cases are explained below.
func decodeWays(g graph.Graph, ec uint64, forward bool, trans graph.Transport, edges *[]graph.Edge) []graph.Way {
	vertexIndex := ec >> (EdgeOffsetBits + StepOffsetBits)
	edgeOffset := (ec >> StepOffsetBits) & MaxEdgeOffset
	offset := ec & MaxStepOffset
	vertex := graph.Vertex(vertexIndex)

	if edgeOffset == MaxEdgeOffset && offset == MaxStepOffset {
		// The easy case, where we hit some vertex exactly.
		w := make([]graph.Way, 1)
		target := g.VertexCoordinate(vertex)
		w[0] = graph.Way{Length: 0, Vertex: vertex, Steps: nil, Target: target}
		return w
	}

	var edge graph.Edge
	oneway := false
	switch t := g.(type) {
	case *graph.GraphFile:
	case *graph.OverlayGraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		edge := (*edges)[edgeOffset]
		oneway = alg.GetBit(t.Oneway, uint(edge))
	default:
		panic("unexpected graph implementation")
	}
	if trans == graph.Foot {
		oneway = false
	}

	t1 := vertex                       // start vertex
	t2 := g.EdgeOpposite(edge, vertex) // end vertex

	// now we can allocate the way corresponding to (edge,offset),
	// but there are three cases to consider:
	// - if the way is bidirectional we have to compute both directions,
	//   if forward == true the from the offset two both endpoints,
	//   and the reverse otherwise
	// - if the way is unidirectional then we have to compute the way
	//   from the StartPoint to offset if forward == false
	// - otherwise we have to compute the way from offset to the EndPoint
	// Strictly speaking only the second case needs an additional binary
	// search in the form of edge.StartPoint, but let's keep this simple
	// for now.
	steps := g.EdgeSteps(edge, vertex)

	fmt.Printf("way: vertex %v, edge offset: %v, step offset: %v (%v)\n", vertex, edgeOffset, offset, len(steps))

	b1 := make([]geo.Coordinate, len(steps[:offset]))
	b2 := make([]geo.Coordinate, len(steps[offset+1:]))
	copy(b1, steps[:offset])
	copy(b2, steps[offset+1:])
	l1 := geo.StepLength(steps[:offset+1])
	l2 := geo.StepLength(steps[offset:])
	t1Coord := g.VertexCoordinate(t1)
	t2Coord := g.VertexCoordinate(t2)
	d1, _ := e.To(t1Coord.Lat, t1Coord.Lng, steps[0].Lat, steps[0].Lng)
	d2, _ := e.To(t2Coord.Lat, t2Coord.Lng, steps[len(steps)-1].Lat, steps[len(steps)-1].Lng)
	l1 += d1
	l2 += d2
	target := steps[offset]

	if !forward {
		reverse(b2)
	} else {
		reverse(b1)
	}

	var w []graph.Way
	if !oneway {
		w = make([]graph.Way, 2) // bidirectional
		w[0] = graph.Way{Length: l1, Vertex: t1, Steps: b1, Forward: forward, Target: target}
		w[1] = graph.Way{Length: l2, Vertex: t2, Steps: b2, Forward: forward, Target: target}
	} else {
		w = make([]graph.Way, 1) // one way
		if forward {
			w[0] = graph.Way{Length: l2, Vertex: t2, Steps: b2, Forward: forward, Target: target}
		} else {
			w[0] = graph.Way{Length: l1, Vertex: t1, Steps: b1, Forward: forward, Target: target}
		}
	}
	return w
}

func reverse(steps []geo.Coordinate) {
	for i, j := 0, len(steps)-1; i < j; i, j = i+1, j-1 {
		steps[i], steps[j] = steps[j], steps[i]
	}
}
<commit_msg>fixed nearest neighbor<commit_after>package kdtree

import (
	"alg"
	"ellipsoid"
	"errors"
	"fmt"
	"geo"
	"graph"
	"log"
	"math"
	"mm"
	"path"
)

var (
	e             ellipsoid.Ellipsoid
	clusterKdTree ClusterKdTree
)

func init() {
	e = ellipsoid.Init("WGS84", ellipsoid.Degrees, ellipsoid.Meter, ellipsoid.Longitude_is_symmetric, ellipsoid.Bearing_is_symmetric)
}

func LoadKdTree(clusterGraph *graph.ClusterGraph, base string) error {
	// TODO Does the precomputation of the coordinates lead to faster live queries?
	// It is not yet clear whether this pays off. The downside is increased memory usage.
	dummyCoordinates := make([]geo.Coordinate, 0)

	// Load the k-d tree of all clusters
	clusterKdTrees := make([]*KdTree, len(clusterGraph.Cluster))
	for i, g := range clusterGraph.Cluster {
		clusterDir := fmt.Sprintf("cluster%d/kdtree.ftf", i+1)
		var encodedSteps []uint64
		err := mm.Open(path.Join(base, clusterDir), &encodedSteps)
		if err != nil {
			return err
		}
		clusterKdTrees[i] = &KdTree{Graph: g, EncodedSteps: encodedSteps, Coordinates: dummyCoordinates}
	}

	// Load the k-d tree of the overlay graph
	var encodedSteps []uint64
	err := mm.Open(path.Join(base, "/overlay/kdtree.ftf"), &encodedSteps)
	if err != nil {
		return err
	}
	overlayKdTree := &KdTree{Graph: clusterGraph.Overlay, EncodedSteps: encodedSteps, Coordinates: dummyCoordinates}

	// Load the bounding boxes of the clusters
	var bboxesFile []int32
	err = mm.Open(path.Join(base, "bboxes.ftf"), &bboxesFile)
	if err != nil {
		return err
	}
	if len(bboxesFile)/4 != clusterGraph.Overlay.ClusterCount() {
		return errors.New("size of bboxes file does not match cluster count")
	}
	bboxes := make([]geo.BBox, len(bboxesFile)/4)
	for i, _ := range bboxes {
		bboxes[i] = geo.DecodeBBox(bboxesFile[4*i : 4*i+4])
	}

	clusterKdTree = ClusterKdTree{Overlay: overlayKdTree, Cluster: clusterKdTrees, BBoxes: bboxes}
	return nil
}

// NearestNeighbor returns -1 if the way is on the overlay graph
// No fail strategy: a nearest point on the overlay graph is always returned if no point
// is found in the clusters.
func NearestNeighbor(x geo.Coordinate, forward bool, trans graph.Transport) (int, []graph.Way) {
	fmt.Printf("nearest neighbor for (%v, %v)\n", x.Lat, x.Lng)

	edges := []graph.Edge(nil)

	// first search on the overlay graph
	overlay := clusterKdTree.Overlay
	bestStepIndex, coordOverlay, foundPoint := binarySearch(overlay, x, 0, overlay.EncodedStepLen()-1,
		true /* compareLat */, trans, &edges)
	minDistance, _ := e.To(x.Lat, x.Lng, coordOverlay.Lat, coordOverlay.Lng)

	fmt.Printf("overlay (%v, %v) -> %v, %v\n", coordOverlay.Lat, coordOverlay.Lng, minDistance, foundPoint)

	// then search on all clusters where the point is inside the bounding box of the cluster
	clusterIndex := -1
	for i, b := range clusterKdTree.BBoxes {
		if b.Contains(x) {
			fmt.Printf("cluster %d\n", i)

			kdTree := clusterKdTree.Cluster[i]
			stepIndex, coord, ok := binarySearch(kdTree, x, 0, kdTree.EncodedStepLen()-1, true /* compareLat */, trans, &edges)
			dist, _ := e.To(x.Lat, x.Lng, coord.Lat, coord.Lng)

			fmt.Printf("cluster %d (%v, %v) -> %v, %v\n", i, coord.Lat, coord.Lng, dist, ok)

			if ok && (!foundPoint || dist < minDistance) {
				foundPoint = true
				minDistance = dist
				bestStepIndex = stepIndex
				clusterIndex = i
			}
		}
	}

	if clusterIndex >= 0 {
		kdTree := clusterKdTree.Cluster[clusterIndex]
		return clusterIndex, decodeWays(kdTree.Graph, kdTree.EncodedStep(bestStepIndex), forward, trans, &edges)
	}
	log.Printf("no matching bounding box found for (%v, %v)", x.Lat, x.Lng)
	return clusterIndex, decodeWays(overlay.Graph, overlay.EncodedStep(bestStepIndex), forward, trans, &edges)
}

// binarySearch in one k-d tree. The index, the coordinate, and if the returned step/vertex
// is accessible are returned.
func binarySearch(kdTree *KdTree, x geo.Coordinate, start, end int, compareLat bool,
	trans graph.Transport, edges *[]graph.Edge) (int, geo.Coordinate, bool) {
	g := kdTree.Graph

	if end-start <= 0 {
		startCoord, startAccessible := decodeCoordinate(g, kdTree.EncodedStep(start), trans, edges)
		return start, startCoord, startAccessible
	}

	/*if end-start < 0 {
		panic("nearestNeighbor: recursion to dead end")
	} else if end-start == 0 {
		startCoord, startAccessible := decodeCoordinate(g, kdTree.EncodedStep(start), trans, edges)
		return start, startCoord, startAccessible
	}*/
	middle := (end-start)/2 + start

	// exact hit
	middleCoord, middleAccessible := decodeCoordinate(g, kdTree.EncodedStep(middle), trans, edges)
	if middleAccessible && x.Lat == middleCoord.Lat && x.Lng == middleCoord.Lng {
		return middle, middleCoord, middleAccessible
	}

	// corner case where the nearest point can be on both sides of the middle
	if !middleAccessible || (compareLat && x.Lat == middleCoord.Lat) || (!compareLat && x.Lng == middleCoord.Lng) {
		// recursion on both halfs
		leftRecIndex, leftCoord, leftAccessible := binarySearch(kdTree, x, start, middle-1, !compareLat, trans, edges)
		rightRecIndex, rightCoord, rightAccessible := binarySearch(kdTree, x, middle+1, end, !compareLat, trans, edges)

		if !middleAccessible && !leftAccessible && !rightAccessible {
			return middle, middleCoord, middleAccessible
		}

		// Infinity is used if a vertex/step it is not accessible as we know that at least one is accessible.
		distMiddle := math.Inf(1)
		distRecursionLeft := math.Inf(1)
		distRecursionRight := math.Inf(1)
		if middleAccessible {
			distMiddle, _ = e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
		}
		if leftAccessible {
			distRecursionLeft, _ = e.To(x.Lat, x.Lng, leftCoord.Lat, leftCoord.Lng)
		}
		if rightAccessible {
			distRecursionRight, _ = e.To(x.Lat, x.Lng, rightCoord.Lat, rightCoord.Lng)
		}

		if distRecursionLeft < distRecursionRight {
			if distRecursionLeft < distMiddle {
				return leftRecIndex, leftCoord, leftAccessible
			}
			return middle, middleCoord, middleAccessible
		}
		if distRecursionRight < distMiddle {
			return rightRecIndex, rightCoord, rightAccessible
		}
		return middle, middleCoord, middleAccessible
	}

	var left bool
	if compareLat {
		left = x.Lat < middleCoord.Lat
	} else {
		left = x.Lng < middleCoord.Lng
	}
	if left {
		// stop if there is nothing left of the middle
		if middle == start {
			return middle, middleCoord, middleAccessible
		}
		// recursion on the left half
		recIndex, recCoord, recAccessible := binarySearch(kdTree, x, start, middle-1, !compareLat, trans, edges)

		// compare middle and result from the left
		distMiddle, _ := e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
		distRecursion, _ := e.To(x.Lat, x.Lng, recCoord.Lat, recCoord.Lng)
		if !recAccessible || distMiddle < distRecursion {
			return middle, middleCoord, middleAccessible
		}
		return recIndex, recCoord, recAccessible
	}
	// stop if there is nothing right of the middle
	if middle == end {
		return middle, middleCoord, middleAccessible
	}
	// recursion on the right half
	recIndex, recCoord, recAccessible := binarySearch(kdTree, x, middle+1, end, !compareLat, trans, edges)

	// compare middle and result from the right
	distMiddle, _ := e.To(x.Lat, x.Lng, middleCoord.Lat, middleCoord.Lng)
	distRecursion, _ := e.To(x.Lat, x.Lng, recCoord.Lat, recCoord.Lng)
	if !recAccessible || distMiddle < distRecursion {
		return middle, middleCoord, middleAccessible
	}
	return recIndex, recCoord, recAccessible
}

// decodeCoordinate returns the coordinate of the encoded vertex/step and if it is accessible by the
// given transport mode
func decodeCoordinate(g graph.Graph, ec uint64, trans graph.Transport, edges *[]graph.Edge) (geo.Coordinate, bool) {
	vertexIndex := ec >> (EdgeOffsetBits + StepOffsetBits)
	edgeOffset := (ec >> StepOffsetBits) & MaxEdgeOffset
	stepOffset := ec & MaxStepOffset
	vertex := graph.Vertex(vertexIndex)
	if edgeOffset == MaxEdgeOffset && stepOffset == MaxStepOffset {
		// it is a vertex and not a step
		return g.VertexCoordinate(vertex), g.VertexAccessible(vertex, trans)
	}

	var edge graph.Edge
	var edgeAccessible bool
	switch t := g.(type) {
	case *graph.GraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		edgeAccessible = t.EdgeAccessible(edge, trans)
	case *graph.OverlayGraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		edgeAccessible = t.EdgeAccessible(edge, trans)
	default:
		panic("unexpected graph implementation")
	}
	edge = (*edges)[edgeOffset]
	steps := g.EdgeSteps(edge, vertex)
	if int(stepOffset) >= len(steps) {
		fmt.Printf("step out of bound (%v, %v, %v) len steps %v\n", vertexIndex, edgeOffset, stepOffset, len(steps))
	}

	return steps[stepOffset], edgeAccessible
}

// decodeWays returns one or two partital edges that are therefore called ways. Even for a vertex a
// way is returned so that later code only has to consider ways. The other cases are explained below.
func decodeWays(g graph.Graph, ec uint64, forward bool, trans graph.Transport, edges *[]graph.Edge) []graph.Way {
	vertexIndex := ec >> (EdgeOffsetBits + StepOffsetBits)
	edgeOffset := (ec >> StepOffsetBits) & MaxEdgeOffset
	offset := ec & MaxStepOffset
	vertex := graph.Vertex(vertexIndex)

	if edgeOffset == MaxEdgeOffset && offset == MaxStepOffset {
		// The easy case, where we hit some vertex exactly.
		w := make([]graph.Way, 1)
		target := g.VertexCoordinate(vertex)
		w[0] = graph.Way{Length: 0, Vertex: vertex, Steps: nil, Target: target}
		return w
	}

	var edge graph.Edge
	oneway := false
	switch t := g.(type) {
	case *graph.GraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		oneway = alg.GetBit(t.Oneway, uint(edge))
	case *graph.OverlayGraphFile:
		(*edges) = t.VertexRawEdges(vertex, *edges)
		oneway = alg.GetBit(t.Oneway, uint(edge))
	default:
		panic("unexpected graph implementation")
	}
	edge = (*edges)[edgeOffset]
	if trans == graph.Foot {
		oneway = false
	}

	t1 := vertex                       // start vertex
	t2 := g.EdgeOpposite(edge, vertex) // end vertex

	// now we can allocate the way corresponding to (edge,offset),
	// but there are three cases to consider:
	// - if the way is bidirectional we have to compute both directions,
	//   if forward == true the from the offset two both endpoints,
	//   and the reverse otherwise
	// - if the way is unidirectional then we have to compute the way
	//   from the StartPoint to offset if forward == false
	// - otherwise we have to compute the way from offset to the EndPoint
	// Strictly speaking only the second case needs an additional binary
	// search in the form of edge.StartPoint, but let's keep this simple
	// for now.
	steps := g.EdgeSteps(edge, vertex)

	b1 := make([]geo.Coordinate, len(steps[:offset]))
	b2 := make([]geo.Coordinate, len(steps[offset+1:]))
	copy(b1, steps[:offset])
	copy(b2, steps[offset+1:])
	l1 := geo.StepLength(steps[:offset+1])
	l2 := geo.StepLength(steps[offset:])
	t1Coord := g.VertexCoordinate(t1)
	t2Coord := g.VertexCoordinate(t2)
	d1, _ := e.To(t1Coord.Lat, t1Coord.Lng, steps[0].Lat, steps[0].Lng)
	d2, _ := e.To(t2Coord.Lat, t2Coord.Lng, steps[len(steps)-1].Lat, steps[len(steps)-1].Lng)
	l1 += d1
	l2 += d2
	target := steps[offset]

	if !forward {
		reverse(b2)
	} else {
		reverse(b1)
	}

	var w []graph.Way
	if !oneway {
		w = make([]graph.Way, 2) // bidirectional
		w[0] = graph.Way{Length: l1, Vertex: t1, Steps: b1, Forward: forward, Target: target}
		w[1] = graph.Way{Length: l2, Vertex: t2, Steps: b2, Forward: forward, Target: target}
	} else {
		w = make([]graph.Way, 1) // one way
		if forward {
			w[0] = graph.Way{Length: l2, Vertex: t2, Steps: b2, Forward: forward, Target: target}
		} else {
			w[0] = graph.Way{Length: l1, Vertex: t1, Steps: b1, Forward: forward, Target: target}
		}
	}
	return w
}

func reverse(steps []geo.Coordinate) {
	for i, j := 0, len(steps)-1; i < j; i, j = i+1, j-1 {
		steps[i], steps[j] = steps[j], steps[i]
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by an Apache License 2.0
// that can be found in the LICENSE file.

package jsonhttp

import (
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"

	"github.com/julienschmidt/httprouter"

	"github.com/stratumn/go/testutils"
)

func TestGet(t *testing.T) {
	s := New(&Config{})

	s.Get("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPost(t *testing.T) {
	s := New(&Config{})

	s.Post("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PostJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPut(t *testing.T) {
	s := New(&Config{})

	s.Put("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PutJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestDelete(t *testing.T) {
	s := New(&Config{})

	s.Delete("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.DeleteJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPatch(t *testing.T) {
	s := New(&Config{})

	s.Patch("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PatchJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestOptions(t *testing.T) {
	s := New(&Config{})

	s.Options("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.OptionsJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestNotFound(t *testing.T) {
	s := New(&Config{})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]interface{}
	res, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != NewErrNotFound("").Status() {
		t.Fatal("unexpected HTTP status")
	}

	if body["error"].(string) != NewErrNotFound("").Error() {
		t.Fatal("unexpected error")
	}

	if int(body["status"].(float64)) != NewErrNotFound("").Status() {
		t.Fatal("unexpected error HTTP status")
	}
}

func TestError(t *testing.T) {
	s := New(&Config{})

	s.Get("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return nil, NewErrBadRequest("no")
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]interface{}
	res, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != NewErrBadRequest("").Status() {
		t.Fatal("unexpected HTTP status")
	}

	if body["error"].(string) != "no" {
		t.Fatal("unexpected error")
	}

	if int(body["status"].(float64)) != NewErrBadRequest("").Status() {
		t.Fatal("unexpected error HTTP status")
	}
}
<commit_msg>Add jsonhttp test for non-ErrHTTP errors<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by an Apache License 2.0
// that can be found in the LICENSE file.

package jsonhttp

import (
	"errors"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"

	"github.com/julienschmidt/httprouter"

	"github.com/stratumn/go/testutils"
)

func TestGet(t *testing.T) {
	s := New(&Config{})

	s.Get("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPost(t *testing.T) {
	s := New(&Config{})

	s.Post("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PostJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPut(t *testing.T) {
	s := New(&Config{})

	s.Put("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PutJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestDelete(t *testing.T) {
	s := New(&Config{})

	s.Delete("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.DeleteJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestPatch(t *testing.T) {
	s := New(&Config{})

	s.Patch("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.PatchJSON(ts.URL+"/test", &body, nil)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestOptions(t *testing.T) {
	s := New(&Config{})

	s.Options("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return map[string]bool{"test": true}, nil
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]bool
	_, err := testutils.OptionsJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(body, map[string]bool{"test": true}) {
		t.Fatal("unexpected body")
	}
}

func TestNotFound(t *testing.T) {
	s := New(&Config{})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]interface{}
	res, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != NewErrNotFound("").Status() {
		t.Fatal("unexpected HTTP status")
	}

	if body["error"].(string) != NewErrNotFound("").Error() {
		t.Fatal("unexpected error")
	}

	if int(body["status"].(float64)) != NewErrNotFound("").Status() {
		t.Fatal("unexpected error HTTP status")
	}
}

func TestErrHTTP(t *testing.T) {
	s := New(&Config{})

	s.Get("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return nil, NewErrBadRequest("no")
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]interface{}
	res, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != NewErrBadRequest("").Status() {
		t.Fatal("unexpected HTTP status")
	}

	if body["error"].(string) != "no" {
		t.Fatal("unexpected error")
	}

	if int(body["status"].(float64)) != NewErrBadRequest("").Status() {
		t.Fatal("unexpected error HTTP status")
	}
}

func TestError(t *testing.T) {
	s := New(&Config{})

	s.Get("/test", func(r http.ResponseWriter, _ *http.Request, p httprouter.Params, _ *Config) (interface{}, error) {
		return nil, errors.New("no")
	})

	ts := httptest.NewServer(s)
	defer ts.Close()

	var body map[string]interface{}
	res, err := testutils.GetJSON(ts.URL+"/test", &body)
	if err != nil {
		t.Fatal(err)
	}

	if res.StatusCode != NewErrInternalServer("").Status() {
		t.Fatal("unexpected HTTP status")
	}

	if body["error"].(string) != NewErrInternalServer("").Error() {
		t.Fatal("unexpected error")
	}

	if int(body["status"].(float64)) != NewErrInternalServer("").Status() {
		t.Fatal("unexpected error HTTP status")
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 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 ssh

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"sync"
	"sync/atomic"
)

// debugMux, if set, causes messages in the connection protocol to be
// logged.
const debugMux = false

// chanList is a thread safe channel list.
type chanList struct {
	// protects concurrent access to chans
	sync.Mutex

	// chans are indexed by the local id of the channel, which the
	// other side should send in the PeersId field.
	chans []*channel

	// This is a debugging aid: it offsets all IDs by this
	// amount. This helps distinguish otherwise identical
	// server/client muxes
	offset uint32
}

// Assigns a channel ID to the given channel.
func (c *chanList) add(ch *channel) uint32 {
	c.Lock()
	defer c.Unlock()
	for i := range c.chans {
		if c.chans[i] == nil {
			c.chans[i] = ch
			return uint32(i) + c.offset
		}
	}
	c.chans = append(c.chans, ch)
	return uint32(len(c.chans)-1) + c.offset
}

// getChan returns the channel for the given ID.
func (c *chanList) getChan(id uint32) *channel {
	id -= c.offset

	c.Lock()
	defer c.Unlock()
	if id < uint32(len(c.chans)) {
		return c.chans[id]
	}
	return nil
}

func (c *chanList) remove(id uint32) {
	id -= c.offset
	c.Lock()
	if id < uint32(len(c.chans)) {
		c.chans[id] = nil
	}
	c.Unlock()
}

// dropAll forgets all channels it knows, returning them in a slice.
func (c *chanList) dropAll() []*channel {
	c.Lock()
	defer c.Unlock()
	var r []*channel

	for _, ch := range c.chans {
		if ch == nil {
			continue
		}
		r = append(r, ch)
	}
	c.chans = nil
	return r
}

// mux represents the state for the SSH connection protocol, which
// multiplexes many channels onto a single packet transport.
type mux struct {
	conn     packetConn
	chanList chanList

	incomingChannels chan NewChannel

	globalSentMu     sync.Mutex
	globalResponses  chan interface{}
	incomingRequests chan *Request

	errCond *sync.Cond
	err     error
}

// Each new chanList instantiation has a different offset.
var globalOff uint32

func (m *mux) Wait() error {
	m.errCond.L.Lock()
	defer m.errCond.L.Unlock()
	for m.err == nil {
		m.errCond.Wait()
	}
	return m.err
}

// newMux returns a mux that runs over the given connection.
func newMux(p packetConn) *mux {
	m := &mux{
		conn:             p,
		incomingChannels: make(chan NewChannel, 16),
		globalResponses:  make(chan interface{}, 1),
		incomingRequests: make(chan *Request, 16),
		errCond:          newCond(),
	}
	m.chanList.offset = atomic.AddUint32(&globalOff, 1)
	go m.loop()
	return m
}

func (m *mux) sendMessage(msg interface{}) error {
	p := Marshal(msg)
	return m.conn.writePacket(p)
}

func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
	if wantReply {
		m.globalSentMu.Lock()
		defer m.globalSentMu.Unlock()
	}

	if err := m.sendMessage(globalRequestMsg{
		Type:      name,
		WantReply: wantReply,
		Data:      payload,
	}); err != nil {
		return false, nil, err
	}

	if !wantReply {
		return false, nil, nil
	}

	msg, ok := <-m.globalResponses
	if !ok {
		return false, nil, io.EOF
	}
	switch msg := msg.(type) {
	case *globalRequestFailureMsg:
		return false, msg.Data, nil
	case *globalRequestSuccessMsg:
		return true, msg.Data, nil
	default:
		return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
	}
}

// ackRequest must be called after processing a global request that
// has WantReply set.
func (m *mux) ackRequest(ok bool, data []byte) error {
	if ok {
		return m.sendMessage(globalRequestSuccessMsg{Data: data})
	}
	return m.sendMessage(globalRequestFailureMsg{Data: data})
}

// TODO(hanwen): Disconnect is a transport layer message. We should
// probably send and receive Disconnect somewhere in the transport
// code.

// Disconnect sends a disconnect message.
func (m *mux) Disconnect(reason uint32, message string) error {
	return m.sendMessage(disconnectMsg{
		Reason:  reason,
		Message: message,
	})
}

func (m *mux) Close() error {
	return m.conn.Close()
}

// loop runs the connection machine. It will process packets until an
// error is encountered. To synchronize on loop exit, use mux.Wait.
func (m *mux) loop() {
	var err error
	for err == nil {
		err = m.onePacket()
	}

	for _, ch := range m.chanList.dropAll() {
		ch.close()
	}

	close(m.incomingChannels)
	close(m.incomingRequests)
	close(m.globalResponses)

	m.conn.Close()

	m.errCond.L.Lock()
	m.err = err
	m.errCond.Broadcast()
	m.errCond.L.Unlock()

	if debugMux {
		log.Println("loop exit", err)
	}
}

// onePacket reads and processes one packet.
func (m *mux) onePacket() error {
	packet, err := m.conn.readPacket()
	if err != nil {
		return err
	}

	if debugMux {
		if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
			log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
		} else {
			p, _ := decode(packet)
			log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
		}
	}

	switch packet[0] {
	case msgNewKeys:
		// Ignore notification of key change.
		return nil
	case msgDisconnect:
		return m.handleDisconnect(packet)
	case msgChannelOpen:
		return m.handleChannelOpen(packet)
	case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
		return m.handleGlobalPacket(packet)
	}

	// assume a channel packet.
	if len(packet) < 5 {
		return parseError(packet[0])
	}
	id := binary.BigEndian.Uint32(packet[1:])
	ch := m.chanList.getChan(id)
	if ch == nil {
		return fmt.Errorf("ssh: invalid channel %d", id)
	}

	return ch.handlePacket(packet)
}

func (m *mux) handleDisconnect(packet []byte) error {
	var d disconnectMsg
	if err := Unmarshal(packet, &d); err != nil {
		return err
	}

	if debugMux {
		log.Printf("caught disconnect: %v", d)
	}
	return &d
}

func (m *mux) handleGlobalPacket(packet []byte) error {
	msg, err := decode(packet)
	if err != nil {
		return err
	}

	switch msg := msg.(type) {
	case *globalRequestMsg:
		m.incomingRequests <- &Request{
			Type:      msg.Type,
			WantReply: msg.WantReply,
			Payload:   msg.Data,
			mux:       m,
		}
	case *globalRequestSuccessMsg, *globalRequestFailureMsg:
		m.globalResponses <- msg
	default:
		panic(fmt.Sprintf("not a global message %#v", msg))
	}

	return nil
}

// handleChannelOpen schedules a channel to be Accept()ed.
func (m *mux) handleChannelOpen(packet []byte) error {
	var msg channelOpenMsg
	if err := Unmarshal(packet, &msg); err != nil {
		return err
	}

	if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
		failMsg := channelOpenFailureMsg{
			PeersId:  msg.PeersId,
			Reason:   ConnectionFailed,
			Message:  "invalid request",
			Language: "en_US.UTF-8",
		}
		return m.sendMessage(failMsg)
	}

	c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
	c.remoteId = msg.PeersId
	c.maxRemotePayload = msg.MaxPacketSize
	c.remoteWin.add(msg.PeersWindow)
	m.incomingChannels <- c
	return nil
}

func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
	ch, err := m.openChannel(chanType, extra)
	if err != nil {
		return nil, nil, err
	}

	return ch, ch.incomingRequests, nil
}

func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
	ch := m.newChannel(chanType, channelOutbound, extra)

	ch.maxIncomingPayload = channelMaxPacket

	open := channelOpenMsg{
		ChanType:         chanType,
		PeersWindow:      ch.myWindow,
		MaxPacketSize:    ch.maxIncomingPayload,
		TypeSpecificData: extra,
		PeersId:          ch.localId,
	}
	if err := m.sendMessage(open); err != nil {
		return nil, err
	}

	switch msg := (<-ch.msg).(type) {
	case *channelOpenConfirmMsg:
		return ch, nil
	case *channelOpenFailureMsg:
		return nil, &OpenChannelError{msg.Reason, msg.Message}
	default:
		return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
	}
}
<commit_msg>go.crypto/ssh: only offset channel IDs when debugMux is set.<commit_after>// Copyright 2013 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 ssh

import (
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"sync"
	"sync/atomic"
)

// debugMux, if set, causes messages in the connection protocol to be
// logged.
const debugMux = false

// chanList is a thread safe channel list.
type chanList struct {
	// protects concurrent access to chans
	sync.Mutex

	// chans are indexed by the local id of the channel, which the
	// other side should send in the PeersId field.
	chans []*channel

	// This is a debugging aid: it offsets all IDs by this
	// amount. This helps distinguish otherwise identical
	// server/client muxes
	offset uint32
}

// Assigns a channel ID to the given channel.
func (c *chanList) add(ch *channel) uint32 {
	c.Lock()
	defer c.Unlock()
	for i := range c.chans {
		if c.chans[i] == nil {
			c.chans[i] = ch
			return uint32(i) + c.offset
		}
	}
	c.chans = append(c.chans, ch)
	return uint32(len(c.chans)-1) + c.offset
}

// getChan returns the channel for the given ID.
func (c *chanList) getChan(id uint32) *channel {
	id -= c.offset

	c.Lock()
	defer c.Unlock()
	if id < uint32(len(c.chans)) {
		return c.chans[id]
	}
	return nil
}

func (c *chanList) remove(id uint32) {
	id -= c.offset
	c.Lock()
	if id < uint32(len(c.chans)) {
		c.chans[id] = nil
	}
	c.Unlock()
}

// dropAll forgets all channels it knows, returning them in a slice.
func (c *chanList) dropAll() []*channel {
	c.Lock()
	defer c.Unlock()
	var r []*channel

	for _, ch := range c.chans {
		if ch == nil {
			continue
		}
		r = append(r, ch)
	}
	c.chans = nil
	return r
}

// mux represents the state for the SSH connection protocol, which
// multiplexes many channels onto a single packet transport.
type mux struct {
	conn     packetConn
	chanList chanList

	incomingChannels chan NewChannel

	globalSentMu     sync.Mutex
	globalResponses  chan interface{}
	incomingRequests chan *Request

	errCond *sync.Cond
	err     error
}

// When debugging, each new chanList instantiation has a different
// offset.
var globalOff uint32

func (m *mux) Wait() error {
	m.errCond.L.Lock()
	defer m.errCond.L.Unlock()
	for m.err == nil {
		m.errCond.Wait()
	}
	return m.err
}

// newMux returns a mux that runs over the given connection.
func newMux(p packetConn) *mux {
	m := &mux{
		conn:             p,
		incomingChannels: make(chan NewChannel, 16),
		globalResponses:  make(chan interface{}, 1),
		incomingRequests: make(chan *Request, 16),
		errCond:          newCond(),
	}
	if debugMux {
		m.chanList.offset = atomic.AddUint32(&globalOff, 1)
	}

	go m.loop()
	return m
}

func (m *mux) sendMessage(msg interface{}) error {
	p := Marshal(msg)
	return m.conn.writePacket(p)
}

func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
	if wantReply {
		m.globalSentMu.Lock()
		defer m.globalSentMu.Unlock()
	}

	if err := m.sendMessage(globalRequestMsg{
		Type:      name,
		WantReply: wantReply,
		Data:      payload,
	}); err != nil {
		return false, nil, err
	}

	if !wantReply {
		return false, nil, nil
	}

	msg, ok := <-m.globalResponses
	if !ok {
		return false, nil, io.EOF
	}
	switch msg := msg.(type) {
	case *globalRequestFailureMsg:
		return false, msg.Data, nil
	case *globalRequestSuccessMsg:
		return true, msg.Data, nil
	default:
		return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
	}
}

// ackRequest must be called after processing a global request that
// has WantReply set.
func (m *mux) ackRequest(ok bool, data []byte) error {
	if ok {
		return m.sendMessage(globalRequestSuccessMsg{Data: data})
	}
	return m.sendMessage(globalRequestFailureMsg{Data: data})
}

// TODO(hanwen): Disconnect is a transport layer message. We should
// probably send and receive Disconnect somewhere in the transport
// code.

// Disconnect sends a disconnect message.
func (m *mux) Disconnect(reason uint32, message string) error {
	return m.sendMessage(disconnectMsg{
		Reason:  reason,
		Message: message,
	})
}

func (m *mux) Close() error {
	return m.conn.Close()
}

// loop runs the connection machine. It will process packets until an
// error is encountered. To synchronize on loop exit, use mux.Wait.
func (m *mux) loop() {
	var err error
	for err == nil {
		err = m.onePacket()
	}

	for _, ch := range m.chanList.dropAll() {
		ch.close()
	}

	close(m.incomingChannels)
	close(m.incomingRequests)
	close(m.globalResponses)

	m.conn.Close()

	m.errCond.L.Lock()
	m.err = err
	m.errCond.Broadcast()
	m.errCond.L.Unlock()

	if debugMux {
		log.Println("loop exit", err)
	}
}

// onePacket reads and processes one packet.
func (m *mux) onePacket() error {
	packet, err := m.conn.readPacket()
	if err != nil {
		return err
	}

	if debugMux {
		if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
			log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
		} else {
			p, _ := decode(packet)
			log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
		}
	}

	switch packet[0] {
	case msgNewKeys:
		// Ignore notification of key change.
		return nil
	case msgDisconnect:
		return m.handleDisconnect(packet)
	case msgChannelOpen:
		return m.handleChannelOpen(packet)
	case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
		return m.handleGlobalPacket(packet)
	}

	// assume a channel packet.
	if len(packet) < 5 {
		return parseError(packet[0])
	}
	id := binary.BigEndian.Uint32(packet[1:])
	ch := m.chanList.getChan(id)
	if ch == nil {
		return fmt.Errorf("ssh: invalid channel %d", id)
	}

	return ch.handlePacket(packet)
}

func (m *mux) handleDisconnect(packet []byte) error {
	var d disconnectMsg
	if err := Unmarshal(packet, &d); err != nil {
		return err
	}

	if debugMux {
		log.Printf("caught disconnect: %v", d)
	}
	return &d
}

func (m *mux) handleGlobalPacket(packet []byte) error {
	msg, err := decode(packet)
	if err != nil {
		return err
	}

	switch msg := msg.(type) {
	case *globalRequestMsg:
		m.incomingRequests <- &Request{
			Type:      msg.Type,
			WantReply: msg.WantReply,
			Payload:   msg.Data,
			mux:       m,
		}
	case *globalRequestSuccessMsg, *globalRequestFailureMsg:
		m.globalResponses <- msg
	default:
		panic(fmt.Sprintf("not a global message %#v", msg))
	}

	return nil
}

// handleChannelOpen schedules a channel to be Accept()ed.
func (m *mux) handleChannelOpen(packet []byte) error {
	var msg channelOpenMsg
	if err := Unmarshal(packet, &msg); err != nil {
		return err
	}

	if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
		failMsg := channelOpenFailureMsg{
			PeersId:  msg.PeersId,
			Reason:   ConnectionFailed,
			Message:  "invalid request",
			Language: "en_US.UTF-8",
		}
		return m.sendMessage(failMsg)
	}

	c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
	c.remoteId = msg.PeersId
	c.maxRemotePayload = msg.MaxPacketSize
	c.remoteWin.add(msg.PeersWindow)
	m.incomingChannels <- c
	return nil
}

func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
	ch, err := m.openChannel(chanType, extra)
	if err != nil {
		return nil, nil, err
	}

	return ch, ch.incomingRequests, nil
}

func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
	ch := m.newChannel(chanType, channelOutbound, extra)

	ch.maxIncomingPayload = channelMaxPacket

	open := channelOpenMsg{
		ChanType:         chanType,
		PeersWindow:      ch.myWindow,
		MaxPacketSize:    ch.maxIncomingPayload,
		TypeSpecificData: extra,
		PeersId:          ch.localId,
	}
	if err := m.sendMessage(open); err != nil {
		return nil, err
	}

	switch msg := (<-ch.msg).(type) {
	case *channelOpenConfirmMsg:
		return ch, nil
	case *channelOpenFailureMsg:
		return nil, &OpenChannelError{msg.Reason, msg.Message}
	default:
		return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
	}
}
<|endoftext|>


<commit_before>package common

import (
	"log"
	"os/exec"

	// "github.com/jiasir/playback/command"
)

// NtpServer are the module args
type NtpServer struct {
	Server  string `json:"Server"`
	Changed bool   `json:"Changed"`
}

// InitNtpServer init the NtpServer struct
func (n *NtpServer) InitNtpServer(k, v interface{}) {
	switch k {
	case "Server":
		n.Server = v.(string)
	}
}
// this is the /etc/chrony/chrony.conf
const chrony = `
# This the default chrony.conf file for the Debian chrony package.  After
# editing this file use the command 'invoke-rc.d chrony restart' to make
# your changes take effect.  John Hasler <jhasler@debian.org> 1998-2008

# See www.pool.ntp.org for an explanation of these servers.  Please
# consider joining the project if possible.  If you can't or don't want to
# use these servers I suggest that you try your ISP's nameservers.  We mark
# the servers 'offline' so that chronyd won't try to connect when the link
# is down.  Scripts in /etc/ppp/ip-up.d and /etc/ppp/ip-down.d use chronyc
# commands to switch it on when a dialup link comes up and off when it goes
# down.  Code in /etc/init.d/chrony attempts to determine whether or not
# the link is up at boot time and set the online status accordingly.  If
# you have an always-on connection such as cable omit the 'offline'
# directive and chronyd will default to online.
#
# Note that if Chrony tries to go "online" and dns lookup of the servers
# fails they will be discarded.  Thus under some circumstances it is
# better to use IP numbers than host names.

server {{.Server}} iburst
server 0.debian.pool.ntp.org offline minpoll 8
server 1.debian.pool.ntp.org offline minpoll 8
server 2.debian.pool.ntp.org offline minpoll 8
server 3.debian.pool.ntp.org offline minpoll 8

# Look here for the admin password needed for chronyc.  The initial
# password is generated by a random process at install time.  You may
# change it if you wish.

keyfile /etc/chrony/chrony.keys

# Set runtime command key.  Note that if you change the key (not the
# password) to anything other than 1 you will need to edit
# /etc/ppp/ip-up.d/chrony, /etc/ppp/ip-down.d/chrony, /etc/init.d/chrony
# and /etc/cron.weekly/chrony as these scripts use it to get the password.

commandkey 1

# I moved the driftfile to /var/lib/chrony to comply with the Debian
# filesystem standard.

driftfile /var/lib/chrony/chrony.drift

# Comment this line out to turn off logging.

log tracking measurements statistics
logdir /var/log/chrony

# Stop bad estimates upsetting machine clock.

maxupdateskew 100.0

# Dump measurements when daemon exits.

dumponexit

# Specify directory for dumping measurements.

dumpdir /var/lib/chrony

# Let computer be a server when it is unsynchronised.

local stratum 10

# Allow computers on the unrouted nets to use the server.

allow 10/8
allow 192.168/16
allow 172.16/12

# This directive forces chronyd to send a message to syslog if it
# makes a system clock adjustment larger than a threshold value in seconds.

logchange 0.5

# This directive defines an email address to which mail should be sent
# if chronyd applies a correction exceeding a particular threshold to the
# system clock.

# mailonchange root@localhost 0.5

# This directive tells chrony to regulate the real-time clock and tells it
# Where to store related data.  It may not work on some newer motherboards
# that use the HPET real-time clock.  It requires enhanced real-time
# support in the kernel.  I've commented it out because with certain
# combinations of motherboard and kernel it is reported to cause lockups.

# rtcfile /var/lib/chrony/chrony.rtc

# If the last line of this file reads 'rtconutc' chrony will assume that
# the CMOS clock is on UTC (GMT).  If it reads '# rtconutc' or is absent
# chrony will assume local time.  The line (if any) was written by the
# chrony postinst based on what it found in /etc/default/rcS.  You may
# change it if necessary.
rtconutc
`

// InstallChrony install chrony for ntp server
func (n *NtpServer) InstallChrony() {
	cmd := exec.Command("sudo", "apt-get", "-y", "install", "chrony")
	if err := cmd.Run(); err != nil {
		log.Fatalf("Install Error: %v", err)
	}

	// parse the template to /etc/chrony/chrony.conf
	ParseTmpl(n, chrony, "ntpserver", "/etc/chrony/chrony.conf", 0644)

	cmd = exec.Command("sudo", "service", "chrony", "restart")
	if err := cmd.Run(); err != nil {
		log.Fatalf("Install Error: %v", err)
	}
}
<commit_msg>Remove all but one server key<commit_after>package common

import (
	"log"
	"os/exec"

	// "github.com/jiasir/playback/command"
)

// NtpServer are the module args
type NtpServer struct {
	Server  string `json:"Server"`
	Changed bool   `json:"Changed"`
}

// InitNtpServer init the NtpServer struct
func (n *NtpServer) InitNtpServer(k, v interface{}) {
	switch k {
	case "Server":
		n.Server = v.(string)
	}
}
// this is the /etc/chrony/chrony.conf
const chrony = `
# This the default chrony.conf file for the Debian chrony package.  After
# editing this file use the command 'invoke-rc.d chrony restart' to make
# your changes take effect.  John Hasler <jhasler@debian.org> 1998-2008

# See www.pool.ntp.org for an explanation of these servers.  Please
# consider joining the project if possible.  If you can't or don't want to
# use these servers I suggest that you try your ISP's nameservers.  We mark
# the servers 'offline' so that chronyd won't try to connect when the link
# is down.  Scripts in /etc/ppp/ip-up.d and /etc/ppp/ip-down.d use chronyc
# commands to switch it on when a dialup link comes up and off when it goes
# down.  Code in /etc/init.d/chrony attempts to determine whether or not
# the link is up at boot time and set the online status accordingly.  If
# you have an always-on connection such as cable omit the 'offline'
# directive and chronyd will default to online.
#
# Note that if Chrony tries to go "online" and dns lookup of the servers
# fails they will be discarded.  Thus under some circumstances it is
# better to use IP numbers than host names.

server {{.Server}} iburst

# Look here for the admin password needed for chronyc.  The initial
# password is generated by a random process at install time.  You may
# change it if you wish.

keyfile /etc/chrony/chrony.keys

# Set runtime command key.  Note that if you change the key (not the
# password) to anything other than 1 you will need to edit
# /etc/ppp/ip-up.d/chrony, /etc/ppp/ip-down.d/chrony, /etc/init.d/chrony
# and /etc/cron.weekly/chrony as these scripts use it to get the password.

commandkey 1

# I moved the driftfile to /var/lib/chrony to comply with the Debian
# filesystem standard.

driftfile /var/lib/chrony/chrony.drift

# Comment this line out to turn off logging.

log tracking measurements statistics
logdir /var/log/chrony

# Stop bad estimates upsetting machine clock.

maxupdateskew 100.0

# Dump measurements when daemon exits.

dumponexit

# Specify directory for dumping measurements.

dumpdir /var/lib/chrony

# Let computer be a server when it is unsynchronised.

local stratum 10

# Allow computers on the unrouted nets to use the server.

allow 10/8
allow 192.168/16
allow 172.16/12

# This directive forces chronyd to send a message to syslog if it
# makes a system clock adjustment larger than a threshold value in seconds.

logchange 0.5

# This directive defines an email address to which mail should be sent
# if chronyd applies a correction exceeding a particular threshold to the
# system clock.

# mailonchange root@localhost 0.5

# This directive tells chrony to regulate the real-time clock and tells it
# Where to store related data.  It may not work on some newer motherboards
# that use the HPET real-time clock.  It requires enhanced real-time
# support in the kernel.  I've commented it out because with certain
# combinations of motherboard and kernel it is reported to cause lockups.

# rtcfile /var/lib/chrony/chrony.rtc

# If the last line of this file reads 'rtconutc' chrony will assume that
# the CMOS clock is on UTC (GMT).  If it reads '# rtconutc' or is absent
# chrony will assume local time.  The line (if any) was written by the
# chrony postinst based on what it found in /etc/default/rcS.  You may
# change it if necessary.
rtconutc
`

// InstallChrony install chrony for ntp server
func (n *NtpServer) InstallChrony() {
	cmd := exec.Command("sudo", "apt-get", "-y", "install", "chrony")
	if err := cmd.Run(); err != nil {
		log.Fatalf("Install Error: %v", err)
	}

	// parse the template to /etc/chrony/chrony.conf
	ParseTmpl(n, chrony, "ntpserver", "/etc/chrony/chrony.conf", 0644)

	cmd = exec.Command("sudo", "service", "chrony", "restart")
	if err := cmd.Run(); err != nil {
		log.Fatalf("Install Error: %v", err)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"errors"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

type catsDB struct {
	CatsDataStore
	db *sql.DB
}

// NewCatsDB returns a new CatsDataStore
func NewCatsDB(dbURL string) CatsDataStore {
	db := connectToDB(dbURL)
	return &catsDB{
		db: db,
	}
}

// ConnectToDB connects to the database
func connectToDB(dbURL string) (db *sql.DB) {
	log.Printf("Connecting to DB[%s]....\n", dbURL)
	conn, err := sql.Open("mysql", dbURL)
	if err != nil {
		log.Fatal(err)
	}

	err = conn.Ping()
	if err != nil {
		log.Fatal(err)
	}

	return conn

}

func (dbWrapper *catsDB) ReadAllCats() (cats []*Cat, err error) {

	rows, err := dbWrapper.db.Query("select * from cats")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	cats = []*Cat{}
	for rows.Next() {
		cat := &Cat{}
		err = rows.Scan(
			&cat.ID,
			&cat.Name,
			&cat.Age,
			&cat.Type,
		)
		if err != nil {
			cats = nil
			return
		}
		cats = append(cats, cat)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return
}

func (dbWrapper *catsDB) CreateCat(cat *Cat) (err error) {

	stmt, err := dbWrapper.db.Prepare("insert into cats set cat_name=?, cat_age=?, cat_type=?")
	if err != nil {
		return
	}
	defer stmt.Close()

	res, err := stmt.Exec(cat.Name, cat.Age, cat.Type)
	if err != nil {
		return
	}
	cat.ID, err = res.LastInsertId()
	if err != nil {
		return
	}
	return
}

func (dbWrapper *catsDB) ReadCat(id int64) (cat *Cat, err error) {

	cat = &Cat{}
	err = dbWrapper.db.QueryRow(
		"select cat_id, cat_name, cat_age, cat_type from cats where cat_id=?", id).
		Scan(
		&cat.ID,
		&cat.Name,
		&cat.Age,
		&cat.Type)
	switch {
	case err == sql.ErrNoRows:
		cat = nil
	}

	return
}

func (dbWrapper *catsDB) UpdateCat(cat *Cat) (err error) {

	stmt, err := dbWrapper.db.Prepare("update cats set cat_name=?, cat_age=?, cat_type=? where cat_id = ?")
	if err != nil {
		return
	}
	defer stmt.Close()

	res, err := stmt.Exec(cat.Name, cat.Age, cat.Type, cat.ID)
	if err != nil {
		return
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return
	}
	if rowsAffected != 1 {
		err = errors.New("Unable to update cat")
	}

	return
}

func (dbWrapper *catsDB) DeleteCat(id int64) (err error) {

	stmt, err := dbWrapper.db.Prepare("delete from cats where cat_id=?")
	if err != nil {
		return
	}
	defer stmt.Close()
	_, err = stmt.Exec(id)

	return
}
<commit_msg>Changed DB variable name. Added explicit table column names.<commit_after>package models

import (
	"database/sql"
	"errors"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

type catsDB struct {
	CatsDataStore
	db *sql.DB
}

// NewCatsDB returns a new CatsDataStore
func NewCatsDB(dbURL string) CatsDataStore {
	db := connectToDB(dbURL)
	return &catsDB{
		db: db,
	}
}

// ConnectToDB connects to the database
func connectToDB(dbURL string) (db *sql.DB) {
	log.Printf("Connecting to DB[%s]....\n", dbURL)
	theDB, err := sql.Open("mysql", dbURL)
	if err != nil {
		log.Fatal(err)
	}

	err = theDB.Ping()
	if err != nil {
		log.Fatal(err)
	}

	return theDB

}

func (dbWrapper *catsDB) ReadAllCats() (cats []*Cat, err error) {

	rows, err := dbWrapper.db.Query("select cat_id, cat_name, cat_age, cat_type from cats")
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	cats = []*Cat{}
	for rows.Next() {
		cat := &Cat{}
		err = rows.Scan(
			&cat.ID,
			&cat.Name,
			&cat.Age,
			&cat.Type,
		)
		if err != nil {
			cats = nil
			return
		}
		cats = append(cats, cat)
	}

	if err = rows.Err(); err != nil {
		return nil, err
	}

	return
}

func (dbWrapper *catsDB) CreateCat(cat *Cat) (err error) {

	stmt, err := dbWrapper.db.Prepare("insert into cats set cat_name=?, cat_age=?, cat_type=?")
	if err != nil {
		return
	}
	defer stmt.Close()

	res, err := stmt.Exec(cat.Name, cat.Age, cat.Type)
	if err != nil {
		return
	}
	cat.ID, err = res.LastInsertId()
	if err != nil {
		return
	}
	return
}

func (dbWrapper *catsDB) ReadCat(id int64) (cat *Cat, err error) {

	cat = &Cat{}
	err = dbWrapper.db.QueryRow(
		"select cat_id, cat_name, cat_age, cat_type from cats where cat_id=?", id).
		Scan(
		&cat.ID,
		&cat.Name,
		&cat.Age,
		&cat.Type)
	switch {
	case err == sql.ErrNoRows:
		cat = nil
	}

	return
}

func (dbWrapper *catsDB) UpdateCat(cat *Cat) (err error) {

	stmt, err := dbWrapper.db.Prepare("update cats set cat_name=?, cat_age=?, cat_type=? where cat_id = ?")
	if err != nil {
		return
	}
	defer stmt.Close()

	res, err := stmt.Exec(cat.Name, cat.Age, cat.Type, cat.ID)
	if err != nil {
		return
	}

	rowsAffected, err := res.RowsAffected()
	if err != nil {
		return
	}
	if rowsAffected != 1 {
		err = errors.New("Unable to update cat")
	}

	return
}

func (dbWrapper *catsDB) DeleteCat(id int64) (err error) {

	stmt, err := dbWrapper.db.Prepare("delete from cats where cat_id=?")
	if err != nil {
		return
	}
	defer stmt.Close()
	_, err = stmt.Exec(id)

	return
}
<|endoftext|>


<commit_before>// Package hostcredentials implements a TransformationProvider that fetches
// credentials from the (oddly named) `host-secrets` service and replaces
// objects of the form: {$hostcredentials: [url, url]} with the credentials.
//
// The given URLs should point to the `/v1/credentials` endpoint of instances of the
// [taskcluster-host-secrets](https://github.com/taskcluster/taskcluster-host-secrets)
// service.  They will be tried in order until success.  This is a simple form
// of client-side resilience to failure of a single instance.
//
// Note that this transform will need to run before the "hostsecrets" transform.
package hostcredentials

import (
	"encoding/json"
	"log"
	"time"

	got "github.com/taskcluster/go-got"

	"github.com/taskcluster/taskcluster-worker/config"
)

type provider struct{}

func init() {
	config.Register("hostcredentials", provider{})
}

func (provider) Transform(cfg map[string]interface{}) error {
	g := got.New()

	return config.ReplaceObjects(cfg, "hostcredentials", func(val map[string]interface{}) (interface{}, error) {
		var urls []string
		for _, u := range val["$hostcredentials"].([]interface{}) {
			urls = append(urls, u.(string))
		}

		var creds struct {
			Credentials struct {
				ClientID    string `json:"clientId"`
				AccessToken string `json:"accessToken"`
				Certificate string `json:"certificate"`
			} `json:"credentials"`
		}

		for {
			for _, url := range urls {
				log.Printf("Trying host-secrets server %s...", url)

				resp, err := g.Get(url).Send()
				if err != nil {
					log.Printf("result: %s; continuing to next server", err)
					continue
				}

				err = json.Unmarshal(resp.Body, &creds)
				if err != nil {
					log.Printf("decoding JSON from server: %s; continuing to next server", err)
					continue
				}

				retval := map[string]interface{}{
					"clientId":    creds.Credentials.ClientID,
					"accessToken": creds.Credentials.AccessToken,
				}
				if creds.Credentials.Certificate != "" {
					retval["certificate"] = creds.Credentials.Certificate
				}
				return retval, nil
			}

			log.Printf("list of servers exhausted; sleeping before starting again")
			time.Sleep(60 * time.Second)
		}
	})
}
<commit_msg>log the clientID, too<commit_after>// Package hostcredentials implements a TransformationProvider that fetches
// credentials from the (oddly named) `host-secrets` service and replaces
// objects of the form: {$hostcredentials: [url, url]} with the credentials.
//
// The given URLs should point to the `/v1/credentials` endpoint of instances of the
// [taskcluster-host-secrets](https://github.com/taskcluster/taskcluster-host-secrets)
// service.  They will be tried in order until success.  This is a simple form
// of client-side resilience to failure of a single instance.
//
// Note that this transform will need to run before the "hostsecrets" transform.
package hostcredentials

import (
	"encoding/json"
	"log"
	"time"

	got "github.com/taskcluster/go-got"

	"github.com/taskcluster/taskcluster-worker/config"
)

type provider struct{}

func init() {
	config.Register("hostcredentials", provider{})
}

func (provider) Transform(cfg map[string]interface{}) error {
	g := got.New()

	return config.ReplaceObjects(cfg, "hostcredentials", func(val map[string]interface{}) (interface{}, error) {
		var urls []string
		for _, u := range val["$hostcredentials"].([]interface{}) {
			urls = append(urls, u.(string))
		}

		var creds struct {
			Credentials struct {
				ClientID    string `json:"clientId"`
				AccessToken string `json:"accessToken"`
				Certificate string `json:"certificate"`
			} `json:"credentials"`
		}

		for {
			for _, url := range urls {
				log.Printf("Trying host-secrets server %s...", url)

				resp, err := g.Get(url).Send()
				if err != nil {
					log.Printf("result: %s; continuing to next server", err)
					continue
				}

				err = json.Unmarshal(resp.Body, &creds)
				if err != nil {
					log.Printf("decoding JSON from server: %s; continuing to next server", err)
					continue
				}

				retval := map[string]interface{}{
					"clientId":    creds.Credentials.ClientID,
					"accessToken": creds.Credentials.AccessToken,
				}
				if creds.Credentials.Certificate != "" {
					retval["certificate"] = creds.Credentials.Certificate
				}
				log.Printf("Success: host-secrets server gave clientId %s...", creds.Credentials.ClientID)
				return retval, nil
			}

			log.Printf("list of servers exhausted; sleeping before starting again")
			time.Sleep(60 * time.Second)
		}
	})
}
<|endoftext|>