<commit_before>// +build windows

package gomounts

/*
#include <string.h>
#include <stdlib.h>
// Dev stub
int GetLogicalDrives(void)
{
	return 13; // A, C, D
}
// Dev stub
int GetVolumeInformation(
char* lpRootPathName,
char* lpVolumeNameBuffer,
int nVolumeNameSize,
int* lpVolumeSerialNumber,
int* lpMaximumComponentLength,
int* lpFileSystemFlags,
char* lpFileSystemNameBuffer,
int nFileSystemNameSize
)
{
	strncpy(lpFileSystemNameBuffer, "NTFS", nFileSystemNameSize);
	return 1; // Success
}
*/
import "C"

import (
	"unsafe"
)

// Windows implementation
func getMountedVolumes() ([]Volume, error) {
	result := make([]Volume, 0)
	var buf [256]C.char

	drives := uint32(C.GetLogicalDrives())

	for i := uint32(0); i < 26; i++ {
		if (1<<i)&drives != 0 {
			letter := 'A' + i
			rootPath := string(letter) + `:\`
			fsType := func() string {
				cRootPath := C.CString(rootPath)
				defer C.free(unsafe.Pointer(cRootPath))
				if C.GetVolumeInformation(cRootPath, nil, 0, nil, nil, nil, &buf[0], C.int(len(buf))) != 0 {
					return C.GoString(&buf[0])
				}
				return "Unknown"
			}()
			result = append(result, Volume{rootPath, fsType})
		}
	}

	return result, nil
}
<commit_msg>Finish win32 implementation<commit_after>// +build windows

package gomounts

/*
#include <string.h>
#include <stdlib.h>
#include <Windows.h>
*/
import "C"

import (
	"unsafe"
)

// Windows implementation
func getMountedVolumes() ([]Volume, error) {
	result := make([]Volume, 0)
	var buf [256]C.char

	drives := uint32(C.GetLogicalDrives())

	for i := uint32(0); i < 26; i++ {
		if (1<<i)&drives != 0 {
			letter := 'A' + i
			rootPath := string(letter) + `:\`
			fsType := func() string {
				cRootPath := C.CString(rootPath)
				defer C.free(unsafe.Pointer(cRootPath))
				if C.GetVolumeInformation(C.LPCSTR(unsafe.Pointer(cRootPath)), nil, 0, nil, nil, nil, C.LPCSTR(unsafe.Pointer(&buf[0])), C.DWORD(len(buf))) != 0 {
					return C.GoString(&buf[0])
				}
				return "Unknown"
			}()
			result = append(result, Volume{rootPath, fsType})
		}
	}

	return result, nil
}
<|endoftext|>


<commit_before>package agent

import (
	"log"
	"os"
	"syscall"

	"github.com/joshlf13/gopack"
)

const (
	BIT_ONE     uint16 = 1
	BIT_TWO     uint16 = 2
	BIT_FOUR    uint16 = 4
	BIT_EIGHT   uint16 = 8
	BIT_SIXTEEN uint16 = 16
)

// Gestic
// http://ww1.microchip.com/downloads/en/DeviceDoc/40001718B.pdf
// Page 36

// Gestic device path
const GESTIC_DEV = "/dev/gestic"

// Flag which indicates if the payload contains data
const ID_SENSOR_DATA_OUTPUT = 0x91

type Reader struct {
}

type Header struct {
	Length, Flags, Seq, Id uint8
}

type DateHeader struct {
	DataMask              uint16
	TimeStamp, SystemInfo uint8
}

type DSPInfo struct {
	Info uint16
}

type GestureInfo struct {
	Gesture uint32
}

type TouchInfo struct {
	Touch uint32
}

type AirWheelInfo struct {
	AirWheel uint8
	Crap     uint8
}

type CoordinateInfo struct {
	X uint8
	Y uint8
	Z uint8
}

var Gestures = []string{
	"No gesture",
	"Garbage model",
	"Flick West to East",
	"Flick East to West",
	"Flick South to North",
	"Flick North to South",
	"Circle clockwise",
	"Circle counter-clockwise",
}

func (gi *GestureInfo) GetGestureName() string {
	gest := gi.Gesture & 0xff
	return Gestures[int(gest)]
}

func (r *Reader) Start() {
	log.Printf("Opening %s", GESTIC_DEV)

	fd, err := syscall.Open(GESTIC_DEV, os.O_RDWR, 0666)

	rfds := &syscall.FdSet{}
	timeout := &syscall.Timeval{1, 1}

	if err != nil {
		log.Fatalf("Can't open %s - %s", GESTIC_DEV, err)
	}

	log.Printf("Reading %s", GESTIC_DEV)

	//	ping_at := time.Now()

	for {

		FD_ZERO(rfds)
		FD_SET(rfds, fd)

		_, err := syscall.Select(fd+1, rfds, nil, nil, timeout)

		if err != nil {
			log.Fatalf("Can't read %s - %s", GESTIC_DEV, err)
		}
		//  One of the fds changed
		if FD_ISSET(rfds, int(fd)) {

			buf := make([]byte, 255)
			n, err := syscall.Read(fd, buf)

			header := &Header{}

			gopack.Unpack(buf[:4], header)

			log.Printf("header %+v", header)

			dataHeader := &DateHeader{}

			gopack.Unpack(buf[4:8], dataHeader)

			log.Printf("dataHeader %+v", dataHeader)

			// var for offset
			offset := 8

			// grab the DSPIfo
			if dataHeader.DataMask&BIT_ONE == BIT_ONE {

				dspinfo := &DSPInfo{}

				gopack.Unpack(buf[offset:offset+2], dspinfo)

				log.Printf("dspinfo %+v", dspinfo)

				offset += 2
			}

			// grab the GestureInfo
			if dataHeader.DataMask&BIT_TWO == BIT_TWO {

				gestureInfo := &GestureInfo{}

				gopack.Unpack(buf[offset:offset+4], gestureInfo)

				log.Printf("gesture %d", gestureInfo.Gesture&0xff)

				offset += 4

			}

			// grab the TouchInfo
			if dataHeader.DataMask&BIT_FOUR == BIT_FOUR {

				touchInfo := &TouchInfo{}

				gopack.Unpack(buf[offset:offset+4], touchInfo)

				log.Printf("touchInfo %v", touchInfo)

				offset += 4
			}

			// grab the AirWheelInfo
			if dataHeader.DataMask&BIT_EIGHT == BIT_EIGHT {

				airWheelInfo := &AirWheelInfo{}

				gopack.Unpack(buf[offset:offset+2], airWheelInfo)

				log.Printf("airWheelInfo %v", airWheelInfo)

				offset += 2
			}

			// grab the CoordinateInfo
			if dataHeader.DataMask&BIT_SIXTEEN == BIT_SIXTEEN {

				coordinateInfo := &CoordinateInfo{}

				gopack.Unpack(buf[offset:offset+6], coordinateInfo)

				log.Printf("coordinateInfo %v", coordinateInfo)

				offset += 6
			}

			if err != nil {
				log.Fatalf("Can't read %s - %s", GESTIC_DEV, err)
			}

			if n > 0 {
				log.Printf("read %x", buf[:n])
			}
		}

	}

}

func FD_SET(p *syscall.FdSet, i int) {
	p.Bits[i/64] |= 1 << uint(i) % 64
}

func FD_ISSET(p *syscall.FdSet, i int) bool {
	return (p.Bits[i/64] & (1 << uint(i) % 64)) != 0
}

func FD_ZERO(p *syscall.FdSet) {
	for i := range p.Bits {
		p.Bits[i] = 0
	}
}
<commit_msg>Moving stuff around and some renaming.<commit_after>package agent

import (
	"log"
	"os"
	"syscall"

	"github.com/joshlf13/gopack"
)

const (
	DSPIfoFlag         uint16 = 1
	GestureInfoFlag    uint16 = 2
	TouchInfoFlag      uint16 = 4
	AirWheelInfoFlag   uint16 = 8
	CoordinateInfoFlag uint16 = 16
)

// Gestic
// http://ww1.microchip.com/downloads/en/DeviceDoc/40001718B.pdf
// Page 36

// Gestic device path
const GesticDevicePath = "/dev/gestic"

// Flag which indicates if the payload contains data
const SensorDataPresentFlag = 0x91

const (
	MaxEpollEvents     = 32
	MaxMessageSize     = 255
	IdSensorDataOutput = 0x91
)

type Reader struct {
}

type GestureCoordinates struct {
	X, Y, Z int
}

// decoded gesture
type Gesture struct {
	Gesture     *string
	Touch       *string
	AirWheel    *int
	Coordinates *GestureCoordinates
}

type EventHeader struct {
	Length, Flags, Seq, Id uint8
}

type DataHeader struct {
	DataMask              uint16
	TimeStamp, SystemInfo uint8
}

type GestureInfo struct {
	Gesture uint32
}

type TouchInfo struct {
	Touch uint32
}

type AirWheelInfo struct {
	AirWheel uint8
	Crap     uint8
}

type CoordinateInfo struct {
	X uint8
	Y uint8
	Z uint8
}

var Gestures = []string{
	"No gesture",
	"Garbage model",
	"Flick West to East",
	"Flick East to West",
	"Flick South to North",
	"Flick North to South",
	"Circle clockwise",
	"Circle counter-clockwise",
}

var ClickLocations = []{

}

func (gi *GestureInfo) GetGestureName() string {
	return Gestures[int(gi.Gesture)]
}

func (r *Reader) Start() {
	log.Printf("Opening %s", GesticDevicePath)

	fd, err := syscall.Open(GesticDevicePath, os.O_RDWR, 0666)

	rfds := &syscall.FdSet{}
	timeout := &syscall.Timeval{1, 1}

	if err != nil {
		log.Fatalf("Can't open %s - %s", GesticDevicePath, err)
	}

	log.Printf("Reading %s", GesticDevicePath)

	for {

		FD_ZERO(rfds)
		FD_SET(rfds, fd)

		_, err := syscall.Select(fd+1, rfds, nil, nil, timeout)

		if err != nil {
			log.Fatalf("Can't read %s - %s", GesticDevicePath, err)
		}
		//  One of the fds changed
		if FD_ISSET(rfds, int(fd)) {

			buf := make([]byte, 255)
			n, err := syscall.Read(fd, buf)

			BuildGestureEvent(buf)
		}

	}

}

func BuildGestureEvent(buf []byte) Gesture {

	header := &Header{}

	gopack.Unpack(buf[:4], header)

	//log.Printf("header %+v", header)

	dataHeader := &DateHeader{}

	gopack.Unpack(buf[4:8], dataHeader)

	//log.Printf("dataHeader %+v", dataHeader)

	// var for offset
	offset := 8

	// grab the DSPIfo
	if dataHeader.DataMask&DSPIfoFlag == DSPIfoFlag {
		offset += 2
	}

	// grab the GestureInfo
	if dataHeader.DataMask&GestureInfoFlag == GestureInfoFlag {

		gestureInfo := &GestureInfo{}

		gopack.Unpack(buf[offset:offset+4], gestureInfo)

		//log.Printf("gesture %d", gestureInfo.Gesture&0xff)

		offset += 4

	}

	// grab the TouchInfo
	if dataHeader.DataMask&TouchInfoFlag == TouchInfoFlag {

		touchInfo := &TouchInfo{}

		gopack.Unpack(buf[offset:offset+4], touchInfo)

		//log.Printf("touchInfo %v", touchInfo)

		offset += 4
	}

	// grab the AirWheelInfo
	if dataHeader.DataMask&AirWheelInfoFlag == AirWheelInfoFlag {

		airWheelInfo := &AirWheelInfo{}

		gopack.Unpack(buf[offset:offset+2], airWheelInfo)

		log.Printf("airWheelInfo %v", airWheelInfo)

		offset += 2
	}

	// grab the CoordinateInfo
	if dataHeader.DataMask&CoordinateInfoFlag == CoordinateInfoFlag {

		coordinateInfo := &CoordinateInfo{}

		gopack.Unpack(buf[offset:offset+6], coordinateInfo)

		//log.Printf("coordinateInfo %v", coordinateInfo)

		offset += 6
	}

	if err != nil {
		log.Fatalf("Can't read %s - %s", GesticDevicePath, err)
	}

	if n > 0 {
		log.Printf("read %x", buf[:n])
	}
}

func FD_SET(p *syscall.FdSet, i int) {
	p.Bits[i/64] |= 1 << uint(i) % 64
}

func FD_ISSET(p *syscall.FdSet, i int) bool {
	return (p.Bits[i/64] & (1 << uint(i) % 64)) != 0
}

func FD_ZERO(p *syscall.FdSet) {
	for i := range p.Bits {
		p.Bits[i] = 0
	}
}
<|endoftext|>


<commit_before>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/vault/meta"
)

// TokenRevokeCommand is a Command that mounts a new mount.
type TokenRevokeCommand struct {
	meta.Meta
}

func (c *TokenRevokeCommand) Run(args []string) int {
	var mode string
	var accessor bool
	flags := c.Meta.FlagSet("token-revoke", meta.FlagSetDefault)
	flags.BoolVar(&accessor, "accessor", false, "")
	flags.StringVar(&mode, "mode", "", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	args = flags.Args()
	if len(args) != 1 {
		flags.Usage()
		c.Ui.Error(fmt.Sprintf(
			"\ntoken-revoke expects one argument"))
		return 1
	}

	token := args[0]

	client, err := c.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing client: %s", err))
		return 2
	}

	var fn func(string) error
	// Handle all 6 possible combinations
	switch {
	case !accessor && mode == "":
		fn = client.Auth().Token().RevokeTree
	case !accessor && mode == "orphan":
		fn = client.Auth().Token().RevokeOrphan
	case !accessor && mode == "path":
		fn = client.Sys().RevokePrefix
	case accessor && mode == "":
		fn = client.Auth().Token().RevokeAccessor
	case accessor && mode == "orphan":
		c.Ui.Error("token-revoke cannot be run for 'orphan' mode when 'accessor' flag is set")
		return 1
	case accessor && mode == "path":
		c.Ui.Error("token-revoke cannot be run for 'path' mode when 'accessor' flag is set")
		return 1
	}

	if err := fn(token); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error revoking token: %s", err))
		return 2
	}

	c.Ui.Output("Success! Token revoked if it existed.")
	return 0
}

func (c *TokenRevokeCommand) Synopsis() string {
	return "Revoke one or more auth tokens"
}

func (c *TokenRevokeCommand) Help() string {
	helpText := `
Usage: vault token-revoke [options] [token|accessor]

  Revoke one or more auth tokens.

  This command revokes auth tokens. Use the "revoke" command for
  revoking secrets.

  Depending on the flags used, auth tokens can be revoked in multiple ways
  depending on the "-mode" flag:

    * Without any value, the token specified and all of its children
      will be revoked.

    * With the "orphan" value, only the specific token will be revoked.
      All of its children will be orphaned.

    * With the "path" value, tokens created from the given auth path
      prefix will be deleted, along with all their children. In this case
      the "token" arg above is actually a "path". This mode does *not*
      work with token values or parts of token values.

  Token can be revoked using the token accessor. This can be done by
  setting the '-accessor' flag. Note that when '-accessor' flag is set,
  '-mode' should not be set for 'orphan' or 'path'. This is because,
  a token accessor always revokes the token along with its child tokens.

General Options:
` + meta.GeneralOptionsUsage() + `
Token Options:

  -accessor               A boolean flag, if set, treats the argument as an accessor of the token.
                          Note that accessor can also be used for looking up the token properties
                          via '/auth/token/lookup-accessor/<accessor>' endpoint.
                          Accessor is used when there is no access to token ID.

  -mode=value             The type of revocation to do. See the documentation
                          above for more information.

`
	return strings.TrimSpace(helpText)
}
<commit_msg>Add -self flag to token-revoke (#2596)<commit_after>package command

import (
	"fmt"
	"strings"

	"github.com/hashicorp/vault/meta"
)

// TokenRevokeCommand is a Command that mounts a new mount.
type TokenRevokeCommand struct {
	meta.Meta
}

func (c *TokenRevokeCommand) Run(args []string) int {
	var mode string
	var accessor bool
	var self bool
	var token string
	flags := c.Meta.FlagSet("token-revoke", meta.FlagSetDefault)
	flags.BoolVar(&accessor, "accessor", false, "")
	flags.BoolVar(&self, "self", false, "")
	flags.StringVar(&mode, "mode", "", "")
	flags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := flags.Parse(args); err != nil {
		return 1
	}

	args = flags.Args()
	switch {
	case len(args) == 1 && !self:
		token = args[0]
	case len(args) != 0 && self:
		flags.Usage()
		c.Ui.Error(fmt.Sprintf(
			"\ntoken-revoke expects no arguments when revoking self"))
		return 1
	case len(args) != 1 && !self:
		flags.Usage()
		c.Ui.Error(fmt.Sprintf(
			"\ntoken-revoke expects one argument or the 'self' flag"))
		return 1
	}

	client, err := c.Client()
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing client: %s", err))
		return 2
	}

	var fn func(string) error
	// Handle all 6 possible combinations
	switch {
	case !accessor && self && mode == "":
		fn = client.Auth().Token().RevokeSelf
	case !accessor && !self && mode == "":
		fn = client.Auth().Token().RevokeTree
	case !accessor && !self && mode == "orphan":
		fn = client.Auth().Token().RevokeOrphan
	case !accessor && !self && mode == "path":
		fn = client.Sys().RevokePrefix
	case accessor && !self && mode == "":
		fn = client.Auth().Token().RevokeAccessor
	case accessor && self:
		c.Ui.Error("token-revoke cannot be run on self when 'accessor' flag is set")
		return 1
	case self && mode != "":
		c.Ui.Error("token-revoke cannot be run on self when 'mode' flag is set")
		return 1
	case accessor && mode == "orphan":
		c.Ui.Error("token-revoke cannot be run for 'orphan' mode when 'accessor' flag is set")
		return 1
	case accessor && mode == "path":
		c.Ui.Error("token-revoke cannot be run for 'path' mode when 'accessor' flag is set")
		return 1
	}

	if err := fn(token); err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error revoking token: %s", err))
		return 2
	}

	c.Ui.Output("Success! Token revoked if it existed.")
	return 0
}

func (c *TokenRevokeCommand) Synopsis() string {
	return "Revoke one or more auth tokens"
}

func (c *TokenRevokeCommand) Help() string {
	helpText := `
Usage: vault token-revoke [options] [token|accessor]

  Revoke one or more auth tokens.

  This command revokes auth tokens. Use the "revoke" command for
  revoking secrets.

  Depending on the flags used, auth tokens can be revoked in multiple ways
  depending on the "-mode" flag:

    * Without any value, the token specified and all of its children
      will be revoked.

    * With the "orphan" value, only the specific token will be revoked.
      All of its children will be orphaned.

    * With the "path" value, tokens created from the given auth path
      prefix will be deleted, along with all their children. In this case
      the "token" arg above is actually a "path". This mode does *not*
      work with token values or parts of token values.

  Token can be revoked using the token accessor. This can be done by
  setting the '-accessor' flag. Note that when '-accessor' flag is set,
  '-mode' should not be set for 'orphan' or 'path'. This is because,
  a token accessor always revokes the token along with its child tokens.

General Options:
` + meta.GeneralOptionsUsage() + `
Token Options:

  -accessor               A boolean flag, if set, treats the argument as an accessor of the token.
                          Note that accessor can also be used for looking up the token properties
                          via '/auth/token/lookup-accessor/<accessor>' endpoint.
                          Accessor is used when there is no access to token ID.

  -self                   A boolean flag, if set, the operation is performed on the currently
                          authenticated token i.e. lookup-self.

  -mode=value             The type of revocation to do. See the documentation
                          above for more information.

`
	return strings.TrimSpace(helpText)
}
<|endoftext|>


<commit_before>// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
//
// Example Usage
//
// The following is a complete example using assert in a standard test function:
//    import (
//      "testing"
//      "github.com/stretchr/testify/assert"
//    )
//
//    func TestSomething(t *testing.T) {
//
//      var a string = "Hello"
//      var b string = "Hello"
//
//      assert.Equal(t, a, b, "The two words should be the same.")
//
//    }
//
// if you assert many times, use the below:
//
//    import (
//      "testing"
//      "github.com/stretchr/testify/assert"
//    )
//
//    func TestSomething(t *testing.T) {
//      assert := assert.New(t)
//
//      var a string = "Hello"
//      var b string = "Hello"
//
//      assert.Equal(a, b, "The two words should be the same.")
//    }
//
// Assertions
//
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
// testing framework. This allows the assertion funcs to write the failings and other details to
// the correct place.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
//    assert.Equal(t, expected, actual [, message [, format-args]])
//
//    assert.EqualValues(t, expected, actual [, message [, format-args]])
//
//    assert.NotEqual(t, notExpected, actual [, message [, format-args]])
//
//    assert.True(t, actualBool [, message [, format-args]])
//
//    assert.False(t, actualBool [, message [, format-args]])
//
//    assert.Nil(t, actualObject [, message [, format-args]])
//
//    assert.NotNil(t, actualObject [, message [, format-args]])
//
//    assert.Empty(t, actualObject [, message [, format-args]])
//
//    assert.NotEmpty(t, actualObject [, message [, format-args]])
//
//    assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
//
//    assert.Error(t, errorObject [, message [, format-args]])
//
//    assert.NoError(t, errorObject [, message [, format-args]])
//
//    assert.EqualError(t, theError, errString [, message [, format-args]])
//
//    assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
//    assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
//    assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.Panics(t, func(){
//
//	    // call code that should panic
//
//    } [, message [, format-args]])
//
//    assert.NotPanics(t, func(){
//
//	    // call code that should not panic
//
//    } [, message [, format-args]])
//
//    assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
//    assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
//    assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
//
// assert package contains Assertions object. it has assertion methods.
//
// Here is an overview of the assert functions:
//    assert.Equal(expected, actual [, message [, format-args]])
//
//    assert.EqualValues(expected, actual [, message [, format-args]])
//
//    assert.NotEqual(notExpected, actual [, message [, format-args]])
//
//    assert.True(actualBool [, message [, format-args]])
//
//    assert.False(actualBool [, message [, format-args]])
//
//    assert.Nil(actualObject [, message [, format-args]])
//
//    assert.NotNil(actualObject [, message [, format-args]])
//
//    assert.Empty(actualObject [, message [, format-args]])
//
//    assert.NotEmpty(actualObject [, message [, format-args]])
//
//    assert.Len(actualObject, expectedLength, [, message [, format-args]])
//
//    assert.Error(errorObject [, message [, format-args]])
//
//    assert.NoError(errorObject [, message [, format-args]])
//
//    assert.EqualError(theError, errString [, message [, format-args]])
//
//    assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
//    assert.IsType(expectedObject, actualObject [, message [, format-args]])
//
//    assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.Panics(func(){
//
//	    // call code that should panic
//
//    } [, message [, format-args]])
//
//    assert.NotPanics(func(){
//
//	    // call code that should not panic
//
//    } [, message [, format-args]])
//
//    assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
//
//    assert.InDelta(numA, numB, delta, [, message [, format-args]])
//
//    assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
package assert
<commit_msg>Fix tiny typo<commit_after>// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
//
// Example Usage
//
// The following is a complete example using assert in a standard test function:
//    import (
//      "testing"
//      "github.com/stretchr/testify/assert"
//    )
//
//    func TestSomething(t *testing.T) {
//
//      var a string = "Hello"
//      var b string = "Hello"
//
//      assert.Equal(t, a, b, "The two words should be the same.")
//
//    }
//
// if you assert many times, use the format below:
//
//    import (
//      "testing"
//      "github.com/stretchr/testify/assert"
//    )
//
//    func TestSomething(t *testing.T) {
//      assert := assert.New(t)
//
//      var a string = "Hello"
//      var b string = "Hello"
//
//      assert.Equal(a, b, "The two words should be the same.")
//    }
//
// Assertions
//
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
// testing framework. This allows the assertion funcs to write the failings and other details to
// the correct place.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
//
// Here is an overview of the assert functions:
//
//    assert.Equal(t, expected, actual [, message [, format-args]])
//
//    assert.EqualValues(t, expected, actual [, message [, format-args]])
//
//    assert.NotEqual(t, notExpected, actual [, message [, format-args]])
//
//    assert.True(t, actualBool [, message [, format-args]])
//
//    assert.False(t, actualBool [, message [, format-args]])
//
//    assert.Nil(t, actualObject [, message [, format-args]])
//
//    assert.NotNil(t, actualObject [, message [, format-args]])
//
//    assert.Empty(t, actualObject [, message [, format-args]])
//
//    assert.NotEmpty(t, actualObject [, message [, format-args]])
//
//    assert.Len(t, actualObject, expectedLength, [, message [, format-args]])
//
//    assert.Error(t, errorObject [, message [, format-args]])
//
//    assert.NoError(t, errorObject [, message [, format-args]])
//
//    assert.EqualError(t, theError, errString [, message [, format-args]])
//
//    assert.Implements(t, (*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
//    assert.IsType(t, expectedObject, actualObject [, message [, format-args]])
//
//    assert.Contains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.NotContains(t, stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.Panics(t, func(){
//
//	    // call code that should panic
//
//    } [, message [, format-args]])
//
//    assert.NotPanics(t, func(){
//
//	    // call code that should not panic
//
//    } [, message [, format-args]])
//
//    assert.WithinDuration(t, timeA, timeB, deltaTime, [, message [, format-args]])
//
//    assert.InDelta(t, numA, numB, delta, [, message [, format-args]])
//
//    assert.InEpsilon(t, numA, numB, epsilon, [, message [, format-args]])
//
// assert package contains Assertions object. it has assertion methods.
//
// Here is an overview of the assert functions:
//    assert.Equal(expected, actual [, message [, format-args]])
//
//    assert.EqualValues(expected, actual [, message [, format-args]])
//
//    assert.NotEqual(notExpected, actual [, message [, format-args]])
//
//    assert.True(actualBool [, message [, format-args]])
//
//    assert.False(actualBool [, message [, format-args]])
//
//    assert.Nil(actualObject [, message [, format-args]])
//
//    assert.NotNil(actualObject [, message [, format-args]])
//
//    assert.Empty(actualObject [, message [, format-args]])
//
//    assert.NotEmpty(actualObject [, message [, format-args]])
//
//    assert.Len(actualObject, expectedLength, [, message [, format-args]])
//
//    assert.Error(errorObject [, message [, format-args]])
//
//    assert.NoError(errorObject [, message [, format-args]])
//
//    assert.EqualError(theError, errString [, message [, format-args]])
//
//    assert.Implements((*MyInterface)(nil), new(MyObject) [,message [, format-args]])
//
//    assert.IsType(expectedObject, actualObject [, message [, format-args]])
//
//    assert.Contains(stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.NotContains(stringOrSlice, substringOrElement [, message [, format-args]])
//
//    assert.Panics(func(){
//
//	    // call code that should panic
//
//    } [, message [, format-args]])
//
//    assert.NotPanics(func(){
//
//	    // call code that should not panic
//
//    } [, message [, format-args]])
//
//    assert.WithinDuration(timeA, timeB, deltaTime, [, message [, format-args]])
//
//    assert.InDelta(numA, numB, delta, [, message [, format-args]])
//
//    assert.InEpsilon(numA, numB, epsilon, [, message [, format-args]])
package assert
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ezcx

import (
	"context"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var (
	ServerDefaultSignals []os.Signal = []os.Signal{
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGHUP,
	}
)

//Handler interface: Defines the contract.
type Handler interface {
	http.Handler
	Handle(res *WebhookResponse, req *WebhookRequest) error
}

// Functional Adapter: HandlerFunc is an adapter.
// HandlerFunc satisfies the Handler interface
type HandlerFunc func(*WebhookResponse, *WebhookRequest) error

// Seems  redundant; may serve a purpose, though, for structural handlers.
// (ie Need to implement for functional handler to satisfy Handle which would
// require implementation for structural handlers.)
func (h HandlerFunc) Handle(res *WebhookResponse, req *WebhookRequest) error {
	return h(res, req)
}

// yaquino@2022-10-07: http.Request's context is flowd down to the WebhookRequest
// via WebhookRequestFromRequest (requests.go)
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	req, err := WebhookRequestFromRequest(r)
	if err != nil {
		log.Println(err)
		return
	}
	req.ctx = r.Context
	res := req.InitializeResponse()
	err = h.Handle(res, req)
	if err != nil {
		log.Println(err)
		return
	}
	res.WriteResponse(w)
}

type Server struct {
	signals []os.Signal
	signal  chan os.Signal
	errs    chan error
	server  *http.Server
	mux     *http.ServeMux
	lg      *log.Logger
}

func NewServer(ctx context.Context, addr string, lg *log.Logger, signals ...os.Signal) *Server {
	return new(Server).Init(ctx, addr, lg, signals...)
}

func (s *Server) Init(ctx context.Context, addr string, lg *log.Logger, signals ...os.Signal) *Server {
	if len(signals) == 0 {
		s.signals = ServerDefaultSignals
	} else {
		// rethink this later on.  We need to make sure there at least
		// the right group of signals!
		s.signals = signals
	}
	s.signal = make(chan os.Signal, 1)
	signal.Notify(s.signal, s.signals...)

	if lg == nil {
		lg = log.Default()
	}
	s.lg = lg

	s.errs = make(chan error)
	s.mux = http.NewServeMux()
	s.server = &http.Server{
		Addr:        addr,
		Handler:     s.mux,
		BaseContext: func(l net.Listener) context.Context { return ctx },
	}
	return s
}

func (s *Server) SetHandler(h http.Handler) {
	s.server.Handler = h
	if s.isMux(h) {
		s.mux = h.(*http.ServeMux)
	} else {
		s.mux = nil
	}
}

func (s *Server) ServeMux() *http.ServeMux {
	return s.mux
}

func (s *Server) isMux(h http.Handler) bool {
	_, ok := h.(*http.ServeMux)
	return ok
}

func (s *Server) HandleCx(pattern string, handler HandlerFunc) {
	s.mux.Handle(pattern, handler)
}

// yaquino@2022-09-21: I have concerns that checking the parent context will not work as desired.
func (s *Server) ListenAndServe(ctx context.Context) {
	defer func() {
		close(s.errs)
		close(s.signal)
	}()
	// Run ListenAndServe on a separate goroutine.
	s.lg.Printf("EZCX server listening and serving on %s\n", s.server.Addr)
	go func() {
		err := s.server.ListenAndServe()
		if err != nil {
			s.lg.Println(err)
			s.errs <- err
			close(s.errs)
		}
	}()

	for {
		select {
		// If the context is done, we need to return.
		case <-ctx.Done():
			s.lg.Println("EZCX server context is done")
			err := ctx.Err()
			if err != nil {
				s.lg.Print("EZCX server context error...")
				s.lg.Println(err)
			}
			return
		// If there's a non-nil error, we need to return
		case err := <-s.errs:
			if err != nil {
				s.lg.Print("EZCX server non-nil error...")
				s.lg.Println(err)
				return
			}
		case sig := <-s.signal:
			s.lg.Printf("EZCX server signal %s received...", sig)
			switch sig {
			case syscall.SIGHUP:
				s.lg.Println("EZCX reconfigure", sig)
				err := s.Reconfigure()
				if err != nil {
					s.errs <- err
				}
			default:
				s.lg.Printf("EZCX graceful shutdown initiated...")
				err := s.Shutdown(ctx)
				if err != nil {
					s.lg.Println(err)
				}
				s.lg.Println("EZCX shutdown SUCCESS")
				return
			}
		}
	}
}

// Omitted for now.
func (s *Server) Reconfigure() error {
	return nil
}

func (s *Server) Shutdown(ctx context.Context) error {
	timeout, cancel := context.WithTimeout(ctx, time.Second*5)
	defer cancel()
	err := s.server.Shutdown(timeout)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>better error handling<commit_after>// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ezcx

import (
	"context"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

var (
	ServerDefaultSignals []os.Signal = []os.Signal{
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGHUP,
	}
)

//Handler interface: Defines the contract.
type Handler interface {
	http.Handler
	Handle(res *WebhookResponse, req *WebhookRequest) error
}

// Functional Adapter: HandlerFunc is an adapter.
// HandlerFunc satisfies the Handler interface
type HandlerFunc func(*WebhookResponse, *WebhookRequest) error

// Seems  redundant; may serve a purpose, though, for structural handlers.
// (ie Need to implement for functional handler to satisfy Handle which would
// require implementation for structural handlers.)
func (h HandlerFunc) Handle(res *WebhookResponse, req *WebhookRequest) error {
	return h(res, req)
}

// yaquino@2022-10-07: http.Request's context is flowd down to the WebhookRequest
// via WebhookRequestFromRequest (requests.go)
func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	req, err := WebhookRequestFromRequest(r)
	if err != nil {
		log.Println("Error during WebhookRequestFromRequest")
		log.Println(err)
		return
	}
	req.ctx = r.Context // flowing down the requests's Context.
	res := req.InitializeResponse()
	err = h(res, req)
	if err != nil {
		log.Println("Error during HandlerFunc execution")
		log.Println(err)
		return
	}
	err = res.WriteResponse(w)
	if err != nil {
		log.Println("Error during WebhookResponse.WriteResponse")
		return
	}
}

type Server struct {
	signals []os.Signal
	signal  chan os.Signal
	errs    chan error
	server  *http.Server
	mux     *http.ServeMux
	lg      *log.Logger
}

func NewServer(ctx context.Context, addr string, lg *log.Logger, signals ...os.Signal) *Server {
	return new(Server).Init(ctx, addr, lg, signals...)
}

func (s *Server) Init(ctx context.Context, addr string, lg *log.Logger, signals ...os.Signal) *Server {
	if len(signals) == 0 {
		s.signals = ServerDefaultSignals
	} else {
		// rethink this later on.  We need to make sure there at least
		// the right group of signals!
		s.signals = signals
	}
	s.signal = make(chan os.Signal, 1)
	signal.Notify(s.signal, s.signals...)

	if lg == nil {
		lg = log.Default()
	}
	s.lg = lg

	s.errs = make(chan error)
	s.mux = http.NewServeMux()
	s.server = &http.Server{
		Addr:        addr,
		Handler:     s.mux,
		BaseContext: func(l net.Listener) context.Context { return ctx },
	}
	return s
}

func (s *Server) SetHandler(h http.Handler) {
	s.server.Handler = h
	if s.isMux(h) {
		s.mux = h.(*http.ServeMux)
	} else {
		s.mux = nil
	}
}

func (s *Server) ServeMux() *http.ServeMux {
	return s.mux
}

func (s *Server) isMux(h http.Handler) bool {
	_, ok := h.(*http.ServeMux)
	return ok
}

func (s *Server) HandleCx(pattern string, handler HandlerFunc) {
	s.mux.Handle(pattern, handler)
}

// yaquino@2022-09-21: I have concerns that checking the parent context will not work as desired.
func (s *Server) ListenAndServe(ctx context.Context) {
	defer func() {
		close(s.errs)
		close(s.signal)
	}()
	// Run ListenAndServe on a separate goroutine.
	s.lg.Printf("EZCX server listening and serving on %s\n", s.server.Addr)
	go func() {
		err := s.server.ListenAndServe()
		if err != nil {
			s.lg.Println(err)
			s.errs <- err
			close(s.errs)
		}
	}()

	for {
		select {
		// If the context is done, we need to return.
		case <-ctx.Done():
			s.lg.Println("EZCX server context is done")
			err := ctx.Err()
			if err != nil {
				s.lg.Print("EZCX server context error...")
				s.lg.Println(err)
			}
			return
		// If there's a non-nil error, we need to return
		case err := <-s.errs:
			if err != nil {
				s.lg.Print("EZCX server non-nil error...")
				s.lg.Println(err)
				return
			}
		case sig := <-s.signal:
			s.lg.Printf("EZCX server signal %s received...", sig)
			switch sig {
			case syscall.SIGHUP:
				s.lg.Println("EZCX reconfigure", sig)
				err := s.Reconfigure()
				if err != nil {
					s.errs <- err
				}
			default:
				s.lg.Printf("EZCX graceful shutdown initiated...")
				err := s.Shutdown(ctx)
				if err != nil {
					s.lg.Println(err)
				}
				s.lg.Println("EZCX shutdown SUCCESS")
				return
			}
		}
	}
}

// Omitted for now.
func (s *Server) Reconfigure() error {
	return nil
}

func (s *Server) Shutdown(ctx context.Context) error {
	timeout, cancel := context.WithTimeout(ctx, time.Second*5)
	defer cancel()
	err := s.server.Shutdown(timeout)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"time"
)

type Server struct {
	http.Server
	config Config
}

type FlushyResponseWriter struct {
	http.ResponseWriter
}

func (writer *FlushyResponseWriter) Write(data []byte) (int, error) {
	defer func() {
		if flusher, ok := writer.ResponseWriter.(http.Flusher); ok {
			flusher.Flush()
		} else {
			log.Fatalf("ResponseWriter is not a flusher")
		}
	}()
	return writer.Write(data)
}

func RunNewServer(c Config, listening chan<- string) error {
	defer func() { listening <- "" }()
	srv := &Server{}
	addr, err := net.ResolveTCPAddr("tcp", c.Addr)
	if err != nil {
		return err
	}
	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return err
	}
	if listening != nil {
		listening <- ln.Addr().String()
	}
	http.Handle("/", http.HandlerFunc(func (writer http.ResponseWriter, req *http.Request) {
		var fwriter io.Writer = &FlushyResponseWriter{writer}
		label := "client#TODO"
		err := NewSink(label, fwriter.(io.Writer), "/path/TODO", c).Run()
		log.Printf("Handler: %s %s", label, err)
	}))
	return srv.Serve(tcpKeepAliveListener{ln})
}

// Copied from net/http because not exported.
//
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<commit_msg>Serve specified path.<commit_after>package main

import (
	"io"
	"log"
	"net"
	"net/http"
	"time"
)

type Server struct {
	http.Server
	config Config
}

type FlushyResponseWriter struct {
	http.ResponseWriter
}

func (writer *FlushyResponseWriter) Write(data []byte) (int, error) {
	defer func() {
		if flusher, ok := writer.ResponseWriter.(http.Flusher); ok {
			flusher.Flush()
		} else {
			log.Fatalf("ResponseWriter is not a flusher")
		}
	}()
	return writer.Write(data)
}

func RunNewServer(c Config, listening chan<- string) error {
	defer func() { listening <- "" }()
	srv := &Server{}
	addr, err := net.ResolveTCPAddr("tcp", c.Addr)
	if err != nil {
		return err
	}
	ln, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return err
	}
	if listening != nil {
		listening <- ln.Addr().String()
	}
	http.Handle("/", http.HandlerFunc(func (writer http.ResponseWriter, req *http.Request) {
		fwriter := &FlushyResponseWriter{writer}
		label := "client#TODO"
		err := NewSink(label, fwriter, c.Path, c).Run()
		log.Printf("Handler: %s %s", label, err)
	}))
	return srv.Serve(tcpKeepAliveListener{ln})
}

// Copied from net/http because not exported.
//
type tcpKeepAliveListener struct {
	*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
	tc, err := ln.AcceptTCP()
	if err != nil {
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(3 * time.Minute)
	return tc, nil
}
<|endoftext|>


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

package main

import (
	"bytes"
	"container/list"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/codegangsta/cli"
	"github.com/gogits/gogs/modules/log"

	"github.com/gogits/git"
	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/base"
)

var (
	COMMANDS_READONLY = map[string]int{
		"git-upload-pack":    models.AU_WRITABLE,
		"git upload-pack":    models.AU_WRITABLE,
		"git-upload-archive": models.AU_WRITABLE,
	}

	COMMANDS_WRITE = map[string]int{
		"git-receive-pack": models.AU_READABLE,
		"git receive-pack": models.AU_READABLE,
	}
)

var CmdServ = cli.Command{
	Name:  "serv",
	Usage: "This command just should be called by ssh shell",
	Description: `
gogs serv provide access auth for repositories`,
	Action: runServ,
	Flags:  []cli.Flag{},
}

func init() {
	level := "0"
	os.MkdirAll("log", os.ModePerm)
	log.NewLogger(10000, "file", fmt.Sprintf(`{"level":%s,"filename":"%s"}`, level, "log/serv.log"))
	log.Info("start logging...")
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}

	verb, args := ss[0], ss[1]
	if verb == "git" {
		ss = strings.SplitN(args, " ", 2)
		args = ss[1]
		verb = fmt.Sprintf("%s %s", verb, ss[0])
	}
	return verb, args
}

func In(b string, sl map[string]int) bool {
	_, e := sl[b]
	return e
}

func runServ(k *cli.Context) {
	base.NewConfigContext()
	models.LoadModelsConfig()
	models.NewEngine()

	keys := strings.Split(os.Args[2], "-")
	if len(keys) != 2 {
		fmt.Println("auth file format error")
		return
	}

	keyId, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		fmt.Println("auth file format error")
		return
	}
	user, err := models.GetUserByKeyId(keyId)
	if err != nil {
		fmt.Println("You have no right to access")
		return
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if cmd == "" {
		println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
		return
	}

	verb, args := parseCmd(cmd)
	rRepo := strings.Trim(args, "'")
	rr := strings.SplitN(rRepo, "/", 2)
	if len(rr) != 2 {
		println("Unavilable repository", args)
		return
	}
	repoName := rr[1]
	if strings.HasSuffix(repoName, ".git") {
		repoName = repoName[:len(repoName)-4]
	}

	isWrite := In(verb, COMMANDS_WRITE)
	isRead := In(verb, COMMANDS_READONLY)

	repo, err := models.GetRepositoryByName(user.Id, repoName)
	var isExist bool = true
	if err != nil {
		if err == models.ErrRepoNotExist {
			isExist = false
			if isRead {
				println("Repository", user.Name+"/"+repoName, "is not exist")
				return
			}
		} else {
			println("Get repository error:", err)
			log.Error(err.Error())
			return
		}
	}

	// access check
	switch {
	case isWrite:
		has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
		if err != nil {
			println("Inernel error:", err)
			log.Error(err.Error())
			return
		}
		if !has {
			println("You have no right to write this repository")
			return
		}
	case isRead:
		has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
		if err != nil {
			println("Inernel error")
			log.Error(err.Error())
			return
		}
		if !has {
			has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
			if err != nil {
				println("Inernel error")
				log.Error(err.Error())
				return
			}
		}
		if !has {
			println("You have no right to access this repository")
			return
		}
	default:
		println("Unknown command")
		return
	}

	var rep *git.Repository
	repoPath := models.RepoPath(user.Name, repoName)
	if !isExist {
		if isWrite {
			_, err = models.CreateRepository(user, repoName, "", "", "", false, true)
			if err != nil {
				println("Create repository failed")
				log.Error(err.Error())
				return
			}
		}
	}

		rep, err = git.OpenRepository(repoPath)
		if err != nil {
			println("OpenRepository failed:", err.Error())
			log.Error(err.Error())
			return
		}

	refs, err := rep.AllReferencesMap()
	if err != nil {
		println("Get All References failed:", err.Error())
		log.Error(err.Error())
		return
	}

	gitcmd := exec.Command(verb, rRepo)
	gitcmd.Dir = base.RepoRootPath

	var s string
	b := bytes.NewBufferString(s)

	gitcmd.Stdout = io.MultiWriter(os.Stdout, b)
	//gitcmd.Stdin = io.MultiReader(os.Stdin, b)
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr

	if err = gitcmd.Run(); err != nil {
		println("execute command error:", err.Error())
		log.Error(err.Error())
		return
	}

	if isRead {
		return
	}

	time.Sleep(time.Second)

	// find push reference name
	var t = "ok refs/heads/"
	var i int
	var refname string
	for {
		l, err := b.ReadString('\n')
		if err != nil {
			break
		}
		i = i + 1
		l = l[:len(l)-1]
		idx := strings.Index(l, t)
		if idx > 0 {
			refname = l[idx+len(t):]
		}
	}
	if refname == "" {
		println("No find any reference name:", b.String())
		return
	}

	var ref *git.Reference
	var ok bool
	var l *list.List
	//log.Info("----", refname, "-----")
	if ref, ok = refs[refname]; !ok {
		// for new branch
		refs, err = rep.AllReferencesMap()
		if err != nil {
			println("Get All References failed:", err.Error())
			log.Error(err.Error())
			return
		}
		if ref, ok = refs[refname]; !ok {
			log.Error("unknow reference name -", refname, "-", b.String())
			return
		}
		l, err = ref.AllCommits()
		if err != nil {
			println("Get All Commits failed:", err.Error())
			log.Error(err.Error())
			return
		}
	} else {
		//log.Info("----", ref, "-----")
		var last *git.Commit
		//log.Info("00000", ref.Oid.String())
		last, err = ref.LastCommit()
		if err != nil {
			println("Get last commit failed:", err.Error())
			log.Error(err.Error())
			return
		}

		ref2, err := rep.LookupReference(ref.Name)
		if err != nil {
			println("look up reference failed:", err.Error())
			log.Error(err.Error())
			return
		}

		//log.Info("11111", ref2.Oid.String())
		before, err := ref2.LastCommit()
		if err != nil {
			println("Get last commit failed:", err.Error())
			log.Error(err.Error())
			return
		}
		//log.Info("----", before.Id(), "-----", last.Id())
		l = ref.CommitsBetween(before, last)
	}

	commits := make([][]string, 0)
	var maxCommits = 3
	for e := l.Front(); e != nil; e = e.Next() {
		commit := e.Value.(*git.Commit)
		commits = append(commits, []string{commit.Id().String(), commit.Message()})
		if len(commits) >= maxCommits {
			break
		}
	}

	if err = models.CommitRepoAction(user.Id, user.Name,
		repo.Id, repoName, refname, &base.PushCommits{l.Len(), commits}); err != nil {
		log.Error("runUpdate.models.CommitRepoAction: %v", err, commits)
	} else {
		c := exec.Command("git", "update-server-info")
		c.Dir = repoPath
		err := c.Run()
		if err != nil {
			log.Error("update-server-info: %v", err)
		}
	}
}
<commit_msg>add log<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"container/list"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/codegangsta/cli"
	"github.com/gogits/gogs/modules/log"

	"github.com/gogits/git"
	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/base"
)

var (
	COMMANDS_READONLY = map[string]int{
		"git-upload-pack":    models.AU_WRITABLE,
		"git upload-pack":    models.AU_WRITABLE,
		"git-upload-archive": models.AU_WRITABLE,
	}

	COMMANDS_WRITE = map[string]int{
		"git-receive-pack": models.AU_READABLE,
		"git receive-pack": models.AU_READABLE,
	}
)

var CmdServ = cli.Command{
	Name:  "serv",
	Usage: "This command just should be called by ssh shell",
	Description: `
gogs serv provide access auth for repositories`,
	Action: runServ,
	Flags:  []cli.Flag{},
}

func init() {
	level := "0"
	os.MkdirAll("log", os.ModePerm)
	log.NewLogger(10000, "file", fmt.Sprintf(`{"level":%s,"filename":"%s"}`, level, "log/serv.log"))
	log.Info("start logging...")
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}

	verb, args := ss[0], ss[1]
	if verb == "git" {
		ss = strings.SplitN(args, " ", 2)
		args = ss[1]
		verb = fmt.Sprintf("%s %s", verb, ss[0])
	}
	return verb, args
}

func In(b string, sl map[string]int) bool {
	_, e := sl[b]
	return e
}

func runServ(k *cli.Context) {
	base.NewConfigContext()
	models.LoadModelsConfig()
	models.NewEngine()

	keys := strings.Split(os.Args[2], "-")
	if len(keys) != 2 {
		fmt.Println("auth file format error")
		return
	}

	keyId, err := strconv.ParseInt(keys[1], 10, 64)
	if err != nil {
		fmt.Println("auth file format error")
		return
	}
	user, err := models.GetUserByKeyId(keyId)
	if err != nil {
		fmt.Println("You have no right to access")
		return
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if cmd == "" {
		println("Hi", user.Name, "! You've successfully authenticated, but Gogs does not provide shell access.")
		return
	}

	verb, args := parseCmd(cmd)
	rRepo := strings.Trim(args, "'")
	rr := strings.SplitN(rRepo, "/", 2)
	if len(rr) != 2 {
		println("Unavilable repository", args)
		return
	}
	repoName := rr[1]
	if strings.HasSuffix(repoName, ".git") {
		repoName = repoName[:len(repoName)-4]
	}

	isWrite := In(verb, COMMANDS_WRITE)
	isRead := In(verb, COMMANDS_READONLY)

	repo, err := models.GetRepositoryByName(user.Id, repoName)
	var isExist bool = true
	if err != nil {
		if err == models.ErrRepoNotExist {
			isExist = false
			if isRead {
				println("Repository", user.Name+"/"+repoName, "is not exist")
				return
			}
		} else {
			println("Get repository error:", err)
			log.Error(err.Error())
			return
		}
	}

	// access check
	switch {
	case isWrite:
		has, err := models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
		if err != nil {
			println("Inernel error:", err)
			log.Error(err.Error())
			return
		}
		if !has {
			println("You have no right to write this repository")
			return
		}
	case isRead:
		has, err := models.HasAccess(user.Name, repoName, models.AU_READABLE)
		if err != nil {
			println("Inernel error")
			log.Error(err.Error())
			return
		}
		if !has {
			has, err = models.HasAccess(user.Name, repoName, models.AU_WRITABLE)
			if err != nil {
				println("Inernel error")
				log.Error(err.Error())
				return
			}
		}
		if !has {
			println("You have no right to access this repository")
			return
		}
	default:
		println("Unknown command")
		return
	}

	var rep *git.Repository
	repoPath := models.RepoPath(user.Name, repoName)
	if !isExist {
		if isWrite {
			_, err = models.CreateRepository(user, repoName, "", "", "", false, true)
			if err != nil {
				println("Create repository failed")
				log.Error(err.Error())
				return
			}
		}
	}

		rep, err = git.OpenRepository(repoPath)
		if err != nil {
			println("OpenRepository failed:", err.Error())
			log.Error(err.Error())
			return
		}

	refs, err := rep.AllReferencesMap()
	if err != nil {
		println("Get All References failed:", err.Error())
		log.Error(err.Error())
		return
	}

	gitcmd := exec.Command(verb, rRepo)
	gitcmd.Dir = base.RepoRootPath

	var s string
	b := bytes.NewBufferString(s)

	gitcmd.Stdout = io.MultiWriter(os.Stdout, b)
	//gitcmd.Stdin = io.MultiReader(os.Stdin, b)
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr

	if err = gitcmd.Run(); err != nil {
		println("execute command error:", err.Error())
		log.Error(err.Error())
		return
	}

	if isRead {
		return
	}

	time.Sleep(time.Second)
	log.Info(s)

	// find push reference name
	var t = "ok refs/heads/"
	var i int
	var refname string
	for {
		l, err := b.ReadString('\n')
		if err != nil {
			break
		}
		i = i + 1
		l = l[:len(l)-1]
		idx := strings.Index(l, t)
		if idx > 0 {
			refname = l[idx+len(t):]
		}
	}
	if refname == "" {
		println("No find any reference name:", s)
		return
	}

	var ref *git.Reference
	var ok bool
	var l *list.List
	//log.Info("----", refname, "-----")
	if ref, ok = refs[refname]; !ok {
		// for new branch
		refs, err = rep.AllReferencesMap()
		if err != nil {
			println("Get All References failed:", err.Error())
			log.Error(err.Error())
			return
		}
		if ref, ok = refs[refname]; !ok {
			log.Error("unknow reference name -", refname, "-", b.String())
			return
		}
		l, err = ref.AllCommits()
		if err != nil {
			println("Get All Commits failed:", err.Error())
			log.Error(err.Error())
			return
		}
	} else {
		//log.Info("----", ref, "-----")
		var last *git.Commit
		//log.Info("00000", ref.Oid.String())
		last, err = ref.LastCommit()
		if err != nil {
			println("Get last commit failed:", err.Error())
			log.Error(err.Error())
			return
		}

		ref2, err := rep.LookupReference(ref.Name)
		if err != nil {
			println("look up reference failed:", err.Error())
			log.Error(err.Error())
			return
		}

		//log.Info("11111", ref2.Oid.String())
		before, err := ref2.LastCommit()
		if err != nil {
			println("Get last commit failed:", err.Error())
			log.Error(err.Error())
			return
		}
		//log.Info("----", before.Id(), "-----", last.Id())
		l = ref.CommitsBetween(before, last)
	}

	commits := make([][]string, 0)
	var maxCommits = 3
	for e := l.Front(); e != nil; e = e.Next() {
		commit := e.Value.(*git.Commit)
		commits = append(commits, []string{commit.Id().String(), commit.Message()})
		if len(commits) >= maxCommits {
			break
		}
	}

	if err = models.CommitRepoAction(user.Id, user.Name,
		repo.Id, repoName, refname, &base.PushCommits{l.Len(), commits}); err != nil {
		log.Error("runUpdate.models.CommitRepoAction: %v", err, commits)
	} else {
		c := exec.Command("git", "update-server-info")
		c.Dir = repoPath
		err := c.Run()
		if err != nil {
			log.Error("update-server-info: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>package booklitcmd

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/sirupsen/logrus"
	"github.com/vito/booklit"
	"github.com/vito/booklit/baselit"
	"github.com/vito/booklit/load"
	"github.com/vito/booklit/render"
)

type Command struct {
	Version func() `short:"v" long:"version" description:"Print the version of Boooklit and exit."`

	In  string `long:"in"  short:"i" required:"true" description:"Input .lit file to load."`
	Out string `long:"out" short:"o" description:"Directory into which sections will be rendered."`

	SectionTag  string `long:"section-tag"  description:"Section tag to render."`
	SectionPath string `long:"section-path" description:"Section path to load and render with --in as its parent."`

	SaveSearchIndex bool `long:"save-search-index" description:"Save a search index JSON file in the destination."`

	ServerPort int `long:"serve" short:"s" description:"Start an HTTP server on the given port."`

	Plugins []string `long:"plugin" short:"p" description:"Package to import, providing a plugin."`

	Debug bool `long:"debug" short:"d" description:"Log at debug level."`

	AllowBrokenReferences bool `long:"allow-broken-references" description:"Replace broken references with a bogus tag."`

	HTMLEngine struct {
		Templates string `long:"templates" description:"Directory containing .tmpl files to load."`
	} `group:"HTML Rendering Engine" namespace:"html"`

	TextEngine struct {
		FileExtension string `long:"file-extension" description:"File extension to use for generated files."`
		Templates     string `long:"templates"      description:"Directory containing .tmpl files to load."`
	} `group:"Text Rendering Engine" namespace:"text"`
}

func (cmd *Command) Execute(args []string) error {
	if cmd.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	isReexec := os.Getenv("BOOKLIT_REEXEC") != ""
	if !isReexec && len(cmd.Plugins) > 0 {
		logrus.Debug("plugins configured; reexecing")
		return cmd.reexec()
	}

	if cmd.ServerPort != 0 {
		return cmd.Serve()
	}

	return cmd.Build()
}

func (cmd *Command) Serve() error {
	http.Handle("/", &Server{
		In: cmd.In,
		Processor: &load.Processor{
			AllowBrokenReferences: cmd.AllowBrokenReferences,
		},

		Templates:  cmd.HTMLEngine.Templates,
		Engine:     render.NewHTMLEngine(),
		FileServer: http.FileServer(http.Dir(cmd.Out)),
	})

	logrus.WithField("port", cmd.ServerPort).Info("listening")

	return http.ListenAndServe(fmt.Sprintf(":%d", cmd.ServerPort), nil)
}

var basePluginFactories = []booklit.PluginFactory{
	baselit.NewPlugin,
}

func (cmd *Command) Build() error {
	processor := &load.Processor{
		AllowBrokenReferences: cmd.AllowBrokenReferences,
	}

	var engine render.Engine
	if cmd.TextEngine.FileExtension != "" {
		textEngine := render.NewTextEngine(cmd.TextEngine.FileExtension)

		if cmd.TextEngine.Templates != "" {
			err := textEngine.LoadTemplates(cmd.TextEngine.Templates)
			if err != nil {
				return err
			}
		}

		engine = textEngine
	} else {
		htmlEngine := render.NewHTMLEngine()

		if cmd.HTMLEngine.Templates != "" {
			err := htmlEngine.LoadTemplates(cmd.HTMLEngine.Templates)
			if err != nil {
				return err
			}
		}

		engine = htmlEngine
	}

	section, err := processor.LoadFile(cmd.In, basePluginFactories)
	if err != nil {
		return err
	}

	sectionToRender := section
	if cmd.SectionTag != "" {
		tags := section.FindTag(cmd.SectionTag)
		if len(tags) == 0 {
			return fmt.Errorf("unknown tag: %s", cmd.SectionTag)
		}

		sectionToRender = tags[0].Section
	} else if cmd.SectionPath != "" {
		sectionToRender, err = processor.LoadFileIn(section, cmd.SectionPath, basePluginFactories)
		if err != nil {
			return err
		}
	}

	if cmd.Out == "" {
		return engine.RenderSection(os.Stdout, sectionToRender)
	}

	err = os.MkdirAll(cmd.Out, 0755)
	if err != nil {
		return err
	}

	writer := render.Writer{
		Engine:      engine,
		Destination: cmd.Out,
	}

	err = writer.WriteSection(sectionToRender)
	if err != nil {
		return err
	}

	if cmd.SaveSearchIndex {
		err = writer.WriteSearchIndex(section, "search_index.json")
		if err != nil {
			return err
		}
	}

	return nil
}

func (cmd *Command) reexec() error {
	tmpdir, err := ioutil.TempDir("", "booklit-reexec")
	if err != nil {
		return err
	}

	defer func() {
		_ = os.RemoveAll(tmpdir)
	}()

	src := filepath.Join(tmpdir, "main.go")
	bin := filepath.Join(tmpdir, "main")

	goSrc := "package main\n"
	goSrc += "import \"github.com/vito/booklit/booklitcmd\"\n"
	for _, p := range cmd.Plugins {
		goSrc += "import _ \"" + p + "\"\n"
	}
	goSrc += "func main() {\n"
	goSrc += "	booklitcmd.Main()\n"
	goSrc += "}\n"

	err = ioutil.WriteFile(src, []byte(goSrc), 0644)
	if err != nil {
		return err
	}

	build := exec.Command("go", "install", src)
	build.Env = append(os.Environ(), "GOBIN="+tmpdir)
	build.Stdout = os.Stdout
	build.Stderr = os.Stderr

	logrus.Debug("building reexec binary")

	err = build.Run()
	if err != nil {
		return fmt.Errorf("build failed: %w", err)
	}

	run := exec.Command(bin, os.Args[1:]...)
	run.Env = append(os.Environ(), "BOOKLIT_REEXEC=1")
	run.Stdout = os.Stdout
	run.Stderr = os.Stderr

	logrus.Debug("reexecing")

	err = run.Run()
	if err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			os.Exit(exitErr.ExitCode())
			return nil
		}

		return fmt.Errorf("reexec failed: %w", err)
	}

	return nil
}
<commit_msg>fix call to os.Exit skipping defer<commit_after>package booklitcmd

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/sirupsen/logrus"
	"github.com/vito/booklit"
	"github.com/vito/booklit/baselit"
	"github.com/vito/booklit/load"
	"github.com/vito/booklit/render"
)

type Command struct {
	Version func() `short:"v" long:"version" description:"Print the version of Boooklit and exit."`

	In  string `long:"in"  short:"i" required:"true" description:"Input .lit file to load."`
	Out string `long:"out" short:"o" description:"Directory into which sections will be rendered."`

	SectionTag  string `long:"section-tag"  description:"Section tag to render."`
	SectionPath string `long:"section-path" description:"Section path to load and render with --in as its parent."`

	SaveSearchIndex bool `long:"save-search-index" description:"Save a search index JSON file in the destination."`

	ServerPort int `long:"serve" short:"s" description:"Start an HTTP server on the given port."`

	Plugins []string `long:"plugin" short:"p" description:"Package to import, providing a plugin."`

	Debug bool `long:"debug" short:"d" description:"Log at debug level."`

	AllowBrokenReferences bool `long:"allow-broken-references" description:"Replace broken references with a bogus tag."`

	HTMLEngine struct {
		Templates string `long:"templates" description:"Directory containing .tmpl files to load."`
	} `group:"HTML Rendering Engine" namespace:"html"`

	TextEngine struct {
		FileExtension string `long:"file-extension" description:"File extension to use for generated files."`
		Templates     string `long:"templates"      description:"Directory containing .tmpl files to load."`
	} `group:"Text Rendering Engine" namespace:"text"`
}

func (cmd *Command) Execute(args []string) error {
	if cmd.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	isReexec := os.Getenv("BOOKLIT_REEXEC") != ""
	if !isReexec && len(cmd.Plugins) > 0 {
		logrus.Debug("plugins configured; reexecing")

		exitCode, err := cmd.reexec()
		if err != nil {
			return err
		}

		os.Exit(exitCode)

		return nil
	}

	if cmd.ServerPort != 0 {
		return cmd.Serve()
	}

	return cmd.Build()
}

func (cmd *Command) Serve() error {
	http.Handle("/", &Server{
		In: cmd.In,
		Processor: &load.Processor{
			AllowBrokenReferences: cmd.AllowBrokenReferences,
		},

		Templates:  cmd.HTMLEngine.Templates,
		Engine:     render.NewHTMLEngine(),
		FileServer: http.FileServer(http.Dir(cmd.Out)),
	})

	logrus.WithField("port", cmd.ServerPort).Info("listening")

	return http.ListenAndServe(fmt.Sprintf(":%d", cmd.ServerPort), nil)
}

var basePluginFactories = []booklit.PluginFactory{
	baselit.NewPlugin,
}

func (cmd *Command) Build() error {
	processor := &load.Processor{
		AllowBrokenReferences: cmd.AllowBrokenReferences,
	}

	var engine render.Engine
	if cmd.TextEngine.FileExtension != "" {
		textEngine := render.NewTextEngine(cmd.TextEngine.FileExtension)

		if cmd.TextEngine.Templates != "" {
			err := textEngine.LoadTemplates(cmd.TextEngine.Templates)
			if err != nil {
				return err
			}
		}

		engine = textEngine
	} else {
		htmlEngine := render.NewHTMLEngine()

		if cmd.HTMLEngine.Templates != "" {
			err := htmlEngine.LoadTemplates(cmd.HTMLEngine.Templates)
			if err != nil {
				return err
			}
		}

		engine = htmlEngine
	}

	section, err := processor.LoadFile(cmd.In, basePluginFactories)
	if err != nil {
		return err
	}

	sectionToRender := section
	if cmd.SectionTag != "" {
		tags := section.FindTag(cmd.SectionTag)
		if len(tags) == 0 {
			return fmt.Errorf("unknown tag: %s", cmd.SectionTag)
		}

		sectionToRender = tags[0].Section
	} else if cmd.SectionPath != "" {
		sectionToRender, err = processor.LoadFileIn(section, cmd.SectionPath, basePluginFactories)
		if err != nil {
			return err
		}
	}

	if cmd.Out == "" {
		return engine.RenderSection(os.Stdout, sectionToRender)
	}

	err = os.MkdirAll(cmd.Out, 0755)
	if err != nil {
		return err
	}

	writer := render.Writer{
		Engine:      engine,
		Destination: cmd.Out,
	}

	err = writer.WriteSection(sectionToRender)
	if err != nil {
		return err
	}

	if cmd.SaveSearchIndex {
		err = writer.WriteSearchIndex(section, "search_index.json")
		if err != nil {
			return err
		}
	}

	return nil
}

func (cmd *Command) reexec() (int, error) {
	tmpdir, err := ioutil.TempDir("", "booklit-reexec")
	if err != nil {
		return 0, err
	}

	defer func() {
		_ = os.RemoveAll(tmpdir)
	}()

	src := filepath.Join(tmpdir, "main.go")
	bin := filepath.Join(tmpdir, "main")

	goSrc := "package main\n"
	goSrc += "import \"github.com/vito/booklit/booklitcmd\"\n"
	for _, p := range cmd.Plugins {
		goSrc += "import _ \"" + p + "\"\n"
	}
	goSrc += "func main() {\n"
	goSrc += "	booklitcmd.Main()\n"
	goSrc += "}\n"

	err = ioutil.WriteFile(src, []byte(goSrc), 0644)
	if err != nil {
		return 0, err
	}

	build := exec.Command("go", "install", src)
	build.Env = append(os.Environ(), "GOBIN="+tmpdir)
	build.Stdout = os.Stdout
	build.Stderr = os.Stderr

	logrus.Debug("building reexec binary")

	err = build.Run()
	if err != nil {
		return 0, fmt.Errorf("build failed: %w", err)
	}

	run := exec.Command(bin, os.Args[1:]...)
	run.Env = append(os.Environ(), "BOOKLIT_REEXEC=1")
	run.Stdout = os.Stdout
	run.Stderr = os.Stderr

	logrus.Debug("reexecing")

	err = run.Run()
	if err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			return exitErr.ExitCode(), nil
		}

		return 0, fmt.Errorf("reexec failed: %w", err)
	}

	return 0, nil
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version    int                 `json:"v"`
	Token      string              `json:"token"`
	Properties handshakeProperties `json:"properties"`
	Compress   bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					fmt.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

func (s *Session) sendHeartbeat(wsConn *websocket.Conn) error {
	return wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {
	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	// Send first heartbeat immediately because lag could put the
	// first heartbeat outside the required heartbeat interval window.
	err := s.sendHeartbeat(wsConn)
	if err != nil {
		fmt.Println("Error sending initial heartbeat:", err)
		return
	}

	ticker := time.NewTicker(i * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			err := s.sendHeartbeat(wsConn)
			if err != nil {
				fmt.Println("Error sending heartbeat:", err)
				return
			}
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// eventToInterface is a mapping of Discord WSAPI events to their
// DiscordGo event container.
var eventToInterface = map[string]interface{}{
	"CHANNEL_CREATE":            ChannelCreate{},
	"CHANNEL_UPDATE":            ChannelUpdate{},
	"CHANNEL_DELETE":            ChannelDelete{},
	"GUILD_CREATE":              GuildCreate{},
	"GUILD_UPDATE":              GuildUpdate{},
	"GUILD_DELETE":              GuildDelete{},
	"GUILD_BAN_ADD":             GuildBanAdd{},
	"GUILD_BAN_REMOVE":          GuildBanRemove{},
	"GUILD_MEMBER_ADD":          GuildMemberAdd{},
	"GUILD_MEMBER_UPDATE":       GuildMemberUpdate{},
	"GUILD_MEMBER_REMOVE":       GuildMemberRemove{},
	"GUILD_ROLE_CREATE":         GuildRoleCreate{},
	"GUILD_ROLE_UPDATE":         GuildRoleUpdate{},
	"GUILD_ROLE_DELETE":         GuildRoleDelete{},
	"GUILD_INTEGRATIONS_UPDATE": GuildIntegrationsUpdate{},
	"GUILD_EMOJIS_UPDATE":       GuildEmojisUpdate{},
	"MESSAGE_ACK":               MessageAck{},
	"MESSAGE_CREATE":            MessageCreate{},
	"MESSAGE_UPDATE":            MessageUpdate{},
	"MESSAGE_DELETE":            MessageDelete{},
	"PRESENCE_UPDATE":           PresenceUpdate{},
	"READY":                     Ready{},
	"USER_UPDATE":               UserUpdate{},
	"USER_SETTINGS_UPDATE":      UserSettingsUpdate{},
	"TYPING_START":              TypingStart{},
	"VOICE_SERVER_UPDATE":       VoiceServerUpdate{},
	"VOICE_STATE_UPDATE":        VoiceStateUpdate{},
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	s.RLock()
	if s.handlers == nil {
		s.RUnlock()
		s.initialize()
	} else {
		s.RUnlock()
	}

	var err error
	var reader io.Reader
	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			fmt.Println(err1)
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				fmt.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		fmt.Println(err)
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = unmarshal(e.RawData, i); err != nil {
			fmt.Println("Unable to unmarshal event data.")
			i = e
		}
	} else {
		fmt.Println("Unknown event.")
		i = e
	}

	s.handle(i)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   string `json:"guild_id"`
	ChannelID string `json:"channel_id"`
	SelfMute  bool   `json:"self_mute"`
	SelfDeaf  bool   `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel. After calling
// this func please monitor the Session.Voice.Ready bool to determine when
// it is ready and able to send/receive audio, that should happen quickly.
//
//    gID   : Guild ID of the channel to join.
//    cID   : Channel ID of the channel to join.
//    mute  : If true, you will be set to muted upon joining.
//    deaf  : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (err error) {

	if s.wsConn == nil {
		return fmt.Errorf("no websocket connection exists")
	}

	// Create new voice{} struct if one does not exist.
	// If you create this prior to calling this func then you can manually
	// set some variables if needed, such as to enable debugging.
	if s.Voice == nil {
		s.Voice = &Voice{}
	}
	// TODO : Determine how to properly change channels and change guild
	// and channel when you are already connected to an existing channel.

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{gID, cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		return
	}

	// Store gID and cID for later use
	s.Voice.guildID = gID
	s.Voice.channelID = cID

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data
// websocket.  This comes immediately after the call to VoiceChannelJoin
// for the session user.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		fmt.Println(err)
		return
	}

	// This event comes for all users, if it's not for the session
	// user just ignore it.
	// TODO Move this IF to the event() func
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	s.Voice.userID = self.ID // TODO: Review
	s.Voice.sessionID = st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
// This event tells us the information needed to open a voice websocket
// connection and should happen after the VOICE_STATE event.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	// Store values for later use
	s.Voice.token = st.Token
	s.Voice.endpoint = st.Endpoint
	s.Voice.guildID = st.GuildID

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := s.Voice.Open()
	if err != nil {
		fmt.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<commit_msg>Allow calling ChannelVoiceJoin even after connected to voice, closes<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains low level functions for interacting with the Discord
// data websocket interface.

package discordgo

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"reflect"
	"runtime"
	"time"

	"github.com/gorilla/websocket"
)

type handshakeProperties struct {
	OS              string `json:"$os"`
	Browser         string `json:"$browser"`
	Device          string `json:"$device"`
	Referer         string `json:"$referer"`
	ReferringDomain string `json:"$referring_domain"`
}

type handshakeData struct {
	Version    int                 `json:"v"`
	Token      string              `json:"token"`
	Properties handshakeProperties `json:"properties"`
	Compress   bool                `json:"compress"`
}

type handshakeOp struct {
	Op   int           `json:"op"`
	Data handshakeData `json:"d"`
}

// Open opens a websocket connection to Discord.
func (s *Session) Open() (err error) {
	s.Lock()
	defer func() {
		if err != nil {
			s.Unlock()
		}
	}()

	if s.wsConn != nil {
		err = errors.New("Web socket already opened.")
		return
	}

	// Get the gateway to use for the Websocket connection
	g, err := s.Gateway()
	if err != nil {
		return
	}

	header := http.Header{}
	header.Add("accept-encoding", "zlib")

	// TODO: See if there's a use for the http response.
	// conn, response, err := websocket.DefaultDialer.Dial(session.Gateway, nil)
	s.wsConn, _, err = websocket.DefaultDialer.Dial(g, header)
	if err != nil {
		return
	}

	err = s.wsConn.WriteJSON(handshakeOp{2, handshakeData{3, s.Token, handshakeProperties{runtime.GOOS, "Discordgo v" + VERSION, "", "", ""}, s.Compress}})
	if err != nil {
		return
	}

	// Create listening outside of listen, as it needs to happen inside the mutex
	// lock.
	s.listening = make(chan interface{})
	go s.listen(s.wsConn, s.listening)

	s.Unlock()

	s.handle(&Connect{})

	return
}

// Close closes a websocket and stops all listening/heartbeat goroutines.
// TODO: Add support for Voice WS/UDP connections
func (s *Session) Close() (err error) {
	s.Lock()

	s.DataReady = false

	if s.listening != nil {
		close(s.listening)
		s.listening = nil
	}

	if s.wsConn != nil {
		err = s.wsConn.Close()
		s.wsConn = nil
	}

	s.Unlock()

	s.handle(&Disconnect{})

	return
}

// listen polls the websocket connection for events, it will stop when
// the listening channel is closed, or an error occurs.
func (s *Session) listen(wsConn *websocket.Conn, listening <-chan interface{}) {
	for {
		messageType, message, err := wsConn.ReadMessage()
		if err != nil {
			// Detect if we have been closed manually. If a Close() has already
			// happened, the websocket we are listening on will be different to the
			// current session.
			s.RLock()
			sameConnection := s.wsConn == wsConn
			s.RUnlock()
			if sameConnection {
				// There has been an error reading, Close() the websocket so that
				// OnDisconnect is fired.
				err := s.Close()
				if err != nil {
					fmt.Println("error closing session connection: ", err)
				}

				// Attempt to reconnect, with expenonential backoff up to 10 minutes.
				if s.ShouldReconnectOnError {
					wait := time.Duration(1)
					for {
						if s.Open() == nil {
							return
						}
						<-time.After(wait * time.Second)
						wait *= 2
						if wait > 600 {
							wait = 600
						}
					}
				}
			}
			return
		}

		select {
		case <-listening:
			return
		default:
			go s.event(messageType, message)
		}
	}
}

type heartbeatOp struct {
	Op   int `json:"op"`
	Data int `json:"d"`
}

func (s *Session) sendHeartbeat(wsConn *websocket.Conn) error {
	return wsConn.WriteJSON(heartbeatOp{1, int(time.Now().Unix())})
}

// heartbeat sends regular heartbeats to Discord so it knows the client
// is still connected.  If you do not send these heartbeats Discord will
// disconnect the websocket connection after a few seconds.
func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) {
	if listening == nil || wsConn == nil {
		return
	}

	s.Lock()
	s.DataReady = true
	s.Unlock()

	// Send first heartbeat immediately because lag could put the
	// first heartbeat outside the required heartbeat interval window.
	err := s.sendHeartbeat(wsConn)
	if err != nil {
		fmt.Println("Error sending initial heartbeat:", err)
		return
	}

	ticker := time.NewTicker(i * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			err := s.sendHeartbeat(wsConn)
			if err != nil {
				fmt.Println("Error sending heartbeat:", err)
				return
			}
		case <-listening:
			return
		}
	}
}

type updateStatusGame struct {
	Name string `json:"name"`
}

type updateStatusData struct {
	IdleSince *int              `json:"idle_since"`
	Game      *updateStatusGame `json:"game"`
}

type updateStatusOp struct {
	Op   int              `json:"op"`
	Data updateStatusData `json:"d"`
}

// UpdateStatus is used to update the authenticated user's status.
// If idle>0 then set status to idle.  If game>0 then set game.
// if otherwise, set status to active, and no game.
func (s *Session) UpdateStatus(idle int, game string) (err error) {
	s.RLock()
	defer s.RUnlock()
	if s.wsConn == nil {
		return errors.New("No websocket connection exists.")
	}

	var usd updateStatusData
	if idle > 0 {
		usd.IdleSince = &idle
	}
	if game != "" {
		usd.Game = &updateStatusGame{game}
	}

	err = s.wsConn.WriteJSON(updateStatusOp{3, usd})

	return
}

// eventToInterface is a mapping of Discord WSAPI events to their
// DiscordGo event container.
var eventToInterface = map[string]interface{}{
	"CHANNEL_CREATE":            ChannelCreate{},
	"CHANNEL_UPDATE":            ChannelUpdate{},
	"CHANNEL_DELETE":            ChannelDelete{},
	"GUILD_CREATE":              GuildCreate{},
	"GUILD_UPDATE":              GuildUpdate{},
	"GUILD_DELETE":              GuildDelete{},
	"GUILD_BAN_ADD":             GuildBanAdd{},
	"GUILD_BAN_REMOVE":          GuildBanRemove{},
	"GUILD_MEMBER_ADD":          GuildMemberAdd{},
	"GUILD_MEMBER_UPDATE":       GuildMemberUpdate{},
	"GUILD_MEMBER_REMOVE":       GuildMemberRemove{},
	"GUILD_ROLE_CREATE":         GuildRoleCreate{},
	"GUILD_ROLE_UPDATE":         GuildRoleUpdate{},
	"GUILD_ROLE_DELETE":         GuildRoleDelete{},
	"GUILD_INTEGRATIONS_UPDATE": GuildIntegrationsUpdate{},
	"GUILD_EMOJIS_UPDATE":       GuildEmojisUpdate{},
	"MESSAGE_ACK":               MessageAck{},
	"MESSAGE_CREATE":            MessageCreate{},
	"MESSAGE_UPDATE":            MessageUpdate{},
	"MESSAGE_DELETE":            MessageDelete{},
	"PRESENCE_UPDATE":           PresenceUpdate{},
	"READY":                     Ready{},
	"USER_UPDATE":               UserUpdate{},
	"USER_SETTINGS_UPDATE":      UserSettingsUpdate{},
	"TYPING_START":              TypingStart{},
	"VOICE_SERVER_UPDATE":       VoiceServerUpdate{},
	"VOICE_STATE_UPDATE":        VoiceStateUpdate{},
}

// Front line handler for all Websocket Events.  Determines the
// event type and passes the message along to the next handler.

// event is the front line handler for all events.  This needs to be
// broken up into smaller functions to be more idiomatic Go.
// Events will be handled by any implemented handler in Session.
// All unhandled events will then be handled by OnEvent.
func (s *Session) event(messageType int, message []byte) {
	s.RLock()
	if s.handlers == nil {
		s.RUnlock()
		s.initialize()
	} else {
		s.RUnlock()
	}

	var err error
	var reader io.Reader
	reader = bytes.NewBuffer(message)

	if messageType == 2 {
		z, err1 := zlib.NewReader(reader)
		if err1 != nil {
			fmt.Println(err1)
			return
		}
		defer func() {
			err := z.Close()
			if err != nil {
				fmt.Println("error closing zlib:", err)
			}
		}()
		reader = z
	}

	var e *Event
	decoder := json.NewDecoder(reader)
	if err = decoder.Decode(&e); err != nil {
		fmt.Println(err)
		return
	}

	if s.Debug {
		printEvent(e)
	}

	i := eventToInterface[e.Type]
	if i != nil {
		// Create a new instance of the event type.
		i = reflect.New(reflect.TypeOf(i)).Interface()

		// Attempt to unmarshal our event.
		// If there is an error we should handle the event itself.
		if err = unmarshal(e.RawData, i); err != nil {
			fmt.Println("Unable to unmarshal event data.")
			i = e
		}
	} else {
		fmt.Println("Unknown event.")
		i = e
	}

	s.handle(i)

	return
}

// ------------------------------------------------------------------------------------------------
// Code related to voice connections that initiate over the data websocket
// ------------------------------------------------------------------------------------------------

// A VoiceServerUpdate stores the data received during the Voice Server Update
// data websocket event. This data is used during the initial Voice Channel
// join handshaking.
type VoiceServerUpdate struct {
	Token    string `json:"token"`
	GuildID  string `json:"guild_id"`
	Endpoint string `json:"endpoint"`
}

type voiceChannelJoinData struct {
	GuildID   string `json:"guild_id"`
	ChannelID string `json:"channel_id"`
	SelfMute  bool   `json:"self_mute"`
	SelfDeaf  bool   `json:"self_deaf"`
}

type voiceChannelJoinOp struct {
	Op   int                  `json:"op"`
	Data voiceChannelJoinData `json:"d"`
}

// ChannelVoiceJoin joins the session user to a voice channel. After calling
// this func please monitor the Session.Voice.Ready bool to determine when
// it is ready and able to send/receive audio, that should happen quickly.
//
//    gID   : Guild ID of the channel to join.
//    cID   : Channel ID of the channel to join.
//    mute  : If true, you will be set to muted upon joining.
//    deaf  : If true, you will be set to deafened upon joining.
func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool) (err error) {

	// Create new voice{} struct if one does not exist.
	// If you create this prior to calling this func then you can manually
	// set some variables if needed, such as to enable debugging.
	if s.Voice == nil {
		s.Voice = &Voice{}
	}

	// Send the request to Discord that we want to join the voice channel
	data := voiceChannelJoinOp{4, voiceChannelJoinData{gID, cID, mute, deaf}}
	err = s.wsConn.WriteJSON(data)
	if err != nil {
		return
	}

	// Store gID and cID for later use
	s.Voice.guildID = gID
	s.Voice.channelID = cID

	return
}

// onVoiceStateUpdate handles Voice State Update events on the data
// websocket.  This comes immediately after the call to VoiceChannelJoin
// for the session user.
func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) {

	// Need to have this happen at login and store it in the Session
	// TODO : This should be done upon connecting to Discord, or
	// be moved to a small helper function
	self, err := s.User("@me") // TODO: move to Login/New
	if err != nil {
		fmt.Println(err)
		return
	}

	// This event comes for all users, if it's not for the session
	// user just ignore it.
	// TODO Move this IF to the event() func
	if st.UserID != self.ID {
		return
	}

	// Store the SessionID for later use.
	s.Voice.userID = self.ID // TODO: Review
	s.Voice.sessionID = st.SessionID
}

// onVoiceServerUpdate handles the Voice Server Update data websocket event.
// This event tells us the information needed to open a voice websocket
// connection and should happen after the VOICE_STATE event.
//
// This is also fired if the Guild's voice region changes while connected
// to a voice channel.  In that case, need to re-establish connection to
// the new region endpoint.
func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) {

	// Store values for later use
	s.Voice.token = st.Token
	s.Voice.endpoint = st.Endpoint
	s.Voice.guildID = st.GuildID

	// We now have enough information to open a voice websocket conenction
	// so, that's what the next call does.
	err := s.Voice.Open()
	if err != nil {
		fmt.Println("onVoiceServerUpdate Voice.Open error: ", err)
		// TODO better logging
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/sclevine/agouti"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

const fixturesPath = "test_fixtures"

var baseURL string

type acceptanceTestSuite struct {
	suite.Suite
	driver *agouti.WebDriver
	page   *agouti.Page
}

func TestAcceptanceTests(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping acceptance tests in short mode.")
	}
	suite.Run(t, new(acceptanceTestSuite))
}

func (s *acceptanceTestSuite) SetupSuite() {
	var err error

	baseURL = fmt.Sprintf("https://%s/", config.addr)

	config.gitHubClientID = "abc"
	config.gitHubClientSecret = "xyz"
	config.tlsCert = filepath.Join(fixturesPath, "cert.pem")
	config.tlsKey = filepath.Join(fixturesPath, "key.pem")

	go main()

	s.driver = agouti.NewWebDriver("http://{{.Address}}", []string{"phantomjs", "--webdriver={{.Address}}", "--ignore-ssl-errors=true"})
	s.driver.Start()

	s.page, err = s.driver.NewPage(agouti.Desired(agouti.NewCapabilities().Browser("chrome")))
	if err != nil {
		s.T().Error(err)
	}

	// don't verify our development TLS certificates
	http.DefaultTransport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	// Make sure server is actually running (see go main() call above) before
	// running tests to avoid race conditions
	for {
		_, err := http.Get(baseURL)

		if err == nil {
			break
		} else {
			switch err.(type) {
			case *url.Error:
				if strings.HasSuffix(err.Error(), "connection refused") {
					time.Sleep(500 * time.Millisecond)
					continue
				}
			default:
				s.T().Error(err)
				break
			}
		}
	}
}

func (s *acceptanceTestSuite) TearDownSuite() {
	s.driver.Stop()
}

func (s *acceptanceTestSuite) TestDebugVarsExposed() {
	testURL := baseURL + "debug/vars"
	err := s.page.Navigate(testURL)

	if err != nil {
		s.T().Error(err)
	}

	bodyText, err := s.page.Find("body").Text()
	if err != nil {
		s.T().Error(err)
	}

	u, _ := s.page.URL()
	assert.Equal(s.T(), testURL, u)

	assert.Contains(s.T(), bodyText, "cmdline")
	assert.Contains(s.T(), bodyText, "memstats")
}

func (s *acceptanceTestSuite) TestHomePageForJavascriptErrors() {
	testURL := baseURL
	err := s.page.Navigate(testURL)
	if err != nil {
		s.T().Error(err)
	}

	logs, err := s.page.ReadAllLogs("browser")
	if err != nil {
		s.T().Error(err)
	}

	u, _ := s.page.URL()
	assert.Equal(s.T(), testURL, u)

	for _, log := range logs {
		assert.NotEqual(s.T(), "WARNING", log.Level, log.Message)
		assert.NotEqual(s.T(), "SEVERE", log.Level, log.Message)
	}
}

func (s *acceptanceTestSuite) TestPageNotFound() {
	resp, err := http.Get(baseURL + "non-existentent-page")
	if err != nil {
		s.T().Error(err)
	}

	assert.Equal(s.T(), http.StatusNotFound, resp.StatusCode)
}
<commit_msg>Change TestDebugVarsExposed to use net/http client<commit_after>package main

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/sclevine/agouti"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/suite"
)

const fixturesPath = "test_fixtures"

var baseURL string

type acceptanceTestSuite struct {
	suite.Suite
	driver *agouti.WebDriver
	page   *agouti.Page
}

func TestAcceptanceTests(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping acceptance tests in short mode.")
	}
	suite.Run(t, new(acceptanceTestSuite))
}

func (s *acceptanceTestSuite) SetupSuite() {
	var err error

	baseURL = fmt.Sprintf("https://%s/", config.addr)

	config.gitHubClientID = "abc"
	config.gitHubClientSecret = "xyz"
	config.tlsCert = filepath.Join(fixturesPath, "cert.pem")
	config.tlsKey = filepath.Join(fixturesPath, "key.pem")

	go main()

	s.driver = agouti.NewWebDriver("http://{{.Address}}", []string{"phantomjs", "--webdriver={{.Address}}", "--ignore-ssl-errors=true"})
	s.driver.Start()

	s.page, err = s.driver.NewPage(agouti.Desired(agouti.NewCapabilities().Browser("chrome")))
	if err != nil {
		s.T().Error(err)
	}

	// don't verify our development TLS certificates
	http.DefaultTransport = &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}

	// Make sure server is actually running (see go main() call above) before
	// running tests to avoid race conditions
	for {
		_, err := http.Get(baseURL)

		if err == nil {
			break
		} else {
			switch err.(type) {
			case *url.Error:
				if strings.HasSuffix(err.Error(), "connection refused") {
					time.Sleep(500 * time.Millisecond)
					continue
				}
			default:
				s.T().Error(err)
				break
			}
		}
	}
}

func (s *acceptanceTestSuite) TearDownSuite() {
	s.driver.Stop()
}

func (s *acceptanceTestSuite) TestDebugVarsExposed() {
	testURL := baseURL + "debug/vars"
	resp, err := http.Get(testURL)
	if err != nil {
		s.T().Error(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		s.T().Error(err)
	}

	assert.Contains(s.T(), string(body), "cmdline")
	assert.Contains(s.T(), string(body), "memstats")
}

func (s *acceptanceTestSuite) TestHomePageForJavascriptErrors() {
	testURL := baseURL
	err := s.page.Navigate(testURL)
	if err != nil {
		s.T().Error(err)
	}

	logs, err := s.page.ReadAllLogs("browser")
	if err != nil {
		s.T().Error(err)
	}

	u, _ := s.page.URL()
	assert.Equal(s.T(), testURL, u)

	for _, log := range logs {
		assert.NotEqual(s.T(), "WARNING", log.Level, log.Message)
		assert.NotEqual(s.T(), "SEVERE", log.Level, log.Message)
	}
}

func (s *acceptanceTestSuite) TestPageNotFound() {
	resp, err := http.Get(baseURL + "non-existentent-page")
	if err != nil {
		s.T().Error(err)
	}

	assert.Equal(s.T(), http.StatusNotFound, resp.StatusCode)
}
<|endoftext|>


<commit_before>// Package wrand provides a way to choose random items where each item has it's own
// weight. For example if item "a" has weight 1 and item "b" has weight 2 then "b
// will be selected about twice as often as "a".
package wrand

import (
	"math/rand"
	"sort"
)

// The Item type holds the user's value
type Item interface {
	Weight() int
	WeightIs(int)
	CumWeight() int
	CumWeightIs(int)
}

// The Object type is the collection that holds all the items choos from.
type Object struct {
	pool itemPool
	totalWeight int
	inverse bool
}

// NewObject creates and returns a new Object to work with. If inverse is true then
// smaller weights are more likely.
func NewObject(inverse bool) *Object {
	return &Object{make(itemPool, 0),  0, inverse}
}

// NewItem adds a new Item to the Object with ithe given value and weight. It returns
// a pointer to the newly created Item.
func (o *Object) NewItem(item Item) {
	// O(n)
	o.pool = append(o.pool, item)
	o.update()
}

// updateItemWeight, as the name suggests, sets the given Item's weight to the value
// provided. You should use this instead of setting the Item's weight yourself.
func (o *Object) UpdateItemWeight(item Item, weight int) {
	// O(n)
	item.WeightIs(weight)
	o.update()
}

func (o *Object) update() {
	maxWeight := 0
	for _, item := range o.pool {
		if item.Weight() > maxWeight {
			maxWeight = item.Weight()
		}
	}
	cumWeight := 0
	for _, item := range o.pool {
		w := item.Weight()
		if o.inverse {
			w = maxWeight - w + 1
		}
		cumWeight += w
		item.CumWeightIs(cumWeight)
	}
	o.totalWeight = cumWeight
	sort.Sort(o.pool)
}

// RandomItem returns a printer to a random Item out of the ones that have been added
// via NewItem taking into account the weights of each item.
func (o *Object) RandomItem() Item {
	// O(log n)
	rnd := int(rand.Float64() * float64(o.totalWeight))
	i := sort.Search(o.pool.Len(), func(i int) bool { return o.pool[i].CumWeight() > rnd })
	return o.pool[i]
}

// itemPool is a sortable list of Items
type itemPool []Item

func (p itemPool) Len() int {
	return len(p)
}

func (p itemPool) Less(i, j int) bool {
	return p[i].CumWeight() < p[j].CumWeight()
}

func (p itemPool) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
<commit_msg>Update/fix documentation.<commit_after>// Package wrand provides a way to choose random items where each item has it's own
// weight. For example if item "a" has weight 1 and item "b" has weight 2 then "b
// will be selected about twice as often as "a".
package wrand

import (
	"math/rand"
	"sort"
)

// The Item type holds the user's value
type Item interface {
	Weight() int
	WeightIs(int)
	CumWeight() int
	CumWeightIs(int)
}

// The Object type is the collection that holds all the items choose from.
type Object struct {
	pool itemPool
	totalWeight int
	inverse bool
}

// NewObject creates and returns a new Object to work with. If inverse is true then
// smaller weights are more likely.
func NewObject(inverse bool) *Object {
	return &Object{make(itemPool, 0),  0, inverse}
}

// NewItem adds a new Item to the Object with ithe given value and weight.
func (o *Object) NewItem(item Item) {
	// O(n)
	o.pool = append(o.pool, item)
	o.update()
}

// updateItemWeight, as the name suggests, sets the given Item's weight to the value
// provided. You should use this instead of setting the Item's weight yourself.
func (o *Object) UpdateItemWeight(item Item, weight int) {
	// O(n)
	item.WeightIs(weight)
	o.update()
}

func (o *Object) update() {
	maxWeight := 0
	for _, item := range o.pool {
		if item.Weight() > maxWeight {
			maxWeight = item.Weight()
		}
	}
	cumWeight := 0
	for _, item := range o.pool {
		w := item.Weight()
		if o.inverse {
			w = maxWeight - w + 1
		}
		cumWeight += w
		item.CumWeightIs(cumWeight)
	}
	o.totalWeight = cumWeight
	sort.Sort(o.pool)
}

// RandomItem returns a random Item out of the ones that have been added via NewItem
// taking into account the weights of each item.
func (o *Object) RandomItem() Item {
	// O(log n)
	rnd := int(rand.Float64() * float64(o.totalWeight))
	i := sort.Search(o.pool.Len(), func(i int) bool { return o.pool[i].CumWeight() > rnd })
	return o.pool[i]
}

// itemPool is a sortable list of Items
type itemPool []Item

func (p itemPool) Len() int {
	return len(p)
}

func (p itemPool) Less(i, j int) bool {
	return p[i].CumWeight() < p[j].CumWeight()
}

func (p itemPool) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
<|endoftext|>