<commit_before>package sdl

// #include "sdl_wrapper.h"
import "C"
import "unsafe"

const (
	AUDIO_MASK_BITSIZE  = C.SDL_AUDIO_MASK_BITSIZE
	AUDIO_MASK_DATATYPE = C.SDL_AUDIO_MASK_DATATYPE
	AUDIO_MASK_ENDIAN   = C.SDL_AUDIO_MASK_ENDIAN
	AUDIO_MASK_SIGNED   = C.SDL_AUDIO_MASK_SIGNED
)

const (
	AUDIO_U8     = C.AUDIO_U8
	AUDIO_S8     = C.AUDIO_S8
	AUDIO_U16LSB = C.AUDIO_U16LSB
	AUDIO_S16LSB = C.AUDIO_S16LSB
	AUDIO_U16MSB = C.AUDIO_U16MSB
	AUDIO_S16MSB = C.AUDIO_S16MSB
	AUDIO_U16    = C.AUDIO_U16
	AUDIO_S16    = C.AUDIO_S16
	AUDIO_S32LSB = C.AUDIO_S32LSB
	AUDIO_S32MSB = C.AUDIO_S32MSB
	AUDIO_S32    = C.AUDIO_S32
	AUDIO_F32LSB = C.AUDIO_F32LSB
	AUDIO_F32MSB = C.AUDIO_F32MSB
	AUDIO_F32    = C.AUDIO_F32
	AUDIO_U16SYS = C.AUDIO_U16SYS
	AUDIO_S16SYS = C.AUDIO_S16SYS
	AUDIO_S32SYS = C.AUDIO_S32SYS
	AUDIO_F32SYS = C.AUDIO_F32SYS
)

const (
	AUDIO_ALLOW_FREQUENCY_CHANGE = C.SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
	AUDIO_ALLOW_FORMAT_CHANGE    = C.SDL_AUDIO_ALLOW_FORMAT_CHANGE
	AUDIO_ALLOW_CHANNELS_CHANGE  = C.SDL_AUDIO_ALLOW_CHANNELS_CHANGE
	AUDIO_ALLOW_ANY_CHANGE       = C.SDL_AUDIO_ALLOW_ANY_CHANGE
)

const (
	AUDIO_STOPPED = C.SDL_AUDIO_STOPPED
	AUDIO_PLAYING = C.SDL_AUDIO_PLAYING
	AUDIO_PAUSED  = C.SDL_AUDIO_PAUSED
)

const MIX_MAXVOLUME = C.SDL_MIX_MAXVOLUME

// AudioFormat (https://wiki.libsdl.org/SDL_AudioFormat)
type AudioFormat uint16
type AudioCallback C.SDL_AudioCallback
type AudioFilter C.SDL_AudioFilter
type AudioDeviceID uint32

// AudioStatus (https://wiki.libsdl.org/SDL_AudioStatus)
type AudioStatus uint

// AudioSpec (https://wiki.libsdl.org/SDL_AudioSpec)
type AudioSpec struct {
	Freq     int32
	Format   AudioFormat
	Channels uint8
	Silence  uint8
	Samples  uint16
	Padding  uint16
	Size     uint32
	Callback AudioCallback
	UserData unsafe.Pointer
}
type cAudioSpec C.SDL_AudioSpec

// AudioCVT (https://wiki.libsdl.org/SDL_AudioCVT)
type AudioCVT struct {
	Needed      int32
	SrcFormat   AudioFormat
	DstFormat   AudioFormat
	RateIncr    float64
	Buf         *uint8
	Len         int32
	LenCVT      int32
	LenMult     int32
	LenRatio    float64
	filters     [10]AudioFilter // internal
	filterIndex int32           // internal
}
type cAudioCVT C.SDL_AudioCVT

func (fmt AudioFormat) c() C.SDL_AudioFormat {
	return C.SDL_AudioFormat(fmt)
}

func (id AudioDeviceID) c() C.SDL_AudioDeviceID {
	return C.SDL_AudioDeviceID(id)
}

func (as *AudioSpec) cptr() *C.SDL_AudioSpec {
	return (*C.SDL_AudioSpec)(unsafe.Pointer(as))
}

func (cvt *AudioCVT) cptr() *C.SDL_AudioCVT {
	return (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
}

func (format AudioFormat) BitSize() uint8 {
	return uint8(format & AUDIO_MASK_BITSIZE)
}

func (format AudioFormat) IsFloat() bool {
	return (format & AUDIO_MASK_DATATYPE) > 0
}

func (format AudioFormat) IsBigEndian() bool {
	return (format & AUDIO_MASK_ENDIAN) > 0
}

func (format AudioFormat) IsSigned() bool {
	return (format & AUDIO_MASK_SIGNED) > 0
}

func (format AudioFormat) IsInt() bool {
	return !format.IsFloat()
}

func (format AudioFormat) IsLittleEndian() bool {
	return !format.IsBigEndian()
}

func (format AudioFormat) IsUnsigned() bool {
	return !format.IsSigned()
}

// GetNumAudioDrivers (https://wiki.libsdl.org/SDL_GetNumAudioDrivers)
func GetNumAudioDrivers() int {
	return int(C.SDL_GetNumAudioDrivers())
}

// GetAudioDriver (https://wiki.libsdl.org/SDL_GetAudioDriver)
func GetAudioDriver(index int) string {
	return string(C.GoString(C.SDL_GetAudioDriver(C.int(index))))
}

// AudioInit (https://wiki.libsdl.org/SDL_AudioInit)
func AudioInit(driverName string) int {
	_driverName := C.CString(driverName)
	defer C.free(unsafe.Pointer(_driverName))
	return int(C.SDL_AudioInit(_driverName))
}

// AudioQuit (https://wiki.libsdl.org/SDL_AudioQuit)
func AudioQuit() {
	C.SDL_AudioQuit()
}

// GetCurrentAudioDriver (https://wiki.libsdl.org/SDL_GetCurrentAudioDriver)
func GetCurrentAudioDriver() string {
	return string(C.GoString(C.SDL_GetCurrentAudioDriver()))
}

// OpenAudio (https://wiki.libsdl.org/SDL_OpenAudio)
func OpenAudio(desired, obtained *AudioSpec) int {
	return int(C.SDL_OpenAudio(desired.cptr(), obtained.cptr()))
}

// GetNumAudioDevices (https://wiki.libsdl.org/SDL_GetNumAudioDevices)
func GetNumAudioDevices(isCapture int) int {
	return int(C.SDL_GetNumAudioDevices(C.int(isCapture)))
}

// GetAudioDeviceName (https://wiki.libsdl.org/SDL_GetAudioDeviceName)
func GetAudioDeviceName(index, isCapture int) string {
	return string(C.GoString(C.SDL_GetAudioDeviceName(C.int(index), C.int(isCapture))))
}

// OpenAudioDevice (https://wiki.libsdl.org/SDL_OpenAudioDevice)
func OpenAudioDevice(device string, isCapture int, desired, obtained *AudioSpec, allowedChanges int) int {
	_device := C.CString(device)
	defer C.free(unsafe.Pointer(_device))
	return int(C.SDL_OpenAudioDevice(_device, C.int(isCapture), desired.cptr(), obtained.cptr(), C.int(allowedChanges)))
}

// GetAudioStatus (https://wiki.libsdl.org/SDL_GetAudioStatus)
func GetAudioStatus() AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioStatus())
}

// GetAudioDeviceStatus (https://wiki.libsdl.org/SDL_GetAudioDeviceStatus)
func GetAudioDeviceStatus(dev AudioDeviceID) AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioDeviceStatus(dev.c()))
}

// PauseAudio (https://wiki.libsdl.org/SDL_PauseAudio)
func PauseAudio(pauseOn int) {
	C.SDL_PauseAudio(C.int(pauseOn))
}

// PauseAudioDevice (https://wiki.libsdl.org/SDL_PauseAudioDevice)
func PauseAudioDevice(dev AudioDeviceID, pauseOn int) {
	C.SDL_PauseAudioDevice(dev.c(), C.int(pauseOn))
}

// LoadWAV_RW (https://wiki.libsdl.org/SDL_LoadWAV_RW)
func LoadWAV_RW(src *RWops, freeSrc int, spec *AudioSpec, audioBuf **uint8, audioLen *uint32) *AudioSpec {
	_audioBuf := (**C.Uint8)(unsafe.Pointer(audioBuf))
	_audioLen := (*C.Uint32)(unsafe.Pointer(audioLen))
	return (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(src.cptr(), C.int(freeSrc), spec.cptr(), _audioBuf, _audioLen)))
}

// LoadWAV (https://wiki.libsdl.org/SDL_LoadWAV)
func LoadWAV(file string, spec *AudioSpec, audioBuf **uint8, audioLen *uint32) *AudioSpec {
	_file := C.CString(file)
	_rb := C.CString("rb")
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_rb))
	_audioBuf := (**C.Uint8)(unsafe.Pointer(audioBuf))
	_audioLen := (*C.Uint32)(unsafe.Pointer(audioLen))
	return (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(C.SDL_RWFromFile(_file, _rb), 1, spec.cptr(), _audioBuf, _audioLen)))
}

// FreeWAV (https://wiki.libsdl.org/SDL_FreeWAV)
func FreeWAV(audioBuf *uint8) {
	_audioBuf := (*C.Uint8)(unsafe.Pointer(audioBuf))
	C.SDL_FreeWAV(_audioBuf)
}

// BuildAudioCVT (https://wiki.libsdl.org/SDL_BuildAudioCVT)
func BuildAudioCVT(cvt *AudioCVT, srcFormat AudioFormat, srcChannels uint8, srcRate int, dstFormat AudioFormat, dstChannels uint8, dstRate int) int {
	return int(C.SDL_BuildAudioCVT(cvt.cptr(), srcFormat.c(), C.Uint8(srcChannels), C.int(srcRate), dstFormat.c(), C.Uint8(dstChannels), C.int(dstRate)))
}

// ConvertAudio (https://wiki.libsdl.org/SDL_ConvertAudio)
func ConvertAudio(cvt *AudioCVT) int {
	_cvt := (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
	return int(C.SDL_ConvertAudio(_cvt))
}

// MixAudio (https://wiki.libsdl.org/SDL_MixAudio)
func MixAudio(dst, src *uint8, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudio(_dst, _src, C.Uint32(len_), C.int(volume))
}

// MixAudioFormat (https://wiki.libsdl.org/SDL_MixAudioFormat)
func MixAudioFormat(dst, src *uint8, format AudioFormat, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudioFormat(_dst, _src, format.c(), C.Uint32(len_), C.int(volume))
}

// LockAudio (https://wiki.libsdl.org/SDL_LockAudio)
func LockAudio() {
	C.SDL_LockAudio()
}

// LockAudioDevice (https://wiki.libsdl.org/SDL_LockAudioDevice)
func LockAudioDevice(dev AudioDeviceID) {
	C.SDL_LockAudioDevice(dev.c())
}

// UnlockAudio (https://wiki.libsdl.org/SDL_UnlockAudio)
func UnlockAudio() {
	C.SDL_UnlockAudio()
}

// UnlockAudioDevice (https://wiki.libsdl.org/SDL_UnlockAudioDevice)
func UnlockAudioDevice(dev AudioDeviceID) {
	C.SDL_UnlockAudioDevice(dev.c())
}

// CloseAudio (https://wiki.libsdl.org/SDL_CloseAudio)
func CloseAudio() {
	C.SDL_UnlockAudio()
}

// CloseAudioDevice (https://wiki.libsdl.org/SDL_CloseAudioDevice)
func CloseAudioDevice(dev AudioDeviceID) {
	C.SDL_CloseAudioDevice(dev.c())
}

/*
func AudioDeviceConnected(dev AudioDeviceID) int {
	_dev := (C.SDL_AudioDeviceID) (dev)
	return int (C.SDL_AudioDeviceConnected(_dev))
}
*/
<commit_msg>audio: fix function call<commit_after>package sdl

// #include "sdl_wrapper.h"
import "C"
import "unsafe"

const (
	AUDIO_MASK_BITSIZE  = C.SDL_AUDIO_MASK_BITSIZE
	AUDIO_MASK_DATATYPE = C.SDL_AUDIO_MASK_DATATYPE
	AUDIO_MASK_ENDIAN   = C.SDL_AUDIO_MASK_ENDIAN
	AUDIO_MASK_SIGNED   = C.SDL_AUDIO_MASK_SIGNED
)

const (
	AUDIO_U8     = C.AUDIO_U8
	AUDIO_S8     = C.AUDIO_S8
	AUDIO_U16LSB = C.AUDIO_U16LSB
	AUDIO_S16LSB = C.AUDIO_S16LSB
	AUDIO_U16MSB = C.AUDIO_U16MSB
	AUDIO_S16MSB = C.AUDIO_S16MSB
	AUDIO_U16    = C.AUDIO_U16
	AUDIO_S16    = C.AUDIO_S16
	AUDIO_S32LSB = C.AUDIO_S32LSB
	AUDIO_S32MSB = C.AUDIO_S32MSB
	AUDIO_S32    = C.AUDIO_S32
	AUDIO_F32LSB = C.AUDIO_F32LSB
	AUDIO_F32MSB = C.AUDIO_F32MSB
	AUDIO_F32    = C.AUDIO_F32
	AUDIO_U16SYS = C.AUDIO_U16SYS
	AUDIO_S16SYS = C.AUDIO_S16SYS
	AUDIO_S32SYS = C.AUDIO_S32SYS
	AUDIO_F32SYS = C.AUDIO_F32SYS
)

const (
	AUDIO_ALLOW_FREQUENCY_CHANGE = C.SDL_AUDIO_ALLOW_FREQUENCY_CHANGE
	AUDIO_ALLOW_FORMAT_CHANGE    = C.SDL_AUDIO_ALLOW_FORMAT_CHANGE
	AUDIO_ALLOW_CHANNELS_CHANGE  = C.SDL_AUDIO_ALLOW_CHANNELS_CHANGE
	AUDIO_ALLOW_ANY_CHANGE       = C.SDL_AUDIO_ALLOW_ANY_CHANGE
)

const (
	AUDIO_STOPPED = C.SDL_AUDIO_STOPPED
	AUDIO_PLAYING = C.SDL_AUDIO_PLAYING
	AUDIO_PAUSED  = C.SDL_AUDIO_PAUSED
)

const MIX_MAXVOLUME = C.SDL_MIX_MAXVOLUME

// AudioFormat (https://wiki.libsdl.org/SDL_AudioFormat)
type AudioFormat uint16
type AudioCallback C.SDL_AudioCallback
type AudioFilter C.SDL_AudioFilter
type AudioDeviceID uint32

// AudioStatus (https://wiki.libsdl.org/SDL_AudioStatus)
type AudioStatus uint

// AudioSpec (https://wiki.libsdl.org/SDL_AudioSpec)
type AudioSpec struct {
	Freq     int32
	Format   AudioFormat
	Channels uint8
	Silence  uint8
	Samples  uint16
	Padding  uint16
	Size     uint32
	Callback AudioCallback
	UserData unsafe.Pointer
}
type cAudioSpec C.SDL_AudioSpec

// AudioCVT (https://wiki.libsdl.org/SDL_AudioCVT)
type AudioCVT struct {
	Needed      int32
	SrcFormat   AudioFormat
	DstFormat   AudioFormat
	RateIncr    float64
	Buf         *uint8
	Len         int32
	LenCVT      int32
	LenMult     int32
	LenRatio    float64
	filters     [10]AudioFilter // internal
	filterIndex int32           // internal
}
type cAudioCVT C.SDL_AudioCVT

func (fmt AudioFormat) c() C.SDL_AudioFormat {
	return C.SDL_AudioFormat(fmt)
}

func (id AudioDeviceID) c() C.SDL_AudioDeviceID {
	return C.SDL_AudioDeviceID(id)
}

func (as *AudioSpec) cptr() *C.SDL_AudioSpec {
	return (*C.SDL_AudioSpec)(unsafe.Pointer(as))
}

func (cvt *AudioCVT) cptr() *C.SDL_AudioCVT {
	return (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
}

func (format AudioFormat) BitSize() uint8 {
	return uint8(format & AUDIO_MASK_BITSIZE)
}

func (format AudioFormat) IsFloat() bool {
	return (format & AUDIO_MASK_DATATYPE) > 0
}

func (format AudioFormat) IsBigEndian() bool {
	return (format & AUDIO_MASK_ENDIAN) > 0
}

func (format AudioFormat) IsSigned() bool {
	return (format & AUDIO_MASK_SIGNED) > 0
}

func (format AudioFormat) IsInt() bool {
	return !format.IsFloat()
}

func (format AudioFormat) IsLittleEndian() bool {
	return !format.IsBigEndian()
}

func (format AudioFormat) IsUnsigned() bool {
	return !format.IsSigned()
}

// GetNumAudioDrivers (https://wiki.libsdl.org/SDL_GetNumAudioDrivers)
func GetNumAudioDrivers() int {
	return int(C.SDL_GetNumAudioDrivers())
}

// GetAudioDriver (https://wiki.libsdl.org/SDL_GetAudioDriver)
func GetAudioDriver(index int) string {
	return string(C.GoString(C.SDL_GetAudioDriver(C.int(index))))
}

// AudioInit (https://wiki.libsdl.org/SDL_AudioInit)
func AudioInit(driverName string) int {
	_driverName := C.CString(driverName)
	defer C.free(unsafe.Pointer(_driverName))
	return int(C.SDL_AudioInit(_driverName))
}

// AudioQuit (https://wiki.libsdl.org/SDL_AudioQuit)
func AudioQuit() {
	C.SDL_AudioQuit()
}

// GetCurrentAudioDriver (https://wiki.libsdl.org/SDL_GetCurrentAudioDriver)
func GetCurrentAudioDriver() string {
	return string(C.GoString(C.SDL_GetCurrentAudioDriver()))
}

// OpenAudio (https://wiki.libsdl.org/SDL_OpenAudio)
func OpenAudio(desired, obtained *AudioSpec) int {
	return int(C.SDL_OpenAudio(desired.cptr(), obtained.cptr()))
}

// GetNumAudioDevices (https://wiki.libsdl.org/SDL_GetNumAudioDevices)
func GetNumAudioDevices(isCapture int) int {
	return int(C.SDL_GetNumAudioDevices(C.int(isCapture)))
}

// GetAudioDeviceName (https://wiki.libsdl.org/SDL_GetAudioDeviceName)
func GetAudioDeviceName(index, isCapture int) string {
	return string(C.GoString(C.SDL_GetAudioDeviceName(C.int(index), C.int(isCapture))))
}

// OpenAudioDevice (https://wiki.libsdl.org/SDL_OpenAudioDevice)
func OpenAudioDevice(device string, isCapture int, desired, obtained *AudioSpec, allowedChanges int) int {
	_device := C.CString(device)
	defer C.free(unsafe.Pointer(_device))
	return int(C.SDL_OpenAudioDevice(_device, C.int(isCapture), desired.cptr(), obtained.cptr(), C.int(allowedChanges)))
}

// GetAudioStatus (https://wiki.libsdl.org/SDL_GetAudioStatus)
func GetAudioStatus() AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioStatus())
}

// GetAudioDeviceStatus (https://wiki.libsdl.org/SDL_GetAudioDeviceStatus)
func GetAudioDeviceStatus(dev AudioDeviceID) AudioStatus {
	return (AudioStatus)(C.SDL_GetAudioDeviceStatus(dev.c()))
}

// PauseAudio (https://wiki.libsdl.org/SDL_PauseAudio)
func PauseAudio(pauseOn int) {
	C.SDL_PauseAudio(C.int(pauseOn))
}

// PauseAudioDevice (https://wiki.libsdl.org/SDL_PauseAudioDevice)
func PauseAudioDevice(dev AudioDeviceID, pauseOn int) {
	C.SDL_PauseAudioDevice(dev.c(), C.int(pauseOn))
}

// LoadWAV_RW (https://wiki.libsdl.org/SDL_LoadWAV_RW)
func LoadWAV_RW(src *RWops, freeSrc int, spec *AudioSpec, audioBuf **uint8, audioLen *uint32) *AudioSpec {
	_audioBuf := (**C.Uint8)(unsafe.Pointer(audioBuf))
	_audioLen := (*C.Uint32)(unsafe.Pointer(audioLen))
	return (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(src.cptr(), C.int(freeSrc), spec.cptr(), _audioBuf, _audioLen)))
}

// LoadWAV (https://wiki.libsdl.org/SDL_LoadWAV)
func LoadWAV(file string, spec *AudioSpec, audioBuf **uint8, audioLen *uint32) *AudioSpec {
	_file := C.CString(file)
	_rb := C.CString("rb")
	defer C.free(unsafe.Pointer(_file))
	defer C.free(unsafe.Pointer(_rb))
	_audioBuf := (**C.Uint8)(unsafe.Pointer(audioBuf))
	_audioLen := (*C.Uint32)(unsafe.Pointer(audioLen))
	return (*AudioSpec)(unsafe.Pointer(C.SDL_LoadWAV_RW(C.SDL_RWFromFile(_file, _rb), 1, spec.cptr(), _audioBuf, _audioLen)))
}

// FreeWAV (https://wiki.libsdl.org/SDL_FreeWAV)
func FreeWAV(audioBuf *uint8) {
	_audioBuf := (*C.Uint8)(unsafe.Pointer(audioBuf))
	C.SDL_FreeWAV(_audioBuf)
}

// BuildAudioCVT (https://wiki.libsdl.org/SDL_BuildAudioCVT)
func BuildAudioCVT(cvt *AudioCVT, srcFormat AudioFormat, srcChannels uint8, srcRate int, dstFormat AudioFormat, dstChannels uint8, dstRate int) int {
	return int(C.SDL_BuildAudioCVT(cvt.cptr(), srcFormat.c(), C.Uint8(srcChannels), C.int(srcRate), dstFormat.c(), C.Uint8(dstChannels), C.int(dstRate)))
}

// ConvertAudio (https://wiki.libsdl.org/SDL_ConvertAudio)
func ConvertAudio(cvt *AudioCVT) int {
	_cvt := (*C.SDL_AudioCVT)(unsafe.Pointer(cvt))
	return int(C.SDL_ConvertAudio(_cvt))
}

// MixAudio (https://wiki.libsdl.org/SDL_MixAudio)
func MixAudio(dst, src *uint8, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudio(_dst, _src, C.Uint32(len_), C.int(volume))
}

// MixAudioFormat (https://wiki.libsdl.org/SDL_MixAudioFormat)
func MixAudioFormat(dst, src *uint8, format AudioFormat, len_ uint32, volume int) {
	_dst := (*C.Uint8)(unsafe.Pointer(dst))
	_src := (*C.Uint8)(unsafe.Pointer(src))
	C.SDL_MixAudioFormat(_dst, _src, format.c(), C.Uint32(len_), C.int(volume))
}

// LockAudio (https://wiki.libsdl.org/SDL_LockAudio)
func LockAudio() {
	C.SDL_LockAudio()
}

// LockAudioDevice (https://wiki.libsdl.org/SDL_LockAudioDevice)
func LockAudioDevice(dev AudioDeviceID) {
	C.SDL_LockAudioDevice(dev.c())
}

// UnlockAudio (https://wiki.libsdl.org/SDL_UnlockAudio)
func UnlockAudio() {
	C.SDL_UnlockAudio()
}

// UnlockAudioDevice (https://wiki.libsdl.org/SDL_UnlockAudioDevice)
func UnlockAudioDevice(dev AudioDeviceID) {
	C.SDL_UnlockAudioDevice(dev.c())
}

// CloseAudio (https://wiki.libsdl.org/SDL_CloseAudio)
func CloseAudio() {
	C.SDL_CloseAudio()
}

// CloseAudioDevice (https://wiki.libsdl.org/SDL_CloseAudioDevice)
func CloseAudioDevice(dev AudioDeviceID) {
	C.SDL_CloseAudioDevice(dev.c())
}

/*
func AudioDeviceConnected(dev AudioDeviceID) int {
	_dev := (C.SDL_AudioDeviceID) (dev)
	return int (C.SDL_AudioDeviceConnected(_dev))
}
*/
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2015 Jesse Sipprell <jessesipprell@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 */

// This package implements a low-overhead idiomatic sempahore for go.
//
// The sempahore is entirely channel based and does not use goroutines.
//
// There is a global version and locally allocatable version, neither uses
// mutexes but the global version does use a sync.WaitGroup for syncronization.
package semaphore // github.com/jsipprell/go-semaphore

import (
	"errors"
	"sync"
	"time"
)

// The basic interface:
//
//     if err := sem.Acquire(); err != nil {
//         if err == semaphore.ErrUnavailable {
//             // ... resource exhausted
//         }
//     } else {
//         defer sem.Release()
//     }
//
// Methods:
//
// Acquire() error - acquire one resource count in a race-safe fashion
// Release()       - release one previously acquired resource count
// Cap()           - return the total maximum resource capacity
//                   (note: NOT what is available/in-use)
type Semaphore interface {
	Acquire() error
	Release()
	Cap() int
}

// To perform blocking, use the WaitableSemaphore interface
//
//     if err := waitsem.Wait(time.Duration(3300)); err != nil {
//         if err == semaphore.ErrUnavailable {
//             // ... resource exhausted
//         }
//     } else {
//         defer sem.Release()
//     }
//
// Additional Methods:
//
// Wait(duration time.Duration) error
//     Waits up time `duration` for the resource to become available and then
//     returns ErrUnavailable. If duration is 0, waits indefinitely.
type WaitableSemaphore interface {
	Semaphore
	Wait(time.Duration) error
}

var (
	// ErrUnavailable is the only error condition returned by this package
	ErrUnavailable = errors.New("semaphore resource unavailable")

	globalSem = sharedSemaphore{simpleSemaphore: &simpleSemaphore{}}
)

type simpleSemaphore struct {
	c chan struct{}
	// NB: capacity is for informational purposes only
	cap int
}

type sharedSemaphore struct {
	*simpleSemaphore
	init sync.Once
	wg   *sync.WaitGroup
}

// Returns the capacity of a semaphore, which is the max number
// of countable resources, NOT what's in-use or remaining.
func (sem *simpleSemaphore) Cap() int {
	return sem.cap
}

// Acquire() one resource unit from the semaphore, *never* blocks,
// but returns ErrUnavailable if exhausted.
func (sem *simpleSemaphore) Acquire() (err error) {
	select {
	case <-sem.c:
	default:
		err = ErrUnavailable
	}
	return
}

// Release a previously required resource unit. It is an error to
// release a resource not obtained via Acquire()
func (sem *simpleSemaphore) Release() {
	sem.c <- struct{}{}
}

func initSem(sem Semaphore) {
	s := sem.(*simpleSemaphore)
	s.c = make(chan struct{}, s.cap)
	for i := 0; i < s.cap; i++ {
		s.c <- struct{}{}
	}
}

func init() {
	if !GlobalIsInitialized() && globalSem.wg != nil {
		wg := &sync.WaitGroup{}
		wg.Add(1)
		globalSem.wg = wg
	}
}

// Allocate a new private semaphore which can have Acquire()
// called on it `max` times without a matching Release() before it will
// return ErrUnavailable.
func New(max int) WaitableSemaphore {
	sem := &simpleSemaphore{cap: max}
	initSem(sem)
	return sem
}

// Returns the global shared semaphore, optionally initializing its
// maximum resource value (if this has not already been done)
func Global(max int) WaitableSemaphore {
	globalSem.init.Do(func() {
		if globalSem.wg == nil {
			wg := &sync.WaitGroup{}
			wg.Add(1)
			globalSem.wg = wg
		}
		defer globalSem.wg.Done()
		if max > -1 && globalSem.cap == 0 {
			globalSem.cap = max
		}
		initSem(globalSem.simpleSemaphore)
	})

	globalSem.wg.Wait()
	return globalSem
}

// Returns true if the global shared semaphore has already been initialized
func GlobalIsInitialized() bool {
	return globalSem.simpleSemaphore.c != nil && globalSem.wg != nil
}

// Wait for a sempahore to have at least one resource available and then
// Acquire() it. If the time.Duration argument is zero, blocks forever.
//
// If the timer expires before the semaphore has Release() called on it
// by another goroutine, returns ErrUnavailable.
func (sem *simpleSemaphore) Wait(t time.Duration) (err error) {
	var C <-chan time.Time
	if t == time.Duration(0) {
		C = make(<-chan time.Time)
	} else {
		C = time.After(t)
	}
	select {
	case <-sem.c:
	case <-C:
		err = ErrUnavailable
	}
	return
}
<commit_msg>canonicalization<commit_after>/*
 * Copyright (c) 2014-2015 Jesse Sipprell <jessesipprell@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 */

// This package implements a low-overhead idiomatic sempahore for go.
//
// The sempahore is entirely channel based and does not use goroutines.
//
// There is a global version and locally allocatable version, neither uses
// mutexes but the global version does use a sync.WaitGroup for syncronization.
package semaphore // "github.com/jsipprell/go-semaphore"

import (
	"errors"
	"sync"
	"time"
)

// The basic interface:
//
//     if err := sem.Acquire(); err != nil {
//         if err == semaphore.ErrUnavailable {
//             // ... resource exhausted
//         }
//     } else {
//         defer sem.Release()
//     }
//
// Methods:
//
// Acquire() error - acquire one resource count in a race-safe fashion
// Release()       - release one previously acquired resource count
// Cap()           - return the total maximum resource capacity
//                   (note: NOT what is available/in-use)
type Semaphore interface {
	Acquire() error
	Release()
	Cap() int
}

// To perform blocking, use the WaitableSemaphore interface
//
//     if err := waitsem.Wait(time.Duration(3300)); err != nil {
//         if err == semaphore.ErrUnavailable {
//             // ... resource exhausted
//         }
//     } else {
//         defer sem.Release()
//     }
//
// Additional Methods:
//
// Wait(duration time.Duration) error
//     Waits up time `duration` for the resource to become available and then
//     returns ErrUnavailable. If duration is 0, waits indefinitely.
type WaitableSemaphore interface {
	Semaphore
	Wait(time.Duration) error
}

var (
	// ErrUnavailable is the only error condition returned by this package
	ErrUnavailable = errors.New("semaphore resource unavailable")

	globalSem = sharedSemaphore{simpleSemaphore: &simpleSemaphore{}}
)

type simpleSemaphore struct {
	c chan struct{}
	// NB: capacity is for informational purposes only
	cap int
}

type sharedSemaphore struct {
	*simpleSemaphore
	init sync.Once
	wg   *sync.WaitGroup
}

// Returns the capacity of a semaphore, which is the max number
// of countable resources, NOT what's in-use or remaining.
func (sem *simpleSemaphore) Cap() int {
	return sem.cap
}

// Acquire() one resource unit from the semaphore, *never* blocks,
// but returns ErrUnavailable if exhausted.
func (sem *simpleSemaphore) Acquire() (err error) {
	select {
	case <-sem.c:
	default:
		err = ErrUnavailable
	}
	return
}

// Release a previously required resource unit. It is an error to
// release a resource not obtained via Acquire()
func (sem *simpleSemaphore) Release() {
	sem.c <- struct{}{}
}

func initSem(sem Semaphore) {
	s := sem.(*simpleSemaphore)
	s.c = make(chan struct{}, s.cap)
	for i := 0; i < s.cap; i++ {
		s.c <- struct{}{}
	}
}

func init() {
	if !GlobalIsInitialized() && globalSem.wg != nil {
		wg := &sync.WaitGroup{}
		wg.Add(1)
		globalSem.wg = wg
	}
}

// Allocate a new private semaphore which can have Acquire()
// called on it `max` times without a matching Release() before it will
// return ErrUnavailable.
func New(max int) WaitableSemaphore {
	sem := &simpleSemaphore{cap: max}
	initSem(sem)
	return sem
}

// Returns the global shared semaphore, optionally initializing its
// maximum resource value (if this has not already been done)
func Global(max int) WaitableSemaphore {
	globalSem.init.Do(func() {
		if globalSem.wg == nil {
			wg := &sync.WaitGroup{}
			wg.Add(1)
			globalSem.wg = wg
		}
		defer globalSem.wg.Done()
		if max > -1 && globalSem.cap == 0 {
			globalSem.cap = max
		}
		initSem(globalSem.simpleSemaphore)
	})

	globalSem.wg.Wait()
	return globalSem
}

// Returns true if the global shared semaphore has already been initialized
func GlobalIsInitialized() bool {
	return globalSem.simpleSemaphore.c != nil && globalSem.wg != nil
}

// Wait for a sempahore to have at least one resource available and then
// Acquire() it. If the time.Duration argument is zero, blocks forever.
//
// If the timer expires before the semaphore has Release() called on it
// by another goroutine, returns ErrUnavailable.
func (sem *simpleSemaphore) Wait(t time.Duration) (err error) {
	var C <-chan time.Time
	if t == time.Duration(0) {
		C = make(<-chan time.Time)
	} else {
		C = time.After(t)
	}
	select {
	case <-sem.c:
	case <-C:
		err = ErrUnavailable
	}
	return
}
<|endoftext|>


<commit_before>package session

import (
	"encoding/gob"
	"errors"
	"log"
	"net/url"

	"github.com/insionng/macross"
)

var GlobalSessions *Manager

var defaultOtions = Options{"memory", `{"cookieName":"MacrossSessionId","gcLifetime":3600}`}

//var defaultOtions = Options{"file", `{"cookieName":"MacrossSessionId","gcLifetime":3600,"providerConfig":"./data/session"}`}

//var defaultOtions = Options{"redis", `{"cookieName":"MacrossSessionId","gcLifetime":3600,"providerConfig":"127.0.0.1:6379"}`}

const (
	CONTEXT_SESSION_KEY = "_SESSION_STORE"
	COOKIE_FLASH_KEY    = "_COOKIE_FLASH"
	CONTEXT_FLASH_KEY   = "_FLASH_VALUE"
	SESSION_FLASH_KEY   = "_SESSION_FLASH"
	SESSION_INPUT_KEY   = "_SESSION_INPUT"
)

type Options struct {
	Provider string
	Config   string
}

func init() {
	gob.Register(url.Values{})
}

// setup 初始化并设置session配置
func setup(op ...Options) error {
	option := defaultOtions
	if len(op) > 0 {
		option = op[0]
	}

	if len(option.Provider) == 0 {
		option.Provider = defaultOtions.Provider
		option.Config = defaultOtions.Config
	}

	log.Println("Macross session config:", option)

	var err error
	GlobalSessions, err = NewManager(option.Provider, option.Config)
	if err != nil {
		return err
	}
	go GlobalSessions.GC()

	return nil
}

// Sessioner Macross session 中间件
func Sessioner(op ...Options) macross.Handler {
	if GlobalSessions == nil {
		if err := setup(op...); err != nil {
			log.Fatalln("session errors:", err)
		}
	}
	return func(c *macross.Context) error {
		if GlobalSessions == nil {
			return errors.New("session manager not found, use session middleware but not init ?")
		}

		sess, err := GlobalSessions.SessionStart(c)
		if err != nil {
			return err
		}

		c.Set(CONTEXT_FLASH_KEY, Flash{})
		flashVals := url.Values{}
		flashIf := sess.Get(SESSION_FLASH_KEY)
		if flashIf != nil {
			vals, _ := url.QueryUnescape(flashIf.(string))
			flashVals, _ = url.ParseQuery(vals)
			if len(flashVals) > 0 {
				flash := Flash{}
				flash.ErrorMsg = flashVals.Get("error")
				flash.WarningMsg = flashVals.Get("warning")
				flash.InfoMsg = flashVals.Get("info")
				flash.SuccessMsg = flashVals.Get("success")
				// flash先暂存到context里面
				c.Set(CONTEXT_FLASH_KEY, flash)

			}
		}

		f := NewFlash()
		sess.Set(SESSION_FLASH_KEY, f)
		c.Set(CONTEXT_SESSION_KEY, sess)

		defer func() {
			//log.Println("save session", sess)
			sess.Set(SESSION_FLASH_KEY, url.QueryEscape(f.Encode()))
			c.Session = sess
			sess.SessionRelease(c)
		}()

		return c.Next()
	}
}

func GetStore(c *macross.Context) Store {
	store := c.Get(CONTEXT_SESSION_KEY)
	if store != nil {
		return store.(Store)
	}
	return nil
}

func GetFlash(c *macross.Context) *Flash {
	if store := GetStore(c); store != nil {
		if tmp := store.Get(SESSION_FLASH_KEY); tmp != nil {
			return tmp.(*Flash)
		}
	}
	return NewFlash()
}

func FlashValue(c *macross.Context) Flash {
	if tmp := c.Get(CONTEXT_FLASH_KEY); tmp != nil {
		return tmp.(Flash)
	}
	return Flash{}
}

func SaveInput(c *macross.Context) {
	if store := GetStore(c); store != nil {
		store.Set(SESSION_INPUT_KEY, url.Values(c.FormParams()))
	}
}

func GetInput(c *macross.Context) url.Values {
	if store := GetStore(c); store != nil {
		input := store.Get(SESSION_INPUT_KEY)
		if input != nil {
			return input.(url.Values)
		}
	}
	return url.Values{}
}

func CleanInput(c *macross.Context) {
	if store := GetStore(c); store != nil {
		store.Set(SESSION_INPUT_KEY, url.Values{})
	}
}

func NewFlash() *Flash {
	return &Flash{url.Values{}, "", "", "", ""}
}

type Flash struct {
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string) {
	f.Set(name, msg)
}

func (f *Flash) Error(msg string) {
	f.ErrorMsg = msg
	f.set("error", msg)
}

func (f *Flash) Warning(msg string) {
	f.WarningMsg = msg
	f.set("warning", msg)
}

func (f *Flash) Info(msg string) {
	f.InfoMsg = msg
	f.set("info", msg)
}

func (f *Flash) Success(msg string) {
	f.SuccessMsg = msg
	f.set("success", msg)
}
<commit_msg>fixed flash<commit_after>package session

import (
	"encoding/gob"
	"errors"
	"log"
	"net/url"

	"github.com/insionng/macross"
)

var GlobalSessions *Manager

var defaultOtions = Options{"memory", `{"cookieName":"MacrossSessionId","gcLifetime":3600}`}

//var defaultOtions = Options{"file", `{"cookieName":"MacrossSessionId","gcLifetime":3600,"providerConfig":"./data/session"}`}

//var defaultOtions = Options{"redis", `{"cookieName":"MacrossSessionId","gcLifetime":3600,"providerConfig":"127.0.0.1:6379"}`}

const (
	CONTEXT_SESSION_KEY = "_SESSION_STORE"
	COOKIE_FLASH_KEY    = "_COOKIE_FLASH"
	CONTEXT_FLASH_KEY   = "_FLASH_VALUE"
	SESSION_FLASH_KEY   = "_SESSION_FLASH"
	SESSION_INPUT_KEY   = "_SESSION_INPUT"
)

type Options struct {
	Provider string
	Config   string
}

func init() {
	gob.Register(url.Values{})
}

// setup 初始化并设置session配置
func setup(op ...Options) error {
	option := defaultOtions
	if len(op) > 0 {
		option = op[0]
	}

	if len(option.Provider) == 0 {
		option.Provider = defaultOtions.Provider
		option.Config = defaultOtions.Config
	}

	log.Println("Macross session config:", option)

	var err error
	GlobalSessions, err = NewManager(option.Provider, option.Config)
	if err != nil {
		return err
	}
	go GlobalSessions.GC()

	return nil
}

// Sessioner Macross session 中间件
func Sessioner(op ...Options) macross.Handler {
	if GlobalSessions == nil {
		if err := setup(op...); err != nil {
			log.Fatalln("session errors:", err)
		}
	}
	return func(c *macross.Context) error {
		if GlobalSessions == nil {
			return errors.New("session manager not found, use session middleware but not init ?")
		}

		sess, err := GlobalSessions.SessionStart(c)
		if err != nil {
			return err
		}

		c.Session = sess
		c.Set(CONTEXT_FLASH_KEY, Flash{})

		flashVals := url.Values{}
		flashIf := sess.Get(SESSION_FLASH_KEY)
		if flashIf != nil {
			vals, _ := url.QueryUnescape(flashIf.(string))
			flashVals, _ = url.ParseQuery(vals)
			if len(flashVals) > 0 {
				flash := Flash{}
				flash.ErrorMsg = flashVals.Get("error")
				flash.WarningMsg = flashVals.Get("warning")
				flash.InfoMsg = flashVals.Get("info")
				flash.SuccessMsg = flashVals.Get("success")
				// flash先暂存到context里面
				c.Set(CONTEXT_FLASH_KEY, flash)

			}
		}

		f := NewFlash()
		sess.Set(SESSION_FLASH_KEY, f)
		c.Set(CONTEXT_SESSION_KEY, sess)

		defer func() {
			//log.Println("save session", sess)
			sess.Set(SESSION_FLASH_KEY, url.QueryEscape(f.Encode()))
			sess.SessionRelease(c)
		}()

		return c.Next()
	}
}

func GetStore(c *macross.Context) Store {
	store := c.Get(CONTEXT_SESSION_KEY)
	if store != nil {
		return store.(Store)
	}
	return nil
}

func GetFlash(c *macross.Context) *Flash {
	if store := GetStore(c); store != nil {
		if tmp := store.Get(SESSION_FLASH_KEY); tmp != nil {
			return tmp.(*Flash)
		}
	}
	return NewFlash()
}

func FlashValue(c *macross.Context) Flash {
	if tmp := c.Get(CONTEXT_FLASH_KEY); tmp != nil {
		return tmp.(Flash)
	}
	return Flash{}
}

func SaveInput(c *macross.Context) {
	if store := GetStore(c); store != nil {
		store.Set(SESSION_INPUT_KEY, url.Values(c.FormParams()))
	}
}

func GetInput(c *macross.Context) url.Values {
	if store := GetStore(c); store != nil {
		input := store.Get(SESSION_INPUT_KEY)
		if input != nil {
			return input.(url.Values)
		}
	}
	return url.Values{}
}

func CleanInput(c *macross.Context) {
	if store := GetStore(c); store != nil {
		store.Set(SESSION_INPUT_KEY, url.Values{})
	}
}

func NewFlash() *Flash {
	return &Flash{url.Values{}, "", "", "", ""}
}

type Flash struct {
	url.Values
	ErrorMsg, WarningMsg, InfoMsg, SuccessMsg string
}

func (f *Flash) set(name, msg string) {
	f.Set(name, msg)
}

func (f *Flash) Error(msg string) {
	f.ErrorMsg = msg
	f.set("error", msg)
}

func (f *Flash) Warning(msg string) {
	f.WarningMsg = msg
	f.set("warning", msg)
}

func (f *Flash) Info(msg string) {
	f.InfoMsg = msg
	f.set("info", msg)
}

func (f *Flash) Success(msg string) {
	f.SuccessMsg = msg
	f.set("success", msg)
}
<|endoftext|>


<commit_before>package docker

import (
	"github.com/dotcloud/docker/rcli"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"sync"
	"testing"
	"time"
)

// FIXME: this is no longer needed
const testLayerPath string = "/var/lib/docker/docker-ut.tar"
const unitTestImageName string = "docker-ut"

var unitTestStoreBase string

func nuke(runtime *Runtime) error {
	var wg sync.WaitGroup
	for _, container := range runtime.List() {
		wg.Add(1)
		go func(c *Container) {
			c.Kill()
			wg.Done()
		}(container)
	}
	wg.Wait()
	return os.RemoveAll(runtime.root)
}

func CopyDirectory(source, dest string) error {
	if _, err := exec.Command("cp", "-ra", source, dest).Output(); err != nil {
		return err
	}
	return nil
}

func layerArchive(tarfile string) (io.Reader, error) {
	// FIXME: need to close f somewhere
	f, err := os.Open(tarfile)
	if err != nil {
		return nil, err
	}
	return f, nil
}

func init() {
	NO_MEMORY_LIMIT = os.Getenv("NO_MEMORY_LIMIT") == "1"

	// Hack to run sys init during unit testing
	if SelfPath() == "/sbin/init" {
		SysInit()
		return
	}

	if usr, err := user.Current(); err != nil {
		panic(err)
	} else if usr.Uid != "0" {
		panic("docker tests needs to be run as root")
	}

	// Create a temp directory
	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		panic(err)
	}
	unitTestStoreBase = root

	// Make it our Store root
	runtime, err := NewRuntimeFromDirectory(root)
	if err != nil {
		panic(err)
	}
	// Create the "Server"
	srv := &Server{
		runtime: runtime,
	}
	// Retrieve the Image
	if err := srv.CmdPull(os.Stdin, rcli.NewDockerLocalConn(os.Stdout), unitTestImageName); err != nil {
		panic(err)
	}
}

func newTestRuntime() (*Runtime, error) {
	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		return nil, err
	}
	if err := os.Remove(root); err != nil {
		return nil, err
	}
	if err := CopyDirectory(unitTestStoreBase, root); err != nil {
		return nil, err
	}

	runtime, err := NewRuntimeFromDirectory(root)
	if err != nil {
		return nil, err
	}

	return runtime, nil
}

func GetTestImage(runtime *Runtime) *Image {
	imgs, err := runtime.graph.All()
	if err != nil {
		panic(err)
	} else if len(imgs) < 1 {
		panic("GASP")
	}
	return imgs[0]
}

func TestRuntimeCreate(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	// Make sure we start we 0 containers
	if len(runtime.List()) != 0 {
		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
	}
	container, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := runtime.Destroy(container); err != nil {
			t.Error(err)
		}
	}()

	// Make sure we can find the newly created container with List()
	if len(runtime.List()) != 1 {
		t.Errorf("Expected 1 container, %v found", len(runtime.List()))
	}

	// Make sure the container List() returns is the right one
	if runtime.List()[0].Id != container.Id {
		t.Errorf("Unexpected container %v returned by List", runtime.List()[0])
	}

	// Make sure we can get the container with Get()
	if runtime.Get(container.Id) == nil {
		t.Errorf("Unable to get newly created container")
	}

	// Make sure it is the right container
	if runtime.Get(container.Id) != container {
		t.Errorf("Get() returned the wrong container")
	}

	// Make sure Exists returns it as existing
	if !runtime.Exists(container.Id) {
		t.Errorf("Exists() returned false for a newly created container")
	}
}

func TestDestroy(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	container, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	// Destroy
	if err := runtime.Destroy(container); err != nil {
		t.Error(err)
	}

	// Make sure runtime.Exists() behaves correctly
	if runtime.Exists("test_destroy") {
		t.Errorf("Exists() returned true")
	}

	// Make sure runtime.List() doesn't list the destroyed container
	if len(runtime.List()) != 0 {
		t.Errorf("Expected 0 container, %v found", len(runtime.List()))
	}

	// Make sure runtime.Get() refuses to return the unexisting container
	if runtime.Get(container.Id) != nil {
		t.Errorf("Unable to get newly created container")
	}

	// Make sure the container root directory does not exist anymore
	_, err = os.Stat(container.root)
	if err == nil || !os.IsNotExist(err) {
		t.Errorf("Container root directory still exists after destroy")
	}

	// Test double destroy
	if err := runtime.Destroy(container); err == nil {
		// It should have failed
		t.Errorf("Double destroy did not fail")
	}
}

func TestGet(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	container1, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container1)

	container2, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container2)

	container3, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container3)

	if runtime.Get(container1.Id) != container1 {
		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.Id), container1)
	}

	if runtime.Get(container2.Id) != container2 {
		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.Id), container2)
	}

	if runtime.Get(container3.Id) != container3 {
		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.Id), container3)
	}

}

func TestRestore(t *testing.T) {

	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		t.Fatal(err)
	}
	if err := os.Remove(root); err != nil {
		t.Fatal(err)
	}
	if err := CopyDirectory(unitTestStoreBase, root); err != nil {
		t.Fatal(err)
	}

	runtime1, err := NewRuntimeFromDirectory(root)
	if err != nil {
		t.Fatal(err)
	}

	// Create a container with one instance of docker
	container1, err := runtime1.Create(&Config{
		Image: GetTestImage(runtime1).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime1.Destroy(container1)

	// Create a second container meant to be killed
	container2, err := runtime1.Create(&Config{
		Image:     GetTestImage(runtime1).Id,
		Cmd:       []string{"/bin/cat"},
		OpenStdin: true,
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime1.Destroy(container2)

	// Start the container non blocking
	if err := container2.Start(); err != nil {
		t.Fatal(err)
	}

	if !container2.State.Running {
		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
	}

	// Simulate a crash/manual quit of dockerd: process dies, states stays 'Running'
	cStdin, _ := container2.StdinPipe()
	cStdin.Close()
	if err := container2.WaitTimeout(2 * time.Second); err != nil {
		t.Fatal(err)
	}
	container2.State.Running = true
	container2.ToDisk()

	if len(runtime1.List()) != 2 {
		t.Errorf("Expected 2 container, %v found", len(runtime1.List()))
	}
	if err := container1.Run(); err != nil {
		t.Fatal(err)
	}

	if !container2.State.Running {
		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
	}

	// Here are are simulating a docker restart - that is, reloading all containers
	// from scratch
	runtime2, err := NewRuntimeFromDirectory(root)
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime2)
	if len(runtime2.List()) != 2 {
		t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
	}
	runningCount := 0
	for _, c := range runtime2.List() {
		if c.State.Running {
			t.Errorf("Running container found: %v (%v)", c.Id, c.Path)
			runningCount++
		}
	}
	if runningCount != 0 {
		t.Fatalf("Expected 0 container alive, %d found", runningCount)
	}
	container3 := runtime2.Get(container1.Id)
	if container3 == nil {
		t.Fatal("Unable to Get container")
	}
	if err := container3.Run(); err != nil {
		t.Fatal(err)
	}
	container2.State.Running = false
}
<commit_msg>Keep a cache of the unit-tests image. So I can code in conferences with crappy wifi.<commit_after>package docker

import (
	"github.com/dotcloud/docker/rcli"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"sync"
	"testing"
	"time"
)

const unitTestImageName string = "docker-ut"

const unitTestStoreBase string = "/var/lib/docker/unit-tests"

func nuke(runtime *Runtime) error {
	var wg sync.WaitGroup
	for _, container := range runtime.List() {
		wg.Add(1)
		go func(c *Container) {
			c.Kill()
			wg.Done()
		}(container)
	}
	wg.Wait()
	return os.RemoveAll(runtime.root)
}

func CopyDirectory(source, dest string) error {
	if _, err := exec.Command("cp", "-ra", source, dest).Output(); err != nil {
		return err
	}
	return nil
}

func layerArchive(tarfile string) (io.Reader, error) {
	// FIXME: need to close f somewhere
	f, err := os.Open(tarfile)
	if err != nil {
		return nil, err
	}
	return f, nil
}

func init() {
	NO_MEMORY_LIMIT = os.Getenv("NO_MEMORY_LIMIT") == "1"

	// Hack to run sys init during unit testing
	if SelfPath() == "/sbin/init" {
		SysInit()
		return
	}

	if usr, err := user.Current(); err != nil {
		panic(err)
	} else if usr.Uid != "0" {
		panic("docker tests needs to be run as root")
	}

	// Make it our Store root
	runtime, err := NewRuntimeFromDirectory(unitTestStoreBase)
	if err != nil {
		panic(err)
	}
	// Create the "Server"
	srv := &Server{
		runtime: runtime,
	}
	// Retrieve the Image
	if err := srv.CmdPull(os.Stdin, rcli.NewDockerLocalConn(os.Stdout), unitTestImageName); err != nil {
		panic(err)
	}
}

func newTestRuntime() (*Runtime, error) {
	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		return nil, err
	}
	if err := os.Remove(root); err != nil {
		return nil, err
	}
	if err := CopyDirectory(unitTestStoreBase, root); err != nil {
		return nil, err
	}

	runtime, err := NewRuntimeFromDirectory(root)
	if err != nil {
		return nil, err
	}

	return runtime, nil
}

func GetTestImage(runtime *Runtime) *Image {
	imgs, err := runtime.graph.All()
	if err != nil {
		panic(err)
	} else if len(imgs) < 1 {
		panic("GASP")
	}
	return imgs[0]
}

func TestRuntimeCreate(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)

	// Make sure we start we 0 containers
	if len(runtime.List()) != 0 {
		t.Errorf("Expected 0 containers, %v found", len(runtime.List()))
	}
	container, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if err := runtime.Destroy(container); err != nil {
			t.Error(err)
		}
	}()

	// Make sure we can find the newly created container with List()
	if len(runtime.List()) != 1 {
		t.Errorf("Expected 1 container, %v found", len(runtime.List()))
	}

	// Make sure the container List() returns is the right one
	if runtime.List()[0].Id != container.Id {
		t.Errorf("Unexpected container %v returned by List", runtime.List()[0])
	}

	// Make sure we can get the container with Get()
	if runtime.Get(container.Id) == nil {
		t.Errorf("Unable to get newly created container")
	}

	// Make sure it is the right container
	if runtime.Get(container.Id) != container {
		t.Errorf("Get() returned the wrong container")
	}

	// Make sure Exists returns it as existing
	if !runtime.Exists(container.Id) {
		t.Errorf("Exists() returned false for a newly created container")
	}
}

func TestDestroy(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	container, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	// Destroy
	if err := runtime.Destroy(container); err != nil {
		t.Error(err)
	}

	// Make sure runtime.Exists() behaves correctly
	if runtime.Exists("test_destroy") {
		t.Errorf("Exists() returned true")
	}

	// Make sure runtime.List() doesn't list the destroyed container
	if len(runtime.List()) != 0 {
		t.Errorf("Expected 0 container, %v found", len(runtime.List()))
	}

	// Make sure runtime.Get() refuses to return the unexisting container
	if runtime.Get(container.Id) != nil {
		t.Errorf("Unable to get newly created container")
	}

	// Make sure the container root directory does not exist anymore
	_, err = os.Stat(container.root)
	if err == nil || !os.IsNotExist(err) {
		t.Errorf("Container root directory still exists after destroy")
	}

	// Test double destroy
	if err := runtime.Destroy(container); err == nil {
		// It should have failed
		t.Errorf("Double destroy did not fail")
	}
}

func TestGet(t *testing.T) {
	runtime, err := newTestRuntime()
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime)
	container1, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container1)

	container2, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container2)

	container3, err := runtime.Create(&Config{
		Image: GetTestImage(runtime).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime.Destroy(container3)

	if runtime.Get(container1.Id) != container1 {
		t.Errorf("Get(test1) returned %v while expecting %v", runtime.Get(container1.Id), container1)
	}

	if runtime.Get(container2.Id) != container2 {
		t.Errorf("Get(test2) returned %v while expecting %v", runtime.Get(container2.Id), container2)
	}

	if runtime.Get(container3.Id) != container3 {
		t.Errorf("Get(test3) returned %v while expecting %v", runtime.Get(container3.Id), container3)
	}

}

func TestRestore(t *testing.T) {

	root, err := ioutil.TempDir("", "docker-test")
	if err != nil {
		t.Fatal(err)
	}
	if err := os.Remove(root); err != nil {
		t.Fatal(err)
	}
	if err := CopyDirectory(unitTestStoreBase, root); err != nil {
		t.Fatal(err)
	}

	runtime1, err := NewRuntimeFromDirectory(root)
	if err != nil {
		t.Fatal(err)
	}

	// Create a container with one instance of docker
	container1, err := runtime1.Create(&Config{
		Image: GetTestImage(runtime1).Id,
		Cmd:   []string{"ls", "-al"},
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime1.Destroy(container1)

	// Create a second container meant to be killed
	container2, err := runtime1.Create(&Config{
		Image:     GetTestImage(runtime1).Id,
		Cmd:       []string{"/bin/cat"},
		OpenStdin: true,
	},
	)
	if err != nil {
		t.Fatal(err)
	}
	defer runtime1.Destroy(container2)

	// Start the container non blocking
	if err := container2.Start(); err != nil {
		t.Fatal(err)
	}

	if !container2.State.Running {
		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
	}

	// Simulate a crash/manual quit of dockerd: process dies, states stays 'Running'
	cStdin, _ := container2.StdinPipe()
	cStdin.Close()
	if err := container2.WaitTimeout(2 * time.Second); err != nil {
		t.Fatal(err)
	}
	container2.State.Running = true
	container2.ToDisk()

	if len(runtime1.List()) != 2 {
		t.Errorf("Expected 2 container, %v found", len(runtime1.List()))
	}
	if err := container1.Run(); err != nil {
		t.Fatal(err)
	}

	if !container2.State.Running {
		t.Fatalf("Container %v should appear as running but isn't", container2.Id)
	}

	// Here are are simulating a docker restart - that is, reloading all containers
	// from scratch
	runtime2, err := NewRuntimeFromDirectory(root)
	if err != nil {
		t.Fatal(err)
	}
	defer nuke(runtime2)
	if len(runtime2.List()) != 2 {
		t.Errorf("Expected 2 container, %v found", len(runtime2.List()))
	}
	runningCount := 0
	for _, c := range runtime2.List() {
		if c.State.Running {
			t.Errorf("Running container found: %v (%v)", c.Id, c.Path)
			runningCount++
		}
	}
	if runningCount != 0 {
		t.Fatalf("Expected 0 container alive, %d found", runningCount)
	}
	container3 := runtime2.Get(container1.Id)
	if container3 == nil {
		t.Fatal("Unable to Get container")
	}
	if err := container3.Run(); err != nil {
		t.Fatal(err)
	}
	container2.State.Running = false
}
<|endoftext|>


<commit_before>package godless

import (
	"testing"
)

func TestEmptyNamespace(t *testing.T) {
	t.Fail()
}

func TestMakeNamespace(t *testing.T) {
	t.Fail()
}

func TestNamespaceIsEmpty(t *testing.T) {
	t.Fail()
}

func TestNamespaceCopy(t *testing.T) {
	t.Fail()
}

func TestNamespaceJoinNamespace(t *testing.T) {
	t.Fail()
}

func TestNamespaceJoinTable(t *testing.T) {
	t.Fail()
}

func TestNamespaceGetTable(t *testing.T) {
	t.Fail()
}

func TestNamespaceEquals(t *testing.T) {
	t.Fail()
}

func TestEmptyTable(t *testing.T) {
	t.Fail()
}

func TestRowMakeTable(t *testing.T) {
	t.Fail()
}

func TestTableForeachrow(t *testing.T) {
	t.Fail()
}

func TestTableCopy(t *testing.T) {
	t.Fail()
}

func TestTableAllRows(t *testing.T) {
	t.Fail()
}

func TestTableJoinTable(t *testing.T) {
	t.Fail()
}

func TestTableJoinRow(t *testing.T) {
	t.Fail()
}

func TestTableGetRow(t *testing.T) {
	t.Fail()
}

func TestTableEquals(t *testing.T) {
	t.Fail()
}

func TestEmptyRow(t *testing.T) {
	t.Fail()
}

func TestEntryMakeRow(t *testing.T) {
	t.Fail()
}

func TestRowCopy(t *testing.T) {
	t.Fail()
}

func TestRowJoinRow(t *testing.T) {
	t.Fail()
}

func TestRowGetEntry(t *testing.T) {
	t.Fail()
}

func TestRowJoinEntry(t *testing.T) {
	t.Fail()
}

func TestRowEquals(t *testing.T) {
	t.Fail()
}

func TestEmptyEntry(t *testing.T) {
	t.Fail()
}

func TestMakeEntry(t *testing.T) {
	t.Fail()
}

func TestEntryJoinEntry(t *testing.T) {
	t.Fail()
}

func TestEntryEquals(t *testing.T) {
	t.Fail()
}

func TestEntryGetValues(t *testing.T) {
	t.Fail()
}
<commit_msg>Namespace tests<commit_after>package godless

import (
	"reflect"
	"runtime"
	"testing"
)

func TestEmptyNamespace(t *testing.T) {
	expected := &Namespace{
		tables: map[string]Table{},
	}
	actual := EmptyNamespace()

	assertNamespaceEquals(t, expected, actual)
}

func TestMakeNamespace(t *testing.T) {
	table := EmptyTable()

	expected := &Namespace{
		tables: map[string]Table{
			"foo": table,
		},
	}
	actual := MakeNamespace(map[string]Table{"foo": table})

	assertNamespaceEquals(t, expected, actual)
}

func TestNamespaceIsEmpty(t *testing.T) {
	table := EmptyTable()

	full := MakeNamespace(map[string]Table{"foo": table})

	empty := EmptyNamespace()

	if !empty.IsEmpty() {
		t.Error("Expected IsEmpty():", empty)
	}

	if full.IsEmpty() {
		t.Error("Unexpected IsEmpty():", full)
	}
}

func TestNamespaceCopy(t *testing.T) {
	expected := MakeNamespace(map[string]Table{"foo": EmptyTable()})
	actual := expected.Copy()

	if expected == actual {
		t.Error("Unexpected pointer equality")
	}

	assertNamespaceEquals(t, expected, actual)
}

func TestNamespaceJoinNamespace(t *testing.T) {
	table := EmptyTable()
	foo := MakeNamespace(map[string]Table{"foo": table})
	bar := MakeNamespace(map[string]Table{"bar": table})

	expectedJoin := MakeNamespace(map[string]Table{"foo": table, "bar": table})
	expectedFoo := MakeNamespace(map[string]Table{"foo": table})
	expectedBar := MakeNamespace(map[string]Table{"bar": table})

	actualJoinFooBar, fooBarErr := foo.JoinNamespace(bar)
	actualJoinBarFoo, barFooErr := bar.JoinNamespace(foo)

	assertNilError(t, fooBarErr)
	assertNilError(t, barFooErr)

	assertNamespaceEquals(t, expectedJoin, actualJoinFooBar)
	assertNamespaceEquals(t, expectedJoin, actualJoinBarFoo)
	assertNamespaceEquals(t, expectedFoo, foo)
	assertNamespaceEquals(t, expectedBar, bar)
}

func TestNamespaceJoinTable(t *testing.T) {
	table := EmptyTable()
	foo := MakeNamespace(map[string]Table{"foo": table})
	barTable := EmptyTable()

	expectedFoo := MakeNamespace(map[string]Table{"foo": table})
	expectedJoin := MakeNamespace(map[string]Table{"foo": table, "bar": table})

	actual, err := foo.JoinTable("bar", barTable)

	assertNilError(t, err)

	assertNamespaceEquals(t, expectedFoo, foo)
	assertNamespaceEquals(t, expectedJoin, actual)
}

func TestNamespaceGetTable(t *testing.T) {
	expectedTable := MakeTable(map[string]Row{"foo": EmptyRow()})
	expectedEmptyTable := Table{}

	hasTable := MakeNamespace(map[string]Table{"bar": expectedTable})
	hasNoTable := EmptyNamespace()

	var actualTable Table
	var err error
	actualTable, err = hasTable.GetTable("bar")

	assertTableEquals(t, expectedTable, actualTable)

	assertNilError(t, err)

	actualTable, err = hasNoTable.GetTable("bar")

	assertTableEquals(t, expectedEmptyTable, actualTable)

	assertNonNilError(t, err)
}

func TestNamespaceEquals(t *testing.T) {

	table := EmptyTable()
	nsA := MakeNamespace(map[string]Table{"foo": table})
	nsB := MakeNamespace(map[string]Table{"bar": table})
	nsC := EmptyNamespace()
	nsD := MakeNamespace(map[string]Table{
		"foo": MakeTable(map[string]Row{
			"howdy": EmptyRow(),
		}),
	})

	foos := []*Namespace{
		nsA, nsB, nsC, nsD,
	}

	bars := make([]*Namespace, len(foos))
	for i, f := range foos {
		bars[i] = f.Copy()
	}

	for i, f := range foos {
		assertNamespaceEquals(t, f, f)
		for j, b := range bars {
			if i == j {
				assertNamespaceEquals(t, f, b)
			} else {
				assertNamespaceNotEquals(t, f, b)
			}

		}
	}
}

func TestEmptyTable(t *testing.T) {
	t.Fail()
}

func TestRowMakeTable(t *testing.T) {
	t.Fail()
}

func TestTableForeachrow(t *testing.T) {
	t.Fail()
}

func TestTableCopy(t *testing.T) {
	t.Fail()
}

func TestTableAllRows(t *testing.T) {
	t.Fail()
}

func TestTableJoinTable(t *testing.T) {
	t.Fail()
}

func TestTableJoinRow(t *testing.T) {
	t.Fail()
}

func TestTableGetRow(t *testing.T) {
	t.Fail()
}

func TestTableEquals(t *testing.T) {
	t.Fail()
}

func TestEmptyRow(t *testing.T) {
	t.Fail()
}

func TestEntryMakeRow(t *testing.T) {
	t.Fail()
}

func TestRowCopy(t *testing.T) {
	t.Fail()
}

func TestRowJoinRow(t *testing.T) {
	t.Fail()
}

func TestRowGetEntry(t *testing.T) {
	t.Fail()
}

func TestRowJoinEntry(t *testing.T) {
	t.Fail()
}

func TestRowEquals(t *testing.T) {
	t.Fail()
}

func TestEmptyEntry(t *testing.T) {
	t.Fail()
}

func TestMakeEntry(t *testing.T) {
	t.Fail()
}

func TestEntryJoinEntry(t *testing.T) {
	t.Fail()
}

func TestEntryEquals(t *testing.T) {
	t.Fail()
}

func TestEntryGetValues(t *testing.T) {
	t.Fail()
}

func assertNamespaceEquals(t *testing.T, expected, actual *Namespace) {
	if !reflect.DeepEqual(expected, actual) {
		debugLine(t)
		t.Error("Expected Namespace", expected, "but received", actual)
	}
}

func assertNamespaceNotEquals(t *testing.T, other, actual *Namespace) {
	if reflect.DeepEqual(other, actual) {
		debugLine(t)
		t.Error("Unexpected Namespace", other, "was equal to", actual)
	}
}

func assertTableEquals(t *testing.T, expected, actual Table) {
	if !reflect.DeepEqual(expected, actual) {
		debugLine(t)
		t.Error("Expected Table", expected, "but received", actual)
	}
}

func assertNilError(t *testing.T, err error) {
	if err != nil {
		debugLine(t)
		t.Error("Unexpected error:", err)
	}
}

func assertNonNilError(t *testing.T, err error) {
	if err == nil {
		debugLine(t)
		t.Error("Expected error")
	}
}

func debugLine(t *testing.T) {
	_, _, line, ok := runtime.Caller(CALLER_DEPTH)

	if !ok {
		panic("debugLine failed")
	}

	t.Log("Test failed at line", line)
}

const CALLER_DEPTH = 2
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http/httptest"
	"os"
	"sync"

	"github.com/abligh/gonbdserver/nbd"
	"github.com/g8os/blockstor/nbdserver/stubs"
	"golang.org/x/net/context"
)

func main() {
	var inMemoryStorage bool
	var protocol string
	var address string
	var volumecontrolleraddress string
	var backendcontrolleraddress string
	flag.BoolVar(&inMemoryStorage, "memorystorage", false, "Stores the data in memory only, usefull for testing or benchmarking")
	flag.StringVar(&protocol, "protocol", "unix", "Protocol to listen on, 'tcp' or 'unix'")
	flag.StringVar(&address, "address", "/tmp/nbd-socket", "Address to listen on, unix socket or tcp address, ':6666' for example")
	flag.StringVar(&volumecontrolleraddress, "volumecontroller", "", "Address of the volumecontroller REST API, leave empty to use the embedded stub")
	flag.StringVar(&backendcontrolleraddress, "backendcontroller", "", "Address of the storage backend controller REST API, leave empty to use the embedded stub")
	flag.Parse()

	//TODO: make this dependant of a profiling flag
	// go func() {
	// 	log.Println(http.ListenAndServe("localhost:6060", http.HandlerFunc(pprof.Index)))
	// }()

	logger := log.New(os.Stderr, "nbdserver:", log.Ldate|log.Ltime)
	if volumecontrolleraddress == "" {
		logger.Println("[INFO] Starting embedded volume controller")
		var s *httptest.Server
		s, volumecontrolleraddress = stubs.NewVolumeControllerServer()
		defer s.Close()
	}
	logger.Println("[INFO] Using volume controller at", volumecontrolleraddress)

	if backendcontrolleraddress == "" {
		logger.Println("[INFO] Starting embedded storage backend controller")
		var s *httptest.Server
		s, backendcontrolleraddress = stubs.NewStorageBackendServer()
		defer s.Close()
	}
	logger.Println("[INFO] Using storage backend controller at", backendcontrolleraddress)

	var sessionWaitGroup sync.WaitGroup

	ctx, cancelFunc := context.WithCancel(context.Background())
	configCtx, _ := context.WithCancel(ctx)
	defer func() {
		logger.Println("[INFO] Shutting down")
		cancelFunc()
		sessionWaitGroup.Wait()
		logger.Println("[INFO] Shutdown complete")
	}()
	s := nbd.ServerConfig{
		Protocol:      protocol,
		Address:       address,
		DefaultExport: "default",
		Exports: []nbd.ExportConfig{nbd.ExportConfig{
			Name:        "default",
			Description: "Deduped g8os blockstor",
			Driver:      "ardb",
			Workers:     5,
			DriverParameters: map[string]string{
				"volumecontrolleraddress":  volumecontrolleraddress,
				"backendcontrolleraddress": backendcontrolleraddress,
			},
		}},
	}
	if inMemoryStorage {
		logger.Println("[INFO] Using in-memory block storage")
	}
	f := &ArdbBackendFactory{BackendPool: NewRedisPool(inMemoryStorage)}

	nbd.RegisterBackend("ardb", f.NewArdbBackend)

	l, err := nbd.NewListener(logger, s)
	if err != nil {
		logger.Fatal(err)
		return
	}
	l.Listen(configCtx, ctx, &sessionWaitGroup)
}
<commit_msg>Make sure to close the redispools<commit_after>package main

import (
	"flag"
	"log"
	"net/http/httptest"
	"os"
	"sync"

	"github.com/abligh/gonbdserver/nbd"
	"github.com/g8os/blockstor/nbdserver/stubs"
	"golang.org/x/net/context"
)

func main() {
	var inMemoryStorage bool
	var protocol string
	var address string
	var volumecontrolleraddress string
	var backendcontrolleraddress string
	flag.BoolVar(&inMemoryStorage, "memorystorage", false, "Stores the data in memory only, usefull for testing or benchmarking")
	flag.StringVar(&protocol, "protocol", "unix", "Protocol to listen on, 'tcp' or 'unix'")
	flag.StringVar(&address, "address", "/tmp/nbd-socket", "Address to listen on, unix socket or tcp address, ':6666' for example")
	flag.StringVar(&volumecontrolleraddress, "volumecontroller", "", "Address of the volumecontroller REST API, leave empty to use the embedded stub")
	flag.StringVar(&backendcontrolleraddress, "backendcontroller", "", "Address of the storage backend controller REST API, leave empty to use the embedded stub")
	flag.Parse()

	//TODO: make this dependant of a profiling flag
	// go func() {
	// 	log.Println(http.ListenAndServe("localhost:6060", http.HandlerFunc(pprof.Index)))
	// }()

	logger := log.New(os.Stderr, "nbdserver:", log.Ldate|log.Ltime)
	if volumecontrolleraddress == "" {
		logger.Println("[INFO] Starting embedded volume controller")
		var s *httptest.Server
		s, volumecontrolleraddress = stubs.NewVolumeControllerServer()
		defer s.Close()
	}
	logger.Println("[INFO] Using volume controller at", volumecontrolleraddress)

	if backendcontrolleraddress == "" {
		logger.Println("[INFO] Starting embedded storage backend controller")
		var s *httptest.Server
		s, backendcontrolleraddress = stubs.NewStorageBackendServer()
		defer s.Close()
	}
	logger.Println("[INFO] Using storage backend controller at", backendcontrolleraddress)

	var sessionWaitGroup sync.WaitGroup

	ctx, cancelFunc := context.WithCancel(context.Background())
	configCtx, _ := context.WithCancel(ctx)
	defer func() {
		logger.Println("[INFO] Shutting down")
		cancelFunc()
		sessionWaitGroup.Wait()
		logger.Println("[INFO] Shutdown complete")
	}()
	s := nbd.ServerConfig{
		Protocol:      protocol,
		Address:       address,
		DefaultExport: "default",
		Exports: []nbd.ExportConfig{nbd.ExportConfig{
			Name:        "default",
			Description: "Deduped g8os blockstor",
			Driver:      "ardb",
			Workers:     5,
			DriverParameters: map[string]string{
				"volumecontrolleraddress":  volumecontrolleraddress,
				"backendcontrolleraddress": backendcontrolleraddress,
			},
		}},
	}
	if inMemoryStorage {
		logger.Println("[INFO] Using in-memory block storage")
	}
	r := NewRedisPool(inMemoryStorage)
	defer r.Close()

	f := &ArdbBackendFactory{BackendPool: r}

	nbd.RegisterBackend("ardb", f.NewArdbBackend)

	l, err := nbd.NewListener(logger, s)
	if err != nil {
		logger.Fatal(err)
		return
	}
	l.Listen(configCtx, ctx, &sessionWaitGroup)
}
<|endoftext|>


<commit_before>// +build go1.7

package nethttp

import (
	"net/http"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

type statusCodeTracker struct {
	http.ResponseWriter
	status int
}

func (w *statusCodeTracker) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

type mwOptions struct {
	opNameFunc    func(r *http.Request) string
	spanObserver  func(span opentracing.Span, r *http.Request)
	componentName string
}

// MWOption controls the behavior of the Middleware.
type MWOption func(*mwOptions)

// OperationNameFunc returns a MWOption that uses given function f
// to generate operation name for each server-side span.
func OperationNameFunc(f func(r *http.Request) string) MWOption {
	return func(options *mwOptions) {
		options.opNameFunc = f
	}
}

// MWComponentName returns a MWOption that sets the component name
// for the server-side span.
func MWComponentName(componentName string) MWOption {
	return func(options *mwOptions) {
		options.componentName = componentName
	}
}

// MWSpanObserver returns a MWOption that observe the span
// for the server-side span.
func MWSpanObserver(f func(span opentracing.Span, r *http.Request)) MWOption {
	return func(options *mwOptions) {
		options.spanObserver = f
	}
}

// Middleware wraps an http.Handler and traces incoming requests.
// Additionally, it adds the span to the request's context.
//
// By default, the operation name of the spans is set to "HTTP {method}".
// This can be overriden with options.
//
// Example:
// 	 http.ListenAndServe("localhost:80", nethttp.Middleware(tracer, http.DefaultServeMux))
//
// The options allow fine tuning the behavior of the middleware.
//
// Example:
//   mw := nethttp.Middleware(
//      tracer,
//      http.DefaultServeMux,
//      nethttp.OperationNameFunc(func(r *http.Request) string {
//	        return "HTTP " + r.Method + ":/api/customers"
//      }),
//      nethttp.MWSpanObserver(func(sp opentracing.Span, r *http.Request) {
//			sp.SetTag("http.uri", r.URL.EscapedPath())
//		}),
//   )
func Middleware(tr opentracing.Tracer, h http.Handler, options ...MWOption) http.Handler {
	opts := mwOptions{
		opNameFunc: func(r *http.Request) string {
			return "HTTP " + r.Method
		},
		spanObserver: func(span opentracing.Span, r *http.Request) {},
	}
	for _, opt := range options {
		opt(&opts)
	}
	fn := func(w http.ResponseWriter, r *http.Request) {
		ctx, _ := tr.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
		sp := tr.StartSpan(opts.opNameFunc(r), ext.RPCServerOption(ctx))
		ext.HTTPMethod.Set(sp, r.Method)
		ext.HTTPUrl.Set(sp, r.URL.String())
		opts.spanObserver(sp, r)

		// set component name, use "net/http" if caller does not specify
		componentName := opts.componentName
		if componentName == "" {
			componentName = defaultComponentName
		}
		ext.Component.Set(sp, componentName)

		w = &statusCodeTracker{w, 200}
		r = r.WithContext(opentracing.ContextWithSpan(r.Context(), sp))

		h.ServeHTTP(w, r)

		ext.HTTPStatusCode.Set(sp, uint16(w.(*statusCodeTracker).status))
		sp.Finish()
	}
	return http.HandlerFunc(fn)
}
<commit_msg>Support middleware around function handlers (#24)<commit_after>// +build go1.7

package nethttp

import (
	"net/http"

	opentracing "github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
)

type statusCodeTracker struct {
	http.ResponseWriter
	status int
}

func (w *statusCodeTracker) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

type mwOptions struct {
	opNameFunc    func(r *http.Request) string
	spanObserver  func(span opentracing.Span, r *http.Request)
	componentName string
}

// MWOption controls the behavior of the Middleware.
type MWOption func(*mwOptions)

// OperationNameFunc returns a MWOption that uses given function f
// to generate operation name for each server-side span.
func OperationNameFunc(f func(r *http.Request) string) MWOption {
	return func(options *mwOptions) {
		options.opNameFunc = f
	}
}

// MWComponentName returns a MWOption that sets the component name
// for the server-side span.
func MWComponentName(componentName string) MWOption {
	return func(options *mwOptions) {
		options.componentName = componentName
	}
}

// MWSpanObserver returns a MWOption that observe the span
// for the server-side span.
func MWSpanObserver(f func(span opentracing.Span, r *http.Request)) MWOption {
	return func(options *mwOptions) {
		options.spanObserver = f
	}
}

// Middleware wraps an http.Handler and traces incoming requests.
// Additionally, it adds the span to the request's context.
//
// By default, the operation name of the spans is set to "HTTP {method}".
// This can be overriden with options.
//
// Example:
// 	 http.ListenAndServe("localhost:80", nethttp.Middleware(tracer, http.DefaultServeMux))
//
// The options allow fine tuning the behavior of the middleware.
//
// Example:
//   mw := nethttp.Middleware(
//      tracer,
//      http.DefaultServeMux,
//      nethttp.OperationNameFunc(func(r *http.Request) string {
//	        return "HTTP " + r.Method + ":/api/customers"
//      }),
//      nethttp.MWSpanObserver(func(sp opentracing.Span, r *http.Request) {
//			sp.SetTag("http.uri", r.URL.EscapedPath())
//		}),
//   )
func Middleware(tr opentracing.Tracer, h http.Handler, options ...MWOption) http.Handler {
	return MiddlewareFunc(tr, h.ServeHTTP, options...)
}

// MiddlewareFunc wraps an http.HandlerFunc and traces incoming requests.
// It behaves identically to the Middleware function above.
//
// Example:
//   http.ListenAndServe("localhost:80", nethttp.MiddlewareFunc(tracer, MyHandler))
func MiddlewareFunc(tr opentracing.Tracer, h http.HandlerFunc, options ...MWOption) http.HandlerFunc {
	opts := mwOptions{
		opNameFunc: func(r *http.Request) string {
			return "HTTP " + r.Method
		},
		spanObserver: func(span opentracing.Span, r *http.Request) {},
	}
	for _, opt := range options {
		opt(&opts)
	}
	fn := func(w http.ResponseWriter, r *http.Request) {
		ctx, _ := tr.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(r.Header))
		sp := tr.StartSpan(opts.opNameFunc(r), ext.RPCServerOption(ctx))
		ext.HTTPMethod.Set(sp, r.Method)
		ext.HTTPUrl.Set(sp, r.URL.String())
		opts.spanObserver(sp, r)

		// set component name, use "net/http" if caller does not specify
		componentName := opts.componentName
		if componentName == "" {
			componentName = defaultComponentName
		}
		ext.Component.Set(sp, componentName)

		w = &statusCodeTracker{w, 200}
		r = r.WithContext(opentracing.ContextWithSpan(r.Context(), sp))

		h(w, r)

		ext.HTTPStatusCode.Set(sp, uint16(w.(*statusCodeTracker).status))
		sp.Finish()
	}
	return http.HandlerFunc(fn)
}
<|endoftext|>


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

//
// Setup env JSON value:
// goboot_newrelic={
//   "enable": true,
//   "name: "Your_App_Name",
//   "license: "__YOUR_NEW_RELIC_LICENSE_KEY__"
// }
//
package newrelic

import (
	"github.com/geaviation/goboot/config"
	"github.com/geaviation/goboot/logging"
	"github.com/newrelic/go-agent"
	"net/http"
	"strings"
	"reflect"
	"runtime"
	"fmt"
)

var settings = config.AppSettings()
var log = logging.Logger()

type NewRelicEnv struct {
	Enable  bool          `env:"goboot_newrelic.enable"`
	Name    string        `env:"goboot_newrelic.name"`
	License string        `env:"goboot_newrelic.license"`
}

func init() {
	env := NewRelicEnv{}

	err := settings.Parse(&env)
	if err != nil {
		log.Errorf("NewRelic init error: %v", err)
		return
	}

	log.Debugf("NewRelic goboot_newrelic.enable: %v", env.Enable)
	if !env.Enable {
		return
	}

	name := env.Name
	log.Debugf("NewRelic goboot_newrelic.name: %v", name)
	if name == "" {
		name = settings.GetStringEnv("VCAP_APPLICATION", "application_name")
		log.Debugf("NewRelic app name read from VCAP_APPLICATION: ", name)
	}

	Config = newrelic.NewConfig(name, env.License)

	Application, err = newrelic.NewApplication(Config)
	if err != nil {
		log.Error(err)
		return
	}

	log.Debugf("NewRelic Application Name: %s  enabled %v: ", name, env.Enable)
}

var (
	Application newrelic.Application
	Config newrelic.Config
)

func HandleFuncAdapter(handler func(http.ResponseWriter, *http.Request), name...string) func(http.ResponseWriter, *http.Request) {
	var defaultName string
	if len(name) == 0 {
		defaultName = ""
	} else {
		defaultName = strings.Join(name, "/")
	}
	return func(res http.ResponseWriter, req *http.Request) {
		if Application != nil {
			var pattern = defaultName
			if pattern == "" {
				pattern = req.URL.Path
			}
			txn := Application.StartTransaction(pattern, res, req)
			defer txn.End()
		}

		handler(res, req)
	}
}

func funcAdapter(fn func(), name...string) func() (err error) {
	var defaultName string
	if len(name) == 0 {
		defaultName = ""
	} else {
		defaultName = strings.Join(name, "/")
	}
	return func() (err error) {
		var txn newrelic.Transaction
		if Application != nil {
			var pattern = defaultName
			if pattern == "" {
				pattern = nameOf(fn)
			}
			txn = Application.StartTransaction(pattern, nil, nil)
			defer txn.End()
			defer func() {
				if r := recover(); r != nil {
					err = fmt.Errorf("Error: %s", r)
					txn.NoticeError(err)
				}
			}()
		}

		fn()

		return
	}
}

func nameOf(f interface{}) string {
	v := reflect.ValueOf(f)
	if v.Kind() == reflect.Func {
		if r := runtime.FuncForPC(v.Pointer()); r != nil {
			return r.Name()
		}
	}
	return v.String()
}

func Trace(fn func(), name...string) {
	funcAdapter(fn, name...)()
}<commit_msg>buble up error for newrelic trace<commit_after>// Copyright 2017 The Goboot Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//
// Setup env JSON value:
// goboot_newrelic={
//   "enable": true,
//   "name: "Your_App_Name",
//   "license: "__YOUR_NEW_RELIC_LICENSE_KEY__"
// }
//
package newrelic

import (
	"github.com/geaviation/goboot/config"
	"github.com/geaviation/goboot/logging"
	"github.com/newrelic/go-agent"
	"net/http"
	"strings"
	"reflect"
	"runtime"
	"fmt"
)

var settings = config.AppSettings()
var log = logging.Logger()

type NewRelicEnv struct {
	Enable  bool          `env:"goboot_newrelic.enable"`
	Name    string        `env:"goboot_newrelic.name"`
	License string        `env:"goboot_newrelic.license"`
}

func init() {
	env := NewRelicEnv{}

	err := settings.Parse(&env)
	if err != nil {
		log.Errorf("NewRelic init error: %v", err)
		return
	}

	log.Debugf("NewRelic goboot_newrelic.enable: %v", env.Enable)
	if !env.Enable {
		return
	}

	name := env.Name
	log.Debugf("NewRelic goboot_newrelic.name: %v", name)
	if name == "" {
		name = settings.GetStringEnv("VCAP_APPLICATION", "application_name")
		log.Debugf("NewRelic app name read from VCAP_APPLICATION: ", name)
	}

	Config = newrelic.NewConfig(name, env.License)

	Application, err = newrelic.NewApplication(Config)
	if err != nil {
		log.Error(err)
		return
	}

	log.Debugf("NewRelic Application Name: %s  enabled %v: ", name, env.Enable)
}

var (
	Application newrelic.Application
	Config newrelic.Config
)

func HandleFuncAdapter(handler func(http.ResponseWriter, *http.Request), name...string) func(http.ResponseWriter, *http.Request) {
	var defaultName string
	if len(name) == 0 {
		defaultName = ""
	} else {
		defaultName = strings.Join(name, "/")
	}
	return func(res http.ResponseWriter, req *http.Request) {
		if Application != nil {
			var pattern = defaultName
			if pattern == "" {
				pattern = req.URL.Path
			}
			txn := Application.StartTransaction(pattern, res, req)
			defer txn.End()
		}

		handler(res, req)
	}
}

func funcAdapter(fn func(), name...string) func() (err error) {
	var defaultName string
	if len(name) == 0 {
		defaultName = ""
	} else {
		defaultName = strings.Join(name, "/")
	}
	return func() (err error) {
		var txn newrelic.Transaction
		if Application != nil {
			var pattern = defaultName
			if pattern == "" {
				pattern = nameOf(fn)
			}
			txn = Application.StartTransaction(pattern, nil, nil)
			defer txn.End()
			defer func() {
				if r := recover(); r != nil {
					err = fmt.Errorf("Error: %s", r)
					txn.NoticeError(err)
				}
			}()
		}

		fn()

		return
	}
}

func nameOf(f interface{}) string {
	v := reflect.ValueOf(f)
	if v.Kind() == reflect.Func {
		if r := runtime.FuncForPC(v.Pointer()); r != nil {
			return r.Name()
		}
	}
	return v.String()
}

func Trace(fn func(), name...string) (err error) {
	err = funcAdapter(fn, name...)()
	return
}<|endoftext|>


<commit_before>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/tealeg/xlsx"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type message struct {
	User, Type, Subtype, Text, Ts string
	Timestamp                     time.Time
}

// Implement the sort interface for type messages
type messages []message

func (m messages) Len() int {
	return len(m)
}

func (m messages) Less(i, j int) bool {
	return m[i].Timestamp.Before(m[j].Timestamp)
}

func (m messages) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

type meta struct {
	ID, Name string
	RealName string `json:"real_name,omitempty"`
}

// Set global CLI vars
var filename, outputDir, timezone string
var metadata = make(map[string][]meta)

func main() {

	app := cli.NewApp()
	app.Usage = "An app for exporting Slack history to Excel (.xlsx)"
	app.HideVersion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "name, n",
			Value:       time.Now().Format("2006-Jan-02") + "_SlackExport.xlsx",
			Usage:       "Set the name of the exported spreadsheet",
			Destination: &filename,
		},
		cli.StringFlag{
			Name:        "destination, d",
			Value:       "./",
			Usage:       "Specify the output directory for\n\t  the exported xlsx workbook",
			Destination: &outputDir,
		},
		cli.StringFlag{
			Name:        "timezone, t",
			Value:       "Local",
			Usage:       "Specify an alternate timezone.\n\t  See here for available options https://goo.gl/Tmq0oR",
			Destination: &timezone,
		},
	}

	app.Action = func(c *cli.Context) {
		if len(c.Args()) != 1 {
			fmt.Printf("\n*** Error: The location of the target zip file must be the last and only argument!\n***\n" +
				"*** For additional help, enter \"slackhist help\"\n\n")
			os.Exit(1)
		}

		if suffix := strings.HasSuffix(filename, ".xlsx"); suffix == false {
			filename = filename + ".xlsx"
		}

		messages := processData(c.Args()[0], metadata)
		createWorkbook(messages)
	}

	app.Run(os.Args)
}

func processData(f string, md map[string][]meta) map[string]messages {

	payload := make(map[string]messages)
	var dirname string

	// Open a readable stream from the zip file
	r, err := zip.OpenReader(f)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	// Collect the required meta to process the information HACK
	for _, file := range r.File {
		switch file.FileHeader.Name {
		case "channels.json", "users.json":
			getMeta(file, md)
		}
	}

	// For every item in the entire zip folder (recursive)
	for _, file := range r.File {

		isDirectory := file.FileInfo().IsDir()

		// Switch on file = directory
		switch isDirectory {
		case true:

			// Retreive the current directory's base name
			path, err := filepath.Abs(file.FileHeader.Name)
			if err != nil {
				panic(err)
			}
			dirname = filepath.Base(path)

			// Make the directory's base name (thus, the channel name) the key
			// and instantiate an empty slice within payload for the messages to
			// be stored
			payload[dirname] = make([]message, 0)

		case false:
			var thisJSON []message

			// If the file is one that we've already processed, break
			// from this particular loop cycle
			switch file.FileHeader.Name {
			case "integration_logs.json", "channels.json", "users.json":
				continue
			}

			// Grab the parent directory's name
			dirname = filepath.Base(filepath.Dir(file.FileHeader.Name))

			// Open a readable stream from the current file
			rc, err := file.Open()
			if err != nil {
				panic(err)
			}
			defer rc.Close()

			// Create JSON decoder and decode the readable stream to "thisJSON"
			decoder := json.NewDecoder(rc)
			for decoder.More() {
				if err := decoder.Decode(&thisJSON); err != nil {
					panic(err)
				}
			}

			// After a full file decode, iterate through the decoded JSON for
			// messages or attachments, and parse the timezone according to the
			// current user's local time zone format
			for _, value := range thisJSON {
				if value.Type == "message" && value.Subtype == "" || value.Subtype == "file_share" {

					value.Timestamp = parseTimestamp(value.Ts)
					_, value.User = parseUser(value.User, md)

					re := regexp.MustCompile(`(<@[a-zA-Z0-9]{9}(\|[a-zA-Z0-9._]+)?>)`)
					if matches := re.FindAllString(value.Text, -1); matches != nil {

						value.Text = re.ReplaceAllStringFunc(value.Text, func(match string) string {
							uid := match[2 : len(match)-1]
							if value.Subtype == "file_share" {
								uid = strings.Split(uid, "|")[0]
							}
							username, _ := parseUser(uid, md)
							return "@" + username
						})

					}

					payload[dirname] = append(payload[dirname], value)
				}
			}

		}

	}

	return payload

}

func createWorkbook(m map[string]messages) {

	var channelNames sort.StringSlice

	workbook := xlsx.NewFile()
	fullPath := filepath.Clean(filepath.Join(outputDir, filename))

	// First, sort the map by channel name
	for channel := range m {
		channelNames = append(channelNames, channel)
	}

	channelNames.Sort()

	for _, channel := range channelNames {
		sheet, err := workbook.AddSheet(channel)
		if err != nil {
			panic(err)
		}

		sort.Sort(sort.Reverse(m[channel]))

		headingRow := sheet.AddRow()
		headingRow.AddCell().SetString("Timestamp")
		headingRow.AddCell().SetString("User")
		headingRow.AddCell().SetString("Message")

		for _, message := range m[channel] {
			messageRow := sheet.AddRow()
			messageRow.AddCell().SetString(message.Timestamp.Format("Jan 02, 2006 | 15:04"))
			messageRow.AddCell().SetString(message.User)
			messageRow.AddCell().SetString(message.Text)
		}

	}

	if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
		panic(err)
	}

	if err := workbook.Save(fullPath); err != nil {
		panic(err)
	}

}

/**************************************************************************
 *                         Utility functions                              *
 **************************************************************************/

func getMeta(f *zip.File, m map[string][]meta) {
	filename := f.FileHeader.Name

	var thisJSON []meta

	rc, err := f.Open()
	if err != nil {
		panic(err)
	}
	defer rc.Close()

	decoder := json.NewDecoder(rc)
	for decoder.More() {
		if err := decoder.Decode(&thisJSON); err != nil {
			panic(err)
		}
	}

	switch filename {
	case "users.json":
		m["users"] = thisJSON
	case "channels.json":
		m["channels"] = thisJSON
	default:
		panic(filename)
	}

}

func parseTimestamp(ts string) time.Time {

	timestring, err := strconv.ParseInt(strings.Split(ts, ".")[0], 10, 64)
	if err != nil {
		panic(err)
	}
	tm := time.Unix(timestring, 0)

	loc, err := time.LoadLocation(timezone)
	if err != nil {
		panic(err)
	}

	return tm.In(loc)
}

func parseUser(uid string, m map[string][]meta) (string, string) {
	var username, realname string
	for _, value := range m["users"] {
		if value.ID == uid {
			username = value.Name
			realname = value.RealName
			break
		}
	}
	return username, realname
}
<commit_msg>Adjust widths of generated cols to better fit data<commit_after>package main

import (
	"archive/zip"
	"encoding/json"
	"fmt"
	"github.com/codegangsta/cli"
	"github.com/tealeg/xlsx"
	"os"
	"path/filepath"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

type message struct {
	User, Type, Subtype, Text, Ts string
	Timestamp                     time.Time
}

// Implement the sort interface for type messages
type messages []message

func (m messages) Len() int {
	return len(m)
}

func (m messages) Less(i, j int) bool {
	return m[i].Timestamp.Before(m[j].Timestamp)
}

func (m messages) Swap(i, j int) {
	m[i], m[j] = m[j], m[i]
}

type meta struct {
	ID, Name string
	RealName string `json:"real_name,omitempty"`
}

// Set global CLI vars
var filename, outputDir, timezone string
var metadata = make(map[string][]meta)

func main() {

	app := cli.NewApp()
	app.Usage = "An app for exporting Slack history to Excel (.xlsx)"
	app.HideVersion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "name, n",
			Value:       time.Now().Format("2006-Jan-02") + "_SlackExport.xlsx",
			Usage:       "Set the name of the exported spreadsheet",
			Destination: &filename,
		},
		cli.StringFlag{
			Name:        "destination, d",
			Value:       "./",
			Usage:       "Specify the output directory for\n\t  the exported xlsx workbook",
			Destination: &outputDir,
		},
		cli.StringFlag{
			Name:        "timezone, t",
			Value:       "Local",
			Usage:       "Specify an alternate timezone.\n\t  See here for available options https://goo.gl/Tmq0oR",
			Destination: &timezone,
		},
	}

	app.Action = func(c *cli.Context) {
		if len(c.Args()) != 1 {
			fmt.Printf("\n*** Error: The location of the target zip file must be the last and only argument!\n***\n" +
				"*** For additional help, enter \"slackhist help\"\n\n")
			os.Exit(1)
		}

		if suffix := strings.HasSuffix(filename, ".xlsx"); suffix == false {
			filename = filename + ".xlsx"
		}

		messages := processData(c.Args()[0], metadata)
		createWorkbook(messages)
	}

	app.Run(os.Args)
}

func processData(f string, md map[string][]meta) map[string]messages {

	payload := make(map[string]messages)
	var dirname string

	// Open a readable stream from the zip file
	r, err := zip.OpenReader(f)
	if err != nil {
		panic(err)
	}
	defer r.Close()

	// Collect the required meta to process the information HACK
	for _, file := range r.File {
		switch file.FileHeader.Name {
		case "channels.json", "users.json":
			getMeta(file, md)
		}
	}

	// For every item in the entire zip folder (recursive)
	for _, file := range r.File {

		isDirectory := file.FileInfo().IsDir()

		// Switch on file = directory
		switch isDirectory {
		case true:

			// Retreive the current directory's base name
			path, err := filepath.Abs(file.FileHeader.Name)
			if err != nil {
				panic(err)
			}
			dirname = filepath.Base(path)

			// Make the directory's base name (thus, the channel name) the key
			// and instantiate an empty slice within payload for the messages to
			// be stored
			payload[dirname] = make([]message, 0)

		case false:
			var thisJSON []message

			// If the file is one that we've already processed, break
			// from this particular loop cycle
			switch file.FileHeader.Name {
			case "integration_logs.json", "channels.json", "users.json":
				continue
			}

			// Grab the parent directory's name
			dirname = filepath.Base(filepath.Dir(file.FileHeader.Name))

			// Open a readable stream from the current file
			rc, err := file.Open()
			if err != nil {
				panic(err)
			}
			defer rc.Close()

			// Create JSON decoder and decode the readable stream to "thisJSON"
			decoder := json.NewDecoder(rc)
			for decoder.More() {
				if err := decoder.Decode(&thisJSON); err != nil {
					panic(err)
				}
			}

			// After a full file decode, iterate through the decoded JSON for
			// messages or attachments, and parse the timezone according to the
			// current user's local time zone format
			for _, value := range thisJSON {
				if value.Type == "message" && value.Subtype == "" || value.Subtype == "file_share" {

					value.Timestamp = parseTimestamp(value.Ts)
					_, value.User = parseUser(value.User, md)

					re := regexp.MustCompile(`(<@[a-zA-Z0-9]{9}(\|[a-zA-Z0-9._]+)?>)`)
					if matches := re.FindAllString(value.Text, -1); matches != nil {

						value.Text = re.ReplaceAllStringFunc(value.Text, func(match string) string {
							uid := match[2 : len(match)-1]
							if value.Subtype == "file_share" {
								uid = strings.Split(uid, "|")[0]
							}
							username, _ := parseUser(uid, md)
							return "@" + username
						})

					}

					payload[dirname] = append(payload[dirname], value)
				}
			}

		}

	}

	return payload

}

func createWorkbook(m map[string]messages) {

	var channelNames sort.StringSlice

	workbook := xlsx.NewFile()
	fullPath := filepath.Clean(filepath.Join(outputDir, filename))

	// First, sort the map by channel name
	for channel := range m {
		channelNames = append(channelNames, channel)
	}

	channelNames.Sort()

	for _, channel := range channelNames {
		sheet, err := workbook.AddSheet(channel)
		if err != nil {
			panic(err)
		}

		sort.Sort(sort.Reverse(m[channel]))

		headingRow := sheet.AddRow()
		headingRow.AddCell().SetString("Timestamp")
		headingRow.AddCell().SetString("User")
		headingRow.AddCell().SetString("Message")

		if err := sheet.SetColWidth(0, 1, 20); err != nil {
			panic(err)
		}

		if err := sheet.SetColWidth(2, 2, 200); err != nil {
			panic(err)
		}

		for _, message := range m[channel] {
			messageRow := sheet.AddRow()
			messageRow.AddCell().SetString(message.Timestamp.Format("Jan 02, 2006 | 15:04"))
			messageRow.AddCell().SetString(message.User)
			messageRow.AddCell().SetString(message.Text)
		}

	}

	if err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm); err != nil {
		panic(err)
	}

	if err := workbook.Save(fullPath); err != nil {
		panic(err)
	}

}

/**************************************************************************
 *                         Utility functions                              *
 **************************************************************************/

func getMeta(f *zip.File, m map[string][]meta) {
	filename := f.FileHeader.Name

	var thisJSON []meta

	rc, err := f.Open()
	if err != nil {
		panic(err)
	}
	defer rc.Close()

	decoder := json.NewDecoder(rc)
	for decoder.More() {
		if err := decoder.Decode(&thisJSON); err != nil {
			panic(err)
		}
	}

	switch filename {
	case "users.json":
		m["users"] = thisJSON
	case "channels.json":
		m["channels"] = thisJSON
	default:
		panic(filename)
	}

}

func parseTimestamp(ts string) time.Time {

	timestring, err := strconv.ParseInt(strings.Split(ts, ".")[0], 10, 64)
	if err != nil {
		panic(err)
	}
	tm := time.Unix(timestring, 0)

	loc, err := time.LoadLocation(timezone)
	if err != nil {
		panic(err)
	}

	return tm.In(loc)
}

func parseUser(uid string, m map[string][]meta) (string, string) {
	var username, realname string
	for _, value := range m["users"] {
		if value.ID == uid {
			username = value.Name
			realname = value.RealName
			break
		}
	}
	return username, realname
}
<|endoftext|>


<commit_before>package torrent

import (
	"math"
)

// Stats contains statistics about Torrent.
type Stats struct {
	// Status of the torrent.
	Status Status

	// Contains the error if torrent is stopped unexpectedly.
	Error error

	Pieces struct {
		Have    uint32
		Missing uint32
		Total   uint32
	}

	Bytes struct {
		// Bytes that are downloaded and passed hash check.
		Complete int64

		// The number of bytes that is needed to complete all missing pieces.
		Incomplete int64

		// The number of total bytes of files in torrent.
		//
		// Total = Complete + Incomplete
		Total int64

		// Downloaded is the number of bytes downloaded from swarm.
		// Because some pieces may be downloaded more than once, this number may be greater than BytesCompleted returns.
		// TODO put into resume
		Downloaded int64

		// Protocol messages are not included, only piece data is counted.
		Uploaded int64

		Wasted int64

		// BytesUploaded is the number of bytes uploaded to the swarm.
		// TODO BytesUploaded   int64
	}

	Peers struct {
		Connected struct {
			// Number of peers that are connected, handshaked and ready to send and receive messages.
			// ConnectedPeers = IncomingPeers + OutgoingPeers
			Total int

			// Number of peers that have connected to us.
			Incoming int

			// Number of peers that we have connected to.
			Outgoing int
		}

		Handshake struct {
			// Number of peers that are not handshaked yet.
			Total int

			// Number of incoming peers in handshake state.
			Incoming int

			// Number of outgoing peers in handshake state.
			Outgoing int
		}

		// Number of peer addresses that are ready to be connected.
		Ready int
	}

	Downloads struct {
		Piece struct {
			// Number of active piece downloads.
			Total int

			// Number of pieces that are being downloaded normally.
			Running int

			// Number of pieces that are being downloaded too slow.
			Snubbed int

			// Number of piece downloads in choked state.
			Choked int
		}

		Metadata struct {
			// Number of active metadata downloads.
			Total int

			// Number of peers that uploading too slow.
			Snubbed int

			// Number of peers that are being downloaded normally.
			Running int
		}
	}
}

func (t *Torrent) stats() Stats {
	var stats Stats
	stats.Status = t.status()
	stats.Error = t.lastError
	stats.Peers.Ready = t.addrList.Len()
	stats.Peers.Handshake.Incoming = len(t.incomingHandshakers)
	stats.Peers.Handshake.Outgoing = len(t.outgoingHandshakers)
	stats.Peers.Handshake.Total = len(t.incomingHandshakers) + len(t.outgoingHandshakers)
	stats.Peers.Connected.Total = len(t.peers)
	stats.Peers.Connected.Incoming = len(t.incomingPeers)
	stats.Peers.Connected.Outgoing = len(t.outgoingPeers)
	stats.Downloads.Metadata.Total = len(t.infoDownloaders)
	stats.Downloads.Metadata.Snubbed = len(t.infoDownloadersSnubbed)
	stats.Downloads.Metadata.Running = len(t.infoDownloaders) - len(t.infoDownloadersSnubbed)
	stats.Downloads.Piece.Total = len(t.pieceDownloaders)
	stats.Downloads.Piece.Snubbed = len(t.pieceDownloadersSnubbed)
	stats.Downloads.Piece.Choked = len(t.pieceDownloadersChoked)
	stats.Downloads.Piece.Running = len(t.pieceDownloaders) - len(t.pieceDownloadersChoked) - len(t.pieceDownloadersSnubbed)

	if t.info != nil {
		stats.Bytes.Total = t.info.TotalLength
		stats.Bytes.Complete = t.bytesComplete()
		stats.Bytes.Incomplete = stats.Bytes.Total - stats.Bytes.Complete
	} else {
		// Some trackers don't send any peer address if don't tell we have missing bytes.
		stats.Bytes.Incomplete = math.MaxUint32
	}
	if t.bitfield != nil {
		stats.Pieces.Total = t.bitfield.Len()
		stats.Pieces.Have = t.bitfield.Count()
		stats.Pieces.Missing = stats.Pieces.Total - stats.Pieces.Have
	}
	stats.Bytes.Downloaded = t.bytesDownloaded
	stats.Bytes.Uploaded = t.bytesUploaded
	stats.Bytes.Wasted = t.bytesWasted
	return stats
}

func (t *Torrent) bytesComplete() int64 {
	if t.bitfield == nil {
		return 0
	}
	n := int64(t.info.PieceLength) * int64(t.bitfield.Count())
	if t.bitfield.Test(t.bitfield.Len() - 1) {
		n -= int64(t.info.PieceLength)
		n += int64(t.pieces[t.bitfield.Len()-1].Length)
	}
	return n
}
<commit_msg>more stats<commit_after>package torrent

import (
	"math"
)

// Stats contains statistics about Torrent.
type Stats struct {
	// Status of the torrent.
	Status Status

	// Contains the error if torrent is stopped unexpectedly.
	Error error

	Pieces struct {
		Have    uint32
		Missing uint32
		Total   uint32
	}

	Bytes struct {
		// Bytes that are downloaded and passed hash check.
		Complete int64

		// The number of bytes that is needed to complete all missing pieces.
		Incomplete int64

		// The number of total bytes of files in torrent.
		//
		// Total = Complete + Incomplete
		Total int64

		// Downloaded is the number of bytes downloaded from swarm.
		// Because some pieces may be downloaded more than once, this number may be greater than BytesCompleted returns.
		// TODO put into resume
		Downloaded int64

		// Protocol messages are not included, only piece data is counted.
		Uploaded int64

		Wasted int64

		// BytesUploaded is the number of bytes uploaded to the swarm.
		// TODO BytesUploaded   int64
	}

	Peers struct {
		Connected struct {
			// Number of peers that are connected, handshaked and ready to send and receive messages.
			// ConnectedPeers = IncomingPeers + OutgoingPeers
			Total int

			// Number of peers that have connected to us.
			Incoming int

			// Number of peers that we have connected to.
			Outgoing int
		}

		Handshake struct {
			// Number of peers that are not handshaked yet.
			Total int

			// Number of incoming peers in handshake state.
			Incoming int

			// Number of outgoing peers in handshake state.
			Outgoing int
		}

		// Number of peer addresses that are ready to be connected.
		Ready int
	}

	Downloads struct {
		Piece struct {
			// Number of active piece downloads.
			Total int

			// Number of pieces that are being downloaded normally.
			Running int

			// Number of pieces that are being downloaded too slow.
			Snubbed int

			// Number of piece downloads in choked state.
			Choked int
		}

		Metadata struct {
			// Number of active metadata downloads.
			Total int

			// Number of peers that uploading too slow.
			Snubbed int

			// Number of peers that are being downloaded normally.
			Running int
		}
	}

	Torrent struct {
		Name        string
		Private     bool
		PieceLength uint32
	}
}

func (t *Torrent) stats() Stats {
	var stats Stats
	stats.Status = t.status()
	stats.Error = t.lastError
	stats.Peers.Ready = t.addrList.Len()
	stats.Peers.Handshake.Incoming = len(t.incomingHandshakers)
	stats.Peers.Handshake.Outgoing = len(t.outgoingHandshakers)
	stats.Peers.Handshake.Total = len(t.incomingHandshakers) + len(t.outgoingHandshakers)
	stats.Peers.Connected.Total = len(t.peers)
	stats.Peers.Connected.Incoming = len(t.incomingPeers)
	stats.Peers.Connected.Outgoing = len(t.outgoingPeers)
	stats.Downloads.Metadata.Total = len(t.infoDownloaders)
	stats.Downloads.Metadata.Snubbed = len(t.infoDownloadersSnubbed)
	stats.Downloads.Metadata.Running = len(t.infoDownloaders) - len(t.infoDownloadersSnubbed)
	stats.Downloads.Piece.Total = len(t.pieceDownloaders)
	stats.Downloads.Piece.Snubbed = len(t.pieceDownloadersSnubbed)
	stats.Downloads.Piece.Choked = len(t.pieceDownloadersChoked)
	stats.Downloads.Piece.Running = len(t.pieceDownloaders) - len(t.pieceDownloadersChoked) - len(t.pieceDownloadersSnubbed)

	if t.info != nil {
		stats.Bytes.Total = t.info.TotalLength
		stats.Bytes.Complete = t.bytesComplete()
		stats.Bytes.Incomplete = stats.Bytes.Total - stats.Bytes.Complete

		stats.Torrent.Name = t.info.Name
		stats.Torrent.Private = (t.info.Private == 1)
		stats.Torrent.PieceLength = t.info.PieceLength
	} else {
		// Some trackers don't send any peer address if don't tell we have missing bytes.
		stats.Bytes.Incomplete = math.MaxUint32

		stats.Torrent.Name = t.name
	}
	if t.bitfield != nil {
		stats.Pieces.Total = t.bitfield.Len()
		stats.Pieces.Have = t.bitfield.Count()
		stats.Pieces.Missing = stats.Pieces.Total - stats.Pieces.Have
	}
	stats.Bytes.Downloaded = t.bytesDownloaded
	stats.Bytes.Uploaded = t.bytesUploaded
	stats.Bytes.Wasted = t.bytesWasted
	return stats
}

func (t *Torrent) bytesComplete() int64 {
	if t.bitfield == nil {
		return 0
	}
	n := int64(t.info.PieceLength) * int64(t.bitfield.Count())
	if t.bitfield.Test(t.bitfield.Len() - 1) {
		n -= int64(t.info.PieceLength)
		n += int64(t.pieces[t.bitfield.Len()-1].Length)
	}
	return n
}
<|endoftext|>