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

package py

// #include <Python.h>
// #include "utils.h"
// static inline void incref(PyObject *obj) { Py_INCREF(obj); }
// static inline void decref(PyObject *obj) { Py_DECREF(obj); }
// static inline void xdecref(PyObject *obj) { Py_XDECREF(obj); }
// static inline uintptr_t headSize(void) { return sizeof(PyObject); }
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

type Object interface {
	Base() *BaseObject
	Type() *Type
	Decref()
	Incref()
	IsTrue() bool
	Not() bool
}

var None = (*NoneObject)(unsafe.Pointer(&C._Py_NoneStruct))

type BaseObject struct {
	C.PyObject
}

type NoneObject struct {
	BaseObject
}

func newBaseObject(obj *C.PyObject) *BaseObject {
	return (*BaseObject)(unsafe.Pointer(obj))
}

func c(obj Object) *C.PyObject {
	if obj == nil {
		return nil
	}
	return (*C.PyObject)(unsafe.Pointer(obj.Base()))
}

func (obj *BaseObject) Base() *BaseObject {
	return obj
}

func (obj *BaseObject) Type() *Type {
	o := c(obj).ob_type
	return newType((*C.PyObject)(unsafe.Pointer(o)))
}

func (obj *BaseObject) Decref() {
	C.decref(c(obj))
}

func (obj *BaseObject) Incref() {
	C.incref(c(obj))
}

func (obj *BaseObject) Call(args *Tuple, kwds *Dict) (Object, os.Error) {
	ret := C.PyObject_Call(c(obj), c(args), c(kwds))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallObject(args *Tuple) (Object, os.Error) {
	var a *C.PyObject = nil
	if args != nil {
		a = c(args)
	}
	ret := C.PyObject_CallObject(c(obj), a)
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunction(format string, args ...interface{}) (Object, os.Error) {
	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethod(name string, format string, args ...interface{}) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunctionObjArgs(args ...Object) (Object, os.Error) {
	t, err := Tuple_Pack(args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethodObjArgs(name string, args ...Object) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := Tuple_Pack(args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) IsTrue() bool {
	ret := C.PyObject_IsTrue(c(obj))
	if ret < 0 {
		panic(exception())
	}
	return ret != 0
}

func (obj *BaseObject) Not() bool {
	ret := C.PyObject_Not(c(obj))
	if ret < 0 {
		panic(exception())
	}
	return ret != 0
}

func (obj *BaseObject) Dir() (Object, os.Error) {
	ret := C.PyObject_Dir(c(obj))
	return obj2ObjErr(ret)
}

var types = make(map[*C.PyTypeObject]*Class)

func registerType(pyType *C.PyTypeObject, class *Class) {
	types[pyType] = class
}

func (obj *BaseObject) actual() Object {
	class, ok := types[(*C.PyTypeObject)(c(obj).ob_type)]
	if ok {
		t := unsafe.Typeof(class.Pointer)
		ret, ok := unsafe.Unreflect(t, unsafe.Pointer(&obj)).(Object)
		if ok {
			return ret
		}
	}
	o := unsafe.Pointer(obj)
	switch C.getBasePyType(c(obj)) {
	case &C.PyList_Type:
		return (*List)(o)
	case &C.PyTuple_Type:
		return (*Tuple)(o)
	case &C.PyDict_Type:
		return (*Dict)(o)
	case &C.PyString_Type:
		return (*String)(o)
	case &C.PyBool_Type:
		return newBool(c(obj))
	case &C.PyInt_Type:
		return (*Int)(o)
	case &C.PyLong_Type:
		return (*Long)(o)
	case &C.PyFloat_Type:
		return (*Float)(o)
	case &C.PyModule_Type:
		return (*Module)(o)
	case &C.PyType_Type:
		return (*Type)(o)
	}
	return obj
}
<commit_msg>Remove unused C function<commit_after>// Copyright 2011 Julian Phillips.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package py

// #include <Python.h>
// #include "utils.h"
// static inline void incref(PyObject *obj) { Py_INCREF(obj); }
// static inline void decref(PyObject *obj) { Py_DECREF(obj); }
// static inline uintptr_t headSize(void) { return sizeof(PyObject); }
import "C"

import (
	"fmt"
	"os"
	"unsafe"
)

type Object interface {
	Base() *BaseObject
	Type() *Type
	Decref()
	Incref()
	IsTrue() bool
	Not() bool
}

var None = (*NoneObject)(unsafe.Pointer(&C._Py_NoneStruct))

type BaseObject struct {
	C.PyObject
}

type NoneObject struct {
	BaseObject
}

func newBaseObject(obj *C.PyObject) *BaseObject {
	return (*BaseObject)(unsafe.Pointer(obj))
}

func c(obj Object) *C.PyObject {
	if obj == nil {
		return nil
	}
	return (*C.PyObject)(unsafe.Pointer(obj.Base()))
}

func (obj *BaseObject) Base() *BaseObject {
	return obj
}

func (obj *BaseObject) Type() *Type {
	o := c(obj).ob_type
	return newType((*C.PyObject)(unsafe.Pointer(o)))
}

func (obj *BaseObject) Decref() {
	C.decref(c(obj))
}

func (obj *BaseObject) Incref() {
	C.incref(c(obj))
}

func (obj *BaseObject) Call(args *Tuple, kwds *Dict) (Object, os.Error) {
	ret := C.PyObject_Call(c(obj), c(args), c(kwds))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallObject(args *Tuple) (Object, os.Error) {
	var a *C.PyObject = nil
	if args != nil {
		a = c(args)
	}
	ret := C.PyObject_CallObject(c(obj), a)
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunction(format string, args ...interface{}) (Object, os.Error) {
	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethod(name string, format string, args ...interface{}) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := buildTuple(format, args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) CallFunctionObjArgs(args ...Object) (Object, os.Error) {
	t, err := Tuple_Pack(args...)
	if err != nil {
		return nil, err
	}
	return obj.CallObject(t)
}

func (obj *BaseObject) CallMethodObjArgs(name string, args ...Object) (Object, os.Error) {
	cname := C.CString(name)
	defer C.free(unsafe.Pointer(cname))

	f := C.PyObject_GetAttrString(c(obj), cname)
	if f == nil {
		return nil, fmt.Errorf("AttributeError: %s", name)
	}
	defer C.decref(f)

	if C.PyCallable_Check(f) == 0 {
		return nil, fmt.Errorf("TypeError: attribute of type '%s' is not callable", name)
	}

	t, err := Tuple_Pack(args...)
	if err != nil {
		return nil, err
	}

	ret := C.PyObject_CallObject(f, c(t))
	return obj2ObjErr(ret)
}

func (obj *BaseObject) IsTrue() bool {
	ret := C.PyObject_IsTrue(c(obj))
	if ret < 0 {
		panic(exception())
	}
	return ret != 0
}

func (obj *BaseObject) Not() bool {
	ret := C.PyObject_Not(c(obj))
	if ret < 0 {
		panic(exception())
	}
	return ret != 0
}

func (obj *BaseObject) Dir() (Object, os.Error) {
	ret := C.PyObject_Dir(c(obj))
	return obj2ObjErr(ret)
}

var types = make(map[*C.PyTypeObject]*Class)

func registerType(pyType *C.PyTypeObject, class *Class) {
	types[pyType] = class
}

func (obj *BaseObject) actual() Object {
	class, ok := types[(*C.PyTypeObject)(c(obj).ob_type)]
	if ok {
		t := unsafe.Typeof(class.Pointer)
		ret, ok := unsafe.Unreflect(t, unsafe.Pointer(&obj)).(Object)
		if ok {
			return ret
		}
	}
	o := unsafe.Pointer(obj)
	switch C.getBasePyType(c(obj)) {
	case &C.PyList_Type:
		return (*List)(o)
	case &C.PyTuple_Type:
		return (*Tuple)(o)
	case &C.PyDict_Type:
		return (*Dict)(o)
	case &C.PyString_Type:
		return (*String)(o)
	case &C.PyBool_Type:
		return newBool(c(obj))
	case &C.PyInt_Type:
		return (*Int)(o)
	case &C.PyLong_Type:
		return (*Long)(o)
	case &C.PyFloat_Type:
		return (*Float)(o)
	case &C.PyModule_Type:
		return (*Module)(o)
	case &C.PyType_Type:
		return (*Type)(o)
	}
	return obj
}
<|endoftext|>


<commit_before>package libkbfs

import (
	"fmt"
	"sync"

	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// CtxCRTagKey is the type used for unique context tags related to
// conflict resolution
type CtxCRTagKey int

const (
	// CtxCRIDKey is the type of the tag for unique operation IDs
	// related to conflict resolution
	CtxCRIDKey CtxCRTagKey = iota
)

// CtxCROpID is the display name for the unique operation
// conflict resolution ID tag.
const CtxCROpID = "CRID"

type conflictInput struct {
	unmerged MetadataRevision
	merged   MetadataRevision
}

// ConflictResolver is responsible for resolving conflicts in the
// background.
type ConflictResolver struct {
	config     Config
	fbo        *FolderBranchOps
	inputChan  chan conflictInput
	inputGroup sync.WaitGroup
	log        logger.Logger

	shutdown     bool
	shutdownLock sync.RWMutex

	currInput conflictInput
	inputLock sync.Mutex
}

// NewConflictResolver constructs a new ConflictResolver (and launches
// any necessary background goroutines).
func NewConflictResolver(
	config Config, fbo *FolderBranchOps) *ConflictResolver {
	// make a logger with an appropriate module name
	branchSuffix := ""
	if fbo.branch() != MasterBranch {
		branchSuffix = " " + string(fbo.branch())
	}
	tlfStringFull := fbo.id().String()
	log := config.MakeLogger(fmt.Sprintf("CR %s%s", tlfStringFull[:8],
		branchSuffix))

	cr := &ConflictResolver{
		config:    config,
		fbo:       fbo,
		inputChan: make(chan conflictInput),
		log:       log,
		currInput: conflictInput{
			unmerged: MetadataRevisionUninitialized,
			merged:   MetadataRevisionUninitialized,
		},
	}

	go cr.processInput()
	return cr
}

func (cr *ConflictResolver) processInput() {
	logTags := make(logger.CtxLogTags)
	logTags[CtxCRIDKey] = CtxCROpID
	backgroundCtx := logger.NewContextWithLogTags(context.Background(), logTags)

	var cancel func()
	defer func() {
		if cancel != nil {
			cancel()
		}
	}()
	for ci := range cr.inputChan {
		ctx := backgroundCtx
		id, err := MakeRandomRequestID()
		if err != nil {
			cr.log.Warning("Couldn't generate a random request ID: %v", err)
		} else {
			ctx = context.WithValue(ctx, CtxCRIDKey, id)
		}

		valid := func() bool {
			cr.inputLock.Lock()
			defer cr.inputLock.Unlock()
			// The input is only interesting if one of the revisions
			// is greater than what we've looked at to date.
			if ci.unmerged <= cr.currInput.unmerged &&
				ci.merged <= cr.currInput.merged {
				return false
			}
			cr.log.CDebugf(ctx, "New conflict input %v following old "+
				"input %v", ci, cr.currInput)
			cr.currInput = ci
			// cancel the existing conflict resolution (if any)
			if cancel != nil {
				cancel()
			}
			return true
		}()
		if !valid {
			cr.log.CDebugf(ctx, "Ignoring uninteresting input: %v", ci)
			cr.inputGroup.Done()
			continue
		}

		ctx, cancel = context.WithCancel(ctx)
		go cr.doResolve(ctx, ci)
	}
}

// Resolve takes the latest known unmerged and merged revision
// numbers, and kicks off the resolution process.
func (cr *ConflictResolver) Resolve(unmerged MetadataRevision,
	merged MetadataRevision) {
	cr.shutdownLock.RLock()
	defer cr.shutdownLock.RUnlock()
	if cr.shutdown {
		return
	}

	cr.inputGroup.Add(1)
	cr.inputChan <- conflictInput{unmerged, merged}
}

// Wait blocks until the current set of submitted resolutions are
// complete (though not necessarily successful), or until the given
// context is canceled.
func (cr *ConflictResolver) Wait(ctx context.Context) error {
	c := make(chan struct{}, 1)
	go func() {
		cr.inputGroup.Wait()
		c <- struct{}{}
	}()

	select {
	case <-c:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Shutdown cancels any ongoing resolutions and stops any background
// goroutines.
func (cr *ConflictResolver) Shutdown() {
	cr.shutdownLock.Lock()
	defer cr.shutdownLock.Unlock()
	cr.shutdown = true
	close(cr.inputChan)
}

func (cr *ConflictResolver) checkDone(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
		return nil
	}
}

func (cr *ConflictResolver) getMDs(ctx context.Context) (
	unmerged []*RootMetadata, merged []*RootMetadata, err error) {
	// first get all outstanding unmerged MDs for this device
	branchPoint, unmerged, err := cr.fbo.getUnmergedMDUpdates(ctx)
	if err != nil {
		return nil, nil, err
	}

	// now get all the merged MDs, starting from after the branch point
	merged, err = getMergedMDUpdates(ctx, cr.fbo.config, cr.fbo.id(),
		branchPoint+1)
	if err != nil {
		return nil, nil, err
	}
	return unmerged, merged, nil
}

func (cr *ConflictResolver) updateCurrInput(ctx context.Context,
	unmerged []*RootMetadata, merged []*RootMetadata) (err error) {
	cr.inputLock.Lock()
	defer cr.inputLock.Unlock()
	// check done while holding the lock, so we know for sure if
	// we've already been canceled and replaced by a new input.
	err = cr.checkDone(ctx)
	if err != nil {
		return err
	}

	prevInput := cr.currInput
	defer func() {
		// reset the currInput if we get an error below
		if err != nil {
			cr.currInput = prevInput
		}
	}()

	if len(unmerged) > 0 {
		rev := unmerged[len(unmerged)-1].Revision
		if rev < cr.currInput.unmerged {
			return fmt.Errorf("Unmerged revision %d is lower than the "+
				"expected unmerged revision %d", rev, cr.currInput.unmerged)
		}
		cr.currInput.unmerged = rev
	}
	if len(merged) > 0 {
		rev := merged[len(merged)-1].Revision
		if rev < cr.currInput.merged {
			return fmt.Errorf("Merged revision %d is lower than the "+
				"expected merged revision %d", rev, cr.currInput.merged)
		}
		cr.currInput.merged = rev
	}
	return nil
}

func (cr *ConflictResolver) doResolve(ctx context.Context, ci conflictInput) {
	cr.log.CDebugf(ctx, "Starting conflict resolution with input %v", ci)
	var err error
	defer cr.inputGroup.Done()
	defer func() {
		cr.log.CDebugf(ctx, "Finished conflict resolution: %v", err)
	}()

	// Canceled before we even got started?
	err = cr.checkDone(ctx)
	if err != nil {
		return
	}

	// Fetch the merged and unmerged MDs
	unmerged, merged, err := cr.getMDs(ctx)
	if err != nil {
		return
	}

	// Update the current input to reflect the MDs we'll actually be
	// working with.
	err = cr.updateCurrInput(ctx, unmerged, merged)
	if err != nil {
		return
	}
}
<commit_msg>cr: re-embed the block changes for all MD updates when necessary<commit_after>package libkbfs

import (
	"fmt"
	"sync"

	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// CtxCRTagKey is the type used for unique context tags related to
// conflict resolution
type CtxCRTagKey int

const (
	// CtxCRIDKey is the type of the tag for unique operation IDs
	// related to conflict resolution
	CtxCRIDKey CtxCRTagKey = iota
)

// CtxCROpID is the display name for the unique operation
// conflict resolution ID tag.
const CtxCROpID = "CRID"

type conflictInput struct {
	unmerged MetadataRevision
	merged   MetadataRevision
}

// ConflictResolver is responsible for resolving conflicts in the
// background.
type ConflictResolver struct {
	config     Config
	fbo        *FolderBranchOps
	inputChan  chan conflictInput
	inputGroup sync.WaitGroup
	log        logger.Logger

	shutdown     bool
	shutdownLock sync.RWMutex

	currInput conflictInput
	inputLock sync.Mutex
}

// NewConflictResolver constructs a new ConflictResolver (and launches
// any necessary background goroutines).
func NewConflictResolver(
	config Config, fbo *FolderBranchOps) *ConflictResolver {
	// make a logger with an appropriate module name
	branchSuffix := ""
	if fbo.branch() != MasterBranch {
		branchSuffix = " " + string(fbo.branch())
	}
	tlfStringFull := fbo.id().String()
	log := config.MakeLogger(fmt.Sprintf("CR %s%s", tlfStringFull[:8],
		branchSuffix))

	cr := &ConflictResolver{
		config:    config,
		fbo:       fbo,
		inputChan: make(chan conflictInput),
		log:       log,
		currInput: conflictInput{
			unmerged: MetadataRevisionUninitialized,
			merged:   MetadataRevisionUninitialized,
		},
	}

	go cr.processInput()
	return cr
}

func (cr *ConflictResolver) processInput() {
	logTags := make(logger.CtxLogTags)
	logTags[CtxCRIDKey] = CtxCROpID
	backgroundCtx := logger.NewContextWithLogTags(context.Background(), logTags)

	var cancel func()
	defer func() {
		if cancel != nil {
			cancel()
		}
	}()
	for ci := range cr.inputChan {
		ctx := backgroundCtx
		id, err := MakeRandomRequestID()
		if err != nil {
			cr.log.Warning("Couldn't generate a random request ID: %v", err)
		} else {
			ctx = context.WithValue(ctx, CtxCRIDKey, id)
		}

		valid := func() bool {
			cr.inputLock.Lock()
			defer cr.inputLock.Unlock()
			// The input is only interesting if one of the revisions
			// is greater than what we've looked at to date.
			if ci.unmerged <= cr.currInput.unmerged &&
				ci.merged <= cr.currInput.merged {
				return false
			}
			cr.log.CDebugf(ctx, "New conflict input %v following old "+
				"input %v", ci, cr.currInput)
			cr.currInput = ci
			// cancel the existing conflict resolution (if any)
			if cancel != nil {
				cancel()
			}
			return true
		}()
		if !valid {
			cr.log.CDebugf(ctx, "Ignoring uninteresting input: %v", ci)
			cr.inputGroup.Done()
			continue
		}

		ctx, cancel = context.WithCancel(ctx)
		go cr.doResolve(ctx, ci)
	}
}

// Resolve takes the latest known unmerged and merged revision
// numbers, and kicks off the resolution process.
func (cr *ConflictResolver) Resolve(unmerged MetadataRevision,
	merged MetadataRevision) {
	cr.shutdownLock.RLock()
	defer cr.shutdownLock.RUnlock()
	if cr.shutdown {
		return
	}

	cr.inputGroup.Add(1)
	cr.inputChan <- conflictInput{unmerged, merged}
}

// Wait blocks until the current set of submitted resolutions are
// complete (though not necessarily successful), or until the given
// context is canceled.
func (cr *ConflictResolver) Wait(ctx context.Context) error {
	c := make(chan struct{}, 1)
	go func() {
		cr.inputGroup.Wait()
		c <- struct{}{}
	}()

	select {
	case <-c:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

// Shutdown cancels any ongoing resolutions and stops any background
// goroutines.
func (cr *ConflictResolver) Shutdown() {
	cr.shutdownLock.Lock()
	defer cr.shutdownLock.Unlock()
	cr.shutdown = true
	close(cr.inputChan)
}

func (cr *ConflictResolver) checkDone(ctx context.Context) error {
	select {
	case <-ctx.Done():
		return ctx.Err()
	default:
		return nil
	}
}

func (cr *ConflictResolver) getMDs(ctx context.Context) (
	unmerged []*RootMetadata, merged []*RootMetadata, err error) {
	// first get all outstanding unmerged MDs for this device
	branchPoint, unmerged, err := cr.fbo.getUnmergedMDUpdates(ctx)
	if err != nil {
		return nil, nil, err
	}

	// now get all the merged MDs, starting from after the branch point
	merged, err = getMergedMDUpdates(ctx, cr.fbo.config, cr.fbo.id(),
		branchPoint+1)
	if err != nil {
		return nil, nil, err
	}

	// re-embed all the block changes
	err = cr.fbo.reembedBlockChanges(ctx, unmerged)
	if err != nil {
		return nil, nil, err
	}
	err = cr.fbo.reembedBlockChanges(ctx, merged)
	if err != nil {
		return nil, nil, err
	}

	return unmerged, merged, nil
}

func (cr *ConflictResolver) updateCurrInput(ctx context.Context,
	unmerged []*RootMetadata, merged []*RootMetadata) (err error) {
	cr.inputLock.Lock()
	defer cr.inputLock.Unlock()
	// check done while holding the lock, so we know for sure if
	// we've already been canceled and replaced by a new input.
	err = cr.checkDone(ctx)
	if err != nil {
		return err
	}

	prevInput := cr.currInput
	defer func() {
		// reset the currInput if we get an error below
		if err != nil {
			cr.currInput = prevInput
		}
	}()

	if len(unmerged) > 0 {
		rev := unmerged[len(unmerged)-1].Revision
		if rev < cr.currInput.unmerged {
			return fmt.Errorf("Unmerged revision %d is lower than the "+
				"expected unmerged revision %d", rev, cr.currInput.unmerged)
		}
		cr.currInput.unmerged = rev
	}
	if len(merged) > 0 {
		rev := merged[len(merged)-1].Revision
		if rev < cr.currInput.merged {
			return fmt.Errorf("Merged revision %d is lower than the "+
				"expected merged revision %d", rev, cr.currInput.merged)
		}
		cr.currInput.merged = rev
	}
	return nil
}

func (cr *ConflictResolver) doResolve(ctx context.Context, ci conflictInput) {
	cr.log.CDebugf(ctx, "Starting conflict resolution with input %v", ci)
	var err error
	defer cr.inputGroup.Done()
	defer func() {
		cr.log.CDebugf(ctx, "Finished conflict resolution: %v", err)
	}()

	// Canceled before we even got started?
	err = cr.checkDone(ctx)
	if err != nil {
		return
	}

	// Fetch the merged and unmerged MDs
	unmerged, merged, err := cr.getMDs(ctx)
	if err != nil {
		return
	}

	// Update the current input to reflect the MDs we'll actually be
	// working with.
	err = cr.updateCurrInput(ctx, unmerged, merged)
	if err != nil {
		return
	}
}
<|endoftext|>


<commit_before>package list

import (
	"../config"
	"fmt"
	"io"
	"os"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/olekukonko/tablewriter"
)

// Reference Code
// http://qiita.com/draco/items/59c94ab8c66314d3a9f0

// Sample Code
// https://github.com/aws/aws-sdk-go/blob/7e9078c250876f26da48aaf36b8dce6a462ecd8a/service/ec2/examples_test.go#L2876

func showError(err error) {
	if awsErr, ok := err.(awserr.Error); ok {
		// Generic AWS Error with Code, Message, and original error (if any)
		fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
		if reqErr, ok := err.(awserr.RequestFailure); ok {
			// A service error occurred
			fmt.Println(reqErr.Code(), reqErr.Message(), reqErr.StatusCode(), reqErr.RequestID())
		}
	} else {
		// This case should never be hit, the SDK should always return an error
		// which satisfies the awserr.Error interface.
		fmt.Println(err.Error())
	}
}

func describeInstance(writer *tablewriter.Table, i *ec2.Instance) {
	var tag_name string
	for _, t := range i.Tags {
		if *t.Key == "Name" {
			tag_name = *t.Value
		}
	}

	var ipAddress string
	if i.PublicIPAddress == nil {
		ipAddress = "---"
	} else {
		ipAddress = *i.PublicIPAddress
	}

	writer.Append([]string{
		tag_name,
		*i.InstanceID,
		*i.InstanceType,
		*i.Placement.AvailabilityZone,
		ipAddress,
		*i.State.Name,
	})
}

func (c *Command) showList(writer io.Writer) {
	conf := config.GetConfig()

	credentials := credentials.NewStaticCredentials(
		conf.Aws.AccessKeyId,
		conf.Aws.SecretAccessKey,
		"")

	svc := ec2.New(
		&aws.Config{
			Region:      "ap-northeast-1",
			Credentials: credentials,
		},
	)

	params := &ec2.DescribeInstancesInput{}

	res, err := svc.DescribeInstances(params)
	if err != nil {
		fmt.Println("failed...")
		showError(err)
		os.Exit(1)
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetBorder(false)
	table.SetRowLine(false)
	table.SetColumnSeparator("\t")
	table.SetColWidth(80)

	for _, r := range res.Reservations {
		for _, i := range r.Instances {
			describeInstance(table, i)
		}
	}

	table.Render()
}
<commit_msg>fix to use passed writer<commit_after>package list

import (
	"../config"
	"fmt"
	"io"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/olekukonko/tablewriter"
)

// Reference Code
// http://qiita.com/draco/items/59c94ab8c66314d3a9f0

// Sample Code
// https://github.com/aws/aws-sdk-go/blob/7e9078c250876f26da48aaf36b8dce6a462ecd8a/service/ec2/examples_test.go#L2876

func showError(err error) {
	if awsErr, ok := err.(awserr.Error); ok {
		// Generic AWS Error with Code, Message, and original error (if any)
		fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
		if reqErr, ok := err.(awserr.RequestFailure); ok {
			// A service error occurred
			fmt.Println(reqErr.Code(), reqErr.Message(), reqErr.StatusCode(), reqErr.RequestID())
		}
	} else {
		// This case should never be hit, the SDK should always return an error
		// which satisfies the awserr.Error interface.
		fmt.Println(err.Error())
	}
}

func describeInstance(writer *tablewriter.Table, i *ec2.Instance) {
	var tag_name string
	for _, t := range i.Tags {
		if *t.Key == "Name" {
			tag_name = *t.Value
		}
	}

	var ipAddress string
	if i.PublicIPAddress == nil {
		ipAddress = "---"
	} else {
		ipAddress = *i.PublicIPAddress
	}

	writer.Append([]string{
		tag_name,
		*i.InstanceID,
		*i.InstanceType,
		*i.Placement.AvailabilityZone,
		ipAddress,
		*i.State.Name,
	})
}

func ShowEc2Instances(writer io.Writer) int {
	conf := config.GetConfig()

	credentials := credentials.NewStaticCredentials(
		conf.Aws.AccessKeyId,
		conf.Aws.SecretAccessKey,
		"")

	svc := ec2.New(
		&aws.Config{
			Region:      "ap-northeast-1",
			Credentials: credentials,
		},
	)

	params := &ec2.DescribeInstancesInput{}

	res, err := svc.DescribeInstances(params)
	if err != nil {
		fmt.Println("failed...")
		showError(err)
		return 1
	}

	table := tablewriter.NewWriter(writer)
	table.SetBorder(false)
	table.SetRowLine(false)
	table.SetColumnSeparator("\t")
	table.SetColWidth(80)

	for _, r := range res.Reservations {
		for _, i := range r.Instances {
			describeInstance(table, i)
		}
	}

	table.Render()
	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// Logger logger
type Logger struct {
	logs *ChatLogs
}

// NewLogger instantiates destiny chat logger
func NewLogger(logs *ChatLogs) *Logger {
	return &Logger{
		logs: logs,
	}
}

// DestinyLog starts logging loop
func (l *Logger) DestinyLog(mc <-chan *common.Message) {
	var subTrigger bool
	giftRegex := regexp.MustCompile("^[a-zA-Z0-9_]+ gifted [a-zA-Z0-9_]+ a Tier (I|II|II|IV) subscription!")
	for m := range mc {
		switch m.Type {
		case "BAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s banned by %s", m.Data, m.Nick))
		case "UNBAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s bunbanned by %s", m.Data, m.Nick))
		case "MUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s bmuted by %s", m.Data, m.Nick))
		case "UNMUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s bunmuted by %s", m.Data, m.Nick))
		case "BROADCAST":
			if strings.Contains(m.Data, "subscriber!") ||
				strings.Contains(m.Data, "subscribed on Twitch!") ||
				strings.Contains(m.Data, "has resubscribed! Active for") ||
				giftRegex.MatchString(m.Data) {
				l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
				subTrigger = !subTrigger
				continue
			}
			if subTrigger {
				l.writeLine(m.Time, m.Channel, "SubscriberMessage", m.Data)
				subTrigger = !subTrigger
				continue
			}
			l.writeLine(m.Time, m.Channel, "Broadcast", m.Data)
		case "MSG":
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
			subTrigger = false
		}
	}
}

// TwitchLog starts logging loop
func (l *Logger) TwitchLog(mc <-chan *common.Message) {
	for m := range mc {
		if m.Type == "MSG" {
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
		}
	}
}

func (l *Logger) writeLine(timestamp time.Time, channel, nick, message string) {
	logs, err := l.logs.Get(filepath.Join(common.GetConfig().LogPath, strings.Title(channel)+" chatlog", timestamp.Format("January 2006"), timestamp.Format("2006-01-02")+".txt"))
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	logs.Write(timestamp, nick, message)
}
<commit_msg>i don't even know how<commit_after>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// Logger logger
type Logger struct {
	logs *ChatLogs
}

// NewLogger instantiates destiny chat logger
func NewLogger(logs *ChatLogs) *Logger {
	return &Logger{
		logs: logs,
	}
}

// DestinyLog starts logging loop
func (l *Logger) DestinyLog(mc <-chan *common.Message) {
	var subTrigger bool
	giftRegex := regexp.MustCompile("^[a-zA-Z0-9_]+ gifted [a-zA-Z0-9_]+ a Tier (I|II|II|IV) subscription!")
	for m := range mc {
		switch m.Type {
		case "BAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s banned by %s", m.Data, m.Nick))
		case "UNBAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unbanned by %s", m.Data, m.Nick))
		case "MUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s muted by %s", m.Data, m.Nick))
		case "UNMUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unmuted by %s", m.Data, m.Nick))
		case "BROADCAST":
			if strings.Contains(m.Data, "subscriber!") ||
				strings.Contains(m.Data, "subscribed on Twitch!") ||
				strings.Contains(m.Data, "has resubscribed! Active for") ||
				giftRegex.MatchString(m.Data) {
				l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
				subTrigger = !subTrigger
				continue
			}
			if subTrigger {
				l.writeLine(m.Time, m.Channel, "SubscriberMessage", m.Data)
				subTrigger = !subTrigger
				continue
			}
			l.writeLine(m.Time, m.Channel, "Broadcast", m.Data)
		case "MSG":
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
			subTrigger = false
		}
	}
}

// TwitchLog starts logging loop
func (l *Logger) TwitchLog(mc <-chan *common.Message) {
	for m := range mc {
		if m.Type == "MSG" {
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
		}
	}
}

func (l *Logger) writeLine(timestamp time.Time, channel, nick, message string) {
	logs, err := l.logs.Get(filepath.Join(common.GetConfig().LogPath, strings.Title(channel)+" chatlog", timestamp.Format("January 2006"), timestamp.Format("2006-01-02")+".txt"))
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	logs.Write(timestamp, nick, message)
}
<|endoftext|>


<commit_before>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libgit

import (
	"context"
	"os"
	"time"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/libfs"
	"github.com/keybase/kbfs/libkbfs"
)

// commonTime computes the current time according to our estimate of
// the mdserver's time.  It's a very crude way of normalizing the
// local clock.
func commonTime(
	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
	log logger.Logger) time.Time {
	offset, haveOffset := mdserver.OffsetFromServerTime()
	if !haveOffset {
		log.CDebugf(ctx, "No offset, cannot use common time; "+
			"falling back to local time")
		return clock.Now()
	}
	return clock.Now().Add(-offset)
}

// canDoWork creates a file that marks the start of some long-term
// work by this node.  It should be called while a lock is taken on
// the server.  It returns true if the caller should start doing the
// work.
func canDoWork(
	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
	fs *libfs.FS, workingFileName string, workLimit time.Duration,
	log logger.Logger) (bool, error) {
	fi, err := fs.Stat(workingFileName)
	currCommonTime := commonTime(ctx, mdserver, clock, log)
	if err != nil && !os.IsNotExist(err) {
		return false, err
	} else if os.IsNotExist(err) {
		log.CDebugf(ctx, "Creating new working file %s", workingFileName)
		f, err := fs.Create(workingFileName)
		if err != nil {
			return false, err
		}
		err = f.Close()
		if err != nil {
			return false, err
		}
	} else { // err == nil
		modCommonTime := fi.ModTime()
		if modCommonTime.Add(workTimeLimit).After(currCommonTime) {
			log.CDebugf(ctx, "Other worker is still working; "+
				"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
				modCommonTime, currCommonTime, workTimeLimit)
			// The other GC is still running within the time
			// limit.
			return false, nil
		}
		log.CDebugf(ctx, "Other GC expired; "+
			"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
			modCommonTime, currCommonTime, workTimeLimit)
	}

	log.CDebugf(ctx, "Setting work common time to %s", currCommonTime)
	err = fs.Chtimes(workingFileName, time.Time{}, currCommonTime)
	if err != nil {
		return false, err
	}
	return true, nil
}
<commit_msg>libgit: use a switch in `canDoWork`<commit_after>// Copyright 2018 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libgit

import (
	"context"
	"os"
	"time"

	"github.com/keybase/client/go/logger"
	"github.com/keybase/kbfs/libfs"
	"github.com/keybase/kbfs/libkbfs"
)

// commonTime computes the current time according to our estimate of
// the mdserver's time.  It's a very crude way of normalizing the
// local clock.
func commonTime(
	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
	log logger.Logger) time.Time {
	offset, haveOffset := mdserver.OffsetFromServerTime()
	if !haveOffset {
		log.CDebugf(ctx, "No offset, cannot use common time; "+
			"falling back to local time")
		return clock.Now()
	}
	return clock.Now().Add(-offset)
}

// canDoWork creates a file that marks the start of some long-term
// work by this node.  It should be called while a lock is taken on
// the server.  It returns true if the caller should start doing the
// work.
func canDoWork(
	ctx context.Context, mdserver libkbfs.MDServer, clock libkbfs.Clock,
	fs *libfs.FS, workingFileName string, workLimit time.Duration,
	log logger.Logger) (bool, error) {
	fi, err := fs.Stat(workingFileName)
	currCommonTime := commonTime(ctx, mdserver, clock, log)
	switch {
	case os.IsNotExist(err):
		log.CDebugf(ctx, "Creating new working file %s", workingFileName)
		f, err := fs.Create(workingFileName)
		if err != nil {
			return false, err
		}
		err = f.Close()
		if err != nil {
			return false, err
		}
	case err != nil:
		return false, err
	default: // err == nil
		modCommonTime := fi.ModTime()
		if modCommonTime.Add(workTimeLimit).After(currCommonTime) {
			log.CDebugf(ctx, "Other worker is still working; "+
				"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
				modCommonTime, currCommonTime, workTimeLimit)
			// The other GC is still running within the time
			// limit.
			return false, nil
		}
		log.CDebugf(ctx, "Other GC expired; "+
			"modCommonTime=%s, currCommonTime=%s, workTimeLimit=%s",
			modCommonTime, currCommonTime, workTimeLimit)
	}

	log.CDebugf(ctx, "Setting work common time to %s", currCommonTime)
	err = fs.Chtimes(workingFileName, time.Time{}, currCommonTime)
	if err != nil {
		return false, err
	}
	return true, nil
}
<|endoftext|>


<commit_before>package main
import (
	"net/http"
	"log"
	"fmt"
	"github.com/astaxie/beego/session"
	ynote "github.com/yangzhe1991/go-ynote"
)

var tmpCredDB map[string]*ynote.Credentials = make(map[string]*ynote.Credentials)

var globalSessions *session.Manager

func index(rw http.ResponseWriter, req *http.Request) {
	yc:=ynote.NewOnlineYnoteClient(ynote.Credentials{
		Token:  Token,
		Secret: Secret})
	sess:=globalSessions.SessionStart(rw,req)
	defer sess.SessionRelease()
	log.Print("/index")

	cred,ok:=sess.Get("accToken").(ynote.Credentials)

	if !ok {
		log.Print("no accToken in session")
		tmpCred, err := yc.RequestTemporaryCredentialsWithCallBack("http://127.0.0.1:8099/note/callback")
		if err != nil {
			return
		}
		tmpCredDB[tmpCred.Token]=tmpCred
		authUrl := yc.AuthorizationURL(tmpCred)

		http.Redirect(rw,req,authUrl,301)
		return
	}
	log.Print(cred)
	yc.AccToken=&cred
	ui,err:=yc.UserInfo()
	if err!=nil{
		fmt.Fprint(rw,"error!")
	}

	fmt.Fprint(rw,ui)

}

func callback(rw http.ResponseWriter, req *http.Request) {
	log.Print("/callback")
	yc:=ynote.NewOnlineYnoteClient(ynote.Credentials{
		Token:  Token,
		Secret: Secret})
	token:=req.FormValue("oauth_token")
	if token==""{
		return
	}
	verifier:=req.FormValue("oauth_verifier")
	if verifier==""{
		return
	}
	tmpCred,ok:=tmpCredDB[token]
	if !ok{
		return
	}

	accToken,err:=yc.RequestToken(tmpCred,verifier)
	if err!=nil{
		return
	}
	sess:=globalSessions.SessionStart(rw,req)
	defer sess.SessionRelease()
	sess.Set("accToken",*accToken)

	http.Redirect(rw,req,"/note",301)
}
func main(){
	globalSessions, _ = session.NewManager("memory", "session", 3600,"")
	go globalSessions.GC()
	http.HandleFunc("/note/callback",callback)
	http.HandleFunc("/note/",index)
	http.HandleFunc("/latex/",latex)
	log.Print("service start")
	err:=http.ListenAndServe(":8099",nil)
	if err!=nil{
		log.Fatal(err)
	}
	fmt.Print("asd")

}

<commit_msg>继续开发中<commit_after>package main
import (
	"net/http"
	"log"
	"fmt"
	"github.com/astaxie/beego/session"
	ynote "github.com/yangzhe1991/go-ynote"
)

var tmpCredDB map[string]*ynote.Credentials = make(map[string]*ynote.Credentials)

var globalSessions *session.Manager

func index(rw http.ResponseWriter, req *http.Request) {
	yc:=ynote.NewOnlineYnoteClient(ynote.Credentials{
		Token:  Token,
		Secret: Secret})
	sess:=globalSessions.SessionStart(rw,req)
	defer sess.SessionRelease()
	log.Print("/")

	cred,ok:=sess.Get("accToken").(ynote.Credentials)

	if !ok {
		log.Print("no accToken in session")
		tmpCred, err := yc.RequestTemporaryCredentialsWithCallBack("http://127.0.0.1:8099/note/callback")
		if err != nil {
			http.Redirect(rw,req,"/note/error",301)
			return
		}
		tmpCredDB[tmpCred.Token]=tmpCred
		authUrl := yc.AuthorizationURL(tmpCred)

		http.Redirect(rw,req,authUrl,301)
		return
	}
	log.Print(cred)
	yc.AccToken=&cred
	_,err:=yc.UserInfo()
	if err!=nil{
		http.Redirect(rw,req,"/note/error",301)
		return
	}

	notebooks,err:=yc.ListNotebooks()
	if err!=nil {
		http.Redirect(rw,req,"/note/error",301)
		return
	}
	var mynotebook ynote.NotebookInfo=nil
	for _,notebook := range notebooks{
		if notebook.Name=="第三方应用" {
			mynotebook=notebook
		}
	}
	if mynotebook==nil{
		mynotebook,err=yc.CreateNotebook("第三方应用","")
		if err!=nil{
			http.Redirect(rw,req,"/note/error",301)
			return
		}
	}
	notes,err:=yc.ListNotes(mynotebook.Path)
	if err!=nil{
		http.Redirect(rw,req,"/note/error",301)
		return
	}
	fmt.Fprintf(rw,html1)
	for _,notepath:=range notes{
		note,err:=yc.NoteInfo(notepath)
		if err!=nil{
			http.Redirect(rw,req,"/note/error",301)
			return
		}
		fmt.Fprintf(rw,"%s
",notepath,note.Title)
	}
	fmt.Fprint(rw,"create a new note
")

	fmt.Fprintf(rw,html2)
}

func edit(rw http.ResponseWriter, req *http.Request) {
	yc:=ynote.NewOnlineYnoteClient(ynote.Credentials{
		Token:  Token,
		Secret: Secret})
	sess:=globalSessions.SessionStart(rw,req)
	defer sess.SessionRelease()
	log.Print("/edit")
	cred,ok:=sess.Get("accToken").(ynote.Credentials)

	if !ok||req.FormValue("path")=="" {
		log.Print("no accToken in session")
		http.Redirect(rw,req,"/note",301)
		return
	}

	yc.AccToken=cred

	note,err:=yc.NoteInfo(req.FormValue("path"))
	if err!=nil{
		http.Redirect(rw,req,"/note/error",301)
		return
	}
	if req.Method=="GET"{
		fmt.Fprintf(rw,html1)
		fmt.Fprint(rw,
			`
			<form>
			title

			 <input name="title" />
			`
		)
		fmt.Fprint(rw,html2)
	}

}

func error(rw http.ResponseWriter, req *http.Request) {
	log.Print("/error")
	fmt.Fprintf(rw,html1)
	fmt.Fprintf(rw,"有地方出错了……")
	fmt.Fprintf(rw,html2)
}

func callback(rw http.ResponseWriter, req *http.Request) {
	log.Print("/callback")
	yc:=ynote.NewOnlineYnoteClient(ynote.Credentials{
		Token:  Token,
		Secret: Secret})
	token:=req.FormValue("oauth_token")
	if token==""{
		return
	}
	verifier:=req.FormValue("oauth_verifier")
	if verifier==""{
		return
	}
	tmpCred,ok:=tmpCredDB[token]
	if !ok{
		return
	}

	accToken,err:=yc.RequestToken(tmpCred,verifier)
	if err!=nil{
		return
	}
	sess:=globalSessions.SessionStart(rw,req)
	defer sess.SessionRelease()
	sess.Set("accToken",*accToken)

	http.Redirect(rw,req,"/note",301)
}
func main(){
	globalSessions, _ = session.NewManager("memory", "session", 3600,"")
	go globalSessions.GC()
	http.HandleFunc("/note/callback",callback)
	http.HandleFunc("/note/edit",edit)
	http.HandleFunc("/note/error",error)
	http.HandleFunc("/note/create",create)
	http.HandleFunc("/note/",index)
	http.HandleFunc("/latex/",latex)
	log.Print("service start")
	err:=http.ListenAndServe(":8099",nil)
	if err!=nil{
		log.Fatal(err)
	}
	fmt.Print("asd")

}

var html1 string = `

				<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
				<title>无名应用</title>

				`
var html2 string= `

				`
<|endoftext|>


<commit_before>package main

import (
	"time"
	"github.com/kidoman/embd"
	"fmt"
	"math"
	"github.com/stianeikeland/go-rpio"
)

var pin_a = 18
var pin_b = 23
var pinA = rpio.Pin(pin_a)
var pinB = rpio.Pin(pin_b)

func discharge() {
	fmt.Println("Discharging...")

	rpio.PinMode(pinA, rpio.Input)
	rpio.PinMode(pinB, rpio.Output)
	rpio.WritePin(pinB, rpio.Low);

	time.Sleep(time.Duration(100) * time.Millisecond)
	fmt.Println("Discharged...")
}

func lightFromR(R int64) float64 {
	return math.Log(float64(1000000)/float64(R)) * 10.0
}

func chargeTime() int64 {
	// GPIO setup
	t1 := time.Now();
	time.Sleep(time.Duration(100) * time.Millisecond)
	return int64(time.Since(t1)/time.Millisecond);

}

func analogRead() int64 {
	discharge()
	return int64(chargeTime())
}

func readResistence() float64 {
	total := int64(0)
	for i := 0; i < 20; i++ {
		total = int64(total) + analogRead()
	}
	reading := float64(total) / float64(20)
	resistence := reading * 6.05 - 939
	return resistence
}

func main() {
	_ := embd.InitGPIO()
	value := lightFromR(analogRead());
	fmt.Print(value);
}<commit_msg>Standardize on using embd library, watching to see when the capacitor charges<commit_after>package main

import (
	"time"
	"github.com/kidoman/embd"
	"fmt"
	"math"
)

var pin_a = 18
var pin_b = 23

func discharge(pinA embd.DigitalPin, pinB embd.DigitalPin) {
	fmt.Println("Discharging...")

	pinA.SetDirection(embd.In)
	pinB.SetDirection(embd.Out)
	pinB.Write(embd.Low)

	time.Sleep(time.Duration(100) * time.Millisecond)
	fmt.Println("Discharged...")
}

func lightFromR(R int64) float64 {
	return math.Log(float64(1000000)/float64(R)) * 10.0
}

func chargeTime(pinA embd.DigitalPin, pinB embd.DigitalPin) int64 {
	pinA.SetDirection(embd.Out)
	pinB.SetDirection(embd.In)
	risen := make(chan interface{})
	t1 := time.Now();
	pinB.Watch(embd.EdgeRising, func(pin embd.DigitalPin) {
		risen <- pin
	})
	_ := <- risen
	return int64(time.Since(t1)/time.Millisecond)

}

func analogRead(pinA embd.DigitalPin, pinB embd.DigitalPin) int64 {
	discharge(pinA, pinB)
	return int64(chargeTime(pinA, pinB))
}

func readResistence() float64 {
	total := int64(0)
	for i := 0; i < 20; i++ {
		total = int64(total) + analogRead()
	}
	reading := float64(total) / float64(20)
	resistence := reading * 6.05 - 939
	return resistence
}

func main() {
	_ := embd.InitGPIO()
	pinA, _ := embd.NewDigitalPin(pin_a)
	pinB, _ := embd.NewDigitalPin(pin_b)
	defer embd.CloseGPIO()
	value := lightFromR(analogRead(pinA, pinB));
	fmt.Print(value);
}<|endoftext|>


<commit_before>/*
Copyright (c) 2014-2015 VMware, Inc. 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 list

import (
	"fmt"
	"path"
	"reflect"

	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
	"golang.org/x/net/context"
)

type Element struct {
	Path   string
	Object mo.Reference
}

func ToElement(r mo.Reference, prefix string) Element {
	var name string

	// Comments about types to be expected in folders copied from the
	// documentation of the Folder managed object:
	// http://pubs.vmware.com/vsphere-55/topic/com.vmware.wssdk.apiref.doc/vim.Folder.html
	switch m := r.(type) {
	case mo.Folder:
		name = m.Name
	case mo.StoragePod:
		name = m.Name

	// { "vim.Datacenter" } - Identifies the root folder and its descendant
	// folders. Data center folders can contain child data center folders and
	// Datacenter managed objects. Datacenter objects contain virtual machine,
	// compute resource, network entity, and datastore folders.
	case mo.Datacenter:
		name = m.Name

	// { "vim.Virtualmachine", "vim.VirtualApp" } - Identifies a virtual machine
	// folder. A virtual machine folder may contain child virtual machine
	// folders. It also can contain VirtualMachine managed objects, templates,
	// and VirtualApp managed objects.
	case mo.VirtualMachine:
		name = m.Name
	case mo.VirtualApp:
		name = m.Name

	// { "vim.ComputeResource" } - Identifies a compute resource
	// folder, which contains child compute resource folders and ComputeResource
	// hierarchies.
	case mo.ComputeResource:
		name = m.Name
	case mo.ClusterComputeResource:
		name = m.Name
	case mo.HostSystem:
		name = m.Name
	case mo.ResourcePool:
		name = m.Name

	// { "vim.Network" } - Identifies a network entity folder.
	// Network entity folders on a vCenter Server can contain Network,
	// DistributedVirtualSwitch, and DistributedVirtualPortgroup managed objects.
	// Network entity folders on an ESXi host can contain only Network objects.
	case mo.Network:
		name = m.Name
	case mo.DistributedVirtualSwitch:
		name = m.Name
	case mo.DistributedVirtualPortgroup:
		name = m.Name
	case mo.VmwareDistributedVirtualSwitch:
		name = m.Name

	// { "vim.Datastore" } - Identifies a datastore folder. Datastore folders can
	// contain child datastore folders and Datastore managed objects.
	case mo.Datastore:
		name = m.Name

	default:
		panic("not implemented for type " + reflect.TypeOf(r).String())
	}

	e := Element{
		Path:   path.Join(prefix, name),
		Object: r,
	}

	return e
}

type Lister struct {
	Collector *property.Collector
	Reference types.ManagedObjectReference
	Prefix    string
	All       bool
}

func traversable(ref types.ManagedObjectReference) bool {
	switch ref.Type {
	case "Folder":
	case "Datacenter":
	case "ComputeResource", "ClusterComputeResource":
		// Treat ComputeResource and ClusterComputeResource as one and the same.
		// It doesn't matter from the perspective of the lister.
	case "HostSystem":
	default:
		return false
	}

	return true
}

func (l Lister) retrieveProperties(ctx context.Context, req types.RetrieveProperties, dst *[]interface{}) error {
	res, err := l.Collector.RetrieveProperties(ctx, req)
	if err != nil {
		return err
	}

	// Instead of using mo.LoadRetrievePropertiesResponse, use a custom loop to
	// iterate over the results and ignore entries that have properties that
	// could not be retrieved (a non-empty `missingSet` property). Since the
	// returned objects are enumerated by vSphere in the first place, any object
	// that has a non-empty `missingSet` property is indicative of a race
	// condition in vSphere where the object was enumerated initially, but was
	// removed before its properties could be collected.
	for _, p := range res.Returnval {
		v, err := mo.ObjectContentToType(p)
		if err != nil {
			// Ignore fault if it is ManagedObjectNotFound
			if soap.IsVimFault(err) {
				switch soap.ToVimFault(err).(type) {
				case *types.ManagedObjectNotFound:
					continue
				}
			}

			return err
		}

		*dst = append(*dst, v)
	}

	return nil
}

func (l Lister) List(ctx context.Context) ([]Element, error) {
	switch l.Reference.Type {
	case "Folder", "StoragePod":
		return l.ListFolder(ctx)
	case "Datacenter":
		return l.ListDatacenter(ctx)
	case "ComputeResource", "ClusterComputeResource":
		// Treat ComputeResource and ClusterComputeResource as one and the same.
		// It doesn't matter from the perspective of the lister.
		return l.ListComputeResource(ctx)
	case "ResourcePool":
		return l.ListResourcePool(ctx)
	case "HostSystem":
		return l.ListHostSystem(ctx)
	default:
		return nil, fmt.Errorf("cannot traverse type " + l.Reference.Type)
	}
}

func (l Lister) ListFolder(ctx context.Context) ([]Element, error) {
	spec := types.PropertyFilterSpec{
		ObjectSet: []types.ObjectSpec{
			{
				Obj: l.Reference,
				SelectSet: []types.BaseSelectionSpec{
					&types.TraversalSpec{
						Path: "childEntity",
						Skip: types.NewBool(false),
						Type: "Folder",
					},
				},
				Skip: types.NewBool(true),
			},
		},
	}

	// Retrieve all objects that we can deal with
	childTypes := []string{
		"Folder",
		"Datacenter",
		"VirtualMachine",
		"Network",
		"ComputeResource",
		"ClusterComputeResource",
		"Datastore",
		"DistributedVirtualSwitch",
	}

	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}

			// Additional basic properties.
			switch t {
			case "ComputeResource", "ClusterComputeResource":
				// The ComputeResource and ClusterComputeResource are dereferenced in
				// the ResourcePoolFlag. Make sure they always have their resourcePool
				// field populated.
				pspec.PathSet = append(pspec.PathSet, "resourcePool")
			}
		}

		spec.PropSet = append(spec.PropSet, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{spec},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListDatacenter(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	// Include every datastore folder in the select set
	fields := []string{
		"vmFolder",
		"hostFolder",
		"datastoreFolder",
		"networkFolder",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "Datacenter",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	pspec := types.PropertySpec{
		Type: "Folder",
	}

	if l.All {
		pspec.All = types.NewBool(true)
	} else {
		pspec.PathSet = []string{"name"}
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   []types.PropertySpec{pspec},
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListComputeResource(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"host",
		"resourcePool",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "ComputeResource",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"HostSystem",
		"ResourcePool",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListResourcePool(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"resourcePool",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "ResourcePool",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"ResourcePool",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListHostSystem(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"datastore",
		"network",
		"vm",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "HostSystem",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"Datastore",
		"Network",
		"VirtualMachine",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}
<commit_msg>Support VirtualApp in the lister<commit_after>/*
Copyright (c) 2014-2015 VMware, Inc. 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 list

import (
	"fmt"
	"path"
	"reflect"

	"github.com/vmware/govmomi/property"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
	"golang.org/x/net/context"
)

type Element struct {
	Path   string
	Object mo.Reference
}

func ToElement(r mo.Reference, prefix string) Element {
	var name string

	// Comments about types to be expected in folders copied from the
	// documentation of the Folder managed object:
	// http://pubs.vmware.com/vsphere-55/topic/com.vmware.wssdk.apiref.doc/vim.Folder.html
	switch m := r.(type) {
	case mo.Folder:
		name = m.Name
	case mo.StoragePod:
		name = m.Name

	// { "vim.Datacenter" } - Identifies the root folder and its descendant
	// folders. Data center folders can contain child data center folders and
	// Datacenter managed objects. Datacenter objects contain virtual machine,
	// compute resource, network entity, and datastore folders.
	case mo.Datacenter:
		name = m.Name

	// { "vim.Virtualmachine", "vim.VirtualApp" } - Identifies a virtual machine
	// folder. A virtual machine folder may contain child virtual machine
	// folders. It also can contain VirtualMachine managed objects, templates,
	// and VirtualApp managed objects.
	case mo.VirtualMachine:
		name = m.Name
	case mo.VirtualApp:
		name = m.Name

	// { "vim.ComputeResource" } - Identifies a compute resource
	// folder, which contains child compute resource folders and ComputeResource
	// hierarchies.
	case mo.ComputeResource:
		name = m.Name
	case mo.ClusterComputeResource:
		name = m.Name
	case mo.HostSystem:
		name = m.Name
	case mo.ResourcePool:
		name = m.Name

	// { "vim.Network" } - Identifies a network entity folder.
	// Network entity folders on a vCenter Server can contain Network,
	// DistributedVirtualSwitch, and DistributedVirtualPortgroup managed objects.
	// Network entity folders on an ESXi host can contain only Network objects.
	case mo.Network:
		name = m.Name
	case mo.DistributedVirtualSwitch:
		name = m.Name
	case mo.DistributedVirtualPortgroup:
		name = m.Name
	case mo.VmwareDistributedVirtualSwitch:
		name = m.Name

	// { "vim.Datastore" } - Identifies a datastore folder. Datastore folders can
	// contain child datastore folders and Datastore managed objects.
	case mo.Datastore:
		name = m.Name

	default:
		panic("not implemented for type " + reflect.TypeOf(r).String())
	}

	e := Element{
		Path:   path.Join(prefix, name),
		Object: r,
	}

	return e
}

type Lister struct {
	Collector *property.Collector
	Reference types.ManagedObjectReference
	Prefix    string
	All       bool
}

func traversable(ref types.ManagedObjectReference) bool {
	switch ref.Type {
	case "Folder":
	case "Datacenter":
	case "ComputeResource", "ClusterComputeResource":
		// Treat ComputeResource and ClusterComputeResource as one and the same.
		// It doesn't matter from the perspective of the lister.
	case "HostSystem":
	case "VirtualApp":
	default:
		return false
	}

	return true
}

func (l Lister) retrieveProperties(ctx context.Context, req types.RetrieveProperties, dst *[]interface{}) error {
	res, err := l.Collector.RetrieveProperties(ctx, req)
	if err != nil {
		return err
	}

	// Instead of using mo.LoadRetrievePropertiesResponse, use a custom loop to
	// iterate over the results and ignore entries that have properties that
	// could not be retrieved (a non-empty `missingSet` property). Since the
	// returned objects are enumerated by vSphere in the first place, any object
	// that has a non-empty `missingSet` property is indicative of a race
	// condition in vSphere where the object was enumerated initially, but was
	// removed before its properties could be collected.
	for _, p := range res.Returnval {
		v, err := mo.ObjectContentToType(p)
		if err != nil {
			// Ignore fault if it is ManagedObjectNotFound
			if soap.IsVimFault(err) {
				switch soap.ToVimFault(err).(type) {
				case *types.ManagedObjectNotFound:
					continue
				}
			}

			return err
		}

		*dst = append(*dst, v)
	}

	return nil
}

func (l Lister) List(ctx context.Context) ([]Element, error) {
	switch l.Reference.Type {
	case "Folder", "StoragePod":
		return l.ListFolder(ctx)
	case "Datacenter":
		return l.ListDatacenter(ctx)
	case "ComputeResource", "ClusterComputeResource":
		// Treat ComputeResource and ClusterComputeResource as one and the same.
		// It doesn't matter from the perspective of the lister.
		return l.ListComputeResource(ctx)
	case "ResourcePool":
		return l.ListResourcePool(ctx)
	case "HostSystem":
		return l.ListHostSystem(ctx)
	case "VirtualApp":
		return l.ListVirtualApp(ctx)
	default:
		return nil, fmt.Errorf("cannot traverse type " + l.Reference.Type)
	}
}

func (l Lister) ListFolder(ctx context.Context) ([]Element, error) {
	spec := types.PropertyFilterSpec{
		ObjectSet: []types.ObjectSpec{
			{
				Obj: l.Reference,
				SelectSet: []types.BaseSelectionSpec{
					&types.TraversalSpec{
						Path: "childEntity",
						Skip: types.NewBool(false),
						Type: "Folder",
					},
				},
				Skip: types.NewBool(true),
			},
		},
	}

	// Retrieve all objects that we can deal with
	childTypes := []string{
		"Folder",
		"Datacenter",
		"VirtualApp",
		"VirtualMachine",
		"Network",
		"ComputeResource",
		"ClusterComputeResource",
		"Datastore",
		"DistributedVirtualSwitch",
	}

	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}

			// Additional basic properties.
			switch t {
			case "ComputeResource", "ClusterComputeResource":
				// The ComputeResource and ClusterComputeResource are dereferenced in
				// the ResourcePoolFlag. Make sure they always have their resourcePool
				// field populated.
				pspec.PathSet = append(pspec.PathSet, "resourcePool")
			}
		}

		spec.PropSet = append(spec.PropSet, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{spec},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListDatacenter(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	// Include every datastore folder in the select set
	fields := []string{
		"vmFolder",
		"hostFolder",
		"datastoreFolder",
		"networkFolder",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "Datacenter",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	pspec := types.PropertySpec{
		Type: "Folder",
	}

	if l.All {
		pspec.All = types.NewBool(true)
	} else {
		pspec.PathSet = []string{"name"}
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   []types.PropertySpec{pspec},
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListComputeResource(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"host",
		"resourcePool",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "ComputeResource",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"HostSystem",
		"ResourcePool",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListResourcePool(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"resourcePool",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "ResourcePool",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"ResourcePool",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListHostSystem(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"datastore",
		"network",
		"vm",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "HostSystem",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"Datastore",
		"Network",
		"VirtualMachine",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}

func (l Lister) ListVirtualApp(ctx context.Context) ([]Element, error) {
	ospec := types.ObjectSpec{
		Obj:  l.Reference,
		Skip: types.NewBool(true),
	}

	fields := []string{
		"resourcePool",
		"vm",
	}

	for _, f := range fields {
		tspec := types.TraversalSpec{
			Path: f,
			Skip: types.NewBool(false),
			Type: "VirtualApp",
		}

		ospec.SelectSet = append(ospec.SelectSet, &tspec)
	}

	childTypes := []string{
		"ResourcePool",
		"VirtualMachine",
	}

	var pspecs []types.PropertySpec
	for _, t := range childTypes {
		pspec := types.PropertySpec{
			Type: t,
		}

		if l.All {
			pspec.All = types.NewBool(true)
		} else {
			pspec.PathSet = []string{"name"}
		}

		pspecs = append(pspecs, pspec)
	}

	req := types.RetrieveProperties{
		SpecSet: []types.PropertyFilterSpec{
			{
				ObjectSet: []types.ObjectSpec{ospec},
				PropSet:   pspecs,
			},
		},
	}

	var dst []interface{}

	err := l.retrieveProperties(ctx, req, &dst)
	if err != nil {
		return nil, err
	}

	es := []Element{}
	for _, v := range dst {
		es = append(es, ToElement(v.(mo.Reference), l.Prefix))
	}

	return es, nil
}
<|endoftext|>


<commit_before>package sandwich

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/augustoroman/sandwich/chain"
)

type fakeClock struct {
	now     time.Time
	advance time.Duration
}

func (f *fakeClock) Now() time.Time {
	now := f.now
	f.now = now.Add(f.advance)
	return now
}

func (f *fakeClock) Sleep(dt time.Duration) {
	f.now = f.now.Add(dt)
}

func validateLogMessage(t *testing.T, logs, expectedColor, expectedMsg string) {
	logs = strings.TrimSpace(logs)

	if !strings.HasPrefix(logs, expectedColor) {
		t.Errorf("Expected color prefix of %q: %q", expectedColor, logs)
	} else {
		logs = strings.TrimPrefix(logs, expectedColor)
	}
	if !strings.HasSuffix(logs, _RESET) {
		t.Errorf("Expected reset suffix: %q", logs)
	} else {
		logs = strings.TrimSuffix(logs, _RESET)
	}
	logs = strings.TrimSpace(logs)
	expectedMsg = strings.TrimSpace(expectedMsg)
	if logs != expectedMsg {
		t.Errorf("Wrong log message:\nExp: %q\nGot: %q", expectedMsg, logs)
	}
}

func TestLogger(t *testing.T) {
	// Restore the world from insanity when we're done:
	orig := WriteLog
	defer func() { time_Now = time.Now; os_Stderr = os.Stderr; WriteLog = orig }()

	// Setup our fake world.
	var logBuf bytes.Buffer
	os_Stderr = &logBuf
	clk := &fakeClock{time.Date(2001, 2, 3, 4, 5, 6, 7, time.UTC), 13 * time.Millisecond}
	time_Now = clk.Now

	// Useful handlers:
	sendMsg := func(w http.ResponseWriter) { w.Write([]byte("Hi there")) }
	slowSendMsg := func(w http.ResponseWriter) { clk.Sleep(100 * time.Millisecond); sendMsg(w) }
	fail := func() error { return errors.New("It went horribly wrong") }
	slowFail := func() error { clk.Sleep(time.Second); return fail() }
	panics := func(w http.ResponseWriter) { sendMsg(w); panic("oops") }

	var resp *httptest.ResponseRecorder
	var req *http.Request

	// Test a normal response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "/", nil)
	req.Header.Add("X-Real-IP", "123.456.789.0")
	TheUsual().With(sendMsg).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _GREEN,
		`2001-02-03T04:05:06Z 123.456.789.0 "GET /" (200 8B 13ms)`)

	// Test a slow response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("POST", "/slow", nil)
	req.Header.Add("X-Forwarded-For", "<any string>")
	TheUsual().With(slowSendMsg).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _YELLOW,
		`2001-02-03T04:05:06Z <any string> "POST /slow" (200 8B 113ms)`)

	// Test a failed response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("BOO!", "/fail", nil)
	req.RemoteAddr = "[::1]:56596"
	TheUsual().With(fail).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _RED,
		`2001-02-03T04:05:06Z [::1]:56596 "BOO! /fail" (500 22B 13ms) `+"\n"+
			`  ERROR: (500) Failure: It went horribly wrong`)

	// Test a slow failed response (should still be red):
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "/slowfail", nil)
	req.RemoteAddr = "[::1]:56596"
	req.Header.Add("X-Forwarded-For", "<any string>")
	req.Header.Add("X-Real-IP", "123.456.789.0") // takes precedence
	TheUsual().With(slowFail).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _RED,
		`2001-02-03T04:05:06Z 123.456.789.0 "PUT /slowfail" (500 22B 1.013s) `+"\n"+
			`  ERROR: (500) Failure: It went horribly wrong`)

	// Test that a panic should be recorded.
	var log LogEntry
	WriteLog = func(e LogEntry) { log = e }
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "/slowfail", nil)
	req.RemoteAddr = "<remote>"
	TheUsual().With(panics).ServeHTTP(resp, req)

	if err, ok := ToError(log.Error).Cause.(chain.PanicError); !ok {
		t.Errorf("log error should be a panic, but is: %#v", log.Error)
	} else if msg := err.Error(); !strings.Contains(msg, `Panic executing middleware`) {
		t.Errorf("Bad err message: %s", err)
	} else if !strings.Contains(msg, `oops`) {
		t.Errorf("Bad err message: %s", err)
	}

	if resp.Body.String() != "Hi thereInternal Server Error\n" {
		t.Errorf("Incorrect client response: %q", resp.Body.String())
	}
}
<commit_msg>Make sure that note taking in logs works.<commit_after>package sandwich

import (
	"bytes"
	"errors"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
	"time"

	"github.com/augustoroman/sandwich/chain"
)

type fakeClock struct {
	now     time.Time
	advance time.Duration
}

func (f *fakeClock) Now() time.Time {
	now := f.now
	f.now = now.Add(f.advance)
	return now
}

func (f *fakeClock) Sleep(dt time.Duration) {
	f.now = f.now.Add(dt)
}

func validateLogMessage(t *testing.T, logs, expectedColor, expectedMsg string) {
	logs = strings.TrimSpace(logs)

	if !strings.HasPrefix(logs, expectedColor) {
		t.Errorf("Expected color prefix of %q: %q", expectedColor, logs)
	} else {
		logs = strings.TrimPrefix(logs, expectedColor)
	}
	if !strings.HasSuffix(logs, _RESET) {
		t.Errorf("Expected reset suffix: %q", logs)
	} else {
		logs = strings.TrimSuffix(logs, _RESET)
	}
	logs = strings.TrimSpace(logs)
	expectedMsg = strings.TrimSpace(expectedMsg)
	if logs != expectedMsg {
		t.Errorf("Wrong log message:\nExp: %q\nGot: %q", expectedMsg, logs)
	}
}

func TestLogger(t *testing.T) {
	// Restore the world from insanity when we're done:
	orig := WriteLog
	defer func() { time_Now = time.Now; os_Stderr = os.Stderr; WriteLog = orig }()

	// Setup our fake world.
	var logBuf bytes.Buffer
	os_Stderr = &logBuf
	clk := &fakeClock{time.Date(2001, 2, 3, 4, 5, 6, 7, time.UTC), 13 * time.Millisecond}
	time_Now = clk.Now

	// Useful handlers:
	sendMsg := func(w http.ResponseWriter) { w.Write([]byte("Hi there")) }
	slowSendMsg := func(w http.ResponseWriter) { clk.Sleep(100 * time.Millisecond); sendMsg(w) }
	fail := func() error { return errors.New("It went horribly wrong") }
	slowFail := func() error { clk.Sleep(time.Second); return fail() }
	panics := func(w http.ResponseWriter) { sendMsg(w); panic("oops") }
	addsNote := func(w http.ResponseWriter, e *LogEntry) { e.Note["a"] = "x"; e.Note["b"] = "y"; sendMsg(w) }

	var resp *httptest.ResponseRecorder
	var req *http.Request

	// Test a normal response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("GET", "/", nil)
	req.Header.Add("X-Real-IP", "123.456.789.0")
	TheUsual().With(addsNote).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _GREEN,
		`2001-02-03T04:05:06Z 123.456.789.0 "GET /" (200 8B 13ms)   a="x" b="y"`)

	// Test a slow response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("POST", "/slow", nil)
	req.Header.Add("X-Forwarded-For", "<any string>")
	TheUsual().With(slowSendMsg).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _YELLOW,
		`2001-02-03T04:05:06Z <any string> "POST /slow" (200 8B 113ms)`)

	// Test a failed response:
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("BOO!", "/fail", nil)
	req.RemoteAddr = "[::1]:56596"
	TheUsual().With(fail).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _RED,
		`2001-02-03T04:05:06Z [::1]:56596 "BOO! /fail" (500 22B 13ms) `+"\n"+
			`  ERROR: (500) Failure: It went horribly wrong`)

	// Test a slow failed response (should still be red):
	logBuf.Reset()
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "/slowfail", nil)
	req.RemoteAddr = "[::1]:56596"
	req.Header.Add("X-Forwarded-For", "<any string>")
	req.Header.Add("X-Real-IP", "123.456.789.0") // takes precedence
	TheUsual().With(slowFail).ServeHTTP(resp, req)
	validateLogMessage(t, logBuf.String(), _RED,
		`2001-02-03T04:05:06Z 123.456.789.0 "PUT /slowfail" (500 22B 1.013s) `+"\n"+
			`  ERROR: (500) Failure: It went horribly wrong`)

	// Test that a panic should be recorded.
	var log LogEntry
	WriteLog = func(e LogEntry) { log = e }
	resp = httptest.NewRecorder()
	req, _ = http.NewRequest("PUT", "/slowfail", nil)
	req.RemoteAddr = "<remote>"
	TheUsual().With(panics).ServeHTTP(resp, req)

	if err, ok := ToError(log.Error).Cause.(chain.PanicError); !ok {
		t.Errorf("log error should be a panic, but is: %#v", log.Error)
	} else if msg := err.Error(); !strings.Contains(msg, `Panic executing middleware`) {
		t.Errorf("Bad err message: %s", err)
	} else if !strings.Contains(msg, `oops`) {
		t.Errorf("Bad err message: %s", err)
	}

	if resp.Body.String() != "Hi thereInternal Server Error\n" {
		t.Errorf("Incorrect client response: %q", resp.Body.String())
	}
}
<|endoftext|>


<commit_before>package ebpf

import (
	"bytes"
	"encoding"
	"encoding/binary"
	"errors"
	"fmt"
	"reflect"
	"runtime"
	"unsafe"

	"github.com/cilium/ebpf/internal"
)

// marshalPtr converts an arbitrary value into a pointer suitable
// to be passed to the kernel.
//
// As an optimization, it returns the original value if it is an
// unsafe.Pointer.
func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
	if ptr, ok := data.(unsafe.Pointer); ok {
		return internal.NewPointer(ptr), nil
	}

	buf, err := marshalBytes(data, length)
	if err != nil {
		return internal.Pointer{}, err
	}

	return internal.NewSlicePointer(buf), nil
}

// marshalBytes converts an arbitrary value into a byte buffer.
//
// Prefer using Map.marshalKey and Map.marshalValue if possible, since
// those have special cases that allow more types to be encoded.
//
// Returns an error if the given value isn't representable in exactly
// length bytes.
func marshalBytes(data interface{}, length int) (buf []byte, err error) {
	if data == nil {
		return nil, errors.New("can't marshal a nil value")
	}

	switch value := data.(type) {
	case encoding.BinaryMarshaler:
		buf, err = value.MarshalBinary()
	case string:
		buf = []byte(value)
	case []byte:
		buf = value
	case unsafe.Pointer:
		err = errors.New("can't marshal from unsafe.Pointer")
	case Map, *Map, Program, *Program:
		err = fmt.Errorf("can't marshal %T", value)
	default:
		var wr bytes.Buffer
		err = binary.Write(&wr, internal.NativeEndian, value)
		if err != nil {
			err = fmt.Errorf("encoding %T: %v", value, err)
		}
		buf = wr.Bytes()
	}
	if err != nil {
		return nil, err
	}

	if len(buf) != length {
		return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
	}
	return buf, nil
}

func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
	if ptr, ok := dst.(unsafe.Pointer); ok {
		return internal.NewPointer(ptr), nil
	}

	buf := make([]byte, length)
	return internal.NewSlicePointer(buf), buf
}

// unmarshalBytes converts a byte buffer into an arbitrary value.
//
// Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since
// those have special cases that allow more types to be encoded.
func unmarshalBytes(data interface{}, buf []byte) error {
	switch value := data.(type) {
	case unsafe.Pointer:
		var dst []byte
		// Use unsafe.Slice when we drop support for pre1.17 (https://github.com/golang/go/issues/19367)
		// We could opt for removing unsafe.Pointer support in the lib as well
		sh := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
		sh.Data = uintptr(value)
		sh.Len = len(buf)
		sh.Cap = len(buf)

		copy(dst, buf)
		runtime.KeepAlive(value)
		return nil
	case Map, *Map, Program, *Program:
		return fmt.Errorf("can't unmarshal into %T", value)
	case encoding.BinaryUnmarshaler:
		return value.UnmarshalBinary(buf)
	case *string:
		*value = string(buf)
		return nil
	case *[]byte:
		*value = buf
		return nil
	case string:
		return errors.New("require pointer to string")
	case []byte:
		return errors.New("require pointer to []byte")
	default:
		rd := bytes.NewReader(buf)
		if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
			return fmt.Errorf("decoding %T: %v", value, err)
		}
		return nil
	}
}

// marshalPerCPUValue encodes a slice containing one value per
// possible CPU into a buffer of bytes.
//
// Values are initialized to zero if the slice has less elements than CPUs.
//
// slice must have a type like []elementType.
func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
	sliceType := reflect.TypeOf(slice)
	if sliceType.Kind() != reflect.Slice {
		return internal.Pointer{}, errors.New("per-CPU value requires slice")
	}

	possibleCPUs, err := internal.PossibleCPUs()
	if err != nil {
		return internal.Pointer{}, err
	}

	sliceValue := reflect.ValueOf(slice)
	sliceLen := sliceValue.Len()
	if sliceLen > possibleCPUs {
		return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
	}

	alignedElemLength := internal.Align(elemLength, 8)
	buf := make([]byte, alignedElemLength*possibleCPUs)

	for i := 0; i < sliceLen; i++ {
		elem := sliceValue.Index(i).Interface()
		elemBytes, err := marshalBytes(elem, elemLength)
		if err != nil {
			return internal.Pointer{}, err
		}

		offset := i * alignedElemLength
		copy(buf[offset:offset+elemLength], elemBytes)
	}

	return internal.NewSlicePointer(buf), nil
}

// unmarshalPerCPUValue decodes a buffer into a slice containing one value per
// possible CPU.
//
// valueOut must have a type like *[]elementType
func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
	slicePtrType := reflect.TypeOf(slicePtr)
	if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
		return fmt.Errorf("per-cpu value requires pointer to slice")
	}

	possibleCPUs, err := internal.PossibleCPUs()
	if err != nil {
		return err
	}

	sliceType := slicePtrType.Elem()
	slice := reflect.MakeSlice(sliceType, possibleCPUs, possibleCPUs)

	sliceElemType := sliceType.Elem()
	sliceElemIsPointer := sliceElemType.Kind() == reflect.Ptr
	if sliceElemIsPointer {
		sliceElemType = sliceElemType.Elem()
	}

	step := len(buf) / possibleCPUs
	if step < elemLength {
		return fmt.Errorf("per-cpu element length is larger than available data")
	}
	for i := 0; i < possibleCPUs; i++ {
		var elem interface{}
		if sliceElemIsPointer {
			newElem := reflect.New(sliceElemType)
			slice.Index(i).Set(newElem)
			elem = newElem.Interface()
		} else {
			elem = slice.Index(i).Addr().Interface()
		}

		// Make a copy, since unmarshal can hold on to itemBytes
		elemBytes := make([]byte, elemLength)
		copy(elemBytes, buf[:elemLength])

		err := unmarshalBytes(elem, elemBytes)
		if err != nil {
			return fmt.Errorf("cpu %d: %w", i, err)
		}

		buf = buf[step:]
	}

	reflect.ValueOf(slicePtr).Elem().Set(slice)
	return nil
}
<commit_msg>Add a sync.Pool to reduce heap allocations for the default case in unmarshalBytes()<commit_after>package ebpf

import (
	"bytes"
	"encoding"
	"encoding/binary"
	"errors"
	"fmt"
	"reflect"
	"runtime"
	"sync"
	"unsafe"

	"github.com/cilium/ebpf/internal"
)

// marshalPtr converts an arbitrary value into a pointer suitable
// to be passed to the kernel.
//
// As an optimization, it returns the original value if it is an
// unsafe.Pointer.
func marshalPtr(data interface{}, length int) (internal.Pointer, error) {
	if ptr, ok := data.(unsafe.Pointer); ok {
		return internal.NewPointer(ptr), nil
	}

	buf, err := marshalBytes(data, length)
	if err != nil {
		return internal.Pointer{}, err
	}

	return internal.NewSlicePointer(buf), nil
}

// marshalBytes converts an arbitrary value into a byte buffer.
//
// Prefer using Map.marshalKey and Map.marshalValue if possible, since
// those have special cases that allow more types to be encoded.
//
// Returns an error if the given value isn't representable in exactly
// length bytes.
func marshalBytes(data interface{}, length int) (buf []byte, err error) {
	if data == nil {
		return nil, errors.New("can't marshal a nil value")
	}

	switch value := data.(type) {
	case encoding.BinaryMarshaler:
		buf, err = value.MarshalBinary()
	case string:
		buf = []byte(value)
	case []byte:
		buf = value
	case unsafe.Pointer:
		err = errors.New("can't marshal from unsafe.Pointer")
	case Map, *Map, Program, *Program:
		err = fmt.Errorf("can't marshal %T", value)
	default:
		var wr bytes.Buffer
		err = binary.Write(&wr, internal.NativeEndian, value)
		if err != nil {
			err = fmt.Errorf("encoding %T: %v", value, err)
		}
		buf = wr.Bytes()
	}
	if err != nil {
		return nil, err
	}

	if len(buf) != length {
		return nil, fmt.Errorf("%T doesn't marshal to %d bytes", data, length)
	}
	return buf, nil
}

func makeBuffer(dst interface{}, length int) (internal.Pointer, []byte) {
	if ptr, ok := dst.(unsafe.Pointer); ok {
		return internal.NewPointer(ptr), nil
	}

	buf := make([]byte, length)
	return internal.NewSlicePointer(buf), buf
}

var bytesReaderPool = sync.Pool{
	New: func() interface{} {
		return new(bytes.Reader)
	},
}

// unmarshalBytes converts a byte buffer into an arbitrary value.
//
// Prefer using Map.unmarshalKey and Map.unmarshalValue if possible, since
// those have special cases that allow more types to be encoded.
func unmarshalBytes(data interface{}, buf []byte) error {
	switch value := data.(type) {
	case unsafe.Pointer:
		var dst []byte
		// Use unsafe.Slice when we drop support for pre1.17 (https://github.com/golang/go/issues/19367)
		// We could opt for removing unsafe.Pointer support in the lib as well
		sh := (*reflect.SliceHeader)(unsafe.Pointer(&dst))
		sh.Data = uintptr(value)
		sh.Len = len(buf)
		sh.Cap = len(buf)

		copy(dst, buf)
		runtime.KeepAlive(value)
		return nil
	case Map, *Map, Program, *Program:
		return fmt.Errorf("can't unmarshal into %T", value)
	case encoding.BinaryUnmarshaler:
		return value.UnmarshalBinary(buf)
	case *string:
		*value = string(buf)
		return nil
	case *[]byte:
		*value = buf
		return nil
	case string:
		return errors.New("require pointer to string")
	case []byte:
		return errors.New("require pointer to []byte")
	default:
		rd := bytesReaderPool.Get().(*bytes.Reader)
		rd.Reset(buf)
		defer bytesReaderPool.Put(rd)
		if err := binary.Read(rd, internal.NativeEndian, value); err != nil {
			return fmt.Errorf("decoding %T: %v", value, err)
		}
		return nil
	}
}

// marshalPerCPUValue encodes a slice containing one value per
// possible CPU into a buffer of bytes.
//
// Values are initialized to zero if the slice has less elements than CPUs.
//
// slice must have a type like []elementType.
func marshalPerCPUValue(slice interface{}, elemLength int) (internal.Pointer, error) {
	sliceType := reflect.TypeOf(slice)
	if sliceType.Kind() != reflect.Slice {
		return internal.Pointer{}, errors.New("per-CPU value requires slice")
	}

	possibleCPUs, err := internal.PossibleCPUs()
	if err != nil {
		return internal.Pointer{}, err
	}

	sliceValue := reflect.ValueOf(slice)
	sliceLen := sliceValue.Len()
	if sliceLen > possibleCPUs {
		return internal.Pointer{}, fmt.Errorf("per-CPU value exceeds number of CPUs")
	}

	alignedElemLength := internal.Align(elemLength, 8)
	buf := make([]byte, alignedElemLength*possibleCPUs)

	for i := 0; i < sliceLen; i++ {
		elem := sliceValue.Index(i).Interface()
		elemBytes, err := marshalBytes(elem, elemLength)
		if err != nil {
			return internal.Pointer{}, err
		}

		offset := i * alignedElemLength
		copy(buf[offset:offset+elemLength], elemBytes)
	}

	return internal.NewSlicePointer(buf), nil
}

// unmarshalPerCPUValue decodes a buffer into a slice containing one value per
// possible CPU.
//
// valueOut must have a type like *[]elementType
func unmarshalPerCPUValue(slicePtr interface{}, elemLength int, buf []byte) error {
	slicePtrType := reflect.TypeOf(slicePtr)
	if slicePtrType.Kind() != reflect.Ptr || slicePtrType.Elem().Kind() != reflect.Slice {
		return fmt.Errorf("per-cpu value requires pointer to slice")
	}

	possibleCPUs, err := internal.PossibleCPUs()
	if err != nil {
		return err
	}

	sliceType := slicePtrType.Elem()
	slice := reflect.MakeSlice(sliceType, possibleCPUs, possibleCPUs)

	sliceElemType := sliceType.Elem()
	sliceElemIsPointer := sliceElemType.Kind() == reflect.Ptr
	if sliceElemIsPointer {
		sliceElemType = sliceElemType.Elem()
	}

	step := len(buf) / possibleCPUs
	if step < elemLength {
		return fmt.Errorf("per-cpu element length is larger than available data")
	}
	for i := 0; i < possibleCPUs; i++ {
		var elem interface{}
		if sliceElemIsPointer {
			newElem := reflect.New(sliceElemType)
			slice.Index(i).Set(newElem)
			elem = newElem.Interface()
		} else {
			elem = slice.Index(i).Addr().Interface()
		}

		// Make a copy, since unmarshal can hold on to itemBytes
		elemBytes := make([]byte, elemLength)
		copy(elemBytes, buf[:elemLength])

		err := unmarshalBytes(elem, elemBytes)
		if err != nil {
			return fmt.Errorf("cpu %d: %w", i, err)
		}

		buf = buf[step:]
	}

	reflect.ValueOf(slicePtr).Elem().Set(slice)
	return nil
}
<|endoftext|>


<commit_before>package mch

import (
	"net/http"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
	"io"
	"encoding/base64"
	"github.com/nanjishidu/gomini/gocrypto"
	"bytes"
	"strconv"
	"time"
)

type NotifyMsg struct {
	AppID    string
	MchID    string
	SubAppID string
	SubMchID string

	OrderInfo
}

type RefundNotifyMsg struct {
	TransactionID string
	OutTradeNO string
	RefundID string
	OutRefundNO string
	TotalFee int
	RefundFee int
	RefundStatus RefundStatus
	SuccessTime time.Time
}

type NotifyHandler struct {
	payNotifyHandler func(*NotifyMsg) error
	refundNotifyHandler func(*RefundNotifyMsg) error

	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	*zap.SugaredLogger
}

func NewNotifyHandler(appID, mchID, apiKey string, payNofityHandler func(*NotifyMsg) error, refundNotifyHandler func(*RefundNotifyMsg) error) *NotifyHandler {
	apiKeyMD5 := fmt.Sprintf("%x", md5.Sum([]byte(apiKey)))
	gocrypto.SetAesKey(apiKeyMD5)

	return &NotifyHandler{
		payNotifyHandler: payNofityHandler,
		refundNotifyHandler: refundNotifyHandler,

		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
}

func (nm *NotifyHandler) reply(w io.Writer, code, reason string) {
	err := EncodeXML(w, map[string]string{
		"return_code": code,
		"return_msg":  reason,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}

func (nm *NotifyHandler) replyError(w io.Writer, reason string) {
	nm.Errorw("NotifyHandler reply error", "error", reason)
	nm.reply(w, ReturnCodeFail, reason)
}

func (nm *NotifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	nm.Serve(w, r, nm.payNotifyHandler, nm.refundNotifyHandler)
}

func (nm *NotifyHandler) Serve(w io.Writer, r *http.Request, payNotifyHandler func(*NotifyMsg) error, refundNotifyHandler func(*RefundNotifyMsg) error) {
	if r.Method != "POST" {
		nm.replyError(w, "unexpected HTTP Method: "+r.Method)
		return
	}

	req, err := DecodeXML(r.Body)
	if err != nil {
		nm.replyError(w, err.Error())
		return
	}

	nm.Infof("wechat callback: %s", req)

	returnCode := req["return_code"]
	if returnCode != ReturnCodeSuccess {
		err = &Error{
			ReturnCode: returnCode,
			ReturnMsg:  req["return_msg"],
		}
		nm.replyError(w, err.Error())
		return
	}

	if nm.appID != "" {
		wantAppId := nm.appID
		haveAppId := req["appid"]
		if !wechat.Compare(haveAppId, wantAppId) {
			nm.replyError(w, fmt.Sprintf("appid mismatch, have: %s, want: %s", haveAppId, wantAppId))
			return
		}
	}
	if nm.mchID != "" {
		wantMchId := nm.mchID
		haveMchId := req["mch_id"]
		if !wechat.Compare(haveMchId, wantMchId) {
			nm.replyError(w, fmt.Sprintf("mch_id mismatch, have: %s, want: %s", haveMchId, wantMchId))
			return
		}
	}

	if nm.subAppID != "" {
		wantSubAppId := nm.subAppID
		haveSubAppId := req["sub_appid"]
		if haveSubAppId != "" && !wechat.Compare(haveSubAppId, wantSubAppId) {
			nm.replyError(w, fmt.Sprintf("sub_appid mismatch, have: %s, want: %s", haveSubAppId, wantSubAppId))
			return
		}
	}
	if nm.subMchID != "" {
		wantSubMchId := nm.subMchID
		haveSubMchId := req["sub_mch_id"]
		if !wechat.Compare(haveSubMchId, wantSubMchId) {
			nm.replyError(w, fmt.Sprintf("sub_mch_id mismatch, have: %s, want: %s", haveSubMchId, wantSubMchId))
			return
		}
	}

	// 1. refund order notify
	if reqInfo, ok := req["req_info"]; ok {
		encrypted, err := base64.StdEncoding.DecodeString(reqInfo)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		decrypted, err := gocrypto.AesECBDecrypt(encrypted)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		nm.Infof("wechat callback: %s", decrypted)
		info, err := DecodeXML(bytes.NewBuffer(decrypted))
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}

		msg, err := getRefundNotifyMsg(info)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}

		err = refundNotifyHandler(msg)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		return
	}

	// 2. pay order notify

	haveSign := req["sign"]
	var wantSign string
	switch signType := req["sign_type"]; signType {
	case "", SignTypeMD5:
		wantSign = Sign(req, nm.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		wantSign = Sign(req, nm.apiKey, hmac.New(sha256.New, []byte(nm.apiKey)))
	default:
		nm.replyError(w, fmt.Sprintf("unsupported notification sign_type: %s", signType))
		return
	}
	if !wechat.Compare(haveSign, wantSign) {
		nm.replyError(w, fmt.Sprintf("sign mismatch,\nhave: %s,\nwant: %s", haveSign, wantSign))
		return
	}

	resultCode := req["result_code"]
	if resultCode != ResultCodeSuccess {
		err = &BizError{
			ResultCode:  resultCode,
			ErrCode:     req["err_code"],
			ErrCodeDesc: req["err_code_des"],
		}
		nm.replyError(w, err.Error())
		return
	}

	orderInfo, err := getOrderInfo(req)
	if err != nil {
		nm.replyError(w, err.Error())
	}

	msg := NotifyMsg{
		AppID: req["appid"],
		MchID: req["mch_id"],
		SubAppID: req["sub_appid"],
		SubMchID: req["sub_mch_id"],
		OrderInfo: *orderInfo,
	}
	err = payNotifyHandler(&msg)
	if err != nil {
		nm.replyError(w, err.Error())
	}

	nm.reply(w, ReturnCodeSuccess, "OK")
}

func getRefundNotifyMsg(req map[string]string) (*RefundNotifyMsg, error) {
	totalFee, err := strconv.Atoi(req["total_fee"])
	if err != nil {
		return nil, err
	}
	refundFee, err := strconv.Atoi(req["refund_fee"])
	if err != nil {
		return nil, err
	}
	var successTime time.Time
	if str, ok := req["success_time"]; ok {
		successTime, err = ParseTime(str)
		if err != nil {
			return nil, err
		}
	}

	return &RefundNotifyMsg{
		TransactionID: req["transaction_id"],
		OutTradeNO: req["out_trade_no"],
		RefundID: req["refund_id"],
		OutRefundNO: req["out_refund_no"],
		TotalFee: totalFee,
		RefundFee: refundFee,
		RefundStatus: RefundStatus(req["refund_status"]),
		SuccessTime: successTime,
	}, nil
}
<commit_msg>Update files<commit_after>package mch

import (
	"net/http"
	"crypto/md5"
	"crypto/hmac"
	"fmt"
	"crypto/sha256"
	"go.uber.org/zap"
	"github.com/jiudaoyun/wechat"
	"io"
	"encoding/base64"
	"github.com/nanjishidu/gomini/gocrypto"
	"bytes"
	"strconv"
	"time"
)

type NotifyMsg struct {
	AppID    string
	MchID    string
	SubAppID string
	SubMchID string

	OrderInfo
}

type RefundNotifyMsg struct {
	TransactionID string
	OutTradeNO string
	RefundID string
	OutRefundNO string
	TotalFee int
	RefundFee int
	RefundStatus RefundStatus
	SuccessTime time.Time
}

type NotifyHandler struct {
	payNotifyHandler func(*NotifyMsg) error
	refundNotifyHandler func(*RefundNotifyMsg) error

	appID  string
	mchID  string
	apiKey string

	subAppID string
	subMchID string

	*zap.SugaredLogger
}

func NewNotifyHandler(appID, mchID, apiKey string, payNofityHandler func(*NotifyMsg) error, refundNotifyHandler func(*RefundNotifyMsg) error) *NotifyHandler {
	apiKeyMD5 := fmt.Sprintf("%x", md5.Sum([]byte(apiKey)))
	gocrypto.SetAesKey(apiKeyMD5)

	return &NotifyHandler{
		payNotifyHandler: payNofityHandler,
		refundNotifyHandler: refundNotifyHandler,

		appID:  appID,
		mchID:  mchID,
		apiKey: apiKey,

		SugaredLogger: wechat.Sugar,
	}
}

func (nm *NotifyHandler) reply(w io.Writer, code, reason string) {
	err := EncodeXML(w, map[string]string{
		"return_code": code,
		"return_msg":  reason,
	})
	if err != nil {
		nm.Errorw("NotifyHandler write XML failed", "error", err)
	}
}

func (nm *NotifyHandler) replyError(w io.Writer, reason string) {
	nm.Errorw("NotifyHandler reply error", "error", reason)
	nm.reply(w, ReturnCodeFail, reason)
}

func (nm *NotifyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	nm.Serve(w, r, nm.payNotifyHandler, nm.refundNotifyHandler)
}

func (nm *NotifyHandler) Serve(w io.Writer, r *http.Request, payNotifyHandler func(*NotifyMsg) error, refundNotifyHandler func(*RefundNotifyMsg) error) {
	if r.Method != "POST" {
		nm.replyError(w, "unexpected HTTP Method: "+r.Method)
		return
	}

	req, err := DecodeXML(r.Body)
	if err != nil {
		nm.replyError(w, err.Error())
		return
	}

	nm.Infof("wechat callback: %s", req)

	returnCode := req["return_code"]
	if returnCode != ReturnCodeSuccess {
		err = &Error{
			ReturnCode: returnCode,
			ReturnMsg:  req["return_msg"],
		}
		nm.replyError(w, err.Error())
		return
	}

	if nm.appID != "" {
		wantAppId := nm.appID
		haveAppId := req["appid"]
		if !wechat.Compare(haveAppId, wantAppId) {
			nm.replyError(w, fmt.Sprintf("appid mismatch, have: %s, want: %s", haveAppId, wantAppId))
			return
		}
	}
	if nm.mchID != "" {
		wantMchId := nm.mchID
		haveMchId := req["mch_id"]
		if !wechat.Compare(haveMchId, wantMchId) {
			nm.replyError(w, fmt.Sprintf("mch_id mismatch, have: %s, want: %s", haveMchId, wantMchId))
			return
		}
	}

	if nm.subAppID != "" {
		wantSubAppId := nm.subAppID
		haveSubAppId := req["sub_appid"]
		if haveSubAppId != "" && !wechat.Compare(haveSubAppId, wantSubAppId) {
			nm.replyError(w, fmt.Sprintf("sub_appid mismatch, have: %s, want: %s", haveSubAppId, wantSubAppId))
			return
		}
	}
	if nm.subMchID != "" {
		wantSubMchId := nm.subMchID
		haveSubMchId := req["sub_mch_id"]
		if !wechat.Compare(haveSubMchId, wantSubMchId) {
			nm.replyError(w, fmt.Sprintf("sub_mch_id mismatch, have: %s, want: %s", haveSubMchId, wantSubMchId))
			return
		}
	}

	// 1. refund order notify
	if reqInfo, ok := req["req_info"]; ok {
		encrypted, err := base64.StdEncoding.DecodeString(reqInfo)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		decrypted, err := gocrypto.AesECBDecrypt(encrypted)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		nm.Infof("wechat callback: %s", decrypted)
		info, err := DecodeXML(bytes.NewBuffer(decrypted))
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}

		msg, err := getRefundNotifyMsg(info)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}

		err = refundNotifyHandler(msg)
		if err != nil {
			nm.replyError(w, err.Error())
			return
		}
		return
	}

	// 2. pay order notify

	haveSign := req["sign"]
	var wantSign string
	switch signType := req["sign_type"]; signType {
	case "", SignTypeMD5:
		wantSign = Sign(req, nm.apiKey, md5.New())
	case SignTypeHMAC_SHA256:
		wantSign = Sign(req, nm.apiKey, hmac.New(sha256.New, []byte(nm.apiKey)))
	default:
		nm.replyError(w, fmt.Sprintf("unsupported notification sign_type: %s", signType))
		return
	}
	if !wechat.Compare(haveSign, wantSign) {
		nm.replyError(w, fmt.Sprintf("sign mismatch,\nhave: %s,\nwant: %s", haveSign, wantSign))
		return
	}

	resultCode := req["result_code"]
	if resultCode != ResultCodeSuccess {
		err = &BizError{
			ResultCode:  resultCode,
			ErrCode:     req["err_code"],
			ErrCodeDesc: req["err_code_des"],
		}
		nm.replyError(w, err.Error())
		return
	}

	orderInfo, err := getOrderInfo(req)
	if err != nil {
		nm.replyError(w, err.Error())
	}

	msg := NotifyMsg{
		AppID: req["appid"],
		MchID: req["mch_id"],
		SubAppID: req["sub_appid"],
		SubMchID: req["sub_mch_id"],
		OrderInfo: *orderInfo,
	}
	err = payNotifyHandler(&msg)
	if err != nil {
		nm.replyError(w, err.Error())
	}

	nm.reply(w, ReturnCodeSuccess, "OK")
}

func getRefundNotifyMsg(req map[string]string) (*RefundNotifyMsg, error) {
	totalFee, err := strconv.Atoi(req["total_fee"])
	if err != nil {
		return nil, err
	}
	refundFee, err := strconv.Atoi(req["refund_fee"])
	if err != nil {
		return nil, err
	}
	var successTime time.Time
	if str, ok := req["success_time"]; ok {
		successTime, err = time.Parse("2006-01-02 15:04:05", str)
		if err != nil {
			return nil, err
		}
	}

	return &RefundNotifyMsg{
		TransactionID: req["transaction_id"],
		OutTradeNO: req["out_trade_no"],
		RefundID: req["refund_id"],
		OutRefundNO: req["out_refund_no"],
		TotalFee: totalFee,
		RefundFee: refundFee,
		RefundStatus: RefundStatus(req["refund_status"]),
		SuccessTime: successTime,
	}, nil
}
<|endoftext|>