<commit_before>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/opt/local/lib -L/usr/lib -lopendkim
#cgo CFLAGS: -g -O2 -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"unsafe"
)

type (
	Canon  int
	Sign   int
	Status int
	Op     int
	Option int
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            Status = 0  // function completed successfully
	StatusBADSIG        Status = 1  // signature available but failed
	StatusNOSIG         Status = 2  // no signature available
	StatusNOKEY         Status = 3  // public key not found
	StatusCANTVRFY      Status = 4  // can't get domain key to verify
	StatusSYNTAX        Status = 5  // message is not valid syntax
	StatusNORESOURCE    Status = 6  // resource unavailable
	StatusINTERNAL      Status = 7  // internal error
	StatusREVOKED       Status = 8  // key found, but revoked
	StatusINVALID       Status = 9  // invalid function parameter
	StatusNOTIMPLEMENT  Status = 10 // function not implemented
	StatusKEYFAIL       Status = 11 // key retrieval failed
	StatusCBREJECT      Status = 12 // callback requested reject
	StatusCBINVALID     Status = 13 // callback gave invalid result
	StatusCBTRYAGAIN    Status = 14 // callback says try again later
	StatusCBERROR       Status = 15 // callback error
	StatusMULTIDNSREPLY Status = 16 // multiple DNS replies
	StatusSIGGEN        Status = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          Option = 0x0000
	LibflagsTMPFILES      Option = 0x0001
	LibflagsKEEPFILES     Option = 0x0002
	LibflagsSIGNLEN       Option = 0x0004
	LibflagsCACHE         Option = 0x0008
	LibflagsZTAGS         Option = 0x0010
	LibflagsDELAYSIGPROC  Option = 0x0020
	LibflagsEOHCHECK      Option = 0x0040
	LibflagsACCEPTV05     Option = 0x0080
	LibflagsFIXCRLF       Option = 0x0100
	LibflagsACCEPTDK      Option = 0x0200
	LibflagsBADSIGHANDLES Option = 0x0400
	LibflagsVERIFYONE     Option = 0x0800
	LibflagsSTRICTHDRS    Option = 0x1000
	LibflagsREPORTBADADSP Option = 0x2000
	LibflagsDROPSIGNER    Option = 0x4000
	LibflagsSTRICTRESIGN  Option = 0x8000
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

var lib *C.struct_DKIM_LIB

func init() {
	lib = C.dkim_init(nil, nil)
	if lib == nil {
		panic("could not init libopendkim")
	}
}

func SetOption(opt Option, data []byte) {
	C.dkim_options(lib, C.int(SetOpt), C.dkim_opts_t(opt), unsafe.Pointer(&data[0]), C.size_t(len(data)))
}

type Dkim struct {
	dkim *C.DKIM
	stat C.DKIM_STAT
	mtx  sync.Mutex
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) *Dkim {
	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&signer.stat,
	)
	if signer.dkim == nil {
		panic("could not create DKIM handle")
	}
	runtime.SetFinalizer(signer, func(s *Dkim) {
		s.Destroy()
	})
	return signer
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) error {
	data := []byte(line)
	var stat C.DKIM_STAT
	stat = C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing header (%s)", getErr(stat))
	}
	return nil
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() error {
	var stat C.DKIM_STAT
	stat = C.dkim_eoh(d.dkim)
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing header (%s)", getErr(stat))
	}
	return nil
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) error {
	var stat C.DKIM_STAT
	stat = C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing body (%s)", getErr(stat))
	}
	return nil
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) error {
	var stat C.DKIM_STAT
	stat = C.dkim_eom(d.dkim, (*C._Bool)(testKey))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing message (%s)", getErr(stat))
	}
	return nil
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if Status(stat) != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, error) {
	var stat C.DKIM_STAT
	var buf = make([]byte, 1024)
	stat = C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0))
	if Status(stat) != StatusOK {
		return "", fmt.Errorf("error computing signature header (%s)", getErr(stat))
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), nil
	}
	return string(buf), nil
}

// GetError gets the last error for the dkim handle
func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

// Destroy destroys the dkim handle
func (d *Dkim) Destroy() error {
	d.mtx.Lock()
	defer d.mtx.Unlock()
	if d.dkim != nil {
		var stat C.DKIM_STAT
		stat = C.dkim_free(d.dkim)
		if Status(stat) != StatusOK {
			return fmt.Errorf("could not destroy DKIM handle (%s)", getErr(stat))
		}
		d.dkim = nil
	}
	return nil
}

func getErr(s C.DKIM_STAT) string {
	return (&dkimError{s}).Error()
}

type dkimError struct {
	stat C.DKIM_STAT
}

func (err *dkimError) Error() string {
	return fmt.Sprintf("%d: %s", err.stat, C.GoString(C.dkim_getresultstr(err.stat)))
}
<commit_msg>Flags are not options<commit_after>// +build !windows

package opendkim

/*
#cgo LDFLAGS: -L/opt/local/lib -L/usr/lib -lopendkim
#cgo CFLAGS: -g -O2 -I/opt/local/include/opendkim/ -I/usr/include/opendkim/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dkim.h>
*/
import "C"

import (
	"bytes"
	"fmt"
	"runtime"
	"sync"
	"unsafe"
)

type (
	Canon  int
	Sign   int
	Status int
	Op     int
	Option int
)

const (
	CanonUNKNOWN Canon = (-1) // unknown method
	CanonSIMPLE  Canon = 0    // as specified in DKIM spec
	CanonRELAXED Canon = 1    // as specified in DKIM spec
)

const (
	SignUNKNOWN   Sign = -2 // unknown method
	SignDEFAULT   Sign = -1 // use internal default
	SignRSASHA1   Sign = 0  // an RSA-signed SHA1 digest
	SignRSASHA256 Sign = 1  // an RSA-signed SHA256 digest
)

const (
	StatusOK            Status = 0  // function completed successfully
	StatusBADSIG        Status = 1  // signature available but failed
	StatusNOSIG         Status = 2  // no signature available
	StatusNOKEY         Status = 3  // public key not found
	StatusCANTVRFY      Status = 4  // can't get domain key to verify
	StatusSYNTAX        Status = 5  // message is not valid syntax
	StatusNORESOURCE    Status = 6  // resource unavailable
	StatusINTERNAL      Status = 7  // internal error
	StatusREVOKED       Status = 8  // key found, but revoked
	StatusINVALID       Status = 9  // invalid function parameter
	StatusNOTIMPLEMENT  Status = 10 // function not implemented
	StatusKEYFAIL       Status = 11 // key retrieval failed
	StatusCBREJECT      Status = 12 // callback requested reject
	StatusCBINVALID     Status = 13 // callback gave invalid result
	StatusCBTRYAGAIN    Status = 14 // callback says try again later
	StatusCBERROR       Status = 15 // callback error
	StatusMULTIDNSREPLY Status = 16 // multiple DNS replies
	StatusSIGGEN        Status = 17 // signature generation failed
)

const (
	OptionFLAGS        Option = 0
	OptionTMPDIR       Option = 1
	OptionTIMEOUT      Option = 2
	OptionSENDERHDRS   Option = 3
	OptionSIGNHDRS     Option = 4
	OptionOVERSIGNHDRS Option = 5
	OptionQUERYMETHOD  Option = 6
	OptionQUERYINFO    Option = 7
	OptionFIXEDTIME    Option = 8
	OptionSKIPHDRS     Option = 9
	OptionALWAYSHDRS   Option = 10 // obsolete
	OptionSIGNATURETTL Option = 11
	OptionCLOCKDRIFT   Option = 12
	OptionMUSTBESIGNED Option = 13
	OptionMINKEYBITS   Option = 14
	OptionREQUIREDHDRS Option = 15
)

const (
	LibflagsNONE          = 0x0000
	LibflagsTMPFILES      = 0x0001
	LibflagsKEEPFILES     = 0x0002
	LibflagsSIGNLEN       = 0x0004
	LibflagsCACHE         = 0x0008
	LibflagsZTAGS         = 0x0010
	LibflagsDELAYSIGPROC  = 0x0020
	LibflagsEOHCHECK      = 0x0040
	LibflagsACCEPTV05     = 0x0080
	LibflagsFIXCRLF       = 0x0100
	LibflagsACCEPTDK      = 0x0200
	LibflagsBADSIGHANDLES = 0x0400
	LibflagsVERIFYONE     = 0x0800
	LibflagsSTRICTHDRS    = 0x1000
	LibflagsREPORTBADADSP = 0x2000
	LibflagsDROPSIGNER    = 0x4000
	LibflagsSTRICTRESIGN  = 0x8000
)

const (
	GetOpt Op = 0
	SetOpt Op = 1
)

var lib *C.struct_DKIM_LIB

func init() {
	lib = C.dkim_init(nil, nil)
	if lib == nil {
		panic("could not init libopendkim")
	}
}

func SetOption(opt Option, data []byte) {
	C.dkim_options(lib, C.int(SetOpt), C.dkim_opts_t(opt), unsafe.Pointer(&data[0]), C.size_t(len(data)))
}

type Dkim struct {
	dkim *C.DKIM
	stat C.DKIM_STAT
	mtx  sync.Mutex
}

// NewSigner creates a new DKIM handle for message signing.
// If -1 is specified for bytesToSign, the whole message body will be signed.
func NewSigner(secret, selector, domain string, hdrCanon, bodyCanon Canon, algo Sign, bytesToSign int64) *Dkim {
	signer := new(Dkim)
	signer.dkim = C.dkim_sign(
		lib,
		nil,
		nil,
		(*C.uchar)(unsafe.Pointer(C.CString(secret))),
		(*C.uchar)(unsafe.Pointer(C.CString(selector))),
		(*C.uchar)(unsafe.Pointer(C.CString(domain))),
		C.dkim_canon_t(hdrCanon),
		C.dkim_canon_t(bodyCanon),
		C.dkim_alg_t(algo),
		C.ssize_t(bytesToSign),
		&signer.stat,
	)
	if signer.dkim == nil {
		panic("could not create DKIM handle")
	}
	runtime.SetFinalizer(signer, func(s *Dkim) {
		s.Destroy()
	})
	return signer
}

// Header processes a single header line.
// May be invoked multiple times.
func (d *Dkim) Header(line string) error {
	data := []byte(line)
	var stat C.DKIM_STAT
	stat = C.dkim_header(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing header (%s)", getErr(stat))
	}
	return nil
}

// Eoh is called to signal end of header.
func (d *Dkim) Eoh() error {
	var stat C.DKIM_STAT
	stat = C.dkim_eoh(d.dkim)
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing header (%s)", getErr(stat))
	}
	return nil
}

// Body processes the message body.
func (d *Dkim) Body(data []byte) error {
	var stat C.DKIM_STAT
	stat = C.dkim_body(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error processing body (%s)", getErr(stat))
	}
	return nil
}

// Eom is called to signal end of message.
func (d *Dkim) Eom(testKey *bool) error {
	var stat C.DKIM_STAT
	stat = C.dkim_eom(d.dkim, (*C._Bool)(testKey))
	if Status(stat) != StatusOK {
		return fmt.Errorf("error closing message (%s)", getErr(stat))
	}
	return nil
}

// Chunk processes a chunk of message data.
// Can include header and body data.
//
// TODO: disabled until I figure out what's fould here
//
// func (d *Dkim) Chunk(data []byte) error {
// 	var stat C.DKIM_STAT
// 	stat = C.dkim_chunk(d.dkim, (*C.u_char)(unsafe.Pointer(&data[0])), C.size_t(len(data)))
// 	if Status(stat) != StatusOK {
// 		return fmt.Errorf("error processing chunk (%s)", getErr(stat))
// 	}
// 	return nil
// }

// GetSigHdr computes the signature header for a message.
func (d *Dkim) GetSigHdr() (string, error) {
	var stat C.DKIM_STAT
	var buf = make([]byte, 1024)
	stat = C.dkim_getsighdr(d.dkim, (*C.u_char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)), C.size_t(0))
	if Status(stat) != StatusOK {
		return "", fmt.Errorf("error computing signature header (%s)", getErr(stat))
	}
	i := bytes.Index(buf, []byte{0x0})
	if i >= 0 {
		return string(buf[:i]), nil
	}
	return string(buf), nil
}

// GetError gets the last error for the dkim handle
func (d *Dkim) GetError() string {
	return C.GoString(C.dkim_geterror(d.dkim))
}

// Destroy destroys the dkim handle
func (d *Dkim) Destroy() error {
	d.mtx.Lock()
	defer d.mtx.Unlock()
	if d.dkim != nil {
		var stat C.DKIM_STAT
		stat = C.dkim_free(d.dkim)
		if Status(stat) != StatusOK {
			return fmt.Errorf("could not destroy DKIM handle (%s)", getErr(stat))
		}
		d.dkim = nil
	}
	return nil
}

func getErr(s C.DKIM_STAT) string {
	return (&dkimError{s}).Error()
}

type dkimError struct {
	stat C.DKIM_STAT
}

func (err *dkimError) Error() string {
	return fmt.Sprintf("%d: %s", err.stat, C.GoString(C.dkim_getresultstr(err.stat)))
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"sync"

	_ "github.com/mattn/go-sqlite3"
)

const (
	thumbsDir      = "public/thumbs"
	bigThumbSize   = "1000x1000"
	smallThumbSize = "200x200"
	workers        = 4 // min: 1
)

func generateSmallThumb(photoPath, identifier string) (thumbPath string, err error) {
	thumbPath = path.Join(thumbsDir, fmt.Sprintf("%s_small.jpg", identifier))
	if _, err = os.Stat(thumbPath); os.IsNotExist(err) { // file does not exist
		err = exec.Command(
			"convert", photoPath,
			"-auto-orient",
			"-strip",
			"-resize", smallThumbSize+"^",
			"-gravity", "center",
			"-extent", smallThumbSize,
			thumbPath).Run()
	}
	return
}

func generateBigThumb(photoPath, identifier string) (thumbPath string, err error) {
	thumbPath = path.Join(thumbsDir, fmt.Sprintf("%s_big.jpg", identifier))
	if _, err = os.Stat(thumbPath); os.IsNotExist(err) { // file does not exist
		err = exec.Command(
			"convert", photoPath,
			"-auto-orient",
			"-strip",
			"-resize", bigThumbSize,
			thumbPath).Run()
	}
	return
}

func generateThumb(ch chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	for photoPath := range ch {
		identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))

		bigThumbPath, err := generateBigThumb(photoPath, identifier)
		if err != nil { // error
			return
		}

		fmt.Println(bigThumbPath)

		smallThumbPath, err := generateSmallThumb(bigThumbPath, identifier)
		if err == nil { // success
			fmt.Println(smallThumbPath)
		}
	}
}

func main() {
	if workers < 1 {
		log.Fatal("number of workers must be at least 1")
	}

	db, err := sql.Open("sqlite3", "thyme.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	rows, err := db.Query(`
	SELECT path FROM photos
	JOIN sets ON photos.set_id = sets.id
	ORDER BY sets.taken_at DESC, photos.taken_at ASC
	`)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	if err := os.MkdirAll(thumbsDir, os.ModeDir|0755); err != nil {
		log.Fatal(err)
	}

	ch := make(chan string)
	wg := sync.WaitGroup{}

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go generateThumb(ch, &wg)
	}

	for rows.Next() {
		var photoPath string
		rows.Scan(&photoPath)
		ch <- photoPath
	}

	close(ch)
	wg.Wait()

	if err := rows.Err(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Extract thumb generation into an implementation function<commit_after>package main

import (
	"crypto/md5"
	"database/sql"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"sync"

	_ "github.com/mattn/go-sqlite3"
)

const (
	thumbsDir      = "public/thumbs"
	bigThumbSize   = "1000x1000"
	smallThumbSize = "200x200"
	workers        = 4 // min: 1
)

func generateSmallThumb(photoPath, identifier string) (thumbPath string, err error) {
	thumbPath = path.Join(thumbsDir, fmt.Sprintf("%s_small.jpg", identifier))
	if _, err = os.Stat(thumbPath); os.IsNotExist(err) { // file does not exist
		err = exec.Command(
			"convert", photoPath,
			"-auto-orient",
			"-strip",
			"-resize", smallThumbSize+"^",
			"-gravity", "center",
			"-extent", smallThumbSize,
			thumbPath).Run()
	}
	return
}

func generateBigThumb(photoPath, identifier string) (thumbPath string, err error) {
	thumbPath = path.Join(thumbsDir, fmt.Sprintf("%s_big.jpg", identifier))
	if _, err = os.Stat(thumbPath); os.IsNotExist(err) { // file does not exist
		err = exec.Command(
			"convert", photoPath,
			"-auto-orient",
			"-strip",
			"-resize", bigThumbSize,
			thumbPath).Run()
	}
	return
}

func generateThumbsImpl(photoPath string) {
	identifier := fmt.Sprintf("%x", md5.Sum([]byte(photoPath)))

	bigThumbPath, err := generateBigThumb(photoPath, identifier)
	if err != nil { // error
		return
	}

	fmt.Println(bigThumbPath)

	smallThumbPath, err := generateSmallThumb(bigThumbPath, identifier)
	if err == nil { // success
		fmt.Println(smallThumbPath)
	}
}

func generateThumbs(ch chan string, wg *sync.WaitGroup) {
	defer wg.Done()

	for photoPath := range ch {
		generateThumbsImpl(photoPath)
	}
}

func main() {
	if workers < 1 {
		log.Fatal("number of workers must be at least 1")
	}

	db, err := sql.Open("sqlite3", "thyme.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	rows, err := db.Query(`
	SELECT path FROM photos
	JOIN sets ON photos.set_id = sets.id
	ORDER BY sets.taken_at DESC, photos.taken_at ASC
	`)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	if err := os.MkdirAll(thumbsDir, os.ModeDir|0755); err != nil {
		log.Fatal(err)
	}

	ch := make(chan string)
	wg := sync.WaitGroup{}

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go generateThumbs(ch, &wg)
	}

	for rows.Next() {
		var photoPath string
		rows.Scan(&photoPath)
		ch <- photoPath
	}

	close(ch)
	wg.Wait()

	if err := rows.Err(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package action

import (
	"errors"
	"fmt"
	"strings"

	"golang.org/x/net/websocket"
)

var (
	errNotImplemented = errors.New("Not Implemented!")
)

// Exec execute the js code on WebBrowser
func Exec(ws *websocket.Conn, js string) error {
	return websocket.Message.Send(ws, js)
}

//Set update a form element (textbox, dropdown, checkbox, etc) to set text value of TargetID.
func Set(ws *websocket.Conn, target, value string) error {
	return errNotImplemented
}

//Enable the target form field or button.
func Enable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Disable  the target form field or button.
func Disable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Replace target with new content
func Replace(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).replaceWith(\"%s\");", target, c)
	return websocket.Message.Send(ws, js)
}

//Replace target with new content
func Html(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).html(\"%s\");", target, c)
	return websocket.Message.Send(ws, js)
}

//Remove target from the DOM
func Remove(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//InsertTop Insert content at the top of target
func InsertTop(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBottom Insert content at the bottom of target
func InsertBottom(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBefore Insert content at the before of target
func InsertBefore(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertAfter Insert content at the after of target
func InsertAfter(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//Redirect to url
func Redirect(ws *websocket.Conn, url string) error {
	return errNotImplemented
}

//Get content of form element
func Get(ws *websocket.Conn, target string) (string, error) {
	ret := ""
	js := fmt.Sprintf("ws.send($('#%s').val());", target)
	err := websocket.Message.Send(ws, js)
	if err != nil {
		return "", err
	}

	err = websocket.Message.Receive(ws, &ret)
	if err != nil {
		return "", err
	}

	return ret, nil
}

//Wire bind an action to an event on target
func Wire(ws *websocket.Conn, target, event, act string) error {
	return errNotImplemented
}
<commit_msg>2 new actions<commit_after>package action

import (
	"errors"
	"fmt"
	"strings"

	"golang.org/x/net/websocket"
)

var (
	errNotImplemented = errors.New("Not Implemented!")
)

// Exec execute the js code on WebBrowser
func Exec(ws *websocket.Conn, js string) error {
	return websocket.Message.Send(ws, js)
}

//Set update a form element (textbox, dropdown, checkbox, etc) to set text value of TargetID.
func Set(ws *websocket.Conn, target, value string) error {
	return errNotImplemented
}

//Enable the target form field or button.
func Enable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Disable  the target form field or button.
func Disable(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//Replace target with new content
func Replace(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).replaceWith(\"%s\");", target, c)
	return websocket.Message.Send(ws, js)
}

//Replace target with new content
func Html(ws *websocket.Conn, target, content string) error {
	c := strings.Replace(content, "\n", "\\n", -1)
	c = strings.Replace(c, "\"", "\\\"", -1)
	js := fmt.Sprintf("$( \"#%s\" ).html(\"%s\");", target, c)
	return websocket.Message.Send(ws, js)
}

//Remove target from the DOM
func Remove(ws *websocket.Conn, target string) error {
	return errNotImplemented
}

//InsertTop Insert content at the top of target
func InsertTop(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBottom Insert content at the bottom of target
func InsertBottom(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertBefore Insert content at the before of target
func InsertBefore(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//InsertAfter Insert content at the after of target
func InsertAfter(ws *websocket.Conn, target, content string) error {
	return errNotImplemented
}

//Redirect to url
func Redirect(ws *websocket.Conn, url string) error {
	return errNotImplemented
}

//Get content of form element
func Get(ws *websocket.Conn, target string) (string, error) {
	ret := ""
	js := fmt.Sprintf("ws.send($('#%s').val());", target)
	err := websocket.Message.Send(ws, js)
	if err != nil {
		return "", err
	}

	err = websocket.Message.Receive(ws, &ret)
	if err != nil {
		return "", err
	}

	return ret, nil
}

//Wire bind an action to an event on target
func Wire(ws *websocket.Conn, target, event, act string) error {
	return errNotImplemented
}

func SendEvent(ws *websocket.Conn, event string) error {
	js := fmt.Sprintf("ws.send('%s');", event)
	err := websocket.Message.Send(ws, js)
	if err != nil {
		return err
	}

	return nil
}

func Alert(ws *websocket.Conn, message string) error {
	js := fmt.Sprintf("alert('%s');", message)
	err := websocket.Message.Send(ws, js)
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


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

package virtual

import (
	"time"

	"github.ibm.com/riethm/gopherlayer.git/datatypes"
	"github.ibm.com/riethm/gopherlayer.git/helpers/product"
	"github.ibm.com/riethm/gopherlayer.git/services"
	"github.ibm.com/riethm/gopherlayer.git/session"
	"github.ibm.com/riethm/gopherlayer.git/sl"
)

// Upgrade a virtual guest specified with an id, and a set of features to
// upgrade. When the upgrade takes place can also be specified (`when`), but
// this is optional. The time set will be 'now' if left as nil.
// The features to upgrade are specified as the options used in
// GetProductPrices().
func UpgradeVirtualGuest(
	sess *session.Session,
	id int,
	options map[string]float64,
	when ...time.Time,
) (datatypes.Container_Product_Order_Receipt, error) {

	pkg, err := product.GetPackageByType(sess, "VIRTUAL_SERVER_INSTANCE")
	if err != nil {
		return datatypes.Container_Product_Order_Receipt{}, err
	}

	productItems, err := product.GetPackageProducts(sess, *pkg.Id)
	if err != nil {
		return datatypes.Container_Product_Order_Receipt{}, err
	}

	prices := product.SelectProductPricesByCategory(productItems, options)

	upgradeTime := time.Now().UTC().Format(time.RFC3339)
	if len(when) > 0 {
		upgradeTime = when[0].UTC().Format(time.RFC3339)
	}

	order := datatypes.Container_Product_Order{
		VirtualGuests: []datatypes.Virtual_Guest{
			{Id: &id},
		},
		Prices: prices,
		Properties: []datatypes.Container_Product_Order_Property{
			{
				Name:  sl.String("MAINTENANCE_WINDOW"),
				Value: &upgradeTime,
			},
		},
	}

	orderService := services.GetProductOrderService(sess)
	return orderService.PlaceOrder(&order, sl.Bool(false))
}
<commit_msg>Add package id to order when upgrading virtual guest<commit_after>/**
 * Copyright 2016 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package virtual

import (
	"time"

	"github.ibm.com/riethm/gopherlayer.git/datatypes"
	"github.ibm.com/riethm/gopherlayer.git/helpers/product"
	"github.ibm.com/riethm/gopherlayer.git/services"
	"github.ibm.com/riethm/gopherlayer.git/session"
	"github.ibm.com/riethm/gopherlayer.git/sl"
)

// Upgrade a virtual guest specified with an id, and a set of features to
// upgrade. When the upgrade takes place can also be specified (`when`), but
// this is optional. The time set will be 'now' if left as nil.
// The features to upgrade are specified as the options used in
// GetProductPrices().
func UpgradeVirtualGuest(
	sess *session.Session,
	id int,
	options map[string]float64,
	when ...time.Time,
) (datatypes.Container_Product_Order_Receipt, error) {

	pkg, err := product.GetPackageByType(sess, "VIRTUAL_SERVER_INSTANCE")
	if err != nil {
		return datatypes.Container_Product_Order_Receipt{}, err
	}

	productItems, err := product.GetPackageProducts(sess, *pkg.Id)
	if err != nil {
		return datatypes.Container_Product_Order_Receipt{}, err
	}

	prices := product.SelectProductPricesByCategory(productItems, options)

	upgradeTime := time.Now().UTC().Format(time.RFC3339)
	if len(when) > 0 {
		upgradeTime = when[0].UTC().Format(time.RFC3339)
	}

	order := datatypes.Container_Product_Order{
		PackageId: pkg.Id,
		VirtualGuests: []datatypes.Virtual_Guest{
			{Id: &id},
		},
		Prices: prices,
		Properties: []datatypes.Container_Product_Order_Property{
			{
				Name:  sl.String("MAINTENANCE_WINDOW"),
				Value: &upgradeTime,
			},
		},
	}

	orderService := services.GetProductOrderService(sess)
	return orderService.PlaceOrder(&order, sl.Bool(false))
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"errors"
	"io"
	"net"
	"net/url"
	"reflect"
	"sync"
	"syscall"
	"time"

	apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
	"github.com/golang/glog"
)

// ListerWatcher is any object that knows how to perform an initial list and start a watch on a resource.
type ListerWatcher interface {
	// List should return a list type object; the Items field will be extracted, and the
	// ResourceVersion field will be used to start the watch in the right place.
	List() (runtime.Object, error)
	// Watch should begin a watch at the specified version.
	Watch(resourceVersion string) (watch.Interface, error)
}

// Reflector watches a specified resource and causes all changes to be reflected in the given store.
type Reflector struct {
	// The type of object we expect to place in the store.
	expectedType reflect.Type
	// The destination to sync up with the watch source
	store Store
	// listerWatcher is used to perform lists and watches.
	listerWatcher ListerWatcher
	// period controls timing between one watch ending and
	// the beginning of the next one.
	period       time.Duration
	resyncPeriod time.Duration
	// lastSyncResourceVersion is the resource version token last
	// observed when doing a sync with the underlying store
	// it is thread safe, but not synchronized with the underlying store
	lastSyncResourceVersion string
	// lastSyncResourceVersionMutex guards read/write access to lastSyncResourceVersion
	lastSyncResourceVersionMutex sync.RWMutex
}

// NewNamespaceKeyedIndexerAndReflector creates an Indexer and a Reflector
// The indexer is configured to key on namespace
func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interface{}, resyncPeriod time.Duration) (indexer Indexer, reflector *Reflector) {
	indexer = NewIndexer(MetaNamespaceKeyFunc, Indexers{"namespace": MetaNamespaceIndexFunc})
	reflector = NewReflector(lw, expectedType, indexer, resyncPeriod)
	return indexer, reflector
}

// NewReflector creates a new Reflector object which will keep the given store up to
// date with the server's contents for the given resource. Reflector promises to
// only put things in the store that have the type of expectedType.
// If resyncPeriod is non-zero, then lists will be executed after every resyncPeriod,
// so that you can use reflectors to periodically process everything as well as
// incrementally processing the things that change.
func NewReflector(lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector {
	r := &Reflector{
		listerWatcher: lw,
		store:         store,
		expectedType:  reflect.TypeOf(expectedType),
		period:        time.Second,
		resyncPeriod:  resyncPeriod,
	}
	return r
}

// Run starts a watch and handles watch events. Will restart the watch if it is closed.
// Run starts a goroutine and returns immediately.
func (r *Reflector) Run() {
	go util.Forever(func() { r.listAndWatch(util.NeverStop) }, r.period)
}

// RunUntil starts a watch and handles watch events. Will restart the watch if it is closed.
// RunUntil starts a goroutine and returns immediately. It will exit when stopCh is closed.
func (r *Reflector) RunUntil(stopCh <-chan struct{}) {
	go util.Until(func() { r.listAndWatch(stopCh) }, r.period, stopCh)
}

var (
	// nothing will ever be sent down this channel
	neverExitWatch <-chan time.Time = make(chan time.Time)

	// Used to indicate that watching stopped so that a resync could happen.
	errorResyncRequested = errors.New("resync channel fired")

	// Used to indicate that watching stopped because of a signal from the stop
	// channel passed in from a client of the reflector.
	errorStopRequested = errors.New("Stop requested")
)

// resyncChan returns a channel which will receive something when a resync is
// required, and a cleanup function.
func (r *Reflector) resyncChan() (<-chan time.Time, func() bool) {
	if r.resyncPeriod == 0 {
		return neverExitWatch, func() bool { return false }
	}
	// The cleanup function is required: imagine the scenario where watches
	// always fail so we end up listing frequently. Then, if we don't
	// manually stop the timer, we could end up with many timers active
	// concurrently.
	t := time.NewTimer(r.resyncPeriod)
	return t.C, t.Stop
}

func (r *Reflector) listAndWatch(stopCh <-chan struct{}) {
	var resourceVersion string
	resyncCh, cleanup := r.resyncChan()
	defer cleanup()

	list, err := r.listerWatcher.List()
	if err != nil {
		glog.Errorf("Failed to list %v: %v", r.expectedType, err)
		return
	}
	meta, err := meta.Accessor(list)
	if err != nil {
		glog.Errorf("Unable to understand list result %#v", list)
		return
	}
	resourceVersion = meta.ResourceVersion()
	items, err := runtime.ExtractList(list)
	if err != nil {
		glog.Errorf("Unable to understand list result %#v (%v)", list, err)
		return
	}
	if err := r.syncWith(items); err != nil {
		glog.Errorf("Unable to sync list result: %v", err)
		return
	}
	r.setLastSyncResourceVersion(resourceVersion)

	for {
		w, err := r.listerWatcher.Watch(resourceVersion)
		if err != nil {
			switch err {
			case io.EOF:
				// watch closed normally
			case io.ErrUnexpectedEOF:
				glog.V(1).Infof("Watch for %v closed with unexpected EOF: %v", r.expectedType, err)
			default:
				glog.Errorf("Failed to watch %v: %v", r.expectedType, err)
			}
			// If this is "connection refused" error, it means that most likely apiserver is not responsive.
			// It doesn't make sense to re-list all objects because most likely we will be able to restart
			// watch where we ended.
			// If that's the case wait and resend watch request.
			if urlError, ok := err.(*url.Error); ok {
				if opError, ok := urlError.Err.(*net.OpError); ok {
					if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
						time.Sleep(time.Second)
						continue
					}
				}
			}
			return
		}
		if err := r.watchHandler(w, &resourceVersion, resyncCh, stopCh); err != nil {
			if err != errorResyncRequested && err != errorStopRequested {
				glog.Errorf("watch of %v ended with: %v", r.expectedType, err)
			}
			return
		}
	}
}

// syncWith replaces the store's items with the given list.
func (r *Reflector) syncWith(items []runtime.Object) error {
	found := make([]interface{}, 0, len(items))
	for _, item := range items {
		found = append(found, item)
	}

	return r.store.Replace(found)
}

// watchHandler watches w and keeps *resourceVersion up to date.
func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, resyncCh <-chan time.Time, stopCh <-chan struct{}) error {
	start := time.Now()
	eventCount := 0

	// Stopping the watcher should be idempotent and if we return from this function there's no way
	// we're coming back in with the same watch interface.
	defer w.Stop()

loop:
	for {
		select {
		case <-stopCh:
			return errorStopRequested
		case <-resyncCh:
			return errorResyncRequested
		case event, ok := <-w.ResultChan():
			if !ok {
				break loop
			}
			if event.Type == watch.Error {
				return apierrs.FromObject(event.Object)
			}
			if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a {
				glog.Errorf("expected type %v, but watch event object had type %v", e, a)
				continue
			}
			meta, err := meta.Accessor(event.Object)
			if err != nil {
				glog.Errorf("unable to understand watch event %#v", event)
				continue
			}
			switch event.Type {
			case watch.Added:
				r.store.Add(event.Object)
			case watch.Modified:
				r.store.Update(event.Object)
			case watch.Deleted:
				// TODO: Will any consumers need access to the "last known
				// state", which is passed in event.Object? If so, may need
				// to change this.
				r.store.Delete(event.Object)
			default:
				glog.Errorf("unable to understand watch event %#v", event)
			}
			*resourceVersion = meta.ResourceVersion()
			r.setLastSyncResourceVersion(*resourceVersion)
			eventCount++
		}
	}

	watchDuration := time.Now().Sub(start)
	if watchDuration < 1*time.Second && eventCount == 0 {
		glog.V(4).Infof("Unexpected watch close - watch lasted less than a second and no items received")
		return errors.New("very short watch")
	}
	glog.V(4).Infof("Watch close - %v total %v items received", r.expectedType, eventCount)
	return nil
}

// LastSyncResourceVersion is the resource version observed when last sync with the underlying store
// The value returned is not synchronized with access to the underlying store and is not thread-safe
func (r *Reflector) LastSyncResourceVersion() string {
	r.lastSyncResourceVersionMutex.RLock()
	defer r.lastSyncResourceVersionMutex.RUnlock()
	return r.lastSyncResourceVersion
}

func (r *Reflector) setLastSyncResourceVersion(v string) {
	r.lastSyncResourceVersionMutex.Lock()
	defer r.lastSyncResourceVersionMutex.Unlock()
	r.lastSyncResourceVersion = v
}
<commit_msg>UPSTREAM: 10024: add originator to reflector logging<commit_after>/*
Copyright 2014 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cache

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/url"
	"reflect"
	goruntime "runtime"
	"strings"
	"sync"
	"syscall"
	"time"

	apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
	"github.com/golang/glog"
)

// ListerWatcher is any object that knows how to perform an initial list and start a watch on a resource.
type ListerWatcher interface {
	// List should return a list type object; the Items field will be extracted, and the
	// ResourceVersion field will be used to start the watch in the right place.
	List() (runtime.Object, error)
	// Watch should begin a watch at the specified version.
	Watch(resourceVersion string) (watch.Interface, error)
}

// Reflector watches a specified resource and causes all changes to be reflected in the given store.
type Reflector struct {
	// name identifies this reflector.  By default it will be a file:line if possible.
	name string

	// The type of object we expect to place in the store.
	expectedType reflect.Type
	// The destination to sync up with the watch source
	store Store
	// listerWatcher is used to perform lists and watches.
	listerWatcher ListerWatcher
	// period controls timing between one watch ending and
	// the beginning of the next one.
	period       time.Duration
	resyncPeriod time.Duration
	// lastSyncResourceVersion is the resource version token last
	// observed when doing a sync with the underlying store
	// it is thread safe, but not synchronized with the underlying store
	lastSyncResourceVersion string
	// lastSyncResourceVersionMutex guards read/write access to lastSyncResourceVersion
	lastSyncResourceVersionMutex sync.RWMutex
}

// NewNamespaceKeyedIndexerAndReflector creates an Indexer and a Reflector
// The indexer is configured to key on namespace
func NewNamespaceKeyedIndexerAndReflector(lw ListerWatcher, expectedType interface{}, resyncPeriod time.Duration) (indexer Indexer, reflector *Reflector) {
	indexer = NewIndexer(MetaNamespaceKeyFunc, Indexers{"namespace": MetaNamespaceIndexFunc})
	reflector = NewReflector(lw, expectedType, indexer, resyncPeriod)
	return indexer, reflector
}

// NewReflector creates a new Reflector object which will keep the given store up to
// date with the server's contents for the given resource. Reflector promises to
// only put things in the store that have the type of expectedType.
// If resyncPeriod is non-zero, then lists will be executed after every resyncPeriod,
// so that you can use reflectors to periodically process everything as well as
// incrementally processing the things that change.
func NewReflector(lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector {
	return NewNamedReflector(getDefaultReflectorName(internalPackages...), lw, expectedType, store, resyncPeriod)
}

// NewNamedReflector same as NewReflector, but with a specified name for logging
func NewNamedReflector(name string, lw ListerWatcher, expectedType interface{}, store Store, resyncPeriod time.Duration) *Reflector {
	r := &Reflector{
		name:          name,
		listerWatcher: lw,
		store:         store,
		expectedType:  reflect.TypeOf(expectedType),
		period:        time.Second,
		resyncPeriod:  resyncPeriod,
	}
	return r
}

// internalPackages are packages that ignored when creating a default reflector name.  These packages are in the common
// call chains to NewReflector, so they'd be low entropy names for reflectors
var internalPackages = []string{"kubernetes/pkg/client/cache/", "kubernetes/pkg/controller/framework/"}

// getDefaultReflectorName walks back through the call stack until we find a caller from outside of the ignoredPackages
// it returns back a shortpath/filename:line to aid in identification of this reflector when it starts logging
func getDefaultReflectorName(ignoredPackages ...string) string {
	name := "????"
outer:
	for i := 1; i < 10; i++ {
		_, file, line, ok := goruntime.Caller(i)
		if !ok {
			break
		}
		for _, ignoredPackage := range ignoredPackages {
			if strings.Contains(file, ignoredPackage) {
				continue outer
			}

		}

		pkgLocation := strings.LastIndex(file, "/pkg/")
		if pkgLocation >= 0 {
			file = file[pkgLocation+1:]
		}
		name = fmt.Sprintf("%s:%d", file, line)
		break
	}

	return name
}

// Run starts a watch and handles watch events. Will restart the watch if it is closed.
// Run starts a goroutine and returns immediately.
func (r *Reflector) Run() {
	go util.Forever(func() { r.listAndWatch(util.NeverStop) }, r.period)
}

// RunUntil starts a watch and handles watch events. Will restart the watch if it is closed.
// RunUntil starts a goroutine and returns immediately. It will exit when stopCh is closed.
func (r *Reflector) RunUntil(stopCh <-chan struct{}) {
	go util.Until(func() { r.listAndWatch(stopCh) }, r.period, stopCh)
}

var (
	// nothing will ever be sent down this channel
	neverExitWatch <-chan time.Time = make(chan time.Time)

	// Used to indicate that watching stopped so that a resync could happen.
	errorResyncRequested = errors.New("resync channel fired")

	// Used to indicate that watching stopped because of a signal from the stop
	// channel passed in from a client of the reflector.
	errorStopRequested = errors.New("Stop requested")
)

// resyncChan returns a channel which will receive something when a resync is
// required, and a cleanup function.
func (r *Reflector) resyncChan() (<-chan time.Time, func() bool) {
	if r.resyncPeriod == 0 {
		return neverExitWatch, func() bool { return false }
	}
	// The cleanup function is required: imagine the scenario where watches
	// always fail so we end up listing frequently. Then, if we don't
	// manually stop the timer, we could end up with many timers active
	// concurrently.
	t := time.NewTimer(r.resyncPeriod)
	return t.C, t.Stop
}

func (r *Reflector) listAndWatch(stopCh <-chan struct{}) {
	var resourceVersion string
	resyncCh, cleanup := r.resyncChan()
	defer cleanup()

	list, err := r.listerWatcher.List()
	if err != nil {
		util.HandleError(fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err))
		return
	}
	meta, err := meta.Accessor(list)
	if err != nil {
		util.HandleError(fmt.Errorf("%s: Unable to understand list result %#v", r.name, list))
		return
	}
	resourceVersion = meta.ResourceVersion()
	items, err := runtime.ExtractList(list)
	if err != nil {
		util.HandleError(fmt.Errorf("%s: Unable to understand list result %#v (%v)", r.name, list, err))
		return
	}
	if err := r.syncWith(items); err != nil {
		util.HandleError(fmt.Errorf("%s: Unable to sync list result: %v", r.name, err))
		return
	}
	r.setLastSyncResourceVersion(resourceVersion)

	for {
		w, err := r.listerWatcher.Watch(resourceVersion)
		if err != nil {
			switch err {
			case io.EOF:
				// watch closed normally
			case io.ErrUnexpectedEOF:
				glog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err)
			default:
				util.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err))
			}
			// If this is "connection refused" error, it means that most likely apiserver is not responsive.
			// It doesn't make sense to re-list all objects because most likely we will be able to restart
			// watch where we ended.
			// If that's the case wait and resend watch request.
			if urlError, ok := err.(*url.Error); ok {
				if opError, ok := urlError.Err.(*net.OpError); ok {
					if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED {
						time.Sleep(time.Second)
						continue
					}
				}
			}
			return
		}
		if err := r.watchHandler(w, &resourceVersion, resyncCh, stopCh); err != nil {
			if err != errorResyncRequested && err != errorStopRequested {
				util.HandleError(fmt.Errorf("%s: watch of %v ended with: %v", r.name, r.expectedType, err))
			}
			return
		}
	}
}

// syncWith replaces the store's items with the given list.
func (r *Reflector) syncWith(items []runtime.Object) error {
	found := make([]interface{}, 0, len(items))
	for _, item := range items {
		found = append(found, item)
	}

	return r.store.Replace(found)
}

// watchHandler watches w and keeps *resourceVersion up to date.
func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, resyncCh <-chan time.Time, stopCh <-chan struct{}) error {
	start := time.Now()
	eventCount := 0

	// Stopping the watcher should be idempotent and if we return from this function there's no way
	// we're coming back in with the same watch interface.
	defer w.Stop()

loop:
	for {
		select {
		case <-stopCh:
			return errorStopRequested
		case <-resyncCh:
			return errorResyncRequested
		case event, ok := <-w.ResultChan():
			if !ok {
				break loop
			}
			if event.Type == watch.Error {
				return apierrs.FromObject(event.Object)
			}
			if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a {
				util.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a))
				continue
			}
			meta, err := meta.Accessor(event.Object)
			if err != nil {
				util.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event))
				continue
			}
			switch event.Type {
			case watch.Added:
				r.store.Add(event.Object)
			case watch.Modified:
				r.store.Update(event.Object)
			case watch.Deleted:
				// TODO: Will any consumers need access to the "last known
				// state", which is passed in event.Object? If so, may need
				// to change this.
				r.store.Delete(event.Object)
			default:
				util.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event))
			}
			*resourceVersion = meta.ResourceVersion()
			r.setLastSyncResourceVersion(*resourceVersion)
			eventCount++
		}
	}

	watchDuration := time.Now().Sub(start)
	if watchDuration < 1*time.Second && eventCount == 0 {
		glog.V(4).Infof("%s: Unexpected watch close - watch lasted less than a second and no items received", r.name)
		return errors.New("very short watch")
	}
	glog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount)
	return nil
}

// LastSyncResourceVersion is the resource version observed when last sync with the underlying store
// The value returned is not synchronized with access to the underlying store and is not thread-safe
func (r *Reflector) LastSyncResourceVersion() string {
	r.lastSyncResourceVersionMutex.RLock()
	defer r.lastSyncResourceVersionMutex.RUnlock()
	return r.lastSyncResourceVersion
}

func (r *Reflector) setLastSyncResourceVersion(v string) {
	r.lastSyncResourceVersionMutex.Lock()
	defer r.lastSyncResourceVersionMutex.Unlock()
	r.lastSyncResourceVersion = v
}
<|endoftext|>


<commit_before>package luar // import "layeh.com/gopher-luar"

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

// New creates and returns a new lua.LValue for the given value.
//
// The following table shows how Go types are converted to Lua types:
//  Kind            gopher-lua Type  Custom Metatable
//  --------------------------------------------------
//  nil             LNil             No
//  Bool            LBool            No
//  Int             LNumber          No
//  Int8            LNumber          No
//  Int16           LNumber          No
//  Int32           LNumber          No
//  Int64           LNumber          No
//  Uint            LNumber          No
//  Uint8           LNumber          No
//  Uint16          LNumber          No
//  Uint32          LNumber          No
//  Uint64          LNumber          No
//  Uintptr         *LUserData       No
//  Float32         LNumber          No
//  Float64         LNumber          No
//  Complex64       *LUserData       No
//  Complex128      *LUserData       No
//  Array           *LUserData       Yes
//  Chan            *LUserData       Yes
//  Func            *LFunction       No
//  Map             *LUserData       Yes
//  Ptr             *LUserData       Yes
//  Slice           *LUserData       Yes
//  String          LString          No
//  Struct          *LUserData       Yes
//  UnsafePointer   *LUserData       No
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = getMetatableFromValue(L, val)
		return ud
	case reflect.Func:
		return funcWrapper(L, val, false)
	case reflect.String:
		return lua.LString(val.String())
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the returned lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = getTypeMetatable(L, val)

	return ud
}

type conversionError struct {
	Lua  lua.LValue
	Hint reflect.Type
}

func (c conversionError) Error() string {
	if _, isNil := c.Lua.(*lua.LNilType); isNil {
		return fmt.Sprintf("cannot use nil as type %s", c.Hint)
	}

	var val interface{}

	if userData, ok := c.Lua.(*lua.LUserData); ok {
		val = userData.Value
	} else {
		val = c.Lua
	}

	return fmt.Sprintf("cannot use %v (type %T) as type %s", val, val, c.Hint)
}

type structFieldError struct {
	Field string
	Type  reflect.Type
}

func (s structFieldError) Error() string {
	return `type ` + s.Type.String() + ` has no field ` + s.Field
}

func lValueToReflect(L *lua.LState, v lua.LValue, hint reflect.Type, tryConvertPtr *bool) (reflect.Value, error) {
	if hint.Implements(refTypeLuaLValue) {
		return reflect.ValueOf(v), nil
	}

	isPtr := false

	switch converted := v.(type) {
	case lua.LBool:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(bool(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LChannel:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LNumber:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(float64(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LFunction:
		switch {
		case hint == refTypeEmptyIface:
			inOut := []reflect.Type{
				reflect.SliceOf(refTypeEmptyIface),
			}
			hint = reflect.FuncOf(inOut, inOut, true)
		case hint.Kind() != reflect.Func:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}

		fn := func(args []reflect.Value) []reflect.Value {
			thread, _ := L.NewThread()
			thread.Push(converted)

			varadicCount := 0

			for i, arg := range args {
				if hint.IsVariadic() && i+1 == len(args) {
					// arg is the varadic slice
					varadicCount = arg.Len()
					for j := 0; j < varadicCount; j++ {
						arg := arg.Index(j)
						if !arg.CanInterface() {
							thread.Pop(i + j + 1)
							panic(fmt.Errorf("unable to Interface argument %d", i+j))
						}
						thread.Push(New(thread, arg.Interface()))
					}
					// recount for varadic slice that appeared
					varadicCount--
					break
				}

				if !arg.CanInterface() {
					thread.Pop(i + 1)
					panic(fmt.Errorf("unable to Interface argument %d", i))
				}
				thread.Push(New(thread, arg.Interface()))
			}

			thread.Call(len(args)+varadicCount, hint.NumOut())
			defer thread.Pop(hint.NumOut())

			ret := make([]reflect.Value, hint.NumOut())

			for i := 0; i < hint.NumOut(); i++ {
				outHint := hint.Out(i)
				var err error
				ret[i], err = lValueToReflect(thread, thread.Get(-hint.NumOut()+i), outHint, nil)
				if err != nil {
					panic(err)
				}
			}

			return ret
		}
		return reflect.MakeFunc(hint, fn), nil
	case *lua.LNilType:
		switch hint.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
			return reflect.Zero(hint), nil
		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LState:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LString:
		val := reflect.ValueOf(string(converted))
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LTable:
		if hint == refTypeEmptyIface {
			hint = reflect.MapOf(refTypeEmptyIface, refTypeEmptyIface)
		}

		switch {
		case hint.Kind() == reflect.Slice:
			elemType := hint.Elem()
			length := converted.Len()
			s := reflect.MakeSlice(hint, length, length)

			for i := 0; i < length; i++ {
				value := converted.RawGetInt(i + 1)
				elemValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.Index(i).Set(elemValue)
			}

			return s, nil

		case hint.Kind() == reflect.Map:
			keyType := hint.Key()
			elemType := hint.Elem()
			s := reflect.MakeMap(hint)

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}

				lKey, err := lValueToReflect(L, key, keyType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				lValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.SetMapIndex(lKey, lValue)
			}

			return s, nil

		case hint.Kind() == reflect.Ptr && hint.Elem().Kind() == reflect.Struct:
			hint = hint.Elem()
			isPtr = true
			fallthrough
		case hint.Kind() == reflect.Struct:
			s := reflect.New(hint)
			t := s.Elem()

			mt := &Metatable{
				LTable: getMetatable(L, hint),
			}

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}
				if _, ok := key.(lua.LString); !ok {
					continue
				}

				fieldName := key.String()
				index := mt.fieldIndex(fieldName)
				if index == nil {
					return reflect.Value{}, structFieldError{
						Type:  hint,
						Field: fieldName,
					}
				}
				field := hint.FieldByIndex(index)

				lValue, err := lValueToReflect(L, value, field.Type, nil)
				if err != nil {
					return reflect.Value{}, nil
				}
				t.FieldByIndex(field.Index).Set(lValue)
			}

			if isPtr {
				return s, nil
			}

			return t, nil

		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LUserData:
		val := reflect.ValueOf(converted.Value)
		if tryConvertPtr != nil && val.Kind() != reflect.Ptr && hint.Kind() == reflect.Ptr && val.Type() == hint.Elem() {
			newVal := reflect.New(hint.Elem())
			newVal.Elem().Set(val)
			val = newVal
			*tryConvertPtr = true
		} else {
			if !val.Type().ConvertibleTo(hint) {
				return reflect.Value{}, conversionError{
					Lua:  converted,
					Hint: hint,
				}
			}
			val = val.Convert(hint)
			if tryConvertPtr != nil {
				*tryConvertPtr = false
			}
		}
		return val, nil
	default:
		panic("never reaches")
	}
}
<commit_msg>fix cancelFunc from NewThread not being called<commit_after>package luar // import "layeh.com/gopher-luar"

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

// New creates and returns a new lua.LValue for the given value.
//
// The following table shows how Go types are converted to Lua types:
//  Kind            gopher-lua Type  Custom Metatable
//  --------------------------------------------------
//  nil             LNil             No
//  Bool            LBool            No
//  Int             LNumber          No
//  Int8            LNumber          No
//  Int16           LNumber          No
//  Int32           LNumber          No
//  Int64           LNumber          No
//  Uint            LNumber          No
//  Uint8           LNumber          No
//  Uint16          LNumber          No
//  Uint32          LNumber          No
//  Uint64          LNumber          No
//  Uintptr         *LUserData       No
//  Float32         LNumber          No
//  Float64         LNumber          No
//  Complex64       *LUserData       No
//  Complex128      *LUserData       No
//  Array           *LUserData       Yes
//  Chan            *LUserData       Yes
//  Func            *LFunction       No
//  Map             *LUserData       Yes
//  Ptr             *LUserData       Yes
//  Slice           *LUserData       Yes
//  String          LString          No
//  Struct          *LUserData       Yes
//  UnsafePointer   *LUserData       No
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = getMetatableFromValue(L, val)
		return ud
	case reflect.Func:
		return funcWrapper(L, val, false)
	case reflect.String:
		return lua.LString(val.String())
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the returned lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = getTypeMetatable(L, val)

	return ud
}

type conversionError struct {
	Lua  lua.LValue
	Hint reflect.Type
}

func (c conversionError) Error() string {
	if _, isNil := c.Lua.(*lua.LNilType); isNil {
		return fmt.Sprintf("cannot use nil as type %s", c.Hint)
	}

	var val interface{}

	if userData, ok := c.Lua.(*lua.LUserData); ok {
		val = userData.Value
	} else {
		val = c.Lua
	}

	return fmt.Sprintf("cannot use %v (type %T) as type %s", val, val, c.Hint)
}

type structFieldError struct {
	Field string
	Type  reflect.Type
}

func (s structFieldError) Error() string {
	return `type ` + s.Type.String() + ` has no field ` + s.Field
}

func lValueToReflect(L *lua.LState, v lua.LValue, hint reflect.Type, tryConvertPtr *bool) (reflect.Value, error) {
	if hint.Implements(refTypeLuaLValue) {
		return reflect.ValueOf(v), nil
	}

	isPtr := false

	switch converted := v.(type) {
	case lua.LBool:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(bool(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LChannel:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LNumber:
		var val reflect.Value
		if hint.Kind() == reflect.String {
			val = reflect.ValueOf(converted.String())
		} else {
			val = reflect.ValueOf(float64(converted))
		}
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LFunction:
		switch {
		case hint == refTypeEmptyIface:
			inOut := []reflect.Type{
				reflect.SliceOf(refTypeEmptyIface),
			}
			hint = reflect.FuncOf(inOut, inOut, true)
		case hint.Kind() != reflect.Func:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}

		fn := func(args []reflect.Value) []reflect.Value {
			thread, cancelFunc := L.NewThread()
			if cancelFunc != nil {
				defer cancelFunc()
			}
			thread.Push(converted)

			varadicCount := 0

			for i, arg := range args {
				if hint.IsVariadic() && i+1 == len(args) {
					// arg is the varadic slice
					varadicCount = arg.Len()
					for j := 0; j < varadicCount; j++ {
						arg := arg.Index(j)
						if !arg.CanInterface() {
							thread.Pop(i + j + 1)
							panic(fmt.Errorf("unable to Interface argument %d", i+j))
						}
						thread.Push(New(thread, arg.Interface()))
					}
					// recount for varadic slice that appeared
					varadicCount--
					break
				}

				if !arg.CanInterface() {
					thread.Pop(i + 1)
					panic(fmt.Errorf("unable to Interface argument %d", i))
				}
				thread.Push(New(thread, arg.Interface()))
			}

			thread.Call(len(args)+varadicCount, hint.NumOut())
			defer thread.Pop(hint.NumOut())

			ret := make([]reflect.Value, hint.NumOut())

			for i := 0; i < hint.NumOut(); i++ {
				outHint := hint.Out(i)
				var err error
				ret[i], err = lValueToReflect(thread, thread.Get(-hint.NumOut()+i), outHint, nil)
				if err != nil {
					panic(err)
				}
			}

			return ret
		}
		return reflect.MakeFunc(hint, fn), nil
	case *lua.LNilType:
		switch hint.Kind() {
		case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
			return reflect.Zero(hint), nil
		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LState:
		val := reflect.ValueOf(converted)
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case lua.LString:
		val := reflect.ValueOf(string(converted))
		if !val.Type().ConvertibleTo(hint) {
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
		return val.Convert(hint), nil
	case *lua.LTable:
		if hint == refTypeEmptyIface {
			hint = reflect.MapOf(refTypeEmptyIface, refTypeEmptyIface)
		}

		switch {
		case hint.Kind() == reflect.Slice:
			elemType := hint.Elem()
			length := converted.Len()
			s := reflect.MakeSlice(hint, length, length)

			for i := 0; i < length; i++ {
				value := converted.RawGetInt(i + 1)
				elemValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.Index(i).Set(elemValue)
			}

			return s, nil

		case hint.Kind() == reflect.Map:
			keyType := hint.Key()
			elemType := hint.Elem()
			s := reflect.MakeMap(hint)

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}

				lKey, err := lValueToReflect(L, key, keyType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				lValue, err := lValueToReflect(L, value, elemType, nil)
				if err != nil {
					return reflect.Value{}, err
				}
				s.SetMapIndex(lKey, lValue)
			}

			return s, nil

		case hint.Kind() == reflect.Ptr && hint.Elem().Kind() == reflect.Struct:
			hint = hint.Elem()
			isPtr = true
			fallthrough
		case hint.Kind() == reflect.Struct:
			s := reflect.New(hint)
			t := s.Elem()

			mt := &Metatable{
				LTable: getMetatable(L, hint),
			}

			for key := lua.LNil; ; {
				var value lua.LValue
				key, value = converted.Next(key)
				if key == lua.LNil {
					break
				}
				if _, ok := key.(lua.LString); !ok {
					continue
				}

				fieldName := key.String()
				index := mt.fieldIndex(fieldName)
				if index == nil {
					return reflect.Value{}, structFieldError{
						Type:  hint,
						Field: fieldName,
					}
				}
				field := hint.FieldByIndex(index)

				lValue, err := lValueToReflect(L, value, field.Type, nil)
				if err != nil {
					return reflect.Value{}, nil
				}
				t.FieldByIndex(field.Index).Set(lValue)
			}

			if isPtr {
				return s, nil
			}

			return t, nil

		default:
			return reflect.Value{}, conversionError{
				Lua:  v,
				Hint: hint,
			}
		}
	case *lua.LUserData:
		val := reflect.ValueOf(converted.Value)
		if tryConvertPtr != nil && val.Kind() != reflect.Ptr && hint.Kind() == reflect.Ptr && val.Type() == hint.Elem() {
			newVal := reflect.New(hint.Elem())
			newVal.Elem().Set(val)
			val = newVal
			*tryConvertPtr = true
		} else {
			if !val.Type().ConvertibleTo(hint) {
				return reflect.Value{}, conversionError{
					Lua:  converted,
					Hint: hint,
				}
			}
			val = val.Convert(hint)
			if tryConvertPtr != nil {
				*tryConvertPtr = false
			}
		}
		return val, nil
	default:
		panic("never reaches")
	}
}
<|endoftext|>


<commit_before><commit_msg>More thorough DATA tests<commit_after><|endoftext|>


<commit_before>package operation

import (
	"math"
	"time"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"

	"bosh-google-cpi/util"
	"google.golang.org/api/compute/v1"
)

func (o GoogleOperationService) Waiter(operation *compute.Operation, zone string, region string) (*compute.Operation, error) {
	var tries int
	var err error

	start := time.Now()
	for tries = 1; tries < googleOperationServiceMaxTries; tries++ {
		factor := math.Pow(2, math.Min(float64(tries), float64(googleOperationServiceMaxSleepExponent)))
		wait := time.Duration(factor) * time.Second
		o.logger.Debug(googleOperationServiceLogTag, "Waiting for Google Operation '%s' to be ready, retrying in %v (%d/%d)", operation.Name, wait, tries, googleOperationServiceMaxTries)
		time.Sleep(wait)

		if zone == "" {
			if region == "" {
				operation, err = o.computeService.GlobalOperations.Get(o.project, operation.Name).Do()
			} else {
				operation, err = o.computeService.RegionOperations.Get(o.project, util.ResourceSplitter(region), operation.Name).Do()
			}
		} else {
			operation, err = o.computeService.ZoneOperations.Get(o.project, util.ResourceSplitter(zone), operation.Name).Do()
		}

		if err != nil {
			o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' finished with an error: %#v", operation.Name, err)
			if operation.Error != nil {
				return nil, bosherr.WrapErrorf(GoogleOperationError(*operation.Error), "Google Operation '%s' finished with an error", operation.Name)
			}

			return nil, bosherr.WrapErrorf(err, "Google Operation '%s' finished with an error", operation.Name)
		}

		if operation.Status == googleOperationReadyStatus {
			if operation.Error != nil {
				o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' finished with an error: %s", operation.Name, GoogleOperationError(*operation.Error))
				return nil, bosherr.WrapErrorf(GoogleOperationError(*operation.Error), "Google Operation '%s' finished with an error", operation.Name)
			}

			o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' is now ready after %v", operation.Name, time.Since(start))
			return operation, nil
		}
	}

	return nil, bosherr.Errorf("Timed out waiting for Google Operation '%s' to be ready", operation.Name)
}
<commit_msg>google/operation_service: Fix nil pointer dereference<commit_after>package operation

import (
	"math"
	"time"

	bosherr "github.com/cloudfoundry/bosh-utils/errors"

	"bosh-google-cpi/util"
	"google.golang.org/api/compute/v1"
)

func (o GoogleOperationService) Waiter(operation *compute.Operation, zone string, region string) (*compute.Operation, error) {
	var tries int
	var err error
	var opName string

	start := time.Now()
	for tries = 1; tries < googleOperationServiceMaxTries; tries++ {
		factor := math.Pow(2, math.Min(float64(tries), float64(googleOperationServiceMaxSleepExponent)))
		wait := time.Duration(factor) * time.Second
		opName = operation.Name
		o.logger.Debug(googleOperationServiceLogTag, "Waiting for Google Operation '%s' to be ready, retrying in %v (%d/%d)", opName, wait, tries, googleOperationServiceMaxTries)
		time.Sleep(wait)

		if zone == "" {
			if region == "" {
				operation, err = o.computeService.GlobalOperations.Get(o.project, opName).Do()
			} else {
				operation, err = o.computeService.RegionOperations.Get(o.project, util.ResourceSplitter(region), opName).Do()
			}
		} else {
			operation, err = o.computeService.ZoneOperations.Get(o.project, util.ResourceSplitter(zone), opName).Do()
		}

		if err != nil {
			o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' finished with an error: %#v", opName, err)
			if operation != nil && operation.Error != nil {
				return nil, bosherr.WrapErrorf(GoogleOperationError(*operation.Error), "Google Operation '%s' finished with an error", opName)
			}

			return nil, bosherr.WrapErrorf(err, "Google Operation '%s' finished with an error", opName)
		}

		if operation.Status == googleOperationReadyStatus {
			if operation.Error != nil {
				o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' finished with an error: %s", opName, GoogleOperationError(*operation.Error))
				return nil, bosherr.WrapErrorf(GoogleOperationError(*operation.Error), "Google Operation '%s' finished with an error", opName)
			}

			o.logger.Debug(googleOperationServiceLogTag, "Google Operation '%s' is now ready after %v", opName, time.Since(start))
			return operation, nil
		}
	}

	return nil, bosherr.Errorf("Timed out waiting for Google Operation '%s' to be ready", opName)
}
<|endoftext|>


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

package measure

import (
	"fmt"
	"github.com/ligato/cn-infra/logging"
	"reflect"
	"sync"
	"time"
)

// StopWatchEntry provides method to log measured time entries
type StopWatchEntry interface {
	LogTimeEntry(d time.Duration)
}

// Stopwatch keeps all time measurement results
type Stopwatch struct {
	// name of the entity/plugin
	name string
	// logger used while printing
	logger logging.Logger
	// map where measurements are stored. Map is in format [string]TimeLog (string is a name related to the measured time(s)
	// which are stored in timelog), for every binapi/netlink api there is
	// a set of times this binapi/netlink was called
	timeTable sync.Map
}

// NewStopwatch creates a new stopwatch object with empty time map
func NewStopwatch(name string, log logging.Logger) *Stopwatch {
	return &Stopwatch{
		name:      name,
		logger:    log,
		timeTable: sync.Map{},
	}
}

// TimeLog is a wrapper for the measured data for specific name
type TimeLog struct {
	entries []time.Duration
}

// GetTimeLog returns a pointer to the TimeLog object related to the provided name (derived from the <n> parameter).
// If stopwatch is not used, returns nil
func GetTimeLog(n interface{}, s *Stopwatch) *TimeLog {
	// return nil if does not exist
	if s == nil {
		return nil
	}
	return s.timeLog(n)
}

// looks over stopwatch timeTable map in order to find a TimeLog object for provided name. If the object does not exist,
// it is created anew, stored in the map and returned
func (st *Stopwatch) timeLog(n interface{}) *TimeLog {
	// derive name
	var name string
	switch nType := n.(type) {
	case string:
		name = nType
	default:
		name = reflect.TypeOf(n).String()
	}
	// create and initialize new TimeLog in case it does not exist
	timer := &TimeLog{}
	timer.entries = make([]time.Duration, 0)
	// if there is no TimeLog under the name, store the created one. Otherwise, existing timer is returned
	existingTimer, loaded := st.timeTable.LoadOrStore(name, timer)
	if loaded {
		// cast to object which can be returned
		existing, ok := existingTimer.(*TimeLog)
		if !ok {
			panic(fmt.Errorf("cannot cast timeTable map value to duration"))
		}
		return existing
	}
	return timer
}

// LogTimeEntry stores time entry to the TimeLog (the time log itself is stored in the stopwatch sync.Map)
func (t *TimeLog) LogTimeEntry(d time.Duration) {
	if t != nil && t.entries != nil {
		t.entries = append(t.entries, d)
	}
}

// PrintLog all entries from TimeLog and reset it
func (st *Stopwatch) PrintLog() {
	isMapEmpty := true
	var wasErr error
	// Calculate stTotal time
	var stTotal time.Duration
	st.timeTable.Range(func(k, v interface{}) bool {
		// Remember that the map contained entries
		isMapEmpty = false
		name, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast timeTable map key to string")
			// stops the iteration
			return false
		}
		value, ok := v.(*TimeLog)
		if !ok {
			wasErr = fmt.Errorf("cannot cast timeTable map value to duration")
			// stops the iteration
			return false
		}
		// Calculate average value of entry list
		nameTotal, average := st.calculateAverage(value.entries)
		// Add to total
		stTotal += nameTotal
		st.logger.WithFields(logging.Fields{"conf": st.name, "wasCalled": len(value.entries),
			"durationInNs": average.Nanoseconds()}).Infof("%v call took %v", name, average)

		return true
	})

	// throw panic outside of logger.Range()
	if wasErr != nil {
		panic(wasErr)
	}

	// In case map is entry
	if isMapEmpty {
		st.logger.WithField("conf", st.name).Infof("stopwatch has no entries")
	}
	// Log overall time
	st.logger.WithFields(logging.Fields{"conf": st.name, "durationInNs": stTotal.Nanoseconds()}).Infof("partial resync time is %v", stTotal)

	// clear map after use
	st.timeTable = sync.Map{}
}

// calculates average duration of binary api + total duration of that binary api (if called more than once)
func (st *Stopwatch) calculateAverage(durations []time.Duration) (total time.Duration, average time.Duration) {
	if len(durations) == 0 {
		return 0, 0
	}
	for _, duration := range durations {
		total += duration
	}

	avgVal := total.Nanoseconds() / int64(len(durations))

	return total, time.Duration(avgVal)
}
<commit_msg>Add LogTimeEntryFor func for single-line usage<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package measure

import (
	"fmt"
	"reflect"
	"sync"
	"time"

	"github.com/ligato/cn-infra/logging"
)

// StopWatchEntry provides method to log measured time entries
type StopWatchEntry interface {
	LogTimeEntry(d time.Duration)
}

// Stopwatch keeps all time measurement results
type Stopwatch struct {
	// name of the entity/plugin
	name string
	// logger used while printing
	logger logging.Logger
	// map where measurements are stored. Map is in format [string]TimeLog (string is a name related to the measured time(s)
	// which are stored in timelog), for every binapi/netlink api there is
	// a set of times this binapi/netlink was called
	timeTable sync.Map
}

// NewStopwatch creates a new stopwatch object with empty time map
func NewStopwatch(name string, log logging.Logger) *Stopwatch {
	return &Stopwatch{
		name:      name,
		logger:    log,
		timeTable: sync.Map{},
	}
}

// TimeLog is a wrapper for the measured data for specific name
type TimeLog struct {
	entries []time.Duration
}

// GetTimeLog returns a pointer to the TimeLog object related to the provided name (derived from the <n> parameter).
// If stopwatch is not used, returns nil
func GetTimeLog(n interface{}, s *Stopwatch) *TimeLog {
	// return nil if does not exist
	if s == nil {
		return nil
	}
	return s.timeLog(n)
}

// looks over stopwatch timeTable map in order to find a TimeLog object for provided name. If the object does not exist,
// it is created anew, stored in the map and returned
func (st *Stopwatch) timeLog(n interface{}) *TimeLog {
	// derive name
	var name string
	switch nType := n.(type) {
	case string:
		name = nType
	default:
		name = reflect.TypeOf(n).String()
	}
	// create and initialize new TimeLog in case it does not exist
	timer := &TimeLog{}
	timer.entries = make([]time.Duration, 0)
	// if there is no TimeLog under the name, store the created one. Otherwise, existing timer is returned
	existingTimer, loaded := st.timeTable.LoadOrStore(name, timer)
	if loaded {
		// cast to object which can be returned
		existing, ok := existingTimer.(*TimeLog)
		if !ok {
			panic(fmt.Errorf("cannot cast timeTable map value to duration"))
		}
		return existing
	}
	return timer
}

// LogTimeEntry stores time entry to the TimeLog (the time log itself is stored in the stopwatch sync.Map)
func (t *TimeLog) LogTimeEntry(d time.Duration) {
	if t != nil && t.entries != nil {
		t.entries = append(t.entries, d)
	}
}

// LogTimeEntryFor sets start time and returns func which logs the time entry,
// usable as single-line defer call: `defer s.LogTimeEntryFor("xyz")()`
func (st *Stopwatch) LogTimeEntryFor(n interface{}) func() {
	if st == nil {
		return func() {}
	}
	l := st.timeLog(n)
	start := time.Now()
	return func() {
		l.LogTimeEntry(time.Since(start))
	}
}

// PrintLog all entries from TimeLog and reset it
func (st *Stopwatch) PrintLog() {
	isMapEmpty := true
	var wasErr error
	// Calculate stTotal time
	var stTotal time.Duration
	st.timeTable.Range(func(k, v interface{}) bool {
		// Remember that the map contained entries
		isMapEmpty = false
		name, ok := k.(string)
		if !ok {
			wasErr = fmt.Errorf("cannot cast timeTable map key to string")
			// stops the iteration
			return false
		}
		value, ok := v.(*TimeLog)
		if !ok {
			wasErr = fmt.Errorf("cannot cast timeTable map value to duration")
			// stops the iteration
			return false
		}
		// Calculate average value of entry list
		nameTotal, average := st.calculateAverage(value.entries)
		// Add to total
		stTotal += nameTotal
		st.logger.WithFields(logging.Fields{"conf": st.name, "wasCalled": len(value.entries),
			"durationInNs": average.Nanoseconds()}).Infof("%v call took %v", name, average)

		return true
	})

	// throw panic outside of logger.Range()
	if wasErr != nil {
		panic(wasErr)
	}

	// In case map is entry
	if isMapEmpty {
		st.logger.WithField("conf", st.name).Infof("stopwatch has no entries")
	}
	// Log overall time
	st.logger.WithFields(logging.Fields{"conf": st.name, "durationInNs": stTotal.Nanoseconds()}).Infof("partial resync time is %v", stTotal)

	// clear map after use
	st.timeTable = sync.Map{}
}

// calculates average duration of binary api + total duration of that binary api (if called more than once)
func (st *Stopwatch) calculateAverage(durations []time.Duration) (total time.Duration, average time.Duration) {
	if len(durations) == 0 {
		return 0, 0
	}
	for _, duration := range durations {
		total += duration
	}

	avgVal := total.Nanoseconds() / int64(len(durations))

	return total, time.Duration(avgVal)
}
<|endoftext|>


<commit_before>package libproxy

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"strings"
	"testing"
	"time"
)

var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
var testBufSize = len(testBuf)

type EchoServer interface {
	Run()
	Close()
	LocalAddr() net.Addr
}

type StreamEchoServer struct {
	listener net.Listener
	testCtx  *testing.T
}

type UDPEchoServer struct {
	conn    net.PacketConn
	testCtx *testing.T
}

func NewEchoServer(t *testing.T, proto, address string) EchoServer {
	var server EchoServer
	if strings.HasPrefix(proto, "tcp") || strings.HasPrefix(proto, "unix") {
		listener, err := net.Listen(proto, address)
		if err != nil {
			t.Fatal(err)
		}
		server = &StreamEchoServer{listener: listener, testCtx: t}
	} else {
		socket, err := net.ListenPacket(proto, address)
		if err != nil {
			t.Fatal(err)
		}
		server = &UDPEchoServer{conn: socket, testCtx: t}
	}
	return server
}

func (server *StreamEchoServer) Run() {
	go func() {
		for {
			client, err := server.listener.Accept()
			if err != nil {
				return
			}
			go func(client net.Conn) {
				if _, err := io.Copy(client, client); err != nil {
					server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
				}
				client.Close()
			}(client)
		}
	}()
}

func (server *StreamEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
func (server *StreamEchoServer) Close()              { server.listener.Addr() }

func (server *UDPEchoServer) Run() {
	go func() {
		readBuf := make([]byte, 1024)
		for {
			read, from, err := server.conn.ReadFrom(readBuf)
			if err != nil {
				return
			}
			for i := 0; i != read; {
				written, err := server.conn.WriteTo(readBuf[i:read], from)
				if err != nil {
					break
				}
				i += written
			}
		}
	}()
}

func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
func (server *UDPEchoServer) Close()              { server.conn.Close() }

func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
	defer proxy.Close()
	go proxy.Run()
	log.Printf("Proxy forwarding from %s -> %s\n", proxy.FrontendAddr().String(), proxy.BackendAddr().String())
	log.Printf("Dial(%s, %s)\n", proto, addr)
	client, err := net.Dial(proto, addr)
	if err != nil {
		t.Fatalf("Can't connect to the proxy: %v", err)
	}
	defer client.Close()
	client.SetDeadline(time.Now().Add(10 * time.Second))
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	recvBuf := make([]byte, testBufSize)
	if _, err = client.Read(recvBuf); err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(testBuf, recvBuf) {
		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
	}
}

func testProxy(t *testing.T, proto string, proxy Proxy) {
	testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
}

func TestUnixProxy(t *testing.T) {
	pathA := "/tmp/network_proxy_test.sock"
	pathB := "/tmp/network_proxy_test.sock2"
	if err := os.Remove(pathA); err != nil && !(os.IsNotExist(err)) {
		t.Fatal(err)
	}
	if err := os.Remove(pathB); err != nil && !(os.IsNotExist(err)) {
		t.Fatal(err)
	}
	backend := NewEchoServer(t, "unix", pathA)
	defer backend.Close()
	backend.Run()
	log.Printf("Running an echo server on %s\n", backend.LocalAddr().String())
	frontendAddr, err := net.ResolveUnixAddr("unix", pathB)
	if err != nil {
		t.Fatal(err)
	}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "unix", proxy)
}

func TestTCP4Proxy(t *testing.T) {
	backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "tcp", proxy)
}

func TestTCP6Proxy(t *testing.T) {
	t.Skip("No support for IPv6 inside Docker")
	backend := NewEchoServer(t, "tcp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "tcp", proxy)
}

func TestTCPDualStackProxy(t *testing.T) {
	// If I understand `godoc -src net favoriteAddrFamily` (used by the
	// net.Listen* functions) correctly this should work, but it doesn't.
	t.Skip("No support for dual stack yet")
	backend := NewEchoServer(t, "tcp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	ipv4ProxyAddr := &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
	}
	testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
}

func TestUDP4Proxy(t *testing.T) {
	backend := NewEchoServer(t, "udp", "127.0.0.1:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "udp", proxy)
}

func TestUDP6Proxy(t *testing.T) {
	t.Skip("No support for IPv6 inside Docker")
	backend := NewEchoServer(t, "udp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "udp", proxy)
}

func TestUDPWriteError(t *testing.T) {
	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	// Hopefully, this port will be free: */
	backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 25587}
	proxy, err := NewIPProxy(frontendAddr, backendAddr)
	if err != nil {
		t.Fatal(err)
	}
	defer proxy.Close()
	go proxy.Run()
	client, err := net.Dial("udp", "127.0.0.1:25587")
	if err != nil {
		t.Fatalf("Can't connect to the proxy: %v", err)
	}
	defer client.Close()
	// Make sure the proxy doesn't stop when there is no actual backend:
	client.Write(testBuf)
	client.Write(testBuf)
	backend := NewEchoServer(t, "udp", "127.0.0.1:25587")
	defer backend.Close()
	backend.Run()
	client.SetDeadline(time.Now().Add(10 * time.Second))
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	recvBuf := make([]byte, testBufSize)
	if _, err = client.Read(recvBuf); err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(testBuf, recvBuf) {
		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
	}
}
<commit_msg>test: fix TestUDPWriteError<commit_after>package libproxy

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"strings"
	"testing"
	"time"
)

var testBuf = []byte("Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo")
var testBufSize = len(testBuf)

type EchoServer interface {
	Run()
	Close()
	LocalAddr() net.Addr
}

type StreamEchoServer struct {
	listener net.Listener
	testCtx  *testing.T
}

type UDPEchoServer struct {
	conn    net.PacketConn
	testCtx *testing.T
}

func NewEchoServer(t *testing.T, proto, address string) EchoServer {
	var server EchoServer
	if strings.HasPrefix(proto, "tcp") || strings.HasPrefix(proto, "unix") {
		listener, err := net.Listen(proto, address)
		if err != nil {
			t.Fatal(err)
		}
		server = &StreamEchoServer{listener: listener, testCtx: t}
	} else {
		socket, err := net.ListenPacket(proto, address)
		if err != nil {
			t.Fatal(err)
		}
		server = &UDPEchoServer{conn: socket, testCtx: t}
	}
	return server
}

func (server *StreamEchoServer) Run() {
	go func() {
		for {
			client, err := server.listener.Accept()
			if err != nil {
				return
			}
			go func(client net.Conn) {
				if _, err := io.Copy(client, client); err != nil {
					server.testCtx.Logf("can't echo to the client: %v\n", err.Error())
				}
				client.Close()
			}(client)
		}
	}()
}

func (server *StreamEchoServer) LocalAddr() net.Addr { return server.listener.Addr() }
func (server *StreamEchoServer) Close()              { server.listener.Addr() }

func (server *UDPEchoServer) Run() {
	go func() {
		readBuf := make([]byte, 1024)
		for {
			read, from, err := server.conn.ReadFrom(readBuf)
			if err != nil {
				return
			}
			for i := 0; i != read; {
				written, err := server.conn.WriteTo(readBuf[i:read], from)
				if err != nil {
					break
				}
				i += written
			}
		}
	}()
}

func (server *UDPEchoServer) LocalAddr() net.Addr { return server.conn.LocalAddr() }
func (server *UDPEchoServer) Close()              { server.conn.Close() }

func testProxyAt(t *testing.T, proto string, proxy Proxy, addr string) {
	defer proxy.Close()
	go proxy.Run()
	log.Printf("Proxy forwarding from %s -> %s\n", proxy.FrontendAddr().String(), proxy.BackendAddr().String())
	log.Printf("Dial(%s, %s)\n", proto, addr)
	client, err := net.Dial(proto, addr)
	if err != nil {
		t.Fatalf("Can't connect to the proxy: %v", err)
	}
	defer client.Close()
	client.SetDeadline(time.Now().Add(10 * time.Second))
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	recvBuf := make([]byte, testBufSize)
	if _, err = client.Read(recvBuf); err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(testBuf, recvBuf) {
		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
	}
}

func testProxy(t *testing.T, proto string, proxy Proxy) {
	testProxyAt(t, proto, proxy, proxy.FrontendAddr().String())
}

func TestUnixProxy(t *testing.T) {
	pathA := "/tmp/network_proxy_test.sock"
	pathB := "/tmp/network_proxy_test.sock2"
	if err := os.Remove(pathA); err != nil && !(os.IsNotExist(err)) {
		t.Fatal(err)
	}
	if err := os.Remove(pathB); err != nil && !(os.IsNotExist(err)) {
		t.Fatal(err)
	}
	backend := NewEchoServer(t, "unix", pathA)
	defer backend.Close()
	backend.Run()
	log.Printf("Running an echo server on %s\n", backend.LocalAddr().String())
	frontendAddr, err := net.ResolveUnixAddr("unix", pathB)
	if err != nil {
		t.Fatal(err)
	}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "unix", proxy)
}

func TestTCP4Proxy(t *testing.T) {
	backend := NewEchoServer(t, "tcp", "127.0.0.1:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "tcp", proxy)
}

func TestTCP6Proxy(t *testing.T) {
	t.Skip("No support for IPv6 inside Docker")
	backend := NewEchoServer(t, "tcp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "tcp", proxy)
}

func TestTCPDualStackProxy(t *testing.T) {
	// If I understand `godoc -src net favoriteAddrFamily` (used by the
	// net.Listen* functions) correctly this should work, but it doesn't.
	t.Skip("No support for dual stack yet")
	backend := NewEchoServer(t, "tcp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.TCPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	ipv4ProxyAddr := &net.TCPAddr{
		IP:   net.IPv4(127, 0, 0, 1),
		Port: proxy.FrontendAddr().(*net.TCPAddr).Port,
	}
	testProxyAt(t, "tcp", proxy, ipv4ProxyAddr.String())
}

func TestUDP4Proxy(t *testing.T) {
	backend := NewEchoServer(t, "udp", "127.0.0.1:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "udp", proxy)
}

func TestUDP6Proxy(t *testing.T) {
	t.Skip("No support for IPv6 inside Docker")
	backend := NewEchoServer(t, "udp", "[::1]:0")
	defer backend.Close()
	backend.Run()
	frontendAddr := &net.UDPAddr{IP: net.IPv6loopback, Port: 0}
	proxy, err := NewIPProxy(frontendAddr, backend.LocalAddr())
	if err != nil {
		t.Fatal(err)
	}
	testProxy(t, "udp", proxy)
}

func TestUDPWriteError(t *testing.T) {
	frontendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0}
	// Normally we would automatically choose a free port for the backend
	// server but we specifically want to check what happens when the server
	// is not running. This means we have to pick a port in advance.
	// Hopefully, this port will be free:
	port := 25587
	backendAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}
	proxy, err := NewIPProxy(frontendAddr, backendAddr)
	if err != nil {
		t.Fatal(err)
	}
	frontendAddr = proxy.FrontendAddr().(*net.UDPAddr)

	defer proxy.Close()
	go proxy.Run()
	client, err := net.Dial("udp", fmt.Sprintf("127.0.0.1:%d", frontendAddr.Port))
	if err != nil {
		t.Fatalf("Can't connect to the proxy: %v", err)
	}
	defer client.Close()

	// Make sure the proxy doesn't stop when there is no actual backend:
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	backend := NewEchoServer(t, "udp", fmt.Sprintf("127.0.0.1:%d", port))
	defer backend.Close()
	backend.Run()
	client.SetDeadline(time.Now().Add(10 * time.Second))
	if _, err = client.Write(testBuf); err != nil {
		t.Fatal(err)
	}
	recvBuf := make([]byte, testBufSize)
	if _, err = client.Read(recvBuf); err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(testBuf, recvBuf) {
		t.Fatal(fmt.Errorf("Expected [%v] but got [%v]", testBuf, recvBuf))
	}
}
<|endoftext|>