<commit_before>// Copyright (c) 2013 Adam Langley. All rights reserved
// Copyright (c) 2014 Andres Erbsen

package ratchet

import (
	"bytes"
	"crypto/rand"
	"testing"
	"time"

	"code.google.com/p/go.crypto/curve25519"
)

func nowFunc() time.Time {
	var t time.Time
	return t
}

func pairedRatchet() (a, b *Ratchet) {
	var preKeyA, preKeyAPrivate [32]byte
	rand.Read(preKeyAPrivate[:])
	curve25519.ScalarBaseMult(&preKeyA, &preKeyAPrivate)

	b, msgBtoA := EncryptFirst(nil, nil, &preKeyA, rand.Reader, nowFunc)
	a, _, err := DecryptFirst(msgBtoA, &preKeyAPrivate, rand.Reader, nowFunc)
	if err != nil {
		panic(err)
	}
	return
}

func TestExchange(t *testing.T) {
	a, b := pairedRatchet()

	msg := []byte("test message")
	encrypted := a.Encrypt(nil, msg)
	result, err := b.Decrypt(encrypted)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(msg, result) {
		t.Fatalf("result doesn't match: %x vs %x", msg, result)
	}
}

type scriptAction struct {
	// object is one of sendA, sendB or sendDelayed. The first two options
	// cause a message to be sent from one party to the other. The latter
	// causes a previously delayed message, identified by id, to be
	// delivered.
	object int
	// result is one of deliver, drop or delay. If delay, then the message
	// is stored using the value in id. This value can be repeated later
	// with a sendDelayed.
	result int
	id     int
}

const (
	sendA = iota
	sendB
	sendDelayed
	deliver
	drop
	delay
)

func reinitRatchet(t *testing.T, r *Ratchet) *Ratchet {
	r.FlushSavedKeys(nowFunc(), 1*time.Hour)
	data, err := r.Marshal()
	if err != nil {
		t.Fatalf("Failed to marshal: %s", err)
	}
	newR := new(Ratchet)
	if err := newR.Unmarshal(data); err != nil {
		t.Fatalf("Failed to unmarshal: %s", err)
	}
	newR.rand = rand.Reader
	newR.now = nowFunc
	return r

}

func testScript(t *testing.T, script []scriptAction) {
	type delayedMessage struct {
		msg       []byte
		encrypted []byte
		fromA     bool
	}
	delayedMessages := make(map[int]delayedMessage)
	a, b := pairedRatchet()

	for i, action := range script {
		switch action.object {
		case sendA, sendB:
			sender, receiver := a, b
			if action.object == sendB {
				sender, receiver = receiver, sender
			}

			var msg [20]byte
			rand.Reader.Read(msg[:])
			encrypted := sender.Encrypt(nil, msg[:])

			switch action.result {
			case deliver:
				result, err := receiver.Decrypt(encrypted)
				if err != nil {
					t.Fatalf("#%d: receiver returned error: %s", i, err)
				}
				if !bytes.Equal(result, msg[:]) {
					t.Fatalf("#%d: bad message: got %x, not %x", i, result, msg[:])
				}
			case delay:
				if _, ok := delayedMessages[action.id]; ok {
					t.Fatalf("#%d: already have delayed message with id %d", i, action.id)
				}
				delayedMessages[action.id] = delayedMessage{msg[:], encrypted, sender == a}
			case drop:
			}
		case sendDelayed:
			delayed, ok := delayedMessages[action.id]
			if !ok {
				t.Fatalf("#%d: no such delayed message id: %d", i, action.id)
			}

			receiver := a
			if delayed.fromA {
				receiver = b
			}

			result, err := receiver.Decrypt(delayed.encrypted)
			if err != nil {
				t.Fatalf("#%d: receiver returned error: %s", i, err)
			}
			if !bytes.Equal(result, delayed.msg) {
				t.Fatalf("#%d: bad message: got %x, not %x", i, result, delayed.msg)
			}
		}

		a = reinitRatchet(t, a)
		b = reinitRatchet(t, b)
	}
}

func TestBackAndForth(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
	})
}

func TestReorder(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendA, delay, 0},
		{sendA, deliver, -1},
		{sendDelayed, deliver, 0},
	})
}

func TestReorderAfterRatchet(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendA, delay, 0},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendDelayed, deliver, 0},
	})
}

func TestDrop(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
	})
}
<commit_msg>fix ratchet serialization test<commit_after>// Copyright (c) 2013 Adam Langley. All rights reserved
// Copyright (c) 2014 Andres Erbsen

package ratchet

import (
	"bytes"
	"crypto/rand"
	"testing"
	"time"

	"code.google.com/p/go.crypto/curve25519"
)

func nowFunc() time.Time {
	var t time.Time
	return t
}

func pairedRatchet() (a, b *Ratchet) {
	var preKeyA, preKeyAPrivate [32]byte
	rand.Read(preKeyAPrivate[:])
	curve25519.ScalarBaseMult(&preKeyA, &preKeyAPrivate)

	b, msgBtoA := EncryptFirst(nil, nil, &preKeyA, rand.Reader, nowFunc)
	a, _, err := DecryptFirst(msgBtoA, &preKeyAPrivate, rand.Reader, nowFunc)
	if err != nil {
		panic(err)
	}
	return
}

func TestExchange(t *testing.T) {
	a, b := pairedRatchet()

	msg := []byte("test message")
	encrypted := a.Encrypt(nil, msg)
	result, err := b.Decrypt(encrypted)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(msg, result) {
		t.Fatalf("result doesn't match: %x vs %x", msg, result)
	}
}

type scriptAction struct {
	// object is one of sendA, sendB or sendDelayed. The first two options
	// cause a message to be sent from one party to the other. The latter
	// causes a previously delayed message, identified by id, to be
	// delivered.
	object int
	// result is one of deliver, drop or delay. If delay, then the message
	// is stored using the value in id. This value can be repeated later
	// with a sendDelayed.
	result int
	id     int
}

const (
	sendA = iota
	sendB
	sendDelayed
	deliver
	drop
	delay
)

func reinitRatchet(t *testing.T, r *Ratchet) *Ratchet {
	r.FlushSavedKeys(nowFunc(), 1*time.Hour)
	data, err := r.Marshal()
	if err != nil {
		t.Fatalf("Failed to marshal: %s", err)
	}
	newR := new(Ratchet)
	if err := newR.Unmarshal(data); err != nil {
		t.Fatalf("Failed to unmarshal: %s", err)
	}
	newR.rand = rand.Reader
	newR.now = nowFunc
	return newR

}

func testScript(t *testing.T, script []scriptAction) {
	type delayedMessage struct {
		msg       []byte
		encrypted []byte
		fromA     bool
	}
	delayedMessages := make(map[int]delayedMessage)
	a, b := pairedRatchet()

	for i, action := range script {
		switch action.object {
		case sendA, sendB:
			sender, receiver := a, b
			if action.object == sendB {
				sender, receiver = receiver, sender
			}

			var msg [20]byte
			rand.Reader.Read(msg[:])
			encrypted := sender.Encrypt(nil, msg[:])

			switch action.result {
			case deliver:
				result, err := receiver.Decrypt(encrypted)
				if err != nil {
					t.Fatalf("#%d: receiver returned error: %s", i, err)
				}
				if !bytes.Equal(result, msg[:]) {
					t.Fatalf("#%d: bad message: got %x, not %x", i, result, msg[:])
				}
			case delay:
				if _, ok := delayedMessages[action.id]; ok {
					t.Fatalf("#%d: already have delayed message with id %d", i, action.id)
				}
				delayedMessages[action.id] = delayedMessage{msg[:], encrypted, sender == a}
			case drop:
			}
		case sendDelayed:
			delayed, ok := delayedMessages[action.id]
			if !ok {
				t.Fatalf("#%d: no such delayed message id: %d", i, action.id)
			}

			receiver := a
			if delayed.fromA {
				receiver = b
			}

			result, err := receiver.Decrypt(delayed.encrypted)
			if err != nil {
				t.Fatalf("#%d: receiver returned error: %s", i, err)
			}
			if !bytes.Equal(result, delayed.msg) {
				t.Fatalf("#%d: bad message: got %x, not %x", i, result, delayed.msg)
			}
		}

		a = reinitRatchet(t, a)
		b = reinitRatchet(t, b)
	}
}

func TestBackAndForth(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
	})
}

func TestReorder(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendA, delay, 0},
		{sendA, deliver, -1},
		{sendDelayed, deliver, 0},
	})
}

func TestReorderAfterRatchet(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, deliver, -1},
		{sendA, delay, 0},
		{sendB, deliver, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
		{sendDelayed, deliver, 0},
	})
}

func TestDrop(t *testing.T) {
	testScript(t, []scriptAction{
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, drop, -1},
		{sendA, deliver, -1},
		{sendB, deliver, -1},
	})
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: ISC
// Copyright (c) 2014-2020 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package proof

import (
	"encoding/json"
	"fmt"

	zmq "github.com/pebbe/zmq4"

	"github.com/bitmark-inc/bitmarkd/chain"
	"github.com/bitmark-inc/bitmarkd/counter"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/bitmarkd/zmqutil"
	"github.com/bitmark-inc/logger"
)

const (
	submissionZapDomain = "submit"
	submissionSignal    = "inproc://bitmark-submission-signal"
)

type submission struct {
	log                *logger.L
	sigSend            *zmq.Socket // signal send
	sigReceive         *zmq.Socket // signal receive
	socket4            *zmq.Socket
	socket6            *zmq.Socket
	minedBlockCount    counter.Counter
	failedBlockCount   counter.Counter
	internalHashEnable bool
}

// initialise the submission
func (sub *submission) initialise(configuration *Configuration) error {
	sub.internalHashEnable = configuration.InternalHashEnable
	log := logger.New("submission")
	sub.log = log

	log.Info("initialising…")

	var err error
	// signalling channel
	sub.sigReceive, sub.sigSend, err = zmqutil.NewSignalPair(submissionSignal)
	if nil != err {
		return err
	}

	// when chain is local, use internal hasher
	if mode.ChainName() == chain.Local && sub.internalHashEnable {
		if err := newInternalHasherReceiver(sub); err != nil {
			return err
		}
		return nil
	}

	// read the keys
	privateKey, err := zmqutil.ReadPrivateKey(configuration.PrivateKey)
	if nil != err {
		return err
	}
	publicKey, err := zmqutil.ReadPublicKey(configuration.PublicKey)
	if nil != err {
		return err
	}

	log.Tracef("server public:  %x", publicKey)
	log.Tracef("server private: %x", privateKey)

	// create connections
	c, _ := util.NewConnections(configuration.Submit)

	// allocate IPv4 and IPv6 sockets
	sub.socket4, sub.socket6, err = zmqutil.NewBind(log, zmq.REP, submissionZapDomain, privateKey, publicKey, c)
	if nil != err {
		log.Errorf("bind error: %s", err)
		return err
	}

	return nil
}

func newInternalHasherReceiver(sub *submission) error {
	var err error

	sub.socket4, err = zmq.NewSocket(internalHasherProtocol)
	if nil != err {
		return fmt.Errorf("create internal reply hasher socket with error: %s", err)
	}

	err = sub.socket4.Connect(internalHasherReply)
	if nil != err {
		return fmt.Errorf("connect internal reply hasher socket with error: %s", err)
	}

	return nil
}

// wait for new blocks or new payment items
// to ensure the queue integrity as heap is not thread-safe
func (sub *submission) Run(args interface{}, shutdown <-chan struct{}) {

	log := sub.log

	log.Info("starting…")

	go func() {
		poller := zmq.NewPoller()
		if nil != sub.socket4 {
			poller.Add(sub.socket4, zmq.POLLIN)
		}
		if nil != sub.socket6 {
			poller.Add(sub.socket6, zmq.POLLIN)
		}
		poller.Add(sub.sigReceive, zmq.POLLIN)
	loop:
		for {
			log.Debug("waiting…")
			sockets, _ := poller.Poll(-1)
			for _, socket := range sockets {
				switch s := socket.Socket; s {
				case sub.sigReceive:
					s.Recv(0)
					break loop
				default:
					sub.process(s)
				}
			}
		}
		sub.sigReceive.Close()
		if nil != sub.socket4 {
			sub.socket4.Close()
		}
		if nil != sub.socket6 {
			sub.socket6.Close()
		}
	}()

	// wait for shutdown
	<-shutdown
	sub.sigSend.SendMessage("stop")
	sub.sigSend.Close()
}

// process the request and return response to prooferd
func (sub *submission) process(socket *zmq.Socket) {

	log := sub.log

	data, err := socket.RecvMessage(0)
	if nil != err {
		log.Errorf("JSON encode error: %s", err)
		return
	}

	log.Infof("received message: %q", data)

	ok := false
	var request SubmittedItem
	err = json.Unmarshal([]byte(data[0]), &request)
	if nil != err {
		log.Errorf("JSON decode error: %s", err)
	} else {

		log.Infof("received message: %v", request)

		ok = matchToJobQueue(&request, log)

		log.Infof("maches: %v", ok)
	}

	// increase minedBlockCount
	if ok {
		sub.minedBlockCount.Increment()
	} else {
		sub.failedBlockCount.Increment()
	}

	response := struct {
		Job string `json:"job"`
		OK  bool   `json:"ok"`
	}{
		Job: request.Job,
		OK:  ok,
	}

	result, err := json.Marshal(response)
	logger.PanicIfError("JSON encode error", err)

	log.Infof("json to send: %s", result)

	// if _, err := socket.Send(to, zmq.SNDMORE|zmq.DONTWAIT); nil != err {
	// 	return err
	// }
	// if _, err := socket.Send(command, zmq.SNDMORE|zmq.DONTWAIT); nil != err {
	// 	return err
	// }
	_, err = socket.SendBytes(result, 0|zmq.DONTWAIT)
	logger.PanicIfError("Submission", err)
}

func MinedBlocks() counter.Counter {
	return globalData.sub.minedBlockCount
}

func FailMinedBlocks() counter.Counter {
	return globalData.sub.failedBlockCount
}
<commit_msg>[proof] prevent too rapid a response in local test mode<commit_after>// SPDX-License-Identifier: ISC
// Copyright (c) 2014-2020 Bitmark Inc.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package proof

import (
	"crypto/rand"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	zmq "github.com/pebbe/zmq4"

	"github.com/bitmark-inc/bitmarkd/chain"
	"github.com/bitmark-inc/bitmarkd/counter"
	"github.com/bitmark-inc/bitmarkd/mode"
	"github.com/bitmark-inc/bitmarkd/util"
	"github.com/bitmark-inc/bitmarkd/zmqutil"
	"github.com/bitmark-inc/logger"
)

const (
	submissionZapDomain = "submit"
	submissionSignal    = "inproc://bitmark-submission-signal"
)

type submission struct {
	log                *logger.L
	sigSend            *zmq.Socket // signal send
	sigReceive         *zmq.Socket // signal receive
	socket4            *zmq.Socket
	socket6            *zmq.Socket
	minedBlockCount    counter.Counter
	failedBlockCount   counter.Counter
	internalHashEnable bool
}

// initialise the submission
func (sub *submission) initialise(configuration *Configuration) error {
	sub.internalHashEnable = configuration.InternalHashEnable
	log := logger.New("submission")
	sub.log = log

	log.Info("initialising…")

	var err error
	// signalling channel
	sub.sigReceive, sub.sigSend, err = zmqutil.NewSignalPair(submissionSignal)
	if nil != err {
		return err
	}

	// when chain is local, use internal hasher
	if mode.ChainName() == chain.Local && sub.internalHashEnable {
		if err := newInternalHasherReceiver(sub); err != nil {
			return err
		}
		return nil
	}

	// read the keys
	privateKey, err := zmqutil.ReadPrivateKey(configuration.PrivateKey)
	if nil != err {
		return err
	}
	publicKey, err := zmqutil.ReadPublicKey(configuration.PublicKey)
	if nil != err {
		return err
	}

	log.Tracef("server public:  %x", publicKey)
	log.Tracef("server private: %x", privateKey)

	// create connections
	c, _ := util.NewConnections(configuration.Submit)

	// allocate IPv4 and IPv6 sockets
	sub.socket4, sub.socket6, err = zmqutil.NewBind(log, zmq.REP, submissionZapDomain, privateKey, publicKey, c)
	if nil != err {
		log.Errorf("bind error: %s", err)
		return err
	}

	return nil
}

func newInternalHasherReceiver(sub *submission) error {
	var err error

	sub.socket4, err = zmq.NewSocket(internalHasherProtocol)
	if nil != err {
		return fmt.Errorf("create internal reply hasher socket with error: %s", err)
	}

	err = sub.socket4.Connect(internalHasherReply)
	if nil != err {
		return fmt.Errorf("connect internal reply hasher socket with error: %s", err)
	}

	return nil
}

// wait for new blocks or new payment items
// to ensure the queue integrity as heap is not thread-safe
func (sub *submission) Run(args interface{}, shutdown <-chan struct{}) {

	log := sub.log

	log.Info("starting…")

	go func() {
		poller := zmq.NewPoller()
		if nil != sub.socket4 {
			poller.Add(sub.socket4, zmq.POLLIN)
		}
		if nil != sub.socket6 {
			poller.Add(sub.socket6, zmq.POLLIN)
		}
		poller.Add(sub.sigReceive, zmq.POLLIN)
	loop:
		for {
			log.Debug("waiting…")
			sockets, _ := poller.Poll(-1)
			for _, socket := range sockets {
				switch s := socket.Socket; s {
				case sub.sigReceive:
					s.Recv(0)
					break loop
				default:
					sub.process(s)
				}
			}
		}
		sub.sigReceive.Close()
		if nil != sub.socket4 {
			sub.socket4.Close()
		}
		if nil != sub.socket6 {
			sub.socket6.Close()
		}
	}()

	// wait for shutdown
	<-shutdown
	sub.sigSend.SendMessage("stop")
	sub.sigSend.Close()
}

// process the request and return response to prooferd
func (sub *submission) process(socket *zmq.Socket) {

	log := sub.log

	data, err := socket.RecvMessage(0)
	if nil != err {
		log.Errorf("JSON encode error: %s", err)
		return
	}

	log.Infof("received message: %q", data)

	ok := false
	var request SubmittedItem
	err = json.Unmarshal([]byte(data[0]), &request)
	if nil != err {
		log.Errorf("JSON decode error: %s", err)
	} else {

		log.Infof("received message: %v", request)

		ok = matchToJobQueue(&request, log)

		log.Infof("maches: %v", ok)
	}

	// increase minedBlockCount
	if ok {
		// do a little delay average around 50ms
		b := make([]byte, 1)
		_, err := rand.Read(b)
		if err != nil {
			b[0] = 5
		}
		time.Sleep((time.Duration(b[0]&0x7f) + 5) * time.Millisecond)

		sub.minedBlockCount.Increment()
	} else {
		sub.failedBlockCount.Increment()
	}

	response := struct {
		Job string `json:"job"`
		OK  bool   `json:"ok"`
	}{
		Job: request.Job,
		OK:  ok,
	}

	result, err := json.Marshal(response)
	logger.PanicIfError("JSON encode error", err)

	log.Infof("json to send: %s", result)

	// retry sending for a few seconds
	// in case the send was interrupted
	const sendRetries = 25
send_loop:
	for retry := 1; retry <= sendRetries; retry += 1 {
		_, err = socket.SendBytes(result, 0|zmq.DONTWAIT)
		if nil == err {
			break send_loop
		}
		log.Warnf("send try: %d/%d  error: %s", retry, sendRetries, err)
		if strings.Contains(err.Error(), "resource temporarily unavailable") {
			time.Sleep(50 * time.Millisecond)
			continue send_loop
		}
		logger.PanicIfError("Submission", err)
	}
}

func MinedBlocks() counter.Counter {
	return globalData.sub.minedBlockCount
}

func FailMinedBlocks() counter.Counter {
	return globalData.sub.failedBlockCount
}
<|endoftext|>


<commit_before>package protocol

import (
	"bytes"
	"reflect"
	"testing"
)

// Test if the types live up to their interface
var (
	_ Codec   = (*Qid)(nil)
	_ Codec   = (*Stat)(nil)
	_ Message = (*VersionRequest)(nil)
	_ Message = (*VersionResponse)(nil)
	_ Message = (*AuthRequest)(nil)
	_ Message = (*AuthResponse)(nil)
	_ Message = (*AttachRequest)(nil)
	_ Message = (*AttachResponse)(nil)
	_ Message = (*ErrorResponse)(nil)
	_ Message = (*FlushRequest)(nil)
	_ Message = (*FlushResponse)(nil)
	_ Message = (*WalkRequest)(nil)
	_ Message = (*WalkResponse)(nil)
	_ Message = (*OpenRequest)(nil)
	_ Message = (*OpenResponse)(nil)
	_ Message = (*CreateRequest)(nil)
	_ Message = (*CreateResponse)(nil)
	_ Message = (*ReadRequest)(nil)
	_ Message = (*ReadResponse)(nil)
	_ Message = (*WriteRequest)(nil)
	_ Message = (*WriteResponse)(nil)
	_ Message = (*ClunkRequest)(nil)
	_ Message = (*ClunkResponse)(nil)
	_ Message = (*RemoveRequest)(nil)
	_ Message = (*RemoveResponse)(nil)
	_ Message = (*StatRequest)(nil)
	_ Message = (*StatResponse)(nil)
	_ Message = (*WriteStatRequest)(nil)
	_ Message = (*WriteStatResponse)(nil)
)

func reencode(i int, in Codec, t *testing.T) {
	// Magic to get the basic type, not the pointer type
	inputType := reflect.ValueOf(in).Elem().Type()
	var other Codec
	buf := new(bytes.Buffer)
	if inm, ok := in.(Message); ok {
		// Full message handling, including length/type wrapper.
		if err := Encode(buf, inm); err != nil {
			t.Errorf("test %d: encoding failed for %v: %v", i, inputType, err)
			return
		}

		var err error
		other, err = Decode(buf)
		if err != nil {
			t.Errorf("test %d: decoding failed for %v: %v", i, inputType, err)
			return
		}
	} else {
		// Only encode/decode the message part itself.
		other = reflect.New(inputType).Interface().(Codec)

		if err := in.Encode(buf); err != nil {
			t.Errorf("test %d: encoding failed for %v: %v", i, inputType, err)
			return
		}

		if err := other.Decode(buf); err != nil {
			t.Errorf("test %d: decoding failed for %v: %v", i, inputType, err)
			return
		}
	}

	// Comparing the interfaces would result in pointer comparisons, so get the basic type first
	if !reflect.DeepEqual(reflect.ValueOf(in).Elem().Interface(), reflect.ValueOf(other).Elem().Interface()) {
		t.Errorf("test %d: %v did not reencode correctly", i, inputType)
	}
}

// This test does NOT guarantee proper 9P2000 spec coding, but ensures at least
// that all codecs are compatible with themselves.
func TestReencode(t *testing.T) {
	tests := []struct {
		in Codec
	}{
		{
			&Qid{
				Type:    QTDIR,
				Version: 0x12340987,
				Path:    0x10293874FFFFFF,
			},
		}, {
			&Stat{
				Type:   0xDEAD,
				Dev:    0xABCDEF08,
				Qid:    Qid{},
				Mode:   FileMode(OTRUNC),
				Atime:  90870987,
				Mtime:  1234124,
				Length: 0x23ABDDF8,
				Name:   "hello",
				UID:    "someone",
				GID:    "over the",
				MUID:   "rainbow",
			},
		}, {
			&VersionRequest{
				Tag:     45,
				MaxSize: 9384,
				Version: "9P2000",
			},
		}, {
			&VersionResponse{
				Tag:     45,
				MaxSize: 9384,
				Version: "9P2000",
			},
		}, {
			&AuthRequest{
				Tag:      45,
				AuthFid:  Fid(1234),
				Username: "someone",
				Service:  "something",
			},
		}, {
			&AuthResponse{
				Tag:     45,
				AuthQid: Qid{},
			},
		}, {
			&AttachRequest{
				Tag:      45,
				Fid:      35243,
				AuthFid:  90872354,
				Username: "",
				Service:  "weee",
			},
		}, {
			&AttachResponse{
				Tag: 45,
				Qid: Qid{},
			},
		}, {
			&ErrorResponse{
				Tag:   45,
				Error: "something something something",
			},
		}, {
			&FlushRequest{
				Tag:    45,
				OldTag: 23453,
			},
		}, {
			&FlushResponse{
				Tag: 45,
			},
		}, {
			&WalkRequest{
				Tag:    45,
				Fid:    1234,
				NewFid: 3452345,
				Names: []string{
					"ongo",
					"bongo",
					"filliyonko",
					"megatronko",
				},
			},
		}, {
			&WalkResponse{
				Tag: 45,
				Qids: []Qid{
					Qid{},
					Qid{},
					Qid{},
				},
			},
		}, {
			&OpenRequest{
				Tag:  45,
				Fid:  21343,
				Mode: 4,
			},
		}, {
			&OpenResponse{
				Tag:    45,
				Qid:    Qid{},
				IOUnit: 1234123,
			},
		}, {
			&CreateRequest{
				Tag:         45,
				Fid:         12343,
				Name:        "wakakaaka",
				Permissions: DMDIR,
				Mode:        4,
			},
		}, {
			&CreateResponse{
				Tag:    45,
				Qid:    Qid{},
				IOUnit: 433535,
			},
		}, {
			&ReadRequest{
				Tag:    45,
				Fid:    5343,
				Offset: 359842382234,
				Count:  23423,
			},
		}, {
			&ReadResponse{
				Tag:  45,
				Data: []byte("ooooh nooo it's full of data"),
			},
		}, {
			&WriteRequest{
				Tag:    45,
				Fid:    254334,
				Offset: 21304978234,
				Data:   []byte("something to write"),
			},
		}, {
			&WriteResponse{
				Tag:   45,
				Count: 12,
			},
		}, {
			&ClunkRequest{
				Tag: 45,
				Fid: 23123,
			},
		}, {
			&ClunkResponse{
				Tag: 45,
			},
		}, {
			&RemoveRequest{
				Tag: 45,
				Fid: 1234,
			},
		}, {
			&RemoveResponse{
				Tag: 45,
			},
		}, {
			&StatRequest{
				Tag: 45,
				Fid: 12341234,
			},
		}, {
			&StatResponse{
				Tag:  45,
				Stat: Stat{},
			},
		}, {
			&WriteStatRequest{
				Tag:  45,
				Fid:  12342134,
				Stat: Stat{},
			},
		}, {
			&WriteStatResponse{
				Tag: 45,
			},
		},
	}
	for i, tt := range tests {
		reencode(i, tt.in, t)
	}
}
<commit_msg>gofmt -s<commit_after>package protocol

import (
	"bytes"
	"reflect"
	"testing"
)

// Test if the types live up to their interface
var (
	_ Codec   = (*Qid)(nil)
	_ Codec   = (*Stat)(nil)
	_ Message = (*VersionRequest)(nil)
	_ Message = (*VersionResponse)(nil)
	_ Message = (*AuthRequest)(nil)
	_ Message = (*AuthResponse)(nil)
	_ Message = (*AttachRequest)(nil)
	_ Message = (*AttachResponse)(nil)
	_ Message = (*ErrorResponse)(nil)
	_ Message = (*FlushRequest)(nil)
	_ Message = (*FlushResponse)(nil)
	_ Message = (*WalkRequest)(nil)
	_ Message = (*WalkResponse)(nil)
	_ Message = (*OpenRequest)(nil)
	_ Message = (*OpenResponse)(nil)
	_ Message = (*CreateRequest)(nil)
	_ Message = (*CreateResponse)(nil)
	_ Message = (*ReadRequest)(nil)
	_ Message = (*ReadResponse)(nil)
	_ Message = (*WriteRequest)(nil)
	_ Message = (*WriteResponse)(nil)
	_ Message = (*ClunkRequest)(nil)
	_ Message = (*ClunkResponse)(nil)
	_ Message = (*RemoveRequest)(nil)
	_ Message = (*RemoveResponse)(nil)
	_ Message = (*StatRequest)(nil)
	_ Message = (*StatResponse)(nil)
	_ Message = (*WriteStatRequest)(nil)
	_ Message = (*WriteStatResponse)(nil)
)

func reencode(i int, in Codec, t *testing.T) {
	// Magic to get the basic type, not the pointer type
	inputType := reflect.ValueOf(in).Elem().Type()
	var other Codec
	buf := new(bytes.Buffer)
	if inm, ok := in.(Message); ok {
		// Full message handling, including length/type wrapper.
		if err := Encode(buf, inm); err != nil {
			t.Errorf("test %d: encoding failed for %v: %v", i, inputType, err)
			return
		}

		var err error
		other, err = Decode(buf)
		if err != nil {
			t.Errorf("test %d: decoding failed for %v: %v", i, inputType, err)
			return
		}
	} else {
		// Only encode/decode the message part itself.
		other = reflect.New(inputType).Interface().(Codec)

		if err := in.Encode(buf); err != nil {
			t.Errorf("test %d: encoding failed for %v: %v", i, inputType, err)
			return
		}

		if err := other.Decode(buf); err != nil {
			t.Errorf("test %d: decoding failed for %v: %v", i, inputType, err)
			return
		}
	}

	// Comparing the interfaces would result in pointer comparisons, so get the basic type first
	if !reflect.DeepEqual(reflect.ValueOf(in).Elem().Interface(), reflect.ValueOf(other).Elem().Interface()) {
		t.Errorf("test %d: %v did not reencode correctly", i, inputType)
	}
}

// This test does NOT guarantee proper 9P2000 spec coding, but ensures at least
// that all codecs are compatible with themselves.
func TestReencode(t *testing.T) {
	tests := []struct {
		in Codec
	}{
		{
			&Qid{
				Type:    QTDIR,
				Version: 0x12340987,
				Path:    0x10293874FFFFFF,
			},
		}, {
			&Stat{
				Type:   0xDEAD,
				Dev:    0xABCDEF08,
				Qid:    Qid{},
				Mode:   FileMode(OTRUNC),
				Atime:  90870987,
				Mtime:  1234124,
				Length: 0x23ABDDF8,
				Name:   "hello",
				UID:    "someone",
				GID:    "over the",
				MUID:   "rainbow",
			},
		}, {
			&VersionRequest{
				Tag:     45,
				MaxSize: 9384,
				Version: "9P2000",
			},
		}, {
			&VersionResponse{
				Tag:     45,
				MaxSize: 9384,
				Version: "9P2000",
			},
		}, {
			&AuthRequest{
				Tag:      45,
				AuthFid:  Fid(1234),
				Username: "someone",
				Service:  "something",
			},
		}, {
			&AuthResponse{
				Tag:     45,
				AuthQid: Qid{},
			},
		}, {
			&AttachRequest{
				Tag:      45,
				Fid:      35243,
				AuthFid:  90872354,
				Username: "",
				Service:  "weee",
			},
		}, {
			&AttachResponse{
				Tag: 45,
				Qid: Qid{},
			},
		}, {
			&ErrorResponse{
				Tag:   45,
				Error: "something something something",
			},
		}, {
			&FlushRequest{
				Tag:    45,
				OldTag: 23453,
			},
		}, {
			&FlushResponse{
				Tag: 45,
			},
		}, {
			&WalkRequest{
				Tag:    45,
				Fid:    1234,
				NewFid: 3452345,
				Names: []string{
					"ongo",
					"bongo",
					"filliyonko",
					"megatronko",
				},
			},
		}, {
			&WalkResponse{
				Tag: 45,
				Qids: []Qid{
					{},
					{},
					{},
				},
			},
		}, {
			&OpenRequest{
				Tag:  45,
				Fid:  21343,
				Mode: 4,
			},
		}, {
			&OpenResponse{
				Tag:    45,
				Qid:    Qid{},
				IOUnit: 1234123,
			},
		}, {
			&CreateRequest{
				Tag:         45,
				Fid:         12343,
				Name:        "wakakaaka",
				Permissions: DMDIR,
				Mode:        4,
			},
		}, {
			&CreateResponse{
				Tag:    45,
				Qid:    Qid{},
				IOUnit: 433535,
			},
		}, {
			&ReadRequest{
				Tag:    45,
				Fid:    5343,
				Offset: 359842382234,
				Count:  23423,
			},
		}, {
			&ReadResponse{
				Tag:  45,
				Data: []byte("ooooh nooo it's full of data"),
			},
		}, {
			&WriteRequest{
				Tag:    45,
				Fid:    254334,
				Offset: 21304978234,
				Data:   []byte("something to write"),
			},
		}, {
			&WriteResponse{
				Tag:   45,
				Count: 12,
			},
		}, {
			&ClunkRequest{
				Tag: 45,
				Fid: 23123,
			},
		}, {
			&ClunkResponse{
				Tag: 45,
			},
		}, {
			&RemoveRequest{
				Tag: 45,
				Fid: 1234,
			},
		}, {
			&RemoveResponse{
				Tag: 45,
			},
		}, {
			&StatRequest{
				Tag: 45,
				Fid: 12341234,
			},
		}, {
			&StatResponse{
				Tag:  45,
				Stat: Stat{},
			},
		}, {
			&WriteStatRequest{
				Tag:  45,
				Fid:  12342134,
				Stat: Stat{},
			},
		}, {
			&WriteStatResponse{
				Tag: 45,
			},
		},
	}
	for i, tt := range tests {
		reencode(i, tt.in, t)
	}
}
<|endoftext|>


<commit_before>/*
Package raw manages the raw launch protocol.

The raw format are timed position,speed commands using the same values as the
Launch's BLE protocol.

The file format is a JSON encoded array of timed actions:

	[
	  {
	    "at": <time>,
	    "pos": <position>,
	    "spd": <speed>
	  },
	  ...
	]

	time    : integer, time in ms when the action is executed
	position: integer, position to move to 0-100 (bottom ... top)
	speed   : integer, speed to move at 0-100 (slow ... fast)

The raw format uses the same values as the BLE protocol, giving the script the
biggest amount of control but with great power comes great responsibility ;-)

Tips

Canceling previous actions before they finish will often result in a more
smooth transition between the moves.

At speed 20% a full stroke takes ~900ms

*/
package raw
<commit_msg>raw-format: Fix ranges in doc<commit_after>/*
Package raw manages the raw launch protocol.

The raw format are timed position,speed commands using the same values as the
Launch's BLE protocol.

The file format is a JSON encoded array of timed actions:

  [
    {
      "at": <time>,
      "pos": <position>,
      "spd": <speed>
    },
    ...
  ]

  time    : integer, time in ms when the action is executed
  position: integer, position to move to 0-99 (bottom ... top)
  speed   : integer, speed to move at 20-99 (slow ... fast)

The raw format uses the same values as the BLE protocol, giving the script the
biggest amount of control but with great power comes great responsibility ;-)

Tips

Canceling previous actions before they finish will often result in a more
smooth transition between the moves.

At speed 20% a full stroke takes ~900ms

*/
package raw
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package tide

import (
	"context"
	"fmt"
	"time"

	"k8s.io/test-infra/prow/github"

	githubql "github.com/shurcooL/githubv4"
	"github.com/sirupsen/logrus"
)

type searchExecutor func(start, end time.Time) ([]PullRequest, int /*true match count*/, error)

func newSearchExecutor(ctx context.Context, ghc githubClient, log *logrus.Entry, q string) searchExecutor {
	return func(start, end time.Time) ([]PullRequest, int, error) {
		q = fmt.Sprintf("%s %s", q, dateToken(start, end))
		vars := map[string]interface{}{
			"query":        githubql.String(q),
			"searchCursor": (*githubql.String)(nil),
		}
		var totalCost, remaining int
		var totalMatches int
		var ret []PullRequest
		for {
			sq := searchQuery{}
			if err := ghc.Query(ctx, &sq, vars); err != nil {
				return nil, 0, err
			}
			totalCost += int(sq.RateLimit.Cost)
			remaining = int(sq.RateLimit.Remaining)
			totalMatches = int(sq.Search.IssueCount)
			// If the search won't return all results, abort.
			if totalMatches > 1000 {
				return nil, totalMatches, nil
			}
			for _, n := range sq.Search.Nodes {
				ret = append(ret, n.PullRequest)
			}
			if !sq.Search.PageInfo.HasNextPage {
				break
			}
			vars["searchCursor"] = githubql.NewString(sq.Search.PageInfo.EndCursor)
		}
		log.WithFields(logrus.Fields{
			"query": q,
			"start": start.String(),
			"end":   start.String(),
		}).Debugf("Query returned %d PRs and cost %d point(s). %d remaining.", len(ret), totalCost, remaining)
		return ret, totalMatches, nil
	}
}

func (q searchExecutor) search() ([]PullRequest, error) {
	prs, _, err := q.searchRange(time.Time{}, time.Now())
	return prs, err
}

func (q searchExecutor) searchSince(t time.Time) ([]PullRequest, error) {
	prs, _, err := q.searchRange(t, time.Now())
	return prs, err
}

func (q searchExecutor) searchRange(start, end time.Time) ([]PullRequest, int, error) {
	// Adjust times to be after GitHub was founded to avoid querying empty time
	// ranges.
	if start.Before(github.FoundingYear) {
		start = github.FoundingYear
	}
	if end.Before(github.FoundingYear) {
		end = github.FoundingYear
	}

	prs, count, err := q(start, end)
	if err != nil {
		return nil, 0, err
	}

	if count <= 1000 {
		// The search returned all the results for the query.
		return prs, len(prs), nil
	}
	// The query returned too many results, we need to partition it.
	prs, err = q.partitionSearchRange(start, end, count)
	return prs, len(prs), err
}

func (q searchExecutor) partitionSearchRange(start, end time.Time, count int) ([]PullRequest, error) {
	partition := partitionTime(start, end, count, 900)
	// Search right side...
	rPRs, rCount, err := q.searchRange(partition, end)
	if err != nil {
		return nil, err
	}

	// Search left side...
	// For the left side we can deduce the count in advance.
	lCount := count - rCount
	// If the count is too large we can skip the initial search and go straight to
	// partitioning to save an API token.
	var lPRs []PullRequest
	if lCount <= 1000 {
		lPRs, _, err = q.searchRange(start, partition)
	} else {
		lPRs, err = q.partitionSearchRange(start, partition, lCount)
	}
	if err != nil {
		return nil, err
	}

	return append(lPRs, rPRs...), nil
}

func partitionTime(start, end time.Time, count, goalSize int) time.Time {
	duration := end.Sub(start)
	if count < goalSize*2 {
		// Choose the midpoint.
		return start.Add(duration / 2)
	}
	// Choose the point that will make the partitionTime->end range contain goalSize
	// many results assuming a uniform distribution over time.
	// Use floats to avoid duration overflow.
	// ->    end - (duration * goalSize / count)
	diff := time.Duration(-float64(duration) * (float64(goalSize) / float64(count)))
	return end.Add(diff)
}

// dateToken generates a GitHub search query token for the specified date range.
// See: https://help.github.com/articles/understanding-the-search-syntax/#query-for-dates
func dateToken(start, end time.Time) string {
	// Github's GraphQL API silently fails if you provide it with an invalid time
	// string.
	// Dates before 1970 (unix epoch) are considered invalid.
	startString, endString := "*", "*"
	if start.Year() >= 1970 {
		startString = start.Format(github.SearchTimeFormat)
	}
	if end.Year() >= 1970 {
		endString = end.Format(github.SearchTimeFormat)
	}
	return fmt.Sprintf("updated:%s..%s", startString, endString)
}
<commit_msg>Fix Tide search to only include the current date token in the query.<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package tide

import (
	"context"
	"fmt"
	"time"

	"k8s.io/test-infra/prow/github"

	githubql "github.com/shurcooL/githubv4"
	"github.com/sirupsen/logrus"
)

type searchExecutor func(start, end time.Time) ([]PullRequest, int /*true match count*/, error)

func newSearchExecutor(ctx context.Context, ghc githubClient, log *logrus.Entry, q string) searchExecutor {
	return func(start, end time.Time) ([]PullRequest, int, error) {
		datedQuery := fmt.Sprintf("%s %s", q, dateToken(start, end))
		vars := map[string]interface{}{
			"query":        githubql.String(datedQuery),
			"searchCursor": (*githubql.String)(nil),
		}
		var totalCost, remaining int
		var totalMatches int
		var ret []PullRequest
		for {
			sq := searchQuery{}
			if err := ghc.Query(ctx, &sq, vars); err != nil {
				return nil, 0, fmt.Errorf("error handling query: %q, err: %v", datedQuery, err)
			}
			totalCost += int(sq.RateLimit.Cost)
			remaining = int(sq.RateLimit.Remaining)
			totalMatches = int(sq.Search.IssueCount)
			// If the search won't return all results, abort.
			if totalMatches > 1000 {
				return nil, totalMatches, nil
			}
			for _, n := range sq.Search.Nodes {
				ret = append(ret, n.PullRequest)
			}
			if !sq.Search.PageInfo.HasNextPage {
				break
			}
			vars["searchCursor"] = githubql.NewString(sq.Search.PageInfo.EndCursor)
		}
		log.WithFields(logrus.Fields{
			"query": datedQuery,
			"start": start.String(),
			"end":   start.String(),
		}).Debugf("Query returned %d PRs and cost %d point(s). %d remaining.", len(ret), totalCost, remaining)
		return ret, totalMatches, nil
	}
}

func (q searchExecutor) search() ([]PullRequest, error) {
	prs, _, err := q.searchRange(time.Time{}, time.Now())
	return prs, err
}

func (q searchExecutor) searchSince(t time.Time) ([]PullRequest, error) {
	prs, _, err := q.searchRange(t, time.Now())
	return prs, err
}

func (q searchExecutor) searchRange(start, end time.Time) ([]PullRequest, int, error) {
	// Adjust times to be after GitHub was founded to avoid querying empty time
	// ranges.
	if start.Before(github.FoundingYear) {
		start = github.FoundingYear
	}
	if end.Before(github.FoundingYear) {
		end = github.FoundingYear
	}

	prs, count, err := q(start, end)
	if err != nil {
		return nil, 0, err
	}

	if count <= 1000 {
		// The search returned all the results for the query.
		return prs, len(prs), nil
	}
	// The query returned too many results, we need to partition it.
	prs, err = q.partitionSearchRange(start, end, count)
	return prs, len(prs), err
}

func (q searchExecutor) partitionSearchRange(start, end time.Time, count int) ([]PullRequest, error) {
	partition := partitionTime(start, end, count, 900)
	// Search right side...
	rPRs, rCount, err := q.searchRange(partition, end)
	if err != nil {
		return nil, err
	}

	// Search left side...
	// For the left side we can deduce the count in advance.
	lCount := count - rCount
	// If the count is too large we can skip the initial search and go straight to
	// partitioning to save an API token.
	var lPRs []PullRequest
	if lCount <= 1000 {
		lPRs, _, err = q.searchRange(start, partition)
	} else {
		lPRs, err = q.partitionSearchRange(start, partition, lCount)
	}
	if err != nil {
		return nil, err
	}

	return append(lPRs, rPRs...), nil
}

func partitionTime(start, end time.Time, count, goalSize int) time.Time {
	duration := end.Sub(start)
	if count < goalSize*2 {
		// Choose the midpoint.
		return start.Add(duration / 2)
	}
	// Choose the point that will make the partitionTime->end range contain goalSize
	// many results assuming a uniform distribution over time.
	// Use floats to avoid duration overflow.
	// ->    end - (duration * goalSize / count)
	diff := time.Duration(-float64(duration) * (float64(goalSize) / float64(count)))
	return end.Add(diff)
}

// dateToken generates a GitHub search query token for the specified date range.
// See: https://help.github.com/articles/understanding-the-search-syntax/#query-for-dates
func dateToken(start, end time.Time) string {
	// Github's GraphQL API silently fails if you provide it with an invalid time
	// string.
	// Dates before 1970 (unix epoch) are considered invalid.
	startString, endString := "*", "*"
	if start.Year() >= 1970 {
		startString = start.Format(github.SearchTimeFormat)
	}
	if end.Year() >= 1970 {
		endString = end.Format(github.SearchTimeFormat)
	}
	return fmt.Sprintf("updated:%s..%s", startString, endString)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"math"
	"time"

	"../sensors"

	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	// "github.com/kidoman/embd/sensor/bmp180"
	"github.com/westphae/goflying/ahrs"
	"github.com/westphae/goflying/ahrsweb"
)

var (
	i2cbus           embd.I2CBus
	myPressureReader sensors.PressureReader
	myIMUReader      sensors.IMUReader
)

func initI2CSensors() {
	i2cbus = embd.NewI2CBus(1)

	go pollSensors()
	go sensorAttitudeSender()
}

func pollSensors() {
	timer := time.NewTicker(4 * time.Second)
	for {
		<-timer.C

		// If it's not currently connected, try connecting to pressure sensor
		if globalSettings.Sensors_Enabled && !globalStatus.PressureSensorConnected {
			globalStatus.PressureSensorConnected = initPressureSensor() // I2C temperature and pressure altitude.
			go tempAndPressureSender()
		}

		// If it's not currently connected, try connecting to IMU
		if globalSettings.Sensors_Enabled && !globalStatus.IMUConnected {
			globalStatus.IMUConnected = initIMU() // I2C accel/gyro/mag.
		}
	}
}

func initPressureSensor() (ok bool) {
	bmp, err := sensors.NewBMP280(&i2cbus, 100*time.Millisecond)
	if err == nil {
		myPressureReader = bmp
		log.Println("AHRS Info: Successfully initialized BMP280")
		return true
	}

	// TODO westphae: make bmp180.go to fit bmp interface
	//for i := 0; i < 5; i++ {
	//	myBMPX80 = bmp180.New(i2cbus)
	//	_, err := myBMPX80.Temperature() // Test to see if it works, since bmp180.New doesn't return err
	//	if err != nil {
	//		time.Sleep(250 * time.Millisecond)
	//	} else {
	//		globalStatus.PressureSensorConnected = true
	//		log.Println("AHRS Info: Successfully initialized BMP180")
	//		return nil
	//	}
	//}

	log.Println("AHRS Info: couldn't initialize BMP280 or BMP180")
	return false
}

func initIMU() (ok bool) {
	log.Println("AHRS Info: attempting to connect to MPU9250")
	imu, err := sensors.NewMPU9250()
	if err == nil {
		myIMUReader = imu
		time.Sleep(200 * time.Millisecond)
		log.Println("AHRS Info: Successfully connected MPU9250, running calibration")
		myIMUReader.Calibrate(1, 5)
		log.Println("AHRS Info: Successfully calibrated MPU9250")
		return true
	}

	// TODO westphae: try to connect to MPU9150

	log.Println("AHRS Error: couldn't initialize MPU9250 or MPU9150")
	return false
}

func tempAndPressureSender() {
	var (
		temp     float64
		press    float64
		altLast  float64
		altitude float64
		err      error
		dt       float64 = 0.1
	)

	// Initialize variables for rate of climb calc
	u := 5 / (5 + float64(dt)) // Use 5 sec decay time for rate of climb, slightly faster than typical VSI
	if press, err = myPressureReader.Pressure(); err != nil {
		log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
		myPressureReader.Close()
		globalStatus.PressureSensorConnected = false // Try reconnecting a little later
	}
	altLast = CalcAltitude(press)

	timer := time.NewTicker(time.Duration(1000*dt) * time.Millisecond)
	for globalSettings.Sensors_Enabled && globalStatus.PressureSensorConnected {
		<-timer.C

		// Read temperature and pressure altitude.
		temp, err = myPressureReader.Temperature()
		if err != nil {
			log.Printf("AHRS Error: Couldn't read temperature from sensor: %s", err)
		}
		press, err = myPressureReader.Pressure()
		if err != nil {
			log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
			myPressureReader.Close()
			globalStatus.PressureSensorConnected = false // Try reconnecting a little later
			break
		}

		// Update the Situation data.
		mySituation.mu_Pressure.Lock()
		mySituation.LastTempPressTime = stratuxClock.Time
		mySituation.Temp = temp
		altitude = CalcAltitude(press)
		mySituation.Pressure_alt = altitude
		// Assuming timer is reasonably accurate, use a regular ewma
		mySituation.RateOfClimb = u*mySituation.RateOfClimb + (1-u)*(altitude-altLast)/(float64(dt)/60)
		mySituation.mu_Pressure.Unlock()
		altLast = altitude
	}
}

func sensorAttitudeSender() {
	log.Println("AHRS Info: Setting up sensorAttitudeSender")
	var (
		roll, pitch, heading                              float64
		t                                                 time.Time
		s                                                 ahrs.AHRSProvider
		m                                                 *ahrs.Measurement
		a1, a2, a3, b1, b2, b3, m1, m2, m3                float64 // IMU measurements
		ff       					  *[3][3]float64 // Sensor orientation matrix
		mpuError, magError                                error
		headingMag, slipSkid, turnRate, gLoad             float64
		errHeadingMag, errSlipSkid, errTurnRate, errGLoad error
	)
	m = ahrs.NewMeasurement()

	//TODO westphae: remove this logging when finished testing, or make it optional in settings
	logger := ahrs.NewSensorLogger(fmt.Sprintf("/var/log/sensors_%s.csv", time.Now().Format("20060102_150405")),
		"T", "TS", "A1", "A2", "A3", "H1", "H2", "H3", "M1", "M2", "M3", "TW", "W1", "W2", "W3", "TA", "Alt",
		"pitch", "roll", "heading", "mag_heading", "slip_skid", "turn_rate", "g_load", "T_Attitude")
	defer logger.Close()

	ahrswebListener, err := ahrsweb.NewKalmanListener()
	if err != nil {
		log.Printf("AHRS Error: couldn't start ahrswebListener: %s\n", err.Error())
	} else {
		defer ahrswebListener.Close()
	}

	// Need a 10Hz sampling freq
	timer := time.NewTicker(100 * time.Millisecond) // ~10Hz update.
	for {
		ff = new([3][3]float64)
		if globalSettings.IMUMapping[0]==0 { // if unset, default to RY836AI
			globalSettings.IMUMapping[0] = -1 // +2
			globalSettings.IMUMapping[1] = +2 // -1
			globalSettings.IMUMapping[2] = -3 // +3
			saveSettings()
		}
		f := globalSettings.IMUMapping
		for i := 0; i < 3; i++ {
			if f[i] < 0 {
				ff[i][-f[i] - 1] = -1
			} else {
				ff[i][f[i] - 1] = +1
			}
		}

		<-timer.C
		for (globalSettings.Sensors_Enabled && globalStatus.IMUConnected) {
			<-timer.C
			t = stratuxClock.Time
			m.T = float64(t.UnixNano() / 1000) / 1e6

			_, b1, b2, b3, a1, a2, a3, m1, m2, m3, mpuError, magError = myIMUReader.ReadRaw()
			// This is how the RY83XAI is wired up
			//m.A1, m.A2, m.A3 = -a2, +a1, -a3
			//m.B1, m.B2, m.B3 = +b2, -b1, +b3
			//m.M1, m.M2, m.M3 = +m1, +m2, +m3
			// This is how the OpenFlightBox board is wired up
			//m.A1, m.A2, m.A3 = +a1, -a2, +a3
			//m.B1, m.B2, m.B3 = -b1, +b2, -b3
			//m.M1, m.M2, m.M3 = +m2, +m1, +m3
			m.A1 = -(ff[0][0]*a1 + ff[0][1]*a2 + ff[0][2]*a3)
			m.A2 = -(ff[1][0]*a1 + ff[1][1]*a2 + ff[1][2]*a3)
			m.A3 = -(ff[2][0]*a1 + ff[2][1]*a2 + ff[2][2]*a3)
			m.B1 =   ff[0][0]*b1 + ff[0][1]*b2 + ff[0][2]*b3
			m.B2 =   ff[1][0]*b1 + ff[1][1]*b2 + ff[1][2]*b3
			m.B3 =   ff[2][0]*b1 + ff[2][1]*b2 + ff[2][2]*b3
			m.M1 =   ff[0][0]*m1 + ff[0][1]*m2 + ff[0][2]*m3
			m.M2 =   ff[1][0]*m1 + ff[1][1]*m2 + ff[1][2]*m3
			m.M3 =   ff[2][0]*m1 + ff[2][1]*m2 + ff[2][2]*m3
			m.SValid = mpuError == nil
			m.MValid = magError == nil
			if mpuError != nil {
				log.Printf("AHRS Gyro/Accel Error: %s\n", mpuError)
				myIMUReader.Close()
				globalStatus.IMUConnected = false
			}
			if magError != nil {
				log.Printf("AHRS Magnetometer Error, not using for this run: %s\n", magError)
				m.MValid = false
				// Don't necessarily disconnect here, unless AHRSProvider deeply depends on magnetometer
			}

			m.WValid = t.Sub(mySituation.LastGroundTrackTime) < 500*time.Millisecond
			if m.WValid {
				m.W1 = mySituation.GroundSpeed * math.Sin(float64(mySituation.TrueCourse) * ahrs.Deg)
				m.W2 = mySituation.GroundSpeed * math.Cos(float64(mySituation.TrueCourse) * ahrs.Deg)
				if globalStatus.PressureSensorConnected {
					m.W3 = mySituation.RateOfClimb * 60 / 6076.12
				} else {
					m.W3 = float64(mySituation.GPSVertVel) * 3600 / 6076.12
				}
			}

			// Run the AHRS calcs
			if s == nil { // s is nil if we should (re-)initialize the Kalman state
				log.Println("AHRS Info: initializing new simple AHRS")
				s = ahrs.InitializeSimple(m, "")
			}
			s.Compute(m)

			// Debugging server:
			if ahrswebListener != nil {
				ahrswebListener.Send(s.GetState(), m)
			}

			// If we have valid AHRS info, then send
			if s.Valid() {
				mySituation.mu_Attitude.Lock()

				roll, pitch, heading = s.CalcRollPitchHeading()
				mySituation.Roll = roll / ahrs.Deg
				mySituation.Pitch = pitch / ahrs.Deg
				mySituation.Gyro_heading = heading / ahrs.Deg

				if headingMag, errHeadingMag = myIMUReader.MagHeading(); errHeadingMag != nil {
					log.Printf("AHRS MPU Error: %s\n", errHeadingMag.Error())
				} else {
					mySituation.Mag_heading = headingMag
				}

				if slipSkid, errSlipSkid = myIMUReader.SlipSkid(); errSlipSkid != nil {
					log.Printf("AHRS MPU Error: %s\n", errSlipSkid.Error())
				} else {
					mySituation.SlipSkid = slipSkid
				}

				if turnRate, errTurnRate = myIMUReader.RateOfTurn(); errTurnRate != nil {
					log.Printf("AHRS MPU Error: %s\n", errTurnRate.Error())
				} else {
					mySituation.RateOfTurn = turnRate
				}

				if gLoad, errGLoad = myIMUReader.GLoad(); errGLoad != nil {
					log.Printf("AHRS MPU Error: %s\n", errGLoad.Error())
				} else {
					mySituation.GLoad = gLoad
				}

				mySituation.LastAttitudeTime = t
				mySituation.mu_Attitude.Unlock()

				// makeFFAHRSSimReport() // simultaneous use of GDL90 and FFSIM not supported in FF 7.5.1 or later. Function definition will be kept for AHRS debugging and future workarounds.
			} else {
				s = nil
				mySituation.LastAttitudeTime = time.Time{}
			}

			makeAHRSGDL90Report() // Send whether or not valid - the function will invalidate the values as appropriate

			logger.Log(
				float64(t.UnixNano() / 1000)/1e6,
				m.T, m.A1, m.A2, m.A3, m.B1, m.B2, m.B3, m.M1, m.M2, m.M3,
				float64(mySituation.LastGroundTrackTime.UnixNano() / 1000)/1e6, m.W1, m.W2, m.W3,
				float64(mySituation.LastTempPressTime.UnixNano() / 1000)/1e6, mySituation.Pressure_alt,
				pitch/ahrs.Deg, roll/ahrs.Deg, heading/ahrs.Deg, headingMag, slipSkid, turnRate, gLoad,
				float64(mySituation.LastAttitudeTime.UnixNano() / 1000)/1e6)
		}
	}
}
<commit_msg>sensorAttitudeSender is a little more robust.<commit_after>package main

import (
	"fmt"
	"log"
	"math"
	"time"

	"../sensors"

	"github.com/kidoman/embd"
	_ "github.com/kidoman/embd/host/all"
	// "github.com/kidoman/embd/sensor/bmp180"
	"github.com/westphae/goflying/ahrs"
	"github.com/westphae/goflying/ahrsweb"
)

const numRetries uint8 = 5

var (
	i2cbus           embd.I2CBus
	myPressureReader sensors.PressureReader
	myIMUReader      sensors.IMUReader
)

func initI2CSensors() {
	i2cbus = embd.NewI2CBus(1)

	go pollSensors()
	go sensorAttitudeSender()
}

func pollSensors() {
	timer := time.NewTicker(4 * time.Second)
	for {
		<-timer.C

		// If it's not currently connected, try connecting to pressure sensor
		if globalSettings.Sensors_Enabled && !globalStatus.PressureSensorConnected {
			globalStatus.PressureSensorConnected = initPressureSensor() // I2C temperature and pressure altitude.
			go tempAndPressureSender()
		}

		// If it's not currently connected, try connecting to IMU
		if globalSettings.Sensors_Enabled && !globalStatus.IMUConnected {
			globalStatus.IMUConnected = initIMU() // I2C accel/gyro/mag.
		}
	}
}

func initPressureSensor() (ok bool) {
	bmp, err := sensors.NewBMP280(&i2cbus, 100*time.Millisecond)
	if err == nil {
		myPressureReader = bmp
		log.Println("AHRS Info: Successfully initialized BMP280")
		return true
	}

	// TODO westphae: make bmp180.go to fit bmp interface
	//for i := 0; i < 5; i++ {
	//	myBMPX80 = bmp180.New(i2cbus)
	//	_, err := myBMPX80.Temperature() // Test to see if it works, since bmp180.New doesn't return err
	//	if err != nil {
	//		time.Sleep(250 * time.Millisecond)
	//	} else {
	//		globalStatus.PressureSensorConnected = true
	//		log.Println("AHRS Info: Successfully initialized BMP180")
	//		return nil
	//	}
	//}

	log.Println("AHRS Info: couldn't initialize BMP280 or BMP180")
	return false
}

func tempAndPressureSender() {
	var (
		temp     float64
		press    float64
		altLast  float64
		altitude float64
		err      error
		dt       float64 = 0.1
		failnum  uint8
	)

	// Initialize variables for rate of climb calc
	u := 5 / (5 + float64(dt)) // Use 5 sec decay time for rate of climb, slightly faster than typical VSI
	time.Sleep(time.Second)
	if press, err = myPressureReader.Pressure(); err != nil {
		log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
		myPressureReader.Close()
		globalStatus.PressureSensorConnected = false // Try reconnecting a little later
	}
	altLast = CalcAltitude(press)

	timer := time.NewTicker(time.Duration(1000*dt) * time.Millisecond)
	for globalSettings.Sensors_Enabled && globalStatus.PressureSensorConnected {
		<-timer.C

		// Read temperature and pressure altitude.
		temp, err = myPressureReader.Temperature()
		if err != nil {
			log.Printf("AHRS Error: Couldn't read temperature from sensor: %s", err)
		}
		press, err = myPressureReader.Pressure()
		if err != nil {
			log.Printf("AHRS Error: Couldn't read pressure from sensor: %s", err)
			failnum += 1
			if failnum > numRetries {
				log.Printf("AHRS Error: Couldn't read pressure from sensor %d times, closing BMP: %s", failnum, err)
				myPressureReader.Close()
				globalStatus.PressureSensorConnected = false // Try reconnecting a little later
				break
			}
		}

		// Update the Situation data.
		mySituation.mu_Pressure.Lock()
		mySituation.LastTempPressTime = stratuxClock.Time
		mySituation.Temp = temp
		altitude = CalcAltitude(press)
		mySituation.Pressure_alt = altitude
		// Assuming timer is reasonably accurate, use a regular ewma
		mySituation.RateOfClimb = u*mySituation.RateOfClimb + (1-u)*(altitude-altLast)/(float64(dt)/60)
		mySituation.mu_Pressure.Unlock()
		altLast = altitude
	}
}

func initIMU() (ok bool) {
	log.Println("AHRS Info: attempting to connect to MPU9250")
	imu, err := sensors.NewMPU9250()
	if err == nil {
		myIMUReader = imu
		time.Sleep(200 * time.Millisecond)
		log.Println("AHRS Info: Successfully connected MPU9250, running calibration")
		myIMUReader.Calibrate(1, 5)
		log.Println("AHRS Info: Successfully calibrated MPU9250")
		return true
	}

	// TODO westphae: try to connect to MPU9150

	log.Println("AHRS Error: couldn't initialize MPU9250 or MPU9150")
	return false
}

func sensorAttitudeSender() {
	var (
		roll, pitch, heading                              float64
		t                                                 time.Time
		s                                                 ahrs.AHRSProvider
		m                                                 *ahrs.Measurement
		a1, a2, a3, b1, b2, b3, m1, m2, m3                float64 // IMU measurements
		ff       					  *[3][3]float64 // Sensor orientation matrix
		mpuError, magError                                error
		headingMag, slipSkid, turnRate, gLoad             float64
		errHeadingMag, errSlipSkid, errTurnRate, errGLoad error
		failnum						  uint8
	)
	m = ahrs.NewMeasurement()

	//TODO westphae: remove this logging when finished testing, or make it optional in settings
	logger := ahrs.NewSensorLogger(fmt.Sprintf("/var/log/sensors_%s.csv", time.Now().Format("20060102_150405")),
		"T", "TS", "A1", "A2", "A3", "H1", "H2", "H3", "M1", "M2", "M3", "TW", "W1", "W2", "W3", "TA", "Alt",
		"pitch", "roll", "heading", "mag_heading", "slip_skid", "turn_rate", "g_load", "T_Attitude")
	defer logger.Close()

	ahrswebListener, err := ahrsweb.NewKalmanListener()
	if err != nil {
		log.Printf("AHRS Error: couldn't start ahrswebListener: %s\n", err.Error())
	} else {
		defer ahrswebListener.Close()
	}

	// Need a 10Hz sampling freq
	timer := time.NewTicker(100 * time.Millisecond) // ~10Hz update.
	for {
		log.Println("AHRS Info: Initializing sensorAttitudeSender")
		ff = new([3][3]float64)
		if globalSettings.IMUMapping[0]==0 { // if unset, default to RY836AI
			globalSettings.IMUMapping[0] = -1 // +2
			globalSettings.IMUMapping[1] = +2 // -1
			globalSettings.IMUMapping[2] = -3 // +3
			saveSettings()
		}
		f := globalSettings.IMUMapping
		for i := 0; i < 3; i++ {
			if f[i] < 0 {
				ff[i][-f[i] - 1] = -1
			} else {
				ff[i][f[i] - 1] = +1
			}
		}

		failnum = 0
		<-timer.C
		for (globalSettings.Sensors_Enabled && globalStatus.IMUConnected) {
			<-timer.C
			t = stratuxClock.Time
			m.T = float64(t.UnixNano() / 1000) / 1e6

			_, b1, b2, b3, a1, a2, a3, m1, m2, m3, mpuError, magError = myIMUReader.ReadRaw()
			// This is how the RY83XAI is wired up
			//m.A1, m.A2, m.A3 = -a2, +a1, -a3
			//m.B1, m.B2, m.B3 = +b2, -b1, +b3
			//m.M1, m.M2, m.M3 = +m1, +m2, +m3
			// This is how the OpenFlightBox board is wired up
			//m.A1, m.A2, m.A3 = +a1, -a2, +a3
			//m.B1, m.B2, m.B3 = -b1, +b2, -b3
			//m.M1, m.M2, m.M3 = +m2, +m1, +m3
			m.A1 = -(ff[0][0]*a1 + ff[0][1]*a2 + ff[0][2]*a3)
			m.A2 = -(ff[1][0]*a1 + ff[1][1]*a2 + ff[1][2]*a3)
			m.A3 = -(ff[2][0]*a1 + ff[2][1]*a2 + ff[2][2]*a3)
			m.B1 =   ff[0][0]*b1 + ff[0][1]*b2 + ff[0][2]*b3
			m.B2 =   ff[1][0]*b1 + ff[1][1]*b2 + ff[1][2]*b3
			m.B3 =   ff[2][0]*b1 + ff[2][1]*b2 + ff[2][2]*b3
			m.M1 =   ff[0][0]*m1 + ff[0][1]*m2 + ff[0][2]*m3
			m.M2 =   ff[1][0]*m1 + ff[1][1]*m2 + ff[1][2]*m3
			m.M3 =   ff[2][0]*m1 + ff[2][1]*m2 + ff[2][2]*m3
			m.SValid = mpuError == nil
			m.MValid = magError == nil
			if mpuError != nil {
				log.Printf("AHRS Gyro/Accel Error: %s\n", mpuError)
				failnum += 1
				if failnum > numRetries {
					log.Printf("AHRS Gyro/Accel Error: failed to read %d times, restarting: %s\n", failnum, mpuError)
					myIMUReader.Close()
					globalStatus.IMUConnected = false
				}
			}
			if magError != nil {
				log.Printf("AHRS Magnetometer Error, not using for this run: %s\n", magError)
				m.MValid = false
				// Don't necessarily disconnect here, unless AHRSProvider deeply depends on magnetometer
			}

			m.WValid = t.Sub(mySituation.LastGroundTrackTime) < 500*time.Millisecond
			if m.WValid {
				m.W1 = mySituation.GroundSpeed * math.Sin(float64(mySituation.TrueCourse) * ahrs.Deg)
				m.W2 = mySituation.GroundSpeed * math.Cos(float64(mySituation.TrueCourse) * ahrs.Deg)
				if globalStatus.PressureSensorConnected {
					m.W3 = mySituation.RateOfClimb * 60 / 6076.12
				} else {
					m.W3 = float64(mySituation.GPSVertVel) * 3600 / 6076.12
				}
			}

			// Run the AHRS calcs
			if s == nil { // s is nil if we should (re-)initialize the Kalman state
				log.Println("AHRS Info: initializing new simple AHRS")
				s = ahrs.InitializeSimple(m, "")
			}
			s.Compute(m)

			// Debugging server:
			if ahrswebListener != nil {
				ahrswebListener.Send(s.GetState(), m)
			}

			// If we have valid AHRS info, then send
			if s.Valid() {
				mySituation.mu_Attitude.Lock()

				roll, pitch, heading = s.CalcRollPitchHeading()
				mySituation.Roll = roll / ahrs.Deg
				mySituation.Pitch = pitch / ahrs.Deg
				mySituation.Gyro_heading = heading / ahrs.Deg

				if headingMag, errHeadingMag = myIMUReader.MagHeading(); errHeadingMag != nil {
					log.Printf("AHRS MPU Error: %s\n", errHeadingMag.Error())
				} else {
					mySituation.Mag_heading = headingMag
				}

				if slipSkid, errSlipSkid = myIMUReader.SlipSkid(); errSlipSkid != nil {
					log.Printf("AHRS MPU Error: %s\n", errSlipSkid.Error())
				} else {
					mySituation.SlipSkid = slipSkid
				}

				if turnRate, errTurnRate = myIMUReader.RateOfTurn(); errTurnRate != nil {
					log.Printf("AHRS MPU Error: %s\n", errTurnRate.Error())
				} else {
					mySituation.RateOfTurn = turnRate
				}

				if gLoad, errGLoad = myIMUReader.GLoad(); errGLoad != nil {
					log.Printf("AHRS MPU Error: %s\n", errGLoad.Error())
				} else {
					mySituation.GLoad = gLoad
				}

				mySituation.LastAttitudeTime = t
				mySituation.mu_Attitude.Unlock()

				// makeFFAHRSSimReport() // simultaneous use of GDL90 and FFSIM not supported in FF 7.5.1 or later. Function definition will be kept for AHRS debugging and future workarounds.
			} else {
				s = nil
				mySituation.LastAttitudeTime = time.Time{}
			}

			makeAHRSGDL90Report() // Send whether or not valid - the function will invalidate the values as appropriate

			logger.Log(
				float64(t.UnixNano() / 1000)/1e6,
				m.T, m.A1, m.A2, m.A3, m.B1, m.B2, m.B3, m.M1, m.M2, m.M3,
				float64(mySituation.LastGroundTrackTime.UnixNano() / 1000)/1e6, m.W1, m.W2, m.W3,
				float64(mySituation.LastTempPressTime.UnixNano() / 1000)/1e6, mySituation.Pressure_alt,
				pitch/ahrs.Deg, roll/ahrs.Deg, heading/ahrs.Deg, headingMag, slipSkid, turnRate, gLoad,
				float64(mySituation.LastAttitudeTime.UnixNano() / 1000)/1e6)
		}
	}
}
<|endoftext|>


<commit_before>package etcd

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
)

const (
	HTTP = iota
	HTTPS
)

// See SetConsistency for how to use these constants.
const (
	// Using strings rather than iota because the consistency level
	// could be persisted to disk, so it'd be better to use
	// human-readable values.
	STRONG_CONSISTENCY = "STRONG"
	WEAK_CONSISTENCY   = "WEAK"
)

const (
	defaultBufferSize = 10
)

type Cluster struct {
	Leader   string   `json:"leader"`
	Machines []string `json:"machines"`
}

type Config struct {
	CertFile    string        `json:"certFile"`
	KeyFile     string        `json:"keyFile"`
	Scheme      string        `json:"scheme"`
	Timeout     time.Duration `json:"timeout"`
	Consistency string        `json: "consistency"`
}

type Client struct {
	cluster     Cluster `json:"cluster"`
	config      Config  `json:"config"`
	httpClient  *http.Client
	persistence io.Writer
	cURLch      chan string
}

// NewClient create a basic client that is configured to be used
// with the given machine list.
func NewClient(machines []string) *Client {
	// if an empty slice was sent in then just assume localhost
	if len(machines) == 0 {
		machines = []string{"http://127.0.0.1:4001"}
	}

	// default leader and machines
	cluster := Cluster{
		Leader:   machines[0],
		Machines: machines,
	}

	config := Config{
		// default use http
		Scheme: "http",
		// default timeout is one second
		Timeout: time.Second,
		// default consistency level is STRONG
		Consistency: STRONG_CONSISTENCY,
	}

	client := &Client{
		cluster: cluster,
		config:  config,
	}

	err := setupHttpClient(client)
	if err != nil {
		panic(err)
	}

	return client
}

// NewClientFile creates a client from a given file path.
// The given file is expected to use the JSON format.
func NewClientFile(fpath string) (*Client, error) {
	fi, err := os.Open(fpath)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := fi.Close(); err != nil {
			panic(err)
		}
	}()

	return NewClientReader(fi)
}

// NewClientReader creates a Client configured from a given reader.
// The config is expected to use the JSON format.
func NewClientReader(reader io.Reader) (*Client, error) {
	var client Client

	b, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(b, &client)
	if err != nil {
		return nil, err
	}

	err = setupHttpClient(&client)
	if err != nil {
		return nil, err
	}

	return &client, nil
}

func setupHttpClient(client *Client) error {
	if client.config.CertFile != "" && client.config.KeyFile != "" {
		err := client.SetCertAndKey(client.config.CertFile, client.config.KeyFile)
		if err != nil {
			return err
		}
	} else {
		client.config.CertFile = ""
		client.config.KeyFile = ""
		tr := &http.Transport{
			Dial: dialTimeout,
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
		client.httpClient = &http.Client{Transport: tr}
	}

	return nil
}

// SetPersistence sets a writer to which the config will be
// written every time it's changed.
func (c *Client) SetPersistence(writer io.Writer) {
	c.persistence = writer
}

// SetConsistency changes the consistency level of the client.
//
// When consistency is set to STRONG_CONSISTENCY, all requests,
// including GET, are sent to the leader.  This means that, assuming
// the absence of leader failures, GET requests are guaranteed to see
// the changes made by previous requests.
//
// When consistency is set to WEAK_CONSISTENCY, other requests
// are still sent to the leader, but GET requests are sent to a
// random server from the server pool.  This reduces the read
// load on the leader, but it's not guaranteed that the GET requests
// will see changes made by previous requests (they might have not
// yet been committed on non-leader servers).
func (c *Client) SetConsistency(consistency string) error {
	if !(consistency == STRONG_CONSISTENCY || consistency == WEAK_CONSISTENCY) {
		return errors.New("The argument must be either STRONG_CONSISTENCY or WEAK_CONSISTENCY.")
	}
	c.config.Consistency = consistency
	return nil
}

// MarshalJSON implements the Marshaller interface
// as defined by the standard JSON package.
func (c *Client) MarshalJSON() ([]byte, error) {
	b, err := json.Marshal(struct {
		Config  Config  `json:"config"`
		Cluster Cluster `json:"cluster"`
	}{
		Config:  c.config,
		Cluster: c.cluster,
	})

	if err != nil {
		return nil, err
	}

	return b, nil
}

// UnmarshalJSON implements the Unmarshaller interface
// as defined by the standard JSON package.
func (c *Client) UnmarshalJSON(b []byte) error {
	temp := struct {
		Config  Config  `json: "config"`
		Cluster Cluster `json: "cluster"`
	}{}
	err := json.Unmarshal(b, &temp)
	if err != nil {
		return err
	}

	c.cluster = temp.Cluster
	c.config = temp.Config
	return nil
}

// saveConfig saves the current config using c.persistence.
func (c *Client) saveConfig() error {
	if c.persistence != nil {
		b, err := json.Marshal(c)
		if err != nil {
			return err
		}

		_, err = c.persistence.Write(b)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Client) SetCertAndKey(cert string, key string) error {
	if cert != "" && key != "" {
		tlsCert, err := tls.LoadX509KeyPair(cert, key)

		if err != nil {
			return err
		}

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				Certificates:       []tls.Certificate{tlsCert},
				InsecureSkipVerify: true,
			},
			Dial: dialTimeout,
		}

		c.httpClient = &http.Client{Transport: tr}
		c.saveConfig()
		return nil
	}
	return errors.New("Require both cert and key path")
}

func (c *Client) SetScheme(scheme int) error {
	if scheme == HTTP {
		c.config.Scheme = "http"
		c.saveConfig()
		return nil
	}
	if scheme == HTTPS {
		c.config.Scheme = "https"
		c.saveConfig()
		return nil
	}
	return errors.New("Unknown Scheme")
}

// SetCluster updates config using the given machine list.
func (c *Client) SetCluster(machines []string) bool {
	success := c.internalSyncCluster(machines)
	return success
}

func (c *Client) GetCluster() []string {
	return c.cluster.Machines
}

// SyncCluster updates config using the internal machine list.
func (c *Client) SyncCluster() bool {
	success := c.internalSyncCluster(c.cluster.Machines)
	return success
}

// internalSyncCluster syncs cluster information using the given machine list.
func (c *Client) internalSyncCluster(machines []string) bool {
	for _, machine := range machines {
		httpPath := c.createHttpPath(machine, version+"/machines")
		resp, err := c.httpClient.Get(httpPath)
		if err != nil {
			// try another machine in the cluster
			continue
		} else {
			b, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				// try another machine in the cluster
				continue
			}

			// update Machines List
			c.cluster.Machines = strings.Split(string(b), ", ")

			// update leader
			// the first one in the machine list is the leader
			logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, c.cluster.Machines[0])
			c.cluster.Leader = c.cluster.Machines[0]

			logger.Debug("sync.machines ", c.cluster.Machines)
			c.saveConfig()
			return true
		}
	}
	return false
}

// createHttpPath creates a complete HTTP URL.
// serverName should contain both the host name and a port number, if any.
func (c *Client) createHttpPath(serverName string, _path string) string {
	u, _ := url.Parse(serverName)
	u.Path = path.Join(u.Path, "/", _path)

	if u.Scheme == "" {
		u.Scheme = "http"
	}
	return u.String()
}

// Dial with timeout.
func dialTimeout(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Second)
}

func (c *Client) updateLeader(u *url.URL) {
	var leader string
	if u.Scheme == "" {
		leader = "http://" + u.Host
	} else {
		leader = u.Scheme + "://" + u.Host
	}

	logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, leader)
	c.cluster.Leader = leader
	c.saveConfig()
}

// switchLeader switch the current leader to machines[num]
func (c *Client) switchLeader(num int) {
	logger.Debugf("switch.leader[from %v to %v]",
		c.cluster.Leader, c.cluster.Machines[num])

	c.cluster.Leader = c.cluster.Machines[num]
}

func (c *Client) OpenCURL() {
	c.cURLch = make(chan string, defaultBufferSize)
}

func (c *Client) CloseCURL() {
	c.cURLch = nil
}

func (c *Client) sendCURL(command string) {
	go func() {
		c.cURLch <- command
	}()
}

func (c *Client) RecvCURL() string {
	return <-c.cURLch
}
<commit_msg>feat(client.go) drop the cURL command if the buffer is full<commit_after>package etcd

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
)

const (
	HTTP = iota
	HTTPS
)

// See SetConsistency for how to use these constants.
const (
	// Using strings rather than iota because the consistency level
	// could be persisted to disk, so it'd be better to use
	// human-readable values.
	STRONG_CONSISTENCY = "STRONG"
	WEAK_CONSISTENCY   = "WEAK"
)

const (
	defaultBufferSize = 10
)

type Cluster struct {
	Leader   string   `json:"leader"`
	Machines []string `json:"machines"`
}

type Config struct {
	CertFile    string        `json:"certFile"`
	KeyFile     string        `json:"keyFile"`
	Scheme      string        `json:"scheme"`
	Timeout     time.Duration `json:"timeout"`
	Consistency string        `json: "consistency"`
}

type Client struct {
	cluster     Cluster `json:"cluster"`
	config      Config  `json:"config"`
	httpClient  *http.Client
	persistence io.Writer
	cURLch      chan string
}

// NewClient create a basic client that is configured to be used
// with the given machine list.
func NewClient(machines []string) *Client {
	// if an empty slice was sent in then just assume localhost
	if len(machines) == 0 {
		machines = []string{"http://127.0.0.1:4001"}
	}

	// default leader and machines
	cluster := Cluster{
		Leader:   machines[0],
		Machines: machines,
	}

	config := Config{
		// default use http
		Scheme: "http",
		// default timeout is one second
		Timeout: time.Second,
		// default consistency level is STRONG
		Consistency: STRONG_CONSISTENCY,
	}

	client := &Client{
		cluster: cluster,
		config:  config,
	}

	err := setupHttpClient(client)
	if err != nil {
		panic(err)
	}

	return client
}

// NewClientFile creates a client from a given file path.
// The given file is expected to use the JSON format.
func NewClientFile(fpath string) (*Client, error) {
	fi, err := os.Open(fpath)
	if err != nil {
		return nil, err
	}
	defer func() {
		if err := fi.Close(); err != nil {
			panic(err)
		}
	}()

	return NewClientReader(fi)
}

// NewClientReader creates a Client configured from a given reader.
// The config is expected to use the JSON format.
func NewClientReader(reader io.Reader) (*Client, error) {
	var client Client

	b, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, err
	}

	err = json.Unmarshal(b, &client)
	if err != nil {
		return nil, err
	}

	err = setupHttpClient(&client)
	if err != nil {
		return nil, err
	}

	return &client, nil
}

func setupHttpClient(client *Client) error {
	if client.config.CertFile != "" && client.config.KeyFile != "" {
		err := client.SetCertAndKey(client.config.CertFile, client.config.KeyFile)
		if err != nil {
			return err
		}
	} else {
		client.config.CertFile = ""
		client.config.KeyFile = ""
		tr := &http.Transport{
			Dial: dialTimeout,
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
		client.httpClient = &http.Client{Transport: tr}
	}

	return nil
}

// SetPersistence sets a writer to which the config will be
// written every time it's changed.
func (c *Client) SetPersistence(writer io.Writer) {
	c.persistence = writer
}

// SetConsistency changes the consistency level of the client.
//
// When consistency is set to STRONG_CONSISTENCY, all requests,
// including GET, are sent to the leader.  This means that, assuming
// the absence of leader failures, GET requests are guaranteed to see
// the changes made by previous requests.
//
// When consistency is set to WEAK_CONSISTENCY, other requests
// are still sent to the leader, but GET requests are sent to a
// random server from the server pool.  This reduces the read
// load on the leader, but it's not guaranteed that the GET requests
// will see changes made by previous requests (they might have not
// yet been committed on non-leader servers).
func (c *Client) SetConsistency(consistency string) error {
	if !(consistency == STRONG_CONSISTENCY || consistency == WEAK_CONSISTENCY) {
		return errors.New("The argument must be either STRONG_CONSISTENCY or WEAK_CONSISTENCY.")
	}
	c.config.Consistency = consistency
	return nil
}

// MarshalJSON implements the Marshaller interface
// as defined by the standard JSON package.
func (c *Client) MarshalJSON() ([]byte, error) {
	b, err := json.Marshal(struct {
		Config  Config  `json:"config"`
		Cluster Cluster `json:"cluster"`
	}{
		Config:  c.config,
		Cluster: c.cluster,
	})

	if err != nil {
		return nil, err
	}

	return b, nil
}

// UnmarshalJSON implements the Unmarshaller interface
// as defined by the standard JSON package.
func (c *Client) UnmarshalJSON(b []byte) error {
	temp := struct {
		Config  Config  `json: "config"`
		Cluster Cluster `json: "cluster"`
	}{}
	err := json.Unmarshal(b, &temp)
	if err != nil {
		return err
	}

	c.cluster = temp.Cluster
	c.config = temp.Config
	return nil
}

// saveConfig saves the current config using c.persistence.
func (c *Client) saveConfig() error {
	if c.persistence != nil {
		b, err := json.Marshal(c)
		if err != nil {
			return err
		}

		_, err = c.persistence.Write(b)
		if err != nil {
			return err
		}
	}

	return nil
}

func (c *Client) SetCertAndKey(cert string, key string) error {
	if cert != "" && key != "" {
		tlsCert, err := tls.LoadX509KeyPair(cert, key)

		if err != nil {
			return err
		}

		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				Certificates:       []tls.Certificate{tlsCert},
				InsecureSkipVerify: true,
			},
			Dial: dialTimeout,
		}

		c.httpClient = &http.Client{Transport: tr}
		c.saveConfig()
		return nil
	}
	return errors.New("Require both cert and key path")
}

func (c *Client) SetScheme(scheme int) error {
	if scheme == HTTP {
		c.config.Scheme = "http"
		c.saveConfig()
		return nil
	}
	if scheme == HTTPS {
		c.config.Scheme = "https"
		c.saveConfig()
		return nil
	}
	return errors.New("Unknown Scheme")
}

// SetCluster updates config using the given machine list.
func (c *Client) SetCluster(machines []string) bool {
	success := c.internalSyncCluster(machines)
	return success
}

func (c *Client) GetCluster() []string {
	return c.cluster.Machines
}

// SyncCluster updates config using the internal machine list.
func (c *Client) SyncCluster() bool {
	success := c.internalSyncCluster(c.cluster.Machines)
	return success
}

// internalSyncCluster syncs cluster information using the given machine list.
func (c *Client) internalSyncCluster(machines []string) bool {
	for _, machine := range machines {
		httpPath := c.createHttpPath(machine, version+"/machines")
		resp, err := c.httpClient.Get(httpPath)
		if err != nil {
			// try another machine in the cluster
			continue
		} else {
			b, err := ioutil.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				// try another machine in the cluster
				continue
			}

			// update Machines List
			c.cluster.Machines = strings.Split(string(b), ", ")

			// update leader
			// the first one in the machine list is the leader
			logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, c.cluster.Machines[0])
			c.cluster.Leader = c.cluster.Machines[0]

			logger.Debug("sync.machines ", c.cluster.Machines)
			c.saveConfig()
			return true
		}
	}
	return false
}

// createHttpPath creates a complete HTTP URL.
// serverName should contain both the host name and a port number, if any.
func (c *Client) createHttpPath(serverName string, _path string) string {
	u, _ := url.Parse(serverName)
	u.Path = path.Join(u.Path, "/", _path)

	if u.Scheme == "" {
		u.Scheme = "http"
	}
	return u.String()
}

// Dial with timeout.
func dialTimeout(network, addr string) (net.Conn, error) {
	return net.DialTimeout(network, addr, time.Second)
}

func (c *Client) updateLeader(u *url.URL) {
	var leader string
	if u.Scheme == "" {
		leader = "http://" + u.Host
	} else {
		leader = u.Scheme + "://" + u.Host
	}

	logger.Debugf("update.leader[%s,%s]", c.cluster.Leader, leader)
	c.cluster.Leader = leader
	c.saveConfig()
}

// switchLeader switch the current leader to machines[num]
func (c *Client) switchLeader(num int) {
	logger.Debugf("switch.leader[from %v to %v]",
		c.cluster.Leader, c.cluster.Machines[num])

	c.cluster.Leader = c.cluster.Machines[num]
}

func (c *Client) OpenCURL() {
	c.cURLch = make(chan string, defaultBufferSize)
}

func (c *Client) CloseCURL() {
	c.cURLch = nil
}

func (c *Client) sendCURL(command string) {
	go func() {
		select {
		case c.cURLch <- command:
		default:
		}
	}()
}

func (c *Client) RecvCURL() string {
	return <-c.cURLch
}
<|endoftext|>


<commit_before>package placetypes

/* https://raw.githubusercontent.com/whosonfirst/whosonfirst-placetypes/master/data/placetypes-spec-latest.json */
/* This file was generated by robots (cmd/mk-spec.go) at 2017-03-29 19:49:50.513397362 +0000 UTC */

const Specification string = `{"102312321": {"role": "optional", "name": "microhood", "parent": [102312319], "names": {}}, "421205763": {"role": "common_optional", "name": "borough", "parent": [102312317, 404221409], "names": {}}, "102312325": {"role": "common_optional", "name": "venue", "parent": [102312327, 102312329, 102312331, 102312321, 102312319], "names": {}}, "102312327": {"role": "common_optional", "name": "building", "parent": [102312329, 102312331, 102312321, 102312319], "names": {}}, "102312329": {"role": "common_optional", "name": "address", "parent": [102312331, 102312321, 102312319], "names": {}}, "102312331": {"role": "common_optional", "name": "campus", "parent": [102312321, 102312319, 102312323, 102312317, 404221409], "names": {}}, "404528653": {"role": "common_optional", "name": "ocean", "parent": [102312341], "names": {}}, "102312335": {"role": "common_optional", "name": "empire", "parent": [102312309], "names": {}}, "102312323": {"role": "optional", "name": "macrohood", "parent": [421205763, 102312317], "names": {}}, "102312341": {"role": "common_optional", "name": "planet", "parent": [], "names": {}}, "1108906905": {"role": "common_optional", "name": "intersection", "parent": [102312331, 102312321, 102312319], "names": {}}, "470996387": {"role": "common_optional", "name": "postalcode", "parent": [102312317, 404221409, 102312313, 102312311], "names": {}}, "1108746739": {"role": "common_optional", "name": "constituency", "parent": [], "names": {}}, "102320821": {"role": "common_optional", "name": "dependency", "parent": [102312307], "names": {}}, "136057795": {"role": "common_optional", "name": "timezone", "parent": [102312307, 102312309, 102312341], "names": {}}, "404528655": {"role": "common_optional", "name": "marinearea", "parent": [102312307, 102312309, 102312341], "names": {}}, "102371933": {"role": "optional", "name": "metroarea", "parent": [], "names": {}}, "404221409": {"role": "common_optional", "name": "localadmin", "parent": [102312313, 102312311], "names": {}}, "404221411": {"role": "optional", "name": "macroregion", "parent": [102320821, 102322043, 102312307], "names": {}}, "404221413": {"role": "optional", "name": "macrocounty", "parent": [102312311], "names": {}}, "102312307": {"role": "common", "name": "country", "parent": [102312335, 102312309], "names": {}}, "102312309": {"role": "common", "name": "continent", "parent": [102312341], "names": {}}, "102312311": {"role": "common", "name": "region", "parent": [404221411, 102320821, 102322043, 102312307], "names": {}}, "102312313": {"role": "common_optional", "name": "county", "parent": [404221413, 102312311], "names": {}}, "102322043": {"role": "common_optional", "name": "disputed", "parent": [102312307], "names": {}}, "102312317": {"role": "common", "name": "locality", "parent": [404221409, 102312313, 102312311], "names": {}}, "102312319": {"role": "common", "name": "neighbourhood", "parent": [102312323, 421205763, 102312317], "names": {"eng_p": ["neighbourhood", "neighborhood"]}}}`<commit_msg>update spec<commit_after>package placetypes

/* https://raw.githubusercontent.com/whosonfirst/whosonfirst-placetypes/master/data/placetypes-spec-latest.json */
/* This file was generated by robots (cmd/mk-spec.go) at 2017-06-19 18:09:55.719107437 +0000 UTC */

const Specification string = `{"102312321": {"role": "optional", "name": "microhood", "parent": [102312319], "names": {}}, "421205763": {"role": "common_optional", "name": "borough", "parent": [102312317, 404221409], "names": {}}, "102312325": {"role": "common_optional", "name": "venue", "parent": [102312327, 102312329, 1108906905, 102312331, 102312321, 102312319], "names": {}}, "102312327": {"role": "common_optional", "name": "building", "parent": [102312329, 1108906905, 102312331, 102312321, 102312319], "names": {}}, "102312329": {"role": "common_optional", "name": "address", "parent": [1108906905, 102312331, 102312321, 102312319], "names": {}}, "102312331": {"role": "common_optional", "name": "campus", "parent": [102312321, 102312319, 102312323, 102312317, 404221409], "names": {}}, "404528653": {"role": "common_optional", "name": "ocean", "parent": [102312341], "names": {}}, "102312335": {"role": "common_optional", "name": "empire", "parent": [102312309], "names": {}}, "102312323": {"role": "optional", "name": "macrohood", "parent": [421205763, 102312317], "names": {}}, "102312341": {"role": "common_optional", "name": "planet", "parent": [], "names": {}}, "1108906905": {"role": "common_optional", "name": "intersection", "parent": [102312331, 102312321, 102312319], "names": {}}, "470996387": {"role": "common_optional", "name": "postalcode", "parent": [102312317, 404221409, 102312313, 102312311], "names": {}}, "1108746739": {"role": "common_optional", "name": "constituency", "parent": [], "names": {}}, "102320821": {"role": "common_optional", "name": "dependency", "parent": [102312307], "names": {}}, "136057795": {"role": "common_optional", "name": "timezone", "parent": [102312307, 102312309, 102312341], "names": {}}, "404528655": {"role": "common_optional", "name": "marinearea", "parent": [102312307, 102312309, 102312341], "names": {}}, "102371933": {"role": "optional", "name": "metroarea", "parent": [], "names": {}}, "404221409": {"role": "common_optional", "name": "localadmin", "parent": [102312313, 102312311], "names": {}}, "404221411": {"role": "optional", "name": "macroregion", "parent": [102320821, 102322043, 102312307], "names": {}}, "404221413": {"role": "optional", "name": "macrocounty", "parent": [102312311], "names": {}}, "102312307": {"role": "common", "name": "country", "parent": [102312335, 102312309], "names": {}}, "102312309": {"role": "common", "name": "continent", "parent": [102312341], "names": {}}, "102312311": {"role": "common", "name": "region", "parent": [404221411, 102320821, 102322043, 102312307], "names": {}}, "102312313": {"role": "common_optional", "name": "county", "parent": [404221413, 102312311], "names": {}}, "102322043": {"role": "common_optional", "name": "disputed", "parent": [102312307], "names": {}}, "102312317": {"role": "common", "name": "locality", "parent": [404221409, 102312313, 102312311], "names": {}}, "102312319": {"role": "common", "name": "neighbourhood", "parent": [102312323, 421205763, 102312317], "names": {"eng_p": ["neighbourhood", "neighborhood"]}}}`<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemID := *flag.Int("new", 1, "new <problem ID>")
	flag.Parse()

	folder := "p" + strconv.Itoa(problemID)
	os.Mkdir(folder, 0771)

	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err := ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := ""
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("class")
		// fmt.Println(class, s.Text())
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("class")
		// fmt.Println(class, s.Text())
		info += "Description:" + s.Text()
	})
	return info
}
<commit_msg>Clean up problem info section<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"strconv"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	problemIDFlag := flag.Int("new", 1, "new <problem ID>")
	flag.Parse()
	problemID := *problemIDFlag
	println("ProblemID: " + strconv.Itoa(problemID))
	folder := "p" + strconv.Itoa(problemID)
	os.Mkdir(folder, 0771)

	data := strings.Replace(problemTemplate, problemIDString, strconv.Itoa(problemID), -1)
	data = strings.Replace(data, problemDescriptionString, getProblemDescription(problemID), -1)
	file := "p" + strconv.Itoa(problemID) + ".go"
	err := ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)

	data = strings.Replace(problemTestTemplate, problemIDString, strconv.Itoa(problemID), -1)
	file = "p" + strconv.Itoa(problemID) + "_test.go"
	err = ioutil.WriteFile(folder+"/"+file, []byte(data), 0664)
	panicIfError(err)
}
func panicIfError(err error) {
	if err != nil {
		panic(err)
	}
}

func getProblemDescription(problemID int) string {
	doc, err := goquery.NewDocument("https://projecteuler.net/problem=" + strconv.Itoa(problemID))
	if err != nil {
		log.Fatal(err)
	}
	info := ""
	doc.Find("h2").Each(func(i int, s *goquery.Selection) {
		// class, _ := s.Attr("id")
		// fmt.Println(class, s.Text())
		info += "Title:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".info").Each(func(i int, s *goquery.Selection) {
		info += "Info:\n" + s.Text()
	})
	info += "\n\n"
	doc.Find(".problem_content").Each(func(i int, s *goquery.Selection) {
		info += "Description:\n" + s.Text() + "{{end_block}}"
	})

	yuckyStrings := map[string]string{
		"\n\n\n":           "\n\n",
		"\n{{end_block}}":  "",
		"Description:\n\n": "Description:\n",
		"Title:\n":         "Title: ",
		"You are currently using a secure connectionInfo:\n": ""}

	for k, v := range yuckyStrings {
		for i := 0; i < 5; i++ { // Make sure all get replaced.
			info = strings.Replace(info, k, v, -1)
		}
	}
	return info
}
<|endoftext|>


<commit_before>package nameserver

import (
	"github.com/miekg/dns"
	. "github.com/weaveworks/weave/common"
	"net"
)

type MDNSServer struct {
	localAddrs []net.Addr
	sendconn   *net.UDPConn
	srv        *dns.Server
	zone       Zone
	running    bool
}

// Create a new mDNS server
// Nothing will be done (including port bindings) until you `Start()` the server
func NewMDNSServer(zone Zone) (*MDNSServer, error) {
	return &MDNSServer{zone: zone}, nil
}

// Return true if testaddr is a UDP address with IP matching my local i/f
func (s *MDNSServer) addrIsLocal(testaddr net.Addr) bool {
	if udpaddr, ok := testaddr.(*net.UDPAddr); ok {
		for _, localaddr := range s.localAddrs {
			if ipnetlocal, ok := localaddr.(*net.IPNet); ok {
				if ipnetlocal.IP.Equal(udpaddr.IP) {
					return true
				}
			}
		}
	}
	return false
}

// Start the mDNS server
func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
	// skip double initialization
	if s.running {
		return nil
	}

	// This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work
	s.sendconn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if err != nil {
		return err
	}

	conn, err := LinkLocalMulticastListener(ifi)
	if err != nil {
		return err
	}

	if ifi == nil {
		s.localAddrs, err = net.InterfaceAddrs()
	} else {
		s.localAddrs, err = ifi.Addrs()
	}
	if err != nil {
		return err
	}

	handleLocal := s.makeHandler(dns.TypeA,
		func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if ips, err := zone.LookupName(q.Name); err == nil {
				return makeAddressReply(r, q, ips)
			}
			return nil
		})

	handleReverse := s.makeHandler(dns.TypePTR,
		func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if names, err := zone.LookupInaddr(q.Name); err == nil {
				return makePTRReply(r, q, names)
			}
			return nil
		})

	mux := dns.NewServeMux()
	mux.HandleFunc(s.zone.Domain(), handleLocal)
	mux.HandleFunc(RDNSDomain, handleReverse)

	s.srv = &dns.Server{
		Listener:   nil,
		PacketConn: conn,
		Handler:    mux,
	}
	go s.srv.ActivateAndServe()
	s.running = true
	return err
}

// Stop the mDNS server
func (s *MDNSServer) Stop() error {
	s.running = false
	return s.srv.Shutdown()
}

func (s *MDNSServer) Zone() Zone {
	return s.zone
}

type LookupFunc func(ZoneLookup, *dns.Msg, *dns.Question) *dns.Msg

func (s *MDNSServer) makeHandler(qtype uint16, lookup LookupFunc) dns.HandlerFunc {
	return func(rw dns.ResponseWriter, r *dns.Msg) {
		// Handle only questions, ignore answers. We might also ignore
		// questions that arise locally (i.e., that come from an IP we
		// think is local), but in the interest of avoiding
		// complication, and easier testing, this is elided on the
		// assumption that the client wouldn't ask if it already knew
		// the answer, and if it does ask, it'll be happy to get an
		// answer.
		// TODO: use any Answer in the query for adding records in the Zone database...
		if len(r.Answer) == 0 && len(r.Question) > 0 {
			q := &r.Question[0]
			if q.Qtype == qtype {
				Debug.Printf("[mdns msgid %d] Trying to answer to mDNS query '%s'", r.MsgHdr.Id, q.Name)
				if m := lookup(s.zone, r, q); m != nil {
					Debug.Printf("[mdns msgid %d] - found local answer to mDNS query '%s'", r.MsgHdr.Id, q.Name)
					if err := s.sendResponse(m); err != nil {
						Warning.Printf("[mdns msgid %d] - error writing to %v", r.MsgHdr.Id, s.sendconn)
					} else {
						Debug.Printf("[mdns msgid %d] - response sent: %d answers", r.MsgHdr.Id, len(m.Answer))
					}
				} else {
					Debug.Printf("[mdns msgid %d] - no local answer for mDNS query '%s'",
						r.MsgHdr.Id, q.Name)
				}
			}
		}
	}
}

func (s *MDNSServer) sendResponse(m *dns.Msg) error {
	buf, err := m.Pack()
	if err != nil {
		return err
	}
	_, err = s.sendconn.WriteTo(buf, ipv4Addr)
	return err
}
<commit_msg>Minor: logs messages...<commit_after>package nameserver

import (
	"github.com/miekg/dns"
	. "github.com/weaveworks/weave/common"
	"net"
)

type MDNSServer struct {
	localAddrs []net.Addr
	sendconn   *net.UDPConn
	srv        *dns.Server
	zone       Zone
	running    bool
}

// Create a new mDNS server
// Nothing will be done (including port bindings) until you `Start()` the server
func NewMDNSServer(zone Zone) (*MDNSServer, error) {
	return &MDNSServer{zone: zone}, nil
}

// Return true if testaddr is a UDP address with IP matching my local i/f
func (s *MDNSServer) addrIsLocal(testaddr net.Addr) bool {
	if udpaddr, ok := testaddr.(*net.UDPAddr); ok {
		for _, localaddr := range s.localAddrs {
			if ipnetlocal, ok := localaddr.(*net.IPNet); ok {
				if ipnetlocal.IP.Equal(udpaddr.IP) {
					return true
				}
			}
		}
	}
	return false
}

// Start the mDNS server
func (s *MDNSServer) Start(ifi *net.Interface) (err error) {
	// skip double initialization
	if s.running {
		return nil
	}

	// This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work
	s.sendconn, err = net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
	if err != nil {
		return err
	}

	conn, err := LinkLocalMulticastListener(ifi)
	if err != nil {
		return err
	}

	if ifi == nil {
		s.localAddrs, err = net.InterfaceAddrs()
	} else {
		s.localAddrs, err = ifi.Addrs()
	}
	if err != nil {
		return err
	}

	handleLocal := s.makeHandler(dns.TypeA,
		func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if ips, err := zone.LookupName(q.Name); err == nil {
				return makeAddressReply(r, q, ips)
			}
			return nil
		})

	handleReverse := s.makeHandler(dns.TypePTR,
		func(zone ZoneLookup, r *dns.Msg, q *dns.Question) *dns.Msg {
			if names, err := zone.LookupInaddr(q.Name); err == nil {
				return makePTRReply(r, q, names)
			}
			return nil
		})

	mux := dns.NewServeMux()
	mux.HandleFunc(s.zone.Domain(), handleLocal)
	mux.HandleFunc(RDNSDomain, handleReverse)

	s.srv = &dns.Server{
		Listener:   nil,
		PacketConn: conn,
		Handler:    mux,
	}
	go s.srv.ActivateAndServe()
	s.running = true
	return err
}

// Stop the mDNS server
func (s *MDNSServer) Stop() error {
	s.running = false
	return s.srv.Shutdown()
}

func (s *MDNSServer) Zone() Zone {
	return s.zone
}

type LookupFunc func(ZoneLookup, *dns.Msg, *dns.Question) *dns.Msg

func (s *MDNSServer) makeHandler(qtype uint16, lookup LookupFunc) dns.HandlerFunc {
	return func(rw dns.ResponseWriter, r *dns.Msg) {
		// Handle only questions, ignore answers. We might also ignore
		// questions that arise locally (i.e., that come from an IP we
		// think is local), but in the interest of avoiding
		// complication, and easier testing, this is elided on the
		// assumption that the client wouldn't ask if it already knew
		// the answer, and if it does ask, it'll be happy to get an
		// answer.
		// TODO: use any Answer in the query for adding records in the Zone database...
		if len(r.Answer) == 0 && len(r.Question) > 0 {
			q := &r.Question[0]
			if q.Qtype == qtype {
				Debug.Printf("[mdns msgid %d] srv: trying to answer to mDNS query '%s'", r.MsgHdr.Id, q.Name)
				if m := lookup(s.zone, r, q); m != nil {
					Debug.Printf("[mdns msgid %d] srv: found local answer to mDNS query '%s'", r.MsgHdr.Id, q.Name)
					if err := s.sendResponse(m); err != nil {
						Warning.Printf("[mdns msgid %d] srv: error writing mDNS response to %v", r.MsgHdr.Id, s.sendconn)
					} else {
						Debug.Printf("[mdns msgid %d] srv: response sent: %d answers", r.MsgHdr.Id, len(m.Answer))
					}
				} else {
					Debug.Printf("[mdns msgid %d] srv: no local answer for answering mDNS query '%s'",
						r.MsgHdr.Id, q.Name)
				}
			}
		}
	}
}

func (s *MDNSServer) sendResponse(m *dns.Msg) error {
	buf, err := m.Pack()
	if err != nil {
		return err
	}
	_, err = s.sendconn.WriteTo(buf, ipv4Addr)
	return err
}
<|endoftext|>