<commit_before>package azure

import (
	"fmt"
	"net/url"
)

const (
	activeDirectoryAPIVersion = "1.0"
)

// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
	Name                      string `json:"name"`
	ManagementPortalURL       string `json:"managementPortalURL"`
	PublishSettingsURL        string `json:"publishSettingsURL"`
	ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
	ResourceManagerEndpoint   string `json:"resourceManagerEndpoint"`
	ActiveDirectoryEndpoint   string `json:"activeDirectoryEndpoint"`
	GalleryEndpoint           string `json:"galleryEndpoint"`
	KeyVaultEndpoint          string `json:"keyVaultEndpoint"`
	GraphEndpoint             string `json:"graphEndpoint"`
	StorageEndpointSuffix     string `json:"storageEndpointSuffix"`
	SQLDatabaseDNSSuffix      string `json:"sqlDatabaseDNSSuffix"`
	TrafficManagerDNSSuffix   string `json:"trafficManagerDNSSuffix"`
	KeyVaultDNSSuffix         string `json:"keyVaultDNSSuffix"`
	ServiceBusEndpointSuffix  string `json:"serviceBusEndpointSuffix"`
}

var (
	// PublicCloud is the default public Azure cloud environment
	PublicCloud = Environment{
		Name:                      "AzurePublicCloud",
		ManagementPortalURL:       "https://manage.windowsazure.com/",
		PublishSettingsURL:        "https://manage.windowsazure.com/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.windows.net/",
		ResourceManagerEndpoint:   "https://management.azure.com/",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.com/",
		GalleryEndpoint:           "https://gallery.azure.com/",
		KeyVaultEndpoint:          "https://vault.azure.net/",
		GraphEndpoint:             "https://graph.windows.net/",
		StorageEndpointSuffix:     "core.windows.net",
		SQLDatabaseDNSSuffix:      "database.windows.net",
		TrafficManagerDNSSuffix:   "trafficmanager.net",
		KeyVaultDNSSuffix:         "vault.azure.net",
		ServiceBusEndpointSuffix:  "servicebus.azure.com",
	}

	// USGovernmentCloud is the cloud environment for the US Government
	USGovernmentCloud = Environment{
		Name:                      "AzureUSGovernmentCloud",
		ManagementPortalURL:       "https://manage.windowsazure.us/",
		PublishSettingsURL:        "https://manage.windowsazure.us/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
		ResourceManagerEndpoint:   "https://management.usgovcloudapi.net",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.com/",
		GalleryEndpoint:           "https://gallery.usgovcloudapi.net/",
		KeyVaultEndpoint:          "https://vault.usgovcloudapi.net/",
		GraphEndpoint:             "https://graph.usgovcloudapi.net/",
		StorageEndpointSuffix:     "core.usgovcloudapi.net",
		SQLDatabaseDNSSuffix:      "database.usgovcloudapi.net",
		TrafficManagerDNSSuffix:   "usgovtrafficmanager.net",
		KeyVaultDNSSuffix:         "vault.usgovcloudapi.net",
		ServiceBusEndpointSuffix:  "servicebus.usgovcloudapi.net",
	}

	// ChinaCloud is the cloud environment operated in China
	ChinaCloud = Environment{
		Name:                      "AzureChinaCloud",
		ManagementPortalURL:       "https://manage.chinacloudapi.com/",
		PublishSettingsURL:        "https://manage.chinacloudapi.com/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
		ResourceManagerEndpoint:   "https://management.chinacloudapi.cn/",
		ActiveDirectoryEndpoint:   "https://login.chinacloudapi.cn/?api-version=1.0",
		GalleryEndpoint:           "https://gallery.chinacloudapi.cn/",
		KeyVaultEndpoint:          "https://vault.azure.cn/",
		GraphEndpoint:             "https://graph.chinacloudapi.cn/",
		StorageEndpointSuffix:     "core.chinacloudapi.cn",
		SQLDatabaseDNSSuffix:      "database.chinacloudapi.cn",
		TrafficManagerDNSSuffix:   "trafficmanager.cn",
		KeyVaultDNSSuffix:         "vault.azure.cn",
		ServiceBusEndpointSuffix:  "servicebus.chinacloudapi.net",
	}

	// GermanCloud is the cloud environment operated in Germany
	GermanCloud = Environment{
		Name:                      "AzureGermanCloud",
		ManagementPortalURL:       "http://portal.microsoftazure.de/",
		PublishSettingsURL:        "https://manage.microsoftazure.de/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.cloudapi.de",
		ResourceManagerEndpoint:   "https://management.microsoftazure.de",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.de/",
		GalleryEndpoint:           "https://gallery.cloudapi.de/",
		KeyVaultEndpoint:          "https://vault.microsoftazure.de/",
		GraphEndpoint:             "https://graph.cloudapi.de/",
		StorageEndpointSuffix:     "core.cloudapi.de",
		SQLDatabaseDNSSuffix:      "database.cloudapi.de",
		TrafficManagerDNSSuffix:   "azuretrafficmanager.de",
		KeyVaultDNSSuffix:         "vault.microsoftazure.de",
		ServiceBusEndpointSuffix:  "servicebus.cloudapi.de",
	}
)

// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
	template := "%s/oauth2/%s?api-version=%s"
	u, err := url.Parse(env.ActiveDirectoryEndpoint)
	if err != nil {
		return nil, err
	}
	authorizeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "authorize", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}
	tokenURL, err := u.Parse(fmt.Sprintf(template, tenantID, "token", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}
	deviceCodeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "devicecode", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}

	return &OAuthConfig{
		AuthorizeEndpoint:  *authorizeURL,
		TokenEndpoint:      *tokenURL,
		DeviceCodeEndpoint: *deviceCodeURL,
	}, nil
}
<commit_msg>Add trailing / to endpoint<commit_after>package azure

import (
	"fmt"
	"net/url"
)

const (
	activeDirectoryAPIVersion = "1.0"
)

// Environment represents a set of endpoints for each of Azure's Clouds.
type Environment struct {
	Name                      string `json:"name"`
	ManagementPortalURL       string `json:"managementPortalURL"`
	PublishSettingsURL        string `json:"publishSettingsURL"`
	ServiceManagementEndpoint string `json:"serviceManagementEndpoint"`
	ResourceManagerEndpoint   string `json:"resourceManagerEndpoint"`
	ActiveDirectoryEndpoint   string `json:"activeDirectoryEndpoint"`
	GalleryEndpoint           string `json:"galleryEndpoint"`
	KeyVaultEndpoint          string `json:"keyVaultEndpoint"`
	GraphEndpoint             string `json:"graphEndpoint"`
	StorageEndpointSuffix     string `json:"storageEndpointSuffix"`
	SQLDatabaseDNSSuffix      string `json:"sqlDatabaseDNSSuffix"`
	TrafficManagerDNSSuffix   string `json:"trafficManagerDNSSuffix"`
	KeyVaultDNSSuffix         string `json:"keyVaultDNSSuffix"`
	ServiceBusEndpointSuffix  string `json:"serviceBusEndpointSuffix"`
}

var (
	// PublicCloud is the default public Azure cloud environment
	PublicCloud = Environment{
		Name:                      "AzurePublicCloud",
		ManagementPortalURL:       "https://manage.windowsazure.com/",
		PublishSettingsURL:        "https://manage.windowsazure.com/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.windows.net/",
		ResourceManagerEndpoint:   "https://management.azure.com/",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.com/",
		GalleryEndpoint:           "https://gallery.azure.com/",
		KeyVaultEndpoint:          "https://vault.azure.net/",
		GraphEndpoint:             "https://graph.windows.net/",
		StorageEndpointSuffix:     "core.windows.net",
		SQLDatabaseDNSSuffix:      "database.windows.net",
		TrafficManagerDNSSuffix:   "trafficmanager.net",
		KeyVaultDNSSuffix:         "vault.azure.net",
		ServiceBusEndpointSuffix:  "servicebus.azure.com",
	}

	// USGovernmentCloud is the cloud environment for the US Government
	USGovernmentCloud = Environment{
		Name:                      "AzureUSGovernmentCloud",
		ManagementPortalURL:       "https://manage.windowsazure.us/",
		PublishSettingsURL:        "https://manage.windowsazure.us/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.usgovcloudapi.net/",
		ResourceManagerEndpoint:   "https://management.usgovcloudapi.net/",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.com/",
		GalleryEndpoint:           "https://gallery.usgovcloudapi.net/",
		KeyVaultEndpoint:          "https://vault.usgovcloudapi.net/",
		GraphEndpoint:             "https://graph.usgovcloudapi.net/",
		StorageEndpointSuffix:     "core.usgovcloudapi.net",
		SQLDatabaseDNSSuffix:      "database.usgovcloudapi.net",
		TrafficManagerDNSSuffix:   "usgovtrafficmanager.net",
		KeyVaultDNSSuffix:         "vault.usgovcloudapi.net",
		ServiceBusEndpointSuffix:  "servicebus.usgovcloudapi.net",
	}

	// ChinaCloud is the cloud environment operated in China
	ChinaCloud = Environment{
		Name:                      "AzureChinaCloud",
		ManagementPortalURL:       "https://manage.chinacloudapi.com/",
		PublishSettingsURL:        "https://manage.chinacloudapi.com/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.chinacloudapi.cn/",
		ResourceManagerEndpoint:   "https://management.chinacloudapi.cn/",
		ActiveDirectoryEndpoint:   "https://login.chinacloudapi.cn/?api-version=1.0",
		GalleryEndpoint:           "https://gallery.chinacloudapi.cn/",
		KeyVaultEndpoint:          "https://vault.azure.cn/",
		GraphEndpoint:             "https://graph.chinacloudapi.cn/",
		StorageEndpointSuffix:     "core.chinacloudapi.cn",
		SQLDatabaseDNSSuffix:      "database.chinacloudapi.cn",
		TrafficManagerDNSSuffix:   "trafficmanager.cn",
		KeyVaultDNSSuffix:         "vault.azure.cn",
		ServiceBusEndpointSuffix:  "servicebus.chinacloudapi.net",
	}

	// GermanCloud is the cloud environment operated in Germany
	GermanCloud = Environment{
		Name:                      "AzureGermanCloud",
		ManagementPortalURL:       "http://portal.microsoftazure.de/",
		PublishSettingsURL:        "https://manage.microsoftazure.de/publishsettings/index",
		ServiceManagementEndpoint: "https://management.core.cloudapi.de/",
		ResourceManagerEndpoint:   "https://management.microsoftazure.de/",
		ActiveDirectoryEndpoint:   "https://login.microsoftonline.de/",
		GalleryEndpoint:           "https://gallery.cloudapi.de/",
		KeyVaultEndpoint:          "https://vault.microsoftazure.de/",
		GraphEndpoint:             "https://graph.cloudapi.de/",
		StorageEndpointSuffix:     "core.cloudapi.de",
		SQLDatabaseDNSSuffix:      "database.cloudapi.de",
		TrafficManagerDNSSuffix:   "azuretrafficmanager.de",
		KeyVaultDNSSuffix:         "vault.microsoftazure.de",
		ServiceBusEndpointSuffix:  "servicebus.cloudapi.de",
	}
)

// OAuthConfigForTenant returns an OAuthConfig with tenant specific urls
func (env Environment) OAuthConfigForTenant(tenantID string) (*OAuthConfig, error) {
	template := "%s/oauth2/%s?api-version=%s"
	u, err := url.Parse(env.ActiveDirectoryEndpoint)
	if err != nil {
		return nil, err
	}
	authorizeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "authorize", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}
	tokenURL, err := u.Parse(fmt.Sprintf(template, tenantID, "token", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}
	deviceCodeURL, err := u.Parse(fmt.Sprintf(template, tenantID, "devicecode", activeDirectoryAPIVersion))
	if err != nil {
		return nil, err
	}

	return &OAuthConfig{
		AuthorizeEndpoint:  *authorizeURL,
		TokenEndpoint:      *tokenURL,
		DeviceCodeEndpoint: *deviceCodeURL,
	}, nil
}
<|endoftext|>


<commit_before><commit_msg>wasm: Update generated binaries<commit_after><|endoftext|>


<commit_before>package leafnodes

import (
	"math"
	"time"

	"github.com/onsi/ginkgo/types"
)

type benchmarker struct {
	measurements map[string]*types.SpecMeasurement
	orderCounter int
}

func newBenchmarker() *benchmarker {
	return &benchmarker{
		measurements: make(map[string]*types.SpecMeasurement, 0),
	}
}

func (b *benchmarker) Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration) {
	t := time.Now()
	body()
	elapsedTime = time.Since(t)

	measurement := b.getMeasurement(name, "Fastest Time", "Slowest Time", "Average Time", "s", info...)
	measurement.Results = append(measurement.Results, elapsedTime.Seconds())

	return
}

func (b *benchmarker) RecordValue(name string, value float64, info ...interface{}) {
	measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", info...)
	measurement.Results = append(measurement.Results, value)
}

func (b *benchmarker) getMeasurement(name string, smallestLabel string, largestLabel string, averageLabel string, units string, info ...interface{}) *types.SpecMeasurement {
	measurement, ok := b.measurements[name]
	if !ok {
		var computedInfo interface{}
		computedInfo = nil
		if len(info) > 0 {
			computedInfo = info[0]
		}
		measurement = &types.SpecMeasurement{
			Name:          name,
			Info:          computedInfo,
			Order:         b.orderCounter,
			SmallestLabel: smallestLabel,
			LargestLabel:  largestLabel,
			AverageLabel:  averageLabel,
			Units:         units,
			Results:       make([]float64, 0),
		}
		b.measurements[name] = measurement
		b.orderCounter++
	}

	return measurement
}

func (b *benchmarker) measurementsReport() map[string]*types.SpecMeasurement {
	for _, measurement := range b.measurements {
		measurement.Smallest = math.MaxFloat64
		measurement.Largest = -math.MaxFloat64
		sum := float64(0)
		sumOfSquares := float64(0)

		for _, result := range measurement.Results {
			if result > measurement.Largest {
				measurement.Largest = result
			}
			if result < measurement.Smallest {
				measurement.Smallest = result
			}
			sum += result
			sumOfSquares += result * result
		}

		n := float64(len(measurement.Results))
		measurement.Average = sum / n
		measurement.StdDeviation = math.Sqrt(sumOfSquares/n - (sum/n)*(sum/n))
	}

	return b.measurements
}
<commit_msg>Fix data race<commit_after>package leafnodes

import (
	"math"
	"time"

	"sync"

	"github.com/onsi/ginkgo/types"
)

type benchmarker struct {
	mu           sync.Mutex
	measurements map[string]*types.SpecMeasurement
	orderCounter int
}

func newBenchmarker() *benchmarker {
	return &benchmarker{
		measurements: make(map[string]*types.SpecMeasurement, 0),
	}
}

func (b *benchmarker) Time(name string, body func(), info ...interface{}) (elapsedTime time.Duration) {
	t := time.Now()
	body()
	elapsedTime = time.Since(t)

    b.mu.Lock()
    defer b.mu.Unlock()
	measurement := b.getMeasurement(name, "Fastest Time", "Slowest Time", "Average Time", "s", info...)
	measurement.Results = append(measurement.Results, elapsedTime.Seconds())

	return
}

func (b *benchmarker) RecordValue(name string, value float64, info ...interface{}) {
	measurement := b.getMeasurement(name, "Smallest", " Largest", " Average", "", info...)
	b.mu.Lock()
	defer b.mu.Unlock()
	measurement.Results = append(measurement.Results, value)
}

func (b *benchmarker) getMeasurement(name string, smallestLabel string, largestLabel string, averageLabel string, units string, info ...interface{}) *types.SpecMeasurement {
	measurement, ok := b.measurements[name]
	if !ok {
		var computedInfo interface{}
		computedInfo = nil
		if len(info) > 0 {
			computedInfo = info[0]
		}
		measurement = &types.SpecMeasurement{
			Name:          name,
			Info:          computedInfo,
			Order:         b.orderCounter,
			SmallestLabel: smallestLabel,
			LargestLabel:  largestLabel,
			AverageLabel:  averageLabel,
			Units:         units,
			Results:       make([]float64, 0),
		}
		b.measurements[name] = measurement
		b.orderCounter++
	}

	return measurement
}

func (b *benchmarker) measurementsReport() map[string]*types.SpecMeasurement {
	b.mu.Lock()
	defer b.mu.Unlock()
	for _, measurement := range b.measurements {
		measurement.Smallest = math.MaxFloat64
		measurement.Largest = -math.MaxFloat64
		sum := float64(0)
		sumOfSquares := float64(0)

		for _, result := range measurement.Results {
			if result > measurement.Largest {
				measurement.Largest = result
			}
			if result < measurement.Smallest {
				measurement.Smallest = result
			}
			sum += result
			sumOfSquares += result * result
		}

		n := float64(len(measurement.Results))
		measurement.Average = sum / n
		measurement.StdDeviation = math.Sqrt(sumOfSquares/n - (sum/n)*(sum/n))
	}

	return b.measurements
}
<|endoftext|>


<commit_before>package remote

import (
	"bytes"
	"testing"

	"github.com/hashicorp/terraform/internal/states/statefile"
	"github.com/hashicorp/terraform/internal/states/statemgr"
)

// TestClient is a generic function to test any client.
func TestClient(t *testing.T, c Client) {
	var buf bytes.Buffer
	s := statemgr.TestFullInitialState()
	sf := statefile.New(s, "stub-lineage", 2)
	err := statefile.Write(sf, &buf)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	data := buf.Bytes()

	if err := c.Put(data); err != nil {
		t.Fatalf("put: %s", err)
	}

	p, err := c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if !bytes.Equal(p.Data, data) {
		t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data))
	}

	if err := c.Delete(); err != nil {
		t.Fatalf("delete: %s", err)
	}

	p, err = c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if p != nil {
		t.Fatalf("expected empty state, got: %q", string(p.Data))
	}
}

// Test the lock implementation for a remote.Client.
// This test requires 2 client instances, in oder to have multiple remote
// clients since some implementations may tie the client to the lock, or may
// have reentrant locks.
func TestRemoteLocks(t *testing.T, a, b Client) {
	lockerA, ok := a.(statemgr.Locker)
	if !ok {
		t.Fatal("client A not a statemgr.Locker")
	}

	lockerB, ok := b.(statemgr.Locker)
	if !ok {
		t.Fatal("client B not a statemgr.Locker")
	}

	infoA := statemgr.NewLockInfo()
	infoA.Operation = "test"
	infoA.Who = "clientA"

	infoB := statemgr.NewLockInfo()
	infoB.Operation = "test"
	infoB.Who = "clientB"

	lockIDA, err := lockerA.Lock(infoA)
	if err != nil {
		t.Fatal("unable to get initial lock:", err)
	}

	_, err = lockerB.Lock(infoB)
	if err == nil {
		lockerA.Unlock(lockIDA)
		t.Fatal("client B obtained lock while held by client A")
	}

	if err := lockerA.Unlock(lockIDA); err != nil {
		t.Fatal("error unlocking client A", err)
	}

	lockIDB, err := lockerB.Lock(infoB)
	if err != nil {
		t.Fatal("unable to obtain lock from client B")
	}

	if lockIDB == lockIDA {
		t.Fatalf("duplicate lock IDs: %q", lockIDB)
	}

	if err = lockerB.Unlock(lockIDB); err != nil {
		t.Fatal("error unlocking client B:", err)
	}

	// TODO: Should we enforce that Unlock requires the correct ID?
}
<commit_msg>states/remote: Check for LockError error type<commit_after>package remote

import (
	"bytes"
	"testing"

	"github.com/hashicorp/terraform/internal/states/statefile"
	"github.com/hashicorp/terraform/internal/states/statemgr"
)

// TestClient is a generic function to test any client.
func TestClient(t *testing.T, c Client) {
	var buf bytes.Buffer
	s := statemgr.TestFullInitialState()
	sf := statefile.New(s, "stub-lineage", 2)
	err := statefile.Write(sf, &buf)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	data := buf.Bytes()

	if err := c.Put(data); err != nil {
		t.Fatalf("put: %s", err)
	}

	p, err := c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if !bytes.Equal(p.Data, data) {
		t.Fatalf("expected full state %q\n\ngot: %q", string(p.Data), string(data))
	}

	if err := c.Delete(); err != nil {
		t.Fatalf("delete: %s", err)
	}

	p, err = c.Get()
	if err != nil {
		t.Fatalf("get: %s", err)
	}
	if p != nil {
		t.Fatalf("expected empty state, got: %q", string(p.Data))
	}
}

// Test the lock implementation for a remote.Client.
// This test requires 2 client instances, in oder to have multiple remote
// clients since some implementations may tie the client to the lock, or may
// have reentrant locks.
func TestRemoteLocks(t *testing.T, a, b Client) {
	lockerA, ok := a.(statemgr.Locker)
	if !ok {
		t.Fatal("client A not a statemgr.Locker")
	}

	lockerB, ok := b.(statemgr.Locker)
	if !ok {
		t.Fatal("client B not a statemgr.Locker")
	}

	infoA := statemgr.NewLockInfo()
	infoA.Operation = "test"
	infoA.Who = "clientA"

	infoB := statemgr.NewLockInfo()
	infoB.Operation = "test"
	infoB.Who = "clientB"

	lockIDA, err := lockerA.Lock(infoA)
	if err != nil {
		t.Fatal("unable to get initial lock:", err)
	}

	_, err = lockerB.Lock(infoB)
	if err == nil {
		lockerA.Unlock(lockIDA)
		t.Fatal("client B obtained lock while held by client A")
	}
	if _, ok := err.(*statemgr.LockError); !ok {
		t.Errorf("expected a LockError, but was %t: %s", err, err)
	}

	if err := lockerA.Unlock(lockIDA); err != nil {
		t.Fatal("error unlocking client A", err)
	}

	lockIDB, err := lockerB.Lock(infoB)
	if err != nil {
		t.Fatal("unable to obtain lock from client B")
	}

	if lockIDB == lockIDA {
		t.Fatalf("duplicate lock IDs: %q", lockIDB)
	}

	if err = lockerB.Unlock(lockIDB); err != nil {
		t.Fatal("error unlocking client B:", err)
	}

	// TODO: Should we enforce that Unlock requires the correct ID?
}
<|endoftext|>


<commit_before>package stupidgcm

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"log"
	"testing"
)

func testCiphers(t *testing.T, our cipher.AEAD, ref cipher.AEAD) {
	t.Run("testEncryptDecrypt", func(t *testing.T) { testEncryptDecrypt(t, our, ref) })
	t.Run("testInplaceSeal", func(t *testing.T) { testInplaceSeal(t, our, ref) })
	t.Run("testInplaceOpen", func(t *testing.T) { testInplaceOpen(t, our, ref) })
	t.Run("testCorruption_c1", func(t *testing.T) { testCorruption(t, our) })
	t.Run("testCorruption_c2", func(t *testing.T) { testCorruption(t, ref) })
	t.Run("testWipe", func(t *testing.T) { testWipe(t, our) })
}

// testEncryptDecrypt encrypts and decrypts using both stupidgcm and Go's built-in
// GCM implementation and verifies that the results are identical.
func testEncryptDecrypt(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	if c1.NonceSize() != c2.NonceSize() {
		t.Fatal("different NonceSize")
	}
	if c1.Overhead() != c2.Overhead() {
		t.Fatal("different Overhead")
	}

	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	dst := make([]byte, 71) // 71 = arbitrary length

	// Check all block sizes from 1 to 5000
	for i := 1; i < 5000; i++ {
		in := make([]byte, i)

		c1out := c1.Seal(dst, iv, in, authData)
		c2out := c2.Seal(dst, iv, in, authData)

		// Ciphertext must be identical to Go GCM
		if !bytes.Equal(c1out, c2out) {
			t.Fatalf("Compare failed for encryption, size %d", i)
			t.Log("c1out:")
			t.Log("\n" + hex.Dump(c1out))
			t.Log("c2out:")
			t.Log("\n" + hex.Dump(c2out))
		}

		c1out2, sErr := c1.Open(dst, iv, c1out[len(dst):], authData)
		if sErr != nil {
			t.Fatal(sErr)
		}
		c2out2, gErr := c2.Open(dst, iv, c2out[len(dst):], authData)
		if gErr != nil {
			t.Fatal(gErr)
		}

		// Plaintext must be identical to Go GCM
		if !bytes.Equal(c1out2, c2out2) {
			t.Fatalf("Compare failed for decryption, size %d", i)
		}
	}
}

// Seal re-uses the "dst" buffer it is large enough.
// Check that this works correctly by testing different "dst" capacities from
// 5000 to 16 and "in" lengths from 1 to 5000.
func testInplaceSeal(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	max := 5016
	// Check all block sizes from 1 to 5000
	for i := 1; i < max-16; i++ {
		in := make([]byte, i)
		dst := make([]byte, max-i)
		dst = dst[:16]

		c1out := c1.Seal(dst, iv, in, authData)
		dst2 := make([]byte, 16)
		c2out := c2.Seal(dst2, iv, in, authData)

		// Ciphertext must be identical to Go GCM
		if !bytes.Equal(c1out, c2out) {
			t.Fatalf("Compare failed for encryption, size %d", i)
			t.Log("sOut:")
			t.Log("\n" + hex.Dump(c1out))
			t.Log("gOut:")
			t.Log("\n" + hex.Dump(c2out))
		}
	}
}

// testInplaceOpen - Open re-uses the "dst" buffer it is large enough.
// Check that this works correctly by testing different "dst" capacities from
// 5000 to 16 and "in" lengths from 1 to 5000.
func testInplaceOpen(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	max := 5016
	// Check all block sizes from 1 to 5000
	for i := 1; i < max-c1.NonceSize(); i++ {
		in := make([]byte, i)

		c2ciphertext := c2.Seal(iv, iv, in, authData)

		dst := make([]byte, max-i)
		// sPlaintext ... stupidgcm plaintext
		c1plaintext, err := c1.Open(dst[:0], iv, c2ciphertext[c1.NonceSize():], authData)
		if err != nil {
			t.Fatal(err)
		}

		// Plaintext must be identical to Go GCM
		if !bytes.Equal(in, c1plaintext) {
			t.Fatalf("Compare failed, i=%d", i)
		}
	}
}

// testCorruption verifies that changes in the ciphertext result in a decryption
// error
func testCorruption(t *testing.T, c cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c.NonceSize())

	in := make([]byte, 354)
	out := c.Seal(nil, iv, in, authData)
	out2, sErr := c.Open(nil, iv, out, authData)
	if sErr != nil {
		t.Fatal(sErr)
	}
	if !bytes.Equal(in, out2) {
		t.Fatalf("Compare failed")
	}

	// Corrupt first byte
	out[0]++
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
	out[0]--

	// Corrupt last byte
	out[len(out)-1]++
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
	out[len(out)-1]--

	// Append one byte
	out = append(out, 0)
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
}

func testWipe(t *testing.T, c cipher.AEAD) {
	switch c2 := c.(type) {
	case *StupidGCM:
		c2.Wipe()
		if !c2.Wiped() {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2._key is not zeroed")
			}
		}
	case *stupidChacha20poly1305:
		c2.Wipe()
		if !c2.Wiped() {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2._key is not zeroed")
			}
		}
	case *stupidXchacha20poly1305:
		c2.Wipe()
		if !c2.wiped {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2.key is not zeroed")
			}
		}
	default:
		t.Fatalf("BUG: unhandled type %T", c2)
	}
}

// Get "n" random bytes from /dev/urandom or panic
func randBytes(n int) []byte {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		log.Panic("Failed to read random bytes: " + err.Error())
	}
	return b
}

/*
BenchmarkCCall benchmarks the overhead of calling from Go into C.
Looks like things improved a bit compared to
https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/
where they measured 171ns/op:

$ go test -bench .
goos: linux
goarch: amd64
pkg: github.com/rfjakob/gocryptfs/v2/internal/stupidgcm
cpu: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz
BenchmarkCCall-4   	13989364	        76.72 ns/op
PASS
ok  	github.com/rfjakob/gocryptfs/v2/internal/stupidgcm	1.735s
*/
func BenchmarkCCall(b *testing.B) {
	for i := 0; i < b.N; i++ {
		noopCFunction()
	}
}
<commit_msg>stupidgcm: add testConcurrency<commit_after>// +build cgo,!without_openssl

package stupidgcm

import (
	"bytes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/hex"
	"log"
	"sync"
	"testing"
)

func testCiphers(t *testing.T, our cipher.AEAD, ref cipher.AEAD) {
	t.Run("testEncryptDecrypt", func(t *testing.T) { testEncryptDecrypt(t, our, ref) })
	t.Run("testInplaceSeal", func(t *testing.T) { testInplaceSeal(t, our, ref) })
	t.Run("testInplaceOpen", func(t *testing.T) { testInplaceOpen(t, our, ref) })
	t.Run("testCorruption_c1", func(t *testing.T) { testCorruption(t, our) })
	t.Run("testCorruption_c2", func(t *testing.T) { testCorruption(t, ref) })
	t.Run("testConcurrency", func(t *testing.T) { testConcurrency(t, our, ref) })
	t.Run("testWipe", func(t *testing.T) { testWipe(t, our) })
}

// testEncryptDecrypt encrypts and decrypts using both stupidgcm and Go's built-in
// GCM implementation and verifies that the results are identical.
func testEncryptDecrypt(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	if c1.NonceSize() != c2.NonceSize() {
		t.Fatal("different NonceSize")
	}
	if c1.Overhead() != c2.Overhead() {
		t.Fatal("different Overhead")
	}

	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	dst := make([]byte, 71) // 71 = arbitrary length

	// Check all block sizes from 1 to 5000
	for i := 1; i < 5000; i++ {
		in := make([]byte, i)

		c1out := c1.Seal(dst, iv, in, authData)
		c2out := c2.Seal(dst, iv, in, authData)

		// Ciphertext must be identical to Go GCM
		if !bytes.Equal(c1out, c2out) {
			t.Fatalf("Compare failed for encryption, size %d", i)
			t.Log("c1out:")
			t.Log("\n" + hex.Dump(c1out))
			t.Log("c2out:")
			t.Log("\n" + hex.Dump(c2out))
		}

		c1out2, sErr := c1.Open(dst, iv, c1out[len(dst):], authData)
		if sErr != nil {
			t.Fatal(sErr)
		}
		c2out2, gErr := c2.Open(dst, iv, c2out[len(dst):], authData)
		if gErr != nil {
			t.Fatal(gErr)
		}

		// Plaintext must be identical to Go GCM
		if !bytes.Equal(c1out2, c2out2) {
			t.Fatalf("Compare failed for decryption, size %d", i)
		}
	}
}

// testConcurrency verifies that we don't corrupt data when called concurrently
func testConcurrency(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	const loopCount = 2
	const goroutineCount = 4

	for h := 0; h < loopCount; h++ {
		var wg sync.WaitGroup
		for i := 0; i < goroutineCount; i++ {
			wg.Add(1)
			go func() {
				testEncryptDecrypt(t, c1, c2)
				wg.Done()
			}()
			wg.Wait()
		}
	}
}

// testInplaceSeal:
// Seal re-uses the "dst" buffer it is large enough.
// Check that this works correctly by testing different "dst" capacities from
// 5000 to 16 and "in" lengths from 1 to 5000.
func testInplaceSeal(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	max := 5016
	// Check all block sizes from 1 to 5000
	for i := 1; i < max-16; i++ {
		in := make([]byte, i)
		dst := make([]byte, max-i)
		dst = dst[:16]

		c1out := c1.Seal(dst, iv, in, authData)
		dst2 := make([]byte, 16)
		c2out := c2.Seal(dst2, iv, in, authData)

		// Ciphertext must be identical to Go GCM
		if !bytes.Equal(c1out, c2out) {
			t.Fatalf("Compare failed for encryption, size %d", i)
			t.Log("sOut:")
			t.Log("\n" + hex.Dump(c1out))
			t.Log("gOut:")
			t.Log("\n" + hex.Dump(c2out))
		}
	}
}

// testInplaceOpen - Open re-uses the "dst" buffer it is large enough.
// Check that this works correctly by testing different "dst" capacities from
// 5000 to 16 and "in" lengths from 1 to 5000.
func testInplaceOpen(t *testing.T, c1 cipher.AEAD, c2 cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c1.NonceSize())

	max := 5016
	// Check all block sizes from 1 to 5000
	for i := 1; i < max-c1.NonceSize(); i++ {
		in := make([]byte, i)

		c2ciphertext := c2.Seal(iv, iv, in, authData)

		dst := make([]byte, max-i)
		// sPlaintext ... stupidgcm plaintext
		c1plaintext, err := c1.Open(dst[:0], iv, c2ciphertext[c1.NonceSize():], authData)
		if err != nil {
			t.Fatal(err)
		}

		// Plaintext must be identical to Go GCM
		if !bytes.Equal(in, c1plaintext) {
			t.Fatalf("Compare failed, i=%d", i)
		}
	}
}

// testCorruption verifies that changes in the ciphertext result in a decryption
// error
func testCorruption(t *testing.T, c cipher.AEAD) {
	authData := randBytes(24)
	iv := randBytes(c.NonceSize())

	in := make([]byte, 354)
	out := c.Seal(nil, iv, in, authData)
	out2, sErr := c.Open(nil, iv, out, authData)
	if sErr != nil {
		t.Fatal(sErr)
	}
	if !bytes.Equal(in, out2) {
		t.Fatalf("Compare failed")
	}

	// Corrupt first byte
	out[0]++
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
	out[0]--

	// Corrupt last byte
	out[len(out)-1]++
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
	out[len(out)-1]--

	// Append one byte
	out = append(out, 0)
	out2, sErr = c.Open(nil, iv, out, authData)
	if sErr == nil || out2 != nil {
		t.Fatalf("Should have gotten error")
	}
}

func testWipe(t *testing.T, c cipher.AEAD) {
	switch c2 := c.(type) {
	case *StupidGCM:
		c2.Wipe()
		if !c2.Wiped() {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2._key is not zeroed")
			}
		}
	case *stupidChacha20poly1305:
		c2.Wipe()
		if !c2.Wiped() {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2._key is not zeroed")
			}
		}
	case *stupidXchacha20poly1305:
		c2.Wipe()
		if !c2.wiped {
			t.Error("c2.wiped is not set")
		}
		for _, v := range c2.key {
			if v != 0 {
				t.Fatal("c2.key is not zeroed")
			}
		}
	default:
		t.Fatalf("BUG: unhandled type %T", c2)
	}
}

// Get "n" random bytes from /dev/urandom or panic
func randBytes(n int) []byte {
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		log.Panic("Failed to read random bytes: " + err.Error())
	}
	return b
}

/*
BenchmarkCCall benchmarks the overhead of calling from Go into C.
Looks like things improved a bit compared to
https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/
where they measured 171ns/op:

$ go test -bench .
goos: linux
goarch: amd64
pkg: github.com/rfjakob/gocryptfs/v2/internal/stupidgcm
cpu: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz
BenchmarkCCall-4   	13989364	        76.72 ns/op
PASS
ok  	github.com/rfjakob/gocryptfs/v2/internal/stupidgcm	1.735s
*/
func BenchmarkCCall(b *testing.B) {
	for i := 0; i < b.N; i++ {
		noopCFunction()
	}
}
<|endoftext|>


<commit_before>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package factory

import (
	"errors"
	"fmt"
	"os"
	"plugin"

	"github.com/hyperledger/fabric/bccsp"
)

const (
	// PluginFactoryName is the factory name for BCCSP plugins
	PluginFactoryName = "PLUGIN"
)

// PluginOpts contains the options for the PluginFactory
type PluginOpts struct {
	// Path to plugin library
	Library string
	// Config map for the plugin library
	Config map[string]interface{}
}

// PluginFactory is the factory for BCCSP plugins
type PluginFactory struct{}

// Name returns the name of this factory
func (f *PluginFactory) Name() string {
	return PluginFactoryName
}

// Get returns an instance of BCCSP using Opts.
func (f *PluginFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) {
	// check for valid config
	if config == nil || config.PluginOpts == nil {
		return nil, errors.New("Invalid config. It must not be nil.")
	}

	// Library is required property
	if config.PluginOpts.Library == "" {
		return nil, errors.New("Invalid config: missing property 'Library'")
	}

	// make sure the library exists
	if _, err := os.Stat(config.PluginOpts.Library); err != nil {
		return nil, fmt.Errorf("Could not find library '%s' [%s]", config.PluginOpts.Library, err)
	}

	// attempt to load the library as a plugin
	plug, err := plugin.Open(config.PluginOpts.Library)
	if err != nil {
		return nil, fmt.Errorf("Failed to load plugin '%s' [%s]", config.PluginOpts.Library, err)
	}

	// lookup the required symbol 'New'
	sym, err := plug.Lookup("New")
	if err != nil {
		return nil, fmt.Errorf("Could not find required symbol 'CryptoServiceProvider' [%s]", err)
	}

	// check to make sure symbol New meets the required function signature
	new, ok := sym.(func(config map[string]interface{}) (bccsp.BCCSP, error))
	if !ok {
		return nil, fmt.Errorf("Plugin does not implement the required function signature for 'New'")
	}

	return new(config.PluginOpts.Config)
}
<commit_msg>FAB-15403 avoid using Go key word for var<commit_after>/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package factory

import (
	"errors"
	"fmt"
	"os"
	"plugin"

	"github.com/hyperledger/fabric/bccsp"
)

const (
	// PluginFactoryName is the factory name for BCCSP plugins
	PluginFactoryName = "PLUGIN"
)

// PluginOpts contains the options for the PluginFactory
type PluginOpts struct {
	// Path to plugin library
	Library string
	// Config map for the plugin library
	Config map[string]interface{}
}

// PluginFactory is the factory for BCCSP plugins
type PluginFactory struct{}

// Name returns the name of this factory
func (f *PluginFactory) Name() string {
	return PluginFactoryName
}

// Get returns an instance of BCCSP using Opts.
func (f *PluginFactory) Get(config *FactoryOpts) (bccsp.BCCSP, error) {
	// check for valid config
	if config == nil || config.PluginOpts == nil {
		return nil, errors.New("Invalid config. It must not be nil.")
	}

	// Library is required property
	if config.PluginOpts.Library == "" {
		return nil, errors.New("Invalid config: missing property 'Library'")
	}

	// make sure the library exists
	if _, err := os.Stat(config.PluginOpts.Library); err != nil {
		return nil, fmt.Errorf("Could not find library '%s' [%s]", config.PluginOpts.Library, err)
	}

	// attempt to load the library as a plugin
	plug, err := plugin.Open(config.PluginOpts.Library)
	if err != nil {
		return nil, fmt.Errorf("Failed to load plugin '%s' [%s]", config.PluginOpts.Library, err)
	}

	// lookup the required symbol 'New'
	sym, err := plug.Lookup("New")
	if err != nil {
		return nil, fmt.Errorf("Could not find required symbol 'CryptoServiceProvider' [%s]", err)
	}

	// check to make sure symbol New meets the required function signature
	symNew, ok := sym.(func(config map[string]interface{}) (bccsp.BCCSP, error))
	if !ok {
		return nil, fmt.Errorf("Plugin does not implement the required function signature for 'New'")
	}

	return symNew(config.PluginOpts.Config)
}
<|endoftext|>


<commit_before>package relay

import (
	"encoding/binary"

	circuit "github.com/libp2p/go-libp2p-circuit"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

// This function cleans up a relay's address set to remove private addresses and curtail
// addrsplosion.
func cleanupAddressSet(pi pstore.PeerInfo) pstore.PeerInfo {
	var public, private []ma.Multiaddr

	for _, a := range pi.Addrs {
		if isRelayAddr(a) {
			continue
		}

		if manet.IsPublicAddr(a) || isDNSAddr(a) {
			public = append(public, a)
			continue
		}

		// discard unroutable addrs
		if manet.IsPrivateAddr(a) {
			private = append(private, a)
		}
	}

	if !hasAddrsplosion(public) {
		return pstore.PeerInfo{ID: pi.ID, Addrs: public}
	}

	addrs := sanitizeAddrsplodedSet(public, private)
	return pstore.PeerInfo{ID: pi.ID, Addrs: addrs}
}

func isRelayAddr(a ma.Multiaddr) bool {
	isRelay := false

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case circuit.P_CIRCUIT:
			isRelay = true
			return false
		default:
			return true
		}
	})

	return isRelay
}

func isDNSAddr(a ma.Multiaddr) bool {
	if first, _ := ma.SplitFirst(a); first != nil {
		switch first.Protocol().Code {
		case 54, 55, 56:
			return true
		}
	}
	return false
}

// we have addrsplosion if for some protocol we advertise multiple ports on
// the same base address.
func hasAddrsplosion(addrs []ma.Multiaddr) bool {
	aset := make(map[string]int)

	for _, a := range addrs {
		key, port := addrKeyAndPort(a)
		xport, ok := aset[key]
		if ok && port != xport {
			return true
		}
		aset[key] = port
	}

	return false
}

func addrKeyAndPort(a ma.Multiaddr) (string, int) {
	var (
		key  string
		port int
	)

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case ma.P_TCP, ma.P_UDP:
			port = int(binary.BigEndian.Uint16(c.RawValue()))
			key += "/" + c.Protocol().Name
		default:
			val := c.Value()
			if val == "" {
				val = c.Protocol().Name
			}
			key += "/" + val
		}
		return true
	})

	return key, port
}

// clean up addrsplosion
// the following heuristic is used:
// - for each base address/protocol combination, if there are multiple ports advertised then
//   only accept the default port if present.
//   - If the default port is not present, we check for non-standard ports by tracking
//     private port bindings if present.
//   - If there is no default or private port binding, then we can't infer the correct
//     port and give up and return all addrs (for that base address)
func sanitizeAddrsplodedSet(public, private []ma.Multiaddr) []ma.Multiaddr {
	type portAndAddr struct {
		addr ma.Multiaddr
		port int
	}

	privports := make(map[int]struct{})
	pubaddrs := make(map[string][]portAndAddr)

	for _, a := range private {
		_, port := addrKeyAndPort(a)
		privports[port] = struct{}{}
	}

	for _, a := range public {
		key, port := addrKeyAndPort(a)
		pubaddrs[key] = append(pubaddrs[key], portAndAddr{addr: a, port: port})
	}

	var result []ma.Multiaddr
	for _, pas := range pubaddrs {
		if len(pas) == 1 {
			// it's not addrsploded
			result = append(result, pas[0].addr)
			continue
		}

		haveAddr := false
		for _, pa := range pas {
			if pa.port == 4001 || pa.port == 4002 {
				// it's a default port, use it
				result = append(result, pa.addr)
				haveAddr = true
				continue
			}

			if _, ok := privports[pa.port]; ok {
				// it matches a privately bound port, use it
				result = append(result, pa.addr)
				haveAddr = true
			}
		}

		if !haveAddr {
			// we weren't able to select a port; bite the bullet and use them all
			for _, pa := range pas {
				result = append(result, pa.addr)
			}
		}
	}

	return result
}
<commit_msg>test for privately bound port first when cleaning up addrsplosion<commit_after>package relay

import (
	"encoding/binary"

	circuit "github.com/libp2p/go-libp2p-circuit"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	ma "github.com/multiformats/go-multiaddr"
	manet "github.com/multiformats/go-multiaddr-net"
)

// This function cleans up a relay's address set to remove private addresses and curtail
// addrsplosion.
func cleanupAddressSet(pi pstore.PeerInfo) pstore.PeerInfo {
	var public, private []ma.Multiaddr

	for _, a := range pi.Addrs {
		if isRelayAddr(a) {
			continue
		}

		if manet.IsPublicAddr(a) || isDNSAddr(a) {
			public = append(public, a)
			continue
		}

		// discard unroutable addrs
		if manet.IsPrivateAddr(a) {
			private = append(private, a)
		}
	}

	if !hasAddrsplosion(public) {
		return pstore.PeerInfo{ID: pi.ID, Addrs: public}
	}

	addrs := sanitizeAddrsplodedSet(public, private)
	return pstore.PeerInfo{ID: pi.ID, Addrs: addrs}
}

func isRelayAddr(a ma.Multiaddr) bool {
	isRelay := false

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case circuit.P_CIRCUIT:
			isRelay = true
			return false
		default:
			return true
		}
	})

	return isRelay
}

func isDNSAddr(a ma.Multiaddr) bool {
	if first, _ := ma.SplitFirst(a); first != nil {
		switch first.Protocol().Code {
		case 54, 55, 56:
			return true
		}
	}
	return false
}

// we have addrsplosion if for some protocol we advertise multiple ports on
// the same base address.
func hasAddrsplosion(addrs []ma.Multiaddr) bool {
	aset := make(map[string]int)

	for _, a := range addrs {
		key, port := addrKeyAndPort(a)
		xport, ok := aset[key]
		if ok && port != xport {
			return true
		}
		aset[key] = port
	}

	return false
}

func addrKeyAndPort(a ma.Multiaddr) (string, int) {
	var (
		key  string
		port int
	)

	ma.ForEach(a, func(c ma.Component) bool {
		switch c.Protocol().Code {
		case ma.P_TCP, ma.P_UDP:
			port = int(binary.BigEndian.Uint16(c.RawValue()))
			key += "/" + c.Protocol().Name
		default:
			val := c.Value()
			if val == "" {
				val = c.Protocol().Name
			}
			key += "/" + val
		}
		return true
	})

	return key, port
}

// clean up addrsplosion
// the following heuristic is used:
// - for each base address/protocol combination, if there are multiple ports advertised then
//   only accept the default port if present.
//   - If the default port is not present, we check for non-standard ports by tracking
//     private port bindings if present.
//   - If there is no default or private port binding, then we can't infer the correct
//     port and give up and return all addrs (for that base address)
func sanitizeAddrsplodedSet(public, private []ma.Multiaddr) []ma.Multiaddr {
	type portAndAddr struct {
		addr ma.Multiaddr
		port int
	}

	privports := make(map[int]struct{})
	pubaddrs := make(map[string][]portAndAddr)

	for _, a := range private {
		_, port := addrKeyAndPort(a)
		privports[port] = struct{}{}
	}

	for _, a := range public {
		key, port := addrKeyAndPort(a)
		pubaddrs[key] = append(pubaddrs[key], portAndAddr{addr: a, port: port})
	}

	var result []ma.Multiaddr
	for _, pas := range pubaddrs {
		if len(pas) == 1 {
			// it's not addrsploded
			result = append(result, pas[0].addr)
			continue
		}

		haveAddr := false
		for _, pa := range pas {
			if _, ok := privports[pa.port]; ok {
				// it matches a privately bound port, use it
				result = append(result, pa.addr)
				haveAddr = true
				continue
			}

			if pa.port == 4001 || pa.port == 4002 {
				// it's a default port, use it
				result = append(result, pa.addr)
				haveAddr = true
			}
		}

		if !haveAddr {
			// we weren't able to select a port; bite the bullet and use them all
			for _, pa := range pas {
				result = append(result, pa.addr)
			}
		}
	}

	return result
}
<|endoftext|>


<commit_before>package noise

import (
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"sync"
	"time"

	proto "github.com/gogo/protobuf/proto"
	logging "github.com/ipfs/go-log"
	"github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"

	ik "github.com/libp2p/go-libp2p-noise/ik"
	pb "github.com/libp2p/go-libp2p-noise/pb"
	xx "github.com/libp2p/go-libp2p-noise/xx"
)

const payload_string = "noise-libp2p-static-key:"

// Each encrypted transport message must be <= 65,535 bytes, including 16
// bytes of authentication data. To write larger plaintexts, we split them
// into fragments of maxPlaintextLength before encrypting.
const maxPlaintextLength = 65519

var log = logging.Logger("noise")

var errNoKeypair = errors.New("cannot initiate secureSession - transport has no noise keypair")

type secureSession struct {
	insecure net.Conn

	initiator bool
	prologue  []byte

	localKey   crypto.PrivKey
	localPeer  peer.ID
	remotePeer peer.ID

	local  peerInfo
	remote peerInfo

	xx_ns *xx.NoiseSession
	ik_ns *ik.NoiseSession

	xx_complete bool
	ik_complete bool

	noisePipesSupport   bool
	noiseStaticKeyCache *KeyCache

	noiseKeypair *Keypair

	msgBuffer []byte
	rwLock    sync.Mutex
}

type peerInfo struct {
	noiseKey  [32]byte // static noise public key
	libp2pKey crypto.PubKey
}

// newSecureSession creates a noise session over the given insecure Conn, using the static
// Noise keypair and libp2p identity keypair from the given Transport.
//
// If tpt.noisePipesSupport == true, the Noise Pipes handshake protocol will be used,
// which consists of the IK and XXfallback handshake patterns. With Noise Pipes on, we first try IK,
// if that fails, move to XXfallback. With Noise Pipes off, we always do XX.
func newSecureSession(tpt *Transport, ctx context.Context, insecure net.Conn, remote peer.ID, initiator bool) (*secureSession, error) {
	if tpt.noiseKeypair == nil {
		return nil, errNoKeypair
	}

	// if the transport doesn't have a key cache, we make a new one just for
	// this session. it's a bit of a waste, but saves us having to check if
	// it's nil later
	keyCache := tpt.noiseStaticKeyCache
	if keyCache == nil {
		keyCache = NewKeyCache()
	}

	localPeerInfo := peerInfo{
		noiseKey:  tpt.noiseKeypair.publicKey,
		libp2pKey: tpt.privateKey.GetPublic(),
	}

	s := &secureSession{
		insecure:            insecure,
		initiator:           initiator,
		prologue:            []byte(ID),
		localKey:            tpt.privateKey,
		localPeer:           tpt.localID,
		remotePeer:          remote,
		local:               localPeerInfo,
		noisePipesSupport:   tpt.noisePipesSupport,
		noiseStaticKeyCache: keyCache,
		msgBuffer:           []byte{},
		noiseKeypair:        tpt.noiseKeypair,
	}

	err := s.runHandshake(ctx)

	return s, err
}

func (s *secureSession) NoiseStaticKeyCache() *KeyCache {
	return s.noiseStaticKeyCache
}

func (s *secureSession) NoisePublicKey() [32]byte {
	return s.noiseKeypair.publicKey
}

func (s *secureSession) NoisePrivateKey() [32]byte {
	return s.noiseKeypair.privateKey
}

func (s *secureSession) readLength() (int, error) {
	buf := make([]byte, 2)
	_, err := s.insecure.Read(buf)
	return int(binary.BigEndian.Uint16(buf)), err
}

func (s *secureSession) writeLength(length int) error {
	buf := make([]byte, 2)
	binary.BigEndian.PutUint16(buf, uint16(length))
	_, err := s.insecure.Write(buf)
	return err
}

func (s *secureSession) setRemotePeerInfo(key []byte) (err error) {
	s.remote.libp2pKey, err = crypto.UnmarshalPublicKey(key)
	return err
}

func (s *secureSession) setRemotePeerID(key crypto.PubKey) (err error) {
	s.remotePeer, err = peer.IDFromPublicKey(key)
	return err
}

func (s *secureSession) verifyPayload(payload *pb.NoiseHandshakePayload, noiseKey [32]byte) (err error) {
	sig := payload.GetNoiseStaticKeySignature()
	msg := append([]byte(payload_string), noiseKey[:]...)

	log.Debugf("verifyPayload msg=%x", msg)

	ok, err := s.RemotePublicKey().Verify(msg, sig)
	if err != nil {
		return err
	} else if !ok {
		return fmt.Errorf("did not verify payload")
	}

	return nil
}

func (s *secureSession) runHandshake(ctx context.Context) error {
	// setup libp2p keys
	localKeyRaw, err := s.LocalPublicKey().Bytes()
	if err != nil {
		return fmt.Errorf("runHandshake err getting raw pubkey: %s", err)
	}

	// sign noise data for payload
	noise_pub := s.noiseKeypair.publicKey
	signedPayload, err := s.localKey.Sign(append([]byte(payload_string), noise_pub[:]...))
	if err != nil {
		log.Errorf("runHandshake signing payload err=%s", err)
		return fmt.Errorf("runHandshake signing payload err=%s", err)
	}

	// create payload
	payload := new(pb.NoiseHandshakePayload)
	payload.Libp2PKey = localKeyRaw
	payload.NoiseStaticKeySignature = signedPayload
	payloadEnc, err := proto.Marshal(payload)
	if err != nil {
		log.Errorf("runHandshake marshal payload err=%s", err)
		return fmt.Errorf("runHandshake proto marshal payload err=%s", err)
	}

	// If we support Noise pipes, we try IK first, falling back to XX if IK fails.
	// The exception is when we're the initiator and don't know the other party's
	// static Noise key. Then IK will always fail, so we go straight to XX.
	tryIK := s.noisePipesSupport
	if s.initiator && s.noiseStaticKeyCache.Load(s.remotePeer) == [32]byte{} {
		tryIK = false
	}
	if tryIK {
		// we're either a responder or an initiator with a known static key for the remote peer, try IK
		buf, err := s.runHandshake_ik(ctx, payloadEnc)
		if err != nil {
			log.Error("runHandshake ik err=%s", err)

			// IK failed, pipe to XXfallback
			err = s.runHandshake_xx(ctx, true, payloadEnc, buf)
			if err != nil {
				log.Error("runHandshake xx err=err", err)
				return fmt.Errorf("runHandshake xx err=%s", err)
			}

			s.xx_complete = true
		} else {
			s.ik_complete = true
		}
	} else {
		// unknown static key for peer, try XX
		err := s.runHandshake_xx(ctx, false, payloadEnc, nil)
		if err != nil {
			log.Error("runHandshake xx err=%s", err)
			return err
		}

		s.xx_complete = true
	}

	return nil
}

func (s *secureSession) LocalAddr() net.Addr {
	return s.insecure.LocalAddr()
}

func (s *secureSession) LocalPeer() peer.ID {
	return s.localPeer
}

func (s *secureSession) LocalPrivateKey() crypto.PrivKey {
	return s.localKey
}

func (s *secureSession) LocalPublicKey() crypto.PubKey {
	return s.localKey.GetPublic()
}

func (s *secureSession) Read(buf []byte) (int, error) {
	l := len(buf)

	// if we have previously unread bytes, and they fit into the buf, copy them over and return
	if l <= len(s.msgBuffer) {
		copy(buf, s.msgBuffer)
		s.msgBuffer = s.msgBuffer[l:]
		return l, nil
	}

	readChunk := func(buf []byte) (int, error) {
		// read length of encrypted message
		l, err := s.readLength()
		if err != nil {
			return 0, err
		}

		// read and decrypt ciphertext
		ciphertext := make([]byte, l)
		_, err = s.insecure.Read(ciphertext)
		if err != nil {
			log.Error("read ciphertext err", err)
			return 0, err
		}

		plaintext, err := s.Decrypt(ciphertext)
		if err != nil {
			log.Error("decrypt err", err)
			return 0, err
		}

		// append plaintext to message buffer, copy over what can fit in the buf
		// then advance message buffer to remove what was copied
		s.msgBuffer = append(s.msgBuffer, plaintext...)
		c := copy(buf, s.msgBuffer)
		s.msgBuffer = s.msgBuffer[c:]
		return c, nil
	}

	total := 0
	for i := 0; i < len(buf); i += maxPlaintextLength {
		end := i + maxPlaintextLength
		if end > len(buf) {
			end = len(buf)
		}

		c, err := readChunk(buf[i:end])
		total += c
		if err != nil {
			return total, err
		}
	}

	return total, nil
}

func (s *secureSession) RemoteAddr() net.Addr {
	return s.insecure.RemoteAddr()
}

func (s *secureSession) RemotePeer() peer.ID {
	return s.remotePeer
}

func (s *secureSession) RemotePublicKey() crypto.PubKey {
	return s.remote.libp2pKey
}

func (s *secureSession) SetDeadline(t time.Time) error {
	return s.insecure.SetDeadline(t)
}

func (s *secureSession) SetReadDeadline(t time.Time) error {
	return s.insecure.SetReadDeadline(t)
}

func (s *secureSession) SetWriteDeadline(t time.Time) error {
	return s.insecure.SetWriteDeadline(t)
}

func (s *secureSession) Write(in []byte) (int, error) {
	s.rwLock.Lock()
	defer s.rwLock.Unlock()

	writeChunk := func(in []byte) (int, error) {
		ciphertext, err := s.Encrypt(in)
		if err != nil {
			log.Error("encrypt error", err)
			return 0, err
		}

		err = s.writeLength(len(ciphertext))
		if err != nil {
			log.Error("write length err", err)
			return 0, err
		}

		_, err = s.insecure.Write(ciphertext)
		return len(in), err
	}

	written := 0
	for i := 0; i < len(in); i += maxPlaintextLength {
		end := i + maxPlaintextLength
		if end > len(in) {
			end = len(in)
		}

		l, err := writeChunk(in[i:end])
		written += l
		if err != nil {
			return written, err
		}
	}
	return written, nil
}

func (s *secureSession) Close() error {
	return s.insecure.Close()
}
<commit_msg>use empty prologue<commit_after>package noise

import (
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"net"
	"sync"
	"time"

	proto "github.com/gogo/protobuf/proto"
	logging "github.com/ipfs/go-log"
	"github.com/libp2p/go-libp2p-core/crypto"
	"github.com/libp2p/go-libp2p-core/peer"

	ik "github.com/libp2p/go-libp2p-noise/ik"
	pb "github.com/libp2p/go-libp2p-noise/pb"
	xx "github.com/libp2p/go-libp2p-noise/xx"
)

const payload_string = "noise-libp2p-static-key:"

// Each encrypted transport message must be <= 65,535 bytes, including 16
// bytes of authentication data. To write larger plaintexts, we split them
// into fragments of maxPlaintextLength before encrypting.
const maxPlaintextLength = 65519

var log = logging.Logger("noise")

var errNoKeypair = errors.New("cannot initiate secureSession - transport has no noise keypair")

type secureSession struct {
	insecure net.Conn

	initiator bool
	prologue  []byte

	localKey   crypto.PrivKey
	localPeer  peer.ID
	remotePeer peer.ID

	local  peerInfo
	remote peerInfo

	xx_ns *xx.NoiseSession
	ik_ns *ik.NoiseSession

	xx_complete bool
	ik_complete bool

	noisePipesSupport   bool
	noiseStaticKeyCache *KeyCache

	noiseKeypair *Keypair

	msgBuffer []byte
	rwLock    sync.Mutex
}

type peerInfo struct {
	noiseKey  [32]byte // static noise public key
	libp2pKey crypto.PubKey
}

// newSecureSession creates a noise session over the given insecure Conn, using the static
// Noise keypair and libp2p identity keypair from the given Transport.
//
// If tpt.noisePipesSupport == true, the Noise Pipes handshake protocol will be used,
// which consists of the IK and XXfallback handshake patterns. With Noise Pipes on, we first try IK,
// if that fails, move to XXfallback. With Noise Pipes off, we always do XX.
func newSecureSession(tpt *Transport, ctx context.Context, insecure net.Conn, remote peer.ID, initiator bool) (*secureSession, error) {
	if tpt.noiseKeypair == nil {
		return nil, errNoKeypair
	}

	// if the transport doesn't have a key cache, we make a new one just for
	// this session. it's a bit of a waste, but saves us having to check if
	// it's nil later
	keyCache := tpt.noiseStaticKeyCache
	if keyCache == nil {
		keyCache = NewKeyCache()
	}

	localPeerInfo := peerInfo{
		noiseKey:  tpt.noiseKeypair.publicKey,
		libp2pKey: tpt.privateKey.GetPublic(),
	}

	s := &secureSession{
		insecure:            insecure,
		initiator:           initiator,
		prologue:            []byte{},
		localKey:            tpt.privateKey,
		localPeer:           tpt.localID,
		remotePeer:          remote,
		local:               localPeerInfo,
		noisePipesSupport:   tpt.noisePipesSupport,
		noiseStaticKeyCache: keyCache,
		msgBuffer:           []byte{},
		noiseKeypair:        tpt.noiseKeypair,
	}

	err := s.runHandshake(ctx)

	return s, err
}

func (s *secureSession) NoiseStaticKeyCache() *KeyCache {
	return s.noiseStaticKeyCache
}

func (s *secureSession) NoisePublicKey() [32]byte {
	return s.noiseKeypair.publicKey
}

func (s *secureSession) NoisePrivateKey() [32]byte {
	return s.noiseKeypair.privateKey
}

func (s *secureSession) readLength() (int, error) {
	buf := make([]byte, 2)
	_, err := s.insecure.Read(buf)
	return int(binary.BigEndian.Uint16(buf)), err
}

func (s *secureSession) writeLength(length int) error {
	buf := make([]byte, 2)
	binary.BigEndian.PutUint16(buf, uint16(length))
	_, err := s.insecure.Write(buf)
	return err
}

func (s *secureSession) setRemotePeerInfo(key []byte) (err error) {
	s.remote.libp2pKey, err = crypto.UnmarshalPublicKey(key)
	return err
}

func (s *secureSession) setRemotePeerID(key crypto.PubKey) (err error) {
	s.remotePeer, err = peer.IDFromPublicKey(key)
	return err
}

func (s *secureSession) verifyPayload(payload *pb.NoiseHandshakePayload, noiseKey [32]byte) (err error) {
	sig := payload.GetNoiseStaticKeySignature()
	msg := append([]byte(payload_string), noiseKey[:]...)

	log.Debugf("verifyPayload msg=%x", msg)

	ok, err := s.RemotePublicKey().Verify(msg, sig)
	if err != nil {
		return err
	} else if !ok {
		return fmt.Errorf("did not verify payload")
	}

	return nil
}

func (s *secureSession) runHandshake(ctx context.Context) error {
	// setup libp2p keys
	localKeyRaw, err := s.LocalPublicKey().Bytes()
	if err != nil {
		return fmt.Errorf("runHandshake err getting raw pubkey: %s", err)
	}

	// sign noise data for payload
	noise_pub := s.noiseKeypair.publicKey
	signedPayload, err := s.localKey.Sign(append([]byte(payload_string), noise_pub[:]...))
	if err != nil {
		log.Errorf("runHandshake signing payload err=%s", err)
		return fmt.Errorf("runHandshake signing payload err=%s", err)
	}

	// create payload
	payload := new(pb.NoiseHandshakePayload)
	payload.Libp2PKey = localKeyRaw
	payload.NoiseStaticKeySignature = signedPayload
	payloadEnc, err := proto.Marshal(payload)
	if err != nil {
		log.Errorf("runHandshake marshal payload err=%s", err)
		return fmt.Errorf("runHandshake proto marshal payload err=%s", err)
	}

	// If we support Noise pipes, we try IK first, falling back to XX if IK fails.
	// The exception is when we're the initiator and don't know the other party's
	// static Noise key. Then IK will always fail, so we go straight to XX.
	tryIK := s.noisePipesSupport
	if s.initiator && s.noiseStaticKeyCache.Load(s.remotePeer) == [32]byte{} {
		tryIK = false
	}
	if tryIK {
		// we're either a responder or an initiator with a known static key for the remote peer, try IK
		buf, err := s.runHandshake_ik(ctx, payloadEnc)
		if err != nil {
			log.Error("runHandshake ik err=%s", err)

			// IK failed, pipe to XXfallback
			err = s.runHandshake_xx(ctx, true, payloadEnc, buf)
			if err != nil {
				log.Error("runHandshake xx err=err", err)
				return fmt.Errorf("runHandshake xx err=%s", err)
			}

			s.xx_complete = true
		} else {
			s.ik_complete = true
		}
	} else {
		// unknown static key for peer, try XX
		err := s.runHandshake_xx(ctx, false, payloadEnc, nil)
		if err != nil {
			log.Error("runHandshake xx err=%s", err)
			return err
		}

		s.xx_complete = true
	}

	return nil
}

func (s *secureSession) LocalAddr() net.Addr {
	return s.insecure.LocalAddr()
}

func (s *secureSession) LocalPeer() peer.ID {
	return s.localPeer
}

func (s *secureSession) LocalPrivateKey() crypto.PrivKey {
	return s.localKey
}

func (s *secureSession) LocalPublicKey() crypto.PubKey {
	return s.localKey.GetPublic()
}

func (s *secureSession) Read(buf []byte) (int, error) {
	l := len(buf)

	// if we have previously unread bytes, and they fit into the buf, copy them over and return
	if l <= len(s.msgBuffer) {
		copy(buf, s.msgBuffer)
		s.msgBuffer = s.msgBuffer[l:]
		return l, nil
	}

	readChunk := func(buf []byte) (int, error) {
		// read length of encrypted message
		l, err := s.readLength()
		if err != nil {
			return 0, err
		}

		// read and decrypt ciphertext
		ciphertext := make([]byte, l)
		_, err = s.insecure.Read(ciphertext)
		if err != nil {
			log.Error("read ciphertext err", err)
			return 0, err
		}

		plaintext, err := s.Decrypt(ciphertext)
		if err != nil {
			log.Error("decrypt err", err)
			return 0, err
		}

		// append plaintext to message buffer, copy over what can fit in the buf
		// then advance message buffer to remove what was copied
		s.msgBuffer = append(s.msgBuffer, plaintext...)
		c := copy(buf, s.msgBuffer)
		s.msgBuffer = s.msgBuffer[c:]
		return c, nil
	}

	total := 0
	for i := 0; i < len(buf); i += maxPlaintextLength {
		end := i + maxPlaintextLength
		if end > len(buf) {
			end = len(buf)
		}

		c, err := readChunk(buf[i:end])
		total += c
		if err != nil {
			return total, err
		}
	}

	return total, nil
}

func (s *secureSession) RemoteAddr() net.Addr {
	return s.insecure.RemoteAddr()
}

func (s *secureSession) RemotePeer() peer.ID {
	return s.remotePeer
}

func (s *secureSession) RemotePublicKey() crypto.PubKey {
	return s.remote.libp2pKey
}

func (s *secureSession) SetDeadline(t time.Time) error {
	return s.insecure.SetDeadline(t)
}

func (s *secureSession) SetReadDeadline(t time.Time) error {
	return s.insecure.SetReadDeadline(t)
}

func (s *secureSession) SetWriteDeadline(t time.Time) error {
	return s.insecure.SetWriteDeadline(t)
}

func (s *secureSession) Write(in []byte) (int, error) {
	s.rwLock.Lock()
	defer s.rwLock.Unlock()

	writeChunk := func(in []byte) (int, error) {
		ciphertext, err := s.Encrypt(in)
		if err != nil {
			log.Error("encrypt error", err)
			return 0, err
		}

		err = s.writeLength(len(ciphertext))
		if err != nil {
			log.Error("write length err", err)
			return 0, err
		}

		_, err = s.insecure.Write(ciphertext)
		return len(in), err
	}

	written := 0
	for i := 0; i < len(in); i += maxPlaintextLength {
		end := i + maxPlaintextLength
		if end > len(in) {
			end = len(in)
		}

		l, err := writeChunk(in[i:end])
		written += l
		if err != nil {
			return written, err
		}
	}
	return written, nil
}

func (s *secureSession) Close() error {
	return s.insecure.Close()
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"

	container "google.golang.org/api/container/v1beta1"
)

type ContainerOperationWaiter struct {
	Service  *container.Service
	Op       *container.Operation
	Project  string
	Location string
}

func (w *ContainerOperationWaiter) State() string {
	if w == nil || w.Op == nil {
		return "<nil>"
	}
	return w.Op.Status
}

func (w *ContainerOperationWaiter) Error() error {
	if w == nil || w.Op == nil {
		return nil
	}

	// Error gets called during operation polling to see if there is an error.
	// Since container's operation doesn't have an "error" field, we must wait
	// until it's done and check the status message
	for _, pending := range w.PendingStates() {
		if w.Op.Status == pending {
			return nil
		}
	}

	if w.Op.StatusMessage != "" {
		return fmt.Errorf(w.Op.StatusMessage)
	}

	return nil
}

func (w *ContainerOperationWaiter) SetOp(op interface{}) error {
	var ok bool
	w.Op, ok = op.(*container.Operation)
	if !ok {
		return fmt.Errorf("Unable to set operation. Bad type!")
	}
	return nil
}

func (w *ContainerOperationWaiter) QueryOp() (interface{}, error) {
	if w == nil || w.Op == nil {
		return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
	}
	name := fmt.Sprintf("projects/%s/locations/%s/operations/%s",
		w.Project, w.Location, w.Op.Name)
	return w.Service.Projects.Locations.Operations.Get(name).Do()
}

func (w *ContainerOperationWaiter) OpName() string {
	if w == nil || w.Op == nil {
		return "<nil>"
	}
	return w.Op.Name
}

func (w *ContainerOperationWaiter) PendingStates() []string {
	return []string{"PENDING", "RUNNING"}
}

func (w *ContainerOperationWaiter) TargetStates() []string {
	return []string{"DONE"}
}

func containerOperationWait(config *Config, op *container.Operation, project, location, activity string, timeoutMinutes int) error {
	w := &ContainerOperationWaiter{
		Service:  config.clientContainerBeta,
		Op:       op,
		Project:  project,
		Location: location,
	}

	if err := w.SetOp(op); err != nil {
		return err
	}

	return OperationWait(w, activity, timeoutMinutes)
}
<commit_msg>Add retries to container Operations (#3801)<commit_after>package google

import (
	"fmt"

	container "google.golang.org/api/container/v1beta1"
)

type ContainerOperationWaiter struct {
	Service  *container.Service
	Op       *container.Operation
	Project  string
	Location string
}

func (w *ContainerOperationWaiter) State() string {
	if w == nil || w.Op == nil {
		return "<nil>"
	}
	return w.Op.Status
}

func (w *ContainerOperationWaiter) Error() error {
	if w == nil || w.Op == nil {
		return nil
	}

	// Error gets called during operation polling to see if there is an error.
	// Since container's operation doesn't have an "error" field, we must wait
	// until it's done and check the status message
	for _, pending := range w.PendingStates() {
		if w.Op.Status == pending {
			return nil
		}
	}

	if w.Op.StatusMessage != "" {
		return fmt.Errorf(w.Op.StatusMessage)
	}

	return nil
}

func (w *ContainerOperationWaiter) SetOp(op interface{}) error {
	var ok bool
	w.Op, ok = op.(*container.Operation)
	if !ok {
		return fmt.Errorf("Unable to set operation. Bad type!")
	}
	return nil
}

func (w *ContainerOperationWaiter) QueryOp() (interface{}, error) {
	if w == nil || w.Op == nil {
		return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
	}
	name := fmt.Sprintf("projects/%s/locations/%s/operations/%s",
		w.Project, w.Location, w.Op.Name)

	var op *container.Operation
	err := retryTimeDuration(func() (opErr error) {
		op, opErr = w.Service.Projects.Locations.Operations.Get(name).Do()
		return opErr
	}, DefaultRequestTimeout)

	return op, err
}

func (w *ContainerOperationWaiter) OpName() string {
	if w == nil || w.Op == nil {
		return "<nil>"
	}
	return w.Op.Name
}

func (w *ContainerOperationWaiter) PendingStates() []string {
	return []string{"PENDING", "RUNNING"}
}

func (w *ContainerOperationWaiter) TargetStates() []string {
	return []string{"DONE"}
}

func containerOperationWait(config *Config, op *container.Operation, project, location, activity string, timeoutMinutes int) error {
	w := &ContainerOperationWaiter{
		Service:  config.clientContainerBeta,
		Op:       op,
		Project:  project,
		Location: location,
	}

	if err := w.SetOp(op); err != nil {
		return err
	}

	return OperationWait(w, activity, timeoutMinutes)
}
<|endoftext|>


<commit_before>package handler

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

	"github.com/jeffbmartinez/log"
)

// BasicResponse creates a handler which responds with a standard response
// code and message string.
func BasicResponse(code int) func(response http.ResponseWriter, request *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		response.WriteHeader(code)
		response.Write([]byte(http.StatusText(code)))
	}
}

// WriteBasicResponse responds the the request with a BasicResponse
func WriteBasicResponse(code int, response http.ResponseWriter) {
	BasicResponse(code)(response, nil)
}

/*
WriteJSONResponse writes a json response (with correct http header).
*/
func WriteJSONResponse(response http.ResponseWriter, message interface{}, statusCode int) {
	responseString, err := json.Marshal(message)
	if err != nil {
		log.Errorf("Couldn't marshal json: %v", err)

		response.WriteHeader(http.StatusInternalServerError)
		response.Write([]byte(""))
		return
	}

	response.Header().Set("Content-Type", "application/json")
	response.WriteHeader(statusCode)
	response.Write([]byte(responseString))
}
<commit_msg>mini refactor<commit_after>package handler

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

	"github.com/jeffbmartinez/log"
)

// BasicResponse creates a handler which responds with a standard response
// code and message string.
func BasicResponse(code int) func(response http.ResponseWriter, request *http.Request) {
	return func(response http.ResponseWriter, request *http.Request) {
		response.WriteHeader(code)
		response.Write([]byte(http.StatusText(code)))
	}
}

// WriteBasicResponse responds the the request with a BasicResponse
func WriteBasicResponse(code int, response http.ResponseWriter) {
	BasicResponse(code)(response, nil)
}

/*
WriteJSONResponse writes a json response (with correct http header).
*/
func WriteJSONResponse(response http.ResponseWriter, message interface{}, statusCode int) {
	responseString, err := json.Marshal(message)
	if err != nil {
		log.Errorf("Couldn't marshal json: %v", err)

		WriteBasicResponse(http.StatusInternalServerError, response)
		return
	}

	response.Header().Set("Content-Type", "application/json")
	response.WriteHeader(statusCode)
	response.Write([]byte(responseString))
}
<|endoftext|>


<commit_before>package handlers

import (
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/thermokarst/bactdb/api"
	"github.com/thermokarst/bactdb/helpers"
	"github.com/thermokarst/bactdb/types"
)

func handleGetter(g api.Getter) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		e, appErr := g.Get(id, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleLister(l api.Lister) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		opt := r.URL.Query()
		opt.Add("Genus", mux.Vars(r)["genus"])

		claims := helpers.GetClaims(r)

		es, appErr := l.List(&opt, &claims)
		if appErr != nil {
			return appErr
		}
		data, err := es.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleUpdater(u api.Updater) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		e, err := u.Unmarshal(bodyBytes)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := u.Update(id, &e, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleCreater(c api.Creater) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		e, err := c.Unmarshal(bodyBytes)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := c.Create(&e, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleDeleter(d api.Deleter) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := d.Delete(id, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		return nil
	}
}
<commit_msg>Specify response status codes (delete, create)<commit_after>package handlers

import (
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/gorilla/mux"
	"github.com/thermokarst/bactdb/api"
	"github.com/thermokarst/bactdb/helpers"
	"github.com/thermokarst/bactdb/types"
)

func handleGetter(g api.Getter) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		e, appErr := g.Get(id, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleLister(l api.Lister) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		opt := r.URL.Query()
		opt.Add("Genus", mux.Vars(r)["genus"])

		claims := helpers.GetClaims(r)

		es, appErr := l.List(&opt, &claims)
		if appErr != nil {
			return appErr
		}
		data, err := es.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleUpdater(u api.Updater) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		e, err := u.Unmarshal(bodyBytes)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := u.Update(id, &e, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}
		w.Write(data)
		return nil
	}
}

func handleCreater(c api.Creater) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		bodyBytes, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		e, err := c.Unmarshal(bodyBytes)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := c.Create(&e, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		data, err := e.Marshal()
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		w.WriteHeader(http.StatusCreated)
		w.Write(data)

		return nil
	}
}

func handleDeleter(d api.Deleter) errorHandler {
	return func(w http.ResponseWriter, r *http.Request) *types.AppError {
		id, err := strconv.ParseInt(mux.Vars(r)["ID"], 10, 0)
		if err != nil {
			return newJSONError(err, http.StatusInternalServerError)
		}

		claims := helpers.GetClaims(r)

		appErr := d.Delete(id, mux.Vars(r)["genus"], &claims)
		if appErr != nil {
			return appErr
		}

		w.WriteHeader(http.StatusNoContent)

		return nil
	}
}
<|endoftext|>


<commit_before>package common

import (
	"sync/atomic"
	"time"
)

/*
ThrottleTimer fires an event at most "dur" after each .Set() call.
If a short burst of .Set() calls happens, ThrottleTimer fires once.
If a long continuous burst of .Set() calls happens, ThrottleTimer fires
at most once every "dur".
*/
type ThrottleTimer struct {
	Name  string
	Ch    chan struct{}
	quit  chan struct{}
	dur   time.Duration
	timer *time.Timer
	isSet uint32
}

func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
	var ch = make(chan struct{})
	var quit = make(chan struct{})
	var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit}
	t.timer = time.AfterFunc(dur, t.fireRoutine)
	t.timer.Stop()
	return t
}

func (t *ThrottleTimer) fireRoutine() {
	select {
	case t.Ch <- struct{}{}:
		atomic.StoreUint32(&t.isSet, 0)
	case <-t.quit:
		// do nothing
	default:
		t.timer.Reset(t.dur)
	}
}

func (t *ThrottleTimer) Set() {
	if atomic.CompareAndSwapUint32(&t.isSet, 0, 1) {
		t.timer.Reset(t.dur)
	}
}

// For ease of .Stop()'ing services before .Start()'ing them,
// we ignore .Stop()'s on nil ThrottleTimers
func (t *ThrottleTimer) Stop() bool {
	if t == nil {
		return false
	}
	close(t.quit)
	return t.timer.Stop()
}
<commit_msg>Add ThrottleTimer.Unset<commit_after>package common

import (
	"sync/atomic"
	"time"
)

/*
ThrottleTimer fires an event at most "dur" after each .Set() call.
If a short burst of .Set() calls happens, ThrottleTimer fires once.
If a long continuous burst of .Set() calls happens, ThrottleTimer fires
at most once every "dur".
*/
type ThrottleTimer struct {
	Name  string
	Ch    chan struct{}
	quit  chan struct{}
	dur   time.Duration
	timer *time.Timer
	isSet uint32
}

func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
	var ch = make(chan struct{})
	var quit = make(chan struct{})
	var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit}
	t.timer = time.AfterFunc(dur, t.fireRoutine)
	t.timer.Stop()
	return t
}

func (t *ThrottleTimer) fireRoutine() {
	select {
	case t.Ch <- struct{}{}:
		atomic.StoreUint32(&t.isSet, 0)
	case <-t.quit:
		// do nothing
	default:
		t.timer.Reset(t.dur)
	}
}

func (t *ThrottleTimer) Set() {
	if atomic.CompareAndSwapUint32(&t.isSet, 0, 1) {
		t.timer.Reset(t.dur)
	}
}

func (t *ThrottleTimer) Unset() {
	t.timer.Stop()
}

// For ease of .Stop()'ing services before .Start()'ing them,
// we ignore .Stop()'s on nil ThrottleTimers
func (t *ThrottleTimer) Stop() bool {
	if t == nil {
		return false
	}
	close(t.quit)
	return t.timer.Stop()
}
<|endoftext|>


<commit_before>package binance

import (
	"context"
	"encoding/json"

	"github.com/adshao/go-binance/common"
)

// ListBookTickersService list best price/qty on the order book for a symbol or symbols
type ListBookTickersService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListBookTickersService) Symbol(symbol string) *ListBookTickersService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListBookTickersService) Do(ctx context.Context, opts ...RequestOption) (res []*BookTicker, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/ticker/bookTicker",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	data = common.ToJSONList(data)
	if err != nil {
		return []*BookTicker{}, err
	}
	res = make([]*BookTicker, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*BookTicker{}, err
	}
	return res, nil
}

// BookTicker define book ticker info
type BookTicker struct {
	Symbol      string `json:"symbol"`
	BidPrice    string `json:"bidPrice"`
	BidQuantity string `json:"bidQty"`
	AskPrice    string `json:"askPrice"`
	AskQuantity string `json:"askQty"`
}

// ListPricesService list latest price for a symbol or symbols
type ListPricesService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListPricesService) Symbol(symbol string) *ListPricesService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListPricesService) Do(ctx context.Context, opts ...RequestOption) (res []*SymbolPrice, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/ticker/price",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return []*SymbolPrice{}, err
	}
	data = common.ToJSONList(data)
	res = make([]*SymbolPrice, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*SymbolPrice{}, err
	}
	return res, nil
}

// SymbolPrice define symbol and price pair
type SymbolPrice struct {
	Symbol string `json:"symbol"`
	Price  string `json:"price"`
}

// ListPriceChangeStatsService show stats of price change in last 24 hours for all symbols
type ListPriceChangeStatsService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListPriceChangeStatsService) Symbol(symbol string) *ListPriceChangeStatsService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListPriceChangeStatsService) Do(ctx context.Context, opts ...RequestOption) (res []*PriceChangeStats, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v1/ticker/24hr",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return res, err
	}
	data = common.ToJSONList(data)
	res = make([]*PriceChangeStats, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// PriceChangeStats define price change stats
type PriceChangeStats struct {
	Symbol             string `json:"symbol"`
	PriceChange        string `json:"priceChange"`
	PriceChangePercent string `json:"priceChangePercent"`
	WeightedAvgPrice   string `json:"weightedAvgPrice"`
	PrevClosePrice     string `json:"prevClosePrice"`
	LastPrice          string `json:"lastPrice"`
	BidPrice           string `json:"bidPrice"`
	AskPrice           string `json:"askPrice"`
	OpenPrice          string `json:"openPrice"`
	HighPrice          string `json:"highPrice"`
	LowPrice           string `json:"lowPrice"`
	Volume             string `json:"volume"`
	QuoteVolume        string `json:"quoteVolume"`
	OpenTime           int64  `json:"openTime"`
	CloseTime          int64  `json:"closeTime"`
	FristID            int64  `json:"firstId"`
	LastID             int64  `json:"lastId"`
	Count              int64  `json:"count"`
}

// AveragePriceService show current average price for a symbol
type AveragePriceService struct {
	c      *Client
	symbol string
}

// Symbol set symbol
func (s *AveragePriceService) Symbol(symbol string) *AveragePriceService {
	s.symbol = symbol
	return s
}

// Do send request
func (s *AveragePriceService) Do(ctx context.Context, opts ...RequestOption) (res *AvgPrice, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/avgPrice",
	}
	r.setParam("symbol", s.symbol)
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return res, err
	}
	res = new(AvgPrice)
	err = json.Unmarshal(data, res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// AvgPrice define average price
type AvgPrice struct {
	Mins  int64  `json:"mins"`
	Price string `json:"price"`
}
<commit_msg>Old endpoint: "/api/v1/ticker/24hr" replaced with a new endpoint: "/api/v3/ticker/24hr" according to documentation: "24hr Ticker Price Change Statistics" (#110)<commit_after>package binance

import (
	"context"
	"encoding/json"

	"github.com/adshao/go-binance/common"
)

// ListBookTickersService list best price/qty on the order book for a symbol or symbols
type ListBookTickersService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListBookTickersService) Symbol(symbol string) *ListBookTickersService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListBookTickersService) Do(ctx context.Context, opts ...RequestOption) (res []*BookTicker, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/ticker/bookTicker",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	data = common.ToJSONList(data)
	if err != nil {
		return []*BookTicker{}, err
	}
	res = make([]*BookTicker, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*BookTicker{}, err
	}
	return res, nil
}

// BookTicker define book ticker info
type BookTicker struct {
	Symbol      string `json:"symbol"`
	BidPrice    string `json:"bidPrice"`
	BidQuantity string `json:"bidQty"`
	AskPrice    string `json:"askPrice"`
	AskQuantity string `json:"askQty"`
}

// ListPricesService list latest price for a symbol or symbols
type ListPricesService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListPricesService) Symbol(symbol string) *ListPricesService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListPricesService) Do(ctx context.Context, opts ...RequestOption) (res []*SymbolPrice, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/ticker/price",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return []*SymbolPrice{}, err
	}
	data = common.ToJSONList(data)
	res = make([]*SymbolPrice, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return []*SymbolPrice{}, err
	}
	return res, nil
}

// SymbolPrice define symbol and price pair
type SymbolPrice struct {
	Symbol string `json:"symbol"`
	Price  string `json:"price"`
}

// ListPriceChangeStatsService show stats of price change in last 24 hours for all symbols
type ListPriceChangeStatsService struct {
	c      *Client
	symbol *string
}

// Symbol set symbol
func (s *ListPriceChangeStatsService) Symbol(symbol string) *ListPriceChangeStatsService {
	s.symbol = &symbol
	return s
}

// Do send request
func (s *ListPriceChangeStatsService) Do(ctx context.Context, opts ...RequestOption) (res []*PriceChangeStats, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/ticker/24hr",
	}
	if s.symbol != nil {
		r.setParam("symbol", *s.symbol)
	}
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return res, err
	}
	data = common.ToJSONList(data)
	res = make([]*PriceChangeStats, 0)
	err = json.Unmarshal(data, &res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// PriceChangeStats define price change stats
type PriceChangeStats struct {
	Symbol             string `json:"symbol"`
	PriceChange        string `json:"priceChange"`
	PriceChangePercent string `json:"priceChangePercent"`
	WeightedAvgPrice   string `json:"weightedAvgPrice"`
	PrevClosePrice     string `json:"prevClosePrice"`
	LastPrice          string `json:"lastPrice"`
	BidPrice           string `json:"bidPrice"`
	AskPrice           string `json:"askPrice"`
	OpenPrice          string `json:"openPrice"`
	HighPrice          string `json:"highPrice"`
	LowPrice           string `json:"lowPrice"`
	Volume             string `json:"volume"`
	QuoteVolume        string `json:"quoteVolume"`
	OpenTime           int64  `json:"openTime"`
	CloseTime          int64  `json:"closeTime"`
	FristID            int64  `json:"firstId"`
	LastID             int64  `json:"lastId"`
	Count              int64  `json:"count"`
}

// AveragePriceService show current average price for a symbol
type AveragePriceService struct {
	c      *Client
	symbol string
}

// Symbol set symbol
func (s *AveragePriceService) Symbol(symbol string) *AveragePriceService {
	s.symbol = symbol
	return s
}

// Do send request
func (s *AveragePriceService) Do(ctx context.Context, opts ...RequestOption) (res *AvgPrice, err error) {
	r := &request{
		method:   "GET",
		endpoint: "/api/v3/avgPrice",
	}
	r.setParam("symbol", s.symbol)
	data, err := s.c.callAPI(ctx, r, opts...)
	if err != nil {
		return res, err
	}
	res = new(AvgPrice)
	err = json.Unmarshal(data, res)
	if err != nil {
		return nil, err
	}
	return res, nil
}

// AvgPrice define average price
type AvgPrice struct {
	Mins  int64  `json:"mins"`
	Price string `json:"price"`
}
<|endoftext|>