<commit_before>package wmi

import (
	"encoding/json"
	"fmt"
	"reflect"
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestQuery(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := Query(q, &dst)
	if err != nil {
		t.Fatal(err)
	}
}

func TestFieldMismatch(t *testing.T) {
	type s struct {
		Name        string
		HandleCount uint32
		Blah        uint32
	}
	var dst []s
	err := Query("SELECT Name, HandleCount FROM Win32_Process", &dst)
	if err == nil || err.Error() != `wmi: cannot load field "Blah" into a "uint32": no such struct field` {
		t.Error("Expected err field mismatch")
	}
}

func TestStrings(t *testing.T) {
	var dst []struct {
		CSName         string
		WindowsVersion string
	}
	q := "Select CSName, WindowsVersion from Win32_Process"
	for i := 0; i < 5000; i++ {
		err := Query(q, &dst)
		if err != nil {
			t.Fatal(err)
		}
		for di, d := range dst {
			v := reflect.ValueOf(d)
			for j := 0; j < v.NumField(); j++ {
				f := v.Field(j)
				if f.Kind() != reflect.String {
					continue
				}
				s := f.Interface().(string)
				if len(s) > 0 && s[0] == '\u0000' {
					b, _ := json.MarshalIndent(d, "", "  ")
					_, _ = b, di
					t.Log(string(b))
					t.Error("bad string in iteration", i, "row", di, "of", len(dst))
				}
			}
		}
	}
}

func TestNamespace(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := QueryNamespace(q, &dst, `root\CIMV2`)
	if err != nil {
		t.Fatal(err)
	}
	dst = nil
	err = QueryNamespace(q, &dst, `broken\nothing`)
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestCreateQuery(t *testing.T) {
	type TestStruct struct {
		Name  string
		Count int
	}
	var dst []TestStruct
	output := "SELECT Name, Count FROM TestStruct WHERE Count > 2"
	tests := []interface{}{
		&dst,
		dst,
		TestStruct{},
		&TestStruct{},
	}
	for i, test := range tests {
		if o := CreateQuery(test, "WHERE Count > 2"); o != output {
			t.Error("bad output on", i, o)
		}
	}
	if CreateQuery(3, "") != "" {
		t.Error("expected empty string")
	}
}

func _TestMany(t *testing.T) {
	limit := 5000
	fmt.Println("running until:", limit)
	fmt.Println("No panics mean it succeeded. Other errors are OK.")
	runtime.GOMAXPROCS(2)
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		for i := 0; i < limit; i++ {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_PerfRawData_PerfDisk_LogicalDisk
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR disk", err)
			}
		}
		wg.Done()
	}()
	go func() {
		for i := 0; i > -limit; i-- {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_OperatingSystem
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR OS", err)
			}
		}
		wg.Done()
	}()
	wg.Wait()
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfDisk_LogicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint32
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint32
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	FreeMegabytes                uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentFreeSpace             uint32
	PercentFreeSpace_Base        uint32
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}
<commit_msg>Break after one round of failures<commit_after>package wmi

import (
	"encoding/json"
	"fmt"
	"reflect"
	"runtime"
	"sync"
	"testing"
	"time"
)

func TestQuery(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := Query(q, &dst)
	if err != nil {
		t.Fatal(err)
	}
}

func TestFieldMismatch(t *testing.T) {
	type s struct {
		Name        string
		HandleCount uint32
		Blah        uint32
	}
	var dst []s
	err := Query("SELECT Name, HandleCount FROM Win32_Process", &dst)
	if err == nil || err.Error() != `wmi: cannot load field "Blah" into a "uint32": no such struct field` {
		t.Error("Expected err field mismatch")
	}
}

func TestStrings(t *testing.T) {
	var dst []struct {
		CSName         string
		WindowsVersion string
	}
	q := "Select CSName, WindowsVersion from Win32_Process"
	for i := 0; i < 5000; i++ {
		err := Query(q, &dst)
		if err != nil {
			t.Fatal(err)
		}
		e := false
		for di, d := range dst {
			v := reflect.ValueOf(d)
			for j := 0; j < v.NumField(); j++ {
				f := v.Field(j)
				if f.Kind() != reflect.String {
					continue
				}
				s := f.Interface().(string)
				if len(s) > 0 && s[0] == '\u0000' {
					b, _ := json.MarshalIndent(d, "", "  ")
					_, _ = b, di
					t.Log(string(b))
					t.Error("bad string in iteration", i, "row", di, "of", len(dst))
					e = true
				}
			}
		}
		if e {
			break
		}
	}
}

func TestNamespace(t *testing.T) {
	var dst []Win32_Process
	q := CreateQuery(&dst, "")
	err := QueryNamespace(q, &dst, `root\CIMV2`)
	if err != nil {
		t.Fatal(err)
	}
	dst = nil
	err = QueryNamespace(q, &dst, `broken\nothing`)
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestCreateQuery(t *testing.T) {
	type TestStruct struct {
		Name  string
		Count int
	}
	var dst []TestStruct
	output := "SELECT Name, Count FROM TestStruct WHERE Count > 2"
	tests := []interface{}{
		&dst,
		dst,
		TestStruct{},
		&TestStruct{},
	}
	for i, test := range tests {
		if o := CreateQuery(test, "WHERE Count > 2"); o != output {
			t.Error("bad output on", i, o)
		}
	}
	if CreateQuery(3, "") != "" {
		t.Error("expected empty string")
	}
}

func _TestMany(t *testing.T) {
	limit := 5000
	fmt.Println("running until:", limit)
	fmt.Println("No panics mean it succeeded. Other errors are OK.")
	runtime.GOMAXPROCS(2)
	wg := sync.WaitGroup{}
	wg.Add(2)
	go func() {
		for i := 0; i < limit; i++ {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_PerfRawData_PerfDisk_LogicalDisk
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR disk", err)
			}
		}
		wg.Done()
	}()
	go func() {
		for i := 0; i > -limit; i-- {
			if i%25 == 0 {
				fmt.Println(i)
			}
			var dst []Win32_OperatingSystem
			q := CreateQuery(&dst, "")
			err := Query(q, &dst)
			if err != nil {
				fmt.Println("ERROR OS", err)
			}
		}
		wg.Done()
	}()
	wg.Wait()
}

type Win32_Process struct {
	CSCreationClassName        string
	CSName                     string
	Caption                    string
	CommandLine                string
	CreationClassName          string
	CreationDate               time.Time
	Description                string
	ExecutablePath             string
	ExecutionState             uint16
	Handle                     string
	HandleCount                uint32
	InstallDate                time.Time
	KernelModeTime             uint64
	MaximumWorkingSetSize      uint32
	MinimumWorkingSetSize      uint32
	Name                       string
	OSCreationClassName        string
	OSName                     string
	OtherOperationCount        uint64
	OtherTransferCount         uint64
	PageFaults                 uint32
	PageFileUsage              uint32
	ParentProcessId            uint32
	PeakPageFileUsage          uint32
	PeakVirtualSize            uint64
	PeakWorkingSetSize         uint32
	Priority                   uint32
	PrivatePageCount           uint64
	ProcessId                  uint32
	QuotaNonPagedPoolUsage     uint32
	QuotaPagedPoolUsage        uint32
	QuotaPeakNonPagedPoolUsage uint32
	QuotaPeakPagedPoolUsage    uint32
	ReadOperationCount         uint64
	ReadTransferCount          uint64
	SessionId                  uint32
	Status                     string
	TerminationDate            time.Time
	ThreadCount                uint32
	UserModeTime               uint64
	VirtualSize                uint64
	WindowsVersion             string
	WorkingSetSize             uint64
	WriteOperationCount        uint64
	WriteTransferCount         uint64
}

type Win32_PerfRawData_PerfDisk_LogicalDisk struct {
	AvgDiskBytesPerRead          uint64
	AvgDiskBytesPerRead_Base     uint32
	AvgDiskBytesPerTransfer      uint64
	AvgDiskBytesPerTransfer_Base uint32
	AvgDiskBytesPerWrite         uint64
	AvgDiskBytesPerWrite_Base    uint32
	AvgDiskQueueLength           uint64
	AvgDiskReadQueueLength       uint64
	AvgDiskSecPerRead            uint32
	AvgDiskSecPerRead_Base       uint32
	AvgDiskSecPerTransfer        uint32
	AvgDiskSecPerTransfer_Base   uint32
	AvgDiskSecPerWrite           uint32
	AvgDiskSecPerWrite_Base      uint32
	AvgDiskWriteQueueLength      uint64
	Caption                      string
	CurrentDiskQueueLength       uint32
	Description                  string
	DiskBytesPerSec              uint64
	DiskReadBytesPerSec          uint64
	DiskReadsPerSec              uint32
	DiskTransfersPerSec          uint32
	DiskWriteBytesPerSec         uint64
	DiskWritesPerSec             uint32
	FreeMegabytes                uint32
	Frequency_Object             uint64
	Frequency_PerfTime           uint64
	Frequency_Sys100NS           uint64
	Name                         string
	PercentDiskReadTime          uint64
	PercentDiskReadTime_Base     uint64
	PercentDiskTime              uint64
	PercentDiskTime_Base         uint64
	PercentDiskWriteTime         uint64
	PercentDiskWriteTime_Base    uint64
	PercentFreeSpace             uint32
	PercentFreeSpace_Base        uint32
	PercentIdleTime              uint64
	PercentIdleTime_Base         uint64
	SplitIOPerSec                uint32
	Timestamp_Object             uint64
	Timestamp_PerfTime           uint64
	Timestamp_Sys100NS           uint64
}

type Win32_OperatingSystem struct {
	BootDevice                                string
	BuildNumber                               string
	BuildType                                 string
	Caption                                   string
	CodeSet                                   string
	CountryCode                               string
	CreationClassName                         string
	CSCreationClassName                       string
	CSDVersion                                string
	CSName                                    string
	CurrentTimeZone                           int16
	DataExecutionPrevention_Available         bool
	DataExecutionPrevention_32BitApplications bool
	DataExecutionPrevention_Drivers           bool
	DataExecutionPrevention_SupportPolicy     uint8
	Debug                                     bool
	Description                               string
	Distributed                               bool
	EncryptionLevel                           uint32
	ForegroundApplicationBoost                uint8
	FreePhysicalMemory                        uint64
	FreeSpaceInPagingFiles                    uint64
	FreeVirtualMemory                         uint64
	InstallDate                               time.Time
	LargeSystemCache                          uint32
	LastBootUpTime                            time.Time
	LocalDateTime                             time.Time
	Locale                                    string
	Manufacturer                              string
	MaxNumberOfProcesses                      uint32
	MaxProcessMemorySize                      uint64
	MUILanguages                              []string
	Name                                      string
	NumberOfLicensedUsers                     uint32
	NumberOfProcesses                         uint32
	NumberOfUsers                             uint32
	OperatingSystemSKU                        uint32
	Organization                              string
	OSArchitecture                            string
	OSLanguage                                uint32
	OSProductSuite                            uint32
	OSType                                    uint16
	OtherTypeDescription                      string
	PAEEnabled                                bool
	PlusProductID                             string
	PlusVersionNumber                         string
	PortableOperatingSystem                   bool
	Primary                                   bool
	ProductType                               uint32
	RegisteredUser                            string
	SerialNumber                              string
	ServicePackMajorVersion                   uint16
	ServicePackMinorVersion                   uint16
	SizeStoredInPagingFiles                   uint64
	Status                                    string
	SuiteMask                                 uint32
	SystemDevice                              string
	SystemDirectory                           string
	SystemDrive                               string
	TotalSwapSpaceSize                        uint64
	TotalVirtualMemorySize                    uint64
	TotalVisibleMemorySize                    uint64
	Version                                   string
	WindowsDirectory                          string
}
<|endoftext|>


<commit_before>package curator

import (
	"github.com/samuel/go-zookeeper/zk"
)

type ACLProvider interface {
	// Return the ACL list to use by default
	GetDefaultAcl() []zk.ACL

	// Return the ACL list to use for the given path
	GetAclForPath(path string) []zk.ACL
}

type getACLBuilder struct {
	client        *curatorFramework
	backgrounding backgrounding
	stat          *zk.Stat
}

func (b *getACLBuilder) ForPath(givenPath string) ([]zk.ACL, error) {
	adjustedPath := b.client.fixForNamespace(givenPath, false)

	if b.backgrounding.inBackground {
		go b.pathInBackground(adjustedPath, givenPath)

		return nil, nil
	} else {
		return b.pathInForeground(adjustedPath)
	}
}

func (b *getACLBuilder) pathInBackground(path string, givenPath string) {
	tracer := b.client.ZookeeperClient().startTracer("getACLBuilder.pathInBackground")

	defer tracer.Commit()

	acls, err := b.pathInForeground(path)

	if b.backgrounding.callback != nil {
		event := &curatorEvent{
			eventType: GET_ACL,
			err:       err,
			path:      b.client.unfixForNamespace(path),
			acls:      acls,
			stat:      b.stat,
			context:   b.backgrounding.context,
		}

		if err != nil {
			event.path = givenPath
		}

		event.name = GetNodeFromPath(event.path)

		b.backgrounding.callback(b.client, event)
	}
}

func (b *getACLBuilder) pathInForeground(path string) ([]zk.ACL, error) {
	zkClient := b.client.ZookeeperClient()

	result, err := zkClient.newRetryLoop().CallWithRetry(func() (interface{}, error) {
		if conn, err := zkClient.Conn(); err != nil {
			return nil, err
		} else {
			acls, stat, err := conn.GetACL(path)

			if stat != nil && b.stat != nil {
				*b.stat = *stat
			}

			return acls, err
		}
	})

	acls, _ := result.([]zk.ACL)

	return acls, err
}

func (b *getACLBuilder) StoringStatIn(stat *zk.Stat) GetACLBuilder {
	b.stat = stat

	return b
}

func (b *getACLBuilder) InBackground() GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true}

	return b
}

func (b *getACLBuilder) InBackgroundWithContext(context interface{}) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context}

	return b
}

func (b *getACLBuilder) InBackgroundWithCallback(callback BackgroundCallback) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, callback: callback}

	return b
}

func (b *getACLBuilder) InBackgroundWithCallbackAndContext(callback BackgroundCallback, context interface{}) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context, callback: callback}

	return b
}

type setACLBuilder struct {
	client        *curatorFramework
	backgrounding backgrounding
	acling        acling
	version       int
}

func (b *setACLBuilder) ForPath(givenPath string) (*zk.Stat, error) {
	adjustedPath := b.client.fixForNamespace(givenPath, false)

	if b.backgrounding.inBackground {
		go b.pathInBackground(adjustedPath, givenPath)

		return nil, nil
	} else {
		return b.pathInForeground(adjustedPath)
	}
}

func (b *setACLBuilder) pathInBackground(path string, givenPath string) {
	tracer := b.client.ZookeeperClient().startTracer("setACLBuilder.pathInBackground")

	defer tracer.Commit()

	stat, err := b.pathInForeground(path)

	if b.backgrounding.callback != nil {
		event := &curatorEvent{
			eventType: SET_ACL,
			err:       err,
			path:      b.client.unfixForNamespace(path),
			acls:      b.acling.aclList,
			stat:      stat,
			context:   b.backgrounding.context,
		}

		if err != nil {
			event.path = givenPath
		}

		event.name = GetNodeFromPath(event.path)

		b.backgrounding.callback(b.client, event)
	}
}

func (b *setACLBuilder) pathInForeground(path string) (*zk.Stat, error) {
	zkClient := b.client.ZookeeperClient()

	result, err := zkClient.newRetryLoop().CallWithRetry(func() (interface{}, error) {
		if conn, err := zkClient.Conn(); err != nil {
			return nil, err
		} else {
			return conn.SetACL(path, b.acling.aclList, int32(b.version))
		}
	})

	stat, _ := result.(*zk.Stat)

	return stat, err
}

func (b *setACLBuilder) WithACL(acls ...zk.ACL) SetACLBuilder {
	b.acling = acling{aclList: acls, aclProvider: b.client.aclProvider}

	return b
}

func (b *setACLBuilder) WithVersion(version int) SetACLBuilder {
	b.version = version

	return b
}

func (b *setACLBuilder) InBackground() SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true}

	return b
}

func (b *setACLBuilder) InBackgroundWithContext(context interface{}) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context}

	return b
}

func (b *setACLBuilder) InBackgroundWithCallback(callback BackgroundCallback) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, callback: callback}

	return b
}

func (b *setACLBuilder) InBackgroundWithCallbackAndContext(callback BackgroundCallback, context interface{}) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context, callback: callback}

	return b
}
<commit_msg>add a default ACL provider<commit_after>package curator

import (
	"github.com/samuel/go-zookeeper/zk"
)

type ACLProvider interface {
	// Return the ACL list to use by default
	GetDefaultAcl() []zk.ACL

	// Return the ACL list to use for the given path
	GetAclForPath(path string) []zk.ACL
}

type defaultACLProvider struct {
	defaultAcls []zk.ACL
}

func (p *defaultACLProvider) GetDefaultAcl() []zk.ACL {
	return p.defaultAcls
}

func (p *defaultACLProvider) GetAclForPath(path string) []zk.ACL {
	return p.defaultAcls
}

func NewDefaultACLProvider() ACLProvider {
	return &defaultACLProvider{zk.WorldACL(zk.PermAll)}
}

type getACLBuilder struct {
	client        *curatorFramework
	backgrounding backgrounding
	stat          *zk.Stat
}

func (b *getACLBuilder) ForPath(givenPath string) ([]zk.ACL, error) {
	adjustedPath := b.client.fixForNamespace(givenPath, false)

	if b.backgrounding.inBackground {
		go b.pathInBackground(adjustedPath, givenPath)

		return nil, nil
	} else {
		return b.pathInForeground(adjustedPath)
	}
}

func (b *getACLBuilder) pathInBackground(path string, givenPath string) {
	tracer := b.client.ZookeeperClient().startTracer("getACLBuilder.pathInBackground")

	defer tracer.Commit()

	acls, err := b.pathInForeground(path)

	if b.backgrounding.callback != nil {
		event := &curatorEvent{
			eventType: GET_ACL,
			err:       err,
			path:      b.client.unfixForNamespace(path),
			acls:      acls,
			stat:      b.stat,
			context:   b.backgrounding.context,
		}

		if err != nil {
			event.path = givenPath
		}

		event.name = GetNodeFromPath(event.path)

		b.backgrounding.callback(b.client, event)
	}
}

func (b *getACLBuilder) pathInForeground(path string) ([]zk.ACL, error) {
	zkClient := b.client.ZookeeperClient()

	result, err := zkClient.newRetryLoop().CallWithRetry(func() (interface{}, error) {
		if conn, err := zkClient.Conn(); err != nil {
			return nil, err
		} else {
			acls, stat, err := conn.GetACL(path)

			if stat != nil && b.stat != nil {
				*b.stat = *stat
			}

			return acls, err
		}
	})

	acls, _ := result.([]zk.ACL)

	return acls, err
}

func (b *getACLBuilder) StoringStatIn(stat *zk.Stat) GetACLBuilder {
	b.stat = stat

	return b
}

func (b *getACLBuilder) InBackground() GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true}

	return b
}

func (b *getACLBuilder) InBackgroundWithContext(context interface{}) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context}

	return b
}

func (b *getACLBuilder) InBackgroundWithCallback(callback BackgroundCallback) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, callback: callback}

	return b
}

func (b *getACLBuilder) InBackgroundWithCallbackAndContext(callback BackgroundCallback, context interface{}) GetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context, callback: callback}

	return b
}

type setACLBuilder struct {
	client        *curatorFramework
	backgrounding backgrounding
	acling        acling
	version       int
}

func (b *setACLBuilder) ForPath(givenPath string) (*zk.Stat, error) {
	adjustedPath := b.client.fixForNamespace(givenPath, false)

	if b.backgrounding.inBackground {
		go b.pathInBackground(adjustedPath, givenPath)

		return nil, nil
	} else {
		return b.pathInForeground(adjustedPath)
	}
}

func (b *setACLBuilder) pathInBackground(path string, givenPath string) {
	tracer := b.client.ZookeeperClient().startTracer("setACLBuilder.pathInBackground")

	defer tracer.Commit()

	stat, err := b.pathInForeground(path)

	if b.backgrounding.callback != nil {
		event := &curatorEvent{
			eventType: SET_ACL,
			err:       err,
			path:      b.client.unfixForNamespace(path),
			acls:      b.acling.aclList,
			stat:      stat,
			context:   b.backgrounding.context,
		}

		if err != nil {
			event.path = givenPath
		}

		event.name = GetNodeFromPath(event.path)

		b.backgrounding.callback(b.client, event)
	}
}

func (b *setACLBuilder) pathInForeground(path string) (*zk.Stat, error) {
	zkClient := b.client.ZookeeperClient()

	result, err := zkClient.newRetryLoop().CallWithRetry(func() (interface{}, error) {
		if conn, err := zkClient.Conn(); err != nil {
			return nil, err
		} else {
			return conn.SetACL(path, b.acling.aclList, int32(b.version))
		}
	})

	stat, _ := result.(*zk.Stat)

	return stat, err
}

func (b *setACLBuilder) WithACL(acls ...zk.ACL) SetACLBuilder {
	b.acling = acling{aclList: acls, aclProvider: b.client.aclProvider}

	return b
}

func (b *setACLBuilder) WithVersion(version int) SetACLBuilder {
	b.version = version

	return b
}

func (b *setACLBuilder) InBackground() SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true}

	return b
}

func (b *setACLBuilder) InBackgroundWithContext(context interface{}) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context}

	return b
}

func (b *setACLBuilder) InBackgroundWithCallback(callback BackgroundCallback) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, callback: callback}

	return b
}

func (b *setACLBuilder) InBackgroundWithCallbackAndContext(callback BackgroundCallback, context interface{}) SetACLBuilder {
	b.backgrounding = backgrounding{inBackground: true, context: context, callback: callback}

	return b
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, OpenPeeDeeP. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xdg

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

type mockDefaulter struct {
	mock.Mock
}

func (m *mockDefaulter) defaultDataHome() string {
	args := m.Called()
	return args.String(0)
}
func (m *mockDefaulter) defaultDataDirs() []string {
	args := m.Called()
	return args.Get(0).([]string)
}
func (m *mockDefaulter) defaultConfigHome() string {
	args := m.Called()
	return args.String(0)
}
func (m *mockDefaulter) defaultConfigDirs() []string {
	args := m.Called()
	return args.Get(0).([]string)
}
func (m *mockDefaulter) defaultCacheHome() string {
	args := m.Called()
	return args.String(0)
}

func TestDataHome_WithoutXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultDataHome").Return(expected)
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_HOME", "") // nolint: errcheck

	actual := DataHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestDataHome_WithXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultDataHome").Return("/wrong/path")
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_HOME", expected) // nolint: errcheck

	actual := DataHome()
	mockDef.AssertNotCalled(t, "defaultDataHome")
	assert.Equal(expected, actual)
}

func TestDataHome_Application(t *testing.T) {
	assert := assert.New(t)
	root := "/some/path"
	vendor := "OpenPeeDeeP"
	app := "XDG"
	expected := filepath.Join(root, vendor, app)
	mockDef := new(mockDefaulter)
	appXDG := New(vendor, app)
	mockDef.On("defaultDataHome").Return(root)
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_HOME", "") // nolint: errcheck

	actual := appXDG.DataHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestDataDirs_WithoutXDG(t *testing.T) {
	assert := assert.New(t)
	expected := []string{"/some/path", "/some/other/path"}
	mockDef := new(mockDefaulter)
	mockDef.On("defaultDataDirs").Return(expected)
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_DIRS", "") // nolint: errcheck

	actual := DataDirs()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestDataDirs_WithXDG(t *testing.T) {
	assert := assert.New(t)
	expected := []string{"/some/path", "/some/other/path"}
	mockDef := new(mockDefaulter)
	mockDef.On("defaultDataDirs").Return([]string{"/wrong/path"})
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_DIRS", strings.Join(expected, string(os.PathListSeparator))) // nolint: errcheck

	actual := DataDirs()
	mockDef.AssertNotCalled(t, "defaultDataDirs")
	assert.Equal(expected, actual)
}

func TestDataDirs_Application(t *testing.T) {
	assert := assert.New(t)
	root := []string{"/some/path", "/some/other/path"}
	vendor := "OpenPeeDeeP"
	app := "XDG"
	expected := make([]string, len(root))
	for i, r := range root {
		expected[i] = filepath.Join(r, vendor, app)
	}
	mockDef := new(mockDefaulter)
	appXDG := New(vendor, app)
	mockDef.On("defaultDataDirs").Return(root)
	setDefaulter(mockDef)
	os.Setenv("XDG_DATA_DIRS", "") // nolint: errcheck

	actual := appXDG.DataDirs()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestConfigHome_WithoutXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultConfigHome").Return(expected)
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_HOME", "") // nolint: errcheck

	actual := ConfigHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestConfigHome_WithXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultConfigHome").Return("/wrong/path")
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_HOME", expected) // nolint: errcheck

	actual := ConfigHome()
	mockDef.AssertNotCalled(t, "defaultConfigHome")
	assert.Equal(expected, actual)
}

func TestConfigHome_Application(t *testing.T) {
	assert := assert.New(t)
	root := "/some/path"
	vendor := "OpenPeeDeeP"
	app := "XDG"
	expected := filepath.Join(root, vendor, app)
	mockDef := new(mockDefaulter)
	appXDG := New(vendor, app)
	mockDef.On("defaultConfigHome").Return(root)
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_HOME", "") // nolint: errcheck

	actual := appXDG.ConfigHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestConfigDirs_WithoutXDG(t *testing.T) {
	assert := assert.New(t)
	expected := []string{"/some/path", "/some/other/path"}
	mockDef := new(mockDefaulter)
	mockDef.On("defaultConfigDirs").Return(expected)
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_DIRS", "") // nolint: errcheck

	actual := ConfigDirs()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestConfigDirs_WithXDG(t *testing.T) {
	assert := assert.New(t)
	expected := []string{"/some/path", "/some/other/path"}
	mockDef := new(mockDefaulter)
	mockDef.On("defaultConfigDirs").Return([]string{"/wrong/path"})
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_DIRS", strings.Join(expected, string(os.PathListSeparator))) // nolint: errcheck

	actual := ConfigDirs()
	mockDef.AssertNotCalled(t, "defaultConfigDirs")
	assert.Equal(expected, actual)
}

func TestConfigDirs_Application(t *testing.T) {
	assert := assert.New(t)
	root := []string{"/some/path", "/some/other/path"}
	vendor := "OpenPeeDeeP"
	app := "XDG"
	expected := make([]string, len(root))
	for i, r := range root {
		expected[i] = filepath.Join(r, vendor, app)
	}
	mockDef := new(mockDefaulter)
	appXDG := New(vendor, app)
	mockDef.On("defaultConfigDirs").Return(root)
	setDefaulter(mockDef)
	os.Setenv("XDG_CONFIG_DIRS", "") // nolint: errcheck

	actual := appXDG.ConfigDirs()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestCacheHome_WithoutXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultCacheHome").Return(expected)
	setDefaulter(mockDef)
	os.Setenv("XDG_CACHE_HOME", "") // nolint: errcheck

	actual := CacheHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}

func TestCacheHome_WithXDG(t *testing.T) {
	assert := assert.New(t)
	expected := "/some/path"
	mockDef := new(mockDefaulter)
	mockDef.On("defaultCacheHome").Return("/wrong/path")
	setDefaulter(mockDef)
	os.Setenv("XDG_CACHE_HOME", expected) // nolint: errcheck

	actual := CacheHome()
	mockDef.AssertNotCalled(t, "defaultCacheHome")
	assert.Equal(expected, actual)
}

func TestCacheHome_Application(t *testing.T) {
	assert := assert.New(t)
	root := "/some/path"
	vendor := "OpenPeeDeeP"
	app := "XDG"
	expected := filepath.Join(root, vendor, app)
	mockDef := new(mockDefaulter)
	appXDG := New(vendor, app)
	mockDef.On("defaultCacheHome").Return(root)
	setDefaulter(mockDef)
	os.Setenv("XDG_CACHE_HOME", "") // nolint: errcheck

	actual := appXDG.CacheHome()
	mockDef.AssertExpectations(t)
	assert.Equal(expected, actual)
}
<commit_msg>Modify test to use test cases<commit_after>// Copyright (c) 2017, OpenPeeDeeP. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xdg

import (
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
)

type mockDefaulter struct {
	mock.Mock
}

func (m *mockDefaulter) defaultDataHome() string {
	args := m.Called()
	return args.String(0)
}
func (m *mockDefaulter) defaultDataDirs() []string {
	args := m.Called()
	return args.Get(0).([]string)
}
func (m *mockDefaulter) defaultConfigHome() string {
	args := m.Called()
	return args.String(0)
}
func (m *mockDefaulter) defaultConfigDirs() []string {
	args := m.Called()
	return args.Get(0).([]string)
}
func (m *mockDefaulter) defaultCacheHome() string {
	args := m.Called()
	return args.String(0)
}

const (
	MDataHome = iota
	MDataDirs
	MConfigHome
	MConfigDirs
	MCacheHome
)

var getterTestCases = []getterTestCase{
	{"DataHome Without", "defaultDataHome", "/some/path", true, "XDG_DATA_HOME", "", MDataHome, nil, "/some/path"},
	{"DataDirs Without", "defaultDataDirs", []string{"/some/path", "/some/other/path"}, true, "XDG_DATA_DIRS", "", MDataDirs, nil, []string{"/some/path", "/some/other/path"}},
	{"ConfigHome Without", "defaultConfigHome", "/some/path", true, "XDG_CONFIG_HOME", "", MConfigHome, nil, "/some/path"},
	{"ConfigDirs Without", "defaultConfigDirs", []string{"/some/path", "/some/other/path"}, true, "XDG_CONFIG_DIRS", "", MConfigDirs, nil, []string{"/some/path", "/some/other/path"}},
	{"CacheHome Without", "defaultCacheHome", "/some/path", true, "XDG_CACHE_HOME", "", MCacheHome, nil, "/some/path"},

	{"DataHome With", "defaultDataHome", "/wrong/path", false, "XDG_DATA_HOME", "/some/path", MDataHome, nil, "/some/path"},
	{"DataDirs With", "defaultDataDirs", []string{"/wrong/path", "/some/other/wrong"}, false, "XDG_DATA_DIRS", strings.Join([]string{"/some/path", "/some/other/path"}, string(os.PathListSeparator)), MDataDirs, nil, []string{"/some/path", "/some/other/path"}},
	{"ConfigHome With", "defaultConfigHome", "/wrong/path", false, "XDG_CONFIG_HOME", "/some/path", MConfigHome, nil, "/some/path"},
	{"ConfigDirs With", "defaultConfigDirs", []string{"/wrong/path", "/some/other/wrong"}, false, "XDG_CONFIG_DIRS", strings.Join([]string{"/some/path", "/some/other/path"}, string(os.PathListSeparator)), MConfigDirs, nil, []string{"/some/path", "/some/other/path"}},
	{"CacheHome With", "defaultCacheHome", "/wrong/path", false, "XDG_CACHE_HOME", "/some/path", MCacheHome, nil, "/some/path"},

	{"DataHome App Without", "defaultDataHome", "/some/path", true, "XDG_DATA_HOME", "", MDataHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},
	{"DataDirs App Without", "defaultDataDirs", []string{"/some/path", "/some/other/path"}, true, "XDG_DATA_DIRS", "", MDataDirs, New("OpenPeeDeeP", "XDG"), []string{"/some/path/OpenPeeDeeP/XDG", "/some/other/path/OpenPeeDeeP/XDG"}},
	{"ConfigHome App Without", "defaultConfigHome", "/some/path", true, "XDG_CONFIG_HOME", "", MConfigHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},
	{"ConfigDirs App Without", "defaultConfigDirs", []string{"/some/path", "/some/other/path"}, true, "XDG_CONFIG_DIRS", "", MConfigDirs, New("OpenPeeDeeP", "XDG"), []string{"/some/path/OpenPeeDeeP/XDG", "/some/other/path/OpenPeeDeeP/XDG"}},
	{"CacheHome App Without", "defaultCacheHome", "/some/path", true, "XDG_CACHE_HOME", "", MCacheHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},

	{"DataHome App With", "defaultDataHome", "/wrong/path", false, "XDG_DATA_HOME", "/some/path", MDataHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},
	{"DataDirs App With", "defaultDataDirs", []string{"/wrong/path", "/some/other/wrong"}, false, "XDG_DATA_DIRS", strings.Join([]string{"/some/path", "/some/other/path"}, string(os.PathListSeparator)), MDataDirs, New("OpenPeeDeeP", "XDG"), []string{"/some/path/OpenPeeDeeP/XDG", "/some/other/path/OpenPeeDeeP/XDG"}},
	{"ConfigHome App With", "defaultConfigHome", "/wrong/path", false, "XDG_CONFIG_HOME", "/some/path", MConfigHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},
	{"ConfigDirs App With", "defaultConfigDirs", []string{"/wrong/path", "/some/other/wrong"}, false, "XDG_CONFIG_DIRS", strings.Join([]string{"/some/path", "/some/other/path"}, string(os.PathListSeparator)), MConfigDirs, New("OpenPeeDeeP", "XDG"), []string{"/some/path/OpenPeeDeeP/XDG", "/some/other/path/OpenPeeDeeP/XDG"}},
	{"CacheHome App With", "defaultCacheHome", "/wrong/path", false, "XDG_CACHE_HOME", "/some/path", MCacheHome, New("OpenPeeDeeP", "XDG"), "/some/path/OpenPeeDeeP/XDG"},
}

type getterTestCase struct {
	name         string
	mokedMethod  string
	mockedReturn interface{}
	calledMocked bool
	env          string
	envVal       string
	method       int
	xdgApp       *XDG
	expected     interface{}
}

func TestXDG_Getters(t *testing.T) {
	for _, tc := range getterTestCases {
		t.Run(tc.name, func(t *testing.T) {
			assert := assert.New(t)
			mockDef := new(mockDefaulter)
			mockDef.On(tc.mokedMethod).Return(tc.mockedReturn)
			setDefaulter(mockDef)
			os.Setenv(tc.env, tc.envVal) // nolint: errcheck

			actual := computeActual(tc)

			if tc.calledMocked {
				mockDef.AssertExpectations(t)
			} else {
				mockDef.AssertNotCalled(t, tc.mokedMethod)
			}
			assert.Equal(tc.expected, actual)
		})
	}
}

// nolint: gocyclo
func computeActual(tc getterTestCase) interface{} {
	var actual interface{}
	switch tc.method {
	case MDataHome:
		if tc.xdgApp != nil {
			actual = tc.xdgApp.DataHome()
		} else {
			actual = DataHome()
		}
	case MDataDirs:
		if tc.xdgApp != nil {
			actual = tc.xdgApp.DataDirs()
		} else {
			actual = DataDirs()
		}
	case MConfigHome:
		if tc.xdgApp != nil {
			actual = tc.xdgApp.ConfigHome()
		} else {
			actual = ConfigHome()
		}
	case MConfigDirs:
		if tc.xdgApp != nil {
			actual = tc.xdgApp.ConfigDirs()
		} else {
			actual = ConfigDirs()
		}
	case MCacheHome:
		if tc.xdgApp != nil {
			actual = tc.xdgApp.CacheHome()
		} else {
			actual = CacheHome()
		}
	}
	return actual
}
<|endoftext|>


<commit_before>package api

import (
	"net/http"
	"strings"
)

const (
	vendorSeparator = "application/vnd."
)

// Version represents an API version.
type Version struct {
	version  string
	handler  http.Handler
	obsolete bool
}

// NewAPI creates a new API with a specified name.
func NewAPI(version string, handler http.Handler) *Version {
	return &Version{version: version, handler: handler}
}

// Version returns the version of the API.
func (a *Version) Version() string {
	return a.version
}

// Handler returns an handler.
func (a *Version) Handler() http.Handler {
	return a.handler
}

// MakeObsolete indicates an API is obsolete.
func (a *Version) MakeObsolete() {
	a.obsolete = true
}

// VendorMiddleware dispatches the request
// regarding the wanted version.
type VendorMiddleware struct {
	vendorName string
	versions   []Version
}

// VendorName returns the vendorName used
// to determine the vendor used in the
// "Accept" header.
func (v *VendorMiddleware) VendorName() string {
	return vendorSeparator + v.vendorName
}

// NewVendorMiddleware returns a new middleware.
func NewVendorMiddleware(name string) *VendorMiddleware {
	return &VendorMiddleware{vendorName: name}
}

func (v *VendorMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	if acceptVersion := r.Header.Get("Accept"); acceptVersion != v.VendorName() {
		http.Error(w, "Unknown vendor", http.StatusNotFound)
	} else {

		if lastIndex := strings.LastIndex(acceptVersion, vendorSeparator); lastIndex == -1 {
			http.Error(w, "Can not read accepted version", http.StatusNotFound)
		} else {

			version := acceptVersion[lastIndex:]

			for _, registeredVersion := range v.versions {
				if registeredVersion.version == version {

				}
			}
		}
	}

}
<commit_msg>Basic implentation<commit_after>package api

import (
	"errors"
	"net/http"
	"strings"
)

const (
	vendorSeparator = "application/vnd."
)

// Version represents an API version.
type Version struct {
	version  string
	handler  http.Handler
	obsolete bool
}

// NewAPI creates a new API with a specified name.
func NewAPI(version string, handler http.Handler) *Version {
	return &Version{version: version, handler: handler, obsolete: false}
}

// Version returns the version of the API.
func (a *Version) Version() string {
	return a.version
}

// Handler returns an handler.
func (a *Version) Handler() http.Handler {
	return a.handler
}

// MakeObsolete indicates an API is obsolete.
func (a *Version) MakeObsolete() {
	a.obsolete = true
}

// VendorMiddleware dispatches the request
// regarding the wanted version.
type VendorMiddleware struct {
	vendorName string
	versions   map[string]*Version
}

func (v *VendorMiddleware) version(versionName string) (*Version, error) {
	for key := range v.versions {
		if key == versionName {
			return v.versions[key], nil
		}
	}
	return nil, errors.New("Version not found")
}

// VendorName returns the vendorName used
// to determine the vendor used in the
// "Accept" header.
func (v *VendorMiddleware) VendorName() string {
	return vendorSeparator + v.vendorName
}

// NewVendorMiddleware returns a new middleware.
func NewVendorMiddleware(name string) *VendorMiddleware {
	return &VendorMiddleware{vendorName: name}
}

func (v *VendorMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {

	if acceptVersion := r.Header.Get("Accept"); acceptVersion != v.VendorName() {
		http.Error(w, "Unknown vendor", http.StatusNotFound)
	} else {

		lastIndex := strings.LastIndex(acceptVersion, vendorSeparator)

		if lastIndex == -1 {
			http.Error(w, "Can not read accepted version", http.StatusNotFound)
			return
		}
		version, err := v.version(acceptVersion[lastIndex:])
		if err != nil {
			http.Error(w, err.Error(), http.StatusNotFound)
			return
		}
		version.handler.ServeHTTP(w, r)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
)

func (h *HTTPClientHandler) addUserHandler(w http.ResponseWriter, r *http.Request) {
	// adding new user to database
}

func (h *HTTPClientHandler) getAllUsersHandler(w http.ResponseWriter, r *http.Request) {
	// displaying all users
}

func (h *HTTPClientHandler) getUserHandler(w http.ResponseWriter, r *http.Request) {
	// display current users locations for HOSTING and where he will be parking or is parking
}

func (h *HTTPClientHandler) updateUserHandler(w http.ResponseWriter, r *http.Request) {

}
<commit_msg>new user through api creation<commit_after>package main

import (
	log "github.com/Sirupsen/logrus"

	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type UserResource struct {
	Data []User `json:"data"`
}

// addUserHandler used to add new user
func (h *HTTPClientHandler) addUserHandler(w http.ResponseWriter, r *http.Request) {
	// adding new user to database
	var userRequest User

	defer r.Body.Close()
	body, err := ioutil.ReadAll(r.Body)

	if err != nil {
		// failed to read response body
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Could not read response body!")
		http.Error(w, "Failed to read request body.", 400)
		return
	}

	err = json.Unmarshal(body, &userRequest)

	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		w.WriteHeader(422) // can't process this entity
		return
	}
	log.WithFields(log.Fields{
		"firstName":     userRequest.FirstName,
		"firstName":     userRequest.LastName,
		"userID":        userRequest.UserID,
		"profilePicUrl": userRequest.ProfilePicUrl,
		"gender":        userRequest.Gender,
		"body":          string(body),
	}).Info("New user inserted!")

}

// getAllUsersHandler used to get all users
func (h *HTTPClientHandler) getAllUsersHandler(w http.ResponseWriter, r *http.Request) {
	// displaying all users
	results, err := h.db.getUsers()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err.Error(),
		}).Error("Got error when tried to get all users")
	}
	// Marshal provided interface into JSON structure
	response := UserResource{Data: results}
	uj, _ := json.Marshal(response)

	// Write content-type, statuscode, payload
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(200)
	fmt.Fprintf(w, "%s", uj)
}

func (h *HTTPClientHandler) getUserHandler(w http.ResponseWriter, r *http.Request) {
	// display current users locations for HOSTING and where he will be parking or is parking
}

func (h *HTTPClientHandler) updateUserHandler(w http.ResponseWriter, r *http.Request) {

}
<|endoftext|>


<commit_before>package dogo

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

// Params are to be used in conjuction with POST or PUT.
type Params map[string]interface{}

// Client is a client to the DigitalOcean API service
type Client struct {
	// DO Access Token
	Token string

	// Base DO API URL
	URL string
}

// NewClient creates a new Client.
func NewClient(token string) (*Client, error) {
	if token == "" {
		token = os.Getenv("DIGITALOCEAN_TOKEN")
	}
	if token == "" {
		return nil, EnvError
	}
	cl := &Client{
		Token: token,
		URL:   "https://api.digitalocean.com/v2",
	}
	return cl, nil
}

func (c *Client) get(endpoint string, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	req, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")
	err = c.DoRequest(req, v)

	if err != nil {
		return err
	}
	return nil
}

func (c *Client) delete(endpoint string) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	req, err := http.NewRequest("DELETE", endpoint, nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	err = c.DoRequest(req, nil)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) post(endpoint string, opts interface{}, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	payload, err := json.Marshal(opts)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(payload))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")

	c.DoRequest(req, v)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) put(endpoint string, opts interface{}, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	payload, err := json.Marshal(opts)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", endpoint, bytes.NewReader(payload))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	c.DoRequest(req, v)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) DoRequest(req *http.Request, v interface{}) error {
	cl := &http.Client{}
	req.Header.Set("Authorization", fmt.Sprintf("Bearer: %s", c.Token))
	resp, err := cl.Do(req)
	if err != nil {
		return fmt.Errorf("Error attemping request: %s", err)
	}
	err = decode(resp, v)
	if err != nil {
		return err
	}
	return nil
}

// Decode parses the response.
func decode(resp *http.Response, v interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("Error reading response: %s", err)
	}
	// create error
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		apiErr := &APIError{
			StatusCode: resp.StatusCode,
		}
		err := json.Unmarshal(body, apiErr)
		if err != nil {
			return fmt.Errorf("Error UnMarshaling JSON Response into error: %s", err)
		}
		return apiErr
	}

	if v != nil {
		err := json.Unmarshal(body, &v)
		if err != nil {
			return fmt.Errorf("Error UnMarshaling JSON Response into struct: %s", err)
		}
	}
	return nil
}

// DoAction performs an action on an endpoint resource with the passed id,
// type of action and its required params are described in the DigitalOcean API.
//
// For example in this case the image resource.
//
// https://developers.digitalocean.com/v2/#image-actions
//
// An example of some params:
//	params := digitalocean.Params{
//		"type": "transfer",
//		"region": "nyc2",
//	}
//
// The above example specifies the type of action, in this case resizing and
// the additional param in this case the size to resize to "1024mb".
//
// Params will sometimes only require the type of action and no additional params.
func (c *Client) DoAction(endpoint string, id int, params Params) error {
	u := fmt.Sprintf("%s/%d/actions", endpoint, id)
	err := c.post(u, params, nil)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>typo in authorization token header<commit_after>package dogo

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

// Params are to be used in conjuction with POST or PUT.
type Params map[string]interface{}

// Client is a client to the DigitalOcean API service
type Client struct {
	// DO Access Token
	Token string

	// Base DO API URL
	URL string
}

// NewClient creates a new Client.
func NewClient(token string) (*Client, error) {
	if token == "" {
		token = os.Getenv("DIGITALOCEAN_TOKEN")
	}
	if token == "" {
		return nil, EnvError
	}
	cl := &Client{
		Token: token,
		URL:   "https://api.digitalocean.com/v2",
	}
	return cl, nil
}

func (c *Client) get(endpoint string, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	req, err := http.NewRequest("GET", endpoint, nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")
	err = c.DoRequest(req, v)

	if err != nil {
		return err
	}
	return nil
}

func (c *Client) delete(endpoint string) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	req, err := http.NewRequest("DELETE", endpoint, nil)
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	err = c.DoRequest(req, nil)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) post(endpoint string, opts interface{}, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	payload, err := json.Marshal(opts)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", endpoint, bytes.NewReader(payload))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")

	c.DoRequest(req, v)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) put(endpoint string, opts interface{}, v interface{}) error {
	endpoint = fmt.Sprintf("%s/%s", c.URL, endpoint)
	payload, err := json.Marshal(opts)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("PUT", endpoint, bytes.NewReader(payload))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	c.DoRequest(req, v)
	if err != nil {
		return err
	}
	return nil
}

func (c *Client) DoRequest(req *http.Request, v interface{}) error {
	cl := &http.Client{}
	req.Header.Set("Authorization", "Bearer "+c.Token)
	resp, err := cl.Do(req)
	if err != nil {
		return fmt.Errorf("Error attemping request: %s", err)
	}
	err = decode(resp, v)
	if err != nil {
		return err
	}
	return nil
}

// Decode parses the response.
func decode(resp *http.Response, v interface{}) error {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("Error reading response: %s", err)
	}
	// create error
	if resp.StatusCode < 200 || resp.StatusCode >= 400 {
		apiErr := &APIError{
			StatusCode: resp.StatusCode,
		}
		err := json.Unmarshal(body, apiErr)
		if err != nil {
			return fmt.Errorf("Error UnMarshaling JSON Response into error: %s", err)
		}
		return apiErr
	}

	if v != nil {
		err := json.Unmarshal(body, &v)
		if err != nil {
			return fmt.Errorf("Error UnMarshaling JSON Response into struct: %s", err)
		}
	}
	return nil
}

// DoAction performs an action on an endpoint resource with the passed id,
// type of action and its required params are described in the DigitalOcean API.
//
// For example in this case the image resource.
//
// https://developers.digitalocean.com/v2/#image-actions
//
// An example of some params:
//	params := digitalocean.Params{
//		"type": "transfer",
//		"region": "nyc2",
//	}
//
// The above example specifies the type of action, in this case resizing and
// the additional param in this case the size to resize to "1024mb".
//
// Params will sometimes only require the type of action and no additional params.
func (c *Client) DoAction(endpoint string, id int, params Params) error {
	u := fmt.Sprintf("%s/%d/actions", endpoint, id)
	err := c.post(u, params, nil)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

type CreateLoadBalancerOptions struct {
	AvailabilityZones string
	Listeners         []ListenerOptions
	LoadBalancerName  string
	Scheme            string
	SecurityGroups    []string
	Subnets           []string
}

type CreateLoadBalancerListenersOptions struct {
	Listeners        []ListenerOptions
	LoadBalancerName string
}

type CreateLoadBalancerPolicyOptions struct {
	PolicyAttributes []string
	PolicyName       string
	PolicyTypeName   string
}

type RegisterInstancesWithLoadBalancerOptions struct {
	Instances        []InstanceOptions
	LoadBalancerName string
}

type ListenerOptions struct {
	LoadBalancerPort string
	Protocol         string
	InstancePort     string
	InstanceProtocol string
	SSLCertificateId string
	SSLCertificate   string
}

type InstanceOptions struct {
	InstanceId string
	IpAddress  string
}

func SetupApiHandlers() {
	http.HandleFunc("/", ELBHandler)
	http.ListenAndServe(":8080", nil)
}

func ELBHandler(w http.ResponseWriter, r *http.Request) {
	action := r.FormValue("Action")
	version := r.FormValue("Version")

	fmt.Println(action, version)

	// This is going to be nasty, but we need to redispatch the
	// request to the correct handler.
	switch action {
	case "CreateLoadBalancer":
		CreateLoadBalancerHandler(w, r)
	case "CreateLoadBalancerListeners":
		CreateLoadBalancerListenersHandler(w, r)
	case "CreateLoadBalancerPolicy":
		CreateLoadBalancerPolicyHandler(w, r)
	case "RegisterInstancesWithLoadBalancer":
		RegisterInstancesWithLoadBalancerHandler(w, r)
	}
}

func CreateLoadBalancerHandler(w http.ResponseWriter, r *http.Request) {

	optionSet := new(CreateLoadBalancerOptions)

	optionSet.LoadBalancerName = r.FormValue("LoadBalancerName")
	optionSet.Scheme = r.FormValue("Scheme")

	listenerSet := ListenerOptions{}
	listenerSet.LoadBalancerPort = r.FormValue("Listeners.member.1.LoadBalancerPort")
	listenerSet.InstancePort = r.FormValue("Listeners.member.1.InstancePort")
	listenerSet.Protocol = r.FormValue("Listeners.member.1.Protocol")
	listenerSet.InstanceProtocol = r.FormValue("Listeners.member.1.InstanceProtocol")

	optionSet.Listeners = append(optionSet.Listeners, listenerSet)

	fmt.Println(optionSet)
}

func CreateLoadBalancerListenersHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func CreateLoadBalancerPolicyHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func RegisterInstancesWithLoadBalancerHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func parseMembersFromInput()
<commit_msg>add policy attributes<commit_after>package main

import (
	"fmt"
	"net/http"
)

type CreateLoadBalancerOptions struct {
	AvailabilityZones string
	Listeners         []ListenerOptions
	LoadBalancerName  string
	Scheme            string
	SecurityGroups    []string
	Subnets           []string
}

type CreateLoadBalancerListenersOptions struct {
	Listeners        []ListenerOptions
	LoadBalancerName string
}

type CreateLoadBalancerPolicyOptions struct {
	PolicyAttributes []PolicyAttributeOptions
	PolicyName       string
	PolicyTypeName   string
}

type RegisterInstancesWithLoadBalancerOptions struct {
	Instances        []InstanceOptions
	LoadBalancerName string
}

type ListenerOptions struct {
	LoadBalancerPort string
	Protocol         string
	InstancePort     string
	InstanceProtocol string
	SSLCertificateId string
	SSLCertificate   string
}

type InstanceOptions struct {
	InstanceId string
	IpAddress  string
}

type PolicyAttributeOptions struct {
	AttributeName  string
	AttributeValue string
}

func SetupApiHandlers() {
	http.HandleFunc("/", ELBHandler)
	http.ListenAndServe(":8080", nil)
}

func ELBHandler(w http.ResponseWriter, r *http.Request) {
	action := r.FormValue("Action")
	version := r.FormValue("Version")

	fmt.Println(action, version)

	// This is going to be nasty, but we need to redispatch the
	// request to the correct handler.
	switch action {
	case "CreateLoadBalancer":
		CreateLoadBalancerHandler(w, r)
	case "CreateLoadBalancerListeners":
		CreateLoadBalancerListenersHandler(w, r)
	case "CreateLoadBalancerPolicy":
		CreateLoadBalancerPolicyHandler(w, r)
	case "RegisterInstancesWithLoadBalancer":
		RegisterInstancesWithLoadBalancerHandler(w, r)
	}
}

func CreateLoadBalancerHandler(w http.ResponseWriter, r *http.Request) {

	optionSet := new(CreateLoadBalancerOptions)

	optionSet.LoadBalancerName = r.FormValue("LoadBalancerName")
	optionSet.Scheme = r.FormValue("Scheme")

	listenerSet := ListenerOptions{}
	listenerSet.LoadBalancerPort = r.FormValue("Listeners.member.1.LoadBalancerPort")
	listenerSet.InstancePort = r.FormValue("Listeners.member.1.InstancePort")
	listenerSet.Protocol = r.FormValue("Listeners.member.1.Protocol")
	listenerSet.InstanceProtocol = r.FormValue("Listeners.member.1.InstanceProtocol")

	optionSet.Listeners = append(optionSet.Listeners, listenerSet)

	fmt.Println(optionSet)
}

func CreateLoadBalancerListenersHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func CreateLoadBalancerPolicyHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func RegisterInstancesWithLoadBalancerHandler(w http.ResponseWriter, r *http.Request) {
	loadBalancerName := r.FormValue("LoadBalancerName")
	fmt.Println(loadBalancerName)
}

func parseMembersFromInput()
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

const (
	headerTaId       = "X-Edo-Ta-Id"
	headerTaToken    = "X-Edo-Ta-Token"
	headerTaTokenSig = "X-Edo-Ta-Token-Sign"
	headerHashFunc   = "X-Edo-Hash-Function"

	headerTaAuthErr = "X-Edo-Ta-Auth-Error"

	cookieTaSess = "X-Edo-Ta-Session"
)

func uriBase(url *url.URL) string {
	return url.Scheme + "://" + url.Host + url.Path
}

// Web プロキシ。
func proxyApi(sys *system, w http.ResponseWriter, r *http.Request) error {

	taId := r.Header.Get(headerTaId)
	if taId == "" {
		taId = sys.taId
	}

	sess, _, err := sys.session(uriBase(r.URL), taId, nil)
	if err != nil {
		return erro.Wrap(err)
	}

	if sess != nil {
		// セッション確立済み。
		log.Debug("authenticated session is exist")
		return forward(sys, w, r, taId, sess)
	} else {
		// セッション未確立。
		log.Debug("session is not exist")
		return startSession(sys, w, r, taId)
	}
}

// 転送する。
func forward(sys *system, w http.ResponseWriter, r *http.Request, taId string, sess *session) error {
	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.id})
	r.RequestURI = ""

	resp, err := sess.cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("forwarded")

	if resp.StatusCode == http.StatusUnauthorized && resp.Header.Get(headerTaAuthErr) != "" {
		// edo-auth で 401 Unauthorized なら、タイミングの問題なので startSession からやり直す。
		// 古いセッションは上書きされるので消す必要無し。
		return startSession(sys, w, r, taId)
	}

	return copyResponse(resp, w)
}

// セッション開始。
func startSession(sys *system, w http.ResponseWriter, r *http.Request, taId string) error {

	cli := &http.Client{}

	r.RequestURI = ""
	resp, err := cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	log.Debug("sent raw request")

	if resp.Header.Get(headerTaAuthErr) == "" || resp.StatusCode != http.StatusUnauthorized {
		// 相手側が TA 認証を必要としていなかったのかもしれない。
		return copyResponse(resp, w)
	}

	// 相手側 TA も認証始めた。
	log.Debug("authentication started")

	sess, sessToken := parseSession(resp)
	if sess == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no cookie "+cookieTaSess, nil))
	} else if sessToken == "" {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no header field "+headerTaToken, nil))
	}

	expiDate := getExpirationDate(sess)

	// 認証用データが揃ってた。
	log.Debug("authentication data was found")

	priKey, _, err := sys.privateKey(taId, nil)
	if err != nil {
		return erro.Wrap(err)
	} else if priKey == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no private key of "+taId, nil))
	}

	// 秘密鍵を用意できた。
	log.Debug("private key of " + taId + " is exist")

	hashName := r.Header.Get(headerHashFunc)
	if hashName == "" {
		hashName = sys.hashName
	}

	tokenSign, err := sign(priKey, hashName, sessToken)
	if err != nil {
		return erro.Wrap(err)
	}

	// 署名できた。
	log.Debug("signed")

	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.Value})
	r.Header.Set(headerTaId, taId)
	r.Header.Set(headerTaTokenSig, tokenSign)
	r.Header.Set(headerHashFunc, hashName)
	r.RequestURI = ""

	resp, err = cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()

	// 認証された。
	log.Debug("authentication finished")

	if resp.Header.Get(headerTaAuthErr) != "" {
		// セッションを保存。
		if _, err := sys.addSession(&session{id: sess.Value, uri: uriBase(r.URL), taId: taId, cli: cli}, expiDate); err != nil {
			return erro.Wrap(err)
		}
	}

	return copyResponse(resp, w)
}

// 相手側 TA の認証開始レスポンスから必要情報を抜き出す。
func parseSession(resp *http.Response) (sess *http.Cookie, sessToken string) {
	for _, cookie := range resp.Cookies() {
		if cookie.Name == cookieTaSess {
			sess = cookie
			break
		}
	}

	return sess, resp.Header.Get(headerTaToken)
}

// 相手側 TA からのレスポンスをリクエスト元へのレスポンスに写す。
func copyResponse(resp *http.Response, w http.ResponseWriter) error {
	// ヘッダフィールドのコピー。
	for key, values := range resp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	// ステータスのコピー。
	w.WriteHeader(resp.StatusCode)

	// ボディのコピー。
	if _, err := io.Copy(w, resp.Body); err != nil {
		return erro.Wrap(err)
	}

	return nil
}

// 相手側 TA からのお題に署名する。
func sign(priKey *rsa.PrivateKey, hashName, token string) (string, error) {
	hash, err := util.ParseHashFunction(hashName)
	if err != nil {
		return "", erro.Wrap(err)
	}

	h := hash.New()
	h.Write([]byte(token))
	buff, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, h.Sum(nil))
	if err != nil {
		return "", erro.Wrap(err)
	}

	return base64.StdEncoding.EncodeToString(buff), nil
}

// 相手側 TA が提示したセッションの有効期限を読み取る。
func getExpirationDate(sess *http.Cookie) (expiDate time.Time) {
	if sess.MaxAge != 0 {
		return time.Now().Add(time.Duration(sess.MaxAge))
	} else {
		return sess.Expires
	}
}
<commit_msg>デバッグログを追加<commit_after>package main

import (
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"github.com/realglobe-Inc/edo/util"
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"io"
	"net"
	"net/http"
	"net/url"
	"time"
)

const (
	headerTaId       = "X-Edo-Ta-Id"
	headerTaToken    = "X-Edo-Ta-Token"
	headerTaTokenSig = "X-Edo-Ta-Token-Sign"
	headerHashFunc   = "X-Edo-Hash-Function"

	headerTaAuthErr = "X-Edo-Ta-Auth-Error"

	cookieTaSess = "X-Edo-Ta-Session"
)

func uriBase(url *url.URL) string {
	return url.Scheme + "://" + url.Host + url.Path
}

// Web プロキシ。
func proxyApi(sys *system, w http.ResponseWriter, r *http.Request) error {

	taId := r.Header.Get(headerTaId)
	if taId == "" {
		taId = sys.taId
	}

	sess, _, err := sys.session(uriBase(r.URL), taId, nil)
	if err != nil {
		return erro.Wrap(err)
	}

	if sess != nil {
		// セッション確立済み。
		log.Debug("authenticated session is exist")
		return forward(sys, w, r, taId, sess)
	} else {
		// セッション未確立。
		log.Debug("session is not exist")
		return startSession(sys, w, r, taId)
	}
}

// 転送する。
func forward(sys *system, w http.ResponseWriter, r *http.Request, taId string, sess *session) error {
	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.id})
	r.RequestURI = ""

	////////////////////////////////////////////////////////////
	util.LogRequest(r, true)
	////////////////////////////////////////////////////////////
	resp, err := sess.cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()
	////////////////////////////////////////////////////////////
	util.LogResponse(resp, true)
	////////////////////////////////////////////////////////////

	log.Debug("forwarded")

	if resp.StatusCode == http.StatusUnauthorized && resp.Header.Get(headerTaAuthErr) != "" {
		// edo-auth で 401 Unauthorized なら、タイミングの問題なので startSession からやり直す。
		// 古いセッションは上書きされるので消す必要無し。
		return startSession(sys, w, r, taId)
	}

	return copyResponse(resp, w)
}

// セッション開始。
func startSession(sys *system, w http.ResponseWriter, r *http.Request, taId string) error {

	cli := &http.Client{}

	r.RequestURI = ""

	////////////////////////////////////////////////////////////
	util.LogRequest(r, true)
	////////////////////////////////////////////////////////////
	resp, err := cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()
	////////////////////////////////////////////////////////////
	util.LogResponse(resp, true)
	////////////////////////////////////////////////////////////

	log.Debug("sent raw request")

	if resp.Header.Get(headerTaAuthErr) == "" || resp.StatusCode != http.StatusUnauthorized {
		// 相手側が TA 認証を必要としていなかったのかもしれない。
		return copyResponse(resp, w)
	}

	// 相手側 TA も認証始めた。
	log.Debug("authentication started")

	sess, sessToken := parseSession(resp)
	if sess == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no cookie "+cookieTaSess, nil))
	} else if sessToken == "" {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no header field "+headerTaToken, nil))
	}

	expiDate := getExpirationDate(sess)

	// 認証用データが揃ってた。
	log.Debug("authentication data was found")

	priKey, _, err := sys.privateKey(taId, nil)
	if err != nil {
		return erro.Wrap(err)
	} else if priKey == nil {
		return erro.Wrap(util.NewHttpStatusError(http.StatusForbidden, "no private key of "+taId, nil))
	}

	// 秘密鍵を用意できた。
	log.Debug("private key of " + taId + " is exist")

	hashName := r.Header.Get(headerHashFunc)
	if hashName == "" {
		hashName = sys.hashName
	}

	tokenSign, err := sign(priKey, hashName, sessToken)
	if err != nil {
		return erro.Wrap(err)
	}

	// 署名できた。
	log.Debug("signed")

	r.AddCookie(&http.Cookie{Name: cookieTaSess, Value: sess.Value})
	r.Header.Set(headerTaId, taId)
	r.Header.Set(headerTaTokenSig, tokenSign)
	r.Header.Set(headerHashFunc, hashName)
	r.RequestURI = ""

	////////////////////////////////////////////////////////////
	util.LogRequest(r, true)
	////////////////////////////////////////////////////////////
	resp, err = cli.Do(r)
	if err != nil {
		err = erro.Wrap(err)
		switch erro.Unwrap(err).(type) {
		case *net.OpError:
			return erro.Wrap(util.NewHttpStatusError(http.StatusNotFound, "cannot connect "+uriBase(r.URL), err))
		default:
			return err
		}
	}
	defer resp.Body.Close()
	////////////////////////////////////////////////////////////
	util.LogResponse(resp, true)
	////////////////////////////////////////////////////////////

	// 認証された。
	log.Debug("authentication finished")

	if resp.Header.Get(headerTaAuthErr) != "" {
		// セッションを保存。
		if _, err := sys.addSession(&session{id: sess.Value, uri: uriBase(r.URL), taId: taId, cli: cli}, expiDate); err != nil {
			return erro.Wrap(err)
		}
	}

	return copyResponse(resp, w)
}

// 相手側 TA の認証開始レスポンスから必要情報を抜き出す。
func parseSession(resp *http.Response) (sess *http.Cookie, sessToken string) {
	for _, cookie := range resp.Cookies() {
		if cookie.Name == cookieTaSess {
			sess = cookie
			break
		}
	}

	return sess, resp.Header.Get(headerTaToken)
}

// 相手側 TA からのレスポンスをリクエスト元へのレスポンスに写す。
func copyResponse(resp *http.Response, w http.ResponseWriter) error {
	// ヘッダフィールドのコピー。
	for key, values := range resp.Header {
		for _, value := range values {
			w.Header().Add(key, value)
		}
	}

	// ステータスのコピー。
	w.WriteHeader(resp.StatusCode)

	// ボディのコピー。
	if _, err := io.Copy(w, resp.Body); err != nil {
		return erro.Wrap(err)
	}

	return nil
}

// 相手側 TA からのお題に署名する。
func sign(priKey *rsa.PrivateKey, hashName, token string) (string, error) {
	hash, err := util.ParseHashFunction(hashName)
	if err != nil {
		return "", erro.Wrap(err)
	}

	h := hash.New()
	h.Write([]byte(token))
	buff, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, h.Sum(nil))
	if err != nil {
		return "", erro.Wrap(err)
	}

	return base64.StdEncoding.EncodeToString(buff), nil
}

// 相手側 TA が提示したセッションの有効期限を読み取る。
func getExpirationDate(sess *http.Cookie) (expiDate time.Time) {
	if sess.MaxAge != 0 {
		return time.Now().Add(time.Duration(sess.MaxAge))
	} else {
		return sess.Expires
	}
}
<|endoftext|>


<commit_before>// Package stockfighter provides a simple wrapper for the Stockfighter API:
//
// https://www.stockfighter.io/
//
// https://starfighter.readme.io/
package stockfighter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"

	"github.com/gorilla/websocket"
)

func apiUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/ob/api/"+path, args...)
}

func gmUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/gm/"+path, args...)
}

func wsUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("wss://api.stockfighter.io/ob/api/ws/"+path, args...)
}

type apiCall interface {
	Err() error
}

type response struct {
	Ok    bool
	Error string
}

func (r response) Err() error {
	if len(r.Error) > 0 {
		return fmt.Errorf(r.Error)
	}
	return nil
}

type venueResponse struct {
	response
	Venue string
}

type stocksResponse struct {
	response
	Symbols []Symbol
}

type orderBookResponse struct {
	response
	OrderBook
}

type quoteResponse struct {
	response
	Quote
}

type orderResponse struct {
	response
	OrderState
}

type bulkOrderResponse struct {
	response
	Venue  string
	Orders []OrderState
}

type quoteMessage struct {
	Ok    bool
	Quote Quote
}

type executionMessage struct {
	Ok      bool
	Account string
	Venue   string
	Symbol  string
	Order   Execution
}

type gameResponse struct {
	response
	Game
}

type gameStateResponse struct {
	response
	GameState
}

type Stockfighter struct {
	apiKey string
	debug  bool
}

// Create new Stockfighter API instance.
// If debug is true, log all HTTP requests and responses.
func NewStockfighter(apiKey string, debug bool) *Stockfighter {
	return &Stockfighter{
		apiKey: apiKey,
		debug:  debug,
	}
}

// Check the API Is Up. If venue is a non-empty string, then check that venue.
// Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) Heartbeat(venue string) error {
	var resp response
	url := apiUrl("heartbeat")
	if len(venue) > 0 {
		url = apiUrl("venues/%s/heartbeat", venue)
	}
	return sf.do("GET", url, nil, &resp)
}

// Get the stocks available for trading on a venue.
func (sf *Stockfighter) Stocks(venue string) ([]Symbol, error) {
	var resp stocksResponse
	url := apiUrl("venues/%s/stocks", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Symbols, nil
}

// Get the orderbook for a particular stock.
func (sf *Stockfighter) OrderBook(venue, stock string) (*OrderBook, error) {
	var resp orderBookResponse
	url := apiUrl("venues/%s/stocks/%s", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderBook, nil
}

// Get a quick look at the most recent trade information for a stock.
func (sf *Stockfighter) Quote(venue, stock string) (*Quote, error) {
	var resp quoteResponse
	url := apiUrl("venues/%s/stocks/%s/quote", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Quote, nil
}

// Place an order
func (sf *Stockfighter) Place(order *Order) (*OrderState, error) {
	body, err := encodeJson(order)
	if err != nil {
		return nil, err
	}
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders", order.Venue, order.Stock)
	if err := sf.do("POST", url, body, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the status for an existing order.
func (sf *Stockfighter) Status(venue, stock string, id uint64) (*OrderState, error) {
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the statuses for all an account's orders of a stock on a venue.
// If stock is a non-empty string, only statuses for that stock are returned
func (sf *Stockfighter) StockStatus(account, venue, stock string) ([]OrderState, error) {
	url := apiUrl("venues/%s/accounts/%s/orders", venue, account)
	if len(stock) > 0 {
		url = apiUrl("venues/%s/accounts/%s/stocks/%s/orders", venue, account, stock)
	}
	var resp bulkOrderResponse
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Orders, nil
}

// Cancel an existing order
func (sf *Stockfighter) Cancel(venue, stock string, id uint64) error {
	var resp response
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	return sf.do("DELETE", url, nil, &resp)
}

// Subscribe to a stream of quotes for a venue.
// If stock is a non-empy string, only quotes for that stock are returned.
func (sf *Stockfighter) Quotes(account, venue, stock string) (chan *Quote, error) {
	url := wsUrl("%s/venues/%s/tickertape", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/tickertape", account, venue, stock)
	}
	c := make(chan *Quote)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var quote quoteMessage
		if err := conn.ReadJSON(&quote); err != nil {
			close(c)
			return err
		}
		if quote.Ok {
			c <- &quote.Quote
		}
		return nil
	})
}

// Subscribe to a stream of executions for a venue.
// If stock is a non-empy string, only executions for that stock are returned.
func (sf *Stockfighter) Executions(account, venue, stock string) (chan *Execution, error) {
	url := wsUrl("%s/venues/%s/executions", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/executions", account, venue, stock)
	}
	c := make(chan *Execution)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var execution executionMessage
		if err := conn.ReadJSON(&execution); err != nil {
			close(c)
			return err
		}
		if execution.Ok {
			c <- &execution.Order
		}
		return nil
	})
}

// Start a new level.
func (sf *Stockfighter) Start(level string) (*Game, error) {
	var resp gameResponse
	url := gmUrl("levels/%s", level)
	if err := sf.do("POST", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Game, nil
}

// Restart a level using the instance id from a previously started Game.
func (sf *Stockfighter) Restart(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/restart", id)
	return sf.do("POST", url, nil, &resp)
}

// Resume a level using the instance id from a previously started Game.
func (sf *Stockfighter) Resume(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/resume", id)
	return sf.do("POST", url, nil, &resp)
}

// Stop a level using the instance id from a previously started Game.
func (sf *Stockfighter) Stop(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/stop", id)
	return sf.do("POST", url, nil, &resp)
}

// Get the GameState using the instance id from a previously started Game.
func (sf *Stockfighter) GameStatus(id uint64) (*GameState, error) {
	var resp gameStateResponse
	url := gmUrl("instances/%d", id)
	if err := sf.do("Get", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.GameState, nil
}

func encodeJson(v interface{}) (io.Reader, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(v); err != nil {
		return nil, err
	}
	return &buf, nil
}

func (sf *Stockfighter) do(method, url string, body io.Reader, value apiCall) error {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("X-Starfighter-Authorization", sf.apiKey)
	if sf.debug {
		out, _ := httputil.DumpRequest(req, true)
		log.Println(string(out))
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if sf.debug {
		out, _ := httputil.DumpResponse(resp, true)
		log.Println(string(out))
	}
	if err := json.NewDecoder(resp.Body).Decode(value); err != nil {
		return err
	}
	return value.Err()
}

func (sf *Stockfighter) pump(url string, f func(*websocket.Conn) error) error {
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return err
	}
	go func() {
		defer conn.Close()
		for err := f(conn); err == nil; err = f(conn) {
		}
	}()
	return nil
}
<commit_msg>Fix Execution message and add Judge API call<commit_after>// Package stockfighter provides a simple wrapper for the Stockfighter API:
//
// https://www.stockfighter.io/
//
// https://starfighter.readme.io/
package stockfighter

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"

	"github.com/gorilla/websocket"
)

func apiUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/ob/api/"+path, args...)
}

func gmUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("https://api.stockfighter.io/gm/"+path, args...)
}

func wsUrl(path string, args ...interface{}) string {
	return fmt.Sprintf("wss://api.stockfighter.io/ob/api/ws/"+path, args...)
}

type apiCall interface {
	Err() error
}

type response struct {
	Ok    bool
	Error string
}

func (r response) Err() error {
	if len(r.Error) > 0 {
		return fmt.Errorf(r.Error)
	}
	return nil
}

type venueResponse struct {
	response
	Venue string
}

type stocksResponse struct {
	response
	Symbols []Symbol
}

type orderBookResponse struct {
	response
	OrderBook
}

type quoteResponse struct {
	response
	Quote
}

type orderResponse struct {
	response
	OrderState
}

type bulkOrderResponse struct {
	response
	Venue  string
	Orders []OrderState
}

type quoteMessage struct {
	Ok    bool
	Quote Quote
}

type executionMessage struct {
	Ok bool
	Execution
}

type gameResponse struct {
	response
	Game
}

type gameStateResponse struct {
	response
	GameState
}

type Stockfighter struct {
	apiKey string
	debug  bool
}

// Create new Stockfighter API instance.
// If debug is true, log all HTTP requests and responses.
func NewStockfighter(apiKey string, debug bool) *Stockfighter {
	return &Stockfighter{
		apiKey: apiKey,
		debug:  debug,
	}
}

// Check the API Is Up. If venue is a non-empty string, then check that venue.
// Returns nil if ok, otherwise the error indicates the problem.
func (sf *Stockfighter) Heartbeat(venue string) error {
	var resp response
	url := apiUrl("heartbeat")
	if len(venue) > 0 {
		url = apiUrl("venues/%s/heartbeat", venue)
	}
	return sf.do("GET", url, nil, &resp)
}

// Get the stocks available for trading on a venue.
func (sf *Stockfighter) Stocks(venue string) ([]Symbol, error) {
	var resp stocksResponse
	url := apiUrl("venues/%s/stocks", venue)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Symbols, nil
}

// Get the orderbook for a particular stock.
func (sf *Stockfighter) OrderBook(venue, stock string) (*OrderBook, error) {
	var resp orderBookResponse
	url := apiUrl("venues/%s/stocks/%s", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderBook, nil
}

// Get a quick look at the most recent trade information for a stock.
func (sf *Stockfighter) Quote(venue, stock string) (*Quote, error) {
	var resp quoteResponse
	url := apiUrl("venues/%s/stocks/%s/quote", venue, stock)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Quote, nil
}

// Place an order
func (sf *Stockfighter) Place(order *Order) (*OrderState, error) {
	body, err := encodeJson(order)
	if err != nil {
		return nil, err
	}
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders", order.Venue, order.Stock)
	if err := sf.do("POST", url, body, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the status for an existing order.
func (sf *Stockfighter) Status(venue, stock string, id uint64) (*OrderState, error) {
	var resp orderResponse
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.OrderState, nil
}

// Get the statuses for all an account's orders of a stock on a venue.
// If stock is a non-empty string, only statuses for that stock are returned
func (sf *Stockfighter) StockStatus(account, venue, stock string) ([]OrderState, error) {
	url := apiUrl("venues/%s/accounts/%s/orders", venue, account)
	if len(stock) > 0 {
		url = apiUrl("venues/%s/accounts/%s/stocks/%s/orders", venue, account, stock)
	}
	var resp bulkOrderResponse
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return resp.Orders, nil
}

// Cancel an existing order
func (sf *Stockfighter) Cancel(venue, stock string, id uint64) error {
	var resp response
	url := apiUrl("venues/%s/stocks/%s/orders/%d", venue, stock, id)
	return sf.do("DELETE", url, nil, &resp)
}

// Subscribe to a stream of quotes for a venue.
// If stock is a non-empy string, only quotes for that stock are returned.
func (sf *Stockfighter) Quotes(account, venue, stock string) (chan *Quote, error) {
	url := wsUrl("%s/venues/%s/tickertape", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/tickertape", account, venue, stock)
	}
	c := make(chan *Quote)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var quote quoteMessage
		if err := conn.ReadJSON(&quote); err != nil {
			close(c)
			return err
		}
		if quote.Ok {
			c <- &quote.Quote
		}
		return nil
	})
}

// Subscribe to a stream of executions for a venue.
// If stock is a non-empy string, only executions for that stock are returned.
func (sf *Stockfighter) Executions(account, venue, stock string) (chan *Execution, error) {
	url := wsUrl("%s/venues/%s/executions", account, venue)
	if len(stock) > 0 {
		url = wsUrl("%s/venues/%s/stocks/%s/executions", account, venue, stock)
	}
	c := make(chan *Execution)
	return c, sf.pump(url, func(conn *websocket.Conn) error {
		var execution executionMessage
		if err := conn.ReadJSON(&execution); err != nil {
			close(c)
			return err
		}
		if execution.Ok {
			c <- &execution.Execution
		}
		return nil
	})
}

// Start a new level.
func (sf *Stockfighter) Start(level string) (*Game, error) {
	var resp gameResponse
	url := gmUrl("levels/%s", level)
	if err := sf.do("POST", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.Game, nil
}

// Restart a level using the instance id from a previously started Game.
func (sf *Stockfighter) Restart(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/restart", id)
	return sf.do("POST", url, nil, &resp)
}

// Resume a level using the instance id from a previously started Game.
func (sf *Stockfighter) Resume(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/resume", id)
	return sf.do("POST", url, nil, &resp)
}

// Stop a level using the instance id from a previously started Game.
func (sf *Stockfighter) Stop(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/stop", id)
	return sf.do("POST", url, nil, &resp)
}

// Get the GameState using the instance id from a previously started Game.
func (sf *Stockfighter) GameStatus(id uint64) (*GameState, error) {
	var resp gameStateResponse
	url := gmUrl("instances/%d", id)
	if err := sf.do("GET", url, nil, &resp); err != nil {
		return nil, err
	}
	return &resp.GameState, nil
}

func (sf *Stockfighter) Judge(id uint64) error {
	var resp response
	url := gmUrl("instances/%d/judge", id)
	test := map[string]interface{}{"test": "test"}
	body, err := encodeJson(test)
	if err != nil {
		return err
	}
	return sf.do("POST", url, body, &resp)
}

func encodeJson(v interface{}) (io.Reader, error) {
	var buf bytes.Buffer
	if err := json.NewEncoder(&buf).Encode(v); err != nil {
		return nil, err
	}
	return &buf, nil
}

func (sf *Stockfighter) do(method, url string, body io.Reader, value apiCall) error {
	req, err := http.NewRequest(method, url, body)
	if err != nil {
		return err
	}
	req.Header.Add("X-Starfighter-Authorization", sf.apiKey)
	if sf.debug {
		out, _ := httputil.DumpRequest(req, true)
		log.Println(string(out))
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if sf.debug {
		out, _ := httputil.DumpResponse(resp, true)
		log.Println(string(out))
	}
	if err := json.NewDecoder(resp.Body).Decode(value); err != nil {
		return err
	}
	return value.Err()
}

func (sf *Stockfighter) pump(url string, f func(*websocket.Conn) error) error {
	conn, _, err := websocket.DefaultDialer.Dial(url, nil)
	if err != nil {
		return err
	}
	go func() {
		defer conn.Close()
		for err := f(conn); err == nil; err = f(conn) {
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2015 Hraban Luyat <hraban@0brg.net>
//
// License for use of this code is detailed in the LICENSE file

package opus

import (
	"fmt"
	"unsafe"
)

/*
// Statically link libopus. Requires a libopus.a in every directory you use this
// as a dependency in. Not great, but CGO doesn't offer anything better, right
// now. Unless you require everyone who USES this package to instal have libopus
// installed system-wide, which is more of a chore because it's so new. Everyone
// will end up having to build it from source anyway, might as well just dump
// the pre-built lib in here. At least it will be up to the package maintainer,
// not the user.
//
// If I missed something, and somebody knows a better way: please let me know.
#cgo LDFLAGS: libopus.a -lm
#cgo CFLAGS: -std=c99 -Wall -Werror -pedantic -Ilibopusbuild/include
#include <opus/opus.h>
*/
import "C"

type Application int

// TODO: Get from lib because #defines can change
const APPLICATION_VOIP Application = 2048
const APPLICATION_AUDIO Application = 2049
const APPLICATION_RESTRICTED_LOWDELAY Application = 2051

const xMAX_BITRATE = 48000
const xMAX_FRAME_SIZE_MS = 60
const xMAX_FRAME_SIZE = xMAX_BITRATE * xMAX_FRAME_SIZE_MS / 1000

func Version() string {
	return C.GoString(C.opus_get_version_string())
}

type Encoder struct {
	p *C.struct_OpusEncoder
}

func opuserr(code int) error {
	return fmt.Errorf("opus: %s", C.GoString(C.opus_strerror(C.int(code))))
}

func NewEncoder(sample_rate int, channels int, application Application) (*Encoder, error) {
	var errno int
	p := C.opus_encoder_create(C.opus_int32(sample_rate), C.int(channels), C.int(application), (*C.int)(unsafe.Pointer(&errno)))
	if errno != 0 {
		return nil, opuserr(errno)
	}
	return &Encoder{p: p}, nil
}

func (enc *Encoder) EncodeFloat32(pcm []float32) ([]byte, error) {
	if pcm == nil || len(pcm) == 0 {
		return nil, fmt.Errorf("opus: no data supplied")
	}
	// I never know how much to allocate
	data := make([]byte, 10000)
	n := int(C.opus_encode_float(
		enc.p,
		(*C.float)(&pcm[0]),
		C.int(len(pcm)),
		(*C.uchar)(&data[0]),
		C.opus_int32(cap(data))))
	if n < 0 {
		return nil, opuserr(n)
	}
	return data[:n], nil
}

// Returns an error if the encoder was already closed
func (enc *Encoder) Close() error {
	if enc.p == nil {
		return fmt.Errorf("opus: encoder already closed")
	}
	C.opus_encoder_destroy(enc.p)
	enc.p = nil
	return nil
}

type Decoder struct {
	p           *C.struct_OpusDecoder
	sample_rate int
}

func NewDecoder(sample_rate int, channels int) (*Decoder, error) {
	var errno int
	p := C.opus_decoder_create(C.opus_int32(sample_rate), C.int(channels), (*C.int)(unsafe.Pointer(&errno)))
	if errno != 0 {
		return nil, opuserr(errno)
	}
	dec := &Decoder{
		p:           p,
		sample_rate: sample_rate,
	}
	return dec, nil
}

func (dec *Decoder) DecodeFloat32(data []byte) ([]float32, error) {
	if data == nil || len(data) == 0 {
		return nil, fmt.Errorf("opus: no data supplied")
	}
	// I don't know how big this frame will be, but this is the limit
	pcm := make([]float32, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000)
	n := int(C.opus_decode_float(
		dec.p,
		(*C.uchar)(&data[0]),
		C.opus_int32(len(data)),
		(*C.float)(&pcm[0]),
		C.int(cap(pcm)),
		0))
	if n < 0 {
		return nil, opuserr(n)
	}
	return pcm[:n], nil
}

// Returns an error if the encoder was already closed
func (dec *Decoder) Close() error {
	if dec.p == nil {
		return fmt.Errorf("opus: decoder already closed")
	}
	C.opus_decoder_destroy(dec.p)
	dec.p = nil
	return nil
}
<commit_msg>(minor) docs and formatting<commit_after>// Copyright © 2015 Hraban Luyat <hraban@0brg.net>
//
// License for use of this code is detailed in the LICENSE file

package opus

import (
	"fmt"
	"unsafe"
)

/*
// Statically link libopus. Requires a libopus.a in every directory you use this
// as a dependency in. Not great, but CGO doesn't offer anything better, right
// now. Unless you require everyone who USES this package to have libopus
// installed system-wide, which is more of a chore because it's so new. Everyone
// will end up having to build it from source anyway, might as well just dump
// the pre-built lib in here. At least it will be up to the package maintainer,
// not the user.
//
// If I missed something, and somebody knows a better way: please let me know.
#cgo LDFLAGS: libopus.a -lm
#cgo CFLAGS: -std=c99 -Wall -Werror -pedantic -Ilibopusbuild/include
#include <opus/opus.h>
*/
import "C"

type Application int

// These constants should be taken from the library instead of defined here.
// Unfortunatly, they are #defines, and CGO can't import those.
const (
	// Optimize encoding for VOIP
	APPLICATION_VOIP Application = 2048
	// Optimize encoding for non-voice signals like music
	APPLICATION_AUDIO Application = 2049
	// Optimize encoding for low latency applications
	APPLICATION_RESTRICTED_LOWDELAY Application = 2051
)

const (
	xMAX_BITRATE       = 48000
	xMAX_FRAME_SIZE_MS = 60
	xMAX_FRAME_SIZE    = xMAX_BITRATE * xMAX_FRAME_SIZE_MS / 1000
)

func Version() string {
	return C.GoString(C.opus_get_version_string())
}

type Encoder struct {
	p *C.struct_OpusEncoder
}

func opuserr(code int) error {
	return fmt.Errorf("opus: %s", C.GoString(C.opus_strerror(C.int(code))))
}

func NewEncoder(sample_rate int, channels int, application Application) (*Encoder, error) {
	var errno int
	p := C.opus_encoder_create(C.opus_int32(sample_rate), C.int(channels), C.int(application), (*C.int)(unsafe.Pointer(&errno)))
	if errno != 0 {
		return nil, opuserr(errno)
	}
	return &Encoder{p: p}, nil
}

func (enc *Encoder) EncodeFloat32(pcm []float32) ([]byte, error) {
	if pcm == nil || len(pcm) == 0 {
		return nil, fmt.Errorf("opus: no data supplied")
	}
	// I never know how much to allocate
	data := make([]byte, 10000)
	n := int(C.opus_encode_float(
		enc.p,
		(*C.float)(&pcm[0]),
		C.int(len(pcm)),
		(*C.uchar)(&data[0]),
		C.opus_int32(cap(data))))
	if n < 0 {
		return nil, opuserr(n)
	}
	return data[:n], nil
}

// Returns an error if the encoder was already closed
func (enc *Encoder) Close() error {
	if enc.p == nil {
		return fmt.Errorf("opus: encoder already closed")
	}
	C.opus_encoder_destroy(enc.p)
	enc.p = nil
	return nil
}

type Decoder struct {
	p           *C.struct_OpusDecoder
	sample_rate int
}

func NewDecoder(sample_rate int, channels int) (*Decoder, error) {
	var errno int
	p := C.opus_decoder_create(C.opus_int32(sample_rate), C.int(channels), (*C.int)(unsafe.Pointer(&errno)))
	if errno != 0 {
		return nil, opuserr(errno)
	}
	dec := &Decoder{
		p:           p,
		sample_rate: sample_rate,
	}
	return dec, nil
}

func (dec *Decoder) DecodeFloat32(data []byte) ([]float32, error) {
	if data == nil || len(data) == 0 {
		return nil, fmt.Errorf("opus: no data supplied")
	}
	// I don't know how big this frame will be, but this is the limit
	pcm := make([]float32, xMAX_FRAME_SIZE_MS*dec.sample_rate/1000)
	n := int(C.opus_decode_float(
		dec.p,
		(*C.uchar)(&data[0]),
		C.opus_int32(len(data)),
		(*C.float)(&pcm[0]),
		C.int(cap(pcm)),
		0))
	if n < 0 {
		return nil, opuserr(n)
	}
	return pcm[:n], nil
}

// Returns an error if the encoder was already closed
func (dec *Decoder) Close() error {
	if dec.p == nil {
		return fmt.Errorf("opus: decoder already closed")
	}
	C.opus_decoder_destroy(dec.p)
	dec.p = nil
	return nil
}
<|endoftext|>