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

package main

import "testing"

func TestParseResourcesSuccess(t *testing.T) {
	ress := []string{
		"http://user:pass@localhost:foo/path?query=val#fragment",
		"https://user:pass@localhost:foo/path?query=val#fragment",

		"ws://user:pass@localhost:42/path?query=val#fragment",
		"wss://user:pass@localhost:42/path?query=val#fragment",

		"tcp://localhost:42",
		"tcp4://localhost:42",
		"tcp6://[::1]:42",

		"file://relative/path/to/file",
		"file://relative/path/to/file#absent",
		"file:///absolute/path/to/file",
		"file://absolute/path/to/file#absent",

		"postgres://user:pass@localhost:5432/dbname?query=val#fragment",

		"mysql://user:pass@localhost:3306/dbname?query=val#fragment",

		"command",
		"command with args",
		"relative/path/to/command",
		"relative/path/to/command with args",
		"/absolute/path/to/command",
		"/absolute/path/to/command with args",

		"",
	}

	actualRess, err := parseResources(ress)
	if err != nil {
		t.Errorf("failed to parse ressources")
	}
	if len(actualRess) != len(ress) {
		t.Errorf("missing parsed ressources")
	}
}

func TestParseResourcesFailure(t *testing.T) {
	_, err := parseResources([]string{"//foo test"})
	if err == nil {
		t.Errorf("expected error parsing invalid ressource")
	}
}

func TestParseFragment(t *testing.T) {
	tests := map[string]map[string]string{
		"":              map[string]string{},
		"=":             map[string]string{}, // invalid format, should be skipped
		"=ignore":       map[string]string{}, // invalid format, should be skipped
		"foo":           map[string]string{"foo": ""},
		"foo=":          map[string]string{"foo": ""},
		"foo=bar":       map[string]string{"foo": "bar"},
		"foo=bar&baz":   map[string]string{"foo": "bar", "baz": ""},
		"foo=bar&baz=1": map[string]string{"foo": "bar", "baz": "1"},
	}
	for given, expected := range tests {
		actual := parseFragment(given)
		if len(actual) != len(expected) {
			t.Errorf("unexpected parsed fragment count %d != %d: %#v",
				len(expected), len(actual), actual)
		}
		for actualK, actualV := range actual {
			if expectedV, ok := expected[actualK]; !ok || actualV[0] != expectedV {
				t.Errorf("unexpected parsed fragment k/v pair")
			}
		}
	}
}
<commit_msg>Update broken tests<commit_after>// Copyright (C) 2016-2018 Betalo AB
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package main

import "testing"

func TestParseResourcesSuccess(t *testing.T) {
	ress := []string{
		"http://user:pass@localhost:1234/path?query=val#fragment",
		"https://user:pass@localhost:1234/path?query=val#fragment",

		"ws://user:pass@localhost:42/path?query=val#fragment",
		"wss://user:pass@localhost:42/path?query=val#fragment",

		"tcp://localhost:42",
		"tcp4://localhost:42",
		"tcp6://[::1]:42",

		"file://relative/path/to/file",
		"file://relative/path/to/file#absent",
		"file:///absolute/path/to/file",
		"file://absolute/path/to/file#absent",

		"postgres://user:pass@localhost:5432/dbname?query=val#fragment",

		"mysql://user:pass@localhost:3306/dbname?query=val#fragment",

		"command",
		"command with args",
		"relative/path/to/command",
		"relative/path/to/command with args",
		"/absolute/path/to/command",
		"/absolute/path/to/command with args",

		"",
	}

	actualRess, err := parseResources(ress)
	if err != nil {
		t.Errorf("failed to parse ressources: %#v", err.Error())
	}
	if len(actualRess) != len(ress) {
		t.Errorf("missing parsed ressources")
	}
}

func TestParseResourcesFailure(t *testing.T) {
	_, err := parseResources([]string{"//foo test"})
	if err == nil {
		t.Errorf("expected error parsing invalid ressource")
	}
}

func TestParseFragment(t *testing.T) {
	tests := map[string]map[string]string{
		"":              map[string]string{},
		"=":             map[string]string{}, // invalid format, should be skipped
		"=ignore":       map[string]string{}, // invalid format, should be skipped
		"foo":           map[string]string{"foo": ""},
		"foo=":          map[string]string{"foo": ""},
		"foo=bar":       map[string]string{"foo": "bar"},
		"foo=bar&baz":   map[string]string{"foo": "bar", "baz": ""},
		"foo=bar&baz=1": map[string]string{"foo": "bar", "baz": "1"},
	}
	for given, expected := range tests {
		actual := parseFragment(given)
		if len(actual) != len(expected) {
			t.Errorf("unexpected parsed fragment count %d != %d: %#v",
				len(expected), len(actual), actual)
		}
		for actualK, actualV := range actual {
			if expectedV, ok := expected[actualK]; !ok || actualV[0] != expectedV {
				t.Errorf("unexpected parsed fragment k/v pair")
			}
		}
	}
}
<|endoftext|>


<commit_before>package adyen

import (
	"testing"
)

// TestResponseErrorResponseStatus - response is valid JSON, but status is > 299, error should be returned
func TestResponseErrorResponseStatus(t *testing.T) {
	t.Parallel()

	responseJSON := `
{
	"errorType" : "authorise",
	"errorCode" : "501",
	"message"   : "sample error",
	"status"    : 501
}
`
	providerResponse, err := createTestResponse(responseJSON, "OK 200", 200)

	if err != nil {
		t.Fatal(err)
	}

	err = providerResponse.handleHTTPError()
	if err == nil {
		t.Fatal("Response should raise an error - got nil")
	}

	errorContent := "[authorise][501]: (501) sample error"
	if err.Error() != errorContent {
		t.Fatal("Expected error message ", errorContent, " got ", err.Error())
	}
}

// TestResponseNotValidJson - response is an empty script, error should be returned
func TestResponseNotValidJson(t *testing.T) {
	t.Parallel()

	providerResponse, err := createTestResponse("", "503", 503)

	err = providerResponse.handleHTTPError()
	if err == nil {
		t.Fatal("Response should raise an error - got nil")
	}
}

func TestCaptureResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "capture response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[capture-received]"
			}`,
			reference: "8413547924770610",
			response:  "[capture-received]",
		},
		{
			name:      "capture returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.capture()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestCancelResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "cancel response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[cancel-received]"
			}`,
			reference: "8413547924770610",
			response:  "[cancel-received]",
		},
		{
			name:      "cancel returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.cancel()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestCancelOrRefundResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "cancelOrRefund response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[cancelOrRefund-received]"
			}`,
			reference: "8413547924770610",
			response:  "[cancelOrRefund-received]",
		},
		{
			name:      "cancelOrRefund returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.cancelOrRefund()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestRefundResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "refund response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[refund-received]"
			}`,
			reference: "8413547924770610",
			response:  "[refund-received]",
		},
		{
			name:      "refund returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.refund()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestAdjustAuthorisationResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "adjustAuthorisation response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[adjustAuthorisation-received]"
			}`,
			reference: "8413547924770610",
			response:  "[adjustAuthorisation-received]",
		},
		{
			name:      "adjustAuthorisation returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.adjustAuthorisation()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}
<commit_msg>Add tests for different response methods<commit_after>package adyen

import (
	"testing"
)

// TestResponseErrorResponseStatus - response is valid JSON, but status is > 299, error should be returned
func TestResponseErrorResponseStatus(t *testing.T) {
	t.Parallel()

	responseJSON := `
{
	"errorType" : "authorise",
	"errorCode" : "501",
	"message"   : "sample error",
	"status"    : 501
}
`
	providerResponse, err := createTestResponse(responseJSON, "OK 200", 200)

	if err != nil {
		t.Fatal(err)
	}

	err = providerResponse.handleHTTPError()
	if err == nil {
		t.Fatal("Response should raise an error - got nil")
	}

	errorContent := "[authorise][501]: (501) sample error"
	if err.Error() != errorContent {
		t.Fatal("Expected error message ", errorContent, " got ", err.Error())
	}
}

// TestResponseNotValidJson - response is an empty script, error should be returned
func TestResponseNotValidJson(t *testing.T) {
	t.Parallel()

	providerResponse, err := createTestResponse("", "503", 503)

	err = providerResponse.handleHTTPError()
	if err == nil {
		t.Fatal("Response should raise an error - got nil")
	}
}

func TestAuthorizeResponse(t *testing.T) {
	cases := []struct {
		name       string
		input      string
		reference  string
		resultCode string
		authCode   string
		expErr     bool
	}{
		{
			name: "authorize response",
			input: `{
				"pspReference" : "8413547924770610",
				"ResultCode" : "Authorised",
				"AuthCode" : "53187"
			}`,
			reference:  "8413547924770610",
			resultCode: "Authorised",
			authCode:   "53187",
		},
		{
			name:       "authorize returns errors",
			input:      "some error string",
			reference:  "",
			resultCode: "",
			authCode:   "",
			expErr:     true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.authorize()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.resultCode, res.ResultCode)
			equals(t, c.authCode, res.AuthCode)
		})
	}
}

func TestCaptureResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "capture response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[capture-received]"
			}`,
			reference: "8413547924770610",
			response:  "[capture-received]",
		},
		{
			name:      "capture returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.capture()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestCancelResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "cancel response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[cancel-received]"
			}`,
			reference: "8413547924770610",
			response:  "[cancel-received]",
		},
		{
			name:      "cancel returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.cancel()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestCancelOrRefundResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "cancelOrRefund response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[cancelOrRefund-received]"
			}`,
			reference: "8413547924770610",
			response:  "[cancelOrRefund-received]",
		},
		{
			name:      "cancelOrRefund returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.cancelOrRefund()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestRefundResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "refund response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[refund-received]"
			}`,
			reference: "8413547924770610",
			response:  "[refund-received]",
		},
		{
			name:      "refund returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.refund()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}

func TestListRecurringDetailsResponse(t *testing.T) {
	cases := []struct {
		name                     string
		input                    string
		shopperReference         string
		recurringDetailReference string
		cartHolderName           string
		expErr                   bool
	}{
		{
			name: "listRecurringDetails response",
			input: `{
				"creationDate": "2018-05-23T15:25:40+02:00",
				"details": [
					{
						"RecurringDetail": {
							"additionalData": {
								"cardBin": "411111"
							},
							"alias": "K333136193308394",
							"aliasType": "Default",
							"card": {
								"expiryMonth": "8",
								"expiryYear": "2018",
								"holderName": "John Smith",
								"number": "1111"
							},
							"contractTypes": [
								"PAYOUT",
								"RECURRING",
								"ONECLICK"
							],
							"creationDate": "2018-08-10T10:28:43+02:00",
							"firstPspReference": "8815338897222637",
							"paymentMethodVariant": "visa",
							"recurringDetailReference": "8415336862463792",
							"variant": "visa"
						}
					}
				],
				"shopperReference": "yourShopperId_IOfW3k9G2PvXFu2j"
			}`,
			shopperReference:         "yourShopperId_IOfW3k9G2PvXFu2j",
			recurringDetailReference: "8415336862463792",
			cartHolderName:           "John Smith",
		},
		{
			name:                     "listRecurringDetails error response",
			input:                    "some error string",
			shopperReference:         "",
			recurringDetailReference: "",
			cartHolderName:           "",
			expErr:                   true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.listRecurringDetails()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.shopperReference, res.ShopperReference)
			equals(t, 1, len(res.Details))
			equals(t, c.recurringDetailReference, res.Details[0].RecurringDetail.RecurringDetailReference)
			equals(t, c.cartHolderName, res.Details[0].RecurringDetail.Card.HolderName)
		})
	}
}

func TestDisableRecurringResponse(t *testing.T) {
	cases := []struct {
		name     string
		input    string
		response string
		expErr   bool
	}{
		{
			name: "disableRecurring response",
			input: `{
				"response" : "[detail-successfully-disabled]"
			}`,
			response: "[detail-successfully-disabled]",
		},
		{
			name:     "disableRecurring returns errors",
			input:    "some error string",
			response: "",
			expErr:   true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.disableRecurring()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.response, res.Response)
		})
	}
}

func TestAdjustAuthorisationResponse(t *testing.T) {
	cases := []struct {
		name      string
		input     string
		reference string
		response  string
		expErr    bool
	}{
		{
			name: "adjustAuthorisation response",
			input: `{
				"pspReference" : "8413547924770610",
				"response" : "[adjustAuthorisation-received]"
			}`,
			reference: "8413547924770610",
			response:  "[adjustAuthorisation-received]",
		},
		{
			name:      "adjustAuthorisation returns errors",
			input:     "some error string",
			reference: "",
			response:  "",
			expErr:    true,
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			response, err := createTestResponse(c.input, "OK 200", 200)

			if err != nil {
				t.Fatal(err)
			}

			res, err := response.adjustAuthorisation()

			if c.expErr {
				if err == nil {
					t.Fatal("expected error but didn't get one")
				}

				return
			}

			equals(t, c.reference, res.PspReference)
			equals(t, c.response, res.Response)
		})
	}
}
<|endoftext|>


<commit_before>package runtime

import (
	"encoding/base64"
	"fmt"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/grpc-ecosystem/grpc-gateway/utilities"
	"google.golang.org/grpc/grpclog"
)

// PopulateQueryParameters populates "values" into "msg".
// A value is ignored if its key starts with one of the elements in "filter".
func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
	for key, values := range values {
		re, err := regexp.Compile("^(.*)\\[(.*)\\]$")
		if err != nil {
			return err
		}
		match := re.FindStringSubmatch(key)
		if len(match) == 3 {
			key = match[1]
			values = append([]string{match[2]}, values...)
		}
		fieldPath := strings.Split(key, ".")
		if filter.HasCommonPrefix(fieldPath) {
			continue
		}
		if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
			return err
		}
	}
	return nil
}

// PopulateFieldFromPath sets a value in a nested Protobuf structure.
// It instantiates missing protobuf fields as it goes.
func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error {
	fieldPath := strings.Split(fieldPathString, ".")
	return populateFieldValueFromPath(msg, fieldPath, []string{value})
}

func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error {
	m := reflect.ValueOf(msg)
	if m.Kind() != reflect.Ptr {
		return fmt.Errorf("unexpected type %T: %v", msg, msg)
	}
	var props *proto.Properties
	m = m.Elem()
	for i, fieldName := range fieldPath {
		isLast := i == len(fieldPath)-1
		if !isLast && m.Kind() != reflect.Struct {
			return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, "."))
		}
		var f reflect.Value
		var err error
		f, props, err = fieldByProtoName(m, fieldName)
		if err != nil {
			return err
		} else if !f.IsValid() {
			grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
			return nil
		}

		switch f.Kind() {
		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
			if !isLast {
				return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
			}
			m = f
		case reflect.Slice:
			if !isLast {
				return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
			}
			// Handle []byte
			if f.Type().Elem().Kind() == reflect.Uint8 {
				m = f
				break
			}
			return populateRepeatedField(f, values, props)
		case reflect.Ptr:
			if f.IsNil() {
				m = reflect.New(f.Type().Elem())
				f.Set(m.Convert(f.Type()))
			}
			m = f.Elem()
			continue
		case reflect.Struct:
			m = f
			continue
		case reflect.Map:
			if !isLast {
				return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
			}
			return populateMapField(f, values, props)
		default:
			return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
		}
	}
	switch len(values) {
	case 0:
		return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
	case 1:
	default:
		grpclog.Infof("too many field values: %s", strings.Join(fieldPath, "."))
	}
	return populateField(m, values[0], props)
}

// fieldByProtoName looks up a field whose corresponding protobuf field name is "name".
// "m" must be a struct value. It returns zero reflect.Value if no such field found.
func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) {
	props := proto.GetProperties(m.Type())

	// look up field name in oneof map
	if op, ok := props.OneofTypes[name]; ok {
		v := reflect.New(op.Type.Elem())
		field := m.Field(op.Field)
		if !field.IsNil() {
			return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName)
		}
		field.Set(v)
		return v.Elem().Field(0), op.Prop, nil
	}

	for _, p := range props.Prop {
		if p.OrigName == name {
			return m.FieldByName(p.Name), p, nil
		}
		if p.JSONName == name {
			return m.FieldByName(p.Name), p, nil
		}
	}
	return reflect.Value{}, nil, nil
}

func populateMapField(f reflect.Value, values []string, props *proto.Properties) error {
	if len(values) != 2 {
		return fmt.Errorf("more than one value provided for key %s in map %s", values[0], props.Name)
	}

	key, value := values[0], values[1]
	keyType := f.Type().Key()
	valueType := f.Type().Elem()
	if f.IsNil() {
		f.Set(reflect.MakeMap(f.Type()))
	}

	keyConv, ok := convFromType[keyType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name)
	}
	valueConv, ok := convFromType[valueType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name)
	}

	keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)})
	if err := keyV[1].Interface(); err != nil {
		return err.(error)
	}
	valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)})
	if err := valueV[1].Interface(); err != nil {
		return err.(error)
	}

	f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType))

	return nil
}

func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
	elemType := f.Type().Elem()

	// is the destination field a slice of an enumeration type?
	if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
		return populateFieldEnumRepeated(f, values, enumValMap)
	}

	conv, ok := convFromType[elemType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported field type %s", elemType)
	}
	f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
	for i, v := range values {
		result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
		if err := result[1].Interface(); err != nil {
			return err.(error)
		}
		f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
	}
	return nil
}

func populateField(f reflect.Value, value string, props *proto.Properties) error {
	i := f.Addr().Interface()

	// Handle protobuf well known types
	type wkt interface {
		XXX_WellKnownType() string
	}
	if wkt, ok := i.(wkt); ok {
		switch wkt.XXX_WellKnownType() {
		case "Timestamp":
			if value == "null" {
				f.Field(0).SetInt(0)
				f.Field(1).SetInt(0)
				return nil
			}

			t, err := time.Parse(time.RFC3339Nano, value)
			if err != nil {
				return fmt.Errorf("bad Timestamp: %v", err)
			}
			f.Field(0).SetInt(int64(t.Unix()))
			f.Field(1).SetInt(int64(t.Nanosecond()))
			return nil
		case "Duration":
			if value == "null" {
				f.Field(0).SetInt(0)
				f.Field(1).SetInt(0)
				return nil
			}
			d, err := time.ParseDuration(value)
			if err != nil {
				return fmt.Errorf("bad Duration: %v", err)
			}

			ns := d.Nanoseconds()
			s := ns / 1e9
			ns %= 1e9
			f.Field(0).SetInt(s)
			f.Field(1).SetInt(ns)
			return nil
		case "DoubleValue":
			fallthrough
		case "FloatValue":
			float64Val, err := strconv.ParseFloat(value, 64)
			if err != nil {
				return fmt.Errorf("bad DoubleValue: %s", value)
			}
			f.Field(0).SetFloat(float64Val)
			return nil
		case "Int64Value":
			fallthrough
		case "Int32Value":
			int64Val, err := strconv.ParseInt(value, 10, 64)
			if err != nil {
				return fmt.Errorf("bad DoubleValue: %s", value)
			}
			f.Field(0).SetInt(int64Val)
			return nil
		case "UInt64Value":
			fallthrough
		case "UInt32Value":
			uint64Val, err := strconv.ParseUint(value, 10, 64)
			if err != nil {
				return fmt.Errorf("bad DoubleValue: %s", value)
			}
			f.Field(0).SetUint(uint64Val)
			return nil
		case "BoolValue":
			if value == "true" {
				f.Field(0).SetBool(true)
			} else if value == "false" {
				f.Field(0).SetBool(false)
			} else {
				return fmt.Errorf("bad BoolValue: %s", value)
			}
			return nil
		case "StringValue":
			f.Field(0).SetString(value)
			return nil
		case "BytesValue":
			bytesVal, err := base64.StdEncoding.DecodeString(value)
			if err != nil {
				return fmt.Errorf("bad BytesValue: %s", value)
			}
			f.Field(0).SetBytes(bytesVal)
			return nil
		}
	}

	// Handle google well known types
	if gwkt, ok := i.(proto.Message); ok {
		switch proto.MessageName(gwkt) {
		case "google.protobuf.FieldMask":
			p := f.Field(0)
			for _, v := range strings.Split(value, ",") {
				if v != "" {
					p.Set(reflect.Append(p, reflect.ValueOf(v)))
				}
			}
			return nil
		}
	}

	// Handle Time and Duration stdlib types
	switch t := i.(type) {
	case *time.Time:
		pt, err := time.Parse(time.RFC3339Nano, value)
		if err != nil {
			return fmt.Errorf("bad Timestamp: %v", err)
		}
		*t = pt
		return nil
	case *time.Duration:
		d, err := time.ParseDuration(value)
		if err != nil {
			return fmt.Errorf("bad Duration: %v", err)
		}
		*t = d
		return nil
	}

	// is the destination field an enumeration type?
	if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
		return populateFieldEnum(f, value, enumValMap)
	}

	conv, ok := convFromType[f.Kind()]
	if !ok {
		return fmt.Errorf("field type %T is not supported in query parameters", i)
	}
	result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
	if err := result[1].Interface(); err != nil {
		return err.(error)
	}
	f.Set(result[0].Convert(f.Type()))
	return nil
}

func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
	// see if it's an enumeration string
	if enumVal, ok := enumValMap[value]; ok {
		return reflect.ValueOf(enumVal).Convert(t), nil
	}

	// check for an integer that matches an enumeration value
	eVal, err := strconv.Atoi(value)
	if err != nil {
		return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
	}
	for _, v := range enumValMap {
		if v == int32(eVal) {
			return reflect.ValueOf(eVal).Convert(t), nil
		}
	}
	return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
}

func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
	cval, err := convertEnum(value, f.Type(), enumValMap)
	if err != nil {
		return err
	}
	f.Set(cval)
	return nil
}

func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
	elemType := f.Type().Elem()
	f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
	for i, v := range values {
		result, err := convertEnum(v, elemType, enumValMap)
		if err != nil {
			return err
		}
		f.Index(i).Set(result)
	}
	return nil
}

var (
	convFromType = map[reflect.Kind]reflect.Value{
		reflect.String:  reflect.ValueOf(String),
		reflect.Bool:    reflect.ValueOf(Bool),
		reflect.Float64: reflect.ValueOf(Float64),
		reflect.Float32: reflect.ValueOf(Float32),
		reflect.Int64:   reflect.ValueOf(Int64),
		reflect.Int32:   reflect.ValueOf(Int32),
		reflect.Uint64:  reflect.ValueOf(Uint64),
		reflect.Uint32:  reflect.ValueOf(Uint32),
		reflect.Slice:   reflect.ValueOf(Bytes),
	}
)
<commit_msg>Fix query.go to avoid invalid protobuf assumptions<commit_after>package runtime

import (
	"encoding/base64"
	"fmt"
	"net/url"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/grpc-ecosystem/grpc-gateway/utilities"
	"google.golang.org/grpc/grpclog"
)

// PopulateQueryParameters populates "values" into "msg".
// A value is ignored if its key starts with one of the elements in "filter".
func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error {
	for key, values := range values {
		re, err := regexp.Compile("^(.*)\\[(.*)\\]$")
		if err != nil {
			return err
		}
		match := re.FindStringSubmatch(key)
		if len(match) == 3 {
			key = match[1]
			values = append([]string{match[2]}, values...)
		}
		fieldPath := strings.Split(key, ".")
		if filter.HasCommonPrefix(fieldPath) {
			continue
		}
		if err := populateFieldValueFromPath(msg, fieldPath, values); err != nil {
			return err
		}
	}
	return nil
}

// PopulateFieldFromPath sets a value in a nested Protobuf structure.
// It instantiates missing protobuf fields as it goes.
func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error {
	fieldPath := strings.Split(fieldPathString, ".")
	return populateFieldValueFromPath(msg, fieldPath, []string{value})
}

func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []string) error {
	m := reflect.ValueOf(msg)
	if m.Kind() != reflect.Ptr {
		return fmt.Errorf("unexpected type %T: %v", msg, msg)
	}
	var props *proto.Properties
	m = m.Elem()
	for i, fieldName := range fieldPath {
		isLast := i == len(fieldPath)-1
		if !isLast && m.Kind() != reflect.Struct {
			return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, "."))
		}
		var f reflect.Value
		var err error
		f, props, err = fieldByProtoName(m, fieldName)
		if err != nil {
			return err
		} else if !f.IsValid() {
			grpclog.Infof("field not found in %T: %s", msg, strings.Join(fieldPath, "."))
			return nil
		}

		switch f.Kind() {
		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64, reflect.String, reflect.Uint32, reflect.Uint64:
			if !isLast {
				return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
			}
			m = f
		case reflect.Slice:
			if !isLast {
				return fmt.Errorf("unexpected repeated field in %s", strings.Join(fieldPath, "."))
			}
			// Handle []byte
			if f.Type().Elem().Kind() == reflect.Uint8 {
				m = f
				break
			}
			return populateRepeatedField(f, values, props)
		case reflect.Ptr:
			if f.IsNil() {
				m = reflect.New(f.Type().Elem())
				f.Set(m.Convert(f.Type()))
			}
			m = f.Elem()
			continue
		case reflect.Struct:
			m = f
			continue
		case reflect.Map:
			if !isLast {
				return fmt.Errorf("unexpected nested field %s in %s", fieldPath[i+1], strings.Join(fieldPath[:i+1], "."))
			}
			return populateMapField(f, values, props)
		default:
			return fmt.Errorf("unexpected type %s in %T", f.Type(), msg)
		}
	}
	switch len(values) {
	case 0:
		return fmt.Errorf("no value of field: %s", strings.Join(fieldPath, "."))
	case 1:
	default:
		grpclog.Infof("too many field values: %s", strings.Join(fieldPath, "."))
	}
	return populateField(m, values[0], props)
}

// fieldByProtoName looks up a field whose corresponding protobuf field name is "name".
// "m" must be a struct value. It returns zero reflect.Value if no such field found.
func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) {
	props := proto.GetProperties(m.Type())

	// look up field name in oneof map
	if op, ok := props.OneofTypes[name]; ok {
		v := reflect.New(op.Type.Elem())
		field := m.Field(op.Field)
		if !field.IsNil() {
			return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName)
		}
		field.Set(v)
		return v.Elem().Field(0), op.Prop, nil
	}

	for _, p := range props.Prop {
		if p.OrigName == name {
			return m.FieldByName(p.Name), p, nil
		}
		if p.JSONName == name {
			return m.FieldByName(p.Name), p, nil
		}
	}
	return reflect.Value{}, nil, nil
}

func populateMapField(f reflect.Value, values []string, props *proto.Properties) error {
	if len(values) != 2 {
		return fmt.Errorf("more than one value provided for key %s in map %s", values[0], props.Name)
	}

	key, value := values[0], values[1]
	keyType := f.Type().Key()
	valueType := f.Type().Elem()
	if f.IsNil() {
		f.Set(reflect.MakeMap(f.Type()))
	}

	keyConv, ok := convFromType[keyType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported key type %s in map %s", keyType, props.Name)
	}
	valueConv, ok := convFromType[valueType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported value type %s in map %s", valueType, props.Name)
	}

	keyV := keyConv.Call([]reflect.Value{reflect.ValueOf(key)})
	if err := keyV[1].Interface(); err != nil {
		return err.(error)
	}
	valueV := valueConv.Call([]reflect.Value{reflect.ValueOf(value)})
	if err := valueV[1].Interface(); err != nil {
		return err.(error)
	}

	f.SetMapIndex(keyV[0].Convert(keyType), valueV[0].Convert(valueType))

	return nil
}

func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error {
	elemType := f.Type().Elem()

	// is the destination field a slice of an enumeration type?
	if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
		return populateFieldEnumRepeated(f, values, enumValMap)
	}

	conv, ok := convFromType[elemType.Kind()]
	if !ok {
		return fmt.Errorf("unsupported field type %s", elemType)
	}
	f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
	for i, v := range values {
		result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
		if err := result[1].Interface(); err != nil {
			return err.(error)
		}
		f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
	}
	return nil
}

func populateField(f reflect.Value, value string, props *proto.Properties) error {
	i := f.Addr().Interface()

	// Handle protobuf well known types
	var name string
	switch m := i.(type) {
	case interface{ XXX_WellKnownType() string }:
		name = m.XXX_WellKnownType()
	case proto.Message:
		const wktPrefix = "google.protobuf."
		if fullName := proto.MessageName(m); strings.HasPrefix(fullName, wktPrefix) {
			name = fullName[len(wktPrefix):]
		}
	}
	switch name {
	case "Timestamp":
		if value == "null" {
			f.FieldByName("Seconds").SetInt(0)
			f.FieldByName("Nanos").SetInt(0)
			return nil
		}

		t, err := time.Parse(time.RFC3339Nano, value)
		if err != nil {
			return fmt.Errorf("bad Timestamp: %v", err)
		}
		f.FieldByName("Seconds").SetInt(int64(t.Unix()))
		f.FieldByName("Nanos").SetInt(int64(t.Nanosecond()))
		return nil
	case "Duration":
		if value == "null" {
			f.FieldByName("Seconds").SetInt(0)
			f.FieldByName("Nanos").SetInt(0)
			return nil
		}
		d, err := time.ParseDuration(value)
		if err != nil {
			return fmt.Errorf("bad Duration: %v", err)
		}

		ns := d.Nanoseconds()
		s := ns / 1e9
		ns %= 1e9
		f.FieldByName("Seconds").SetInt(s)
		f.FieldByName("Nanos").SetInt(ns)
		return nil
	case "DoubleValue":
		fallthrough
	case "FloatValue":
		float64Val, err := strconv.ParseFloat(value, 64)
		if err != nil {
			return fmt.Errorf("bad DoubleValue: %s", value)
		}
		f.FieldByName("Value").SetFloat(float64Val)
		return nil
	case "Int64Value":
		fallthrough
	case "Int32Value":
		int64Val, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return fmt.Errorf("bad DoubleValue: %s", value)
		}
		f.FieldByName("Value").SetInt(int64Val)
		return nil
	case "UInt64Value":
		fallthrough
	case "UInt32Value":
		uint64Val, err := strconv.ParseUint(value, 10, 64)
		if err != nil {
			return fmt.Errorf("bad DoubleValue: %s", value)
		}
		f.FieldByName("Value").SetUint(uint64Val)
		return nil
	case "BoolValue":
		if value == "true" {
			f.FieldByName("Value").SetBool(true)
		} else if value == "false" {
			f.FieldByName("Value").SetBool(false)
		} else {
			return fmt.Errorf("bad BoolValue: %s", value)
		}
		return nil
	case "StringValue":
		f.FieldByName("Value").SetString(value)
		return nil
	case "BytesValue":
		bytesVal, err := base64.StdEncoding.DecodeString(value)
		if err != nil {
			return fmt.Errorf("bad BytesValue: %s", value)
		}
		f.FieldByName("Value").SetBytes(bytesVal)
		return nil
	case "FieldMask":
		p := f.FieldByName("Paths")
		for _, v := range strings.Split(value, ",") {
			if v != "" {
				p.Set(reflect.Append(p, reflect.ValueOf(v)))
			}
		}
		return nil
	}

	// Handle Time and Duration stdlib types
	switch t := i.(type) {
	case *time.Time:
		pt, err := time.Parse(time.RFC3339Nano, value)
		if err != nil {
			return fmt.Errorf("bad Timestamp: %v", err)
		}
		*t = pt
		return nil
	case *time.Duration:
		d, err := time.ParseDuration(value)
		if err != nil {
			return fmt.Errorf("bad Duration: %v", err)
		}
		*t = d
		return nil
	}

	// is the destination field an enumeration type?
	if enumValMap := proto.EnumValueMap(props.Enum); enumValMap != nil {
		return populateFieldEnum(f, value, enumValMap)
	}

	conv, ok := convFromType[f.Kind()]
	if !ok {
		return fmt.Errorf("field type %T is not supported in query parameters", i)
	}
	result := conv.Call([]reflect.Value{reflect.ValueOf(value)})
	if err := result[1].Interface(); err != nil {
		return err.(error)
	}
	f.Set(result[0].Convert(f.Type()))
	return nil
}

func convertEnum(value string, t reflect.Type, enumValMap map[string]int32) (reflect.Value, error) {
	// see if it's an enumeration string
	if enumVal, ok := enumValMap[value]; ok {
		return reflect.ValueOf(enumVal).Convert(t), nil
	}

	// check for an integer that matches an enumeration value
	eVal, err := strconv.Atoi(value)
	if err != nil {
		return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
	}
	for _, v := range enumValMap {
		if v == int32(eVal) {
			return reflect.ValueOf(eVal).Convert(t), nil
		}
	}
	return reflect.Value{}, fmt.Errorf("%s is not a valid %s", value, t)
}

func populateFieldEnum(f reflect.Value, value string, enumValMap map[string]int32) error {
	cval, err := convertEnum(value, f.Type(), enumValMap)
	if err != nil {
		return err
	}
	f.Set(cval)
	return nil
}

func populateFieldEnumRepeated(f reflect.Value, values []string, enumValMap map[string]int32) error {
	elemType := f.Type().Elem()
	f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
	for i, v := range values {
		result, err := convertEnum(v, elemType, enumValMap)
		if err != nil {
			return err
		}
		f.Index(i).Set(result)
	}
	return nil
}

var (
	convFromType = map[reflect.Kind]reflect.Value{
		reflect.String:  reflect.ValueOf(String),
		reflect.Bool:    reflect.ValueOf(Bool),
		reflect.Float64: reflect.ValueOf(Float64),
		reflect.Float32: reflect.ValueOf(Float32),
		reflect.Int64:   reflect.ValueOf(Int64),
		reflect.Int32:   reflect.ValueOf(Int32),
		reflect.Uint64:  reflect.ValueOf(Uint64),
		reflect.Uint32:  reflect.ValueOf(Uint32),
		reflect.Slice:   reflect.ValueOf(Bytes),
	}
)
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

/*
SampleType is a Go union type example for the C union type:
    union SampleType
    {
        long f1;
        unsigned long f2;
        unsigned char f3;
        short f4;
    };
*/
type SampleType [4]byte

// Get casted pointer
func (st *SampleType) cast(t reflect.Type) reflect.Value {
	return reflect.NewAt(t, unsafe.Pointer(&st[0]))
}

// Assign value from an union field (used by getters)
func (st *SampleType) assign(v interface{}) {
	value := reflect.ValueOf(v).Elem()

	value.Set(st.cast(value.Type()).Elem())
}

// Get typed pointer
func (st *SampleType) pointer(v interface{}) {
	value := reflect.ValueOf(v).Elem()

	value.Set(st.cast(value.Type().Elem()))
}

// UntypedSet is the generic setter
func (st *SampleType) UntypedSet(v interface{}) {
	value := reflect.ValueOf(v)

	st.cast(value.Type()).Elem().Set(value)
}

/* Pointers */
// PtrF1 gets pointer on F1 field
func (st *SampleType) PtrF1() (res *int32) { st.pointer(&res); return }

// PtrF2 gets pointer on F2 field
func (st *SampleType) PtrF2() (res *uint32) { st.pointer(&res); return }

// PtrF3 gets pointer on F3 field
func (st *SampleType) PtrF3() (res *byte) { st.pointer(&res); return }

// PtrF4 gets pointer on F4 field
func (st *SampleType) PtrF4() (res *int16) { st.pointer(&res); return }

/* Setters */
// SetF1 sets F1 field
func (st *SampleType) SetF1(v int32) { st.UntypedSet(v) }

// SetF2 sets F2 field
func (st *SampleType) SetF2(v uint32) { st.UntypedSet(v) }

// SetF3 sets F3 field
func (st *SampleType) SetF3(v byte) { st.UntypedSet(v) }

// SetF4 sets F4 field
func (st *SampleType) SetF4(v int16) { st.UntypedSet(v) }

/* Getters */
// GetF1 gets F1 field
func (st *SampleType) GetF1() (res int32) { st.assign(&res); return }

// GetF2 gets F2 field
func (st *SampleType) GetF2() (res uint32) { st.assign(&res); return }

// GetF3 gets F3 field
func (st *SampleType) GetF3() (res byte) { st.assign(&res); return }

// GetF4 gets F4 field
func (st *SampleType) GetF4() (res int16) { st.assign(&res); return }

func main() {
	// Create the union
	var u SampleType

	// Set a value
	u.UntypedSet(0x12345678)

	// Get values
	f1 := u.GetF1()
	f2 := u.GetF2()
	f3 := u.GetF3()
	f4 := u.GetF4()

	// Print the results
	fmt.Printf("Values:              %x %x %x %x\n", f1, f2, f3, f4)

	// Get pointers
	p1 := u.PtrF1()
	p2 := u.PtrF2()
	p3 := u.PtrF3()
	p4 := u.PtrF4()

	// Print values before modification
	fmt.Printf("Before modification: %x %x %x %x\n", *p1, *p2, *p3, *p4)

	// modification
	*p2 = 0x12344321

	// Print values after modification
	fmt.Printf("After modification:  %x %x %x %x\n", *p1, *p2, *p3, *p4)
}
<commit_msg>Just change comments<commit_after>package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

/*
SampleType is a Go union type example for the C union type:
    union SampleType
    {
        long f1;
        unsigned long f2;
        unsigned char f3;
        short f4;
    };
*/
type SampleType [4]byte

// Get casted pointer
func (st *SampleType) cast(t reflect.Type) reflect.Value {
    return reflect.NewAt(t, unsafe.Pointer(&st[0]))
}

// Assign value from an union field (used by getters)
func (st *SampleType) assign(v interface{}) {
    value := reflect.ValueOf(v).Elem()

    value.Set(st.cast(value.Type()).Elem())
}

// Get typed pointer
func (st *SampleType) pointer(v interface{}) {
    value := reflect.ValueOf(v).Elem()

    value.Set(st.cast(value.Type().Elem()))
}

// UntypedSet is the generic setter
func (st *SampleType) UntypedSet(v interface{}) {
    value := reflect.ValueOf(v)

    st.cast(value.Type()).Elem().Set(value)
}

/* -- Pointers -- */

// PtrF1 gets pointer on F1 field
func (st *SampleType) PtrF1() (res *int32) { st.pointer(&res); return }

// PtrF2 gets pointer on F2 field
func (st *SampleType) PtrF2() (res *uint32) { st.pointer(&res); return }

// PtrF3 gets pointer on F3 field
func (st *SampleType) PtrF3() (res *byte) { st.pointer(&res); return }

// PtrF4 gets pointer on F4 field
func (st *SampleType) PtrF4() (res *int16) { st.pointer(&res); return }

/* -- Setters -- */

// SetF1 sets F1 field
func (st *SampleType) SetF1(v int32) { st.UntypedSet(v) }

// SetF2 sets F2 field
func (st *SampleType) SetF2(v uint32) { st.UntypedSet(v) }

// SetF3 sets F3 field
func (st *SampleType) SetF3(v byte) { st.UntypedSet(v) }

// SetF4 sets F4 field
func (st *SampleType) SetF4(v int16) { st.UntypedSet(v) }

/* -- Getters -- */

// GetF1 gets F1 field
func (st *SampleType) GetF1() (res int32) { st.assign(&res); return }

// GetF2 gets F2 field
func (st *SampleType) GetF2() (res uint32) { st.assign(&res); return }

// GetF3 gets F3 field
func (st *SampleType) GetF3() (res byte) { st.assign(&res); return }

// GetF4 gets F4 field
func (st *SampleType) GetF4() (res int16) { st.assign(&res); return }

func main() {
    // Create the union
    var u SampleType

    // Set a value
    u.UntypedSet(0x12345678)

    // Get values
    f1 := u.GetF1()
    f2 := u.GetF2()
    f3 := u.GetF3()
    f4 := u.GetF4()

    // Print the results
    fmt.Printf("Values:              %x %x %x %x\n", f1, f2, f3, f4)

    // Get pointers
    p1 := u.PtrF1()
    p2 := u.PtrF2()
    p3 := u.PtrF3()
    p4 := u.PtrF4()

    // Print values before modification
    fmt.Printf("Before modification: %x %x %x %x\n", *p1, *p2, *p3, *p4)

    // modification
    *p2 = 0x12344321

    // Print values after modification
    fmt.Printf("After modification:  %x %x %x %x\n", *p1, *p2, *p3, *p4)
}
<|endoftext|>


<commit_before>package schedule

import (
	"errors"
	"github.com/0xfoo/punchcard/git"
	"github.com/0xfoo/punchcard/utils"
	"strings"
	"time"
)

const (
	SCHEDULE_WIDTH = 53
)

// TextSchedule creates commits over the past 365/366 days to build the given text.
// These commits will be created in the given git repo using the FileGenerator.
func TextSchedule(text string, repo git.Git, filegen utils.FileGenerator) error {
	messageBase := GetCommitMessageBase()
	days := GetDaysSinceNowMinusOneYear()
	commits, err := getTextCommitSchedule(text, days, messageBase)
	if err != nil {
		return err
	}
	for _, commit := range commits {
		repo.Add(filegen.CreateFile())
		repo.Commit(commit.Message, commit.DateTime.String())
	}
	return err
}

func getTextCommitSchedule(text string, days []time.Time, messageBase []string) ([]Commit, error) {
	if !textFits(text) {
		return nil, errors.New("Text does not fit.")
	}
	schedule := buildTextCommitSchedule(days, text)
	commits := convertScheduleToCommits(schedule)
	return commits, nil
}

func textFits(text string) bool {
	textWidth := getTextWidth(text)
	textIsNotToWide := textWidth <= SCHEDULE_WIDTH-2 // adjust for margins
	textIsNotEmpty := textWidth > 0
	return textIsNotEmpty && textIsNotToWide
}

func getTextWidth(text string) int {
	// TODO get the width of each letter and add spacing
	return len(text)
}

func convertScheduleToCommits(schedule CommitSchedule) []Commit {
	return nil
}

func buildTextCommitSchedule(days []time.Time, text string) CommitSchedule {
	schedule := BuildCommitSchedule(days)
	mapTextOntoCommitSchedule(text, &schedule)
	return schedule
}

func mapTextOntoCommitSchedule(text string, schedule *CommitSchedule) {
	letters := buildTextFields(text)
	rightShift := 0
	for _, fields := range letters {
		for rowIndex, row := range fields {
			for columnIndex, field := range row {
				schedule[rowIndex][columnIndex+rightShift] = field
			}
			rightShift += len(row)
		}
	}
}

func buildTextFields(text string) [][][]int {
	var letters [][][]int
	space, _ := utils.TranslateLetter(" ")
	for _, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		letters = append(letters, letter, space)
	}
	return letters
}
<commit_msg>Minor fixes to get tests to pass.<commit_after>package schedule

import (
	"errors"
	"github.com/0xfoo/punchcard/git"
	"github.com/0xfoo/punchcard/utils"
	"strings"
	"time"
)

const (
	SCHEDULE_WIDTH = 53
)

// TextSchedule creates commits over the past 365/366 days to build the given text.
// These commits will be created in the given git repo using the FileGenerator.
func TextSchedule(text string, repo git.Git, filegen utils.FileGenerator) error {
	messageBase := GetCommitMessageBase()
	days := GetDaysSinceNowMinusOneYear()
	commits, err := getTextCommitSchedule(text, days, messageBase)
	if err != nil {
		return err
	}
	for _, commit := range commits {
		repo.Add(filegen.CreateFile())
		repo.Commit(commit.Message, commit.DateTime.String())
	}
	return err
}

func getTextCommitSchedule(text string, days []time.Time, messageBase []string) ([]Commit, error) {
	if !textFits(text) {
		return nil, errors.New("Text does not fit.")
	}
	schedule := buildTextCommitSchedule(days, text)
	commits := convertScheduleToCommits(schedule)
	return commits, nil
}

func textFits(text string) bool {
	textWidth := getTextWidth(text)
	textIsNotToWide := textWidth <= SCHEDULE_WIDTH-2 // adjust for margins
	textIsNotEmpty := textWidth > 0
	return textIsNotEmpty && textIsNotToWide
}

func getTextWidth(text string) int {
	width := 0
	for _, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		width += len(letter[0]) + 1 // adjust for space between letters
	}
	return width - 1 // last letter does not need and extra space
}

func convertScheduleToCommits(schedule CommitSchedule) []Commit {
	var commits []Commit
	return commits
}

func buildTextCommitSchedule(days []time.Time, text string) CommitSchedule {
	schedule := BuildCommitSchedule(days)
	mapTextOntoCommitSchedule(text, &schedule)
	return schedule
}

func mapTextOntoCommitSchedule(text string, schedule *CommitSchedule) {
	letters := buildTextFields(text)
	rightShift := 0
	for _, fields := range letters {
		for rowIndex, row := range fields {
			for columnIndex, field := range row {
				schedule[rowIndex][columnIndex+rightShift] = field
			}
			rightShift += len(row)
		}
	}
}

func buildTextFields(text string) [][][]int {
	var letters [][][]int
	space, _ := utils.TranslateLetter(" ")
	length := len(text)
	for index, char := range strings.Split(text, "") {
		letter, _ := utils.TranslateLetter(char)
		if index == length-1 {
			letters = append(letters, letter)
		} else {

			letters = append(letters, letter, space)
		}
	}
	return letters
}
<|endoftext|>


<commit_before>package mdns

// Advertise network services via multicast DNS

import (
	"errors"
	"log"
	"net"

	"dns"
	"github.com/davecheney/gmx"
)

var (
	ipv4mcastaddr = &net.UDPAddr{
		IP:   net.ParseIP("224.0.0.251"),
		Port: 5353,
	}

	ipv6mcastaddr = &net.UDPAddr{
		IP:   net.ParseIP("ff02::fb"),
		Port: 5353,
	}
	local *zone // the local mdns zone
)

func init() {
	local = &zone{
		entries: make(map[string]entries),
		add:     make(chan *entry, 16),
		queries: make(chan *query, 16),
	}
	go local.mainloop()
	if err := local.listen(ipv4mcastaddr); err != nil {
		log.Fatalf("Failed to listen %s: %s", ipv4mcastaddr, err)
	}
	if err := local.listen(ipv6mcastaddr); err != nil {
		log.Printf("Failed to listen %s: %s", ipv6mcastaddr, err)
	}

	// publish gmx stats for the local zone
	gmx.Publish("mdns.zone.local.queries", func() interface{} {
		return local.queryCount
	})
	gmx.Publish("mdns.zone.local.entries", func() interface{} {
		return local.entryCount
	})

}

// Publish adds a record, described in RFC XXX
func Publish(r string) error {
	rr, err := dns.NewRR(r)
	if err != nil {
		return err
	}
	local.add <- &entry{rr}
	return nil
}

type entry struct {
	dns.RR
}

func (e *entry) fqdn() string {
	return e.Header().Name
}

type query struct {
	dns.Question
	result chan *entry
}

type entries []*entry

func (e entries) contains(entry *entry) bool {
	for _, ee := range e {
		if equals(entry, ee) {
			return true
		}
	}
	return false
}

type zone struct {
	entries map[string]entries
	add     chan *entry // add entries to zone
	queries chan *query // query exsting entries in zone

	// gmx statistics
	queryCount, entryCount int
}

func (z *zone) mainloop() {
	for {
		select {
		case entry := <-z.add:
			z.entryCount++
			if !z.entries[entry.fqdn()].contains(entry) {
				z.entries[entry.fqdn()] = append(z.entries[entry.fqdn()], entry)
			}
		case q := <-z.queries:
			z.queryCount++
			for _, entry := range z.entries[q.Question.Name] {
				if q.matches(entry) {
					q.result <- entry
				}
			}
			close(q.result)
		}
	}
}

func (z *zone) query(q dns.Question) (entries []*entry) {
	res := make(chan *entry, 16)
	z.queries <- &query{q, res}
	for e := range res {
		entries = append(entries, e)
	}
	return
}

func (q *query) matches(entry *entry) bool {
	return q.Question.Qtype == dns.TypeANY || q.Question.Qtype == entry.RR.Header().Rrtype
}

func equals(this, that *entry) bool {
	if _, ok := this.RR.(*dns.RR_ANY); ok {
		return true // *RR_ANY matches anything
	}
	if _, ok := that.RR.(*dns.RR_ANY); ok {
		return true // *RR_ANY matches all
	}
	return false
}

type connector struct {
	*net.UDPAddr
	*net.UDPConn
	*zone

	// gmx statistics
	questions, responses int
}

func (z *zone) listen(addr *net.UDPAddr) error {
	conn, err := openSocket(addr)
	if err != nil {
		return err
	}
	c := &connector{
		UDPAddr: addr,
		UDPConn: conn,
		zone:    z,
	}
	go c.mainloop()

	// publish gmx stats for the connector
	gmx.Publish("mdns.connector.questions", func() interface{} {
		return c.questions
	})
	gmx.Publish("mdns.connector.responses", func() interface{} {
		return c.responses
	})

	return nil
}

func openSocket(addr *net.UDPAddr) (*net.UDPConn, error) {
	switch addr.IP.To4() {
	case nil:
		return net.ListenMulticastUDP("udp6", nil, ipv6mcastaddr)
	default:
		return net.ListenMulticastUDP("udp4", nil, ipv4mcastaddr)
	}
	panic("unreachable")
}

func (c *connector) mainloop() {
	in := make(chan struct {
		*dns.Msg
		*net.UDPAddr
	}, 32)
	go func() {
		for {
			msg, addr, err := c.readMessage()
			if err != nil {
				// log dud packets
				log.Printf("Cound not read from %s: %s", c.UDPConn, err)
			}
			if msg.IsQuestion() {
				c.questions++
				in <- struct {
					*dns.Msg
					*net.UDPAddr
				}{msg, addr}
			}
		}
	}()
	for {
		msg := <-in
		msg.MsgHdr.Response = true // convert question to response
		for _, result := range c.query(msg.Question) {
			msg.Answer = append(msg.Answer, result.RR)
		}
		msg.Extra = append(msg.Extra, c.findExtra(msg.Answer...)...)
		if len(msg.Answer) > 0 {
			c.responses++
			if err := c.writeMessage(msg.Msg); err != nil {
				log.Fatalf("Cannot send: %s", err)
			}
		}
	}
}

func (c *connector) query(qs []dns.Question) (results []*entry) {
	for _, q := range qs {
		results = append(results, c.zone.query(q)...)
	}
	return
}

// recursively probe for related records
func (c *connector) findExtra(r ...dns.RR) (extra []dns.RR) {
	for _, rr := range r {
		var q dns.Question
		switch rr := rr.(type) {
		case *dns.RR_PTR:
			q = dns.Question{
				Name:   rr.Ptr,
				Qtype:  dns.TypeANY,
				Qclass: dns.ClassINET,
			}
		case *dns.RR_SRV:
			q = dns.Question{
				Name:   rr.Target,
				Qtype:  dns.TypeA,
				Qclass: dns.ClassINET,
			}
		default:
			continue
		}
		res := c.zone.query(q)
		if len(res) > 0 {
			for _, entry := range res {
				extra = append(append(extra, entry.RR), c.findExtra(entry.RR)...)
			}
		}
	}
	return
}

// encode an mdns msg and broadcast it on the wire
func (c *connector) writeMessage(msg *dns.Msg) (err error) {
	if buf, ok := msg.Pack(); ok {
		_, err = c.WriteToUDP(buf, c.UDPAddr)
	}
	return
}

// consume an mdns packet from the wire and decode it
func (c *connector) readMessage() (*dns.Msg, *net.UDPAddr, error) {
	buf := make([]byte, 1500)
	read, addr, err := c.ReadFromUDP(buf)
	if err != nil {
		return nil, nil, err
	}
	if msg := new(dns.Msg); msg.Unpack(buf[:read]) {
		return msg, addr, nil
	}
	return nil, addr, errors.New("Unable to unpack buffer")
}
<commit_msg>Small fix<commit_after>package mdns

// Advertise network services via multicast DNS

import (
	"errors"
	"log"
	"net"

	"dns"
	"github.com/davecheney/gmx"
)

var (
	ipv4mcastaddr = &net.UDPAddr{
		IP:   net.ParseIP("224.0.0.251"),
		Port: 5353,
	}

	ipv6mcastaddr = &net.UDPAddr{
		IP:   net.ParseIP("ff02::fb"),
		Port: 5353,
	}
	local *zone // the local mdns zone
)

func init() {
	local = &zone{
		entries: make(map[string]entries),
		add:     make(chan *entry),
		queries: make(chan *query, 16),
	}
	go local.mainloop()
	if err := local.listen(ipv4mcastaddr); err != nil {
		log.Fatalf("Failed to listen %s: %s", ipv4mcastaddr, err)
	}
	if err := local.listen(ipv6mcastaddr); err != nil {
		log.Printf("Failed to listen %s: %s", ipv6mcastaddr, err)
	}

	// publish gmx stats for the local zone
	gmx.Publish("mdns.zone.local.queries", func() interface{} {
		return local.queryCount
	})
	gmx.Publish("mdns.zone.local.entries", func() interface{} {
		return local.entryCount
	})

}

// Publish adds a record, described in RFC XXX
func Publish(r string) error {
	rr, err := dns.NewRR(r)
	if err != nil {
		return err
	}
	local.add <- &entry{rr}
	return nil
}

type entry struct {
	dns.RR
}

func (e *entry) fqdn() string {
	return e.Header().Name
}

type query struct {
	dns.Question
	result chan *entry
}

type entries []*entry

func (e entries) contains(entry *entry) bool {
	for _, ee := range e {
		if equals(entry, ee) {
			return true
		}
	}
	return false
}

type zone struct {
	entries map[string]entries
	add     chan *entry // add entries to zone
	queries chan *query // query exsting entries in zone

	// gmx statistics
	queryCount, entryCount int
}

func (z *zone) mainloop() {
	for {
		select {
		case entry := <-z.add:
			z.entryCount++
			if !z.entries[entry.fqdn()].contains(entry) {
				z.entries[entry.fqdn()] = append(z.entries[entry.fqdn()], entry)
			}
		case q := <-z.queries:
			z.queryCount++
			for _, entry := range z.entries[q.Question.Name] {
				if q.matches(entry) {
					q.result <- entry
				}
			}
			close(q.result)
		}
	}
}

func (z *zone) query(q dns.Question) (entries []*entry) {
	res := make(chan *entry, 16)
	z.queries <- &query{q, res}
	for e := range res {
		entries = append(entries, e)
	}
	return
}

func (q *query) matches(entry *entry) bool {
	return q.Question.Qtype == dns.TypeANY || q.Question.Qtype == entry.RR.Header().Rrtype
}

func equals(this, that *entry) bool {
	if _, ok := this.RR.(*dns.RR_ANY); ok {
		return true // *RR_ANY matches anything
	}
	if _, ok := that.RR.(*dns.RR_ANY); ok {
		return true // *RR_ANY matches all
	}
	return false
}

type connector struct {
	*net.UDPAddr
	*net.UDPConn
	*zone

	// gmx statistics
	questions, responses int
}

func (z *zone) listen(addr *net.UDPAddr) error {
	conn, err := openSocket(addr)
	if err != nil {
		return err
	}
	c := &connector{
		UDPAddr: addr,
		UDPConn: conn,
		zone:    z,
	}
	go c.mainloop()

	// publish gmx stats for the connector
	gmx.Publish("mdns.connector.questions", func() interface{} {
		return c.questions
	})
	gmx.Publish("mdns.connector.responses", func() interface{} {
		return c.responses
	})

	return nil
}

func openSocket(addr *net.UDPAddr) (*net.UDPConn, error) {
	switch addr.IP.To4() {
	case nil:
		return net.ListenMulticastUDP("udp6", nil, ipv6mcastaddr)
	default:
		return net.ListenMulticastUDP("udp4", nil, ipv4mcastaddr)
	}
	panic("unreachable")
}

func (c *connector) mainloop() {
	in := make(chan struct {
		*dns.Msg
		*net.UDPAddr
	}, 32)
	go func() {
		for {
			msg, addr, err := c.readMessage()
			if err != nil {
				// log dud packets
				log.Printf("Cound not read from %s: %s", c.UDPConn, err)
			}
			if msg.IsQuestion() {
				c.questions++
				in <- struct {
					*dns.Msg
					*net.UDPAddr
				}{msg, addr}
			}
		}
	}()
	for {
		msg := <-in
		msg.MsgHdr.Response = true // convert question to response
		for _, result := range c.query(msg.Question) {
			msg.Answer = append(msg.Answer, result.RR)
		}
		msg.Extra = append(msg.Extra, c.findExtra(msg.Answer...)...)
		if len(msg.Answer) > 0 {
			c.responses++
			if err := c.writeMessage(msg.Msg); err != nil {
				log.Fatalf("Cannot send: %s", err)
			}
		}
	}
}

func (c *connector) query(qs []dns.Question) (results []*entry) {
	for _, q := range qs {
		results = append(results, c.zone.query(q)...)
	}
	return
}

// recursively probe for related records
func (c *connector) findExtra(r ...dns.RR) (extra []dns.RR) {
	for _, rr := range r {
		var q dns.Question
		switch rr := rr.(type) {
		case *dns.RR_PTR:
			q = dns.Question{
				Name:   rr.Ptr,
				Qtype:  dns.TypeANY,
				Qclass: dns.ClassINET,
			}
		case *dns.RR_SRV:
			q = dns.Question{
				Name:   rr.Target,
				Qtype:  dns.TypeA,
				Qclass: dns.ClassINET,
			}
		default:
			continue
		}
		res := c.zone.query(q)
		if len(res) > 0 {
			for _, entry := range res {
				extra = append(append(extra, entry.RR), c.findExtra(entry.RR)...)
			}
		}
	}
	return
}

// encode an mdns msg and broadcast it on the wire
func (c *connector) writeMessage(msg *dns.Msg) (err error) {
	if buf, ok := msg.Pack(); ok {
		_, err = c.WriteToUDP(buf, c.UDPAddr)
	}
	return
}

// consume an mdns packet from the wire and decode it
func (c *connector) readMessage() (*dns.Msg, *net.UDPAddr, error) {
	buf := make([]byte, 1500)
	read, addr, err := c.ReadFromUDP(buf)
	if err != nil {
		return nil, nil, err
	}
	if msg := new(dns.Msg); msg.Unpack(buf[:read]) {
		return msg, addr, nil
	}
	return nil, addr, errors.New("Unable to unpack buffer")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	_ "strings"
	"github.com/jessevdk/go-flags"
	"time"
)

type Cookbook struct {
	Location string
}

type Artifact struct {
	Id string
	Version string
	Location string
}

type Release struct {
	Time      int
	Cookbooks []Cookbook
	Artifacts []Artifact
}

var opts struct {
	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
	ArtifactIds []string `short:"i" long:"artifact-id" description:"An artifact id"`
	ArtifactVersions []string `short:"v" long:"artifact-version" description:"An artifact version"`
	ArtifactLocations []string `short:"l" long:"artifact-location" description:"An artifact location"`
	Cookbooks []string `short:"c" long:"cookbook" description:"A cookbook location"`
}

func help() {
	fmt.Printf(`Usage: menu <command> <arguments and options>

Commands:
	help
	create
	show
	artifacts
	cookbooks
	list
`)
}

func helpHelp() {
	fmt.Printf(`Usage: menu help <command>

Commands:
	help
	create
	show
	artifacts
	cookbooks
	list
`)
}

func helpCreate() {
	fmt.Printf(`Usage: menu create

Options:
	-ai,--artifact-id
	-av,--artifact-version
	-al,--artifact-location
	-c,--cookbook
`)
}

func helpShow() {
	fmt.Printf(`Usage: menu show <path>
`)
}

func helpArtifacts() {
	fmt.Printf(`Usage: menu artifacts <path>
`)
}

func helpCookbooks() {
	fmt.Printf(`Usage: menu cookbooks <path>
`)
}

func helpList() {
	fmt.Printf(`Usage: menu list <options>

Options:
	-ai,--artifact-id
	-av,--artifact-version
	-al,--artifact-location
	-c,--cookbook
`)
}

func main() {
	args, err := flags.Parse(&opts)

	if err != nil {
		panic(err)
		help()
		os.Exit(1)
	}
	if len(args) == 0 {
		help()
		os.Exit(1)
	}

	if args[0] == "help" {
		handleHelp(args)
		os.Exit(0)
	}
	if args[0] == "create" {
		handleCreate(args)
		os.Exit(0)
	}

	/*
	fmt.Printf("Verbosity: %v\n", opts.Verbose)
	fmt.Printf("Cookbooks: %v\n", opts.Cookbooks)
	fmt.Printf("Command: %s\n", args[0])
	fmt.Printf("Remaining args: %s\n", strings.Join(args[1:], " "))
	*/
}

func handleHelp(args []string) {
	if len(args) > 1 {
		if args[1] == "create" {
			helpCreate()
			return
		}
		if args[1] == "show" {
			helpShow()
			return
		}
		if args[1] == "cookbooks" {
			helpCookbooks()
			return
		}
		if args[1] == "artifacts" {
			helpArtifacts()
			return
		}
		if args[1] == "list" {
			helpList()
			return
		}
	}
	helpHelp()
}

func handleCreate(args []string) {
	// [todo] Validate the options.
	if len(opts.ArtifactIds) != len(opts.ArtifactVersions) {
		fmt.Println("An equal number of artifact ids, versions and locations are required.")
		helpCreate()
		os.Exit(1)
	}
	if len(opts.ArtifactVersions) != len(opts.ArtifactLocations) {
		fmt.Println("An equal number of artifact ids, versions and locations are required.")
		helpCreate()
		os.Exit(1)
	}

	artifacts := make([]Artifact, len(opts.ArtifactVersions))
	cookbooks := make([]Cookbook, len(opts.Cookbooks))

	for i := 0; i < len(opts.ArtifactIds); i++ {
		artifact := Artifact{
			Id: opts.ArtifactIds[i],
			Version: opts.ArtifactVersions[i],
			Location: opts.ArtifactLocations[i],
		}
		artifacts[i] = artifact
	}

	for i := 0; i < len(opts.Cookbooks); i++ {
		cookbook := Cookbook{
			Location: opts.Cookbooks[i],
		}
		cookbooks[i] = cookbook
	}

	createdAt := time.Now().Unix()

	release := Release{
		Time: int(createdAt),
		Artifacts: artifacts,
		Cookbooks: cookbooks,
	}

	b, err := json.Marshal(release)
	if err != nil {
		fmt.Println("error:", err)
		os.Exit(1)
	}
	fmt.Println(string(b))
}

func handleShow(args []string) {
	helpShow()
}

func handleArtifacts(args []string) {
	helpArtifacts()
}

func handleCookbooks(args []string) {
	helpCookbooks()
}

func handleList(args []string) {
	helpList()
}
<commit_msg>Filling in create logic.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	_ "strings"
	"github.com/jessevdk/go-flags"
	"time"
	"path/filepath"
	"io/ioutil"
)

type Cookbook struct {
	Location string
}

type Artifact struct {
	Id string
	Version string
	Location string
}

type Release struct {
	Time      int
	Cookbooks []Cookbook
	Artifacts []Artifact
}

var opts struct {
	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
	ArtifactIds []string `short:"i" long:"artifact-id" description:"An artifact id"`
	ArtifactVersions []string `short:"v" long:"artifact-version" description:"An artifact version"`
	ArtifactLocations []string `short:"l" long:"artifact-location" description:"An artifact location"`
	Cookbooks []string `short:"c" long:"cookbook" description:"A cookbook location"`
}

func help() {
	fmt.Printf(`Usage: menu <command> <arguments and options>

Commands:
	help
	create
	show
	artifacts
	cookbooks
	list
`)
}

func helpHelp() {
	fmt.Printf(`Usage: menu help <command>

Commands:
	help
	create
	show
	artifacts
	cookbooks
	list
`)
}

func helpCreate() {
	fmt.Printf(`Usage: menu create

Options:
	-ai,--artifact-id
	-av,--artifact-version
	-al,--artifact-location
	-c,--cookbook
`)
}

func helpShow() {
	fmt.Printf(`Usage: menu show <path>
`)
}

func helpArtifacts() {
	fmt.Printf(`Usage: menu artifacts <path>
`)
}

func helpCookbooks() {
	fmt.Printf(`Usage: menu cookbooks <path>
`)
}

func helpList() {
	fmt.Printf(`Usage: menu list <options>

Options:
	-ai,--artifact-id
	-av,--artifact-version
	-al,--artifact-location
	-c,--cookbook
`)
}

func main() {
	args, err := flags.Parse(&opts)

	if err != nil {
		panic(err)
		help()
		os.Exit(1)
	}
	if len(args) == 0 {
		help()
		os.Exit(1)
	}

	if args[0] == "help" {
		handleHelp(args)
		os.Exit(0)
	}
	if args[0] == "create" {
		handleCreate(args)
		os.Exit(0)
	}

	/*
	fmt.Printf("Verbosity: %v\n", opts.Verbose)
	fmt.Printf("Cookbooks: %v\n", opts.Cookbooks)
	fmt.Printf("Command: %s\n", args[0])
	fmt.Printf("Remaining args: %s\n", strings.Join(args[1:], " "))
	*/
}

func handleHelp(args []string) {
	if len(args) > 1 {
		if args[1] == "create" {
			helpCreate()
			return
		}
		if args[1] == "show" {
			helpShow()
			return
		}
		if args[1] == "cookbooks" {
			helpCookbooks()
			return
		}
		if args[1] == "artifacts" {
			helpArtifacts()
			return
		}
		if args[1] == "list" {
			helpList()
			return
		}
	}
	helpHelp()
}

func handleCreate(args []string) {
	// [todo] Validate the options.
	if len(opts.ArtifactIds) != len(opts.ArtifactVersions) {
		fmt.Println("An equal number of artifact ids, versions and locations are required.")
		helpCreate()
		os.Exit(1)
	}
	if len(opts.ArtifactVersions) != len(opts.ArtifactLocations) {
		fmt.Println("An equal number of artifact ids, versions and locations are required.")
		helpCreate()
		os.Exit(1)
	}

	artifacts := make([]Artifact, len(opts.ArtifactVersions))
	cookbooks := make([]Cookbook, len(opts.Cookbooks))

	for i := 0; i < len(opts.ArtifactIds); i++ {
		artifact := Artifact{
			Id: opts.ArtifactIds[i],
			Version: opts.ArtifactVersions[i],
			Location: opts.ArtifactLocations[i],
		}
		artifacts[i] = artifact
	}

	for i := 0; i < len(opts.Cookbooks); i++ {
		cookbook := Cookbook{
			Location: opts.Cookbooks[i],
		}
		cookbooks[i] = cookbook
	}

	createdAt := time.Now().Unix()

	release := Release{
		Time: int(createdAt),
		Artifacts: artifacts,
		Cookbooks: cookbooks,
	}

	b, err := json.Marshal(release)
	if err != nil {
		fmt.Println("error:", err)
		os.Exit(1)
	}
	fmt.Println(string(b))

	path := getCreatePath(release, args)
	dir, fileName := filepath.Split(path)
	fmt.Println("Writing file ", fileName, " to directory ", dir)

	dirExists := false
	dirExists, err = exists(dir); if err != nil {
		panic(err)
	}
	if dirExists == false {
		err = os.MkdirAll(dir, os.ModeDir); if err != nil {
			panic(err)
		}
	}
	err = ioutil.WriteFile(path, b, 0644); if err != nil {
		panic(err)
	}
}

func exists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func getCreatePath(release Release, args []string) string {
	if len(args) > 1 {
		return args[1]
	}
	cwd, err := os.Getwd(); if err != nil {
		panic(err)
	}
	fileName := fmt.Sprintf("%v.menu", release.Time)
	return filepath.Join(cwd, fileName)
}

func handleShow(args []string) {
	helpShow()
}

func handleArtifacts(args []string) {
	helpArtifacts()
}

func handleCookbooks(args []string) {
	helpCookbooks()
}

func handleList(args []string) {
	helpList()
}
<|endoftext|>


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

// Package meth is a thin wrapper around upper.io/db to ease some repettitive tasks
package meth

import (
	"errors"
	"reflect"
	"upper.io/db"
	"upper.io/db/util"
)

// Shared error codes
var (
	ErrNoID    = errors.New(`no id field found`)
	ErrNoSlice = errors.New(`slice expected`)
)

type (
	// Persistent is the interface that allows us to communicate with upper.io/db collection
	Persistent interface {
		Collection() db.Collection
	}
	// resFunc is a func type to operate over results
	resFunc func(db.Result)
)

// The next functions are basically alias for their upper counterparts
// the documentation is mostly stolen from upper

// Limit defines the maximum number of results, returns a resFunc usable on AllOp
func Limit(u uint) resFunc {
	return func(r db.Result) {
		r.Limit(u)
	}
}

// Skip ignores the first *n* results, returns a resFunc usable on AllOp
func Skip(n uint) resFunc {
	return func(r db.Result) {
		r.Skip(n)
	}
}

// Sort receives field names that define the order in which elements will
// be returned in a query, field names may be prefixed with a minus sign (-)
// indicating descending order; ascending order would be used by default.
// also returns a resFunc
func Sort(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Sort(i...)
	}
}

// Select defines specific fields to be fulfilled on results in this result
// set.
func Select(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Select(i...)
	}
}

// Where discards the initial filtering conditions and sets new ones.
func Where(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Where(i...)
	}
}

// Group is used to group results that have the same value in the same
// column or columns.
func Group(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Group(i...)
	}
}

// Paginate applies a limit and skip to a result set
func Paginate(limit, skip uint) resFunc {
	return func(r db.Result) {
		r.Limit(limit)
		r.Skip(skip)
	}
}

// One fills p with one element based on the id field
func One(p Persistent) error {
	col := p.Collection()

	id, err := getID(p)
	if err != nil {
		return err
	}

	res := col.Find(db.Cond{`id`: id})

	if err := res.One(p); err != nil {
		return err
	}

	return nil
}

// OneBy fills p with one element matching the given conditions
func OneBy(p Persistent, cond ...interface{}) error {
	col := p.Collection()
	res := col.Find(cond...)

	if err := res.One(p); err != nil {
		return err
	}

	return nil
}

// AllBy fills rows with data from the result set matching the given conditions
func AllBy(p Persistent, rows interface{}, cond ...interface{}) error {
	col := p.Collection()
	res := col.Find(cond...)

	if err := res.All(rows); err != nil {
		return err
	}

	return nil
}

// All works as an alias for AllBy
func All(p Persistent, rows interface{}, cond ...interface{}) error {
	return AllBy(p, rows, cond...)
}

// Exists returns true if a record exists matching either id or the given conditions
func Exists(p Persistent, cond ...interface{}) bool {
	col := p.Collection()

	if len(cond) < 1 {
		id, _ := getID(p)
		cond = []interface{}{db.Cond{`id`: id}}
	}

	res := col.Find(cond...)

	count, _ := res.Count()

	return count > 0
}

// AllOp works like All but applies an operation in form of resFunc [func(*db.Result)] to work
// with the result set [for things like select, group, limit]
func AllOp(p Persistent, operation resFunc, rows interface{}, cond ...interface{}) error {
	col := p.Collection()

	res := col.Find(cond...)

	operation(res)

	err := res.All(rows)

	return err
}

// OneOp works like AllOp but returns only one row
func OneOp(p Persistent, operation resFunc, row interface{}, cond ...interface{}) error {
	col := p.Collection()

	res := col.Find(cond...)

	operation(res)

	err := res.One(row)

	return err
}

func getID(p interface{}) (int64, error) {
	valP := getValue(p)
	i := util.GetStructFieldIndex(valP.Type(), `id`)
	if len(i) != 1 {
		return 0, ErrNoID
	}

	id := valP.FieldByIndex(i).Int()

	return id, nil
}

func getValue(t interface{}) (rslt reflect.Value) {
	rslt = reflect.ValueOf(t)
	for rslt.Kind() == reflect.Ptr {
		rslt = rslt.Elem()
	}

	return
}

func isSlice(t interface{}) bool {
	if k := reflect.TypeOf(t).Kind(); k == reflect.Slice {
		return true
	}

	return false
}
<commit_msg>comment unexported functions<commit_after>// Copyright (c) 2014 Hiram Jerónimo Pérez worg{at}linuxmail[dot]org
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package meth is a thin wrapper around upper.io/db to ease some repettitive tasks
package meth

import (
	"errors"
	"reflect"
	"upper.io/db"
	"upper.io/db/util"
)

// Shared error codes
var (
	ErrNoID    = errors.New(`no id field found`)
	ErrNoSlice = errors.New(`slice expected`)
)

type (
	// Persistent is the interface that allows us to communicate with upper.io/db collection
	Persistent interface {
		Collection() db.Collection
	}
	// resFunc is a func type to operate over results
	resFunc func(db.Result)
)

// The next functions are basically alias for their upper counterparts
// the documentation is mostly stolen from upper

// Limit defines the maximum number of results, returns a resFunc usable on AllOp
func Limit(u uint) resFunc {
	return func(r db.Result) {
		r.Limit(u)
	}
}

// Skip ignores the first *n* results, returns a resFunc usable on AllOp
func Skip(n uint) resFunc {
	return func(r db.Result) {
		r.Skip(n)
	}
}

// Sort receives field names that define the order in which elements will
// be returned in a query, field names may be prefixed with a minus sign (-)
// indicating descending order; ascending order would be used by default.
// also returns a resFunc
func Sort(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Sort(i...)
	}
}

// Select defines specific fields to be fulfilled on results in this result
// set.
func Select(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Select(i...)
	}
}

// Where discards the initial filtering conditions and sets new ones.
func Where(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Where(i...)
	}
}

// Group is used to group results that have the same value in the same
// column or columns.
func Group(i ...interface{}) resFunc {
	return func(r db.Result) {
		r.Group(i...)
	}
}

// Paginate applies a limit and skip to a result set
func Paginate(limit, skip uint) resFunc {
	return func(r db.Result) {
		r.Limit(limit)
		r.Skip(skip)
	}
}

// One fills p with one element based on the id field
func One(p Persistent) error {
	col := p.Collection()

	id, err := getID(p)
	if err != nil {
		return err
	}

	res := col.Find(db.Cond{`id`: id})

	if err := res.One(p); err != nil {
		return err
	}

	return nil
}

// OneBy fills p with one element matching the given conditions
func OneBy(p Persistent, cond ...interface{}) error {
	col := p.Collection()
	res := col.Find(cond...)

	if err := res.One(p); err != nil {
		return err
	}

	return nil
}

// AllBy fills rows with data from the result set matching the given conditions
func AllBy(p Persistent, rows interface{}, cond ...interface{}) error {
	col := p.Collection()
	res := col.Find(cond...)

	if err := res.All(rows); err != nil {
		return err
	}

	return nil
}

// All works as an alias for AllBy
func All(p Persistent, rows interface{}, cond ...interface{}) error {
	return AllBy(p, rows, cond...)
}

// Exists returns true if a record exists matching either id or the given conditions
func Exists(p Persistent, cond ...interface{}) bool {
	col := p.Collection()

	if len(cond) < 1 {
		id, _ := getID(p)
		cond = []interface{}{db.Cond{`id`: id}}
	}

	res := col.Find(cond...)

	count, _ := res.Count()

	return count > 0
}

// AllOp works like All but applies an operation in form of resFunc [func(*db.Result)] to work
// with the result set [for things like select, group, limit]
func AllOp(p Persistent, operation resFunc, rows interface{}, cond ...interface{}) error {
	col := p.Collection()

	res := col.Find(cond...)

	operation(res)

	err := res.All(rows)

	return err
}

// OneOp works like AllOp but returns only one row
func OneOp(p Persistent, operation resFunc, row interface{}, cond ...interface{}) error {
	col := p.Collection()

	res := col.Find(cond...)

	operation(res)

	err := res.One(row)

	return err
}

// getID Returns the id field from a struct
func getID(p interface{}) (int64, error) {
	valP := getValue(p)
	i := util.GetStructFieldIndex(valP.Type(), `id`)
	if len(i) != 1 {
		return 0, ErrNoID
	}

	id := valP.FieldByIndex(i).Int()

	return id, nil
}

// getValue Returns a reflect.Value from an interface taking care of pointers when needed
func getValue(t interface{}) (rslt reflect.Value) {
	rslt = reflect.ValueOf(t)
	for rslt.Kind() == reflect.Ptr {
		rslt = rslt.Elem()
	}

	return
}

// isSlice Check if an interface is a slice
func isSlice(t interface{}) bool {
	if k := reflect.TypeOf(t).Kind(); k == reflect.Slice {
		return true
	}

	return false
}
<|endoftext|>


<commit_before>// myLG is command line looking glass that written with Go language
// it tries from its own icmp and external looking glasses tools
package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/http/ping"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"github.com/mehrdadrad/mylg/ns"
	"github.com/mehrdadrad/mylg/peeringdb"
	"github.com/mehrdadrad/mylg/scan"
	"github.com/mehrdadrad/mylg/whois"
)

// Provider represents looking glass
type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() []string
	ChangeNode(node string) bool
	Ping() (string, error)
	Trace() chan string
	BGP() chan string
}

const (
	version = "0.1.8"
)

var (
	// register looking glass hosts
	providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3), "cogent": new(lg.Cogent)}
	pNames    = providerNames()
	req       = make(chan string, 1)
	nxt       = make(chan struct{}, 1)
	spin      = spinner.New(spinner.CharSets[26], 220*time.Millisecond)
	args      string
	prompt    string
	cPName    string
	nsr       *ns.Request
	c         *cli.Readline
)

// providerName
func providerNames() []string {
	pNames := []string{}
	for p := range providers {
		pNames = append(pNames, p)
	}
	return pNames
}

// validateProvider
func validateProvider(p string) (string, error) {
	pNames := []string{}
	match, _ := regexp.MatchString("("+strings.Join(pNames, "|")+")", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	}
	return "", errors.New("provider not support")

}
func init() {
	// initialize cli
	c = cli.Init("local", version)
	go c.Run(req, nxt)
	// initialize name server
	nsr = ns.NewRequest()
	go nsr.Init()
	// set default provider
	cPName = "local"
}

func main() {
	var (
		request string
		loop    = true
	)

	r, _ := regexp.Compile(`(ping|trace|bgp|lg|ns|dig|whois|peering|scan|hping|connect|node|local|mode|help|exit|quit)\s{0,1}(.*)`)

	for loop {
		select {
		case request, loop = <-req:
			if !loop {
				break
			}
			if len(request) < 1 {
				c.Next()
				continue
			}
			subReq := r.FindStringSubmatch(request)
			if len(subReq) == 0 {
				println("syntax error")
				c.Next()
				continue
			}
			prompt = c.GetPrompt()
			args = strings.TrimSpace(subReq[2])
			cmd := strings.TrimSpace(subReq[1])
			switch {
			case cmd == "hping" && cPName == "local":
				hping()
			case cmd == "ping" && cPName == "local":
				pingLocal()
			case cmd == "ping":
				pingLG()
			case cmd == "trace":
				trace()
			case cmd == "bgp":
				BGP()
			case cmd == "dig":
				nsr.Dig(args)
			case cmd == "node":
				node()
			case cmd == "local":
				nsr.Local()
				cPName = "local"
				c.SetPrompt(cPName)
			case cmd == "connect":
				connect()
			case cmd == "lg":
				c.SetPrompt("lg")
				c.UpdateCompleter("connect", pNames)
			case cmd == "ns":
				c.UpdateCompleter("connect", nsr.CountryList())
				c.UpdateCompleter("node", []string{})
				c.SetPrompt("ns")
			case cmd == "whois":
				whois.Lookup(args)
			case cmd == "peering":
				peeringdb.Search(args)
			case cmd == "scan":
				scanPorts()
			case cmd == "mode":
				mode()
			case cmd == "help":
				c.Help()
			case cmd == "exit", cmd == "quit":
				c.Close(nxt)
				close(req)
			}
			// next line
			c.Next()
		}
	}
}

// node handles node cmd
func node() {
	switch {
	case strings.HasPrefix(prompt, "lg"):
		if _, ok := providers[cPName]; ok {
			if providers[cPName].ChangeNode(args) {
				c.UpdatePromptN(args, 3)
				return
			}
		}
		println("the specified node doesn't support")
	case strings.HasPrefix(prompt, "ns"):
		if !nsr.ChkNode(args) {
			println("error: argument is not valid")
		} else {
			c.UpdatePromptN(args, 3)
		}
	default:
		if cPName == "local" {
			println("local doesn't support node")
		}

	}
}

// connect handles connect cmd
func connect() {
	var (
		pName string
		err   error
	)
	switch {
	case strings.HasPrefix(prompt, "lg"):
		if pName, err = validateProvider(args); err != nil {
			println("provider not available")
			c.Next()
			return
		}
		cPName = pName
		if _, ok := providers[cPName]; ok {
			c.UpdatePromptN(cPName+"/"+providers[cPName].GetDefaultNode(), 2)
			go func() {
				c.UpdateCompleter("node", providers[cPName].GetNodes())
			}()
		} else {
			println("it doesn't support")
		}
	case strings.HasPrefix(prompt, "ns"):
		if !nsr.ChkCountry(args) {
			println("error: argument is not valid")
		} else {
			c.SetPrompt("ns/" + args)
			c.UpdateCompleter("node", nsr.NodeList())
		}
	}
}

// mode set editor mode
func mode() {
	if args == "vim" {
		c.SetVim()
	} else if args == "emacs" {
		c.SetEmacs()
	} else {
		println("the request mode doesn't support")
	}
}

// trace tries to trace from local and lg
func trace() {
	switch {
	case strings.HasPrefix(prompt, "local"):
		trace := icmp.Trace{}
		trace.Run(args)
	case strings.HasPrefix(prompt, "lg"):
		providers[cPName].Set(args, "ipv4")
		for l := range providers[cPName].Trace() {
			println(l)
		}
	}
}

// hping tries to ping a web server by http
func hping() {
	p, err := ping.NewPing(args)
	if err != nil {
		println(err.Error())
	} else {
		p.Run()
	}
}

// pingLG tries to ping through a looking glass
func pingLG() {
	spin.Prefix = "please wait "
	spin.Start()
	providers[cPName].Set(args, "ipv4")
	m, err := providers[cPName].Ping()
	spin.Stop()
	if err != nil {
		println(err.Error())
	} else {
		println(m)
	}
}

// pingLocal tries to ping from local source ip
func pingLocal() {
	p, err := icmp.NewPing(args)
	if err != nil {
		return
	}
	p.Run()
}

// scanPorts tries to scan tcp/ip ports
func scanPorts() {
	scan, err := scan.NewScan(args)
	if err != nil {
		println(err.Error())
	} else {
		scan.Run()
	}
}

// BGP tries to get BGP lookup from a LG
func BGP() {
	if cPName == "local" {
		println("no provider selected")
		return
	}
	providers[cPName].Set(args, "ipv4")
	for l := range providers[cPName].BGP() {
		println(l)
	}
}
<commit_msg>added web service for testing<commit_after>// myLG is command line looking glass that written with Go language
// it tries from its own icmp and external looking glasses tools
package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/http/ping"
	"github.com/mehrdadrad/mylg/http/server"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"github.com/mehrdadrad/mylg/ns"
	"github.com/mehrdadrad/mylg/peeringdb"
	"github.com/mehrdadrad/mylg/scan"
	"github.com/mehrdadrad/mylg/whois"
)

// Provider represents looking glass
type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() []string
	ChangeNode(node string) bool
	Ping() (string, error)
	Trace() chan string
	BGP() chan string
}

const (
	version = "0.1.8"
)

var (
	// register looking glass hosts
	providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3), "cogent": new(lg.Cogent)}
	pNames    = providerNames()
	req       = make(chan string, 1)
	nxt       = make(chan struct{}, 1)
	spin      = spinner.New(spinner.CharSets[26], 220*time.Millisecond)
	args      string
	prompt    string
	cPName    string
	nsr       *ns.Request
	c         *cli.Readline
)

// providerName
func providerNames() []string {
	pNames := []string{}
	for p := range providers {
		pNames = append(pNames, p)
	}
	return pNames
}

// validateProvider
func validateProvider(p string) (string, error) {
	pNames := []string{}
	match, _ := regexp.MatchString("("+strings.Join(pNames, "|")+")", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	}
	return "", errors.New("provider not support")

}
func init() {
	// initialize cli
	c = cli.Init("local", version)
	go c.Run(req, nxt)
	// initialize name server
	nsr = ns.NewRequest()
	go nsr.Init()
	// start web server
	go server.Run()
	// set default provider
	cPName = "local"
}

func main() {
	var (
		request string
		loop    = true
	)

	r, _ := regexp.Compile(`(ping|trace|bgp|lg|ns|dig|whois|peering|scan|hping|connect|node|local|mode|help|exit|quit)\s{0,1}(.*)`)

	for loop {
		select {
		case request, loop = <-req:
			if !loop {
				break
			}
			if len(request) < 1 {
				c.Next()
				continue
			}
			subReq := r.FindStringSubmatch(request)
			if len(subReq) == 0 {
				println("syntax error")
				c.Next()
				continue
			}
			prompt = c.GetPrompt()
			args = strings.TrimSpace(subReq[2])
			cmd := strings.TrimSpace(subReq[1])
			switch {
			case cmd == "hping" && cPName == "local":
				hping()
			case cmd == "ping" && cPName == "local":
				pingLocal()
			case cmd == "ping":
				pingLG()
			case cmd == "trace":
				trace()
			case cmd == "bgp":
				BGP()
			case cmd == "dig":
				nsr.Dig(args)
			case cmd == "node":
				node()
			case cmd == "local":
				nsr.Local()
				cPName = "local"
				c.SetPrompt(cPName)
			case cmd == "connect":
				connect()
			case cmd == "lg":
				c.SetPrompt("lg")
				c.UpdateCompleter("connect", pNames)
			case cmd == "ns":
				c.UpdateCompleter("connect", nsr.CountryList())
				c.UpdateCompleter("node", []string{})
				c.SetPrompt("ns")
			case cmd == "whois":
				whois.Lookup(args)
			case cmd == "peering":
				peeringdb.Search(args)
			case cmd == "scan":
				scanPorts()
			case cmd == "mode":
				mode()
			case cmd == "help":
				c.Help()
			case cmd == "exit", cmd == "quit":
				c.Close(nxt)
				close(req)
			}
			// next line
			c.Next()
		}
	}
}

// node handles node cmd
func node() {
	switch {
	case strings.HasPrefix(prompt, "lg"):
		if _, ok := providers[cPName]; ok {
			if providers[cPName].ChangeNode(args) {
				c.UpdatePromptN(args, 3)
				return
			}
		}
		println("the specified node doesn't support")
	case strings.HasPrefix(prompt, "ns"):
		if !nsr.ChkNode(args) {
			println("error: argument is not valid")
		} else {
			c.UpdatePromptN(args, 3)
		}
	default:
		if cPName == "local" {
			println("local doesn't support node")
		}

	}
}

// connect handles connect cmd
func connect() {
	var (
		pName string
		err   error
	)
	switch {
	case strings.HasPrefix(prompt, "lg"):
		if pName, err = validateProvider(args); err != nil {
			println("provider not available")
			c.Next()
			return
		}
		cPName = pName
		if _, ok := providers[cPName]; ok {
			c.UpdatePromptN(cPName+"/"+providers[cPName].GetDefaultNode(), 2)
			go func() {
				c.UpdateCompleter("node", providers[cPName].GetNodes())
			}()
		} else {
			println("it doesn't support")
		}
	case strings.HasPrefix(prompt, "ns"):
		if !nsr.ChkCountry(args) {
			println("error: argument is not valid")
		} else {
			c.SetPrompt("ns/" + args)
			c.UpdateCompleter("node", nsr.NodeList())
		}
	}
}

// mode set editor mode
func mode() {
	if args == "vim" {
		c.SetVim()
	} else if args == "emacs" {
		c.SetEmacs()
	} else {
		println("the request mode doesn't support")
	}
}

// trace tries to trace from local and lg
func trace() {
	switch {
	case strings.HasPrefix(prompt, "local"):
		trace := icmp.Trace{}
		trace.Run(args)
	case strings.HasPrefix(prompt, "lg"):
		providers[cPName].Set(args, "ipv4")
		for l := range providers[cPName].Trace() {
			println(l)
		}
	}
}

// hping tries to ping a web server by http
func hping() {
	p, err := ping.NewPing(args)
	if err != nil {
		println(err.Error())
	} else {
		p.Run()
	}
}

// pingLG tries to ping through a looking glass
func pingLG() {
	spin.Prefix = "please wait "
	spin.Start()
	providers[cPName].Set(args, "ipv4")
	m, err := providers[cPName].Ping()
	spin.Stop()
	if err != nil {
		println(err.Error())
	} else {
		println(m)
	}
}

// pingLocal tries to ping from local source ip
func pingLocal() {
	p, err := icmp.NewPing(args)
	if err != nil {
		return
	}
	p.Run()
}

// scanPorts tries to scan tcp/ip ports
func scanPorts() {
	scan, err := scan.NewScan(args)
	if err != nil {
		println(err.Error())
	} else {
		scan.Run()
	}
}

// BGP tries to get BGP lookup from a LG
func BGP() {
	if cPName == "local" {
		println("no provider selected")
		return
	}
	providers[cPName].Set(args, "ipv4")
	for l := range providers[cPName].BGP() {
		println(l)
	}
}
<|endoftext|>