<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package rpcreflect

import (
	"errors"
	"reflect"
	"sort"
	"sync"
)

var (
	errorType  = reflect.TypeOf((*error)(nil)).Elem()
	stringType = reflect.TypeOf("")
)

var (
	typeMutex     sync.RWMutex
	typesByGoType = make(map[reflect.Type]*Type)

	objTypeMutex     sync.RWMutex
	objTypesByGoType = make(map[reflect.Type]*ObjType)
)

var ErrMethodNotFound = errors.New("no such method")

// Type holds information about a type that implements RPC server methods,
// a root-level RPC type.
type Type struct {
	// root holds the root type.
	root reflect.Type

	// method maps from root-object method name to
	// information about that method. The term "obtain"
	// is because these methods obtain an object to
	// call an action on.
	method map[string]*RootMethod

	// discarded holds names of all discarded methods.
	discarded []string
}

// MethodNames returns the names of all the root object
// methods on the receiving object.
func (r *Type) MethodNames() []string {
	names := make([]string, 0, len(r.method))
	for name := range r.method {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

// Method returns information on the method with the given name,
// or the zero Method and ErrMethodNotFound if there is no such method.
func (r *Type) Method(name string) (RootMethod, error) {
	m, ok := r.method[name]
	if !ok {
		return RootMethod{}, ErrMethodNotFound
	}
	return *m, nil
}

func (r *Type) DiscardedMethods() []string {
	return append([]string(nil), r.discarded...)
}

// RootMethod holds information on a root-level method.
type RootMethod struct {
	// Call invokes the method. The rcvr parameter must be
	// the same type as the root object. The given id is passed
	// as an argument to the method.
	Call func(rcvr reflect.Value, id string) (reflect.Value, error)

	// Methods holds RPC object-method information about
	// objects returned from the above call.
	ObjType *ObjType
}

// TypeOf returns information on all root-level RPC methods
// implemented by an object of the given Go type.
func TypeOf(goType reflect.Type) *Type {
	typeMutex.RLock()
	t := typesByGoType[goType]
	typeMutex.RUnlock()
	if t != nil {
		return t
	}
	typeMutex.Lock()
	defer typeMutex.Unlock()
	t = typesByGoType[goType]
	if t != nil {
		return t
	}
	t = typeInfo(goType)
	typesByGoType[goType] = t
	return t
}

// typeInfo is like TypeInfo but without the cache - it
// always allocates. Called with rootTypeMutex locked.
func typeInfo(goType reflect.Type) *Type {
	rm := &Type{
		method: make(map[string]*RootMethod),
	}
	for i := 0; i < goType.NumMethod(); i++ {
		m := goType.Method(i)
		if m.PkgPath != "" || isKillMethod(m) {
			// The Kill method gets a special exception because
			// it fulfils the Killer interface which we're expecting,
			// so it's not really discarded as such.
			continue
		}
		if o := newRootMethod(m); o != nil {
			rm.method[m.Name] = o
		} else {
			rm.discarded = append(rm.discarded, m.Name)
		}
	}
	return rm
}

func isKillMethod(m reflect.Method) bool {
	return m.Name == "Kill" && m.Type.NumIn() == 1 && m.Type.NumOut() == 0
}

func newRootMethod(m reflect.Method) *RootMethod {
	if m.PkgPath != "" {
		return nil
	}
	t := m.Type
	if t.NumIn() != 2 ||
		t.NumOut() != 2 ||
		t.In(1) != stringType ||
		t.Out(1) != errorType {
		return nil
	}
	f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {
		out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})
		if !out[1].IsNil() {
			err = out[1].Interface().(error)
		}
		r = out[0]
		return
	}
	return &RootMethod{
		Call:    f,
		ObjType: ObjTypeOf(t.Out(0)),
	}
}

// ObjType holds information on RPC methods implemented on
// an RPC object.
type ObjType struct {
	goType    reflect.Type
	method    map[string]*ObjMethod
	discarded []string
}

func (t *ObjType) GoType() reflect.Type {
	return t.goType
}

// Method returns information on the method with the given name,
// or the zero Method and an error if there is no such method.
func (t *ObjType) Method(name string) (ObjMethod, error) {
	m, ok := t.method[name]
	if !ok {
		return ObjMethod{}, ErrMethodNotFound
	}
	return *m, nil
}

// DiscardedMethods returns the names of all methods that cannot
// implement RPC calls because their type signature is inappropriate.
func (t *ObjType) DiscardedMethods() []string {
	return append([]string(nil), t.discarded...)
}

// MethodNames returns the names of all the RPC methods
// defined on the type.
func (t *ObjType) MethodNames() []string {
	names := make([]string, 0, len(t.method))
	for name := range t.method {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

// ObjMethod holds information about an RPC method on an
// object returned by a root-level method.
type ObjMethod struct {
	// Params holds the argument type of the method, or nil
	// if there is no argument.
	Params reflect.Type

	// Result holds the return type of the method, or nil
	// if the method returns no value.
	Result reflect.Type

	// Call calls the method with the given argument
	// on the given receiver value. If the method does
	// not return a value, the returned value will not be valid.
	Call func(rcvr, arg reflect.Value) (reflect.Value, error)
}

// ObjTypeOf returns information on all RPC methods
// implemented by an object of the given Go type,
// as returned from a root-level method.
func ObjTypeOf(objType reflect.Type) *ObjType {
	objTypeMutex.RLock()
	methods := objTypesByGoType[objType]
	objTypeMutex.RUnlock()
	if methods != nil {
		return methods
	}
	objTypeMutex.Lock()
	defer objTypeMutex.Unlock()
	methods = objTypesByGoType[objType]
	if methods != nil {
		return methods
	}
	methods = objTypeOf(objType)
	objTypesByGoType[objType] = methods
	return methods
}

// objTypeOf is like ObjTypeOf but without the cache.
// Called with objTypeMutex locked.
func objTypeOf(goType reflect.Type) *ObjType {
	objType := &ObjType{
		method: make(map[string]*ObjMethod),
		goType: goType,
	}
	for i := 0; i < goType.NumMethod(); i++ {
		m := goType.Method(i)
		if m.PkgPath != "" {
			continue
		}
		if objm := newMethod(m, goType.Kind()); objm != nil {
			objType.method[m.Name] = objm
		} else {
			objType.discarded = append(objType.discarded, m.Name)
		}
	}
	return objType
}

func newMethod(m reflect.Method, receiverKind reflect.Kind) *ObjMethod {
	if m.PkgPath != "" {
		return nil
	}
	var p ObjMethod
	var assemble func(arg reflect.Value) []reflect.Value
	// N.B. The method type has the receiver as its first argument
	// unless the receiver is an interface.
	receiverArgCount := 1
	if receiverKind == reflect.Interface {
		receiverArgCount = 0
	}
	t := m.Type
	switch {
	case t.NumIn() == 0+receiverArgCount:
		// Method() ...
		assemble = func(arg reflect.Value) []reflect.Value {
			return nil
		}
	case t.NumIn() == 1+receiverArgCount:
		// Method(T) ...
		p.Params = t.In(receiverArgCount)
		assemble = func(arg reflect.Value) []reflect.Value {
			return []reflect.Value{arg}
		}
	default:
		return nil
	}

	switch {
	case t.NumOut() == 0:
		// Method(...)
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			rcvr.Method(m.Index).Call(assemble(arg))
			return
		}
	case t.NumOut() == 1 && t.Out(0) == errorType:
		// Method(...) error
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			if !out[0].IsNil() {
				err = out[0].Interface().(error)
			}
			return
		}
	case t.NumOut() == 1:
		// Method(...) R
		p.Result = t.Out(0)
		p.Call = func(rcvr, arg reflect.Value) (reflect.Value, error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			return out[0], nil
		}
	case t.NumOut() == 2 && t.Out(1) == errorType:
		// Method(...) (R, error)
		p.Result = t.Out(0)
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			r = out[0]
			if !out[1].IsNil() {
				err = out[1].Interface().(error)
			}
			return
		}
	default:
		return nil
	}
	// The parameters and return value must be of struct type.
	if p.Params != nil && p.Params.Kind() != reflect.Struct {
		return nil
	}
	if p.Result != nil && p.Result.Kind() != reflect.Struct {
		return nil
	}
	return &p
}
<commit_msg>rpc/rpcreflect: use the right function name this time<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package rpcreflect

import (
	"errors"
	"reflect"
	"sort"
	"sync"
)

var (
	errorType  = reflect.TypeOf((*error)(nil)).Elem()
	stringType = reflect.TypeOf("")
)

var (
	typeMutex     sync.RWMutex
	typesByGoType = make(map[reflect.Type]*Type)

	objTypeMutex     sync.RWMutex
	objTypesByGoType = make(map[reflect.Type]*ObjType)
)

var ErrMethodNotFound = errors.New("no such method")

// Type holds information about a type that implements RPC server methods,
// a root-level RPC type.
type Type struct {
	// root holds the root type.
	root reflect.Type

	// method maps from root-object method name to
	// information about that method. The term "obtain"
	// is because these methods obtain an object to
	// call an action on.
	method map[string]*RootMethod

	// discarded holds names of all discarded methods.
	discarded []string
}

// MethodNames returns the names of all the root object
// methods on the receiving object.
func (r *Type) MethodNames() []string {
	names := make([]string, 0, len(r.method))
	for name := range r.method {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

// Method returns information on the method with the given name,
// or the zero Method and ErrMethodNotFound if there is no such method.
func (r *Type) Method(name string) (RootMethod, error) {
	m, ok := r.method[name]
	if !ok {
		return RootMethod{}, ErrMethodNotFound
	}
	return *m, nil
}

func (r *Type) DiscardedMethods() []string {
	return append([]string(nil), r.discarded...)
}

// RootMethod holds information on a root-level method.
type RootMethod struct {
	// Call invokes the method. The rcvr parameter must be
	// the same type as the root object. The given id is passed
	// as an argument to the method.
	Call func(rcvr reflect.Value, id string) (reflect.Value, error)

	// Methods holds RPC object-method information about
	// objects returned from the above call.
	ObjType *ObjType
}

// TypeOf returns information on all root-level RPC methods
// implemented by an object of the given Go type.
func TypeOf(goType reflect.Type) *Type {
	typeMutex.RLock()
	t := typesByGoType[goType]
	typeMutex.RUnlock()
	if t != nil {
		return t
	}
	typeMutex.Lock()
	defer typeMutex.Unlock()
	t = typesByGoType[goType]
	if t != nil {
		return t
	}
	t = typeOf(goType)
	typesByGoType[goType] = t
	return t
}

// typeOf is like TypeOf but without the cache - it
// always allocates. Called with rootTypeMutex locked.
func typeOf(goType reflect.Type) *Type {
	rm := &Type{
		method: make(map[string]*RootMethod),
	}
	for i := 0; i < goType.NumMethod(); i++ {
		m := goType.Method(i)
		if m.PkgPath != "" || isKillMethod(m) {
			// The Kill method gets a special exception because
			// it fulfils the Killer interface which we're expecting,
			// so it's not really discarded as such.
			continue
		}
		if o := newRootMethod(m); o != nil {
			rm.method[m.Name] = o
		} else {
			rm.discarded = append(rm.discarded, m.Name)
		}
	}
	return rm
}

func isKillMethod(m reflect.Method) bool {
	return m.Name == "Kill" && m.Type.NumIn() == 1 && m.Type.NumOut() == 0
}

func newRootMethod(m reflect.Method) *RootMethod {
	if m.PkgPath != "" {
		return nil
	}
	t := m.Type
	if t.NumIn() != 2 ||
		t.NumOut() != 2 ||
		t.In(1) != stringType ||
		t.Out(1) != errorType {
		return nil
	}
	f := func(rcvr reflect.Value, id string) (r reflect.Value, err error) {
		out := rcvr.Method(m.Index).Call([]reflect.Value{reflect.ValueOf(id)})
		if !out[1].IsNil() {
			err = out[1].Interface().(error)
		}
		r = out[0]
		return
	}
	return &RootMethod{
		Call:    f,
		ObjType: ObjTypeOf(t.Out(0)),
	}
}

// ObjType holds information on RPC methods implemented on
// an RPC object.
type ObjType struct {
	goType    reflect.Type
	method    map[string]*ObjMethod
	discarded []string
}

func (t *ObjType) GoType() reflect.Type {
	return t.goType
}

// Method returns information on the method with the given name,
// or the zero Method and an error if there is no such method.
func (t *ObjType) Method(name string) (ObjMethod, error) {
	m, ok := t.method[name]
	if !ok {
		return ObjMethod{}, ErrMethodNotFound
	}
	return *m, nil
}

// DiscardedMethods returns the names of all methods that cannot
// implement RPC calls because their type signature is inappropriate.
func (t *ObjType) DiscardedMethods() []string {
	return append([]string(nil), t.discarded...)
}

// MethodNames returns the names of all the RPC methods
// defined on the type.
func (t *ObjType) MethodNames() []string {
	names := make([]string, 0, len(t.method))
	for name := range t.method {
		names = append(names, name)
	}
	sort.Strings(names)
	return names
}

// ObjMethod holds information about an RPC method on an
// object returned by a root-level method.
type ObjMethod struct {
	// Params holds the argument type of the method, or nil
	// if there is no argument.
	Params reflect.Type

	// Result holds the return type of the method, or nil
	// if the method returns no value.
	Result reflect.Type

	// Call calls the method with the given argument
	// on the given receiver value. If the method does
	// not return a value, the returned value will not be valid.
	Call func(rcvr, arg reflect.Value) (reflect.Value, error)
}

// ObjTypeOf returns information on all RPC methods
// implemented by an object of the given Go type,
// as returned from a root-level method.
func ObjTypeOf(objType reflect.Type) *ObjType {
	objTypeMutex.RLock()
	methods := objTypesByGoType[objType]
	objTypeMutex.RUnlock()
	if methods != nil {
		return methods
	}
	objTypeMutex.Lock()
	defer objTypeMutex.Unlock()
	methods = objTypesByGoType[objType]
	if methods != nil {
		return methods
	}
	methods = objTypeOf(objType)
	objTypesByGoType[objType] = methods
	return methods
}

// objTypeOf is like ObjTypeOf but without the cache.
// Called with objTypeMutex locked.
func objTypeOf(goType reflect.Type) *ObjType {
	objType := &ObjType{
		method: make(map[string]*ObjMethod),
		goType: goType,
	}
	for i := 0; i < goType.NumMethod(); i++ {
		m := goType.Method(i)
		if m.PkgPath != "" {
			continue
		}
		if objm := newMethod(m, goType.Kind()); objm != nil {
			objType.method[m.Name] = objm
		} else {
			objType.discarded = append(objType.discarded, m.Name)
		}
	}
	return objType
}

func newMethod(m reflect.Method, receiverKind reflect.Kind) *ObjMethod {
	if m.PkgPath != "" {
		return nil
	}
	var p ObjMethod
	var assemble func(arg reflect.Value) []reflect.Value
	// N.B. The method type has the receiver as its first argument
	// unless the receiver is an interface.
	receiverArgCount := 1
	if receiverKind == reflect.Interface {
		receiverArgCount = 0
	}
	t := m.Type
	switch {
	case t.NumIn() == 0+receiverArgCount:
		// Method() ...
		assemble = func(arg reflect.Value) []reflect.Value {
			return nil
		}
	case t.NumIn() == 1+receiverArgCount:
		// Method(T) ...
		p.Params = t.In(receiverArgCount)
		assemble = func(arg reflect.Value) []reflect.Value {
			return []reflect.Value{arg}
		}
	default:
		return nil
	}

	switch {
	case t.NumOut() == 0:
		// Method(...)
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			rcvr.Method(m.Index).Call(assemble(arg))
			return
		}
	case t.NumOut() == 1 && t.Out(0) == errorType:
		// Method(...) error
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			if !out[0].IsNil() {
				err = out[0].Interface().(error)
			}
			return
		}
	case t.NumOut() == 1:
		// Method(...) R
		p.Result = t.Out(0)
		p.Call = func(rcvr, arg reflect.Value) (reflect.Value, error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			return out[0], nil
		}
	case t.NumOut() == 2 && t.Out(1) == errorType:
		// Method(...) (R, error)
		p.Result = t.Out(0)
		p.Call = func(rcvr, arg reflect.Value) (r reflect.Value, err error) {
			out := rcvr.Method(m.Index).Call(assemble(arg))
			r = out[0]
			if !out[1].IsNil() {
				err = out[1].Interface().(error)
			}
			return
		}
	default:
		return nil
	}
	// The parameters and return value must be of struct type.
	if p.Params != nil && p.Params.Kind() != reflect.Struct {
		return nil
	}
	if p.Result != nil && p.Result.Kind() != reflect.Struct {
		return nil
	}
	return &p
}
<|endoftext|>


<commit_before>package main

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

func startUdpServer() {
	service := Conf.UdpBind
	udpAddr, err := net.ResolveUDPAddr("udp4", service)
	if err != nil {
		log.Panic(err)
	}
	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Panic(err)
	}
	for {
		handleUdpConn(conn)
	}
}

func handleUdpConn(conn *net.UDPConn) {
	var buf [512]byte
	_, addr, err := conn.ReadFromUDP(buf[0:])
	if err != nil {
		return
	}
	log.Debugf("udp conn from %s  buf: %v ", addr, buf)
}
<commit_msg>update log<commit_after>package main

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

func startUdpServer() {
	service := Conf.UdpBind
	udpAddr, err := net.ResolveUDPAddr("udp4", service)
	if err != nil {
		log.Panic(err)
	}
	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Panic(err)
	}
	for {
		handleUdpConn(conn)
	}
}

func handleUdpConn(conn *net.UDPConn) {
	var buf [512]byte
	_, addr, err := conn.ReadFromUDP(buf[0:])
	if err != nil {
		return
	}
	log.Debugf("udp conn from %s  buf: %s ", addr, string(buf))
}
<|endoftext|>


<commit_before>package libspf2

/*
#cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lspf2
#cgo CFLAGS: -g -O2 -Wno-error -I/usr/include -I/usr/local/include

#include <stdio.h>
#include <netdb.h>
#include <spf2/spf.h>
*/
import "C"
import "errors"

const (
	SPFResultINVALID   = Result(C.SPF_RESULT_INVALID)   // (invalid)
	SPFResultPASS      = Result(C.SPF_RESULT_PASS)      // pass
	SPFResultFAIL      = Result(C.SPF_RESULT_FAIL)      // fail
	SPFResultSOFTFAIL  = Result(C.SPF_RESULT_SOFTFAIL)  // softfail
	SPFResultNEUTRAL   = Result(C.SPF_RESULT_NEUTRAL)   // neutral
	SPFResultPERMERROR = Result(C.SPF_RESULT_PERMERROR) // permerror
	SPFResultTEMPERROR = Result(C.SPF_RESULT_TEMPERROR) // temperror
	SPFResultNONE      = Result(C.SPF_RESULT_NONE)      // none
)

type Client interface {
	Query(host, ip string) (Result, error)
	Close()
}

type clientImpl struct {
	s *C.SPF_server_t
}

// NewClient creates a new SPF client.
func NewClient() Client {
	client := new(clientImpl)
	client.s = C.SPF_server_new(C.SPF_DNS_CACHE, 0)
	return client
}

func (s *clientImpl) Query(host, ip string) (Result, error) {
	if s.s == nil {
		return SPFResultINVALID, errors.New("client already closed")
	}
	req := newRequest(s)
	defer req.free()
	if err := req.setEnvFrom(host); err != nil {
		return SPFResultINVALID, err
	}
	if err := req.setIPv4Addr(ip); err != nil {
		return SPFResultINVALID, err
	}
	resp, err := req.query()
	if err != nil {
		return SPFResultNONE, err
	}
	defer resp.free()
	return resp.result(), nil
}

func (s *clientImpl) Close() {
	if s.s != nil {
		C.SPF_server_free(s.s)
		s.s = nil
	}
}

type request struct {
	s *clientImpl
	r *C.SPF_request_t
}

func newRequest(s *clientImpl) *request {
	r := new(request)
	r.s = s
	r.r = C.SPF_request_new(s.s)
	return r
}

// SetIPv4Addr sets the sender IPv4
func (r *request) setIPv4Addr(addr string) error {
	var stat C.SPF_errcode_t
	stat = C.SPF_request_set_ipv4_str(r.r, C.CString(addr))
	if stat != C.SPF_E_SUCCESS {
		return &spfError{stat}
	}
	return nil
}

// SetEnvFrom sets the sender host
func (r *request) setEnvFrom(fromHost string) error {
	var stat C.int
	stat = C.SPF_request_set_env_from(r.r, C.CString(fromHost))
	if stat != C.int(C.SPF_E_SUCCESS) {
		return &spfError{C.SPF_errcode_t(stat)}
	}
	return nil
}

// Query starts the SPF query
func (r *request) query() (*response, error) {
	var stat C.SPF_errcode_t
	var resp *C.SPF_response_t
	stat = C.SPF_request_query_mailfrom(r.r, &resp)
	if stat != C.SPF_E_SUCCESS {
		return nil, &spfError{stat}
	}
	return &response{resp}, nil
}

// Free the request handle
func (r *request) free() {
	if r.r != nil {
		C.SPF_request_free(r.r)
		r.r = nil
	}
}

type response struct {
	r *C.SPF_response_t
}

// Result returns the SPF validation result
func (r *response) result() Result {
	return Result(C.SPF_response_result(r.r))
}

// Free frees the response handle
func (r *response) free() {
	if r.r != nil {
		C.SPF_response_free(r.r)
		r.r = nil
	}
}

type Result int

func (r Result) String() string {
	return C.GoString(C.SPF_strresult(C.SPF_result_t(r)))
}

type spfError struct {
	code C.SPF_errcode_t
}

func (e *spfError) Error() string {
	return C.GoString(C.SPF_strerror(e.code))
}
<commit_msg>Add v6 support, clean some v6 strings. Use net.IP instead of string for ip<commit_after>package libspf2

/*
#cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lspf2
#cgo CFLAGS: -g -O2 -Wno-error -I/usr/include -I/usr/local/include

#include <stdlib.h>
#include <netdb.h>
#include <spf2/spf.h>
*/
import "C"

import (
	"errors"
	"net"
	"unsafe"
)

const (
	SPFResultINVALID   = Result(C.SPF_RESULT_INVALID)   // (invalid)
	SPFResultPASS      = Result(C.SPF_RESULT_PASS)      // pass
	SPFResultFAIL      = Result(C.SPF_RESULT_FAIL)      // fail
	SPFResultSOFTFAIL  = Result(C.SPF_RESULT_SOFTFAIL)  // softfail
	SPFResultNEUTRAL   = Result(C.SPF_RESULT_NEUTRAL)   // neutral
	SPFResultPERMERROR = Result(C.SPF_RESULT_PERMERROR) // permerror
	SPFResultTEMPERROR = Result(C.SPF_RESULT_TEMPERROR) // temperror
	SPFResultNONE      = Result(C.SPF_RESULT_NONE)      // none
)

type Client interface {
	Query(host string, ip net.IP) (Result, error)
	Close()
}

type clientImpl struct {
	s *C.SPF_server_t
}

// NewClient creates a new SPF client.
func NewClient() Client {
	client := new(clientImpl)
	client.s = C.SPF_server_new(C.SPF_DNS_CACHE, 0)
	return client
}

func (s *clientImpl) Query(host string, ip net.IP) (Result, error) {
	if s.s == nil {
		return SPFResultINVALID, errors.New("client already closed")
	}
	req := newRequest(s)
	defer req.free()
	if err := req.setEnvFrom(host); err != nil {
		return SPFResultINVALID, err
	}
	if err := req.setIpAddr(ip); err != nil {
		return SPFResultINVALID, err
	}
	resp, err := req.query()
	if err != nil {
		return SPFResultNONE, err
	}
	defer resp.free()
	return resp.result(), nil
}

func (s *clientImpl) Close() {
	if s.s != nil {
		C.SPF_server_free(s.s)
		s.s = nil
	}
}

type request struct {
	s *clientImpl
	r *C.SPF_request_t
}

func newRequest(s *clientImpl) *request {
	r := new(request)
	r.s = s
	r.r = C.SPF_request_new(s.s)
	return r
}

// SetIPAddr sets the IP address of the client (sending) MTA
func (r *request) setIpAddr(ip net.IP) error {
	var stat C.SPF_errcode_t
	cstring := C.CString(ip.String())
	defer C.free(unsafe.Pointer(cstring))
	if ip.To4() != nil {
		stat = C.SPF_request_set_ipv4_str(r.r, cstring)
	} else {
		stat = C.SPF_request_set_ipv6_str(r.r, cstring)
	}
	if stat != C.SPF_E_SUCCESS {
		return &spfError{stat}
	}
	return nil
}

// SetEnvFrom sets the envelope from email address from the SMTP MAIL FROM: command
func (r *request) setEnvFrom(from string) error {
	var stat C.int
	cstring := C.CString(from)
	defer C.free(unsafe.Pointer(cstring))
	stat = C.SPF_request_set_env_from(r.r, cstring)
	if stat != C.int(C.SPF_E_SUCCESS) {
		return &spfError{C.SPF_errcode_t(stat)}
	}
	return nil
}

// Query starts the SPF query
func (r *request) query() (*response, error) {
	var stat C.SPF_errcode_t
	var resp *C.SPF_response_t
	stat = C.SPF_request_query_mailfrom(r.r, &resp)
	if stat != C.SPF_E_SUCCESS {
		return nil, &spfError{stat}
	}
	return &response{resp}, nil
}

// Free the request handle
func (r *request) free() {
	if r.r != nil {
		C.SPF_request_free(r.r)
		r.r = nil
	}
}

type response struct {
	r *C.SPF_response_t
}

// Result returns the SPF validation result
func (r *response) result() Result {
	return Result(C.SPF_response_result(r.r))
}

// Free frees the response handle
func (r *response) free() {
	if r.r != nil {
		C.SPF_response_free(r.r)
		r.r = nil
	}
}

type Result int

func (r Result) String() string {
	return C.GoString(C.SPF_strresult(C.SPF_result_t(r)))
}

type spfError struct {
	code C.SPF_errcode_t
}

func (e *spfError) Error() string {
	return C.GoString(C.SPF_strerror(e.code))
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/go-martini/martini"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/redigo/redis"
	"github.com/ninjasphere/sphere-go-homecloud/homecloud"
	"github.com/ninjasphere/sphere-go-homecloud/routes"
)

// RestServer Holds stuff shared by all the rest services
type RestServer struct {
	redisPool *redis.Pool
	conn      *ninja.Connection

	roomModel   *homecloud.RoomModel
	thingModel  *homecloud.ThingModel
	deviceModel *homecloud.DeviceModel
}

func NewRestServer(conn *ninja.Connection) *RestServer {

	conn, err := ninja.Connect("sphere-go-homecloud-rest")

	if err != nil {
		log.FatalError(err, "Failed to connect to mqtt")
	}

	return &RestServer{
		redisPool:   homecloud.RedisPool,
		conn:        conn,
		roomModel:   homecloud.NewRoomModel(homecloud.RedisPool, conn),
		thingModel:  homecloud.NewThingModel(homecloud.RedisPool, conn),
		deviceModel: homecloud.NewDeviceModel(homecloud.RedisPool, conn),
	}
}

func (r *RestServer) Listen() {

	m := martini.Classic()

	m.Map(r.roomModel)
	m.Map(r.thingModel)
	m.Map(r.deviceModel)
	m.Map(r.conn)

	location := routes.NewLocationRouter()
	thing := routes.NewThingRouter()
	room := routes.NewRoomRouter()

	m.Group("/rest/v1/location", location.Register)
	m.Group("/rest/v1/thing", thing.Register)
	m.Group("/rest/v1/room", room.Register)

	http.ListenAndServe(":8000", m)
}

func (r *RestServer) getStuff() string {
	return "Hello world!"
}
<commit_msg>Pluralise to match cloud and 99% of other web services :)<commit_after>package main

import (
	"net/http"

	"github.com/go-martini/martini"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/redigo/redis"
	"github.com/ninjasphere/sphere-go-homecloud/homecloud"
	"github.com/ninjasphere/sphere-go-homecloud/routes"
)

// RestServer Holds stuff shared by all the rest services
type RestServer struct {
	redisPool *redis.Pool
	conn      *ninja.Connection

	roomModel   *homecloud.RoomModel
	thingModel  *homecloud.ThingModel
	deviceModel *homecloud.DeviceModel
}

func NewRestServer(conn *ninja.Connection) *RestServer {

	conn, err := ninja.Connect("sphere-go-homecloud-rest")

	if err != nil {
		log.FatalError(err, "Failed to connect to mqtt")
	}

	return &RestServer{
		redisPool:   homecloud.RedisPool,
		conn:        conn,
		roomModel:   homecloud.NewRoomModel(homecloud.RedisPool, conn),
		thingModel:  homecloud.NewThingModel(homecloud.RedisPool, conn),
		deviceModel: homecloud.NewDeviceModel(homecloud.RedisPool, conn),
	}
}

func (r *RestServer) Listen() {

	m := martini.Classic()

	m.Map(r.roomModel)
	m.Map(r.thingModel)
	m.Map(r.deviceModel)
	m.Map(r.conn)

	location := routes.NewLocationRouter()
	thing := routes.NewThingRouter()
	room := routes.NewRoomRouter()

	m.Group("/rest/v1/locations", location.Register)
	m.Group("/rest/v1/things", thing.Register)
	m.Group("/rest/v1/rooms", room.Register)

	http.ListenAndServe(":8000", m)
}

func (r *RestServer) getStuff() string {
	return "Hello world!"
}
<|endoftext|>


<commit_before>package darksky

import (
	"compress/gzip"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
)

func get(url string, output interface{}) error {
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return err
	}

	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Accept-Encoding", "gzip")

	client := http.Client{}
	response, err := client.Do(req)

	defer response.Body.Close()

	err = checkErrors(response)

	if err != nil {
		return err
	}

	body, err := decompress(response)

	if err != nil {
		return err
	}

	return decodeJson(body, &output)
}

func checkErrors(response *http.Response) error {
	if response.StatusCode != 200 {
		body, _ := ioutil.ReadAll(response.Body)
		return errors.New("Bad response: " + string(body))
	}

	return nil
}

func decompress(response *http.Response) (io.Reader, error) {
	header := response.Header.Get("Content-Encoding")

	if len(header) < 1 {
		return response.Body, nil
	}

	reader, err := gzip.NewReader(response.Body)

	if err != nil {
		return nil, err
	}

	return reader, nil
}

func decodeJson(body io.Reader, into interface{}) error {
	jsonDecoder := json.NewDecoder(body)

	return jsonDecoder.Decode(&into)
}
<commit_msg>specify charset<commit_after>package darksky

import (
	"compress/gzip"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net/http"
)

func get(url string, output interface{}) error {
	req, err := http.NewRequest("GET", url, nil)

	if err != nil {
		return err
	}

	req.Header.Add("Content-Type", "application/json; charset=utf-8")
	req.Header.Add("Accept-Encoding", "gzip")

	client := http.Client{}
	response, err := client.Do(req)

	defer response.Body.Close()

	err = checkErrors(response)

	if err != nil {
		return err
	}

	body, err := decompress(response)

	if err != nil {
		return err
	}

	return decodeJson(body, &output)
}

func checkErrors(response *http.Response) error {
	if response.StatusCode != 200 {
		body, _ := ioutil.ReadAll(response.Body)
		return errors.New("Bad response: " + string(body))
	}

	return nil
}

func decompress(response *http.Response) (io.Reader, error) {
	header := response.Header.Get("Content-Encoding")

	if len(header) < 1 {
		return response.Body, nil
	}

	reader, err := gzip.NewReader(response.Body)

	if err != nil {
		return nil, err
	}

	return reader, nil
}

func decodeJson(body io.Reader, into interface{}) error {
	jsonDecoder := json.NewDecoder(body)

	return jsonDecoder.Decode(&into)
}
<|endoftext|>


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

package net

import (
	"os"
	"runtime"
	"testing"
)

var listenMulticastUDPTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
}

func TestListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		return
	case "linux":
		if runtime.GOARCH == "arm" {
			return
		}
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		defer c.Close() // test to listen concurrently across multiple listeners
		if !tt.ipv6 {
			testIPv4MulticastSocketOptions(t, c.fd, ifi)
		} else {
			testIPv6MulticastSocketOptions(t, c.fd, ifi)
		}
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		var found bool
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("%q not found in RIB", tt.gaddr.String())
		}
	}
}

func TestSimpleListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		return
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		c.Close()
	}
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	t.Logf("IPv4 multicast interface: %v", ifmc)
	err = setIPv4MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv4MulticastInterface failed: %v", err)
	}

	ttl, err := ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	t.Logf("IPv4 multicast TTL: %v", ttl)
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}

	loop, err := ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv4 multicast loopback: %v", loop)
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	t.Logf("IPv6 multicast interface: %v", ifmc)
	err = setIPv6MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv6MulticastInterface failed: %v", err)
	}

	hoplim, err := ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	t.Logf("IPv6 multicast hop limit: %v", hoplim)
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}

	loop, err := ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv6 multicast loopback: %v", loop)
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<commit_msg>net: Don't run UDP multicast tests on Alpha GNU/Linux.<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package net

import (
	"os"
	"runtime"
	"testing"
)

var listenMulticastUDPTests = []struct {
	net   string
	gaddr *UDPAddr
	flags Flags
	ipv6  bool
}{
	// cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
	{"udp", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp4", &UDPAddr{IPv4(224, 0, 0, 254), 12345}, FlagUp | FlagLoopback, false},
	{"udp", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff01::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff02::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff04::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff05::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff08::114"), 12345}, FlagUp | FlagLoopback, true},
	{"udp6", &UDPAddr{ParseIP("ff0e::114"), 12345}, FlagUp | FlagLoopback, true},
}

func TestListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "netbsd", "openbsd", "plan9", "windows":
		return
	case "linux":
		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
			return
		}
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 && (!supportsIPv6 || os.Getuid() != 0) {
			continue
		}
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		defer c.Close() // test to listen concurrently across multiple listeners
		if !tt.ipv6 {
			testIPv4MulticastSocketOptions(t, c.fd, ifi)
		} else {
			testIPv6MulticastSocketOptions(t, c.fd, ifi)
		}
		ifmat, err := ifi.MulticastAddrs()
		if err != nil {
			t.Fatalf("MulticastAddrs failed: %v", err)
		}
		var found bool
		for _, ifma := range ifmat {
			if ifma.(*IPAddr).IP.Equal(tt.gaddr.IP) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("%q not found in RIB", tt.gaddr.String())
		}
	}
}

func TestSimpleListenMulticastUDP(t *testing.T) {
	switch runtime.GOOS {
	case "plan9":
		return
	}

	for _, tt := range listenMulticastUDPTests {
		if tt.ipv6 {
			continue
		}
		tt.flags = FlagUp | FlagMulticast
		ift, err := Interfaces()
		if err != nil {
			t.Fatalf("Interfaces failed: %v", err)
		}
		var ifi *Interface
		for _, x := range ift {
			if x.Flags&tt.flags == tt.flags {
				ifi = &x
				break
			}
		}
		if ifi == nil {
			t.Logf("an appropriate multicast interface not found")
			return
		}
		c, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
		if err != nil {
			t.Fatalf("ListenMulticastUDP failed: %v", err)
		}
		c.Close()
	}
}

func testIPv4MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv4MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastInterface failed: %v", err)
	}
	t.Logf("IPv4 multicast interface: %v", ifmc)
	err = setIPv4MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv4MulticastInterface failed: %v", err)
	}

	ttl, err := ipv4MulticastTTL(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastTTL failed: %v", err)
	}
	t.Logf("IPv4 multicast TTL: %v", ttl)
	err = setIPv4MulticastTTL(fd, 1)
	if err != nil {
		t.Fatalf("setIPv4MulticastTTL failed: %v", err)
	}

	loop, err := ipv4MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv4MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv4 multicast loopback: %v", loop)
	err = setIPv4MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv4MulticastLoopback failed: %v", err)
	}
}

func testIPv6MulticastSocketOptions(t *testing.T, fd *netFD, ifi *Interface) {
	ifmc, err := ipv6MulticastInterface(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastInterface failed: %v", err)
	}
	t.Logf("IPv6 multicast interface: %v", ifmc)
	err = setIPv6MulticastInterface(fd, ifi)
	if err != nil {
		t.Fatalf("setIPv6MulticastInterface failed: %v", err)
	}

	hoplim, err := ipv6MulticastHopLimit(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastHopLimit failed: %v", err)
	}
	t.Logf("IPv6 multicast hop limit: %v", hoplim)
	err = setIPv6MulticastHopLimit(fd, 1)
	if err != nil {
		t.Fatalf("setIPv6MulticastHopLimit failed: %v", err)
	}

	loop, err := ipv6MulticastLoopback(fd)
	if err != nil {
		t.Fatalf("ipv6MulticastLoopback failed: %v", err)
	}
	t.Logf("IPv6 multicast loopback: %v", loop)
	err = setIPv6MulticastLoopback(fd, false)
	if err != nil {
		t.Fatalf("setIPv6MulticastLoopback failed: %v", err)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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 fieldpath

import (
	"bytes"
	"io"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
)

func (s *Set) ToJSON() ([]byte, error) {
	buf := bytes.Buffer{}
	err := s.ToJSONStream(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (s *Set) ToJSONStream(w io.Writer) error {
	stream := writePool.BorrowStream(w)
	defer writePool.ReturnStream(stream)

	var r reusableBuilder

	stream.WriteObjectStart()
	err := s.emitContents_v1(false, stream, &r)
	if err != nil {
		return err
	}
	stream.WriteObjectEnd()
	return stream.Flush()
}

func manageMemory(stream *jsoniter.Stream) error {
	// Help jsoniter manage its buffers--without this, it does a bunch of
	// alloctaions that are not necessary. They were probably optimizing
	// for folks using the buffer directly.
	b := stream.Buffer()
	if len(b) > 4096 || cap(b)-len(b) < 2048 {
		if err := stream.Flush(); err != nil {
			return err
		}
		stream.SetBuffer(b[:0])
	}
	return nil
}

type reusableBuilder struct {
	bytes.Buffer
}

func (r *reusableBuilder) unsafeString() string {
	b := r.Bytes()
	return *(*string)(unsafe.Pointer(&b))
}

func (r *reusableBuilder) reset() *bytes.Buffer {
	r.Reset()
	return &r.Buffer
}

func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error {
	mi, ci := 0, 0
	first := true
	preWrite := func() {
		if first {
			first = false
			return
		}
		stream.WriteMore()
	}

	for mi < len(s.Members.members) && ci < len(s.Children.members) {
		mpe := s.Members.members[mi]
		cpe := s.Children.members[ci].pathElement

		if mpe.Less(cpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteEmptyObject()
			mi++
		} else if cpe.Less(mpe) {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			ci++
		} else {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(true, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			mi++
			ci++
		}
	}

	for mi < len(s.Members.members) {
		mpe := s.Members.members[mi]

		preWrite()
		if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteEmptyObject()
		mi++
	}

	for ci < len(s.Children.members) {
		cpe := s.Children.members[ci].pathElement

		preWrite()
		if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteObjectStart()
		if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
			return err
		}
		stream.WriteObjectEnd()
		ci++
	}

	if includeSelf && !first {
		preWrite()
		stream.WriteObjectField(".")
		stream.WriteEmptyObject()
	}
	return manageMemory(stream)
}

// FromJSON clears s and reads a JSON formatted set structure.
func (s *Set) FromJSON(r io.Reader) error {
	// The iterator pool is completely useless for memory management, grrr.
	iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096)

	found, _ := readIter_v1(iter)
	if found == nil {
		*s = Set{}
	} else {
		*s = *found
	}
	return iter.Error
}

// returns true if this subtree is also (or only) a member of parent; s is nil
// if there are no further children.
func readIter_v1(iter *jsoniter.Iterator) (children *Set, isMember bool) {
	iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool {
		if key == "." {
			isMember = true
			iter.Skip()
			return true
		}
		pe, err := DeserializePathElement(key)
		if err == ErrUnknownPathElementType {
			// Ignore these-- a future version maybe knows what
			// they are. We drop these completely rather than try
			// to preserve things we don't understand.
			iter.Skip()
			return true
		} else if err != nil {
			iter.ReportError("parsing key as path element", err.Error())
			iter.Skip()
			return true
		}
		grandchildren, childIsMember := readIter_v1(iter)
		if childIsMember {
			if children == nil {
				children = &Set{}
			}
			m := &children.Members.members
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe)
			if appendOK {
				*m = append(*m, pe)
			} else {
				children.Members.Insert(pe)
			}
		}
		if grandchildren != nil {
			if children == nil {
				children = &Set{}
			}
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			m := &children.Children.members
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe)
			if appendOK {
				*m = append(*m, setNode{pe, grandchildren})
			} else {
				*children.Children.Descend(pe) = *grandchildren
			}
		}
		return true
	})
	if children == nil {
		isMember = true
	}

	return children, isMember
}
<commit_msg>Use Compare when serializing rather than Less<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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 fieldpath

import (
	"bytes"
	"io"
	"unsafe"

	jsoniter "github.com/json-iterator/go"
)

func (s *Set) ToJSON() ([]byte, error) {
	buf := bytes.Buffer{}
	err := s.ToJSONStream(&buf)
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

func (s *Set) ToJSONStream(w io.Writer) error {
	stream := writePool.BorrowStream(w)
	defer writePool.ReturnStream(stream)

	var r reusableBuilder

	stream.WriteObjectStart()
	err := s.emitContents_v1(false, stream, &r)
	if err != nil {
		return err
	}
	stream.WriteObjectEnd()
	return stream.Flush()
}

func manageMemory(stream *jsoniter.Stream) error {
	// Help jsoniter manage its buffers--without this, it does a bunch of
	// alloctaions that are not necessary. They were probably optimizing
	// for folks using the buffer directly.
	b := stream.Buffer()
	if len(b) > 4096 || cap(b)-len(b) < 2048 {
		if err := stream.Flush(); err != nil {
			return err
		}
		stream.SetBuffer(b[:0])
	}
	return nil
}

type reusableBuilder struct {
	bytes.Buffer
}

func (r *reusableBuilder) unsafeString() string {
	b := r.Bytes()
	return *(*string)(unsafe.Pointer(&b))
}

func (r *reusableBuilder) reset() *bytes.Buffer {
	r.Reset()
	return &r.Buffer
}

func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream, r *reusableBuilder) error {
	mi, ci := 0, 0
	first := true
	preWrite := func() {
		if first {
			first = false
			return
		}
		stream.WriteMore()
	}

	for mi < len(s.Members.members) && ci < len(s.Children.members) {
		mpe := s.Members.members[mi]
		cpe := s.Children.members[ci].pathElement

		if c := mpe.Compare(cpe); c < 0 {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteEmptyObject()
			mi++
		} else if c > 0 {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			ci++
		} else {
			preWrite()
			if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
				return err
			}
			stream.WriteObjectField(r.unsafeString())
			stream.WriteObjectStart()
			if err := s.Children.members[ci].set.emitContents_v1(true, stream, r); err != nil {
				return err
			}
			stream.WriteObjectEnd()
			mi++
			ci++
		}
	}

	for mi < len(s.Members.members) {
		mpe := s.Members.members[mi]

		preWrite()
		if err := serializePathElementToWriter(r.reset(), mpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteEmptyObject()
		mi++
	}

	for ci < len(s.Children.members) {
		cpe := s.Children.members[ci].pathElement

		preWrite()
		if err := serializePathElementToWriter(r.reset(), cpe); err != nil {
			return err
		}
		stream.WriteObjectField(r.unsafeString())
		stream.WriteObjectStart()
		if err := s.Children.members[ci].set.emitContents_v1(false, stream, r); err != nil {
			return err
		}
		stream.WriteObjectEnd()
		ci++
	}

	if includeSelf && !first {
		preWrite()
		stream.WriteObjectField(".")
		stream.WriteEmptyObject()
	}
	return manageMemory(stream)
}

// FromJSON clears s and reads a JSON formatted set structure.
func (s *Set) FromJSON(r io.Reader) error {
	// The iterator pool is completely useless for memory management, grrr.
	iter := jsoniter.Parse(jsoniter.ConfigCompatibleWithStandardLibrary, r, 4096)

	found, _ := readIter_v1(iter)
	if found == nil {
		*s = Set{}
	} else {
		*s = *found
	}
	return iter.Error
}

// returns true if this subtree is also (or only) a member of parent; s is nil
// if there are no further children.
func readIter_v1(iter *jsoniter.Iterator) (children *Set, isMember bool) {
	iter.ReadMapCB(func(iter *jsoniter.Iterator, key string) bool {
		if key == "." {
			isMember = true
			iter.Skip()
			return true
		}
		pe, err := DeserializePathElement(key)
		if err == ErrUnknownPathElementType {
			// Ignore these-- a future version maybe knows what
			// they are. We drop these completely rather than try
			// to preserve things we don't understand.
			iter.Skip()
			return true
		} else if err != nil {
			iter.ReportError("parsing key as path element", err.Error())
			iter.Skip()
			return true
		}
		grandchildren, childIsMember := readIter_v1(iter)
		if childIsMember {
			if children == nil {
				children = &Set{}
			}
			m := &children.Members.members
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].Less(pe)
			if appendOK {
				*m = append(*m, pe)
			} else {
				children.Members.Insert(pe)
			}
		}
		if grandchildren != nil {
			if children == nil {
				children = &Set{}
			}
			// Since we expect that most of the time these will have been
			// serialized in the right order, we just verify that and append.
			m := &children.Children.members
			appendOK := len(*m) == 0 || (*m)[len(*m)-1].pathElement.Less(pe)
			if appendOK {
				*m = append(*m, setNode{pe, grandchildren})
			} else {
				*children.Children.Descend(pe) = *grandchildren
			}
		}
		return true
	})
	if children == nil {
		isMember = true
	}

	return children, isMember
}
<|endoftext|>


<commit_before>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * output.go
 *
 *  Created on: Mar 30, 2018
 *      Author: Massimiliano Ghilardi
 */

package fast

import (
	"fmt"
	"go/types"
	"io"
	r "reflect"
	"sort"

	"github.com/cosmos72/gomacro/base"
	"github.com/cosmos72/gomacro/base/output"
	"github.com/cosmos72/gomacro/base/paths"
	xr "github.com/cosmos72/gomacro/xreflect"
)

func (b Builtin) String() string {
	return fmt.Sprintf("%p", b.Compile)
}

func (imp *Import) String() string {
	return fmt.Sprintf("{%s %q, %d binds, %d types}", imp.Name, imp.Path, len(imp.Binds), len(imp.Types))
}

func typestringer(path string) func(xr.Type) string {
	name := paths.FileName(path)
	if name == path {
		return xr.Type.String
	}
	qualifier := func(pkg *types.Package) string {
		pkgpath := pkg.Path()
		if pkgpath == path {
			// base.Debugf("replaced package path %q -> %s", path, name)
			return name
		}
		// base.Debugf("keep package path %q, does not match %q", pkgpath, path)
		return pkgpath
	}
	return func(t xr.Type) string {
		return types.TypeString(t.GoType(), qualifier)
	}
}

func (ir *Interp) ShowPackage(name string) {
	if len(name) != 0 {
		ir.ShowImportedPackage(name)
		return
	}
	// show current package and its outer scopes
	stack := make([]*Interp, 0)
	interp := ir
	for {
		stack = append(stack, interp)
		c := interp.Comp
		env := interp.env
		for i := 0; i < c.UpCost && env != nil; i++ {
			env = env.Outer
		}
		c = c.Outer
		if env == nil || c == nil {
			break
		}
		interp = &Interp{c, env}
	}
	for i := len(stack) - 1; i >= 0; i-- {
		stack[i].ShowAsPackage()
	}
}

func (ir *Interp) ShowAsPackage() {
	c := ir.Comp
	env := ir.PrepareEnv()
	out := c.Globals.Stdout
	stringer := typestringer(c.Path)
	if binds := c.Binds; len(binds) > 0 {
		output.ShowPackageHeader(out, c.Name, c.Path, "binds")

		keys := make([]string, len(binds))
		i := 0
		for k := range binds {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		for _, k := range keys {
			if bind := binds[k]; bind != nil {
				v := bind.RuntimeValue(env)
				showValue(out, k, v, bind.Type, stringer)
			}
		}
		fmt.Fprintln(out)
	}
	showTypes(out, c.Name, c.Path, c.Types, stringer)
}

func (ir *Interp) ShowImportedPackage(name string) {
	var imp *Import
	var ok bool
	if bind := ir.Comp.Binds[name]; bind != nil && bind.Const() && bind.Type != nil && bind.Type.ReflectType() == rtypeOfPtrImport {
		imp, ok = bind.Value.(*Import)
	}
	if !ok {
		ir.Comp.Warnf("not an imported package: %q", name)
		return
	}
	imp.Show(ir.Comp.CompGlobals)
}

func (imp *Import) Show(g *CompGlobals) {
	stringer := typestringer(imp.Path)
	out := g.Stdout
	if binds := imp.Binds; len(binds) > 0 {
		output.ShowPackageHeader(out, imp.Name, imp.Path, "binds")

		keys := make([]string, len(binds))
		i := 0
		for k := range binds {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		env := imp.env
		for _, k := range keys {
			bind := imp.Binds[k]
			v := bind.RuntimeValue(env)
			showValue(out, k, v, bind.Type, stringer)
		}
		fmt.Fprintln(out)
	}
	showTypes(out, imp.Name, imp.Path, imp.Types, stringer)
}

func showTypes(out io.Writer, name string, path string, types map[string]xr.Type, stringer func(xr.Type) string) {
	if len(types) > 0 {
		output.ShowPackageHeader(out, name, path, "types")

		keys := make([]string, len(types))
		i := 0
		for k := range types {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		for _, k := range keys {
			t := types[k]
			if t != nil {
				showType(out, k, t, stringer)
			}
		}
		fmt.Fprintln(out)
	}
}

const spaces15 = "               "

func showValue(out io.Writer, name string, v r.Value, t xr.Type, stringer func(xr.Type) string) {
	n := len(name) & 15
	str := stringer(t)
	if v == base.Nil || v == base.None {
		fmt.Fprintf(out, "%s%s = nil\t// %s\n", name, spaces15[n:], str)
	} else {
		fmt.Fprintf(out, "%s%s = %v\t// %s\n", name, spaces15[n:], v, str)
	}
}

func showType(out io.Writer, name string, t xr.Type, stringer func(xr.Type) string) {
	n := len(name) & 15
	fmt.Fprintf(out, "%s%s = %v\t// %v\n", name, spaces15[n:], stringer(t), t.Kind())
}
<commit_msg>harden :env against panics in printing package's constants and variables - should fix #47<commit_after>/*
 * gomacro - A Go interpreter with Lisp-like macros
 *
 * Copyright (C) 2017-2018 Massimiliano Ghilardi
 *
 *     This Source Code Form is subject to the terms of the Mozilla Public
 *     License, v. 2.0. If a copy of the MPL was not distributed with this
 *     file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *
 * output.go
 *
 *  Created on: Mar 30, 2018
 *      Author: Massimiliano Ghilardi
 */

package fast

import (
	"fmt"
	"go/types"
	"io"
	r "reflect"
	"sort"

	"github.com/cosmos72/gomacro/base"
	"github.com/cosmos72/gomacro/base/output"
	"github.com/cosmos72/gomacro/base/paths"
	xr "github.com/cosmos72/gomacro/xreflect"
)

func (b Builtin) String() string {
	return fmt.Sprintf("%p", b.Compile)
}

func (imp *Import) String() string {
	return fmt.Sprintf("{%s %q, %d binds, %d types}", imp.Name, imp.Path, len(imp.Binds), len(imp.Types))
}

func typestringer(path string) func(xr.Type) string {
	name := paths.FileName(path)
	if name == path {
		return xr.Type.String
	}
	qualifier := func(pkg *types.Package) string {
		pkgpath := pkg.Path()
		if pkgpath == path {
			// base.Debugf("replaced package path %q -> %s", path, name)
			return name
		}
		// base.Debugf("keep package path %q, does not match %q", pkgpath, path)
		return pkgpath
	}
	return func(t xr.Type) string {
		return types.TypeString(t.GoType(), qualifier)
	}
}

func (ir *Interp) ShowPackage(name string) {
	if len(name) != 0 {
		ir.ShowImportedPackage(name)
		return
	}
	// show current package and its outer scopes
	stack := make([]*Interp, 0)
	interp := ir
	for {
		stack = append(stack, interp)
		c := interp.Comp
		env := interp.env
		for i := 0; i < c.UpCost && env != nil; i++ {
			env = env.Outer
		}
		c = c.Outer
		if env == nil || c == nil {
			break
		}
		interp = &Interp{c, env}
	}
	for i := len(stack) - 1; i >= 0; i-- {
		stack[i].ShowAsPackage()
	}
}

func (ir *Interp) ShowAsPackage() {
	c := ir.Comp
	env := ir.PrepareEnv()
	out := c.Globals.Stdout
	stringer := typestringer(c.Path)
	if binds := c.Binds; len(binds) > 0 {
		output.ShowPackageHeader(out, c.Name, c.Path, "binds")

		keys := make([]string, len(binds))
		i := 0
		for k := range binds {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		for _, k := range keys {
			if bind := binds[k]; bind != nil {
				v := bind.RuntimeValue(env)
				showValue(out, k, v, bind.Type, stringer)
			}
		}
		fmt.Fprintln(out)
	}
	showTypes(out, c.Name, c.Path, c.Types, stringer)
}

func (ir *Interp) ShowImportedPackage(name string) {
	var imp *Import
	var ok bool
	if bind := ir.Comp.Binds[name]; bind != nil && bind.Const() && bind.Type != nil && bind.Type.ReflectType() == rtypeOfPtrImport {
		imp, ok = bind.Value.(*Import)
	}
	if !ok {
		ir.Comp.Warnf("not an imported package: %q", name)
		return
	}
	imp.Show(ir.Comp.CompGlobals)
}

func (imp *Import) Show(g *CompGlobals) {
	stringer := typestringer(imp.Path)
	out := g.Stdout
	if binds := imp.Binds; len(binds) > 0 {
		output.ShowPackageHeader(out, imp.Name, imp.Path, "binds")

		keys := make([]string, len(binds))
		i := 0
		for k := range binds {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		env := imp.env
		for _, k := range keys {
			bind := imp.Binds[k]
			v := bind.RuntimeValue(env)
			showValue(out, k, v, bind.Type, stringer)
		}
		fmt.Fprintln(out)
	}
	showTypes(out, imp.Name, imp.Path, imp.Types, stringer)
}

func showTypes(out io.Writer, name string, path string, types map[string]xr.Type, stringer func(xr.Type) string) {
	if len(types) > 0 {
		output.ShowPackageHeader(out, name, path, "types")

		keys := make([]string, len(types))
		i := 0
		for k := range types {
			keys[i] = k
			i++
		}
		sort.Strings(keys)
		for _, k := range keys {
			t := types[k]
			if t != nil {
				showType(out, k, t, stringer)
			}
		}
		fmt.Fprintln(out)
	}
}

const spaces15 = "               "

func showType(out io.Writer, name string, t xr.Type, stringer func(xr.Type) string) {
	n := len(name) & 15
	fmt.Fprintf(out, "%s%s = %v\t// %v\n", name, spaces15[n:], stringer(t), t.Kind())
}

func showValue(out io.Writer, name string, v r.Value, t xr.Type, stringer func(xr.Type) string) {
	n := len(name) & 15
	fmt.Fprintf(out, "%s%s = %v\t// %s\n", name, spaces15[n:], valueString(v, 0), stringer(t))
}

// convert a reflect.Value to string, intercepting any panic
func valueString(v r.Value, depth int) (s string) {
	ok := false
	defer func() {
		if !ok {
			recover()
			s = valueString2(v, depth)
		}
	}()
	if !v.IsValid() || v == base.None {
		s = "nil"
	} else {
		s = fmt.Sprintf("%v", v)
	}
	ok = true
	return s
}

func valueString2(v r.Value, depth int) (s string) {
	ok := false
	defer func() {
		if !ok {
			err := recover()
			if depth == 0 {
				s = "(error printing value: " + valueString(r.ValueOf(err), depth+1) + ")"
			} else {
				s = "(error printing error)"
			}
		}
	}()
	s = fmt.Sprintf("%#v", v)
	ok = true
	return s
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"html/template"
	"strings"
	"github.com/layeh/gumble/gumble_ffmpeg"
	"github.com/layeh/gumble/gumble"
	"github.com/layeh/gumble/gumbleutil"
	"encoding/gob"
	"flag"
)
const helpTemplate = `
Gumblebot Help

       Soundboard Commands:

 sbon to enable soundboard, sboff to disable soundboard

		{{range $key, $value := .}}

            {{$key}}

        {{end}}

`

const datafile = "data"

type SoundboardUser struct {
	SoundboardEnabled bool
	SoundboardVolume float64
	WelcomeSound string
}

var soundboard_users map[string]SoundboardUser

func send_usage(client *gumble.Client, soundboard map[string]string) {
	var buffer bytes.Buffer

	outTemplate, err := template.New("help").Parse(helpTemplate)
	if err != nil {
		panic(err)
	}

	err = outTemplate.Execute(&buffer, soundboard )
	if err != nil {
		panic(err);
	}
	message := gumble.TextMessage{
		Channels: []*gumble.Channel{
			client.Self.Channel,
		},
		Message: buffer.String(),
	}
	client.Send(&message)
}
func decode_users() {
	iobuffer, err := ioutil.ReadFile(datafile)
	if err != nil {
		fmt.Println(err)
		return
	}
	buffer := bytes.NewBuffer(iobuffer)
	dec := gob.NewDecoder(buffer)

	err = dec.Decode(&soundboard_users)
	if err != nil {
		panic(err)
	}
}
func encode_users() {
	var buffer bytes.Buffer
	enc := gob.NewEncoder(&buffer)
	err := enc.Encode(soundboard_users)
	if err != nil {
		panic(err)
	}
	err = ioutil.WriteFile(datafile, buffer.Bytes(), 0755)
	if err != nil {
		panic(err)
	}
}
func update_users(client *gumble.Client) {
	for _, user := range client.Users {
		if _, ok := soundboard_users[user.Name]; ok {
			continue
		}
		soundboard_users[user.Name] = SoundboardUser{false, 0.5, ""}
		encode_users()
	}
}
func init() {
	soundboard_users = make(map[string]SoundboardUser)

	decode_users()
}

func main() {
	var sounds_dir = flag.String("sounds", "sounds", "directory where soundboard files are located")
	var volume = flag.Float64("volume", 0.25, "soundboard volume from 0 to 1")
	var stream *gumble_ffmpeg.Stream
	soundboard := make(map[string]string)

	// Populate soundboard with files in $pwd/sounds/
	files, err := ioutil.ReadDir(*sounds_dir)
	if err != nil  {
		fmt.Println(err)
		return
	}
	for _, f := range files {
		key := f.Name()
		if filepath.Ext(key) == ".mp3" || filepath.Ext(key) == ".ogg" || filepath.Ext(key) == ".wav" {
			value, _ := filepath.Abs(filepath.Join(*sounds_dir, key))
			soundboard[key] = value
		}
	}

	var gumbleclient *gumble.Client

	gumbleutil.Main(func(client *gumble.Client) {
		stream, _ = gumble_ffmpeg.New(client)
		stream.Volume = float32(*volume)
		client.Attach(gumbleutil.AutoBitrate)
		gumbleclient = client
	}, gumbleutil.Listener{
		Connect: func(e *gumble.ConnectEvent) {
			fmt.Printf("Connected!\n")
			update_users(gumbleclient)
		},
		TextMessage: func(e *gumble.TextMessageEvent) {
			if e.Sender == nil {
				return
			}
			if e.Message == "stop" {
				stream.Stop()
			}
			if e.Message == "help" {
				go send_usage(gumbleclient, soundboard)
			}
			if e.Message == "sboff" {
				u := soundboard_users[e.Sender.Name]
				u.SoundboardEnabled = false
				soundboard_users[e.Sender.Name] = u
				encode_users()
			}
			if e.Message == "sbon" {
				u := soundboard_users[e.Sender.Name]
				u.SoundboardEnabled = true
				soundboard_users[e.Sender.Name] = u
				encode_users()
			}
			for key, value := range soundboard {
				if strings.Index(key, e.Message) == 0 {
					vtarget := &gumble.VoiceTarget{}
					vtarget.ID = 1
					for username, sb := range soundboard_users {
						userstruct := gumbleclient.Users.Find(username)
						if userstruct != nil && sb.SoundboardEnabled == true {
							vtarget.AddUser(userstruct)
						}
					}
					stream.Stop()
					gumbleclient.Send(vtarget)
					gumbleclient.VoiceTarget = vtarget
					stream.Play(value)
				}
			}
		},
		UserChange: func(e *gumble.UserChangeEvent) {
			update_users(gumbleclient)
		},
	})

}

<commit_msg>added and implemented Soundboard type<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"html/template"
	"strings"
	"github.com/layeh/gumble/gumble_ffmpeg"
	"github.com/layeh/gumble/gumble"
	"github.com/layeh/gumble/gumbleutil"
	"encoding/gob"
	"flag"
)
const helpTemplate = `
Gumblebot Help

       Soundboard Commands:

 sbon to enable soundboard, sboff to disable soundboard

		{{range $key, $value := .}}

            {{$key}}

        {{end}}

`

const datafile = "data"

type SoundboardUser struct {
	SoundboardEnabled bool
	SoundboardVolume float64
	WelcomeSound string
}
type Soundboard struct {
	Users map[string]SoundboardUser
	sounds map[string]string
}
func (s *Soundboard) LoadSounds(path string) {
	s.sounds = make(map[string]string)
	files,err := ioutil.ReadDir(path)
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, f := range files {
		key := f.Name()
		if filepath.Ext(key) == ".mp3" || filepath.Ext(key) == ".ogg" || filepath.Ext(key) == ".wav" {
			value, _ := filepath.Abs(filepath.Join(path, key))
			s.sounds[key] = value
		}
	}
}
func (s *Soundboard) LoadUsers(datapath string) {
	iobuffer, err := ioutil.ReadFile(datapath)
	if err != nil {
		fmt.Println(err)
		return
	}
	buffer := bytes.NewBuffer(iobuffer)
	dec := gob.NewDecoder(buffer)
	err = dec.Decode(&s.Users)
	if err != nil {
		panic(err)
	}
}
func (s *Soundboard) SaveUsers(datapath string) {
	var buffer bytes.Buffer
	enc := gob.NewEncoder(&buffer)
	err := enc.Encode(s.Users)
	if err != nil {
		panic(err)
	}
	err = ioutil.WriteFile(datapath, buffer.Bytes(), 0755)
	if err != nil {
		panic(err)
	}
}
func (s *Soundboard) UpdateUsers(client *gumble.Client) {
	for _, user := range client.Users {
		if _, ok := s.Users[user.Name]; ok {
			continue
		}
		s.Users[user.Name] = SoundboardUser{false, 0.5, ""}
	}
}
func (s *Soundboard) Play(client *gumble.Client, stream *gumble_ffmpeg.Stream, sound string)  {
	for key, value := range s.sounds {
		if strings.Index(key, sound) == 0 {
			vtarget := &gumble.VoiceTarget{}
			vtarget.ID = 1
			for username, sb := range s.Users {
				userstruct := client.Users.Find(username)
				if userstruct != nil && sb.SoundboardEnabled == true {
					vtarget.AddUser(userstruct)
				}
			}
			stream.Stop()
			client.Send(vtarget)
			client.VoiceTarget = vtarget
			stream.Play(value)
		}
	}
}

func send_usage(client *gumble.Client, soundboard map[string]string) {
	var buffer bytes.Buffer

	outTemplate, err := template.New("help").Parse(helpTemplate)
	if err != nil {
		panic(err)
	}

	err = outTemplate.Execute(&buffer, soundboard )
	if err != nil {
		panic(err);
	}
	message := gumble.TextMessage{
		Channels: []*gumble.Channel{
			client.Self.Channel,
		},
		Message: buffer.String(),
	}
	client.Send(&message)
}

func main() {
	var sounds_dir = flag.String("sounds", "sounds", "directory where soundboard files are located")
	var volume = flag.Float64("volume", 0.25, "soundboard volume from 0 to 1")
	var stream *gumble_ffmpeg.Stream

	var soundboard Soundboard
	var gumbleclient *gumble.Client

	soundboard.LoadUsers(datafile)
	soundboard.LoadSounds(*sounds_dir)

	gumbleutil.Main(func(client *gumble.Client) {
		stream, _ = gumble_ffmpeg.New(client)
		stream.Volume = float32(*volume)
		client.Attach(gumbleutil.AutoBitrate)
		gumbleclient = client
	}, gumbleutil.Listener{
		Connect: func(e *gumble.ConnectEvent) {
			fmt.Printf("Connected!\n")
			soundboard.UpdateUsers(gumbleclient)
			soundboard.SaveUsers(datafile)
		},
		TextMessage: func(e *gumble.TextMessageEvent) {
			if e.Sender == nil {
				return
			}
			if e.Message == "stop" {
				stream.Stop()
			}
			if e.Message == "help" {
				go send_usage(gumbleclient, soundboard.sounds)
			}
			if e.Message == "sboff" {
				u := soundboard.Users[e.Sender.Name]
				u.SoundboardEnabled = false
				soundboard.Users[e.Sender.Name] = u
				soundboard.SaveUsers(datafile)
			}
			if e.Message == "sbon" {
				u := soundboard.Users[e.Sender.Name]
				u.SoundboardEnabled = true
				soundboard.Users[e.Sender.Name] = u
				soundboard.SaveUsers(datafile)
			}
			soundboard.Play(gumbleclient, stream, e.Message)
		},
		UserChange: func(e *gumble.UserChangeEvent) {
			soundboard.UpdateUsers(gumbleclient)
			soundboard.SaveUsers(datafile)
		},
	})

}

<|endoftext|>


<commit_before>package kite

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"

	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just like RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it during app initializations. After the registration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

func (k *Kite) getKontrolPath(path string) string {
	heartbeatURL := k.Config.KontrolURL + "/" + path
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/" + path
	}

	return heartbeatURL
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	registerURL := k.getKontrolPath("register")
	client := &http.Client{Timeout: time.Second * 10}

	args := protocol.RegisterArgs{
		URL:  kiteURL.String(),
		Kite: k.Kite(),
		Auth: &protocol.Auth{
			Type: "kiteKey",
			Key:  k.Config.KiteKey,
		},
	}

	data, err := json.Marshal(&args)
	if err != nil {
		return nil, err
	}

	resp, err := client.Post(registerURL, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var rr protocol.RegisterResult
	dec := json.NewDecoder(resp.Body)

	if err := dec.Decode(&rr); err != nil {
		return nil, err
	}

	if rr.Error != "" {
		return nil, errors.New(rr.Error)
	}

	if rr.HeartbeatInterval == 0 {
		return nil, errors.New("heartbeal interval cannot be zero")
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	heartbeatURL := k.getKontrolPath("heartbeat")

	k.Log.Debug("Sending heartbeat to: %s", heartbeatURL)

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	client := &http.Client{
		Timeout: time.Second * 10,
	}

	heartbeatFunc := func() error {
		k.Log.Debug("Sending heartbeat to %s", u.String())

		resp, err := client.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Debug("Heartbeat response received '%s'", strings.TrimSpace(string(body)))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", strings.TrimSpace(string(body)))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<commit_msg>kite: add cookie jar implementation for kontrol clients<commit_after>package kite

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strings"
	"time"

	"github.com/koding/kite/protocol"
)

type kontrolFunc func(*Client) error

// the implementation of New() doesn't have any error to be returned yet it
// returns, so it's totally safe to neglect the error
var cookieJar, _ = cookiejar.New(nil)

var defaultClient = &http.Client{
	Timeout: time.Second * 10,
	// add this so we can make use of load balancer's sticky session features,
	// such as AWS ELB
	Jar: cookieJar,
}

// kontrolFunc setups and prepares a kontrol instance. It connects to
// kontrol and providers a way to call the given function in that connected
// kontrol environment. This method is called internally whenever a kontrol
// client specific action is taking (getKites, getToken, register). The main
// reason for having this is doing the call and close the connection
// immediately, so there will be no persistent connection.
func (k *Kite) kontrolFunc(fn kontrolFunc) error {
	if k.Config.KontrolURL == "" {
		return errors.New("no kontrol URL given in config")
	}

	client := k.NewClient(k.Config.KontrolURL)

	client.Kite = protocol.Kite{Name: "kontrol"} // for logging purposes
	client.Auth = &Auth{
		Type: "kiteKey",
		Key:  k.Config.KiteKey,
	}

	if err := client.Dial(); err != nil {
		return err
	}
	defer client.Close()

	return fn(client)
}

// RegisterHTTPForever is just like RegisterHTTP however it first tries to
// register forever until a response from kontrol is received. It's useful to
// use it during app initializations. After the registration a reconnect is
// automatically handled inside the RegisterHTTP method.
func (k *Kite) RegisterHTTPForever(kiteURL *url.URL) {
	interval := time.NewTicker(kontrolRetryDuration)
	defer interval.Stop()

	_, err := k.RegisterHTTP(kiteURL)
	if err == nil {
		return
	}

	for _ = range interval.C {
		_, err := k.RegisterHTTP(kiteURL)
		if err == nil {
			return
		}

		k.Log.Error("Cannot register to Kontrol: %s Will retry after %d seconds",
			err, kontrolRetryDuration/time.Second)

	}
}

func (k *Kite) getKontrolPath(path string) string {
	heartbeatURL := k.Config.KontrolURL + "/" + path
	if strings.HasSuffix(k.Config.KontrolURL, "/kite") {
		heartbeatURL = strings.TrimSuffix(k.Config.KontrolURL, "/kite") + "/" + path
	}

	return heartbeatURL
}

// RegisterHTTP registers current Kite to Kontrol. After registration other Kites
// can find it via GetKites() or WatchKites() method. It registers again if
// connection to kontrol is lost.
func (k *Kite) RegisterHTTP(kiteURL *url.URL) (*registerResult, error) {
	registerURL := k.getKontrolPath("register")

	args := protocol.RegisterArgs{
		URL:  kiteURL.String(),
		Kite: k.Kite(),
		Auth: &protocol.Auth{
			Type: "kiteKey",
			Key:  k.Config.KiteKey,
		},
	}

	data, err := json.Marshal(&args)
	if err != nil {
		return nil, err
	}

	resp, err := defaultClient.Post(registerURL, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var rr protocol.RegisterResult
	dec := json.NewDecoder(resp.Body)

	if err := dec.Decode(&rr); err != nil {
		return nil, err
	}

	if rr.Error != "" {
		return nil, errors.New(rr.Error)
	}

	if rr.HeartbeatInterval == 0 {
		return nil, errors.New("heartbeal interval cannot be zero")
	}

	parsed, err := url.Parse(rr.URL)
	if err != nil {
		k.Log.Error("Cannot parse registered URL: %s", err.Error())
	}

	heartbeat := time.Duration(rr.HeartbeatInterval) * time.Second

	k.Log.Info("Registered (via HTTP) with URL: '%s' and HeartBeat interval: '%s'",
		rr.URL, heartbeat)

	go k.sendHeartbeats(heartbeat, kiteURL)

	return &registerResult{parsed}, nil
}

func (k *Kite) sendHeartbeats(interval time.Duration, kiteURL *url.URL) {
	tick := time.NewTicker(interval)

	heartbeatURL := k.getKontrolPath("heartbeat")

	k.Log.Debug("Sending heartbeat to: %s", heartbeatURL)

	u, err := url.Parse(heartbeatURL)
	if err != nil {
		k.Log.Fatal("HeartbeatURL is malformed: %s", err)
	}

	q := u.Query()
	q.Set("id", k.Id)
	u.RawQuery = q.Encode()

	errRegisterAgain := errors.New("register again")

	client := &http.Client{
		Timeout: time.Second * 10,
	}

	heartbeatFunc := func() error {
		k.Log.Debug("Sending heartbeat to %s", u.String())

		resp, err := client.Get(u.String())
		if err != nil {
			return err
		}
		defer resp.Body.Close()

		// we are just receving small size strings such as "pong",
		// "registeragain" so it's totally normal to consume the whole response
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err
		}

		k.Log.Debug("Heartbeat response received '%s'", strings.TrimSpace(string(body)))

		switch string(body) {
		case "pong":
			return nil
		case "registeragain":
			tick.Stop()
			k.RegisterHTTP(kiteURL)
			return errRegisterAgain
		}

		return fmt.Errorf("malformed heartbeat response %v", strings.TrimSpace(string(body)))
	}

	for _ = range tick.C {
		err := heartbeatFunc()
		if err == errRegisterAgain {
			return // return so we don't run forever
		}

		if err != nil {
			k.Log.Error("couldn't sent hearbeat: %s", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	// Incremental Increasing TImeout
	StateRunningTimeout                = 5 * time.Minute  // Time from cluster ready to nodes being created
	RegisteredTimeout                  = 15 * time.Minute // Time from node created to registered
	StateSchedulableTimeout            = 1 * time.Minute  // Time from registered to schedulable
	StateHealthyTimeout                = 1 * time.Minute
	ConditionRouteBrokenTimeout        = 1 * time.Minute
	ConditionNetworkUnavailableTimeout = 1 * time.Minute
	ConditionReadyTimeout              = 1 * time.Minute
)

type NodeTests struct {
	Kubernetes        *framework.Kubernetes
	Kubernikus        *framework.Kubernikus
	OpenStack         *framework.OpenStack
	ExpectedNodeCount int
	KlusterName       string
}

func (k *NodeTests) Run(t *testing.T) {
	_ = t.Run("Created", k.StateRunning) &&
		t.Run("Registered", k.Registered) &&
		//t.Run("LatestStableContainerLinux", k.LatestStableContainerLinux) &&
		t.Run("Schedulable", k.StateSchedulable) &&
		t.Run("NetworkUnavailable", k.ConditionNetworkUnavailable) &&
		t.Run("Healthy", k.StateHealthy) &&
		t.Run("Ready", k.ConditionReady) &&
		t.Run("Labeled", k.Labeled) &&
		t.Run("Sufficient", k.Sufficient) &&
		t.Run("SameBuildingBlock", k.SameBuildingBlock)
}

func (k *NodeTests) StateRunning(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Running }, StateRunningTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) StateSchedulable(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Schedulable }, StateSchedulableTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) StateHealthy(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Healthy }, StateHealthyTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) ConditionNetworkUnavailable(t *testing.T) {
	count, err := k.checkCondition(t, v1.NodeNetworkUnavailable, v1.ConditionFalse, ConditionNetworkUnavailableTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) ConditionReady(t *testing.T) {
	count, err := k.checkCondition(t, v1.NodeReady, v1.ConditionTrue, ConditionReadyTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) Labeled(t *testing.T) {
	nodeList, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	require.NoError(t, err, "There must be no error while listing the kluster's nodes")

	for _, node := range nodeList.Items {
		assert.Contains(t, node.Labels, "ccloud.sap.com/nodepool", "node %s is missing the ccloud.sap.com/nodepool label", node.Name)
	}

}

func (k *NodeTests) Registered(t *testing.T) {
	count := 0
	err := wait.PollImmediate(framework.Poll, RegisteredTimeout,
		func() (bool, error) {
			nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
			if err != nil {
				return false, fmt.Errorf("Failed to list nodes: %v", err)
			}
			count = len(nodes.Items)

			return count >= k.ExpectedNodeCount, nil
		})

	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k NodeTests) LatestStableContainerLinux(t *testing.T) {

	nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	if !assert.NoError(t, err) {
		return
	}
	resp, err := http.Get("https://stable.release.core-os.net/amd64-usr/current/version.txt")
	if !assert.NoError(t, err) {
		return
	}
	if !assert.Equal(t, 200, resp.StatusCode) {
		return
	}

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		keyval := strings.Split(scanner.Text(), "=")
		if len(keyval) == 2 && keyval[0] == "COREOS_VERSION" {
			for _, node := range nodes.Items {
				assert.Contains(t, node.Status.NodeInfo.OSImage, keyval[1], "Node %s is not on latest version", node.Name)
			}
			return
		}
	}
	t.Error("Failed to detect latest stable Container Linux version")

}

func (k *NodeTests) Sufficient(t *testing.T) {
	nodeList, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	require.NoError(t, err, "There must be no error while listing the kluster's nodes")
	require.Equal(t, len(nodeList.Items), SmokeTestNodeCount, "There must be exactly %d nodes", SmokeTestNodeCount)
}

type poolCount func(models.NodePoolInfo) int64

func (k *NodeTests) checkState(t *testing.T, fn poolCount, timeout time.Duration) (int, error) {
	count := 0
	err := wait.PollImmediate(framework.Poll, StateRunningTimeout,
		func() (done bool, err error) {
			cluster, err := k.Kubernikus.Client.Operations.ShowCluster(
				operations.NewShowClusterParams().WithName(k.KlusterName),
				k.Kubernikus.AuthInfo,
			)
			if err != nil {
				return false, err
			}

			count = int(fn(cluster.Payload.Status.NodePools[0]))
			return count >= k.ExpectedNodeCount, nil
		})

	return count, err
}

func (k *NodeTests) checkCondition(t *testing.T, conditionType v1.NodeConditionType, expectedStatus v1.ConditionStatus, timeout time.Duration) (int, error) {
	count := 0
	err := wait.PollImmediate(framework.Poll, timeout,
		func() (bool, error) {
			nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
			if err != nil {
				return false, fmt.Errorf("Failed to list nodes: %v", err)
			}

			count = 0
			for _, node := range nodes.Items {
				for _, condition := range node.Status.Conditions {
					if condition.Type == conditionType {
						if condition.Status == expectedStatus {
							count++
						}
						break
					}
				}
			}

			return count >= k.ExpectedNodeCount, nil
		})

	return count, err
}

func (k *NodeTests) SameBuildingBlock(t *testing.T) {
	if k.ExpectedNodeCount < 2 {
		return
	}

	computeClient, err := openstack.NewComputeV2(k.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	project, err := tokens.Get(k.OpenStack.Identity, k.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	serversListOpts := servers.ListOpts{
		Name:     "e2e-",
		TenantID: project.ID,
	}

	allPages, err := servers.List(computeClient, serversListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing all servers")

	var s []struct {
		BuildingBlock string `json:"OS-EXT-SRV-ATTR:host"`
	}
	err = servers.ExtractServersInto(allPages, &s)
	require.NoError(t, err, "There should be no error extracting server info")

	bb := ""
	for _, bbs := range s {
		require.NotEmpty(t, bbs.BuildingBlock, "Node building block should not be empty")
		if bb == "" {
			bb = string(bbs.BuildingBlock)
		} else {
			require.Equal(t, bb, bbs.BuildingBlock, "Nodes should be on the same building block")
		}
	}
}
<commit_msg>Delay check for current core os version in e2e tests<commit_after>package main

import (
	"bufio"
	"fmt"
	"net/http"
	"strings"
	"testing"
	"time"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"

	"github.com/sapcc/kubernikus/pkg/api/client/operations"
	"github.com/sapcc/kubernikus/pkg/api/models"
	"github.com/sapcc/kubernikus/test/e2e/framework"
)

const (
	// Incremental Increasing TImeout
	StateRunningTimeout                = 5 * time.Minute  // Time from cluster ready to nodes being created
	RegisteredTimeout                  = 15 * time.Minute // Time from node created to registered
	StateSchedulableTimeout            = 1 * time.Minute  // Time from registered to schedulable
	StateHealthyTimeout                = 1 * time.Minute
	ConditionRouteBrokenTimeout        = 1 * time.Minute
	ConditionNetworkUnavailableTimeout = 1 * time.Minute
	ConditionReadyTimeout              = 1 * time.Minute
)

type NodeTests struct {
	Kubernetes        *framework.Kubernetes
	Kubernikus        *framework.Kubernikus
	OpenStack         *framework.OpenStack
	ExpectedNodeCount int
	KlusterName       string
}

func (k *NodeTests) Run(t *testing.T) {
	_ = t.Run("Created", k.StateRunning) &&
		t.Run("Registered", k.Registered) &&
		t.Run("LatestStableContainerLinux", k.LatestStableContainerLinux) &&
		t.Run("Schedulable", k.StateSchedulable) &&
		t.Run("NetworkUnavailable", k.ConditionNetworkUnavailable) &&
		t.Run("Healthy", k.StateHealthy) &&
		t.Run("Ready", k.ConditionReady) &&
		t.Run("Labeled", k.Labeled) &&
		t.Run("Sufficient", k.Sufficient) &&
		t.Run("SameBuildingBlock", k.SameBuildingBlock)
}

func (k *NodeTests) StateRunning(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Running }, StateRunningTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) StateSchedulable(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Schedulable }, StateSchedulableTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) StateHealthy(t *testing.T) {
	count, err := k.checkState(t, func(pool models.NodePoolInfo) int64 { return pool.Healthy }, StateHealthyTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) ConditionNetworkUnavailable(t *testing.T) {
	count, err := k.checkCondition(t, v1.NodeNetworkUnavailable, v1.ConditionFalse, ConditionNetworkUnavailableTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) ConditionReady(t *testing.T) {
	count, err := k.checkCondition(t, v1.NodeReady, v1.ConditionTrue, ConditionReadyTimeout)
	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k *NodeTests) Labeled(t *testing.T) {
	nodeList, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	require.NoError(t, err, "There must be no error while listing the kluster's nodes")

	for _, node := range nodeList.Items {
		assert.Contains(t, node.Labels, "ccloud.sap.com/nodepool", "node %s is missing the ccloud.sap.com/nodepool label", node.Name)
	}

}

func (k *NodeTests) Registered(t *testing.T) {
	count := 0
	err := wait.PollImmediate(framework.Poll, RegisteredTimeout,
		func() (bool, error) {
			nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
			if err != nil {
				return false, fmt.Errorf("Failed to list nodes: %v", err)
			}
			count = len(nodes.Items)

			return count >= k.ExpectedNodeCount, nil
		})

	assert.NoError(t, err)
	assert.Equal(t, k.ExpectedNodeCount, count)
}

func (k NodeTests) LatestStableContainerLinux(t *testing.T) {
	nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	if !assert.NoError(t, err) {
		return
	}
	resp, err := http.Get("https://stable.release.core-os.net/amd64-usr/current/version.txt")
	if !assert.NoError(t, err) {
		return
	}
	if !assert.Equal(t, 200, resp.StatusCode) {
		return
	}

	version := ""
	var date time.Time
	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		keyval := strings.Split(scanner.Text(), "=")

		if len(keyval) == 2 && keyval[0] == "COREOS_VERSION" {
			version = keyval[1]
			if !assert.NotEmpty(t, version, "Failed to detect latest stable Container Linux version") {
				return
			}
		}

		if len(keyval) == 2 && keyval[0] == "COREOS_BUILD_ID" {
			date, err = time.Parse("2006-01-02", keyval[1][1:11])
			if !assert.NoError(t, err) {
				return
			}
			if !assert.NotEmpty(t, date, "Could not get release date") {
				return
			}
			// check if release is at least 72 old, otherwise image might not be up-to-date
			if time.Since(date).Hours() < 72 {
				return
			}
		}
	}

	for _, node := range nodes.Items {
		assert.Contains(t, node.Status.NodeInfo.OSImage, version, "Node %s is not on latest version", node.Name)
	}
}

func (k *NodeTests) Sufficient(t *testing.T) {
	nodeList, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
	require.NoError(t, err, "There must be no error while listing the kluster's nodes")
	require.Equal(t, len(nodeList.Items), SmokeTestNodeCount, "There must be exactly %d nodes", SmokeTestNodeCount)
}

type poolCount func(models.NodePoolInfo) int64

func (k *NodeTests) checkState(t *testing.T, fn poolCount, timeout time.Duration) (int, error) {
	count := 0
	err := wait.PollImmediate(framework.Poll, StateRunningTimeout,
		func() (done bool, err error) {
			cluster, err := k.Kubernikus.Client.Operations.ShowCluster(
				operations.NewShowClusterParams().WithName(k.KlusterName),
				k.Kubernikus.AuthInfo,
			)
			if err != nil {
				return false, err
			}

			count = int(fn(cluster.Payload.Status.NodePools[0]))
			return count >= k.ExpectedNodeCount, nil
		})

	return count, err
}

func (k *NodeTests) checkCondition(t *testing.T, conditionType v1.NodeConditionType, expectedStatus v1.ConditionStatus, timeout time.Duration) (int, error) {
	count := 0
	err := wait.PollImmediate(framework.Poll, timeout,
		func() (bool, error) {
			nodes, err := k.Kubernetes.ClientSet.CoreV1().Nodes().List(meta_v1.ListOptions{})
			if err != nil {
				return false, fmt.Errorf("Failed to list nodes: %v", err)
			}

			count = 0
			for _, node := range nodes.Items {
				for _, condition := range node.Status.Conditions {
					if condition.Type == conditionType {
						if condition.Status == expectedStatus {
							count++
						}
						break
					}
				}
			}

			return count >= k.ExpectedNodeCount, nil
		})

	return count, err
}

func (k *NodeTests) SameBuildingBlock(t *testing.T) {
	if k.ExpectedNodeCount < 2 {
		return
	}

	computeClient, err := openstack.NewComputeV2(k.OpenStack.Provider, gophercloud.EndpointOpts{})
	require.NoError(t, err, "There should be no error creating compute client")

	project, err := tokens.Get(k.OpenStack.Identity, k.OpenStack.Provider.Token()).ExtractProject()
	require.NoError(t, err, "There should be no error while extracting the project")

	serversListOpts := servers.ListOpts{
		Name:     "e2e-",
		TenantID: project.ID,
	}

	allPages, err := servers.List(computeClient, serversListOpts).AllPages()
	require.NoError(t, err, "There should be no error while listing all servers")

	var s []struct {
		BuildingBlock string `json:"OS-EXT-SRV-ATTR:host"`
	}
	err = servers.ExtractServersInto(allPages, &s)
	require.NoError(t, err, "There should be no error extracting server info")

	bb := ""
	for _, bbs := range s {
		require.NotEmpty(t, bbs.BuildingBlock, "Node building block should not be empty")
		if bb == "" {
			bb = string(bbs.BuildingBlock)
		} else {
			require.Equal(t, bb, bbs.BuildingBlock, "Nodes should be on the same building block")
		}
	}
}
<|endoftext|>