<commit_before>package yang

import (
	"fmt"
	"os"

	"github.com/openconfig/goyang/pkg/yang"
	"github.com/oshothebig/pbast"
)

var builtinMap = map[yang.TypeKind]pbast.Type{
	yang.Yint8:   pbast.Int32,
	yang.Yint16:  pbast.Int32,
	yang.Yint32:  pbast.Int32,
	yang.Yint64:  pbast.Int64,
	yang.Yuint8:  pbast.UInt32,
	yang.Yuint16: pbast.UInt32,
	yang.Yuint32: pbast.UInt32,
	yang.Yuint64: pbast.UInt64,
	yang.Ystring: pbast.String,
	yang.Ybool:   pbast.Bool,
	yang.Ybinary: pbast.Bytes,
}

var builtinTypes = stringSet{
	"int8":                struct{}{},
	"int16":               struct{}{},
	"int32":               struct{}{},
	"int64":               struct{}{},
	"uint8":               struct{}{},
	"uint16":              struct{}{},
	"unit32":              struct{}{},
	"uint64":              struct{}{},
	"string":              struct{}{},
	"boolean":             struct{}{},
	"enumeration":         struct{}{},
	"bits":                struct{}{},
	"binary":              struct{}{},
	"leafref":             struct{}{},
	"identityref":         struct{}{},
	"empty":               struct{}{},
	"union":               struct{}{},
	"instance-identifier": struct{}{},
}

type transformer struct {
	topScope           *scope
	decimal64          *pbast.Message
	leafRef            *pbast.Message
	identityRef        *pbast.Message
	instanceIdentifier *pbast.Message
	emptyNeeded        bool
}

// e must be YANG module
func Transform(e *yang.Entry) *pbast.File {
	if _, ok := e.Node.(*yang.Module); !ok {
		return nil
	}

	t := &transformer{
		topScope: newScope(),
	}

	return t.module(entry{e})
}

func (t *transformer) declare(m pbast.Type) {
	if err := t.topScope.addType(m); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func (t *transformer) reflectTo(f *pbast.File) {
	if typ := t.topScope.types[pbast.Empty.TypeName()]; typ != nil {
		f.AddImport(pbast.NewImport("google/protobuf/empty.proto"))
	}
	t.topScope.reflectTo(f)
}

func (t *transformer) module(e entry) *pbast.File {
	namespace := e.Namespace().Name
	f := pbast.NewFile(pbast.NewPackageWithElements(guessElements(namespace)))

	f.Comment = e.moduleComment()

	root := t.buildMessage("Root", e)
	// Clear Root messgage comment because it overlaps with
	// the file level comment being generated from module description too
	root.Comment = nil
	// Child nodes are enclosed with Root message
	f.AddMessage(root)

	// RPCs
	s := t.rpcs(e)
	f.AddService(s)

	// Notifications
	n := t.notifications(e)
	f.AddService(n)

	t.reflectTo(f)

	return f
}

func (t *transformer) rpcs(e entry) *pbast.Service {
	rpcs := e.rpcs()
	if len(rpcs) == 0 {
		return nil
	}

	s := pbast.NewService(CamelCase(e.Name) + "Service")
	for _, rpc := range rpcs {
		r := t.rpc(rpc)
		s.AddRPC(r)
	}

	return s
}

func (t *transformer) rpc(e entry) *pbast.RPC {
	method := CamelCase(e.Name)
	var in pbast.Type
	if e.RPC.Input == nil {
		in = pbast.Empty
	} else {
		in = t.buildMessage(method+"Request", entry{e.RPC.Input})
	}
	t.declare(in)

	var out pbast.Type
	if e.RPC.Output == nil {
		out = pbast.Empty
	} else {
		out = t.buildMessage(method+"Response", entry{e.RPC.Output})
	}
	t.declare(out)

	rpc := pbast.NewRPC(
		method,
		pbast.NewReturnType(in.TypeName()),
		pbast.NewReturnType(out.TypeName()),
	)
	rpc.Comment = e.genericComments()

	return rpc
}

func (t *transformer) notifications(e entry) *pbast.Service {
	notifications := e.notifications()
	if len(notifications) == 0 {
		return nil
	}

	s := pbast.NewService(CamelCase(e.Name + "Notification"))
	for _, notification := range notifications {
		n := t.notification(notification)
		n.Comment = notification.genericComments()
		s.AddRPC(n)
	}

	return s
}

func (t *transformer) notification(e entry) *pbast.RPC {
	const common = "Notification"
	method := CamelCase(e.Name)
	in := pbast.Empty
	t.declare(in)
	out := t.buildMessage(buildName(method, common, "Response"), e)
	t.declare(out)

	return pbast.NewRPC(method,
		pbast.NewReturnType(in.TypeName()),
		pbast.NewReturnType(out.TypeName()).SetStreamable(true))
}

func (t *transformer) buildMessage(name string, e entry) *pbast.Message {
	if e.Entry == nil {
		return nil
	}

	msg := &pbast.Message{
		Name:    name,
		Comment: e.genericComments(),
	}
	scope := newScope()
	for index, child := range e.children() {
		fieldNum := index + 1
		var field *pbast.MessageField
		switch {
		case child.IsLeaf(), child.IsLeafList():
			typ := t.leaf(child.Type, messageName(child))

			if needsInTopScope(typ) {
				t.declare(typ)
			} else {
				if err := scope.addType(typ); err != nil {
					fmt.Fprintln(os.Stderr, err)
				}
			}

			field = &pbast.MessageField{
				Repeated: child.IsLeafList(),
				Type:     typ.TypeName(),
				Name:     underscoreCase(child.Name),
				Index:    fieldNum,
				Comment:  child.genericComments(),
			}
		case child.IsContainer(), child.IsList(), child.IsChoice(), child.IsCase():
			field = t.directory(scope, child, fieldNum, child.IsList())
		}
		msg.AddField(field)
	}

	scope.reflectTo(msg)

	return msg
}

func (t *transformer) leaf(typ *yang.YangType, name string) pbast.Type {
	if needsCustomType(typ.Kind) {
		return t.customType(typ, CamelCase(name))
	}

	if isBuiltinType(typ.Name) {
		return t.mapBuiltinType(typ.Kind)
	}

	inner := t.mapBuiltinType(typ.Kind)
	msg := pbast.NewMessage(CamelCase(name)).
		AddField(pbast.NewMessageField(inner, "value", 1))
	if needsInTopScope(inner) {
		t.declare(inner)
	} else {
		msg.AddType(inner)
	}
	return msg
}

func messageName(e entry) string {
	if isBuiltinType(e.Type.Name) {
		return e.Name
	}

	return e.Type.Name
}

func needsInTopScope(t pbast.Type) bool {
	switch t {
	case decimal64, leafRef, identityRef, instanceIdentifier, pbast.Empty:
		return true
	default:
		return false
	}
}

func (t *transformer) customType(typ *yang.YangType, name string) pbast.Type {
	switch typ.Kind {
	case yang.Yenum:
		return t.customEnum(name, typ.Enum)
	case yang.Ybits:
		return t.customBits(name, typ.Bit)
	case yang.Yunion:
		return t.customUnion(name, typ.Type)
	default:
		return nil
	}
}

func isBuiltinType(name string) bool {
	if _, ok := yang.TypeKindFromName[name]; !ok {
		return false
	}
	return true
}

func needsCustomType(kind yang.TypeKind) bool {
	switch kind {
	case yang.Yenum, yang.Ybits, yang.Yunion:
		return true
	default:
		return false
	}
}

func (t *transformer) mapBuiltinType(kind yang.TypeKind) pbast.Type {
	switch kind {
	case yang.Yint8, yang.Yint16, yang.Yint32:
		return pbast.Int32
	case yang.Yint64:
		return pbast.Int64
	case yang.Yuint8, yang.Yuint16, yang.Yuint32:
		return pbast.UInt32
	case yang.Yuint64:
		return pbast.UInt64
	case yang.Ystring:
		return pbast.String
	case yang.Ybool:
		return pbast.Bool
	case yang.Ybinary:
		return pbast.Bytes
	case yang.Yleafref:
		return leafRef
	case yang.Yidentityref:
		return identityRef
	case yang.Yempty:
		return pbast.Empty
	case yang.YinstanceIdentifier:
		return instanceIdentifier
	case yang.Ydecimal64:
		return decimal64
	default:
		return nil
	}
}

func (t *transformer) customBits(name string, bits *yang.EnumType) *pbast.Message {
	msg := pbast.NewMessage(name)
	for i, n := range bits.Names() {
		v := 1 << uint(bits.Values()[i])
		msg.AddField(pbast.NewMessageField(pbast.Bool, n, v))
	}

	return msg
}

func (t *transformer) customEnum(name string, e *yang.EnumType) *pbast.Message {
	enum := pbast.NewEnum("Value")
	for _, v := range e.Values() {
		n := e.ValueMap()[v]
		enum.AddField(pbast.NewEnumField(constantName(n), int(v)))
	}
	msg := pbast.NewMessage(name).
		AddEnum(enum).
		AddField(pbast.NewMessageField(enum, "value", 1))

	return msg
}

func (t *transformer) customUnion(name string, types []*yang.YangType) *pbast.Message {
	scope := newScope()
	pbTypes := t.unionFields(types, nil, scope)

	oneof := pbast.NewOneOf("value")
	for i, typ := range pbTypes {
		oneof.AddField(pbast.NewOneOfField(typ, underscoreCase(typ.TypeName()), i+1))
	}

	msg := pbast.NewMessage(name).AddOneOf(oneof)
	scope.reflectTo(msg)

	return msg
}

func (t *transformer) unionFields(types []*yang.YangType, pbTypes []pbast.Type, scope *scope) []pbast.Type {
	for _, typ := range types {
		if typ.Kind == yang.Yunion {
			pbTypes = t.unionFields(typ.Type, pbTypes, scope)
			continue
		}

		pbtype := t.leaf(typ, typ.Name)
		if pbtype == nil {
			continue
		}

		pbTypes = append(pbTypes, pbtype)
		scope.addType(pbtype)
	}

	return pbTypes
}

func (t *transformer) directory(scope *scope, e entry, index int, repeated bool) *pbast.MessageField {
	fieldName := underscoreCase(e.Name)
	typeName := CamelCase(e.Name)

	inner := t.buildMessage(typeName, e)
	field := &pbast.MessageField{
		Repeated: repeated,
		Type:     inner.TypeName(),
		Name:     fieldName,
		Index:    index,
	}

	if err := scope.addType(inner); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	return field
}
<commit_msg>Remove unreferenced fields<commit_after>package yang

import (
	"fmt"
	"os"

	"github.com/openconfig/goyang/pkg/yang"
	"github.com/oshothebig/pbast"
)

var builtinMap = map[yang.TypeKind]pbast.Type{
	yang.Yint8:   pbast.Int32,
	yang.Yint16:  pbast.Int32,
	yang.Yint32:  pbast.Int32,
	yang.Yint64:  pbast.Int64,
	yang.Yuint8:  pbast.UInt32,
	yang.Yuint16: pbast.UInt32,
	yang.Yuint32: pbast.UInt32,
	yang.Yuint64: pbast.UInt64,
	yang.Ystring: pbast.String,
	yang.Ybool:   pbast.Bool,
	yang.Ybinary: pbast.Bytes,
}

var builtinTypes = stringSet{
	"int8":                struct{}{},
	"int16":               struct{}{},
	"int32":               struct{}{},
	"int64":               struct{}{},
	"uint8":               struct{}{},
	"uint16":              struct{}{},
	"unit32":              struct{}{},
	"uint64":              struct{}{},
	"string":              struct{}{},
	"boolean":             struct{}{},
	"enumeration":         struct{}{},
	"bits":                struct{}{},
	"binary":              struct{}{},
	"leafref":             struct{}{},
	"identityref":         struct{}{},
	"empty":               struct{}{},
	"union":               struct{}{},
	"instance-identifier": struct{}{},
}

type transformer struct {
	topScope *scope
}

// e must be YANG module
func Transform(e *yang.Entry) *pbast.File {
	if _, ok := e.Node.(*yang.Module); !ok {
		return nil
	}

	t := &transformer{
		topScope: newScope(),
	}

	return t.module(entry{e})
}

func (t *transformer) declare(m pbast.Type) {
	if err := t.topScope.addType(m); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}

func (t *transformer) reflectTo(f *pbast.File) {
	if typ := t.topScope.types[pbast.Empty.TypeName()]; typ != nil {
		f.AddImport(pbast.NewImport("google/protobuf/empty.proto"))
	}
	t.topScope.reflectTo(f)
}

func (t *transformer) module(e entry) *pbast.File {
	namespace := e.Namespace().Name
	f := pbast.NewFile(pbast.NewPackageWithElements(guessElements(namespace)))

	f.Comment = e.moduleComment()

	root := t.buildMessage("Root", e)
	// Clear Root messgage comment because it overlaps with
	// the file level comment being generated from module description too
	root.Comment = nil
	// Child nodes are enclosed with Root message
	f.AddMessage(root)

	// RPCs
	s := t.rpcs(e)
	f.AddService(s)

	// Notifications
	n := t.notifications(e)
	f.AddService(n)

	t.reflectTo(f)

	return f
}

func (t *transformer) rpcs(e entry) *pbast.Service {
	rpcs := e.rpcs()
	if len(rpcs) == 0 {
		return nil
	}

	s := pbast.NewService(CamelCase(e.Name) + "Service")
	for _, rpc := range rpcs {
		r := t.rpc(rpc)
		s.AddRPC(r)
	}

	return s
}

func (t *transformer) rpc(e entry) *pbast.RPC {
	method := CamelCase(e.Name)
	var in pbast.Type
	if e.RPC.Input == nil {
		in = pbast.Empty
	} else {
		in = t.buildMessage(method+"Request", entry{e.RPC.Input})
	}
	t.declare(in)

	var out pbast.Type
	if e.RPC.Output == nil {
		out = pbast.Empty
	} else {
		out = t.buildMessage(method+"Response", entry{e.RPC.Output})
	}
	t.declare(out)

	rpc := pbast.NewRPC(
		method,
		pbast.NewReturnType(in.TypeName()),
		pbast.NewReturnType(out.TypeName()),
	)
	rpc.Comment = e.genericComments()

	return rpc
}

func (t *transformer) notifications(e entry) *pbast.Service {
	notifications := e.notifications()
	if len(notifications) == 0 {
		return nil
	}

	s := pbast.NewService(CamelCase(e.Name + "Notification"))
	for _, notification := range notifications {
		n := t.notification(notification)
		n.Comment = notification.genericComments()
		s.AddRPC(n)
	}

	return s
}

func (t *transformer) notification(e entry) *pbast.RPC {
	const common = "Notification"
	method := CamelCase(e.Name)
	in := pbast.Empty
	t.declare(in)
	out := t.buildMessage(buildName(method, common, "Response"), e)
	t.declare(out)

	return pbast.NewRPC(method,
		pbast.NewReturnType(in.TypeName()),
		pbast.NewReturnType(out.TypeName()).SetStreamable(true))
}

func (t *transformer) buildMessage(name string, e entry) *pbast.Message {
	if e.Entry == nil {
		return nil
	}

	msg := &pbast.Message{
		Name:    name,
		Comment: e.genericComments(),
	}
	scope := newScope()
	for index, child := range e.children() {
		fieldNum := index + 1
		var field *pbast.MessageField
		switch {
		case child.IsLeaf(), child.IsLeafList():
			typ := t.leaf(child.Type, messageName(child))

			if needsInTopScope(typ) {
				t.declare(typ)
			} else {
				if err := scope.addType(typ); err != nil {
					fmt.Fprintln(os.Stderr, err)
				}
			}

			field = &pbast.MessageField{
				Repeated: child.IsLeafList(),
				Type:     typ.TypeName(),
				Name:     underscoreCase(child.Name),
				Index:    fieldNum,
				Comment:  child.genericComments(),
			}
		case child.IsContainer(), child.IsList(), child.IsChoice(), child.IsCase():
			field = t.directory(scope, child, fieldNum, child.IsList())
		}
		msg.AddField(field)
	}

	scope.reflectTo(msg)

	return msg
}

func (t *transformer) leaf(typ *yang.YangType, name string) pbast.Type {
	if needsCustomType(typ.Kind) {
		return t.customType(typ, CamelCase(name))
	}

	if isBuiltinType(typ.Name) {
		return t.mapBuiltinType(typ.Kind)
	}

	inner := t.mapBuiltinType(typ.Kind)
	msg := pbast.NewMessage(CamelCase(name)).
		AddField(pbast.NewMessageField(inner, "value", 1))
	if needsInTopScope(inner) {
		t.declare(inner)
	} else {
		msg.AddType(inner)
	}
	return msg
}

func messageName(e entry) string {
	if isBuiltinType(e.Type.Name) {
		return e.Name
	}

	return e.Type.Name
}

func needsInTopScope(t pbast.Type) bool {
	switch t {
	case decimal64, leafRef, identityRef, instanceIdentifier, pbast.Empty:
		return true
	default:
		return false
	}
}

func (t *transformer) customType(typ *yang.YangType, name string) pbast.Type {
	switch typ.Kind {
	case yang.Yenum:
		return t.customEnum(name, typ.Enum)
	case yang.Ybits:
		return t.customBits(name, typ.Bit)
	case yang.Yunion:
		return t.customUnion(name, typ.Type)
	default:
		return nil
	}
}

func isBuiltinType(name string) bool {
	if _, ok := yang.TypeKindFromName[name]; !ok {
		return false
	}
	return true
}

func needsCustomType(kind yang.TypeKind) bool {
	switch kind {
	case yang.Yenum, yang.Ybits, yang.Yunion:
		return true
	default:
		return false
	}
}

func (t *transformer) mapBuiltinType(kind yang.TypeKind) pbast.Type {
	switch kind {
	case yang.Yint8, yang.Yint16, yang.Yint32:
		return pbast.Int32
	case yang.Yint64:
		return pbast.Int64
	case yang.Yuint8, yang.Yuint16, yang.Yuint32:
		return pbast.UInt32
	case yang.Yuint64:
		return pbast.UInt64
	case yang.Ystring:
		return pbast.String
	case yang.Ybool:
		return pbast.Bool
	case yang.Ybinary:
		return pbast.Bytes
	case yang.Yleafref:
		return leafRef
	case yang.Yidentityref:
		return identityRef
	case yang.Yempty:
		return pbast.Empty
	case yang.YinstanceIdentifier:
		return instanceIdentifier
	case yang.Ydecimal64:
		return decimal64
	default:
		return nil
	}
}

func (t *transformer) customBits(name string, bits *yang.EnumType) *pbast.Message {
	msg := pbast.NewMessage(name)
	for i, n := range bits.Names() {
		v := 1 << uint(bits.Values()[i])
		msg.AddField(pbast.NewMessageField(pbast.Bool, n, v))
	}

	return msg
}

func (t *transformer) customEnum(name string, e *yang.EnumType) *pbast.Message {
	enum := pbast.NewEnum("Value")
	for _, v := range e.Values() {
		n := e.ValueMap()[v]
		enum.AddField(pbast.NewEnumField(constantName(n), int(v)))
	}
	msg := pbast.NewMessage(name).
		AddEnum(enum).
		AddField(pbast.NewMessageField(enum, "value", 1))

	return msg
}

func (t *transformer) customUnion(name string, types []*yang.YangType) *pbast.Message {
	scope := newScope()
	pbTypes := t.unionFields(types, nil, scope)

	oneof := pbast.NewOneOf("value")
	for i, typ := range pbTypes {
		oneof.AddField(pbast.NewOneOfField(typ, underscoreCase(typ.TypeName()), i+1))
	}

	msg := pbast.NewMessage(name).AddOneOf(oneof)
	scope.reflectTo(msg)

	return msg
}

func (t *transformer) unionFields(types []*yang.YangType, pbTypes []pbast.Type, scope *scope) []pbast.Type {
	for _, typ := range types {
		if typ.Kind == yang.Yunion {
			pbTypes = t.unionFields(typ.Type, pbTypes, scope)
			continue
		}

		pbtype := t.leaf(typ, typ.Name)
		if pbtype == nil {
			continue
		}

		pbTypes = append(pbTypes, pbtype)
		scope.addType(pbtype)
	}

	return pbTypes
}

func (t *transformer) directory(scope *scope, e entry, index int, repeated bool) *pbast.MessageField {
	fieldName := underscoreCase(e.Name)
	typeName := CamelCase(e.Name)

	inner := t.buildMessage(typeName, e)
	field := &pbast.MessageField{
		Repeated: repeated,
		Type:     inner.TypeName(),
		Name:     fieldName,
		Index:    index,
	}

	if err := scope.addType(inner); err != nil {
		fmt.Fprintln(os.Stderr, err)
	}

	return field
}
<|endoftext|>


<commit_before>package common

import (
	"github.com/meshbird/meshbird/log"
	"github.com/meshbird/meshbird/network/protocol"
	"github.com/meshbird/meshbird/secure"
	"net"
	"sync"
	"time"
)

type NetTable struct {
	BaseService

	localNode       *LocalNode
	waitGroup       sync.WaitGroup
	dhtInChan       chan string

	lock            sync.RWMutex
	blackList       map[string]time.Time
	peers           map[string]*RemoteNode

	heartbeatTicker <-chan time.Time

	logger          log.Logger
}

func (nt NetTable) Name() string {
	return "net-table"
}

func (nt *NetTable) Init(ln *LocalNode) error {
	nt.logger = log.L(nt.Name())
	nt.localNode = ln
	nt.dhtInChan = make(chan string, 10)
	nt.blackList = make(map[string]time.Time)
	nt.peers = make(map[string]*RemoteNode)
	return nil
}

func (nt *NetTable) Run() error {
	for i := 0; i < 10; i++ {
		go nt.processDHTIn()
	}
	go nt.heartbeat()
	return nil
}

func (nt *NetTable) Stop() {
	nt.SetStatus(StatusStopping)
	nt.lock.Lock()
	defer nt.lock.Unlock()
	for _, peer := range nt.peers {
		peer.Close()
	}
}

func (nt *NetTable) GetDHTInChannel() chan <- string {
	return nt.dhtInChan
}

func (nt *NetTable) RemoteNodeByIP(ip net.IP) *RemoteNode {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	return nt.peers[ip.To4().String()]
}

func (nt *NetTable) AddRemoteNode(rn *RemoteNode) {
	nt.logger.Debug("trying to add node, private %q, public %q", rn.privateIP.String(), rn.publicAddress)

	if nt.localNode.State().PrivateIP.Equal(rn.privateIP) {
		nt.logger.Debug("i found myself, node will not be added")
		return
	}

	nt.lock.Lock()
	defer nt.lock.Unlock()

	nt.peers[rn.privateIP.To4().String()] = rn
	nt.logger.Info("added remove node, private %q, public %q", rn.privateIP.String(), rn.publicAddress)
	go rn.listen(nt.localNode)
}

func (nt *NetTable) RemoveRemoteNode(ip net.IP) {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	delete(nt.peers, ip.To4().String())
}

func (nt *NetTable) processDHTIn() {
	for nt.Status() != StatusStopping {
		select {
		case host, ok := <-nt.dhtInChan:
			if !ok {
				return
			}
			nt.lock.Lock()
			_, ok = nt.blackList[host]
			if !ok {
				for _, peer := range nt.peers {
					if peer.publicAddress == host {
						ok = true
						break
					}
				}
			}
			nt.lock.Unlock()

			if !ok {
				if err := nt.tryConnect(host); err != nil {
					nt.logger.Info("unable connect %s err: %s", host, err)
				}
			}
		}
	}
}

func (nt *NetTable) heartbeat() {
	nt.heartbeatTicker = time.Tick(5 * time.Second)

	for {
		select {
		case _, ok := <-nt.heartbeatTicker:
			if !ok {
				break
			}
			nt.lock.Lock()
			for _, peer := range nt.peers {
				if err := peer.SendPack(protocol.NewHeartbeatMessage(nt.localNode.State().PrivateIP)); err != nil {
					nt.logger.Error("error on send heartbeat. %v", err)
				}
			}
			nt.lock.Unlock()
		}
	}
}

func (nt *NetTable) tryConnect(h string) error {
	rn, err := TryConnect(h, nt.localNode.NetworkSecret(), nt.localNode)
	if err != nil {
		nt.addToBlackList(h)
		return err
	}
	nt.logger.Debug("adding remote node...")
	nt.AddRemoteNode(rn)
	return nil
}

func (nt *NetTable) addToBlackList(h string) {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	//nt.blackList[h] = time.Now()
}

func (nt *NetTable) SendPacket(dstIP net.IP, payload []byte) {
	nt.logger.Debug("sending packet %d bytes to %q", len(payload), dstIP.String())

	rn := nt.RemoteNodeByIP(dstIP)
	if rn == nil {
		nt.logger.Debug("destination host %q unreachable", dstIP.String())
		nt.logger.Debug("known hosts, %v", nt.knownHosts())
		return
	}

	payloadEnc, err := secure.EncryptIV(payload, nt.localNode.State().Secret.Key, nt.localNode.State().Secret.Key)
	if err != nil {
		nt.logger.Error("error on encrypt, %v", err)
		return
	}

	if err := rn.SendToInterface(payloadEnc); err != nil {
		nt.logger.Error("error on sending packet to %q, %v", dstIP.String(), err)
	}
}

func (nt *NetTable) PeerAddresses() map[string]string {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	peers := make(map[string]string)
	for l, peer := range nt.peers {
		peers[l] = peer.publicAddress
	}
	return peers
}

func (nt *NetTable) knownHosts() []string {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	ips := make([]string, len(nt.peers))
	var i int
	for k := range nt.peers {
		ips[i] = k
		i++
	}
	return ips
}
<commit_msg>log sending packet<commit_after>package common

import (
	"github.com/meshbird/meshbird/log"
	"github.com/meshbird/meshbird/network/protocol"
	"github.com/meshbird/meshbird/secure"
	"net"
	"sync"
	"time"
)

type NetTable struct {
	BaseService

	localNode       *LocalNode
	waitGroup       sync.WaitGroup
	dhtInChan       chan string

	lock            sync.RWMutex
	blackList       map[string]time.Time
	peers           map[string]*RemoteNode

	heartbeatTicker <-chan time.Time

	logger          log.Logger
}

func (nt NetTable) Name() string {
	return "net-table"
}

func (nt *NetTable) Init(ln *LocalNode) error {
	nt.logger = log.L(nt.Name())
	nt.localNode = ln
	nt.dhtInChan = make(chan string, 10)
	nt.blackList = make(map[string]time.Time)
	nt.peers = make(map[string]*RemoteNode)
	return nil
}

func (nt *NetTable) Run() error {
	for i := 0; i < 10; i++ {
		go nt.processDHTIn()
	}
	go nt.heartbeat()
	return nil
}

func (nt *NetTable) Stop() {
	nt.SetStatus(StatusStopping)
	nt.lock.Lock()
	defer nt.lock.Unlock()
	for _, peer := range nt.peers {
		peer.Close()
	}
}

func (nt *NetTable) GetDHTInChannel() chan <- string {
	return nt.dhtInChan
}

func (nt *NetTable) RemoteNodeByIP(ip net.IP) *RemoteNode {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	return nt.peers[ip.To4().String()]
}

func (nt *NetTable) AddRemoteNode(rn *RemoteNode) {
	nt.logger.Debug("trying to add node, private %q, public %q", rn.privateIP.String(), rn.publicAddress)

	if nt.localNode.State().PrivateIP.Equal(rn.privateIP) {
		nt.logger.Debug("i found myself, node will not be added")
		return
	}

	nt.lock.Lock()
	defer nt.lock.Unlock()

	nt.peers[rn.privateIP.To4().String()] = rn
	nt.logger.Info("added remove node, private %q, public %q", rn.privateIP.String(), rn.publicAddress)
	go rn.listen(nt.localNode)
}

func (nt *NetTable) RemoveRemoteNode(ip net.IP) {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	delete(nt.peers, ip.To4().String())
}

func (nt *NetTable) processDHTIn() {
	for nt.Status() != StatusStopping {
		select {
		case host, ok := <-nt.dhtInChan:
			if !ok {
				return
			}
			nt.lock.Lock()
			_, ok = nt.blackList[host]
			if !ok {
				for _, peer := range nt.peers {
					if peer.publicAddress == host {
						ok = true
						break
					}
				}
			}
			nt.lock.Unlock()

			if !ok {
				if err := nt.tryConnect(host); err != nil {
					nt.logger.Info("unable connect %s err: %s", host, err)
				}
			}
		}
	}
}

func (nt *NetTable) heartbeat() {
	nt.heartbeatTicker = time.Tick(5 * time.Second)

	for {
		select {
		case _, ok := <-nt.heartbeatTicker:
			if !ok {
				break
			}
			nt.lock.Lock()
			for _, peer := range nt.peers {
				if err := peer.SendPack(protocol.NewHeartbeatMessage(nt.localNode.State().PrivateIP)); err != nil {
					nt.logger.Error("error on send heartbeat. %v", err)
				}
			}
			nt.lock.Unlock()
		}
	}
}

func (nt *NetTable) tryConnect(h string) error {
	rn, err := TryConnect(h, nt.localNode.NetworkSecret(), nt.localNode)
	if err != nil {
		nt.addToBlackList(h)
		return err
	}
	nt.logger.Debug("adding remote node...")
	nt.AddRemoteNode(rn)
	return nil
}

func (nt *NetTable) addToBlackList(h string) {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	//nt.blackList[h] = time.Now()
}

func (nt *NetTable) SendPacket(dstIP net.IP, payload []byte) {
	srcAddr := net.IP(payload[12:16])
	dstAddr := net.IP(payload[16:20])
	nt.logger.Info("sending packet to %s, len %d bytes", srcAddr.String(), dstAddr.String(), len(payload))

	rn := nt.RemoteNodeByIP(dstIP)
	if rn == nil {
		nt.logger.Debug("destination host %q unreachable", dstIP.String())
		nt.logger.Debug("known hosts, %v", nt.knownHosts())
		return
	}

	payloadEnc, err := secure.EncryptIV(payload, nt.localNode.State().Secret.Key, nt.localNode.State().Secret.Key)
	if err != nil {
		nt.logger.Error("error on encrypt, %v", err)
		return
	}

	if err := rn.SendToInterface(payloadEnc); err != nil {
		nt.logger.Error("error on sending packet to %q, %v", dstIP.String(), err)
	}
}

func (nt *NetTable) PeerAddresses() map[string]string {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	peers := make(map[string]string)
	for l, peer := range nt.peers {
		peers[l] = peer.publicAddress
	}
	return peers
}

func (nt *NetTable) knownHosts() []string {
	nt.lock.Lock()
	defer nt.lock.Unlock()
	ips := make([]string, len(nt.peers))
	var i int
	for k := range nt.peers {
		ips[i] = k
		i++
	}
	return ips
}
<|endoftext|>


<commit_before>package main

import (
    "os"
    "fmt"
    "github.com/speedata/gogit"
    "path/filepath"
)

const REF_S3_PUSH string = "LAST_S3_PUSH"

type Repository struct {
    GitRepo         *gogit.Repository
    HeadCommit      *gogit.Commit
    LastPushCommit  *gogit.Commit
    UnpushedFiles   []string
}

func OpenRepository() (*Repository, error) {
    repo := new(Repository)

    wd, err := os.Getwd()
    if err != nil {
        return nil, err
    }

    path := filepath.Join(wd, ".git")
    if _, err := os.Stat(path); os.IsNotExist(err) {
        return nil, err
    }

    gitRepo, err := gogit.OpenRepository(path)
    if err != nil {
        return nil, err
    }
    repo.GitRepo = gitRepo

    return repo, nil
}

func (repo *Repository) FindRelevantCommits() error {
    headRef, err := repo.GitRepo.LookupReference("HEAD")
    if err != nil {
        return err
    }

    headCommit, err := repo.GitRepo.LookupCommit(headRef.Target())
    if err != nil {
        return err
    }
    repo.HeadCommit = headCommit

    lastPushRef, err := repo.GitRepo.LookupReference(REF_S3_PUSH)
    if err != nil {
        return nil
    }

    lastPushCommit, err := repo.GitRepo.LookupCommit(lastPushRef.Target())
    if err != nil {
        return nil
    }
    repo.LastPushCommit = lastPushCommit

    return nil
}

func (repo *Repository) ModifiedFilesInCommit(dirname string, te *gogit.TreeEntry) int {
    filePath := filepath.Join(dirname, te.Name)

    if _, err := os.Stat(filePath); err == nil {
        repo.UnpushedFiles = append(repo.UnpushedFiles, filePath)
    }

    return 0;
}

func (repo *Repository) FindUnpushedModifiedFiles() {
    currentCommit := repo.HeadCommit;

    for currentCommit != nil && currentCommit.ParentCount() > 0 {
        currentCommit.Tree.Walk(repo.ModifiedFilesInCommit)

        if repo.LastPushCommit != nil && repo.LastPushCommit.Id() == currentCommit.Id() {
            break;
        }

        currentCommit = currentCommit.Parent(0)
    }
}

func main() {
    repo, err := OpenRepository()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if err := repo.FindRelevantCommits(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    repo.FindUnpushedModifiedFiles();
    fmt.Println(len(repo.UnpushedFiles))

    fmt.Println(repo.LastPushCommit)
}<commit_msg>Implement pushing modified files to S3 (with hard-coded bucket/region)<commit_after>package main

import (
    "os"
    //"io"
    "fmt"
    "github.com/speedata/gogit"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3/s3manager"
    "path/filepath"
)

const REF_S3_PUSH string = "LAST_S3_PUSH"

type Repository struct {
    GitRepo         *gogit.Repository
    HeadCommit      *gogit.Commit
    LastPushCommit  *gogit.Commit
    UnpushedFiles   []string
    Config          RepoConfig
    S3Uploader      S3Uploader
}

type RepoConfig struct {
    S3Region        string
    S3Bucket        string
}

func OpenRepository() (*Repository, error) {
    repo := new(Repository)

    wd, err := os.Getwd()
    if err != nil {
        return nil, err
    }

    path := filepath.Join(wd, ".git")
    if _, err := os.Stat(path); os.IsNotExist(err) {
        return nil, err
    }

    gitRepo, err := gogit.OpenRepository(path)
    if err != nil {
        return nil, err
    }
    repo.GitRepo = gitRepo

    return repo, nil
}

func (repo *Repository) FindRelevantCommits() error {
    headRef, err := repo.GitRepo.LookupReference("HEAD")
    if err != nil {
        return err
    }

    headCommit, err := repo.GitRepo.LookupCommit(headRef.Target())
    if err != nil {
        return err
    }
    repo.HeadCommit = headCommit

    lastPushRef, err := repo.GitRepo.LookupReference(REF_S3_PUSH)
    if err != nil {
        return nil
    }

    lastPushCommit, err := repo.GitRepo.LookupCommit(lastPushRef.Target())
    if err != nil {
        return nil
    }
    repo.LastPushCommit = lastPushCommit

    return nil
}

func (repo *Repository) ModifiedFilesInCommit(dirname string, te *gogit.TreeEntry) int {
    filePath := filepath.Join(dirname, te.Name)

    if _, err := os.Stat(filePath); err == nil {
        repo.UnpushedFiles = append(repo.UnpushedFiles, filePath)
    }

    return 0;
}

func (repo *Repository) FindUnpushedModifiedFiles() {
    if repo.HeadCommit.Id().Equal(repo.LastPushCommit.Id()) {
        return
    }

    currentCommit := repo.HeadCommit;

    for currentCommit != nil && currentCommit.ParentCount() > 0 {
        currentCommit.Tree.Walk(repo.ModifiedFilesInCommit)

        if repo.LastPushCommit != nil && repo.LastPushCommit.Id() == currentCommit.Id() {
            break;
        }

        currentCommit = currentCommit.Parent(0)
    }
}

type S3Uploader struct {
    BucketName      *string
    S3Uploader      *s3manager.Uploader
}

func InitS3Uploader(config RepoConfig) *S3Uploader {
    uploader := new(S3Uploader)
    uploader.BucketName = aws.String(config.S3Bucket)

    s3config := aws.Config{Region: aws.String(config.S3Region)}
    s3uploader := s3manager.NewUploader(session.New(&s3config))
    uploader.S3Uploader = s3uploader

    return uploader
}

func (uploader S3Uploader) UploadFile(path string) error {
    file, err := os.Open(path)
    if err != nil {
        return err
    }

    result, err := uploader.S3Uploader.Upload(&s3manager.UploadInput{
        Body: file,
        Bucket: uploader.BucketName,
        Key: aws.String(path),
    })

    if err != nil {
        return err
    }

    fmt.Println(result.Location)
    return nil
}

func main() {
    repo, err := OpenRepository()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if err := repo.FindRelevantCommits(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    repo.FindUnpushedModifiedFiles();

    if len(repo.UnpushedFiles) == 0 {
        fmt.Println("No modified files to push")
        os.Exit(0)
    }

    config := RepoConfig{S3Region: "eu-west-1", S3Bucket: "git-s3-push-test"}
    uploader := InitS3Uploader(config)

    for _, filePath := range repo.UnpushedFiles {
        fmt.Println("Uploading: " + filePath)
        err := uploader.UploadFile(filePath)
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
    }
}<|endoftext|>


<commit_before>package github

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

	"github.com/github/hub/ui"
	"github.com/github/hub/utils"
)

type verboseTransport struct {
	Transport   *http.Transport
	Verbose     bool
	OverrideURL *url.URL
	Out         io.Writer
	Colorized   bool
}

func (t *verboseTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	if t.Verbose {
		t.dumpRequest(req)
	}

	if t.OverrideURL != nil {
		port := "80"
		if s := strings.Split(req.URL.Host, ":"); len(s) > 1 {
			port = s[1]
		}

		req = cloneRequest(req)
		req.Header.Set("X-Original-Scheme", req.URL.Scheme)
		req.Header.Set("X-Original-Port", port)
		req.URL.Scheme = t.OverrideURL.Scheme
		req.URL.Host = t.OverrideURL.Host
	}

	resp, err = t.Transport.RoundTrip(req)

	if err == nil && t.Verbose {
		t.dumpResponse(resp)
	}

	return
}

func (t *verboseTransport) dumpRequest(req *http.Request) {
	info := fmt.Sprintf("> %s %s://%s%s", req.Method, req.URL.Scheme, req.Host, req.URL.Path)
	t.verbosePrintln(info)
	t.dumpHeaders(req.Header, ">")
	body := t.dumpBody(req.Body)
	if body != nil {
		// reset body since it's been read
		req.Body = body
	}
}

func (t *verboseTransport) dumpResponse(resp *http.Response) {
	info := fmt.Sprintf("< HTTP %d", resp.StatusCode)
	t.verbosePrintln(info)
	t.dumpHeaders(resp.Header, "<")
	body := t.dumpBody(resp.Body)
	if body != nil {
		// reset body since it's been read
		resp.Body = body
	}
}

func (t *verboseTransport) dumpHeaders(header http.Header, indent string) {
	dumpHeaders := []string{"Authorization", "X-GitHub-OTP", "Location"}
	for _, h := range dumpHeaders {
		v := header.Get(h)
		if v != "" {
			r := regexp.MustCompile("(?i)^(basic|token) (.+)")
			if r.MatchString(v) {
				v = r.ReplaceAllString(v, "$1 [REDACTED]")
			}

			info := fmt.Sprintf("%s %s: %s", indent, h, v)
			t.verbosePrintln(info)
		}
	}
}

func (t *verboseTransport) dumpBody(body io.ReadCloser) io.ReadCloser {
	if body == nil {
		return nil
	}

	defer body.Close()
	buf := new(bytes.Buffer)
	_, err := io.Copy(buf, body)
	utils.Check(err)

	if buf.Len() > 0 {
		t.verbosePrintln(buf.String())
	}

	return ioutil.NopCloser(buf)
}

func (t *verboseTransport) verbosePrintln(msg string) {
	if t.Colorized {
		msg = fmt.Sprintf("\033[36m%s\033[0m", msg)
	}

	fmt.Fprintln(t.Out, msg)
}

func newHttpClient(testHost string, verbose bool) *http.Client {
	var testURL *url.URL
	if testHost != "" {
		testURL, _ = url.Parse(testHost)
	}
	tr := &verboseTransport{
		Transport: &http.Transport{
			Proxy: proxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
		},
		Verbose:     verbose,
		OverrideURL: testURL,
		Out:         ui.Stderr,
		Colorized:   ui.IsTerminal(os.Stderr),
	}
	return &http.Client{Transport: tr}
}

func cloneRequest(req *http.Request) *http.Request {
	dup := new(http.Request)
	*dup = *req
	dup.URL, _ = url.Parse(req.URL.String())
	dup.Header = make(http.Header)
	for k, s := range req.Header {
		dup.Header[k] = s
	}
	return dup
}

// An implementation of http.ProxyFromEnvironment that isn't broken
func proxyFromEnvironment(req *http.Request) (*url.URL, error) {
	proxy := os.Getenv("http_proxy")
	if proxy == "" {
		proxy = os.Getenv("HTTP_PROXY")
	}
	if proxy == "" {
		return nil, nil
	}

	proxyURL, err := url.Parse(proxy)
	if err != nil || !strings.HasPrefix(proxyURL.Scheme, "http") {
		if proxyURL, err := url.Parse("http://" + proxy); err == nil {
			return proxyURL, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
	}

	return proxyURL, nil
}

type simpleClient struct {
	httpClient  *http.Client
	rootUrl     *url.URL
	accessToken string
}

func (c *simpleClient) Get(path string) (res *simpleResponse, err error) {
	url, err := url.Parse(path)
	if err != nil {
		return
	}

	url = c.rootUrl.ResolveReference(url)
	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return
	}
	req.Header.Set("Authorization", "token "+c.accessToken)

	httpResponse, err := c.httpClient.Do(req)
	if err == nil {
		res = &simpleResponse{httpResponse}
	}

	return
}

type simpleResponse struct {
	*http.Response
}

func (res *simpleResponse) Unmarshal(dest interface{}) (err error) {
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	return json.Unmarshal(body, dest)
}
<commit_msg>Improve HTTP debugging by including query params<commit_after>package github

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

	"github.com/github/hub/ui"
	"github.com/github/hub/utils"
)

type verboseTransport struct {
	Transport   *http.Transport
	Verbose     bool
	OverrideURL *url.URL
	Out         io.Writer
	Colorized   bool
}

func (t *verboseTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	if t.Verbose {
		t.dumpRequest(req)
	}

	if t.OverrideURL != nil {
		port := "80"
		if s := strings.Split(req.URL.Host, ":"); len(s) > 1 {
			port = s[1]
		}

		req = cloneRequest(req)
		req.Header.Set("X-Original-Scheme", req.URL.Scheme)
		req.Header.Set("X-Original-Port", port)
		req.URL.Scheme = t.OverrideURL.Scheme
		req.URL.Host = t.OverrideURL.Host
	}

	resp, err = t.Transport.RoundTrip(req)

	if err == nil && t.Verbose {
		t.dumpResponse(resp)
	}

	return
}

func (t *verboseTransport) dumpRequest(req *http.Request) {
	info := fmt.Sprintf("> %s %s://%s%s", req.Method, req.URL.Scheme, req.Host, req.URL.RequestURI())
	t.verbosePrintln(info)
	t.dumpHeaders(req.Header, ">")
	body := t.dumpBody(req.Body)
	if body != nil {
		// reset body since it's been read
		req.Body = body
	}
}

func (t *verboseTransport) dumpResponse(resp *http.Response) {
	info := fmt.Sprintf("< HTTP %d", resp.StatusCode)
	t.verbosePrintln(info)
	t.dumpHeaders(resp.Header, "<")
	body := t.dumpBody(resp.Body)
	if body != nil {
		// reset body since it's been read
		resp.Body = body
	}
}

func (t *verboseTransport) dumpHeaders(header http.Header, indent string) {
	dumpHeaders := []string{"Authorization", "X-GitHub-OTP", "Location"}
	for _, h := range dumpHeaders {
		v := header.Get(h)
		if v != "" {
			r := regexp.MustCompile("(?i)^(basic|token) (.+)")
			if r.MatchString(v) {
				v = r.ReplaceAllString(v, "$1 [REDACTED]")
			}

			info := fmt.Sprintf("%s %s: %s", indent, h, v)
			t.verbosePrintln(info)
		}
	}
}

func (t *verboseTransport) dumpBody(body io.ReadCloser) io.ReadCloser {
	if body == nil {
		return nil
	}

	defer body.Close()
	buf := new(bytes.Buffer)
	_, err := io.Copy(buf, body)
	utils.Check(err)

	if buf.Len() > 0 {
		t.verbosePrintln(buf.String())
	}

	return ioutil.NopCloser(buf)
}

func (t *verboseTransport) verbosePrintln(msg string) {
	if t.Colorized {
		msg = fmt.Sprintf("\033[36m%s\033[0m", msg)
	}

	fmt.Fprintln(t.Out, msg)
}

func newHttpClient(testHost string, verbose bool) *http.Client {
	var testURL *url.URL
	if testHost != "" {
		testURL, _ = url.Parse(testHost)
	}
	tr := &verboseTransport{
		Transport: &http.Transport{
			Proxy: proxyFromEnvironment,
			Dial: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).Dial,
			TLSHandshakeTimeout: 10 * time.Second,
		},
		Verbose:     verbose,
		OverrideURL: testURL,
		Out:         ui.Stderr,
		Colorized:   ui.IsTerminal(os.Stderr),
	}
	return &http.Client{Transport: tr}
}

func cloneRequest(req *http.Request) *http.Request {
	dup := new(http.Request)
	*dup = *req
	dup.URL, _ = url.Parse(req.URL.String())
	dup.Header = make(http.Header)
	for k, s := range req.Header {
		dup.Header[k] = s
	}
	return dup
}

// An implementation of http.ProxyFromEnvironment that isn't broken
func proxyFromEnvironment(req *http.Request) (*url.URL, error) {
	proxy := os.Getenv("http_proxy")
	if proxy == "" {
		proxy = os.Getenv("HTTP_PROXY")
	}
	if proxy == "" {
		return nil, nil
	}

	proxyURL, err := url.Parse(proxy)
	if err != nil || !strings.HasPrefix(proxyURL.Scheme, "http") {
		if proxyURL, err := url.Parse("http://" + proxy); err == nil {
			return proxyURL, nil
		}
	}

	if err != nil {
		return nil, fmt.Errorf("invalid proxy address %q: %v", proxy, err)
	}

	return proxyURL, nil
}

type simpleClient struct {
	httpClient  *http.Client
	rootUrl     *url.URL
	accessToken string
}

func (c *simpleClient) Get(path string) (res *simpleResponse, err error) {
	url, err := url.Parse(path)
	if err != nil {
		return
	}

	url = c.rootUrl.ResolveReference(url)
	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		return
	}
	req.Header.Set("Authorization", "token "+c.accessToken)

	httpResponse, err := c.httpClient.Do(req)
	if err == nil {
		res = &simpleResponse{httpResponse}
	}

	return
}

type simpleResponse struct {
	*http.Response
}

func (res *simpleResponse) Unmarshal(dest interface{}) (err error) {
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return
	}

	return json.Unmarshal(body, dest)
}
<|endoftext|>


<commit_before>package test_utils

import (
	"io/ioutil"

	log "github.com/Sirupsen/logrus"
	jwt "github.com/dgrijalva/jwt-go"
)

func CreateTokenWithPayload(payload map[string]interface{}, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims = payload
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func CreateToken(hostUuid string, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims["hostUuid"] = hostUuid
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func CreateBackendToken(reportedUuid string, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims["reportedUuid"] = reportedUuid
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func ParseTestPrivateKey() interface{} {
	keyBytes, err := ioutil.ReadFile("../test_utils/private.pem")
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}

	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(keyBytes)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}

	return privateKey
}
<commit_msg>add utility method for reading test public keys<commit_after>package test_utils

import (
	"io/ioutil"

	log "github.com/Sirupsen/logrus"
	jwt "github.com/dgrijalva/jwt-go"
)

func CreateTokenWithPayload(payload map[string]interface{}, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims = payload
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func CreateToken(hostUuid string, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims["hostUuid"] = hostUuid
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func CreateBackendToken(reportedUuid string, privateKey interface{}) string {
	token := jwt.New(jwt.GetSigningMethod("RS256"))
	token.Claims["reportedUuid"] = reportedUuid
	signed, err := token.SignedString(privateKey)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}
	return signed
}

func ParseTestPrivateKey() interface{} {
	keyBytes, err := ioutil.ReadFile("../test_utils/private.pem")
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}

	privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(keyBytes)
	if err != nil {
		log.Fatal("Failed to parse private key.", err)
	}

	return privateKey
}

func ParseTestPublicKey() interface{} {
	keyBytes, err := ioutil.ReadFile("../test_utils/public.pem")
	if err != nil {
		log.Fatal("Failed to parse public key.", err)
	}

	publicKey, err := jwt.ParseRSAPublicKeyFromPEM(keyBytes)
	if err != nil {
		log.Fatal("Failed to parse public key.", err)
	}

	return publicKey

}
<|endoftext|>


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

//+build i386 amd64
package loader

/*
#include <asm/types.h>
#include <linux/const.h>
#include <string.h>

#ifdef __x86_64__
#include <x86_64-linux-gnu/asm/bootparam.h>
#else
#include <i386-linux-gnu/asm/bootparam.h>
#endif

// E820 codes.
const int E820Ram = E820_RAM;
const int E820Reserved = E820_RESERVED;
const int E820Acpi = E820_ACPI;

// Our E820 map.
static inline void e820_set_count(
    struct boot_params* boot,
    int count) {

    boot->e820_entries = count;
}
static inline void e820_set_region(
    struct boot_params* boot,
    int index,
    __u64 start,
    __u64 size,
    __u8 type) {

    boot->e820_map[index].addr = start;
    boot->e820_map[index].size = size;
    boot->e820_map[index].type = type;
}
static inline void set_header(
    struct boot_params* boot,
    __u64 initrd_addr,
    __u64 initrd_len,
    __u64 cmdline_addr) {

    boot->hdr.vid_mode = 0xffff;
    boot->hdr.type_of_loader = 0xff;
    boot->hdr.loadflags = 0;
    boot->hdr.setup_move_size = 0;
    boot->hdr.ramdisk_image = initrd_addr;
    boot->hdr.ramdisk_size = initrd_len;
    boot->hdr.heap_end_ptr = 0;
    boot->hdr.cmd_line_ptr = cmdline_addr;
    boot->hdr.setup_data = 0;
}
*/
import "C"

import (
	"novmm/machine"
	"novmm/platform"
	"unsafe"
)

func SetupLinuxBootParams(
	model *machine.Model,
	boot_params_data []byte,
	orig_boot_params_data []byte,
	cmdline_addr platform.Paddr,
	initrd_addr platform.Paddr,
	initrd_len uint64) error {

	// Grab a reference to our boot params struct.
	boot_params := (*C.struct_boot_params)(unsafe.Pointer(&boot_params_data[0]))

	// The setup header.
	// First step is to copy the existing setup_header
	// out of the given kernel image. We copy only the
	// header, and not the rest of the setup page.
	setup_start := 0x01f1
	setup_end := 0x0202 + int(orig_boot_params_data[0x0201])
	if setup_end > platform.PageSize {
		return InvalidSetupHeader
	}
	C.memcpy(
		unsafe.Pointer(&boot_params_data[setup_start]),
		unsafe.Pointer(&orig_boot_params_data[setup_start]),
		C.size_t(setup_end-setup_start))

	// Setup our BIOS memory map.
	// NOTE: We have to do this via C bindings. This is really
	// annoying, but basically because of the unaligned structures
	// in the struct_boot_params, the Go code generated here is
	// actually *incompatible* with the actual C layout.

	// First, the count.
	C.e820_set_count(boot_params, C.int(len(model.MemoryMap)))

	// Then, fill out the region information.
	for index, region := range model.MemoryMap {

		var memtype C.int
		switch region.MemoryType {
		case machine.MemoryTypeUser:
			memtype = C.E820Ram
		case machine.MemoryTypeReserved:
			memtype = C.E820Reserved
		case machine.MemoryTypeSpecial:
			memtype = C.E820Reserved
		case machine.MemoryTypeAcpi:
			memtype = C.E820Acpi
		}

		C.e820_set_region(
			boot_params,
			C.int(index),
			C.__u64(region.Start),
			C.__u64(region.Size),
			C.__u8(memtype))
	}

	// Set necessary setup header bits.
	C.set_header(
		boot_params,
		C.__u64(initrd_addr),
		C.__u64(initrd_len),
		C.__u64(cmdline_addr))

	// All done!
	return nil
}
<commit_msg>Use proper include path for bootparam.h.<commit_after>// Copyright 2014 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//+build i386 amd64
package loader

/*
#include <asm/types.h>
#include <linux/const.h>
#include <string.h>
#include <asm/bootparam.h>

// E820 codes.
const int E820Ram = E820_RAM;
const int E820Reserved = E820_RESERVED;
const int E820Acpi = E820_ACPI;

// Our E820 map.
static inline void e820_set_count(
    struct boot_params* boot,
    int count) {

    boot->e820_entries = count;
}
static inline void e820_set_region(
    struct boot_params* boot,
    int index,
    __u64 start,
    __u64 size,
    __u8 type) {

    boot->e820_map[index].addr = start;
    boot->e820_map[index].size = size;
    boot->e820_map[index].type = type;
}
static inline void set_header(
    struct boot_params* boot,
    __u64 initrd_addr,
    __u64 initrd_len,
    __u64 cmdline_addr) {

    boot->hdr.vid_mode = 0xffff;
    boot->hdr.type_of_loader = 0xff;
    boot->hdr.loadflags = 0;
    boot->hdr.setup_move_size = 0;
    boot->hdr.ramdisk_image = initrd_addr;
    boot->hdr.ramdisk_size = initrd_len;
    boot->hdr.heap_end_ptr = 0;
    boot->hdr.cmd_line_ptr = cmdline_addr;
    boot->hdr.setup_data = 0;
}
*/
import "C"

import (
	"novmm/machine"
	"novmm/platform"
	"unsafe"
)

func SetupLinuxBootParams(
	model *machine.Model,
	boot_params_data []byte,
	orig_boot_params_data []byte,
	cmdline_addr platform.Paddr,
	initrd_addr platform.Paddr,
	initrd_len uint64) error {

	// Grab a reference to our boot params struct.
	boot_params := (*C.struct_boot_params)(unsafe.Pointer(&boot_params_data[0]))

	// The setup header.
	// First step is to copy the existing setup_header
	// out of the given kernel image. We copy only the
	// header, and not the rest of the setup page.
	setup_start := 0x01f1
	setup_end := 0x0202 + int(orig_boot_params_data[0x0201])
	if setup_end > platform.PageSize {
		return InvalidSetupHeader
	}
	C.memcpy(
		unsafe.Pointer(&boot_params_data[setup_start]),
		unsafe.Pointer(&orig_boot_params_data[setup_start]),
		C.size_t(setup_end-setup_start))

	// Setup our BIOS memory map.
	// NOTE: We have to do this via C bindings. This is really
	// annoying, but basically because of the unaligned structures
	// in the struct_boot_params, the Go code generated here is
	// actually *incompatible* with the actual C layout.

	// First, the count.
	C.e820_set_count(boot_params, C.int(len(model.MemoryMap)))

	// Then, fill out the region information.
	for index, region := range model.MemoryMap {

		var memtype C.int
		switch region.MemoryType {
		case machine.MemoryTypeUser:
			memtype = C.E820Ram
		case machine.MemoryTypeReserved:
			memtype = C.E820Reserved
		case machine.MemoryTypeSpecial:
			memtype = C.E820Reserved
		case machine.MemoryTypeAcpi:
			memtype = C.E820Acpi
		}

		C.e820_set_region(
			boot_params,
			C.int(index),
			C.__u64(region.Start),
			C.__u64(region.Size),
			C.__u8(memtype))
	}

	// Set necessary setup header bits.
	C.set_header(
		boot_params,
		C.__u64(initrd_addr),
		C.__u64(initrd_len),
		C.__u64(cmdline_addr))

	// All done!
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Authors of Cilium
//
// 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 cmd

import (
	"fmt"
	"os"
	"sort"
	"text/tabwriter"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/common/types"
	"github.com/cilium/cilium/pkg/command"

	"github.com/spf13/cobra"
)

// serviceListCmd represents the service_list command
var serviceListCmd = &cobra.Command{
	Use:   "list",
	Short: "List services",
	Run: func(cmd *cobra.Command, args []string) {
		listServices(cmd, args)
	},
}

func init() {
	serviceCmd.AddCommand(serviceListCmd)
	command.AddJSONOutput(serviceListCmd)
}

func listServices(cmd *cobra.Command, args []string) {
	list, err := client.GetServices()
	if err != nil {
		Fatalf("Cannot get services list: %s", err)
	}
	w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0)
	printServiceList(w, list)
}

func printServiceList(w *tabwriter.Writer, list []*models.Service) {
	fmt.Fprintln(w, "ID\tFrontend\tBackend\t")

	type ServiceOutput struct {
		ID               int64
		FrontendAddress  string
		BackendAddresses []string
	}
	svcs := []ServiceOutput{}

	for _, svc := range list {
		feA, err := types.NewL3n4AddrFromModel(svc.FrontendAddress)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing frontend %+v", svc.FrontendAddress)
			continue
		}

		var backendAddresses []string
		for i, be := range svc.BackendAddresses {
			beA, err := types.NewL3n4AddrFromBackendModel(be)
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing backend %+v", be)
				continue
			}
			var str string
			if be.Weight != 0 {
				str = fmt.Sprintf("%d => %s (W: %d)", i+1, beA.String(), be.Weight)
			} else {
				str = fmt.Sprintf("%d => %s", i+1, beA.String())
			}
			backendAddresses = append(backendAddresses, str)
		}

		SvcOutput := ServiceOutput{
			ID:               svc.ID,
			FrontendAddress:  feA.String(),
			BackendAddresses: backendAddresses,
		}
		svcs = append(svcs, SvcOutput)
	}

	sort.Slice(svcs, func(i, j int) bool {
		return svcs[i].ID <= svcs[j].ID
	})

	if command.OutputJSON() {
		if err := command.PrintOutput(svcs); err != nil {
			os.Exit(1)
		}
		return
	}

	for _, service := range svcs {
		var str string

		if len(service.BackendAddresses) == 0 {
			str = fmt.Sprintf("%d\t%s\t\t",
				service.ID, service.FrontendAddress)
			fmt.Fprintln(w, str)
			continue
		}

		str = fmt.Sprintf("%d\t%s\t%s\t",
			service.ID, service.FrontendAddress,
			service.BackendAddresses[0])
		fmt.Fprintln(w, str)

		for _, bkaddr := range service.BackendAddresses[1:] {
			str := fmt.Sprintf("\t\t%s\t", bkaddr)
			fmt.Fprintln(w, str)
		}
	}

	w.Flush()
}
<commit_msg>cli: cilium service list -o json returns raw json<commit_after>// Copyright 2017 Authors of Cilium
//
// 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 cmd

import (
	"fmt"
	"os"
	"sort"
	"text/tabwriter"

	"github.com/cilium/cilium/api/v1/models"
	"github.com/cilium/cilium/common/types"
	"github.com/cilium/cilium/pkg/command"

	"github.com/spf13/cobra"
)

// serviceListCmd represents the service_list command
var serviceListCmd = &cobra.Command{
	Use:   "list",
	Short: "List services",
	Run: func(cmd *cobra.Command, args []string) {
		listServices(cmd, args)
	},
}

func init() {
	serviceCmd.AddCommand(serviceListCmd)
	command.AddJSONOutput(serviceListCmd)
}

func listServices(cmd *cobra.Command, args []string) {
	list, err := client.GetServices()
	if err != nil {
		Fatalf("Cannot get services list: %s", err)
	}

	if command.OutputJSON() {
		if err := command.PrintOutput(list); err != nil {
			os.Exit(1)
		}
		return
	}

	w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0)
	printServiceList(w, list)
}

func printServiceList(w *tabwriter.Writer, list []*models.Service) {
	fmt.Fprintln(w, "ID\tFrontend\tBackend\t")

	type ServiceOutput struct {
		ID               int64
		FrontendAddress  string
		BackendAddresses []string
	}
	svcs := []ServiceOutput{}

	for _, svc := range list {
		feA, err := types.NewL3n4AddrFromModel(svc.FrontendAddress)
		if err != nil {
			fmt.Fprintf(os.Stderr, "error parsing frontend %+v", svc.FrontendAddress)
			continue
		}

		var backendAddresses []string
		for i, be := range svc.BackendAddresses {
			beA, err := types.NewL3n4AddrFromBackendModel(be)
			if err != nil {
				fmt.Fprintf(os.Stderr, "error parsing backend %+v", be)
				continue
			}
			var str string
			if be.Weight != 0 {
				str = fmt.Sprintf("%d => %s (W: %d)", i+1, beA.String(), be.Weight)
			} else {
				str = fmt.Sprintf("%d => %s", i+1, beA.String())
			}
			backendAddresses = append(backendAddresses, str)
		}

		SvcOutput := ServiceOutput{
			ID:               svc.ID,
			FrontendAddress:  feA.String(),
			BackendAddresses: backendAddresses,
		}
		svcs = append(svcs, SvcOutput)
	}

	sort.Slice(svcs, func(i, j int) bool {
		return svcs[i].ID <= svcs[j].ID
	})

	for _, service := range svcs {
		var str string

		if len(service.BackendAddresses) == 0 {
			str = fmt.Sprintf("%d\t%s\t\t",
				service.ID, service.FrontendAddress)
			fmt.Fprintln(w, str)
			continue
		}

		str = fmt.Sprintf("%d\t%s\t%s\t",
			service.ID, service.FrontendAddress,
			service.BackendAddresses[0])
		fmt.Fprintln(w, str)

		for _, bkaddr := range service.BackendAddresses[1:] {
			str := fmt.Sprintf("\t\t%s\t", bkaddr)
			fmt.Fprintln(w, str)
		}
	}

	w.Flush()
}
<|endoftext|>


<commit_before>package git

import (
	"net/url"
	"strings"
)

// NormalizeURL strips everything from the URL except for the host and the path.
// A trailing ".git" is also stripped. The purpose is to allow for small
// variations in repo URL to be recognized as the same repo. The URL needs to
// contain a valid transport protocol, e.g. https, ssh.
// These URLs will all return 'github.com/skia-dev/textfiles':
//
//    "https://github.com/skia-dev/textfiles.git"
//    "ssh://git@github.com/skia-dev/textfiles"
//    "ssh://git@github.com:skia-dev/textfiles.git"
//
func NormalizeURL(inputURL string) (string, error) {
	parsedURL, err := url.Parse(inputURL)
	if err != nil {
		return "", err
	}

	// If the scheme is ssh we have to account for the scp-like syntax with a ':'
	host := parsedURL.Host
	if parsedURL.Scheme == "ssh" {
		host = strings.Replace(host, ":", "/", 1)
	}
	path := "/" + strings.TrimLeft(strings.TrimSuffix(parsedURL.Path, ".git"), "/:")
	return host + path, nil
}
<commit_msg>[gitsync] Removing trailing slashes from URLs<commit_after>package git

import (
	"net/url"
	"strings"
)

// NormalizeURL strips everything from the URL except for the host and the path.
// A trailing ".git" is also stripped. The purpose is to allow for small
// variations in repo URL to be recognized as the same repo. The URL needs to
// contain a valid transport protocol, e.g. https, ssh.
// These URLs will all return 'github.com/skia-dev/textfiles':
//
//    "https://github.com/skia-dev/textfiles.git"
//    "ssh://git@github.com/skia-dev/textfiles"
//    "ssh://git@github.com:skia-dev/textfiles.git"
//
func NormalizeURL(inputURL string) (string, error) {
	parsedURL, err := url.Parse(inputURL)
	if err != nil {
		return "", err
	}

	// If the scheme is ssh we have to account for the scp-like syntax with a ':'
	host := parsedURL.Host
	if parsedURL.Scheme == "ssh" {
		host = strings.Replace(host, ":", "/", 1)
	}

	// Trim trailing slashes and the ".git" extension.
	path := strings.TrimRight(strings.TrimSuffix(parsedURL.Path, ".git"), "/")
	path = "/" + strings.TrimLeft(path, "/:")
	return host + path, nil
}
<|endoftext|>


<commit_before>package golisp

import "testing"

var testdata = []struct {
	expression []string
	result     []string
}{
	{[]string{"(+ 2 3)"}, []string{"5"}},
	{[]string{"(+ 1 6)"}, []string{"7"}},
	{[]string{"(oddp (+ 1 6))"}, []string{"t"}},
	{[]string{"(* 3 (+ 1 6))"}, []string{"21"}},
	{[]string{"(/ (* 2 11) (+ 1 6))"}, []string{"22/7"}},
	{[]string{"23"}, []string{"23"}},
	{[]string{"t"}, []string{"t"}},
	{[]string{"nil"}, []string{"nil"}},
	{[]string{"(equal (+ 7 5) (* 2 8))"}, []string{"nil"}},
	{[]string{"(/ (+ 6 8) 2.0)"}, []string{"7.0"}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8)"}, []string{"nil", "7.0"}},
	{[]string{"(defun square (n) (* n n))", "(square 2)"}, []string{"nil", "4"}},
	{[]string{"(defun total-cost (quantity price handling-charge) (+ (* quantity price) handling-charge))", "(total-cost 2 3 4)"}, []string{"nil", "10"}},
	{[]string{"pi"}, []string{"3.14159"}},
	{[]string{"(equal 'kirk 'spock)"}, []string{"nil"}},
	{[]string{"(list 'james t 'kirk)"}, []string{"(james t kirk)"}},
	{[]string{"(defun riddle (x y) (list 'why 'is 'a x 'like 'a y))", "(riddle 'raven 'writing-desk)"}, []string{"nil", "(why is a raven like a writing-desk)"}},
	{[]string{"(first (list 1 2 3))"}, []string{"1"}},
	{[]string{"(first '(we hold these truths))"}, []string{"we"}},
	{[]string{"'(+ 1 2)"}, []string{"(+ 1 2)"}},
	{[]string{"(oddp (+ 1 2))"}, []string{"t"}},
	{[]string{"(list 'a 'b 'c)"}, []string{"(a b c)"}},
	{[]string{"(cons 'a '(b c))"}, []string{"(a b c)"}},
	{[]string{"(+ 10 (- 5 2))"}, []string{"13"}},
	{[]string{"(list 'buy '(* 27 34) 'bagels)"}, []string{"(buy (* 27 34) bagels)"}},
	{[]string{"(list 'buy (* 27 34) 'bagels)"}, []string{"(buy 918 bagels)"}},
}

var baddata = []struct {
	expression []string
	fail       []bool
	message    []string
}{
	{[]string{"(1 2 3)"}, []bool{true}, []string{""}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8 7)"}, []bool{false, true}, []string{"", ""}},
	{[]string{"(equal kirk spock)"}, []bool{true}, []string{""}},
	{[]string{"(list kirk 1 2)"}, []bool{true}, []string{""}},
	{[]string{"(first (we hold these truths))"}, []bool{true}, []string{"Error! 'we' undefined function"}},
	{[]string{"(first 1 2 3 4)"}, []bool{true}, []string{""}},
	{[]string{"(oddp '(+ 1 2))"}, []bool{false}, []string{"Error! Wrong type input to oddp"}},
	{[]string{"(cons 'a (b c))"}, []bool{false}, []string{"Error! 'b' undefined function"}},
	{[]string{"(cons a (b c))"}, []bool{false}, []string{""}},
	{[]string{"(+ 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to +"}},
	{[]string{"(- 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to -"}},
	{[]string{"('foo 'bar 'baz)"}, []bool{false}, []string{"Error! 'foo' undefined function"}},
}

func TestGolispBad(t *testing.T) {
	for _, test := range baddata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			p, err := i.Eval(e.(Primitive))
			if test.fail[j] && err == nil {
				t.Errorf("Executing %v has not failed and it should have done: %v -> %v", e.str(), p, p.str())
			}
			if err != nil && test.message[j] != "" {
				if test.message[j] != err.Error() {
					t.Errorf("Error messages don't match %v vs %v", test.message[j], err.Error())
				}
			}
		}
	}
}

func TestGolisp(t *testing.T) {
	for _, test := range testdata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			r, err := i.Eval(e.(Primitive))
			if err != nil {
				t.Errorf("Executing %v has failed for %v", e.str(), err)
			} else if r.str() != test.result[j] {
				t.Errorf("%v did not lead to %v, it lead to %v", test.expression[j], test.result[j], r.str())
			}
		}
	}
}
<commit_msg>Added test for number 32. This closes #56.<commit_after>package golisp

import "testing"

var testdata = []struct {
	expression []string
	result     []string
}{
	{[]string{"(+ 2 3)"}, []string{"5"}},
	{[]string{"(+ 1 6)"}, []string{"7"}},
	{[]string{"(oddp (+ 1 6))"}, []string{"t"}},
	{[]string{"(* 3 (+ 1 6))"}, []string{"21"}},
	{[]string{"(/ (* 2 11) (+ 1 6))"}, []string{"22/7"}},
	{[]string{"23"}, []string{"23"}},
	{[]string{"t"}, []string{"t"}},
	{[]string{"nil"}, []string{"nil"}},
	{[]string{"(equal (+ 7 5) (* 2 8))"}, []string{"nil"}},
	{[]string{"(/ (+ 6 8) 2.0)"}, []string{"7.0"}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8)"}, []string{"nil", "7.0"}},
	{[]string{"(defun square (n) (* n n))", "(square 2)"}, []string{"nil", "4"}},
	{[]string{"(defun total-cost (quantity price handling-charge) (+ (* quantity price) handling-charge))", "(total-cost 2 3 4)"}, []string{"nil", "10"}},
	{[]string{"pi"}, []string{"3.14159"}},
	{[]string{"(equal 'kirk 'spock)"}, []string{"nil"}},
	{[]string{"(list 'james t 'kirk)"}, []string{"(james t kirk)"}},
	{[]string{"(defun riddle (x y) (list 'why 'is 'a x 'like 'a y))", "(riddle 'raven 'writing-desk)"}, []string{"nil", "(why is a raven like a writing-desk)"}},
	{[]string{"(first (list 1 2 3))"}, []string{"1"}},
	{[]string{"(first '(we hold these truths))"}, []string{"we"}},
	{[]string{"'(+ 1 2)"}, []string{"(+ 1 2)"}},
	{[]string{"(oddp (+ 1 2))"}, []string{"t"}},
	{[]string{"(list 'a 'b 'c)"}, []string{"(a b c)"}},
	{[]string{"(cons 'a '(b c))"}, []string{"(a b c)"}},
	{[]string{"(+ 10 (- 5 2))"}, []string{"13"}},
	{[]string{"(list 'buy '(* 27 34) 'bagels)"}, []string{"(buy (* 27 34) bagels)"}},
	{[]string{"(list 'buy (* 27 34) 'bagels)"}, []string{"(buy 918 bagels)"}},
	{[]string{"'(foo bar baz)"}, []string{"(foo bar baz)"}},
}

var baddata = []struct {
	expression []string
	fail       []bool
	message    []string
}{
	{[]string{"(1 2 3)"}, []bool{true}, []string{""}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8 7)"}, []bool{false, true}, []string{"", ""}},
	{[]string{"(equal kirk spock)"}, []bool{true}, []string{""}},
	{[]string{"(list kirk 1 2)"}, []bool{true}, []string{""}},
	{[]string{"(first (we hold these truths))"}, []bool{true}, []string{"Error! 'we' undefined function"}},
	{[]string{"(first 1 2 3 4)"}, []bool{true}, []string{""}},
	{[]string{"(oddp '(+ 1 2))"}, []bool{false}, []string{"Error! Wrong type input to oddp"}},
	{[]string{"(cons 'a (b c))"}, []bool{false}, []string{"Error! 'b' undefined function"}},
	{[]string{"(cons a (b c))"}, []bool{false}, []string{""}},
	{[]string{"(+ 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to +"}},
	{[]string{"(- 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to -"}},
	{[]string{"('foo 'bar 'baz)"}, []bool{false}, []string{"Error! 'foo' undefined function"}},
}

func TestGolispBad(t *testing.T) {
	for _, test := range baddata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			p, err := i.Eval(e.(Primitive))
			if test.fail[j] && err == nil {
				t.Errorf("Executing %v has not failed and it should have done: %v -> %v", e.str(), p, p.str())
			}
			if err != nil && test.message[j] != "" {
				if test.message[j] != err.Error() {
					t.Errorf("Error messages don't match %v vs %v", test.message[j], err.Error())
				}
			}
		}
	}
}

func TestGolisp(t *testing.T) {
	for _, test := range testdata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			r, err := i.Eval(e.(Primitive))
			if err != nil {
				t.Errorf("Executing %v has failed for %v", e.str(), err)
			} else if r.str() != test.result[j] {
				t.Errorf("%v did not lead to %v, it lead to %v", test.expression[j], test.result[j], r.str())
			}
		}
	}
}
<|endoftext|>


<commit_before>package gorocheck

import (
	"bufio"
	"bytes"
	"fmt"
	"reflect"
	"runtime"
	"strings"
)

var pkgName string

func init() {
	t := reflect.TypeOf(Goroutine{})
	parts := strings.Split(t.PkgPath(), "/")

	pkgName = parts[len(parts)-1]
}

type Goroutine struct {
	Function string
	Number   int
	Action   string
	Stack    []string
}

func funcNameFromStackLine(s string) string {
	parts := strings.Split(s, "(")
	s = parts[0]
	parts = strings.Split(s, "/")
	return parts[len(parts)-1]
}

func parseStack() []*Goroutine {
	stkbuf := make([]byte, 1000000)
	n := runtime.Stack(stkbuf, true)
	stkbuf = stkbuf[:n]

	var out []*Goroutine
	var cur *Goroutine
	scan := bufio.NewScanner(bytes.NewReader(stkbuf))
	for scan.Scan() {
		if strings.HasPrefix(scan.Text(), "goroutine") {
			parts := strings.Split(scan.Text(), " ")

			var num int
			fmt.Sscanf(parts[1], "%d", &num)

			if !scan.Scan() {
				panic("bad format")
			}

			fname := funcNameFromStackLine(scan.Text())

			g := &Goroutine{
				Number:   num,
				Function: fname,
				Stack:    []string{scan.Text()},
			}
			out = append(out, g)
			cur = g
		} else if cur != nil {
			cur.Stack = append(cur.Stack, scan.Text())
		}
	}
	return out
}

func filterSystemRoutines(gs []*Goroutine) []*Goroutine {
	sys := map[string]struct{}{
		"testing.RunTests":      struct{}{},
		pkgName + ".parseStack": struct{}{},
		"signal.loop":           struct{}{},
	}

	var out []*Goroutine
	for _, g := range gs {
		if _, found := sys[g.Function]; !found {
			out = append(out, g)
		}
	}
	return out
}

func CheckForLeaks(filter func(*Goroutine) bool) error {
	goros := filterSystemRoutines(parseStack())
	var gorosFiltered []*Goroutine
	if filter != nil {
		for _, g := range goros {
			if !filter(g) {
				gorosFiltered = append(gorosFiltered, g)
			}
		}
	}
	if len(goros) > 0 {
		return fmt.Errorf("had %d goroutines still running. First on list: %s", len(goros), goros[0].Stack)
	}
	return nil
}
<commit_msg>A couple fixes<commit_after>package gorocheck

import (
	"bufio"
	"bytes"
	"fmt"
	"reflect"
	"runtime"
	"strings"
)

var pkgName string

func init() {
	t := reflect.TypeOf(Goroutine{})
	parts := strings.Split(t.PkgPath(), "/")

	pkgName = parts[len(parts)-1]
}

type Goroutine struct {
	Function string
	Number   int
	Action   string
	Stack    []string
}

func funcNameFromStackLine(s string) string {
	parts := strings.Split(s, "(")
	s = parts[0]
	parts = strings.Split(s, "/")
	return parts[len(parts)-1]
}

func parseStack() []*Goroutine {
	stkbuf := make([]byte, 1000000)
	n := runtime.Stack(stkbuf, true)
	stkbuf = stkbuf[:n]

	var out []*Goroutine
	var cur *Goroutine
	scan := bufio.NewScanner(bytes.NewReader(stkbuf))
	for scan.Scan() {
		if strings.HasPrefix(scan.Text(), "goroutine") {
			parts := strings.Split(scan.Text(), " ")

			var num int
			fmt.Sscanf(parts[1], "%d", &num)

			if !scan.Scan() {
				panic("bad format")
			}

			fname := funcNameFromStackLine(scan.Text())

			g := &Goroutine{
				Number:   num,
				Function: fname,
				Stack:    []string{scan.Text()},
			}
			out = append(out, g)
			cur = g
		} else if cur != nil {
			cur.Stack = append(cur.Stack, scan.Text())
		}
	}
	return out
}

func filterSystemRoutines(gs []*Goroutine) []*Goroutine {
	sys := map[string]struct{}{
		"testing.RunTests":      struct{}{},
		pkgName + ".parseStack": struct{}{},
		"signal.loop":           struct{}{},
		"runtime.goexit":        struct{}{},
	}

	var out []*Goroutine
	for _, g := range gs {
		if _, found := sys[g.Function]; !found {
			out = append(out, g)
		}
	}
	return out
}

func CheckForLeaks(filter func(*Goroutine) bool) error {
	goros := filterSystemRoutines(parseStack())
	var gorosFiltered []*Goroutine
	if filter != nil {
		for _, g := range goros {
			if !filter(g) {
				gorosFiltered = append(gorosFiltered, g)
			}
		}
	}
	goros = gorosFiltered
	if len(goros) > 0 {
		return fmt.Errorf("had %d goroutines still running. First on list: %s", len(goros), goros[0].Stack)
	}
	return nil
}
<|endoftext|>


<commit_before>//
// Copyright 2020, Eric Stevens
//
// 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 gitlab

import (
	"fmt"
	"time"
)

// GroupHook represents a GitLab group hook.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
type GroupHook struct {
	ID                       int        `json:"id"`
	URL                      string     `json:"url"`
	GroupID                  int        `json:"group_id"`
	PushEvents               bool       `json:"push_events"`
	IssuesEvents             bool       `json:"issues_events"`
	ConfidentialIssuesEvents bool       `json:"confidential_issues_events"`
	ConfidentialNoteEvents   bool       `json:"confidential_note_events"`
	MergeRequestsEvents      bool       `json:"merge_requests_events"`
	TagPushEvents            bool       `json:"tag_push_events"`
	NoteEvents               bool       `json:"note_events"`
	JobEvents                bool       `json:"job_events"`
	PipelineEvents           bool       `json:"pipeline_events"`
	WikiPageEvents           bool       `json:"wiki_page_events"`
	EnableSSLVerification    bool       `json:"enable_ssl_verification"`
	CreatedAt                *time.Time `json:"created_at"`
}

// ListGroupHooks gets a list of group hooks.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
func (s *GroupsService) ListGroupHooks(gid interface{}) ([]*GroupHook, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))

	req, err := s.client.NewRequest("GET", u, nil, nil)
	if err != nil {
		return nil, nil, err
	}
	var gh []*GroupHook
	resp, err := s.client.Do(req, &gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// GetGroupHook gets a specific hook for a group.
//
// GitLab API docs:
// https://gitlab.com/help/api/groups.md#get-group-hook
func (s *GroupsService) GetGroupHook(pid interface{}, hook int, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	gh := &GroupHook{}
	resp, err := s.client.Do(req, gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// AddGroupHookOptions represents the available AddGroupHook() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
type AddGroupHookOptions struct {
	URL                      *string `url:"url,omitempty" json:"url,omitempty"`
	PushEvents               *bool   `url:"push_events,omitempty"  json:"push_events,omitempty"`
	IssuesEvents             *bool   `url:"issues_events,omitempty"  json:"issues_events,omitempty"`
	ConfidentialIssuesEvents *bool   `url:"confidential_issues_events,omitempty"  json:"confidential_issues_events,omitempty"`
	ConfidentialNoteEvents   *bool   `url:"confidential_note_events,omitempty"  json:"confidential_note_events,omitempty"`
	MergeRequestsEvents      *bool   `url:"merge_requests_events,omitempty"  json:"merge_requests_events,omitempty"`
	TagPushEvents            *bool   `url:"tag_push_events,omitempty"  json:"tag_push_events,omitempty"`
	NoteEvents               *bool   `url:"note_events,omitempty"  json:"note_events,omitempty"`
	JobEvents                *bool   `url:"job_events,omitempty"  json:"job_events,omitempty"`
	PipelineEvents           *bool   `url:"pipeline_events,omitempty"  json:"pipeline_events,omitempty"`
	WikiPageEvents           *bool   `url:"wiki_page_events,omitempty"  json:"wiki_page_events,omitempty"`
	EnableSSLVerification    *bool   `url:"enable_ssl_verification,omitempty"  json:"enable_ssl_verification,omitempty"`
	Token                    *string `url:"token,omitempty" json:"token,omitempty"`
}

// AddGroupHook create a new group scoped webhook.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
func (s *GroupsService) AddGroupHook(gid interface{}, opt *AddGroupHookOptions, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gh := new(GroupHook)
	resp, err := s.client.Do(req, gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// EditGroupHookOptions represents the available EditGroupHook() options.
//
// GitLab API docs:
// https://gitlab.com/help/api/groups.md#edit-group-hook
type EditGroupHookOptions struct {
	URL                      *string `url:"url,omitempty" json:"url,omitempty"`
	PushEvents               *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
	IssuesEvents             *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
	ConfidentialIssuesEvents *bool   `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
	ConfidentialNoteEvents   *bool   `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"`
	MergeRequestsEvents      *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
	TagPushEvents            *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
	NoteEvents               *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
	JobEvents                *bool   `url:"job_events,omitempty" json:"job_events,omitempty"`
	PipelineEvents           *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
	WikiPageEvents           *bool   `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
	EnableSSLVerification    *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
	Token                    *string `url:"token,omitempty" json:"token,omitempty"`
}

// EditGroupHook edits a hook for a specified group.
//
// Gitlab API docs:
// https://gitlab.com/help/api/groups.md#edit-group-hook
func (s *GroupsService) EditGroupHook(pid interface{}, hook int, opt *EditGroupHookOptions, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ph := &GroupHook{}
	resp, err := s.client.Do(req, ph)
	if err != nil {
		return nil, resp, err
	}

	return ph, resp, err
}

// DeleteGroupHook removes a hook from a group. This is an idempotent
// method and can be called multiple times. Either the hook is available or not.
//
// GitLab API docs:
// https://gitlab.com/help/api/groups.md#delete-group-hook
func (s *GroupsService) DeleteGroupHook(pid interface{}, hook int, options ...OptionFunc) (*Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>Update group_hooks.go<commit_after>//
// Copyright 2020, Eric Stevens
//
// 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 gitlab

import (
	"fmt"
	"time"
)

// GroupHook represents a GitLab group hook.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
type GroupHook struct {
	ID                       int        `json:"id"`
	URL                      string     `json:"url"`
	GroupID                  int        `json:"group_id"`
	PushEvents               bool       `json:"push_events"`
	IssuesEvents             bool       `json:"issues_events"`
	ConfidentialIssuesEvents bool       `json:"confidential_issues_events"`
	ConfidentialNoteEvents   bool       `json:"confidential_note_events"`
	MergeRequestsEvents      bool       `json:"merge_requests_events"`
	TagPushEvents            bool       `json:"tag_push_events"`
	NoteEvents               bool       `json:"note_events"`
	JobEvents                bool       `json:"job_events"`
	PipelineEvents           bool       `json:"pipeline_events"`
	WikiPageEvents           bool       `json:"wiki_page_events"`
	EnableSSLVerification    bool       `json:"enable_ssl_verification"`
	CreatedAt                *time.Time `json:"created_at"`
}

// ListGroupHooks gets a list of group hooks.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/groups.html#list-group-hooks
func (s *GroupsService) ListGroupHooks(gid interface{}) ([]*GroupHook, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))

	req, err := s.client.NewRequest("GET", u, nil, nil)
	if err != nil {
		return nil, nil, err
	}
	var gh []*GroupHook
	resp, err := s.client.Do(req, &gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// GetGroupHook gets a specific hook for a group.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/groups.html#get-group-hook
func (s *GroupsService) GetGroupHook(pid interface{}, hook int, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("GET", u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	gh := &GroupHook{}
	resp, err := s.client.Do(req, gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// AddGroupHookOptions represents the available AddGroupHook() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
type AddGroupHookOptions struct {
	URL                      *string `url:"url,omitempty" json:"url,omitempty"`
	PushEvents               *bool   `url:"push_events,omitempty"  json:"push_events,omitempty"`
	IssuesEvents             *bool   `url:"issues_events,omitempty"  json:"issues_events,omitempty"`
	ConfidentialIssuesEvents *bool   `url:"confidential_issues_events,omitempty"  json:"confidential_issues_events,omitempty"`
	ConfidentialNoteEvents   *bool   `url:"confidential_note_events,omitempty"  json:"confidential_note_events,omitempty"`
	MergeRequestsEvents      *bool   `url:"merge_requests_events,omitempty"  json:"merge_requests_events,omitempty"`
	TagPushEvents            *bool   `url:"tag_push_events,omitempty"  json:"tag_push_events,omitempty"`
	NoteEvents               *bool   `url:"note_events,omitempty"  json:"note_events,omitempty"`
	JobEvents                *bool   `url:"job_events,omitempty"  json:"job_events,omitempty"`
	PipelineEvents           *bool   `url:"pipeline_events,omitempty"  json:"pipeline_events,omitempty"`
	WikiPageEvents           *bool   `url:"wiki_page_events,omitempty"  json:"wiki_page_events,omitempty"`
	EnableSSLVerification    *bool   `url:"enable_ssl_verification,omitempty"  json:"enable_ssl_verification,omitempty"`
	Token                    *string `url:"token,omitempty" json:"token,omitempty"`
}

// AddGroupHook create a new group scoped webhook.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/groups.html#add-group-hook
func (s *GroupsService) AddGroupHook(gid interface{}, opt *AddGroupHookOptions, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks", pathEscape(group))

	req, err := s.client.NewRequest("POST", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	gh := new(GroupHook)
	resp, err := s.client.Do(req, gh)
	if err != nil {
		return nil, resp, err
	}

	return gh, resp, err
}

// EditGroupHookOptions represents the available EditGroupHook() options.
//
// GitLab API docs:
// https://gitlab.com/help/api/groups.md#edit-group-hook
type EditGroupHookOptions struct {
	URL                      *string `url:"url,omitempty" json:"url,omitempty"`
	PushEvents               *bool   `url:"push_events,omitempty" json:"push_events,omitempty"`
	IssuesEvents             *bool   `url:"issues_events,omitempty" json:"issues_events,omitempty"`
	ConfidentialIssuesEvents *bool   `url:"confidential_issues_events,omitempty" json:"confidential_issues_events,omitempty"`
	ConfidentialNoteEvents   *bool   `url:"confidential_note_events,omitempty" json:"confidential_note_events,omitempty"`
	MergeRequestsEvents      *bool   `url:"merge_requests_events,omitempty" json:"merge_requests_events,omitempty"`
	TagPushEvents            *bool   `url:"tag_push_events,omitempty" json:"tag_push_events,omitempty"`
	NoteEvents               *bool   `url:"note_events,omitempty" json:"note_events,omitempty"`
	JobEvents                *bool   `url:"job_events,omitempty" json:"job_events,omitempty"`
	PipelineEvents           *bool   `url:"pipeline_events,omitempty" json:"pipeline_events,omitempty"`
	WikiPageEvents           *bool   `url:"wiki_page_events,omitempty" json:"wiki_page_events,omitempty"`
	EnableSSLVerification    *bool   `url:"enable_ssl_verification,omitempty" json:"enable_ssl_verification,omitempty"`
	Token                    *string `url:"token,omitempty" json:"token,omitempty"`
}

// EditGroupHook edits a hook for a specified group.
//
// Gitlab API docs:
// https://gitlab.com/help/api/groups.md#edit-group-hook
func (s *GroupsService) EditGroupHook(pid interface{}, hook int, opt *EditGroupHookOptions, options ...OptionFunc) (*GroupHook, *Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("PUT", u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	ph := &GroupHook{}
	resp, err := s.client.Do(req, ph)
	if err != nil {
		return nil, resp, err
	}

	return ph, resp, err
}

// DeleteGroupHook removes a hook from a group. This is an idempotent
// method and can be called multiple times. Either the hook is available or not.
//
// GitLab API docs:
// https://gitlab.com/help/api/groups.md#delete-group-hook
func (s *GroupsService) DeleteGroupHook(pid interface{}, hook int, options ...OptionFunc) (*Response, error) {
	group, err := parseID(pid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/hooks/%d", pathEscape(group), hook)

	req, err := s.client.NewRequest("DELETE", u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package grpc

import (
	"context"
	"fmt"
	"net"
	"os"
	"os/signal"
	"reflect"
	"syscall"

	"github.com/fatih/structs"
	"github.com/swagchat/chat-api/logger"
	"github.com/swagchat/chat-api/utils"
	scpb "github.com/swagchat/protobuf"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

func unaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		workspace := ""
		// headers, ok := metadata.FromIncomingContext(ctx)
		// if ok {
		// 	if v, ok := headers[strings.ToLower(utils.HeaderWorkspace)]; ok {
		// 		if len(v) > 0 {
		// 			workspace = v[0]
		// 		}
		// 	}
		// }

		// if workspace == "" {
		r := reflect.ValueOf(req)
		if r.IsValid() {
			switch r.Kind() {
			case reflect.Ptr:
				if !r.IsNil() {
					fields := structs.Fields(req)
					for _, f := range fields {
						if f.Name() == "Workspace" {
							workspace = f.Value().(string)
						}
					}
				}
			}
		}
		// }

		if workspace == "" {
			workspace = utils.Config().Datastore.Database
		}

		ctx = context.WithValue(ctx, utils.CtxWorkspace, workspace)

		res, err := handler(ctx, req)
		if err != nil {
			return nil, err
		}

		return res, err
	}
}

// Run runs GRPC API server
func Run(ctx context.Context) {
	cfg := utils.Config()

	lis, err := net.Listen("tcp", fmt.Sprintf(":%s", cfg.GRPCPort))
	if err != nil {
		logger.Error(fmt.Sprintf("Failed to serve %s server[GRPC]. %v", utils.AppName, err))
	}

	ops := make([]grpc.ServerOption, 0)
	ops = append(ops, grpc.UnaryInterceptor(unaryServerInterceptor()))
	s := grpc.NewServer(ops...)
	logger.Info(fmt.Sprintf("Starting %s server[GRPC] on listen tcp :%s", utils.AppName, cfg.GRPCPort))

	scpb.RegisterChatIncomingServer(s, &chatIncomingServer{})
	scpb.RegisterRoomUserServiceServer(s, &roomUserServiceServer{})
	scpb.RegisterUserServiceServer(s, &userServiceServer{})
	scpb.RegisterUserRoleServiceServer(s, &userRoleServiceServer{})

	reflection.Register(s)

	signalChan := make(chan os.Signal)
	signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
	errCh := make(chan error)
	go func() {
		errCh <- s.Serve(lis)
	}()

	select {
	case <-ctx.Done():
		logger.Info(fmt.Sprintf("Stopping %s server[GRPC]", utils.AppName))
		s.GracefulStop()
	case signal := <-signalChan:
		if signal == syscall.SIGTERM || signal == syscall.SIGINT {
			logger.Info(fmt.Sprintf("Stopping %s server[GRPC]", utils.AppName))
			s.GracefulStop()
		}
	case err = <-errCh:
		logger.Error(fmt.Sprintf("Failed to serve %s server[GRPC]. %v", utils.AppName, err))
	}
}
<commit_msg>Update grpc server<commit_after>package grpc

import (
	"context"
	"fmt"
	"net"
	"os"
	"os/signal"
	"strings"
	"syscall"

	"github.com/swagchat/chat-api/logger"
	"github.com/swagchat/chat-api/utils"
	scpb "github.com/swagchat/protobuf"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/reflection"
)

func unaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		workspace := ""

		headers, ok := metadata.FromIncomingContext(ctx)
		if ok {
			if v, ok := headers[strings.ToLower(utils.HeaderWorkspace)]; ok {
				if len(v) > 0 {
					workspace = v[0]
				}
			}
		}

		if workspace == "" {
			workspace = utils.Config().Datastore.Database
		}

		ctx = context.WithValue(ctx, utils.CtxWorkspace, workspace)

		reply, err := handler(ctx, req)
		if err != nil {
			return nil, err
		}

		return reply, nil
	}
}

// Run runs GRPC API server
func Run(ctx context.Context) {
	cfg := utils.Config()

	lis, err := net.Listen("tcp", fmt.Sprintf(":%s", cfg.GRPCPort))
	if err != nil {
		logger.Error(fmt.Sprintf("Failed to serve %s server[GRPC]. %v", utils.AppName, err))
	}

	ops := []grpc.ServerOption{grpc.UnaryInterceptor(unaryServerInterceptor())}
	s := grpc.NewServer(ops...)
	logger.Info(fmt.Sprintf("Starting %s server[GRPC] on listen tcp :%s", utils.AppName, cfg.GRPCPort))

	scpb.RegisterChatIncomingServer(s, &chatIncomingServer{})
	scpb.RegisterRoomUserServiceServer(s, &roomUserServiceServer{})
	scpb.RegisterUserServiceServer(s, &userServiceServer{})
	scpb.RegisterUserRoleServiceServer(s, &userRoleServiceServer{})

	reflection.Register(s)

	signalChan := make(chan os.Signal)
	signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT)
	errCh := make(chan error)
	go func() {
		errCh <- s.Serve(lis)
	}()

	select {
	case <-ctx.Done():
		logger.Info(fmt.Sprintf("Stopping %s server[GRPC]", utils.AppName))
		s.GracefulStop()
	case signal := <-signalChan:
		if signal == syscall.SIGTERM || signal == syscall.SIGINT {
			logger.Info(fmt.Sprintf("Stopping %s server[GRPC]", utils.AppName))
			s.GracefulStop()
		}
	case err = <-errCh:
		logger.Error(fmt.Sprintf("Failed to serve %s server[GRPC]. %v", utils.AppName, err))
	}
}
<|endoftext|>