<commit_before>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package obcpbft

import (
	"reflect"
	"testing"
	"time"

	"github.com/hyperledger/fabric/consensus"
	pb "github.com/hyperledger/fabric/protos"

	"github.com/golang/protobuf/proto"
	"github.com/spf13/viper"
)

func (op *obcBatch) getPBFTCore() *pbftCore {
	return op.pbft
}

func obcBatchHelper(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
	// It's not entirely obvious why the compiler likes the parent function, but not newObcBatch directly
	return newObcBatch(id, config, stack)
}

func TestNetworkBatch(t *testing.T) {
	batchSize := 2
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, obcBatchHelper, func(ce *consumerEndpoint) {
		ce.consumer.(*obcBatch).batchSize = batchSize
	})
	defer net.stop()

	broadcaster := net.endpoints[generateBroadcaster(validatorCount)].getHandle()
	err := net.endpoints[1].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(1), broadcaster)
	if err != nil {
		t.Fatalf("External request was not processed by backup: %v", err)
	}

	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 1 {
		t.Fatalf("%d message expected in primary's batchStore, found %d", 1, l)
	}

	err = net.endpoints[2].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(2), broadcaster)
	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 0 {
		t.Fatalf("%d messages expected in primary's batchStore, found %d", 0, l)
	}

	for _, ep := range net.endpoints {
		ce := ep.(*consumerEndpoint)
		block, err := ce.consumer.(*obcBatch).stack.GetBlock(1)
		if nil != err {
			t.Fatalf("Replica %d executed requests, expected a new block on the chain, but could not retrieve it : %s", ce.id, err)
		}
		numTrans := len(block.Transactions)
		if numTrans != batchSize {
			t.Fatalf("Replica %d executed %d requests, expected %d",
				ce.id, numTrans, batchSize)
		}
		if numTxResults := len(block.NonHashData.TransactionResults); numTxResults != 1 /*numTrans*/ {
			t.Fatalf("Replica %d has %d txResults, expected %d", ce.id, numTxResults, numTrans)
		}
	}
}

func TestBatchCustody(t *testing.T) {
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, func(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
		config.Set("general.batchsize", "1")
		config.Set("general.timeout.batch", "250ms")
		if id == 0 {
			// Keep replica 0 from unnecessarilly advancing its view
			config.Set("general.timeout.request", "1500ms")
		} else {
			config.Set("general.timeout.request", "1000ms")
		}
		config.Set("general.timeout.viewchange", "800ms")
		return newObcBatch(id, config, stack)
	})
	defer net.stop()
	net.filterFn = func(src int, dst int, payload []byte) []byte {
		logger.Info("msg from %d to %d", src, dst)
		if src == 0 {
			return nil
		}
		return payload
	}

	// Submit two requests to replica 2, because vp0 is byzantine, they will not be processed until complaints triggers a view change
	// Once the complaints work, we should end up in view 1, with 2 blocks
	r2 := net.endpoints[2].(*consumerEndpoint).consumer
	r2.RecvMsg(createOcMsgWithChainTx(1), net.endpoints[1].getHandle())
	r2.RecvMsg(createOcMsgWithChainTx(2), net.endpoints[1].getHandle())

	//net.debug = true
	net.debugMsg("Stage 1\n")
	// Get the requests into the custody store, will return once vp2 complaints
	net.process()
	net.debugMsg("Stage 2\n")

	// Let the complaint timer expire for vp1/vp3
	time.Sleep(500 * time.Millisecond)

	// Process the new view and execute the requests
	net.process()
	net.debugMsg("Stage 3\n")

	// Let the complaint timer expire for the other request
	time.Sleep(500 * time.Millisecond)

	// Process the complaint, this time without view change
	net.process()
	net.debugMsg("Stage 4\n")

	for i, ep := range net.endpoints {

		b := ep.(*consumerEndpoint).consumer.(*obcBatch)

		if _, err := b.stack.GetBlock(2); nil != err {
			t.Errorf("Expected replica %d to have two blocks", i)
		} else {
			expectedView := uint64(1)
			if b.pbft.view != expectedView {
				t.Errorf("Expected replica %d to have two blocks and be in view %d", b.pbft.id, expectedView)
			}
		}
	}

}

func TestBatchStaleCustody(t *testing.T) {
	config := loadConfig()
	config.Set("general.batchsize", "1")
	config.Set("general.timeout.batch", "250ms")
	config.Set("general.timeout.request", "250ms")
	config.Set("general.timeout.viewchange", "800ms")

	var reqs []*Request
	stack := &omniProto{
		UnicastImpl: func(msg *pb.Message, p *pb.PeerID) error {
			m := &Message{}
			proto.Unmarshal(msg.Payload, m)
			if r := m.GetRequest(); r != nil {
				reqs = append(reqs, r)
			}
			return nil
		},
		BeginTxBatchImpl: func(id interface{}) error {
			return nil
		},
		ExecTxsImpl: func(id interface{}, txs []*pb.Transaction) ([]byte, error) {
			return nil, nil
		},
		CommitTxBatchImpl: func(id interface{}, meta []byte) (*pb.Block, error) {
			return nil, nil
		},
	}
	op := newObcBatch(1, config, stack)
	defer op.Close()

	req1 := createOcMsgWithChainTx(1)
	op.RecvMsg(req1, &pb.PeerID{})
	op.RecvMsg(createOcMsgWithChainTx(2), &pb.PeerID{})
	<-op.idleChannel()
	op.pbft.currentExec = new(uint64) // so that pbft.execDone doesn't get unhappy
	*op.pbft.currentExec = 1
	rblock2raw, _ := proto.Marshal(&RequestBlock{[]*Request{reqs[1]}})
	op.executeImpl(1, rblock2raw)
	time.Sleep(500 * time.Millisecond)
	<-op.idleChannel()

	if len(reqs) != 3 || !reflect.DeepEqual(reqs[2].Payload, req1.Payload) {
		t.Error("expected resubmitted request")
	}
}
<commit_msg>pbft/batch/test: stub out mock for occasional timing issues<commit_after>/*
Copyright IBM Corp. 2016 All Rights Reserved.

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

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

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

package obcpbft

import (
	"reflect"
	"testing"
	"time"

	"github.com/hyperledger/fabric/consensus"
	pb "github.com/hyperledger/fabric/protos"

	"github.com/golang/protobuf/proto"
	"github.com/spf13/viper"
)

func (op *obcBatch) getPBFTCore() *pbftCore {
	return op.pbft
}

func obcBatchHelper(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
	// It's not entirely obvious why the compiler likes the parent function, but not newObcBatch directly
	return newObcBatch(id, config, stack)
}

func TestNetworkBatch(t *testing.T) {
	batchSize := 2
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, obcBatchHelper, func(ce *consumerEndpoint) {
		ce.consumer.(*obcBatch).batchSize = batchSize
	})
	defer net.stop()

	broadcaster := net.endpoints[generateBroadcaster(validatorCount)].getHandle()
	err := net.endpoints[1].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(1), broadcaster)
	if err != nil {
		t.Fatalf("External request was not processed by backup: %v", err)
	}

	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 1 {
		t.Fatalf("%d message expected in primary's batchStore, found %d", 1, l)
	}

	err = net.endpoints[2].(*consumerEndpoint).consumer.RecvMsg(createOcMsgWithChainTx(2), broadcaster)
	net.process()

	if l := len(net.endpoints[0].(*consumerEndpoint).consumer.(*obcBatch).batchStore); l != 0 {
		t.Fatalf("%d messages expected in primary's batchStore, found %d", 0, l)
	}

	for _, ep := range net.endpoints {
		ce := ep.(*consumerEndpoint)
		block, err := ce.consumer.(*obcBatch).stack.GetBlock(1)
		if nil != err {
			t.Fatalf("Replica %d executed requests, expected a new block on the chain, but could not retrieve it : %s", ce.id, err)
		}
		numTrans := len(block.Transactions)
		if numTrans != batchSize {
			t.Fatalf("Replica %d executed %d requests, expected %d",
				ce.id, numTrans, batchSize)
		}
		if numTxResults := len(block.NonHashData.TransactionResults); numTxResults != 1 /*numTrans*/ {
			t.Fatalf("Replica %d has %d txResults, expected %d", ce.id, numTxResults, numTrans)
		}
	}
}

func TestBatchCustody(t *testing.T) {
	validatorCount := 4
	net := makeConsumerNetwork(validatorCount, func(id uint64, config *viper.Viper, stack consensus.Stack) pbftConsumer {
		config.Set("general.batchsize", "1")
		config.Set("general.timeout.batch", "250ms")
		if id == 0 {
			// Keep replica 0 from unnecessarilly advancing its view
			config.Set("general.timeout.request", "1500ms")
		} else {
			config.Set("general.timeout.request", "1000ms")
		}
		config.Set("general.timeout.viewchange", "800ms")
		return newObcBatch(id, config, stack)
	})
	defer net.stop()
	net.filterFn = func(src int, dst int, payload []byte) []byte {
		logger.Info("msg from %d to %d", src, dst)
		if src == 0 {
			return nil
		}
		return payload
	}

	// Submit two requests to replica 2, because vp0 is byzantine, they will not be processed until complaints triggers a view change
	// Once the complaints work, we should end up in view 1, with 2 blocks
	r2 := net.endpoints[2].(*consumerEndpoint).consumer
	r2.RecvMsg(createOcMsgWithChainTx(1), net.endpoints[1].getHandle())
	r2.RecvMsg(createOcMsgWithChainTx(2), net.endpoints[1].getHandle())

	//net.debug = true
	net.debugMsg("Stage 1\n")
	// Get the requests into the custody store, will return once vp2 complaints
	net.process()
	net.debugMsg("Stage 2\n")

	// Let the complaint timer expire for vp1/vp3
	time.Sleep(500 * time.Millisecond)

	// Process the new view and execute the requests
	net.process()
	net.debugMsg("Stage 3\n")

	// Let the complaint timer expire for the other request
	time.Sleep(500 * time.Millisecond)

	// Process the complaint, this time without view change
	net.process()
	net.debugMsg("Stage 4\n")

	for i, ep := range net.endpoints {

		b := ep.(*consumerEndpoint).consumer.(*obcBatch)

		if _, err := b.stack.GetBlock(2); nil != err {
			t.Errorf("Expected replica %d to have two blocks", i)
		} else {
			expectedView := uint64(1)
			if b.pbft.view != expectedView {
				t.Errorf("Expected replica %d to have two blocks and be in view %d", b.pbft.id, expectedView)
			}
		}
	}

}

func TestBatchStaleCustody(t *testing.T) {
	config := loadConfig()
	config.Set("general.batchsize", "1")
	config.Set("general.timeout.batch", "250ms")
	config.Set("general.timeout.request", "250ms")
	config.Set("general.timeout.viewchange", "800ms")

	var reqs []*Request
	stack := &omniProto{
		UnicastImpl: func(msg *pb.Message, p *pb.PeerID) error {
			m := &Message{}
			proto.Unmarshal(msg.Payload, m)
			if r := m.GetRequest(); r != nil {
				reqs = append(reqs, r)
			}
			return nil
		},
		BroadcastImpl: func(msg *pb.Message, pt pb.PeerEndpoint_Type) error {
			// we need this mock because occasionally the
			// custody timer for req3 goes off, and a
			// complaint is sent.
			return nil
		},
		BeginTxBatchImpl: func(id interface{}) error {
			return nil
		},
		ExecTxsImpl: func(id interface{}, txs []*pb.Transaction) ([]byte, error) {
			return nil, nil
		},
		CommitTxBatchImpl: func(id interface{}, meta []byte) (*pb.Block, error) {
			return nil, nil
		},
	}
	op := newObcBatch(1, config, stack)
	defer op.Close()

	req1 := createOcMsgWithChainTx(1)
	op.RecvMsg(req1, &pb.PeerID{})
	op.RecvMsg(createOcMsgWithChainTx(2), &pb.PeerID{})
	<-op.idleChannel()
	op.pbft.currentExec = new(uint64) // so that pbft.execDone doesn't get unhappy
	*op.pbft.currentExec = 1
	rblock2raw, _ := proto.Marshal(&RequestBlock{[]*Request{reqs[1]}})
	op.executeImpl(1, rblock2raw)
	time.Sleep(500 * time.Millisecond)
	<-op.idleChannel()

	if len(reqs) != 3 || !reflect.DeepEqual(reqs[2].Payload, req1.Payload) {
		t.Error("expected resubmitted request")
	}
}
<|endoftext|>


<commit_before>// Package kontrol provides an implementation for the name service kite.
// It can be queried to get the list of running kites.
package kontrol

import (
	"errors"
	"math/rand"
	"strings"
	"sync"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite"
	"github.com/koding/kite/config"
	"github.com/koding/kite/kitekey"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/nu7hatch/gouuid"
)

const (
	KontrolVersion = "0.0.4"
	KitesPrefix    = "/kites"
	TokenLeeway    = 1 * time.Minute
)

var (
	TokenTTL    = 48 * time.Hour
	DefaultPort = 4000

	tokenCache   = make(map[string]string)
	tokenCacheMu sync.Mutex

	// HeartbeatInterval is the interval in which kites are sending heartbeats
	HeartbeatInterval = time.Second * 30

	// HeartbeatDelay is the compensation interval which is added to the
	// heartbeat to avoid network delays
	HeartbeatDelay = time.Second * 10

	// UpdateInterval is the interval in which the key gets updated
	// periodically. Keeping it low increase the write load to the storage, so
	// be cautious when changing it.
	UpdateInterval = time.Second * 150

	// KeyTLL is the timeout in which a key expires. Each storage
	// implementation needs to set keys according to this Key. If a storage
	// doesn't support TTL mechanism (such as PostgreSQL), it should use a
	// background cleaner which cleans up keys that are KeyTTL old.
	KeyTTL = time.Second * 180
)

type Kontrol struct {
	Kite *kite.Kite

	// MachineAuthenticate is used to authenticate the request in the
	// "handleMachine" method.  The reason for a separate auth function is, the
	// request must not be authenticated because clients do not have a kite.key
	// before they register to this machine.
	MachineAuthenticate func(r *kite.Request) error

	// RSA keys
	publicKey  string // for validating tokens
	privateKey string // for signing tokens

	clientLocks *IdLock

	// storage defines the storage of the kites.
	storage Storage

	// RegisterURL defines the URL that is used to self register when adding
	// itself to the storage backend
	RegisterURL string

	log kite.Logger
}

// New creates a new kontrol instance with the given version and config
// instance. Publickey is used for validating tokens and privateKey is used for
// signing tokens.
//
// Public and private keys are RSA pem blocks that can be generated with the
// following command:
//     openssl genrsa -out testkey.pem 2048
//     openssl rsa -in testkey.pem -pubout > testkey_pub.pem
//
func New(conf *config.Config, version, publicKey, privateKey string) *Kontrol {
	k := kite.New("kontrol", version)
	k.Config = conf

	// Listen on 4000 by default
	if k.Config.Port == 0 {
		k.Config.Port = DefaultPort
	}

	kontrol := &Kontrol{
		Kite:        k,
		publicKey:   publicKey,
		privateKey:  privateKey,
		log:         k.Log,
		clientLocks: NewIdlock(),
	}

	k.HandleFunc("register", kontrol.handleRegister)
	k.HandleFunc("registerMachine", kontrol.handleMachine).DisableAuthentication()
	k.HandleFunc("getKites", kontrol.handleGetKites)
	k.HandleFunc("getToken", kontrol.handleGetToken)

	return kontrol
}

func (k *Kontrol) AddAuthenticator(keyType string, fn func(*kite.Request) error) {
	k.Kite.Authenticators[keyType] = fn
}

func (k *Kontrol) Run() {
	rand.Seed(time.Now().UnixNano())

	if k.storage == nil {
		panic("kontrol storage is not set")
	}

	// now go and register ourself
	go k.registerSelf()

	k.Kite.Run()
}

// SetStorage sets the backend storage that kontrol is going to use to store
// kites
func (k *Kontrol) SetStorage(storage Storage) {
	k.storage = storage
}

// Close stops kontrol and closes all connections
func (k *Kontrol) Close() {
	k.Kite.Close()
}

// InitializeSelf registers his host by writing a key to ~/.kite/kite.key
func (k *Kontrol) InitializeSelf() error {
	key, err := k.registerUser(k.Kite.Config.Username)
	if err != nil {
		return err
	}
	return kitekey.Write(key)
}

func (k *Kontrol) registerUser(username string) (kiteKey string, err error) {
	// Only accept requests of type machine
	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("cannot generate a token")
	}

	token := jwt.New(jwt.GetSigningMethod("RS256"))

	token.Claims = map[string]interface{}{
		"iss":        k.Kite.Kite().Username,         // Issuer
		"sub":        username,                       // Subject
		"iat":        time.Now().UTC().Unix(),        // Issued At
		"jti":        tknID.String(),                 // JWT ID
		"kontrolURL": k.Kite.Config.KontrolURL,       // Kontrol URL
		"kontrolKey": strings.TrimSpace(k.publicKey), // Public key of kontrol
	}

	k.Kite.Log.Info("Registered machine on user: %s", username)

	return token.SignedString([]byte(k.privateKey))
}

// registerSelf adds Kontrol itself to the storage as a kite.
func (k *Kontrol) registerSelf() {
	value := &kontrolprotocol.RegisterValue{
		URL: k.Kite.Config.KontrolURL,
	}

	// change if the user wants something different
	if k.RegisterURL != "" {
		value.URL = k.RegisterURL
	}

	// Register first by adding the value to the storage. We don't return any
	// error because we need to know why kontrol doesn't register itself
	if err := k.storage.Add(k.Kite.Kite(), value); err != nil {
		k.log.Error(err.Error())
	}

	for {
		if err := k.storage.Update(k.Kite.Kite(), value); err != nil {
			k.log.Error(err.Error())
			time.Sleep(time.Second)
			continue
		}

		time.Sleep(HeartbeatDelay + HeartbeatInterval)
	}
}

// generateToken returns a JWT token string. Please see the URL for details:
// http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1
func generateToken(aud, username, issuer, privateKey string) (string, error) {
	tokenCacheMu.Lock()
	defer tokenCacheMu.Unlock()

	uniqKey := aud + username + issuer // neglect privateKey, its always the same
	signed, ok := tokenCache[uniqKey]
	if ok {
		return signed, nil
	}

	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("Server error: Cannot generate a token")
	}

	// Identifies the expiration time after which the JWT MUST NOT be accepted
	// for processing.
	ttl := TokenTTL

	// Implementers MAY provide for some small leeway, usually no more than
	// a few minutes, to account for clock skew.
	leeway := TokenLeeway

	tkn := jwt.New(jwt.GetSigningMethod("RS256"))
	tkn.Claims["iss"] = issuer                                       // Issuer
	tkn.Claims["sub"] = username                                     // Subject
	tkn.Claims["aud"] = aud                                          // Audience
	tkn.Claims["exp"] = time.Now().UTC().Add(ttl).Add(leeway).Unix() // Expiration Time
	tkn.Claims["nbf"] = time.Now().UTC().Add(-leeway).Unix()         // Not Before
	tkn.Claims["iat"] = time.Now().UTC().Unix()                      // Issued At
	tkn.Claims["jti"] = tknID.String()                               // JWT ID

	signed, err = tkn.SignedString([]byte(privateKey))
	if err != nil {
		return "", errors.New("Server error: Cannot generate a token")
	}

	// cache our token
	tokenCache[uniqKey] = signed

	// cache invalidation, because we cache the token in tokenCache we need to
	// invalidate it expiration time. This was handled usually within JWT, but
	// now we have to do it manually for our own cache.
	time.AfterFunc(TokenTTL, func() {
		tokenCacheMu.Lock()
		defer tokenCacheMu.Unlock()

		delete(tokenCache, uniqKey)
	})

	return signed, nil
}
<commit_msg>kontrol/kontrol: decrease the heartbeat<commit_after>// Package kontrol provides an implementation for the name service kite.
// It can be queried to get the list of running kites.
package kontrol

import (
	"errors"
	"math/rand"
	"strings"
	"sync"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/koding/kite"
	"github.com/koding/kite/config"
	"github.com/koding/kite/kitekey"
	kontrolprotocol "github.com/koding/kite/kontrol/protocol"
	"github.com/nu7hatch/gouuid"
)

const (
	KontrolVersion = "0.0.4"
	KitesPrefix    = "/kites"
	TokenLeeway    = 1 * time.Minute
)

var (
	TokenTTL    = 48 * time.Hour
	DefaultPort = 4000

	tokenCache   = make(map[string]string)
	tokenCacheMu sync.Mutex

	// HeartbeatInterval is the interval in which kites are sending heartbeats
	HeartbeatInterval = time.Second * 10

	// HeartbeatDelay is the compensation interval which is added to the
	// heartbeat to avoid network delays
	HeartbeatDelay = time.Second * 10

	// UpdateInterval is the interval in which the key gets updated
	// periodically. Keeping it low increase the write load to the storage, so
	// be cautious when changing it.
	UpdateInterval = time.Second * 150

	// KeyTLL is the timeout in which a key expires. Each storage
	// implementation needs to set keys according to this Key. If a storage
	// doesn't support TTL mechanism (such as PostgreSQL), it should use a
	// background cleaner which cleans up keys that are KeyTTL old.
	KeyTTL = time.Second * 180
)

type Kontrol struct {
	Kite *kite.Kite

	// MachineAuthenticate is used to authenticate the request in the
	// "handleMachine" method.  The reason for a separate auth function is, the
	// request must not be authenticated because clients do not have a kite.key
	// before they register to this machine.
	MachineAuthenticate func(r *kite.Request) error

	// RSA keys
	publicKey  string // for validating tokens
	privateKey string // for signing tokens

	clientLocks *IdLock

	// storage defines the storage of the kites.
	storage Storage

	// RegisterURL defines the URL that is used to self register when adding
	// itself to the storage backend
	RegisterURL string

	log kite.Logger
}

// New creates a new kontrol instance with the given version and config
// instance. Publickey is used for validating tokens and privateKey is used for
// signing tokens.
//
// Public and private keys are RSA pem blocks that can be generated with the
// following command:
//     openssl genrsa -out testkey.pem 2048
//     openssl rsa -in testkey.pem -pubout > testkey_pub.pem
//
func New(conf *config.Config, version, publicKey, privateKey string) *Kontrol {
	k := kite.New("kontrol", version)
	k.Config = conf

	// Listen on 4000 by default
	if k.Config.Port == 0 {
		k.Config.Port = DefaultPort
	}

	kontrol := &Kontrol{
		Kite:        k,
		publicKey:   publicKey,
		privateKey:  privateKey,
		log:         k.Log,
		clientLocks: NewIdlock(),
	}

	k.HandleFunc("register", kontrol.handleRegister)
	k.HandleFunc("registerMachine", kontrol.handleMachine).DisableAuthentication()
	k.HandleFunc("getKites", kontrol.handleGetKites)
	k.HandleFunc("getToken", kontrol.handleGetToken)

	return kontrol
}

func (k *Kontrol) AddAuthenticator(keyType string, fn func(*kite.Request) error) {
	k.Kite.Authenticators[keyType] = fn
}

func (k *Kontrol) Run() {
	rand.Seed(time.Now().UnixNano())

	if k.storage == nil {
		panic("kontrol storage is not set")
	}

	// now go and register ourself
	go k.registerSelf()

	k.Kite.Run()
}

// SetStorage sets the backend storage that kontrol is going to use to store
// kites
func (k *Kontrol) SetStorage(storage Storage) {
	k.storage = storage
}

// Close stops kontrol and closes all connections
func (k *Kontrol) Close() {
	k.Kite.Close()
}

// InitializeSelf registers his host by writing a key to ~/.kite/kite.key
func (k *Kontrol) InitializeSelf() error {
	key, err := k.registerUser(k.Kite.Config.Username)
	if err != nil {
		return err
	}
	return kitekey.Write(key)
}

func (k *Kontrol) registerUser(username string) (kiteKey string, err error) {
	// Only accept requests of type machine
	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("cannot generate a token")
	}

	token := jwt.New(jwt.GetSigningMethod("RS256"))

	token.Claims = map[string]interface{}{
		"iss":        k.Kite.Kite().Username,         // Issuer
		"sub":        username,                       // Subject
		"iat":        time.Now().UTC().Unix(),        // Issued At
		"jti":        tknID.String(),                 // JWT ID
		"kontrolURL": k.Kite.Config.KontrolURL,       // Kontrol URL
		"kontrolKey": strings.TrimSpace(k.publicKey), // Public key of kontrol
	}

	k.Kite.Log.Info("Registered machine on user: %s", username)

	return token.SignedString([]byte(k.privateKey))
}

// registerSelf adds Kontrol itself to the storage as a kite.
func (k *Kontrol) registerSelf() {
	value := &kontrolprotocol.RegisterValue{
		URL: k.Kite.Config.KontrolURL,
	}

	// change if the user wants something different
	if k.RegisterURL != "" {
		value.URL = k.RegisterURL
	}

	// Register first by adding the value to the storage. We don't return any
	// error because we need to know why kontrol doesn't register itself
	if err := k.storage.Add(k.Kite.Kite(), value); err != nil {
		k.log.Error(err.Error())
	}

	for {
		if err := k.storage.Update(k.Kite.Kite(), value); err != nil {
			k.log.Error(err.Error())
			time.Sleep(time.Second)
			continue
		}

		time.Sleep(HeartbeatDelay + HeartbeatInterval)
	}
}

// generateToken returns a JWT token string. Please see the URL for details:
// http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13#section-4.1
func generateToken(aud, username, issuer, privateKey string) (string, error) {
	tokenCacheMu.Lock()
	defer tokenCacheMu.Unlock()

	uniqKey := aud + username + issuer // neglect privateKey, its always the same
	signed, ok := tokenCache[uniqKey]
	if ok {
		return signed, nil
	}

	tknID, err := uuid.NewV4()
	if err != nil {
		return "", errors.New("Server error: Cannot generate a token")
	}

	// Identifies the expiration time after which the JWT MUST NOT be accepted
	// for processing.
	ttl := TokenTTL

	// Implementers MAY provide for some small leeway, usually no more than
	// a few minutes, to account for clock skew.
	leeway := TokenLeeway

	tkn := jwt.New(jwt.GetSigningMethod("RS256"))
	tkn.Claims["iss"] = issuer                                       // Issuer
	tkn.Claims["sub"] = username                                     // Subject
	tkn.Claims["aud"] = aud                                          // Audience
	tkn.Claims["exp"] = time.Now().UTC().Add(ttl).Add(leeway).Unix() // Expiration Time
	tkn.Claims["nbf"] = time.Now().UTC().Add(-leeway).Unix()         // Not Before
	tkn.Claims["iat"] = time.Now().UTC().Unix()                      // Issued At
	tkn.Claims["jti"] = tknID.String()                               // JWT ID

	signed, err = tkn.SignedString([]byte(privateKey))
	if err != nil {
		return "", errors.New("Server error: Cannot generate a token")
	}

	// cache our token
	tokenCache[uniqKey] = signed

	// cache invalidation, because we cache the token in tokenCache we need to
	// invalidate it expiration time. This was handled usually within JWT, but
	// now we have to do it manually for our own cache.
	time.AfterFunc(TokenTTL, func() {
		tokenCacheMu.Lock()
		defer tokenCacheMu.Unlock()

		delete(tokenCache, uniqKey)
	})

	return signed, nil
}
<|endoftext|>


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

package caddypki

import (
	"fmt"

	"github.com/caddyserver/caddy/v2"
	"github.com/smallstep/truststore"
	"go.uber.org/zap"
)

func init() {
	caddy.RegisterModule(PKI{})
}

// PKI provides Public Key Infrastructure facilities for Caddy.
type PKI struct {
	// The CAs to manage. Each CA is keyed by an ID that is used
	// to uniquely identify it from other CAs. The default CA ID
	// is "local".
	CAs map[string]*CA `json:"certificate_authorities,omitempty"`

	ctx caddy.Context
	log *zap.Logger
}

// CaddyModule returns the Caddy module information.
func (PKI) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "pki",
		New: func() caddy.Module { return new(PKI) },
	}
}

// Provision sets up the configuration for the PKI app.
func (p *PKI) Provision(ctx caddy.Context) error {
	p.ctx = ctx
	p.log = ctx.Logger(p)

	// if this app is initialized at all, ensure there's
	// at least a default CA that can be used
	if len(p.CAs) == 0 {
		p.CAs = map[string]*CA{defaultCAID: new(CA)}
	}

	for caID, ca := range p.CAs {
		err := ca.Provision(ctx, caID, p.log)
		if err != nil {
			return fmt.Errorf("provisioning CA '%s': %v", caID, err)
		}
	}

	return nil
}

// Start starts the PKI app.
func (p *PKI) Start() error {
	// install roots to trust store, if not disabled
	for _, ca := range p.CAs {
		if ca.InstallTrust != nil && !*ca.InstallTrust {
			ca.log.Warn("root certificate trust store installation disabled; local clients may show warnings",
				zap.String("path", ca.rootCertPath))
			continue
		}

		// avoid password prompt if already trusted
		if trusted(ca.root) {
			ca.log.Info("root certificate is already trusted by system",
				zap.String("path", ca.rootCertPath))
			continue
		}

		ca.log.Warn("trusting root certificate (you might be prompted for password)",
			zap.String("path", ca.rootCertPath))

		err := truststore.Install(ca.root,
			truststore.WithDebug(),
			truststore.WithFirefox(),
			truststore.WithJava(),
		)
		if err != nil {
			return fmt.Errorf("adding root certificate to trust store: %v", err)
		}
	}

	// see if root/intermediates need renewal...
	p.renewCerts()

	// ...and keep them renewed
	go p.maintenance()

	return nil
}

// Stop stops the PKI app.
func (p *PKI) Stop() error {
	return nil
}

// Interface guards
var (
	_ caddy.Provisioner = (*PKI)(nil)
	_ caddy.App         = (*PKI)(nil)
)
<commit_msg>pki: Don't treat cert installation failure as error<commit_after>// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package caddypki

import (
	"fmt"

	"github.com/caddyserver/caddy/v2"
	"github.com/smallstep/truststore"
	"go.uber.org/zap"
)

func init() {
	caddy.RegisterModule(PKI{})
}

// PKI provides Public Key Infrastructure facilities for Caddy.
type PKI struct {
	// The CAs to manage. Each CA is keyed by an ID that is used
	// to uniquely identify it from other CAs. The default CA ID
	// is "local".
	CAs map[string]*CA `json:"certificate_authorities,omitempty"`

	ctx caddy.Context
	log *zap.Logger
}

// CaddyModule returns the Caddy module information.
func (PKI) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "pki",
		New: func() caddy.Module { return new(PKI) },
	}
}

// Provision sets up the configuration for the PKI app.
func (p *PKI) Provision(ctx caddy.Context) error {
	p.ctx = ctx
	p.log = ctx.Logger(p)

	// if this app is initialized at all, ensure there's
	// at least a default CA that can be used
	if len(p.CAs) == 0 {
		p.CAs = map[string]*CA{defaultCAID: new(CA)}
	}

	for caID, ca := range p.CAs {
		err := ca.Provision(ctx, caID, p.log)
		if err != nil {
			return fmt.Errorf("provisioning CA '%s': %v", caID, err)
		}
	}

	return nil
}

// Start starts the PKI app.
func (p *PKI) Start() error {
	// install roots to trust store, if not disabled
	for _, ca := range p.CAs {
		if ca.InstallTrust != nil && !*ca.InstallTrust {
			ca.log.Warn("root certificate trust store installation disabled; local clients may show warnings",
				zap.String("path", ca.rootCertPath))
			continue
		}

		// avoid password prompt if already trusted
		if trusted(ca.root) {
			ca.log.Info("root certificate is already trusted by system",
				zap.String("path", ca.rootCertPath))
			continue
		}

		ca.log.Warn("trusting root certificate (you might be prompted for password)",
			zap.String("path", ca.rootCertPath))

		err := truststore.Install(ca.root,
			truststore.WithDebug(),
			truststore.WithFirefox(),
			truststore.WithJava(),
		)
		if err != nil {
			// could be some system dependencies that are missing;
			// shouldn't totally prevent startup, but we should log it
			p.log.Error("failed to install root certificate",
				zap.Error(err),
				zap.String("certificate_file", ca.rootCertPath))
		}
	}

	// see if root/intermediates need renewal...
	p.renewCerts()

	// ...and keep them renewed
	go p.maintenance()

	return nil
}

// Stop stops the PKI app.
func (p *PKI) Stop() error {
	return nil
}

// Interface guards
var (
	_ caddy.Provisioner = (*PKI)(nil)
	_ caddy.App         = (*PKI)(nil)
)
<|endoftext|>


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

package gopmod

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/goplus/gop/token"
	"github.com/goplus/gop/x/mod/modfile"
	"github.com/goplus/gop/x/mod/modload"
	"golang.org/x/mod/module"
)

// -----------------------------------------------------------------------------

type Module struct {
	modload.Module
	classes map[string]*modfile.Classfile
	vers    map[string]module.Version
	gengo   func(act string, mod module.Version)
	fset    *token.FileSet
}

func New(mod modload.Module) *Module {
	classes := make(map[string]*modfile.Classfile)
	vers := mod.Deps()
	fset := token.NewFileSet()
	return &Module{classes: classes, vers: vers, Module: mod, fset: fset}
}

func Load(dir string) (*Module, error) {
	mod, err := modload.Load(dir)
	if err != nil {
		return nil, err
	}
	return New(mod), nil
}

func (p *Module) SetGenGo(gengo func(act string, mod module.Version)) {
	p.gengo = gengo
}

func (p *Module) Imports(dir string) (imps []string, err error) {
	imports := make(map[string]struct{})
	err = p.parseImports(imports, dir)
	imps = getKeys(imports)
	return
}

func getKeys(v map[string]struct{}) []string {
	keys := make([]string, 0, len(v))
	for key := range v {
		keys = append(keys, key)
	}
	return keys
}

func (p *Module) parseImports(imports map[string]struct{}, dir string) (err error) {
	list, err := os.ReadDir(dir)
	if err != nil {
		return
	}
	var errs ErrorList
	for _, d := range list {
		if d.IsDir() {
			continue
		}
		fname := d.Name()
		ext := filepath.Ext(fname)
		switch ext {
		case ".gop":
			p.parseGopImport(&errs, imports, filepath.Join(dir, fname))
		case ".go":
			if !strings.HasPrefix(fname, "gop_autogen") {
				p.parseGoImport(&errs, imports, filepath.Join(dir, fname))
			}
		default:
			if c, ok := p.classes[ext]; ok {
				for _, pkgPath := range c.PkgPaths {
					imports[pkgPath] = struct{}{}
				}
				p.parseGopImport(&errs, imports, filepath.Join(dir, fname))
			}
		}
	}
	if len(errs) > 0 {
		err = errs
	}
	return
}

// -----------------------------------------------------------------------------

type ErrorList []error

func (e ErrorList) Error() string {
	errStrs := make([]string, len(e))
	for i, err := range e {
		errStrs[i] = err.Error()
	}
	return strings.Join(errStrs, "\n")
}

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

package gopmod

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/goplus/gop/token"
	"github.com/goplus/gop/x/mod/modfile"
	"github.com/goplus/gop/x/mod/modload"
	"golang.org/x/mod/module"
)

// -----------------------------------------------------------------------------

type Module struct {
	modload.Module
	classes map[string]*modfile.Classfile
	vers    map[string]module.Version
	gengo   func(act string, mod module.Version)
	fset    *token.FileSet
}

func New(mod modload.Module) *Module {
	classes := make(map[string]*modfile.Classfile)
	vers := mod.Deps()
	fset := token.NewFileSet()
	return &Module{classes: classes, vers: vers, Module: mod, fset: fset}
}

func Load(dir string) (*Module, error) {
	mod, err := modload.Load(dir)
	if err != nil {
		return nil, err
	}
	return New(mod), nil
}

func (p *Module) SetGenGo(gengo func(act string, mod module.Version)) {
	p.gengo = gengo
}

func (p *Module) Imports(dir string, recursive bool) (imps []string, err error) {
	imports := make(map[string]struct{})
	err = p.parseImports(imports, dir, recursive)
	imps = getKeys(imports)
	return
}

func getKeys(v map[string]struct{}) []string {
	keys := make([]string, 0, len(v))
	for key := range v {
		keys = append(keys, key)
	}
	return keys
}

func (p *Module) parseImports(imports map[string]struct{}, dir string, recursive bool) (err error) {
	list, err := os.ReadDir(dir)
	if err != nil {
		return
	}
	var errs ErrorList
	for _, d := range list {
		fname := d.Name()
		if d.IsDir() {
			if recursive {
				p.parseImports(imports, filepath.Join(dir, fname), true)
			}
			continue
		}
		ext := filepath.Ext(fname)
		switch ext {
		case ".gop":
			p.parseGopImport(&errs, imports, filepath.Join(dir, fname))
		case ".go":
			if !strings.HasPrefix(fname, "gop_autogen") {
				p.parseGoImport(&errs, imports, filepath.Join(dir, fname))
			}
		default:
			if c, ok := p.classes[ext]; ok {
				for _, pkgPath := range c.PkgPaths {
					imports[pkgPath] = struct{}{}
				}
				p.parseGopImport(&errs, imports, filepath.Join(dir, fname))
			}
		}
	}
	if len(errs) > 0 {
		err = errs
	}
	return
}

// -----------------------------------------------------------------------------

type ErrorList []error

func (e ErrorList) Error() string {
	errStrs := make([]string, len(e))
	for i, err := range e {
		errStrs[i] = err.Error()
	}
	return strings.Join(errStrs, "\n")
}

// -----------------------------------------------------------------------------
<|endoftext|>


<commit_before>package profile

import (
	"fmt"
	"testing"
)

func TestStrData(t *testing.T) {
	_ = StrData(10)
}

func TestData(t *testing.T) {
	_ = Data(10)
}

var benchs = []int{100} //, 1000, 10000}

func BenchmarkData(b *testing.B) {
	var name string
	for _, tt := range benchs {

		name = fmt.Sprintf("Data(%d)", tt)
		b.Run(name, func(b *testing.B) {
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				_ = Data(tt)
			}
		})

		name = fmt.Sprintf("StrData(%d)", tt)
		b.Run(name, func(b *testing.B) {
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				_ = StrData(tt)
			}
		})
	}
}
<commit_msg>profile: fix tests order<commit_after>package profile

import (
	"fmt"
	"testing"
)

func TestData(t *testing.T) {
	_ = Data(10)
}

func TestStrData(t *testing.T) {
	_ = StrData(10)
}

var benchs = []int{100} //, 1000, 10000}

func BenchmarkData(b *testing.B) {
	var name string
	for _, tt := range benchs {

		name = fmt.Sprintf("Data(%d)", tt)
		b.Run(name, func(b *testing.B) {
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				_ = Data(tt)
			}
		})

		name = fmt.Sprintf("StrData(%d)", tt)
		b.Run(name, func(b *testing.B) {
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				_ = StrData(tt)
			}
		})

	}
}
<|endoftext|>


<commit_before>package main

import (
	"sync"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/driver-go-blecombined/bluez"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-ninja/suit"
)

var btinfo = ninja.LoadModuleInfo("./bletag-package.json")
var btlog = logger.GetLogger("driver-go-bletag")

type BLETagDriver struct {
	conn       *ninja.Connection
	sendEvent  func(event string, payload interface{}) error
	gattClient *gatt.Client
	running    bool
	FoundTags  map[string]bool
	lkConfig   sync.Mutex
	Config     *Config
}

func NewBLETagDriver(client *gatt.Client) (*BLETagDriver, error) {

	conn, err := ninja.Connect("BLETag")

	if err != nil {
		btlog.Fatalf("Failed to create BLE tag driver: %s", err)
		return nil, err
	}

	driver := &BLETagDriver{
		conn:       conn,
		gattClient: client,
		running:    true,
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		btlog.Fatalf("Failed to export BLE tag driver: %s", err)
		return nil, err
	}

	driver.FoundTags = make(map[string]bool)

	return driver, nil
}

func (d *BLETagDriver) Configure(request *model.ConfigurationRequest) (*suit.ConfigurationScreen, error) {
	log.Infof("Incoming configuration request. Action:%s Data:%s", request.Action, string(request.Data))

	return nil, nil
}

func (d *BLETagDriver) GetModuleInfo() *model.Module {
	return btinfo
}

func (d *BLETagDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (fp *BLETagDriver) Start(config *Config) error {
	btlog.Infof(spew.Sprintf("Starting BLE tag driver %v", config))
	fp.Config = config

	for _, tagConfig := range fp.Config.BleTags {
		NewBLETagFromConfig(fp, tagConfig)
	}

	fp.running = true
	return nil
}

func (fp *BLETagDriver) Stop() error {
	fp.running = false
	return nil
}

func (fp *BLETagDriver) saveNewTag(address string, publicAddress bool, readChar *bluez.Characteristic, alertChar *bluez.Characteristic) {

	fp.lkConfig.Lock()

	defer fp.lkConfig.Unlock()

	btlog.Debugf(spew.Sprintf("saveNewTag %s %t %#v %#v", address, publicAddress, readChar, alertChar))

	bleConfig := &BleTagConfig{
		Address:              address,
		PublicAddress:        publicAddress,
		ReadUUID:             readChar.UUID,
		ReadHandle:           readChar.Handle,
		ReadCharValueHandle:  readChar.CharValueHandle,
		AlertUUID:            alertChar.UUID,
		AlertHandle:          alertChar.Handle,
		AlertCharValueHandle: alertChar.CharValueHandle,
	}

	// replace in the list
	for i, bleTag := range fp.Config.BleTags {
		if bleTag.Address == bleConfig.Address {
			// delete that entry
			fp.Config.BleTags = append(fp.Config.BleTags[:i], fp.Config.BleTags[i+1:]...)
		}
	}

	// apend to the configuration
	fp.Config.BleTags = append(fp.Config.BleTags, bleConfig)

	btlog.Infof("saving configuration %#v", fp.Config)

	err := fp.sendEvent("config", fp.Config)

	if err != nil {
		btlog.Errorf("Error saving configuration: %s", err)
	}
}

// Config is persisted by HomeCloud, and provided when the app starts.
type Config struct {
	BleTags []*BleTagConfig `json:"bleTags"`
}

// BleTagConfig is persisted by HomeCloud, and provided when the app starts.
type BleTagConfig struct {
	Address       string `json:"address"`
	PublicAddress bool   `json:"publicAddress"`

	ReadUUID            string `json:"readUUID"`
	ReadHandle          string `json:"readHandle"`
	ReadCharValueHandle string `json:"readCharValueHandle"`

	AlertUUID            string `json:"alertUUID"`
	AlertHandle          string `json:"alertHandle"`
	AlertCharValueHandle string `json:"alertCharValueHandle"`
}
<commit_msg>fix: Resloved configuration update related bug.<commit_after>package main

import (
	"sync"

	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/driver-go-blecombined/bluez"
	"github.com/ninjasphere/gatt"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-ninja/suit"
)

var btinfo = ninja.LoadModuleInfo("./bletag-package.json")
var btlog = logger.GetLogger("driver-go-bletag")

type BLETagDriver struct {
	conn       *ninja.Connection
	sendEvent  func(event string, payload interface{}) error
	gattClient *gatt.Client
	running    bool
	FoundTags  map[string]bool
	lkConfig   sync.Mutex
	Config     *Config
}

func NewBLETagDriver(client *gatt.Client) (*BLETagDriver, error) {

	conn, err := ninja.Connect("BLETag")

	if err != nil {
		btlog.Fatalf("Failed to create BLE tag driver: %s", err)
		return nil, err
	}

	driver := &BLETagDriver{
		conn:       conn,
		gattClient: client,
		running:    true,
		Config:     &Config{},
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		btlog.Fatalf("Failed to export BLE tag driver: %s", err)
		return nil, err
	}

	driver.FoundTags = make(map[string]bool)

	return driver, nil
}

func (d *BLETagDriver) Configure(request *model.ConfigurationRequest) (*suit.ConfigurationScreen, error) {
	log.Infof("Incoming configuration request. Action:%s Data:%s", request.Action, string(request.Data))

	return nil, nil
}

func (d *BLETagDriver) GetModuleInfo() *model.Module {
	return btinfo
}

func (d *BLETagDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}

func (fp *BLETagDriver) Start(config *Config) error {
	btlog.Infof(spew.Sprintf("Starting BLE tag driver %v", config))

	for _, tagConfig := range config.BleTags {
		btlog.Infof("NewBLETagFromConfig address=%s", tagConfig.Address)
		NewBLETagFromConfig(fp, tagConfig) // NOTE: This also saves it to the configuration
	}

	fp.running = true
	return nil
}

func (fp *BLETagDriver) Stop() error {
	fp.running = false
	return nil
}

func (fp *BLETagDriver) saveNewTag(address string, publicAddress bool, readChar *bluez.Characteristic, alertChar *bluez.Characteristic) {

	fp.lkConfig.Lock()

	defer fp.lkConfig.Unlock()

	btlog.Debugf(spew.Sprintf("saveNewTag %s %t %#v %#v", address, publicAddress, readChar, alertChar))

	bleConfig := &BleTagConfig{
		Address:              address,
		PublicAddress:        publicAddress,
		ReadUUID:             readChar.UUID,
		ReadHandle:           readChar.Handle,
		ReadCharValueHandle:  readChar.CharValueHandle,
		AlertUUID:            alertChar.UUID,
		AlertHandle:          alertChar.Handle,
		AlertCharValueHandle: alertChar.CharValueHandle,
	}

	// replace in the list
	for i, bleTag := range fp.Config.BleTags {
		if bleTag.Address == bleConfig.Address {
			// delete that entry
			fp.Config.BleTags = append(fp.Config.BleTags[:i], fp.Config.BleTags[i+1:]...)
		}
	}

	// apend to the configuration
	fp.Config.BleTags = append(fp.Config.BleTags, bleConfig)

	btlog.Infof("saving configuration %#v", fp.Config)

	err := fp.sendEvent("config", fp.Config)

	if err != nil {
		btlog.Errorf("Error saving configuration: %s", err)
	}
}

// Config is persisted by HomeCloud, and provided when the app starts.
type Config struct {
	BleTags []*BleTagConfig `json:"bleTags"`
}

// BleTagConfig is persisted by HomeCloud, and provided when the app starts.
type BleTagConfig struct {
	Address       string `json:"address"`
	PublicAddress bool   `json:"publicAddress"`

	ReadUUID            string `json:"readUUID"`
	ReadHandle          string `json:"readHandle"`
	ReadCharValueHandle string `json:"readCharValueHandle"`

	AlertUUID            string `json:"alertUUID"`
	AlertHandle          string `json:"alertHandle"`
	AlertCharValueHandle string `json:"alertCharValueHandle"`
}
<|endoftext|>


<commit_before>package kpaxutil

import (
	"encoding"

	"h12.me/kpax/broker"
	"h12.me/kpax/cluster"
	"h12.me/kpax/producer"
)

type Sender struct {
	p *producer.P
}

func NewSender(brokers []string) *Sender {
	return &Sender{p: producer.New(cluster.New(broker.New, brokers))}
}

func (s *Sender) Send(topic string, value encoding.BinaryMarshaler) error {
	buf, err := value.MarshalBinary()
	if err != nil {
		return err
	}
	return s.p.Produce(topic, nil, buf)
}
<commit_msg>use interface instead of struct<commit_after>package kpaxutil

import (
	"encoding"

	"h12.me/kpax/broker"
	"h12.me/kpax/cluster"
	"h12.me/kpax/producer"
)

type Sender interface {
	Send(topic string, value encoding.BinaryMarshaler) error
}

type simpleSender struct {
	p *producer.P
}

func NewSender(brokers []string) Sender {
	return &simpleSender{p: producer.New(cluster.New(broker.New, brokers))}
}

func (s *simpleSender) Send(topic string, value encoding.BinaryMarshaler) error {
	buf, err := value.MarshalBinary()
	if err != nil {
		return err
	}
	return s.p.Produce(topic, nil, buf)
}
<|endoftext|>


<commit_before>package xslt

//import "github.com/moovweb/gokogiri/xml"
//import "unicode/utf8"
import "testing"

func compareStep(t *testing.T, m *MatchStep, op StepOperation, val string) {
	if m.Op != op || val != m.Value {
		t.Error("Expected", op, "=", val, "\nActual  ", m.Op, "=", m.Value)
	}
}

func TestPatternSimple(t *testing.T) {
	steps := parseMatchPattern("test")
	compareStep(t, steps[0], OP_ELEM, "test")
}

func TestPatternParent(t *testing.T) {
	steps := parseMatchPattern("foo/bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternRootParent(t *testing.T) {
	steps := parseMatchPattern("/bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_ROOT, "/")
	compareStep(t, steps[2], OP_END, "")
}

func TestPatternAncestor(t *testing.T) {
	steps := parseMatchPattern("foo//bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_ANCESTOR, "//")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternRootAncestor(t *testing.T) {
	steps := parseMatchPattern("//bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternAttrib(t *testing.T) {
	steps := parseMatchPattern("@test")
	compareStep(t, steps[0], OP_ATTR, "test")
}

func TestPatternWildcardAttrib(t *testing.T) {
	steps := parseMatchPattern("@*")
	compareStep(t, steps[0], OP_ATTR, "*")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternNodeTestAttrib(t *testing.T) {
	steps := parseMatchPattern("@node()")
	compareStep(t, steps[0], OP_ATTR, "*")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternAttribWithParent(t *testing.T) {
	steps := parseMatchPattern("foo/@bar")
	compareStep(t, steps[0], OP_ATTR, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternNodeType(t *testing.T) {
	steps := parseMatchPattern("node()")
	compareStep(t, steps[0], OP_NODE, "()")
}
func TestPatternCommentType(t *testing.T) {
	steps := parseMatchPattern("comment()")
	compareStep(t, steps[0], OP_COMMENT, "()")
}
func TestPatternTextType(t *testing.T) {
	steps := parseMatchPattern("text()")
	compareStep(t, steps[0], OP_TEXT, "()")
}
func TestPatternPiType(t *testing.T) {
	steps := parseMatchPattern("processing-instruction()")
	compareStep(t, steps[0], OP_PI, "()")
}
func TestPatternAll(t *testing.T) {
	steps := parseMatchPattern("*")
	compareStep(t, steps[0], OP_ALL, "*")
}
func TestPatternParentAll(t *testing.T) {
	steps := parseMatchPattern("foo/*")
	compareStep(t, steps[0], OP_ALL, "*")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternPred(t *testing.T) {
	steps := parseMatchPattern("item[position()=1]")
	compareStep(t, steps[0], OP_ELEM, "item")
	compareStep(t, steps[1], OP_PREDICATE, "position()=1")
}

func TestPatternNonTerminalPred(t *testing.T) {
	steps := parseMatchPattern("item[position()=1]/foo")
	compareStep(t, steps[0], OP_ELEM, "foo")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "item")
	compareStep(t, steps[3], OP_PREDICATE, "position()=1")
}

func TestPatternNestedPred(t *testing.T) {
	steps := parseMatchPattern("list[item[@foo='bar']]")
	compareStep(t, steps[0], OP_ELEM, "list")
	compareStep(t, steps[1], OP_PREDICATE, "item[@foo='bar']")
}

func TestPatternNamespace(t *testing.T) {
	steps := parseMatchPattern("foo:bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_NS, "foo")
}

func TestPatternAxis(t *testing.T) {
	steps := parseMatchPattern("foo/child::bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternAttributeAxis(t *testing.T) {
	steps := parseMatchPattern("foo/attribute::bar")
	compareStep(t, steps[0], OP_ATTR, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternChildAxis(t *testing.T) {
	steps := parseMatchPattern("child::bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternOr(t *testing.T) {
	steps := parseMatchPattern("foo|bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_OR, "|")
	compareStep(t, steps[2], OP_ELEM, "foo")
	compareStep(t, steps[3], OP_END, "")
}

func TestPatternOrAtrr(t *testing.T) {
	steps := parseMatchPattern("@foo|bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_OR, "|")
	compareStep(t, steps[2], OP_ATTR, "foo")
	compareStep(t, steps[3], OP_END, "")
}
<commit_msg>Add a match test for the /* pattern<commit_after>package xslt

//import "github.com/moovweb/gokogiri/xml"
//import "unicode/utf8"
import "testing"

func compareStep(t *testing.T, m *MatchStep, op StepOperation, val string) {
	if m.Op != op || val != m.Value {
		t.Error("Expected", op, "=", val, "\nActual  ", m.Op, "=", m.Value)
	}
}

func TestPatternSimple(t *testing.T) {
	steps := parseMatchPattern("test")
	compareStep(t, steps[0], OP_ELEM, "test")
}

func TestPatternParent(t *testing.T) {
	steps := parseMatchPattern("foo/bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternRootParent(t *testing.T) {
	steps := parseMatchPattern("/bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_ROOT, "/")
	compareStep(t, steps[2], OP_END, "")
}

func TestPatternRootWildcard(t *testing.T) {
	steps := parseMatchPattern("/*")
	compareStep(t, steps[0], OP_ALL, "*")
	compareStep(t, steps[1], OP_ROOT, "/")
	compareStep(t, steps[2], OP_END, "")
}

func TestPatternAncestor(t *testing.T) {
	steps := parseMatchPattern("foo//bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_ANCESTOR, "//")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternRootAncestor(t *testing.T) {
	steps := parseMatchPattern("//bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternAttrib(t *testing.T) {
	steps := parseMatchPattern("@test")
	compareStep(t, steps[0], OP_ATTR, "test")
}

func TestPatternWildcardAttrib(t *testing.T) {
	steps := parseMatchPattern("@*")
	compareStep(t, steps[0], OP_ATTR, "*")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternNodeTestAttrib(t *testing.T) {
	steps := parseMatchPattern("@node()")
	compareStep(t, steps[0], OP_ATTR, "*")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternAttribWithParent(t *testing.T) {
	steps := parseMatchPattern("foo/@bar")
	compareStep(t, steps[0], OP_ATTR, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternNodeType(t *testing.T) {
	steps := parseMatchPattern("node()")
	compareStep(t, steps[0], OP_NODE, "()")
}
func TestPatternCommentType(t *testing.T) {
	steps := parseMatchPattern("comment()")
	compareStep(t, steps[0], OP_COMMENT, "()")
}
func TestPatternTextType(t *testing.T) {
	steps := parseMatchPattern("text()")
	compareStep(t, steps[0], OP_TEXT, "()")
}
func TestPatternPiType(t *testing.T) {
	steps := parseMatchPattern("processing-instruction()")
	compareStep(t, steps[0], OP_PI, "()")
}
func TestPatternAll(t *testing.T) {
	steps := parseMatchPattern("*")
	compareStep(t, steps[0], OP_ALL, "*")
}
func TestPatternParentAll(t *testing.T) {
	steps := parseMatchPattern("foo/*")
	compareStep(t, steps[0], OP_ALL, "*")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternPred(t *testing.T) {
	steps := parseMatchPattern("item[position()=1]")
	compareStep(t, steps[0], OP_ELEM, "item")
	compareStep(t, steps[1], OP_PREDICATE, "position()=1")
}

func TestPatternNonTerminalPred(t *testing.T) {
	steps := parseMatchPattern("item[position()=1]/foo")
	compareStep(t, steps[0], OP_ELEM, "foo")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "item")
	compareStep(t, steps[3], OP_PREDICATE, "position()=1")
}

func TestPatternNestedPred(t *testing.T) {
	steps := parseMatchPattern("list[item[@foo='bar']]")
	compareStep(t, steps[0], OP_ELEM, "list")
	compareStep(t, steps[1], OP_PREDICATE, "item[@foo='bar']")
}

func TestPatternNamespace(t *testing.T) {
	steps := parseMatchPattern("foo:bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_NS, "foo")
}

func TestPatternAxis(t *testing.T) {
	steps := parseMatchPattern("foo/child::bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternAttributeAxis(t *testing.T) {
	steps := parseMatchPattern("foo/attribute::bar")
	compareStep(t, steps[0], OP_ATTR, "bar")
	compareStep(t, steps[1], OP_PARENT, "/")
	compareStep(t, steps[2], OP_ELEM, "foo")
}

func TestPatternChildAxis(t *testing.T) {
	steps := parseMatchPattern("child::bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_END, "")
}

func TestPatternOr(t *testing.T) {
	steps := parseMatchPattern("foo|bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_OR, "|")
	compareStep(t, steps[2], OP_ELEM, "foo")
	compareStep(t, steps[3], OP_END, "")
}

func TestPatternOrAtrr(t *testing.T) {
	steps := parseMatchPattern("@foo|bar")
	compareStep(t, steps[0], OP_ELEM, "bar")
	compareStep(t, steps[1], OP_OR, "|")
	compareStep(t, steps[2], OP_ATTR, "foo")
	compareStep(t, steps[3], OP_END, "")
}
<|endoftext|>


<commit_before>// Automatically generated by MockGen. DO NOT EDIT!
// Source: gpio.go

package mock_gpio

import (
	gomock "code.google.com/p/gomock/gomock"
	. "github.com/alext/gpio"
)

// Mock of Pin interface
type MockPin struct {
	ctrl     *gomock.Controller
	recorder *_MockPinRecorder
}

// Recorder for MockPin (not exported)
type _MockPinRecorder struct {
	mock *MockPin
}

func NewMockPin(ctrl *gomock.Controller) *MockPin {
	mock := &MockPin{ctrl: ctrl}
	mock.recorder = &_MockPinRecorder{mock}
	return mock
}

func (_m *MockPin) EXPECT() *_MockPinRecorder {
	return _m.recorder
}

func (_m *MockPin) Mode() (Mode, error) {
	ret := _m.ctrl.Call(_m, "Mode")
	ret0, _ := ret[0].(Mode)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func (_mr *_MockPinRecorder) Mode() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Mode")
}

func (_m *MockPin) SetMode(_param0 Mode) error {
	ret := _m.ctrl.Call(_m, "SetMode", _param0)
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) SetMode(arg0 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "SetMode", arg0)
}

func (_m *MockPin) Set() error {
	ret := _m.ctrl.Call(_m, "Set")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Set() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Set")
}

func (_m *MockPin) Clear() error {
	ret := _m.ctrl.Call(_m, "Clear")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Clear() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Clear")
}

func (_m *MockPin) Close() error {
	ret := _m.ctrl.Call(_m, "Close")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Close() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Close")
}

func (_m *MockPin) Get() (bool, error) {
	ret := _m.ctrl.Call(_m, "Get")
	ret0, _ := ret[0].(bool)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func (_mr *_MockPinRecorder) Get() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Get")
}

func (_m *MockPin) BeginWatch(_param0 Edge, _param1 IRQEvent) error {
	ret := _m.ctrl.Call(_m, "BeginWatch", _param0, _param1)
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) BeginWatch(arg0, arg1 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "BeginWatch", arg0, arg1)
}

func (_m *MockPin) EndWatch() error {
	ret := _m.ctrl.Call(_m, "EndWatch")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) EndWatch() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "EndWatch")
}

func (_m *MockPin) Wait(_param0 bool) {
	_m.ctrl.Call(_m, "Wait", _param0)
}

func (_mr *_MockPinRecorder) Wait(arg0 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Wait", arg0)
}
<commit_msg>Update gomock import URL.<commit_after>// Automatically generated by MockGen. DO NOT EDIT!
// Source: gpio.go

package mock_gpio

import (
	. "github.com/alext/gpio"
	gomock "github.com/golang/mock/gomock"
)

// Mock of Pin interface
type MockPin struct {
	ctrl     *gomock.Controller
	recorder *_MockPinRecorder
}

// Recorder for MockPin (not exported)
type _MockPinRecorder struct {
	mock *MockPin
}

func NewMockPin(ctrl *gomock.Controller) *MockPin {
	mock := &MockPin{ctrl: ctrl}
	mock.recorder = &_MockPinRecorder{mock}
	return mock
}

func (_m *MockPin) EXPECT() *_MockPinRecorder {
	return _m.recorder
}

func (_m *MockPin) Mode() (Mode, error) {
	ret := _m.ctrl.Call(_m, "Mode")
	ret0, _ := ret[0].(Mode)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func (_mr *_MockPinRecorder) Mode() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Mode")
}

func (_m *MockPin) SetMode(_param0 Mode) error {
	ret := _m.ctrl.Call(_m, "SetMode", _param0)
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) SetMode(arg0 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "SetMode", arg0)
}

func (_m *MockPin) Set() error {
	ret := _m.ctrl.Call(_m, "Set")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Set() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Set")
}

func (_m *MockPin) Clear() error {
	ret := _m.ctrl.Call(_m, "Clear")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Clear() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Clear")
}

func (_m *MockPin) Close() error {
	ret := _m.ctrl.Call(_m, "Close")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) Close() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Close")
}

func (_m *MockPin) Get() (bool, error) {
	ret := _m.ctrl.Call(_m, "Get")
	ret0, _ := ret[0].(bool)
	ret1, _ := ret[1].(error)
	return ret0, ret1
}

func (_mr *_MockPinRecorder) Get() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Get")
}

func (_m *MockPin) BeginWatch(_param0 Edge, _param1 IRQEvent) error {
	ret := _m.ctrl.Call(_m, "BeginWatch", _param0, _param1)
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) BeginWatch(arg0, arg1 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "BeginWatch", arg0, arg1)
}

func (_m *MockPin) EndWatch() error {
	ret := _m.ctrl.Call(_m, "EndWatch")
	ret0, _ := ret[0].(error)
	return ret0
}

func (_mr *_MockPinRecorder) EndWatch() *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "EndWatch")
}

func (_m *MockPin) Wait(_param0 bool) {
	_m.ctrl.Call(_m, "Wait", _param0)
}

func (_mr *_MockPinRecorder) Wait(arg0 interface{}) *gomock.Call {
	return _mr.mock.ctrl.RecordCall(_mr.mock, "Wait", arg0)
}
<|endoftext|>


<commit_before>package registry

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type loginOptions struct {
	serverAddress string
	user          string
	password      string
	email         string
}

// NewLoginCommand creates a new `docker login` command
func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
	var opts loginOptions

	cmd := &cobra.Command{
		Use:   "login [OPTIONS] [SERVER]",
		Short: "Log in to a Docker registry",
		Long:  "Log in to a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
		Args:  cli.RequiresMaxArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 {
				opts.serverAddress = args[0]
			}
			return runLogin(dockerCli, opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.user, "username", "u", "", "Username")
	flags.StringVarP(&opts.password, "password", "p", "", "Password")

	// Deprecated in 1.11: Should be removed in docker 17.06
	flags.StringVarP(&opts.email, "email", "e", "", "Email")
	flags.MarkDeprecated("email", "will be removed in 17.06.")

	return cmd
}

func runLogin(dockerCli command.Cli, opts loginOptions) error {
	ctx := context.Background()
	clnt := dockerCli.Client()

	var (
		serverAddress string
		authServer    = command.ElectAuthServer(ctx, dockerCli)
	)
	if opts.serverAddress != "" && opts.serverAddress != registry.DefaultNamespace {
		serverAddress = opts.serverAddress
	} else {
		serverAddress = authServer
	}

	isDefaultRegistry := serverAddress == authServer

	authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry)
	if err != nil {
		return err
	}
	response, err := clnt.RegistryLogin(ctx, authConfig)
	if err != nil {
		return err
	}
	if response.IdentityToken != "" {
		authConfig.Password = ""
		authConfig.IdentityToken = response.IdentityToken
	}
	if err := dockerCli.CredentialsStore(serverAddress).Store(authConfig); err != nil {
		return errors.Errorf("Error saving credentials: %v", err)
	}

	if response.Status != "" {
		fmt.Fprintln(dockerCli.Out(), response.Status)
	}
	return nil
}
<commit_msg>Remove deprecated -e/--email flag from docker login<commit_after>package registry

import (
	"fmt"

	"golang.org/x/net/context"

	"github.com/docker/cli/cli"
	"github.com/docker/cli/cli/command"
	"github.com/docker/docker/registry"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)

type loginOptions struct {
	serverAddress string
	user          string
	password      string
	email         string
}

// NewLoginCommand creates a new `docker login` command
func NewLoginCommand(dockerCli command.Cli) *cobra.Command {
	var opts loginOptions

	cmd := &cobra.Command{
		Use:   "login [OPTIONS] [SERVER]",
		Short: "Log in to a Docker registry",
		Long:  "Log in to a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
		Args:  cli.RequiresMaxArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			if len(args) > 0 {
				opts.serverAddress = args[0]
			}
			return runLogin(dockerCli, opts)
		},
	}

	flags := cmd.Flags()

	flags.StringVarP(&opts.user, "username", "u", "", "Username")
	flags.StringVarP(&opts.password, "password", "p", "", "Password")

	return cmd
}

func runLogin(dockerCli command.Cli, opts loginOptions) error {
	ctx := context.Background()
	clnt := dockerCli.Client()

	var (
		serverAddress string
		authServer    = command.ElectAuthServer(ctx, dockerCli)
	)
	if opts.serverAddress != "" && opts.serverAddress != registry.DefaultNamespace {
		serverAddress = opts.serverAddress
	} else {
		serverAddress = authServer
	}

	isDefaultRegistry := serverAddress == authServer

	authConfig, err := command.ConfigureAuth(dockerCli, opts.user, opts.password, serverAddress, isDefaultRegistry)
	if err != nil {
		return err
	}
	response, err := clnt.RegistryLogin(ctx, authConfig)
	if err != nil {
		return err
	}
	if response.IdentityToken != "" {
		authConfig.Password = ""
		authConfig.IdentityToken = response.IdentityToken
	}
	if err := dockerCli.CredentialsStore(serverAddress).Store(authConfig); err != nil {
		return errors.Errorf("Error saving credentials: %v", err)
	}

	if response.Status != "" {
		fmt.Fprintln(dockerCli.Out(), response.Status)
	}
	return nil
}
<|endoftext|>


<commit_before>package crawler

type task interface {
    process()
    output()
}

type factory interface {
    create(lint string) string
}<commit_msg>Fixed factory interface.<commit_after>package crawler

type task interface {
	process()
	output()
}

type factory interface {
	create(lint string) task
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"text/template"
	"time"
)

const (
	packageName   = "io.qpm.cli"
	stagingDir    = "packages"
	repositoryDir = "repository"
)

var (
	platforms = map[string]string{
		"windows_386":   "qpm.exe",
		"windows_amd64": "qpm.exe",
		"linux_386":     "qpm",
		"linux_amd64":   "qpm",
		"darwin_386":    "qpm",
		"darwin_amd64":  "qpm",
	}

	licenseTxt = template.Must(template.New("licenseTxt").Parse(`
qpm is available under the terms of a license.
	`))

	rootPackageXml = template.Must(template.New("rootPackageXml").Parse(
		`<?xml version="1.0"?>
<Package>
    <DisplayName>qpm</DisplayName>
    <Description>qpm is a command line tool for installing packages from the qpm.io repository.</Description>
    <Version>{{.Version}}</Version>
    <ReleaseDate>{{.ReleaseDate}}</ReleaseDate>
    <Name>{{.Root}}</Name>
    <Licenses>
        <License name="License Agreement" file="license.txt" />
    </Licenses>
    <UpdateText>Initial release</UpdateText>
    <Default>true</Default>
    <ForcedInstallation>false</ForcedInstallation>
    <Essential>false</Essential>
</Package>
	`))

	platformPackageXml = template.Must(template.New("platformPackageXml").Parse(
		`<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>{{.Platform}} binaries</DisplayName>
    <Description>qpm binaries for running on {{.Platform}}</Description>
    <Version>{{.Version}}</Version>
    <ReleaseDate>{{.ReleaseDate}}</ReleaseDate>
    <Name>{{.Root}}.{{.Platform}}</Name>
    <Default>false</Default>
</Package>
`))
)

type packageInfo struct {
	Root        string
	Platform    string
	ReleaseDate string
	Version     string
}

func newDir(dir string) string {
	if err := os.MkdirAll(dir, os.FileMode(0755)); err != nil {
		log.Fatalf("could not create %s, %s", dir, err.Error())
	}
	return dir
}

func copyBinary(src, dest string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	defer s.Close()

	d, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer d.Close()

	if _, err = io.Copy(d, s); err != nil {
		return err
	}
	if err := d.Sync(); err != nil {
		return err
	}

	return d.Chmod(0755)
}

func writeTemplate(filename string, tpl *template.Template, pkg *packageInfo) error {
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalf("Could not create file %s: %s", filename, err.Error())
		return err
	}
	defer file.Close()

	err = tpl.Execute(file, pkg)
	if err != nil {
		log.Fatalf("Could not generate file %s: %s", filename, err.Error())
		return err
	}

	return nil
}

func main() {

	binDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatalf("Error getting bin dir: %v\n", err)
	}

	var outputDir string
	if len(os.Args) < 2 {
		outputDir, err = filepath.Abs(repositoryDir)
	} else {
		outputDir, err = filepath.Abs(os.Args[1])
	}
	if err != nil {
		log.Fatalf("Error getting output dirr: %v\n", err)
	}

	staging := newDir(outputDir + "/" + stagingDir + "/")
	log.Printf("Generated repository at %s\n", outputDir)

	buffer := bytes.NewBufferString(staging)
	reset := buffer.Len()

	pkg := &packageInfo{
		Root:        packageName,
		Version:     "0.0.1",
		ReleaseDate: time.Now().Format("2006-01-02"),
	}

	rootMetaDir := newDir(staging + packageName + "/meta/")
	newDir(staging + packageName + "/data")

	if err = writeTemplate(rootMetaDir+"package.xml", rootPackageXml, pkg); err != nil {
		log.Fatalf("Could not generate package.xml for root %s", err.Error())
	}
	if err = writeTemplate(rootMetaDir+"license.txt", licenseTxt, pkg); err != nil {
		log.Fatalf("Could not generate license.txt for root %s", err.Error())
	}

	for platform, binary := range platforms {
		srcDir := binDir + "/" + platform + "/"
		if _, err := os.Stat(srcDir); err != nil {
			log.Printf("Platform %s does not exist", platform)
			continue
		}

		// Create meta dir
		buffer.Truncate(reset)
		buffer.WriteString(packageName + ".")
		buffer.WriteString(platform)
		buffer.WriteString("/meta/")
		metaDir := buffer.String()
		newDir(metaDir)

		// Create data dir
		buffer.Truncate(reset)
		buffer.WriteString(packageName + ".")
		buffer.WriteString(platform)
		buffer.WriteString("/data/qpm/")
		dataDir := buffer.String()
		newDir(dataDir)

		if err := copyBinary(srcDir+binary, dataDir+binary); err != nil {
			log.Fatalf("Cannot copy binary to %s: %s", dataDir, err.Error())
		}

		pkg.Platform = platform
		if err := writeTemplate(metaDir+"package.xml", platformPackageXml, pkg); err != nil {
			log.Fatalf("Could not generate package.xml for %s: %s", platform, err.Error())
		}
	}
}
<commit_msg>Some fixes to the packager tool and add a proper license file.<commit_after>package main

import (
	"bytes"
	"io"
	"log"
	"os"
	"path/filepath"
	"text/template"
	"time"
	"qpm.io/qpm/core"
	"strings"
)

const (
	packageName   = "io.qpm.cli"
	stagingDir    = "packages"
	repositoryDir = "repository"
	qpmLicense    = "artistic-2.0"
	licenseAddendum = `
--------------------------

The following additional terms shall apply to use of the qpm software, the qpm.io
website and repository:

"qpm" and "qpm.io" are owned by Cutehacks AS. All rights reserved.

Modules published on the qpm registry are not officially endorsed by Cutehacks AS.

Data published to the qpm registry is not part of qpm itself, and is the sole
property of the publisher. While every effort is made to ensure accountability,
there is absolutely no guarantee, warranty, or assertion expressed or implied
as to the quality, fitness for a specific purpose, or lack of malice in any
given qpm package.  Packages downloaded through qpm.io are independently licensed
and are not covered by this license.
	`
)

var (
	platforms = map[string]string{
		"windows_386":   "qpm.exe",
		"windows_amd64": "qpm.exe",
		"linux_386":     "qpm",
		"linux_amd64":   "qpm",
		"darwin_386":    "qpm",
		"darwin_amd64":  "qpm",
	}

	rootPackageXml = template.Must(template.New("rootPackageXml").Parse(
		`<?xml version="1.0"?>
<Package>
    <DisplayName>qpm</DisplayName>
    <Description>qpm is a command line tool for installing packages from the qpm.io repository.</Description>
    <Version>{{.Version}}</Version>
    <ReleaseDate>{{.ReleaseDate}}</ReleaseDate>
    <Name>{{.Root}}</Name>
    <Licenses>
        <License name="License Agreement" file="license.txt" />
    </Licenses>
    <UpdateText>Initial release</UpdateText>
    <Default>true</Default>
    <ForcedInstallation>false</ForcedInstallation>
    <Essential>false</Essential>
</Package>
	`))

	platformPackageXml = template.Must(template.New("platformPackageXml").Parse(
		`<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>{{.Platform}} binaries</DisplayName>
    <Description>qpm binaries for running on {{.Platform}}</Description>
    <Version>{{.Version}}</Version>
    <ReleaseDate>{{.ReleaseDate}}</ReleaseDate>
    <Name>{{.Root}}.{{.Platform}}</Name>
    <Default>false</Default>
</Package>
`))
)

type packageInfo struct {
	Root        string
	Platform    string
	ReleaseDate string
	Version     string
}

func newDir(dir string) string {
	if err := os.MkdirAll(dir, os.FileMode(0755)); err != nil {
		log.Fatalf("could not create %s, %s", dir, err.Error())
	}
	return dir
}

func copyBinary(src, dest string) error {
	s, err := os.Open(src)
	if err != nil {
		return err
	}
	defer s.Close()

	d, err := os.Create(dest)
	if err != nil {
		return err
	}
	defer d.Close()

	if _, err = io.Copy(d, s); err != nil {
		return err
	}
	if err := d.Sync(); err != nil {
		return err
	}

	return d.Chmod(0755)
}

func writeText(filename,  text string) error {
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalf("Could not create file %s: %s", filename, err.Error())
		return err
	}
	defer file.Close()

	_, err = file.WriteString(text)
	return err
}

func writeTemplate(filename string, tpl *template.Template, pkg *packageInfo) error {
	file, err := os.Create(filename)
	if err != nil {
		log.Fatalf("Could not create file %s: %s", filename, err.Error())
		return err
	}
	defer file.Close()

	err = tpl.Execute(file, pkg)
	if err != nil {
		log.Fatalf("Could not generate file %s: %s", filename, err.Error())
		return err
	}

	return nil
}

func main() {

	binDir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatalf("Error getting bin dir: %v\n", err)
	}

	var outputDir string
	if len(os.Args) < 2 {
		outputDir, err = filepath.Abs(repositoryDir)
	} else {
		outputDir, err = filepath.Abs(os.Args[1])
	}
	if err != nil {
		log.Fatalf("Error getting output dir: %v\n", err)
	}

	staging := newDir(filepath.Join(outputDir, stagingDir))
	log.Printf("Generated repository at %s\n", outputDir)

	buffer := bytes.NewBufferString(staging)
	reset := buffer.Len()

	pkg := &packageInfo{
		Root:        packageName,
		Version:     "0.0.1",
		ReleaseDate: time.Now().Format("2006-01-02"),
	}

	rootMetaDir := newDir(filepath.Join(staging, packageName, "meta"))
	newDir(filepath.Join(staging, packageName, "data"))

	if err = writeTemplate(filepath.Join(rootMetaDir,"package.xml"), rootPackageXml, pkg); err != nil {
		log.Fatalf("Could not generate package.xml for root %s", err.Error())
	}

	license, err := core.GetLicense(qpmLicense)
	if err != nil {
		log.Fatalf("Could not fetch license info:", err.Error())
	}

	licenseTxt := license.Body
	licenseTxt = strings.Replace(licenseTxt, "[fullname]", "Cutehacks AS", -1)
	licenseTxt = strings.Replace(licenseTxt, "[year]", time.Now().Format("2006"), -1)
	licenseTxt +=  licenseAddendum

	if err = writeText(filepath.Join(rootMetaDir,"license.txt"), licenseTxt); err != nil {
		log.Fatalf("Could not generate license.txt for root %s", err.Error())
	}

	for platform, binary := range platforms {
		srcDir := filepath.Join(binDir, platform)
		if _, err := os.Stat(srcDir); err != nil {
			log.Printf("Platform %s does not exist", platform)
			continue
		}

		// Create meta dir
		buffer.Truncate(reset)
		buffer.WriteString("/" + packageName + ".")
		buffer.WriteString(platform)
		buffer.WriteString("/meta/")
		metaDir := buffer.String()
		newDir(metaDir)

		// Create data dir
		buffer.Truncate(reset)
		buffer.WriteString("/" + packageName + ".")
		buffer.WriteString(platform)
		buffer.WriteString("/data/qpm/")
		dataDir := buffer.String()
		newDir(dataDir)

		if err := copyBinary(filepath.Join(srcDir, binary), filepath.Join(dataDir, binary)); err != nil {
			log.Fatalf("Cannot copy binary to %s: %s", dataDir, err.Error())
		}

		pkg.Platform = platform
		if err := writeTemplate(filepath.Join(metaDir, "package.xml"), platformPackageXml, pkg); err != nil {
			log.Fatalf("Could not generate package.xml for %s: %s", platform, err.Error())
		}
	}
}
<|endoftext|>


<commit_before>package fingerprint

import (
	"fmt"
	"log"
	"net"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

const (
	// defaultNetworkSpeed is the speed set if the network link speed could not
	// be detected.
	defaultNetworkSpeed = 1000
)

// NetworkFingerprint is used to fingerprint the Network capabilities of a node
type NetworkFingerprint struct {
	StaticFingerprinter
	logger            *log.Logger
	interfaceDetector NetworkInterfaceDetector
}

// An interface to isolate calls to various api in net package
// This facilitates testing where we can implement
// fake interfaces and addresses to test varios code paths
type NetworkInterfaceDetector interface {
	Interfaces() ([]net.Interface, error)
	InterfaceByName(name string) (*net.Interface, error)
	Addrs(intf *net.Interface) ([]net.Addr, error)
}

// Implements the interface detector which calls net directly
type DefaultNetworkInterfaceDetector struct {
}

func (b *DefaultNetworkInterfaceDetector) Interfaces() ([]net.Interface, error) {
	return net.Interfaces()
}

func (b *DefaultNetworkInterfaceDetector) InterfaceByName(name string) (*net.Interface, error) {
	return net.InterfaceByName(name)
}

func (b *DefaultNetworkInterfaceDetector) Addrs(intf *net.Interface) ([]net.Addr, error) {
	return intf.Addrs()
}

// NewNetworkFingerprint returns a new NetworkFingerprinter with the given
// logger
func NewNetworkFingerprint(logger *log.Logger) Fingerprint {
	f := &NetworkFingerprint{logger: logger, interfaceDetector: &DefaultNetworkInterfaceDetector{}}
	return f
}

func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Find the named interface
	intf, err := f.findInterface(cfg.NetworkInterface)
	switch {
	case err != nil:
		return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err)
	case intf == nil:
		// No interface could be found
		return false, nil
	}

	// Record the throughput of the interface
	var mbits int
	throughput := f.linkSpeed(intf.Name)
	if cfg.NetworkSpeed != 0 {
		mbits = cfg.NetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", mbits)
	} else if throughput != 0 {
		mbits = throughput
		f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, mbits)
	} else {
		mbits = defaultNetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: link speed could not be detected and no speed specified by user. Defaulting to %d", defaultNetworkSpeed)
	}

	// Create the network resources from the interface
	nwResources, err := f.createNetworkResources(mbits, intf)
	if err != nil {
		return false, err
	}

	// Add the network resources to the node
	for _, nwResource := range nwResources {
		node.Resources.Networks = append(node.Resources.Networks, nwResource)
		f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP: %v, CIDR: %v during fingerprinting",
			intf.Name, nwResource.IP, nwResource.CIDR)
	}

	if len(nwResources) > 0 {
		node.Attributes["unique.network.ip-address"] = nwResources[0].IP
	}

	// return true, because we have a network connection
	return true, nil
}

// createNetworkResources creates network resources for every IP
func (f *NetworkFingerprint) createNetworkResources(throughput int, intf *net.Interface) ([]*structs.NetworkResource, error) {
	// Find the interface with the name
	addrs, err := f.interfaceDetector.Addrs(intf)
	if err != nil {
		return nil, err
	}
	nwResources := make([]*structs.NetworkResource, len(addrs))
	for i, addr := range addrs {
		// Create a new network resource
		newNetwork := &structs.NetworkResource{
			Device: intf.Name,
			MBits:  throughput,
		}

		// Find the IP Addr and the CIDR from the Address
		switch v := (addr).(type) {
		case *net.IPNet:
			newNetwork.IP = v.IP.String()
			newNetwork.CIDR = v.String()
		case *net.IPAddr:
			ip := v.IP
			newNetwork.IP = ip.String()
			if ip.To4() != nil {
				newNetwork.CIDR = newNetwork.IP + "/32"
			} else {
				newNetwork.CIDR = newNetwork.IP + "/128"
			}
		}
		nwResources[i] = newNetwork
	}
	return nwResources, nil
}

// Checks if the device is marked UP by the operator
func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {
	return intf.Flags&net.FlagUp != 0
}

// Checks if the device has any IP address configured
func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
	addrs, err := f.interfaceDetector.Addrs(intf)
	return err == nil && len(addrs) != 0
}

func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
	return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0
}

// Returns the interface with the name passed by user
// If the name is blank then it iterates through all the devices
// and finds one which is routable and marked as UP
// It excludes PPP and lo devices unless they are specifically asked
func (f *NetworkFingerprint) findInterface(deviceName string) (*net.Interface, error) {
	var interfaces []net.Interface
	var err error

	if deviceName != "" {
		return f.interfaceDetector.InterfaceByName(deviceName)
	}

	var intfs []net.Interface

	if intfs, err = f.interfaceDetector.Interfaces(); err != nil {
		return nil, err
	}

	for _, intf := range intfs {
		if f.isDeviceEnabled(&intf) && !f.isDeviceLoopBackOrPointToPoint(&intf) && f.deviceHasIpAddress(&intf) {
			interfaces = append(interfaces, intf)
		}
	}

	if len(interfaces) == 0 {
		return nil, nil
	}
	return &interfaces[0], nil
}
<commit_msg>Ignoring link local addresses<commit_after>package fingerprint

import (
	"fmt"
	"log"
	"net"

	"github.com/hashicorp/nomad/client/config"
	"github.com/hashicorp/nomad/nomad/structs"
)

const (
	// defaultNetworkSpeed is the speed set if the network link speed could not
	// be detected.
	defaultNetworkSpeed = 1000
)

// NetworkFingerprint is used to fingerprint the Network capabilities of a node
type NetworkFingerprint struct {
	StaticFingerprinter
	logger            *log.Logger
	interfaceDetector NetworkInterfaceDetector
}

// An interface to isolate calls to various api in net package
// This facilitates testing where we can implement
// fake interfaces and addresses to test varios code paths
type NetworkInterfaceDetector interface {
	Interfaces() ([]net.Interface, error)
	InterfaceByName(name string) (*net.Interface, error)
	Addrs(intf *net.Interface) ([]net.Addr, error)
}

// Implements the interface detector which calls net directly
type DefaultNetworkInterfaceDetector struct {
}

func (b *DefaultNetworkInterfaceDetector) Interfaces() ([]net.Interface, error) {
	return net.Interfaces()
}

func (b *DefaultNetworkInterfaceDetector) InterfaceByName(name string) (*net.Interface, error) {
	return net.InterfaceByName(name)
}

func (b *DefaultNetworkInterfaceDetector) Addrs(intf *net.Interface) ([]net.Addr, error) {
	return intf.Addrs()
}

// NewNetworkFingerprint returns a new NetworkFingerprinter with the given
// logger
func NewNetworkFingerprint(logger *log.Logger) Fingerprint {
	f := &NetworkFingerprint{logger: logger, interfaceDetector: &DefaultNetworkInterfaceDetector{}}
	return f
}

func (f *NetworkFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
	if node.Resources == nil {
		node.Resources = &structs.Resources{}
	}

	// Find the named interface
	intf, err := f.findInterface(cfg.NetworkInterface)
	switch {
	case err != nil:
		return false, fmt.Errorf("Error while detecting network interface during fingerprinting: %v", err)
	case intf == nil:
		// No interface could be found
		return false, nil
	}

	// Record the throughput of the interface
	var mbits int
	throughput := f.linkSpeed(intf.Name)
	if cfg.NetworkSpeed != 0 {
		mbits = cfg.NetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: setting link speed to user configured speed: %d", mbits)
	} else if throughput != 0 {
		mbits = throughput
		f.logger.Printf("[DEBUG] fingerprint.network: link speed for %v set to %v", intf.Name, mbits)
	} else {
		mbits = defaultNetworkSpeed
		f.logger.Printf("[DEBUG] fingerprint.network: link speed could not be detected and no speed specified by user. Defaulting to %d", defaultNetworkSpeed)
	}

	// Create the network resources from the interface
	nwResources, err := f.createNetworkResources(mbits, intf)
	if err != nil {
		return false, err
	}

	// Add the network resources to the node
	for _, nwResource := range nwResources {
		node.Resources.Networks = append(node.Resources.Networks, nwResource)
		f.logger.Printf("[DEBUG] fingerprint.network: Detected interface %v with IP: %v, CIDR: %v during fingerprinting",
			intf.Name, nwResource.IP, nwResource.CIDR)
	}

	if len(nwResources) > 0 {
		node.Attributes["unique.network.ip-address"] = nwResources[0].IP
	}

	// return true, because we have a network connection
	return true, nil
}

// createNetworkResources creates network resources for every IP
func (f *NetworkFingerprint) createNetworkResources(throughput int, intf *net.Interface) ([]*structs.NetworkResource, error) {
	// Find the interface with the name
	addrs, err := f.interfaceDetector.Addrs(intf)
	if err != nil {
		return nil, err
	}
	nwResources := make([]*structs.NetworkResource, 0)
	for _, addr := range addrs {
		// Create a new network resource
		newNetwork := &structs.NetworkResource{
			Device: intf.Name,
			MBits:  throughput,
		}

		// Find the IP Addr and the CIDR from the Address
		var ip net.IP
		switch v := (addr).(type) {
		case *net.IPNet:
			ip = v.IP
			newNetwork.IP = v.IP.String()
		case *net.IPAddr:
			ip = v.IP
		}

		// If the ip is link-local then we ignore it
		if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
			continue
		}
		newNetwork.IP = ip.String()
		if ip.To4() != nil {
			newNetwork.CIDR = newNetwork.IP + "/32"
		} else {
			newNetwork.CIDR = newNetwork.IP + "/128"
		}

		nwResources = append(nwResources, newNetwork)
	}
	return nwResources, nil
}

// Checks if the device is marked UP by the operator
func (f *NetworkFingerprint) isDeviceEnabled(intf *net.Interface) bool {
	return intf.Flags&net.FlagUp != 0
}

// Checks if the device has any IP address configured
func (f *NetworkFingerprint) deviceHasIpAddress(intf *net.Interface) bool {
	addrs, err := f.interfaceDetector.Addrs(intf)
	return err == nil && len(addrs) != 0
}

func (n *NetworkFingerprint) isDeviceLoopBackOrPointToPoint(intf *net.Interface) bool {
	return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0
}

// Returns the interface with the name passed by user
// If the name is blank then it iterates through all the devices
// and finds one which is routable and marked as UP
// It excludes PPP and lo devices unless they are specifically asked
func (f *NetworkFingerprint) findInterface(deviceName string) (*net.Interface, error) {
	var interfaces []net.Interface
	var err error

	if deviceName != "" {
		return f.interfaceDetector.InterfaceByName(deviceName)
	}

	var intfs []net.Interface

	if intfs, err = f.interfaceDetector.Interfaces(); err != nil {
		return nil, err
	}

	for _, intf := range intfs {
		if f.isDeviceEnabled(&intf) && !f.isDeviceLoopBackOrPointToPoint(&intf) && f.deviceHasIpAddress(&intf) {
			interfaces = append(interfaces, intf)
		}
	}

	if len(interfaces) == 0 {
		return nil, nil
	}
	return &interfaces[0], nil
}
<|endoftext|>