<commit_before>package kinetic

import (
	"errors"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var (
	NullStreamError = errors.New("A stream must be specified!")
	NotActiveError  = errors.New("The Stream is not yet active!")
)

type Listener struct {
	*kinesis

	concurrency   int
	concurrencyMu sync.Mutex
	sem           chan bool

	wg        sync.WaitGroup
	msgCount  int
	errCount  int
	msgBuffer int

	listening   bool
	listeningMu sync.Mutex
	consuming   bool
	consumingMu sync.Mutex
	messageMu   sync.Mutex

	errors     chan error
	messages   chan *Message
	interrupts chan os.Signal
}

func (l *Listener) init(stream, shard, shardIterType, accessKey, secretKey, region string, concurrency int) (*Listener, error) {
	var err error

	if stream == "" {
		return nil, NullStreamError
	}

	l.setConcurrency(concurrency)

	l.sem = make(chan bool, l.getConcurrency())
	l.messages = make(chan *Message, l.getConcurrency())
	l.errors = make(chan error)
	l.interrupts = make(chan os.Signal, 1)

	// Relay incoming interrupt signals to this channel
	signal.Notify(l.interrupts, os.Interrupt)

	l.kinesis, err = new(kinesis).init(stream, shard, shardIterType, accessKey, secretKey, region)
	if err != nil {
		return l, err
	}

	// Is the stream ready?
	active, err := l.checkActive()
	if err != nil || active != true {
		if err != nil {
			return l, err
		} else {
			return l, NotActiveError
		}
	}

	// Start feeder consumer
	go l.consume()

	return l, err
}

// Initialize a listener with the params specified in the configuration file
func (l *Listener) Init() (*Listener, error) {
	return l.init(conf.Kinesis.Stream, conf.Kinesis.Shard, ShardIterTypes[conf.Kinesis.ShardIteratorType], conf.AWS.AccessKey, conf.AWS.SecretKey, conf.AWS.Region, conf.Concurrency.Listener)
}

// Initialize a listener with the supplied params
func (l *Listener) InitC(stream, shard, shardIterType, accessKey, secretKey, region string, concurrency int) (*Listener, error) {
	return l.init(stream, shard, shardIterType, accessKey, secretKey, region, concurrency)
}

// Re-initialize kinesis client with new endpoint. Used for testing with kinesalite
func (l *Listener) NewEndpoint(endpoint, stream string) {
	l.kinesis.client = l.kinesis.newClient(endpoint, stream)
	l.initShardIterator()

	if !l.IsConsuming() {
		go l.consume()
	}
}

func (l *Listener) setConcurrency(concurrency int) {
	l.concurrencyMu.Lock()
	l.concurrency = concurrency
	l.concurrencyMu.Unlock()
}

func (l *Listener) getConcurrency() int {
	l.concurrencyMu.Lock()
	defer l.concurrencyMu.Unlock()
	return l.concurrency
}

func (l *Listener) setListening(listening bool) {
	l.listeningMu.Lock()
	l.listening = listening
	l.listeningMu.Unlock()
}

// Identifies whether or not messages and errors are being handled after consumption
func (l *Listener) IsListening() bool {
	l.listeningMu.Lock()
	defer l.listeningMu.Unlock()
	return l.listening
}

func (l *Listener) setConsuming(consuming bool) {
	l.consumingMu.Lock()
	l.consuming = consuming
	l.consumingMu.Unlock()
}

// Identifies whether or not the kinesis stream is being polled
func (l *Listener) IsConsuming() bool {
	l.consumingMu.Lock()
	defer l.consumingMu.Unlock()
	return l.consuming
}

func (l *Listener) shouldConsume() bool {
	select {
	case <-l.interrupts:
		return false
	default:
		return true
	}

}

// Handle the consumed messages, errors and interrupts
func (l *Listener) Listen(fn msgFn) {
	l.setListening(true)
stop:
	for {
		l.sem <- true
		select {
		case err := <-l.Errors():
			l.errCount++
			l.wg.Add(1)
			go l.handleError(err)
		case msg := <-l.Messages():
			l.msgCount++
			l.wg.Add(1)
			go l.handleMsg(msg, fn)
		case sig := <-l.interrupts:
			l.handleInterrupt(sig)
			break stop
		}
	}
	l.setListening(false)
}

func (l *Listener) addMessage(msg *Message) {
	l.messageMu.Lock()

	l.msgBuffer++

	// Allow reads to catch up to prevent deadlock
	if l.msgBuffer >= l.getConcurrency() {
		l.msgBuffer--
		l.messageMu.Unlock()

		<-time.After(1 * time.Millisecond)

		l.addMessage(msg)
		return
	}

	l.messages <- msg
	l.messageMu.Unlock()
}

// Continually poll the Kinesis stream
func (l *Listener) consume() {
	l.setConsuming(true)

	counter := 0
	timer := time.Now()

	for {
		l.throttle(&counter, &timer)

		// args() will give us the shard iterator and type as well as the shard id
		response, err := l.client.GetRecords(l.args())
		if err != nil {
			l.errors <- err
		}

		if response != nil {
			l.setShardIterator(response.NextShardIterator)

			if len(response.Records) > 0 {
				for _, record := range response.Records {
					l.addMessage(&Message{record})
				}
			}
		}

		if !l.shouldConsume() {
			l.setConsuming(false)
			break
		}
	}
}

// Retrive a message from the stream and return the value
func (l *Listener) Retrieve() (*Message, error) {
	select {
	case msg := <-l.Messages():
		return msg, nil
	case err := <-l.Errors():
		return nil, err
	case sig := <-l.interrupts:
		l.handleInterrupt(sig)
		return nil, nil
	}
}

// Retrieve a message from the queue and apply the supplied function to the message
func (l *Listener) RetrieveFn(fn msgFn) {
	select {
	case err := <-l.Errors():
		l.wg.Add(1)
		go l.handleError(err)
	case msg := <-l.Messages():
		l.wg.Add(1)
		go fn(msg.Value(), &l.wg)
	case sig := <-l.interrupts:
		l.handleInterrupt(sig)
	}
}

// Stops consuming and listening and waits for all tasks to finish
func (l *Listener) Close() error {
	if conf.Debug.Verbose {
		log.Println("Listener is waiting for all tasks to finish...")
	}

	// Stop consuming
	go func() {
		l.interrupts <- syscall.SIGINT
	}()

	l.wg.Wait()

	if conf.Debug.Verbose {
		log.Println("Listener is shutting down.")
	}

	return nil
}

func (l *Listener) Errors() <-chan error {
	return l.errors
}

func (l *Listener) Messages() <-chan *Message {
	l.messageMu.Lock()
	defer l.messageMu.Unlock()
	l.msgBuffer--
	return l.messages
}

func (l *Listener) handleMsg(msg *Message, fn msgFn) {
	if conf.Debug.Verbose {
		log.Printf("Received message: %s with key: %s", msg.Value(), msg.Key())
		log.Printf("Messages received: %d", l.msgCount)
	}

	defer func() {
		<-l.sem
	}()

	fn(msg.Value(), &l.wg)
}

func (l *Listener) handleInterrupt(signal os.Signal) {
	if conf.Debug.Verbose {
		log.Println("Listener received interrupt signal")
	}

	defer func() {
		<-l.sem
	}()

	l.Close()
}

func (l *Listener) handleError(err error) {
	if err != nil && conf.Debug.Verbose {
		log.Println("Received error: ", err.Error())
	}

	defer func() {
		<-l.sem
	}()

	l.wg.Done()
}

// Kinesis allows five read ops per second per shard
// http://docs.aws.amazon.com/kinesis/latest/dev/service-sizes-and-limits.html
func (l *Listener) throttle(counter *int, timer *time.Time) {
	// If a second has passed since the last timer start, reset the timer
	if time.Now().After(timer.Add(1 * time.Second)) {
		*timer = time.Now()
		*counter = 0
	}

	*counter++

	// If we have attempted five times and it has been less than one second
	// since we started reading then we need to wait for the second to finish
	if *counter >= kinesisReadsPerSec && !(time.Now().After(timer.Add(1 * time.Second))) {
		// Wait for the remainder of the second - timer and counter will be reset on next pass
		<-time.After(1*time.Second - time.Since(*timer))
	}
}
<commit_msg>Refresh shard iterator on error<commit_after>package kinetic

import (
	"errors"
	"log"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var (
	NullStreamError = errors.New("A stream must be specified!")
	NotActiveError  = errors.New("The Stream is not yet active!")
)

type Listener struct {
	*kinesis

	concurrency   int
	concurrencyMu sync.Mutex
	sem           chan bool

	wg        sync.WaitGroup
	msgCount  int
	errCount  int
	msgBuffer int

	listening   bool
	listeningMu sync.Mutex
	consuming   bool
	consumingMu sync.Mutex
	messageMu   sync.Mutex

	errors     chan error
	messages   chan *Message
	interrupts chan os.Signal
}

func (l *Listener) init(stream, shard, shardIterType, accessKey, secretKey, region string, concurrency int) (*Listener, error) {
	var err error

	if stream == "" {
		return nil, NullStreamError
	}

	l.setConcurrency(concurrency)

	l.sem = make(chan bool, l.getConcurrency())
	l.messages = make(chan *Message, l.getConcurrency())
	l.errors = make(chan error)
	l.interrupts = make(chan os.Signal, 1)

	// Relay incoming interrupt signals to this channel
	signal.Notify(l.interrupts, os.Interrupt)

	l.kinesis, err = new(kinesis).init(stream, shard, shardIterType, accessKey, secretKey, region)
	if err != nil {
		return l, err
	}

	// Is the stream ready?
	active, err := l.checkActive()
	if err != nil || active != true {
		if err != nil {
			return l, err
		} else {
			return l, NotActiveError
		}
	}

	// Start feeder consumer
	go l.consume()

	return l, err
}

// Initialize a listener with the params specified in the configuration file
func (l *Listener) Init() (*Listener, error) {
	return l.init(conf.Kinesis.Stream, conf.Kinesis.Shard, ShardIterTypes[conf.Kinesis.ShardIteratorType], conf.AWS.AccessKey, conf.AWS.SecretKey, conf.AWS.Region, conf.Concurrency.Listener)
}

// Initialize a listener with the supplied params
func (l *Listener) InitC(stream, shard, shardIterType, accessKey, secretKey, region string, concurrency int) (*Listener, error) {
	return l.init(stream, shard, shardIterType, accessKey, secretKey, region, concurrency)
}

// Re-initialize kinesis client with new endpoint. Used for testing with kinesalite
func (l *Listener) NewEndpoint(endpoint, stream string) {
	l.kinesis.client = l.kinesis.newClient(endpoint, stream)
	l.initShardIterator()

	if !l.IsConsuming() {
		go l.consume()
	}
}

func (l *Listener) setConcurrency(concurrency int) {
	l.concurrencyMu.Lock()
	l.concurrency = concurrency
	l.concurrencyMu.Unlock()
}

func (l *Listener) getConcurrency() int {
	l.concurrencyMu.Lock()
	defer l.concurrencyMu.Unlock()
	return l.concurrency
}

func (l *Listener) setListening(listening bool) {
	l.listeningMu.Lock()
	l.listening = listening
	l.listeningMu.Unlock()
}

// Identifies whether or not messages and errors are being handled after consumption
func (l *Listener) IsListening() bool {
	l.listeningMu.Lock()
	defer l.listeningMu.Unlock()
	return l.listening
}

func (l *Listener) setConsuming(consuming bool) {
	l.consumingMu.Lock()
	l.consuming = consuming
	l.consumingMu.Unlock()
}

// Identifies whether or not the kinesis stream is being polled
func (l *Listener) IsConsuming() bool {
	l.consumingMu.Lock()
	defer l.consumingMu.Unlock()
	return l.consuming
}

func (l *Listener) shouldConsume() bool {
	select {
	case <-l.interrupts:
		return false
	default:
		return true
	}

}

// Handle the consumed messages, errors and interrupts
func (l *Listener) Listen(fn msgFn) {
	l.setListening(true)
stop:
	for {
		l.sem <- true
		select {
		case err := <-l.Errors():
			l.errCount++
			l.wg.Add(1)
			go l.handleError(err)
		case msg := <-l.Messages():
			l.msgCount++
			l.wg.Add(1)
			go l.handleMsg(msg, fn)
		case sig := <-l.interrupts:
			l.handleInterrupt(sig)
			break stop
		}
	}
	l.setListening(false)
}

func (l *Listener) addMessage(msg *Message) {
	l.messageMu.Lock()

	l.msgBuffer++

	// Allow reads to catch up to prevent deadlock
	if l.msgBuffer >= l.getConcurrency() {
		l.msgBuffer--
		l.messageMu.Unlock()

		<-time.After(1 * time.Millisecond)

		l.addMessage(msg)
		return
	}

	l.messages <- msg
	l.messageMu.Unlock()
}

// Continually poll the Kinesis stream
func (l *Listener) consume() {
	l.setConsuming(true)

	counter := 0
	timer := time.Now()

	for {
		l.throttle(&counter, &timer)

		// args() will give us the shard iterator and type as well as the shard id
		response, err := l.client.GetRecords(l.args())
		if err != nil {
			l.errors <- err

			// Refresh the shard iterator
			l.initShardIterator()
		}

		if response != nil {
			l.setShardIterator(response.NextShardIterator)

			if len(response.Records) > 0 {
				for _, record := range response.Records {
					l.addMessage(&Message{record})
				}
			}
		}

		if !l.shouldConsume() {
			l.setConsuming(false)
			break
		}
	}
}

// Retrive a message from the stream and return the value
func (l *Listener) Retrieve() (*Message, error) {
	select {
	case msg := <-l.Messages():
		return msg, nil
	case err := <-l.Errors():
		return nil, err
	case sig := <-l.interrupts:
		l.handleInterrupt(sig)
		return nil, nil
	}
}

// Retrieve a message from the queue and apply the supplied function to the message
func (l *Listener) RetrieveFn(fn msgFn) {
	select {
	case err := <-l.Errors():
		l.wg.Add(1)
		go l.handleError(err)
	case msg := <-l.Messages():
		l.wg.Add(1)
		go fn(msg.Value(), &l.wg)
	case sig := <-l.interrupts:
		l.handleInterrupt(sig)
	}
}

// Stops consuming and listening and waits for all tasks to finish
func (l *Listener) Close() error {
	if conf.Debug.Verbose {
		log.Println("Listener is waiting for all tasks to finish...")
	}

	// Stop consuming
	go func() {
		l.interrupts <- syscall.SIGINT
	}()

	l.wg.Wait()

	if conf.Debug.Verbose {
		log.Println("Listener is shutting down.")
	}

	return nil
}

func (l *Listener) Errors() <-chan error {
	return l.errors
}

func (l *Listener) Messages() <-chan *Message {
	l.messageMu.Lock()
	defer l.messageMu.Unlock()
	l.msgBuffer--
	return l.messages
}

func (l *Listener) handleMsg(msg *Message, fn msgFn) {
	if conf.Debug.Verbose {
		log.Printf("Received message: %s with key: %s", msg.Value(), msg.Key())
		log.Printf("Messages received: %d", l.msgCount)
	}

	defer func() {
		<-l.sem
	}()

	fn(msg.Value(), &l.wg)
}

func (l *Listener) handleInterrupt(signal os.Signal) {
	if conf.Debug.Verbose {
		log.Println("Listener received interrupt signal")
	}

	defer func() {
		<-l.sem
	}()

	l.Close()
}

func (l *Listener) handleError(err error) {
	if err != nil && conf.Debug.Verbose {
		log.Println("Received error: ", err.Error())
	}

	defer func() {
		<-l.sem
	}()

	l.wg.Done()
}

// Kinesis allows five read ops per second per shard
// http://docs.aws.amazon.com/kinesis/latest/dev/service-sizes-and-limits.html
func (l *Listener) throttle(counter *int, timer *time.Time) {
	// If a second has passed since the last timer start, reset the timer
	if time.Now().After(timer.Add(1 * time.Second)) {
		*timer = time.Now()
		*counter = 0
	}

	*counter++

	// If we have attempted five times and it has been less than one second
	// since we started reading then we need to wait for the second to finish
	if *counter >= kinesisReadsPerSec && !(time.Now().After(timer.Add(1 * time.Second))) {
		// Wait for the remainder of the second - timer and counter will be reset on next pass
		<-time.After(1*time.Second - time.Since(*timer))
	}
}
<|endoftext|>


<commit_before>package bus

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	nsq "github.com/nsqio/go-nsq"
	"net"
	"time"
)

var (
	TopicRequired   = errors.New("creating a new consumer requires a non-empty topic")
	ChannelRequired = errors.New("creating a new consumer requires a non-empty channel")
)

type handlerFunc func(m *Message) (interface{}, error)

type Listener interface {
	On(lc ListenerConfig) error
}

type ListenerConfig struct {
	Topic                   string
	Channel                 string
	Lookup                  []string
	HandlerFunc             handlerFunc
	HandlerConcurrency      int
	DialTimeout             time.Duration
	ReadTimeout             time.Duration
	WriteTimeout            time.Duration
	LocalAddr               net.Addr
	LookupdPollInterval     time.Duration
	LookupdPollJitter       float64
	MaxRequeueDelay         time.Duration
	DefaultRequeueDelay     time.Duration
	BackoffStrategy         nsq.BackoffStrategy
	MaxBackoffDuration      time.Duration
	BackoffMultiplier       time.Duration
	MaxAttempts             uint16
	LowRdyIdleTimeout       time.Duration
	RDYRedistributeInterval time.Duration
	ClientID                string
	Hostname                string
	UserAgent               string
	HeartbeatInterval       time.Duration
	SampleRate              int32
	TlsV1                   bool
	TlsConfig               *tls.Config
	Deflate                 bool
	DeflateLevel            int
	Snappy                  bool
	OutputBufferSize        int64
	OutputBufferTimeout     time.Duration
	MaxInFlight             int
	MsgTimeout              time.Duration
	AuthSecret              string
}

func On(lc ListenerConfig) (err error) {
	if len(lc.Topic) == 0 {
		err = TopicRequired
		return
	}

	if len(lc.Channel) == 0 {
		err = ChannelRequired
		return
	}

	if len(lc.Lookup) == 0 {
		lc.Lookup = []string{"localhost:4161"}
	}

	if lc.HandlerConcurrency == 0 {
		lc.HandlerConcurrency = 1
	}

	config := newListenerConfig(lc)
	consumer, err := nsq.NewConsumer(lc.Topic, lc.Channel, config)
	if err != nil {
		return
	}

	handler := handleMessage(lc)
	consumer.AddConcurrentHandlers(handler, lc.HandlerConcurrency)
	err = consumer.ConnectToNSQLookupds(lc.Lookup)

	return
}

func handleMessage(lc ListenerConfig) nsq.HandlerFunc {
	return nsq.HandlerFunc(func(message *nsq.Message) (err error) {
		m := Message{Message: message}
		if err = json.Unmarshal(message.Body, &m); err != nil {
			return
		}

		res, err := lc.HandlerFunc(&m)
		if err != nil {
			return
		}

		if m.ReplyTo == "" {
			return
		}

		emitter, err := NewEmitter(EmitterConfig{})
		if err != nil {
			return
		}

		err = emitter.Emit(m.ReplyTo, res)

		return
	})
}

func newListenerConfig(lc ListenerConfig) (config *nsq.Config) {
	config = nsq.NewConfig()

	if lc.DialTimeout != 0 {
		config.DialTimeout = lc.DialTimeout
	}

	if lc.ReadTimeout != 0 {
		config.ReadTimeout = lc.ReadTimeout
	}

	if lc.LocalAddr != nil {
		config.LocalAddr = lc.LocalAddr
	}

	if lc.LookupdPollInterval != 0 {
		config.LookupdPollInterval = lc.LookupdPollInterval
	}

	if lc.LookupdPollJitter != 0 {
		config.LookupdPollJitter = lc.LookupdPollJitter
	}

	if lc.MaxRequeueDelay != 0 {
		config.MaxRequeueDelay = lc.MaxRequeueDelay
	}

	if lc.DefaultRequeueDelay != 0 {
		config.DefaultRequeueDelay = lc.DefaultRequeueDelay
	}

	if lc.BackoffStrategy != nil {
		config.BackoffStrategy = lc.BackoffStrategy
	}

	if lc.MaxBackoffDuration != 0 {
		config.MaxBackoffDuration = lc.MaxBackoffDuration
	}

	if lc.BackoffMultiplier != 0 {
		config.BackoffMultiplier = lc.BackoffMultiplier
	}

	if lc.MaxAttempts != 0 {
		config.MaxAttempts = lc.MaxAttempts
	}

	if lc.LowRdyIdleTimeout != 0 {
		config.LowRdyIdleTimeout = lc.LowRdyIdleTimeout
	}

	if lc.RDYRedistributeInterval != 0 {
		config.RDYRedistributeInterval = lc.RDYRedistributeInterval
	}

	if lc.ClientID != "" {
		config.ClientID = lc.ClientID
	}

	if lc.Hostname != "" {
		config.Hostname = lc.Hostname
	}

	if lc.UserAgent != "" {
		config.UserAgent = lc.UserAgent
	}

	if lc.HeartbeatInterval != 0 {
		config.HeartbeatInterval = lc.HeartbeatInterval
	}

	if lc.SampleRate != 0 {
		config.SampleRate = lc.SampleRate
	}

	if lc.TlsV1 {
		config.TlsV1 = lc.TlsV1
	}

	if lc.TlsConfig != nil {
		config.TlsConfig = lc.TlsConfig
	}

	if lc.Deflate {
		config.Deflate = lc.Deflate
	}

	if lc.OutputBufferSize != 0 {
		config.OutputBufferSize = lc.OutputBufferSize
	}

	if lc.OutputBufferTimeout != 0 {
		config.OutputBufferTimeout = lc.OutputBufferTimeout
	}

	if lc.MaxInFlight != 0 {
		config.MaxInFlight = lc.MaxInFlight
	}

	if lc.MsgTimeout != 0 {
		config.MsgTimeout = lc.MsgTimeout
	}

	if lc.AuthSecret != "" {
		config.AuthSecret = lc.AuthSecret
	}

	return
}
<commit_msg>Remove lint warnings from listener<commit_after>package bus

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	nsq "github.com/nsqio/go-nsq"
	"net"
	"time"
)

var (
	// ErrTopicRequired is returned when topic is not passed as parameter in bus.ListenerConfig.
	ErrTopicRequired = errors.New("creating a new consumer requires a non-empty topic")
	// ErrChannelRequired is returned when channel is not passed as parameter in bus.ListenerConfig.
	ErrChannelRequired = errors.New("creating a new consumer requires a non-empty channel")
)

// ListenerConfig carries the different variables to tune a newly started consumer,
// it exposes the same configuration available from official nsq go client.
type ListenerConfig struct {
	Topic                   string
	Channel                 string
	Lookup                  []string
	HandlerFunc             handlerFunc
	HandlerConcurrency      int
	DialTimeout             time.Duration
	ReadTimeout             time.Duration
	WriteTimeout            time.Duration
	LocalAddr               net.Addr
	LookupdPollInterval     time.Duration
	LookupdPollJitter       float64
	MaxRequeueDelay         time.Duration
	DefaultRequeueDelay     time.Duration
	BackoffStrategy         nsq.BackoffStrategy
	MaxBackoffDuration      time.Duration
	BackoffMultiplier       time.Duration
	MaxAttempts             uint16
	LowRdyIdleTimeout       time.Duration
	RDYRedistributeInterval time.Duration
	ClientID                string
	Hostname                string
	UserAgent               string
	HeartbeatInterval       time.Duration
	SampleRate              int32
	TLSV1                   bool
	TLSConfig               *tls.Config
	Deflate                 bool
	DeflateLevel            int
	Snappy                  bool
	OutputBufferSize        int64
	OutputBufferTimeout     time.Duration
	MaxInFlight             int
	MsgTimeout              time.Duration
	AuthSecret              string
}

type handlerFunc func(m *Message) (interface{}, error)

// On listen to a message from a specific topic using nsq consumer, returns
// an error if topic and channel not passed or if an error ocurred while creating
// nsq consumer.
func On(lc ListenerConfig) (err error) {
	if len(lc.Topic) == 0 {
		err = ErrTopicRequired
		return
	}

	if len(lc.Channel) == 0 {
		err = ErrChannelRequired
		return
	}

	if len(lc.Lookup) == 0 {
		lc.Lookup = []string{"localhost:4161"}
	}

	if lc.HandlerConcurrency == 0 {
		lc.HandlerConcurrency = 1
	}

	config := newListenerConfig(lc)
	consumer, err := nsq.NewConsumer(lc.Topic, lc.Channel, config)
	if err != nil {
		return
	}

	handler := handleMessage(lc)
	consumer.AddConcurrentHandlers(handler, lc.HandlerConcurrency)
	err = consumer.ConnectToNSQLookupds(lc.Lookup)

	return
}

func handleMessage(lc ListenerConfig) nsq.HandlerFunc {
	return nsq.HandlerFunc(func(message *nsq.Message) (err error) {
		m := Message{Message: message}
		if err = json.Unmarshal(message.Body, &m); err != nil {
			return
		}

		res, err := lc.HandlerFunc(&m)
		if err != nil {
			return
		}

		if m.ReplyTo == "" {
			return
		}

		emitter, err := NewEmitter(EmitterConfig{})
		if err != nil {
			return
		}

		err = emitter.Emit(m.ReplyTo, res)

		return
	})
}

func newListenerConfig(lc ListenerConfig) (config *nsq.Config) {
	config = nsq.NewConfig()

	if lc.DialTimeout != 0 {
		config.DialTimeout = lc.DialTimeout
	}

	if lc.ReadTimeout != 0 {
		config.ReadTimeout = lc.ReadTimeout
	}

	if lc.LocalAddr != nil {
		config.LocalAddr = lc.LocalAddr
	}

	if lc.LookupdPollInterval != 0 {
		config.LookupdPollInterval = lc.LookupdPollInterval
	}

	if lc.LookupdPollJitter != 0 {
		config.LookupdPollJitter = lc.LookupdPollJitter
	}

	if lc.MaxRequeueDelay != 0 {
		config.MaxRequeueDelay = lc.MaxRequeueDelay
	}

	if lc.DefaultRequeueDelay != 0 {
		config.DefaultRequeueDelay = lc.DefaultRequeueDelay
	}

	if lc.BackoffStrategy != nil {
		config.BackoffStrategy = lc.BackoffStrategy
	}

	if lc.MaxBackoffDuration != 0 {
		config.MaxBackoffDuration = lc.MaxBackoffDuration
	}

	if lc.BackoffMultiplier != 0 {
		config.BackoffMultiplier = lc.BackoffMultiplier
	}

	if lc.MaxAttempts != 0 {
		config.MaxAttempts = lc.MaxAttempts
	}

	if lc.LowRdyIdleTimeout != 0 {
		config.LowRdyIdleTimeout = lc.LowRdyIdleTimeout
	}

	if lc.RDYRedistributeInterval != 0 {
		config.RDYRedistributeInterval = lc.RDYRedistributeInterval
	}

	if lc.ClientID != "" {
		config.ClientID = lc.ClientID
	}

	if lc.Hostname != "" {
		config.Hostname = lc.Hostname
	}

	if lc.UserAgent != "" {
		config.UserAgent = lc.UserAgent
	}

	if lc.HeartbeatInterval != 0 {
		config.HeartbeatInterval = lc.HeartbeatInterval
	}

	if lc.SampleRate != 0 {
		config.SampleRate = lc.SampleRate
	}

	if lc.TLSV1 {
		config.TlsV1 = lc.TLSV1
	}

	if lc.TLSConfig != nil {
		config.TlsConfig = lc.TLSConfig
	}

	if lc.Deflate {
		config.Deflate = lc.Deflate
	}

	if lc.OutputBufferSize != 0 {
		config.OutputBufferSize = lc.OutputBufferSize
	}

	if lc.OutputBufferTimeout != 0 {
		config.OutputBufferTimeout = lc.OutputBufferTimeout
	}

	if lc.MaxInFlight != 0 {
		config.MaxInFlight = lc.MaxInFlight
	}

	if lc.MsgTimeout != 0 {
		config.MsgTimeout = lc.MsgTimeout
	}

	if lc.AuthSecret != "" {
		config.AuthSecret = lc.AuthSecret
	}

	return
}
<|endoftext|>


<commit_before>package typhon

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/facebookgo/httpdown"
	log "github.com/mondough/slog"
	"golang.org/x/net/context"
)

type Listener interface {
	httpdown.Server
	Addr() net.Addr
	WaitC() <-chan struct{}
}

type listener struct {
	httpdown.Server
	addr net.Addr
}

func (l listener) Addr() net.Addr {
	return l.addr
}

func (l listener) WaitC() <-chan struct{} {
	c := make(chan struct{}, 0)
	go func() {
		l.Wait()
		close(c)
	}()
	return c
}

func Listen(svc Service) Listener {
	// Determine on which address to listen, choosing in order one of:
	// 1. LISTEN_ADDR environment variable
	// 2. PORT variable (listening on all interfaces)
	// 3. Random, available port
	addr := ":0"
	if addr_ := os.Getenv("LISTEN_ADDR"); addr_ != "" {
		addr = addr_
	} else if port, err := strconv.Atoi(os.Getenv("PORT")); err == nil && port >= 0 {
		addr = fmt.Sprintf(":%d", port)
	}
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		panic(err)
	}

	l, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		panic(err)
	}

	svc = svc.Filter(networkFilter)
	downer := &httpdown.HTTP{
		StopTimeout: 20 * time.Second,
		KillTimeout: 25 * time.Second}
	server := downer.Serve(&http.Server{
		Handler:        httpHandler(svc),
		MaxHeaderBytes: http.DefaultMaxHeaderBytes}, l)
	log.Info(nil, "Listening on %v", l.Addr())
	return listener{
		Server: server,
		addr:   l.Addr()}
}

func httpHandler(svc Service) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, httpReq *http.Request) {
		req := Request{
			Request: *httpReq,
			Context: context.Background()} // @TODO: Proper context
		rsp := svc(req)

		// Write the response out to the wire
		for k, v := range rsp.Header {
			rw.Header()[k] = v
		}
		rw.WriteHeader(rsp.StatusCode)
		if rsp.Body != nil {
			defer rsp.Body.Close()
			if _, err := io.Copy(rw, rsp.Body); err != nil {
				log.Error(req, "[Typhon:http:networkTransport] Error copying response body: %v", err)
			}
		}
	})
}
<commit_msg>Allow overriding default listener address<commit_after>package typhon

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"strconv"
	"time"

	"github.com/facebookgo/httpdown"
	log "github.com/mondough/slog"
	"golang.org/x/net/context"
)

var DefaultListenAddr = ":0"

type Listener interface {
	httpdown.Server
	Addr() net.Addr
	WaitC() <-chan struct{}
}

type listener struct {
	httpdown.Server
	addr net.Addr
}

func (l listener) Addr() net.Addr {
	return l.addr
}

func (l listener) WaitC() <-chan struct{} {
	c := make(chan struct{}, 0)
	go func() {
		l.Wait()
		close(c)
	}()
	return c
}

func Listen(svc Service) Listener {
	// Determine on which address to listen, choosing in order one of:
	// 1. LISTEN_ADDR environment variable
	// 2. PORT variable (listening on all interfaces)
	// 3. Random, available port
	addr := DefaultListenAddr
	if addr_ := os.Getenv("LISTEN_ADDR"); addr_ != "" {
		addr = addr_
	} else if port, err := strconv.Atoi(os.Getenv("PORT")); err == nil && port >= 0 {
		addr = fmt.Sprintf(":%d", port)
	}
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		panic(err)
	}

	l, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		panic(err)
	}

	svc = svc.Filter(networkFilter)
	downer := &httpdown.HTTP{
		StopTimeout: 20 * time.Second,
		KillTimeout: 25 * time.Second}
	server := downer.Serve(&http.Server{
		Handler:        httpHandler(svc),
		MaxHeaderBytes: http.DefaultMaxHeaderBytes}, l)
	log.Info(nil, "Listening on %v", l.Addr())
	return listener{
		Server: server,
		addr:   l.Addr()}
}

func httpHandler(svc Service) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, httpReq *http.Request) {
		req := Request{
			Request: *httpReq,
			Context: context.Background()} // @TODO: Proper context
		rsp := svc(req)

		// Write the response out to the wire
		for k, v := range rsp.Header {
			rw.Header()[k] = v
		}
		rw.WriteHeader(rsp.StatusCode)
		if rsp.Body != nil {
			defer rsp.Body.Close()
			if _, err := io.Copy(rw, rsp.Body); err != nil {
				log.Error(req, "[Typhon:http:networkTransport] Error copying response body: %v", err)
			}
		}
	})
}
<|endoftext|>


<commit_before>package mongotrainer

import (
	"code.google.com/p/goprotobuf/proto"
	// "github.com/golang/glog"
	pb "github.com/ajtulloch/decisiontrees/protobufs"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"testing"
)

func TestMongoInteraction(t *testing.T) {
	session, err := mgo.Dial(*MongoServer)
	if err != nil {
		panic(err)
	}
	defer session.Close()

	// Optional. Switch the session to a monotonic behavior.
	session.SetMode(mgo.Monotonic, true)

	c := session.DB(*MongoDatabase).C(*MongoCollection)
	entry := pb.TrainingRow{
		TrainingStatus: pb.TrainingStatus_UNCLAIMED.Enum(),
		ForestConfig: &pb.ForestConfig{
			NumWeakLearners: proto.Int64(5),
		},
	}
	err = c.Insert(entry)
	if err != nil {
		panic(err)
	}

	result := pb.TrainingRow{}
	err = c.Find(bson.M{}).One(&result)
	if err != nil {
		panic(err)
	}
	t.Log("Got result: ", result.String())
	if !proto.Equal(&result, &entry) {
		t.Fatal(result, entry)
	}
	c.Remove(bson.M{})
}
<commit_msg>[Decision Trees] Use dedicated collection for mongo_interface tests.<commit_after>package mongotrainer

import (
	"code.google.com/p/goprotobuf/proto"
	// "github.com/golang/glog"
	pb "github.com/ajtulloch/decisiontrees/protobufs"
	"labix.org/v2/mgo"
	"labix.org/v2/mgo/bson"
	"testing"
)

func TestMongoInteraction(t *testing.T) {
	session, err := mgo.Dial(*MongoServer)
	if err != nil {
		panic(err)
	}
	defer session.Close()

	// Optional. Switch the session to a monotonic behavior.
	session.SetMode(mgo.Monotonic, true)

	c := session.DB("test").C("mongo_interface_test")
	c.Remove(bson.M{})
	entry := pb.TrainingRow{
		TrainingStatus: pb.TrainingStatus_UNCLAIMED.Enum(),
		ForestConfig: &pb.ForestConfig{
			NumWeakLearners: proto.Int64(5),
		},
	}
	err = c.Insert(entry)
	if err != nil {
		panic(err)
	}

	result := pb.TrainingRow{}
	err = c.Find(bson.M{}).One(&result)
	if err != nil {
		panic(err)
	}
	t.Log("Got result: ", result.String())
	if !proto.Equal(&result, &entry) {
		t.Fatal(result, entry)
	}
	c.Remove(bson.M{})
}
<|endoftext|>


<commit_before>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"reflect"
	"unsafe"
)

type Multi struct {
	page   []byte
	stride int
}

// WrapMulti converts a page of contiguous values with stride size into a
// Multi.  WrapMulti panics if len(page) is not a multiple of stride.
//
//		_, val, _ := cursor.Get(nil, nil, lmdb.FirstDup)
//		_, page, _ := cursor.Get(nil, nil, lmdb.GetMultiple)
//		multi := lmdb.WrapMulti(page, len(val))
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
func WrapMulti(page []byte, stride int) *Multi {
	if len(page)%stride != 0 {
		panic("incongruent arguments")
	}

	return &Multi{page: page, stride: stride}
}

// Vals returns a slice containing each value in m.
func (m *Multi) Vals() [][]byte {
	i, ps := 0, make([][]byte, m.Len())
	for off := 0; off < len(m.page); off += m.stride {
		ps[i] = m.page[off : off+m.stride]
		i++
	}
	return ps
}

// Val returns the m at index i.  Val panics if i is out of range.
func (m *Multi) Val(i int) []byte {
	if i < 0 || m.Len() <= i {
		panic("index out of range")
	}
	off := i * m.stride
	return m.page[off : off+m.stride]
}

// Len returns the number of m in the Multi.
func (m *Multi) Len() int {
	return len(m.page) / m.stride
}

// Stride returns the length of an individual item in the Multi.
func (m *Multi) Stride() int {
	return m.stride
}

// Size returns the total size of the Multi data and is equim to
//
//		m.Len()*m.String()
//
func (m *Multi) Size() int {
	return len(m.page)
}

// Page returns the Multi page data as a raw slice of bytes with length
// m.Size().
func (m *Multi) Page() []byte {
	return m.page[:len(m.page):len(m.page)]
}

func (m *Multi) val() *multiVal {
	return &multiVal{
		mdbVal{
			mv_size: C.size_t(m.stride),
			mv_data: unsafe.Pointer(&m.page[0]),
		},
		mdbVal{
			mv_size: C.size_t(len(m.page) / m.stride),
		},
	}
}

// multiVal is a type to hold a page of values retrieved from a database
// created with DupSort|DupFixed.
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
type multiVal [2]mdbVal

// val converts a Multi into a pointer to mdbVal.  This effectively creates a
// C-style array of the Multi data.
//
// See mdb_cursor_put and MDB_MULTIPLE.
func (val *multiVal) val() *mdbVal {
	return &val[0]
}

// MDB_val
type mdbVal C.MDB_val

// wrapVal creates an mdbVal that points to p's data. the mdbVal's data must
// not be freed manually and C references must not survive the garbage
// collection of p.
func wrapVal(p []byte) *mdbVal {
	if len(p) == 0 {
		return new(mdbVal)
	}
	return &mdbVal{
		mv_size: C.size_t(len(p)),
		mv_data: unsafe.Pointer(&p[0]),
	}
}

// BytesCopy returns a slice copied from the region pointed to by val.
func (val *mdbVal) BytesCopy() []byte {
	return C.GoBytes(val.mv_data, C.int(val.mv_size))
}

// Bytes creates a slice referencing the region referenced by val.
func (val *mdbVal) Bytes() []byte {
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(val.mv_data)),
		Len:  int(val.mv_size),
		Cap:  int(val.mv_size),
	}
	return *(*[]byte)(unsafe.Pointer(&hdr))
}

// If val is nil, an empty string is returned.
func (val *mdbVal) String() string {
	return C.GoStringN((*C.char)(val.mv_data), C.int(val.mv_size))
}
<commit_msg>numerous godoc fixes regarding the Multi type<commit_after>package lmdb

/*
#include <stdlib.h>
#include <stdio.h>
#include "lmdb.h"
*/
import "C"

import (
	"reflect"
	"unsafe"
)

// Multi is a wrapper for a contiguous page of sorted, fixed-length values
// passed to Cursor.PutMulti or retrieved using Cursor.Get with the
// GetMultiple/NextMultiple flag.
//
// Multi values are only useful in databases opened with DupSort|DupFixed.
type Multi struct {
	page   []byte
	stride int
}

// WrapMulti converts a page of contiguous values with stride size into a
// Multi.  WrapMulti panics if len(page) is not a multiple of stride.
//
//		_, val, _ := cursor.Get(nil, nil, lmdb.FirstDup)
//		_, page, _ := cursor.Get(nil, nil, lmdb.GetMultiple)
//		multi := lmdb.WrapMulti(page, len(val))
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
func WrapMulti(page []byte, stride int) *Multi {
	if len(page)%stride != 0 {
		panic("incongruent arguments")
	}

	return &Multi{page: page, stride: stride}
}

// Vals returns a slice containing the values in m.  The returned slice has
// length m.Len() and each item has length m.Stride().
func (m *Multi) Vals() [][]byte {
	i, ps := 0, make([][]byte, m.Len())
	for off := 0; off < len(m.page); off += m.stride {
		ps[i] = m.page[off : off+m.stride]
		i++
	}
	return ps
}

// Val returns the value at index i.  Val panics if i is out of range.
func (m *Multi) Val(i int) []byte {
	if i < 0 || m.Len() <= i {
		panic("index out of range")
	}
	off := i * m.stride
	return m.page[off : off+m.stride]
}

// Len returns the number of values in the Multi.
func (m *Multi) Len() int {
	return len(m.page) / m.stride
}

// Stride returns the length of an individual value in the m.
func (m *Multi) Stride() int {
	return m.stride
}

// Size returns the total size of the Multi data and is equal to
//
//		m.Len()*m.Stride()
//
func (m *Multi) Size() int {
	return len(m.page)
}

// Page returns the Multi page data as a raw slice of bytes with length
// m.Size().
func (m *Multi) Page() []byte {
	return m.page[:len(m.page):len(m.page)]
}

func (m *Multi) val() *multiVal {
	return &multiVal{
		mdbVal{
			mv_size: C.size_t(m.stride),
			mv_data: unsafe.Pointer(&m.page[0]),
		},
		mdbVal{
			mv_size: C.size_t(len(m.page) / m.stride),
		},
	}
}

// multiVal is a type to hold a page of values retrieved from a database
// created with DupSort|DupFixed.
//
// See mdb_cursor_get and MDB_GET_MULTIPLE.
type multiVal [2]mdbVal

// val converts a Multi into a pointer to mdbVal.  This effectively creates a
// C-style array of the Multi data.
//
// See mdb_cursor_put and MDB_MULTIPLE.
func (val *multiVal) val() *mdbVal {
	return &val[0]
}

// MDB_val
type mdbVal C.MDB_val

// wrapVal creates an mdbVal that points to p's data. the mdbVal's data must
// not be freed manually and C references must not survive the garbage
// collection of p.
func wrapVal(p []byte) *mdbVal {
	if len(p) == 0 {
		return new(mdbVal)
	}
	return &mdbVal{
		mv_size: C.size_t(len(p)),
		mv_data: unsafe.Pointer(&p[0]),
	}
}

// BytesCopy returns a slice copied from the region pointed to by val.
func (val *mdbVal) BytesCopy() []byte {
	return C.GoBytes(val.mv_data, C.int(val.mv_size))
}

// Bytes creates a slice referencing the region referenced by val.
func (val *mdbVal) Bytes() []byte {
	hdr := reflect.SliceHeader{
		Data: uintptr(unsafe.Pointer(val.mv_data)),
		Len:  int(val.mv_size),
		Cap:  int(val.mv_size),
	}
	return *(*[]byte)(unsafe.Pointer(&hdr))
}

// If val is nil, an empty string is returned.
func (val *mdbVal) String() string {
	return C.GoStringN((*C.char)(val.mv_data), C.int(val.mv_size))
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"bytes"
	"log"
	"net/http"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"code.google.com/p/vitess/go/cache"
)

const CacheCapacity = 256*1024*1024 // 256MB
const CacheTTL = 60 // raw.github.com cache TTL is ~120

var DefaultTemplate string

type CacheValue struct {
	Value string
	CreatedAt int64
}

func (cv *CacheValue) Size() int {
	return len(cv.Value)
}

func parseRequest(r *http.Request) (user, repo, doc string, err error) {
	hostname := strings.Split(r.Host, ".")
	user = hostname[0]
	path := strings.Split(r.RequestURI, "/")
	repo = path[1]
	if len(path) < 3 || (len(path) == 3 && strings.HasSuffix(r.RequestURI, "/")) {
		doc = "index"
	} else {
		doc = strings.Join(path[2:], "/")
		if strings.HasSuffix(doc, "/") {
        	doc = doc[:len(doc)-1]
    	}
	}
	return
}

func fetchAndRenderDoc(user, repo, doc string) (string, error) {
	template := make(chan string)
	go func() {
		resp, err := http.Get("https://raw.github.com/"+user+"/"+repo+"/master/docs/template.html")
		if err != nil || resp.StatusCode == 404 {
			template <- DefaultTemplate
			return
		}
		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			template <- DefaultTemplate
			return
		}
		template <- string(body)
	}()
	resp, err := http.Get("https://raw.github.com/"+user+"/"+repo+"/master/docs/"+doc+".md")
	if err != nil {
		return "", err
	}
	var body []byte
	if resp.StatusCode == 200 {
		body, err = ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return "", err
		}
	} else {
		resp.Body.Close()
		body = []byte("# Page not found")
	}
	payload, err := json.Marshal(map[string]string{"text": string(body)})
	if err != nil {
		return "", err
	}
	resp, err = http.Post("https://api.github.com/markdown?access_token="+os.Getenv("ACCESS_TOKEN"), "application/json", bytes.NewBuffer(payload))
	if err != nil {
		return "", err
	}
	body, err = ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return "", err
	}
	output := strings.Replace(<-template, "{{CONTENT}}", string(body), 1)
	output = strings.Replace(output, "{{NAME}}", repo, -1)
	output = strings.Replace(output, "{{USER}}", user, -1)
	return output, nil
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8888"
	}

	lru := cache.NewLRUCache(CacheCapacity)

	resp, err := http.Get("https://raw.github.com/progrium/viewdocs/master/docs/template.html")
	if err != nil || resp.StatusCode == 404 {
		log.Fatal("Unable to fetch default template")
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	DefaultTemplate = string(body)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.RequestURI == "/" {
			http.Redirect(w, r, "http://progrium.viewdocs.io/viewdocs", 301)
			return
		}
		if r.RequestURI == "/favicon.ico" {
			return
		}
		switch r.Method {
		case "GET":
			user, repo, doc, err := parseRequest(r)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			key := user + ":" + repo + ":" + doc
			value, ok := lru.Get(key)
			var output string
			if !ok {
				output, err = fetchAndRenderDoc(user, repo, doc)
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}
				lru.Set(key, &CacheValue{output, time.Now().Unix()})
				log.Println("CACHE MISS:", key, lru.StatsJSON())
			} else {
				output = value.(*CacheValue).Value
				if time.Now().Unix() - value.(*CacheValue).CreatedAt > CacheTTL {
					lru.Delete(key)
				}
			}
			w.Write([]byte(output))
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})
	log.Println("Listening on port "+port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<commit_msg>Error out in case ACCESS_TOKEN is not set<commit_after>package main

import (
	"encoding/json"
	"bytes"
	"log"
	"net/http"
	"io/ioutil"
	"os"
	"strings"
	"time"

	"code.google.com/p/vitess/go/cache"
)

const CacheCapacity = 256*1024*1024 // 256MB
const CacheTTL = 60 // raw.github.com cache TTL is ~120

var DefaultTemplate string

type CacheValue struct {
	Value string
	CreatedAt int64
}

func (cv *CacheValue) Size() int {
	return len(cv.Value)
}

func parseRequest(r *http.Request) (user, repo, doc string, err error) {
	hostname := strings.Split(r.Host, ".")
	user = hostname[0]
	path := strings.Split(r.RequestURI, "/")
	repo = path[1]
	if len(path) < 3 || (len(path) == 3 && strings.HasSuffix(r.RequestURI, "/")) {
		doc = "index"
	} else {
		doc = strings.Join(path[2:], "/")
		if strings.HasSuffix(doc, "/") {
        	doc = doc[:len(doc)-1]
    	}
	}
	return
}

func fetchAndRenderDoc(user, repo, doc string) (string, error) {
	template := make(chan string)
	go func() {
		resp, err := http.Get("https://raw.github.com/"+user+"/"+repo+"/master/docs/template.html")
		if err != nil || resp.StatusCode == 404 {
			template <- DefaultTemplate
			return
		}
		body, err := ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			template <- DefaultTemplate
			return
		}
		template <- string(body)
	}()
	resp, err := http.Get("https://raw.github.com/"+user+"/"+repo+"/master/docs/"+doc+".md")
	if err != nil {
		return "", err
	}
	var body []byte
	if resp.StatusCode == 200 {
		body, err = ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			return "", err
		}
	} else {
		resp.Body.Close()
		body = []byte("# Page not found")
	}
	payload, err := json.Marshal(map[string]string{"text": string(body)})
	if err != nil {
		return "", err
	}
	resp, err = http.Post("https://api.github.com/markdown?access_token="+os.Getenv("ACCESS_TOKEN"), "application/json", bytes.NewBuffer(payload))
	if err != nil {
		return "", err
	}
	body, err = ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return "", err
	}
	output := strings.Replace(<-template, "{{CONTENT}}", string(body), 1)
	output = strings.Replace(output, "{{NAME}}", repo, -1)
	output = strings.Replace(output, "{{USER}}", user, -1)
	return output, nil
}

func main() {
	if os.Getenv("ACCESS_TOKEN") == "" {
		// TODO: Add direct link to Development section of the README
		log.Fatal("ACCESS_TOKEN was not found!")
	}

	port := os.Getenv("PORT")
	if port == "" {
		port = "8888"
	}

	lru := cache.NewLRUCache(CacheCapacity)

	resp, err := http.Get("https://raw.github.com/progrium/viewdocs/master/docs/template.html")
	if err != nil || resp.StatusCode == 404 {
		log.Fatal("Unable to fetch default template")
	}
	body, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	DefaultTemplate = string(body)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.RequestURI == "/" {
			http.Redirect(w, r, "http://progrium.viewdocs.io/viewdocs", 301)
			return
		}
		if r.RequestURI == "/favicon.ico" {
			return
		}
		switch r.Method {
		case "GET":
			user, repo, doc, err := parseRequest(r)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte(err.Error()))
				return
			}
			key := user + ":" + repo + ":" + doc
			value, ok := lru.Get(key)
			var output string
			if !ok {
				output, err = fetchAndRenderDoc(user, repo, doc)
				if err != nil {
					w.WriteHeader(http.StatusInternalServerError)
					w.Write([]byte(err.Error()))
					return
				}
				lru.Set(key, &CacheValue{output, time.Now().Unix()})
				log.Println("CACHE MISS:", key, lru.StatsJSON())
			} else {
				output = value.(*CacheValue).Value
				if time.Now().Unix() - value.(*CacheValue).CreatedAt > CacheTTL {
					lru.Delete(key)
				}
			}
			w.Write([]byte(output))
		default:
			w.WriteHeader(http.StatusMethodNotAllowed)
		}
	})
	log.Println("Listening on port "+port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


<commit_before>package net

import (
	"bytes"
	"encoding/json"
	"fmt"
	e "gowork/error"
	"gowork/extern/logging"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

var (
	HTTP_METHOD_GET    = "GET"
	HTTP_METHOD_PUT    = "PUT"
	HTTP_METHOD_POST   = "POST"
	HTTP_METHOD_PATCH  = "PATCH"
	HTTP_METHOD_DELETE = "DELETE"

	CONTENT_NONE = ""
	CONTENT_JSON = "application/json"
	CONTENT_YAML = "application/yaml"
)

type HTTPRequest struct {
	Method       string
	URL          string
	UserID       string
	X_Auth_Token string
	Form         interface{}
	Body         interface{}
}

type HTTPResponse struct {
	Code int         `json:"code, omitempty"`
	Msg  string      `json:"msg, omitempty"`
	Data interface{} `json:"data, omitempty"`
}

type IRequest interface {
	DoRequest(resp interface{}) *e.WError
}

// warpper
type Responser http.ResponseWriter
type Requester http.Request
type HandlerFunc func(http.ResponseWriter, *http.Request)
type Handler interface {
	ServeHTTP(http.ResponseWriter, *http.Request)
}

func Serve(srvPort string, handler http.Handler) {
	logging.Info("[Serve] Try to listen on port: %s", srvPort)
	go func() {
		err := http.ListenAndServe(srvPort, handler)
		if err != nil {
			logging.Error("[Serve] Listen failed, error = %s", err.Error())
			return
		}
	}()
}

func Health(srvPort string, handler http.Handler) {
	logging.Info("[Health] Try to monitor health condition on port: %s", srvPort)
	go func() {
		err := http.ListenAndServe(srvPort, handler)
		if err != nil {
			logging.Error("[Health] monitor failed, error = %s", err.Error())
			return
		}
	}()
}

func HandleFunc(addr string, handler HandlerFunc) {
	http.HandleFunc(addr, handler)
}

///////////////////////////////////////////////////////////////////////
type Request struct {
	ID      string
	URL     string
	Method  string
	Content string
	Req     *http.Request
}

func NewRequest(id string, target string, method string, content string, contentType string) *Request {
	req := &Request{
		ID:      id,
		URL:     target,
		Method:  method,
		Content: content,
	}

	request, err := http.NewRequest(req.Method, req.URL, strings.NewReader(req.Content))
	if err != nil {
		logging.Error("[NewRequest] Fatal error when create request, error = %s, url = %s", err.Error(), target)
		return nil
	}

	if contentType != CONTENT_NONE {
		request.Header.Set("Content-Type", contentType)
	}

	req.Req = request

	return req
}

func (req *Request) AddHeader(key string, value string) {
	req.Req.Header.Add(key, value)
}

func (req *Request) DoRequest(resp interface{}) (*http.Response, *e.WError) {
	logging.Debug("[Request.DoRequest, id: %s] start connection[to: %s, method: %s, content: %s]", req.ID, req.URL, req.Method, req.Content)
	client := &http.Client{}
	client.Timeout = time.Duration(4 * time.Second)

	response, err := client.Do(req.Req)
	if err != nil {
		logging.Error("[Request.DoRequest] Failed to talk with remote server, error = %s, id: %s", err.Error(), req.ID)
		return nil, e.NewWError(1003, "Failed to request to remote server[url: %s], error = %s", req.URL, err.Error())
	}

	if response.StatusCode < 200 || response.StatusCode >= 300 {
		logging.Error("[Request.DoRequest] Error returns with code: %d, msg: %s", response.StatusCode, response.Status)
		return nil, e.NewWError(1003, "Error returns with code: %d, msg: %s", response.StatusCode, response.Status)
	}

	if resp != nil {
		defer response.Body.Close()

		text, err := ioutil.ReadAll(response.Body)
		if err != nil {
			logging.Error("[Request.DoRequest, id: %s] Failed to read body of response: %v", req.ID, response.Body)
			return nil, e.NewWError(1003, err.Error())
		}

		err = json.Unmarshal(text, &resp)
		if err != nil {
			logging.Error("[Request.DoRequest, id: %s] json unmarshal, error: %s", req.ID, err.Error())
			return nil, e.NewWError(1003, err.Error())
		}

		return nil, nil
	}

	return response, nil
}

func Serialize(source map[string]interface{}) string {
	text, err := json.Marshal(&source)
	if err != nil {
		logging.Error("[Serialize] Failed to convert map to json byte, error: %s", err.Error())
		return ""
	}

	buff := bytes.NewBuffer(text)

	return string(buff.Bytes())
}

func Call(name string, url string, method string, content string, contentType string, resp interface{}) (string, *e.WError) {
	req := NewRequest(name, url, method, content, contentType)
	if req == nil {
		logging.Error("[Call, id: %s] Failed to create Request", name)
		return "", e.NewWError(1003, "Failed to create Request")
	}

	if resp != nil {
		_, err := req.DoRequest(resp)
		if err != nil {
			logging.Error("[Call, id: %s] Failed to do Request, error = %s", name, err.Error())
			return "", err
		}

		return "", nil
	}

	response, err := req.DoRequest(nil)
	if err != nil {
		logging.Error("[Call, id: %s] Failed to do Request, error = %s", name, err.Error())
		return "", err
	}

	text, ee := ioutil.ReadAll(response.Body)
	if ee != nil {
		logging.Error("[Call, id: %s] Failed to read body of response: %v", name, response.Body)
		return "", e.NewWError(1003, ee.Error())
	}

	return string(text), nil
}

func GetRequestBody(req *http.Request, v interface{}) (interface{}, *e.WError) {

	alter := map[string]interface{}{}

	buff := bytes.NewBufferString("")
	_, err := io.Copy(buff, req.Body)
	if err != nil {
		logging.Error("[GetRequestBody] Failed to copy req body error, request = %v, error = %s", req.Body, err.Error())
		return nil, e.NewWError(e.ERR_CODE_IO, "Failed to copy req body, error = %s", err.Error())
	}
	text := buff.String()
	req.Body = ioutil.NopCloser(strings.NewReader(text))

	if v == nil {
		err = json.Unmarshal([]byte(text), alter)
	} else {
		err = json.Unmarshal([]byte(text), v)
	}
	if err != nil {
		logging.Error("[GetRequestBody] Failed to unmarshal json body error, text = %s, error = %s", text, err.Error())
		return nil, e.NewWError(e.ERR_CODE_IO, "Failed to unmarshal json body, error = %s", err.Error())
	}

	return alter, nil
}

func GetResponseData(err *e.WError, data interface{}) []byte {
	resp := &HTTPResponse{}
	if err == nil {
		resp.Code = 0
		resp.Msg = "ok"
	} else {
		resp.Code = err.Code()
		resp.Msg = err.Error()
	}
	resp.Data = data

	r, we := json.Marshal(resp)
	if we != nil {
		logging.Error("[GetResponseData] Failed, %s, data = %v", err.Error(), data)
		panic(fmt.Sprintf("[GetResponseData] Failed, %s", we.Error()))
	}

	return r
}

func LogGetResponseData(req *http.Request, err *e.WError, data interface{}) []byte {
	ret := GetResponseData(err, data)

	body := ""
	b_body, ee := ioutil.ReadAll(req.Body)
	if ee == nil {
		body = string(b_body)
	}

	//logReq := HTTPRequest{
	//	Method: req.Method,
	//	URL:    req.RequestURI,
	//	Form:   req.Form,
	//	Body:   body,
	//}

	logging.Debug( "HANDLE_LOG: url = %s, method: %s, request = %s", req.RequestURI, req.Method, string(body))
	logging.Debug("HANDLE_RESPONSE: response = %s", string(ret))

	return ret
}

func LogGetResponseDataEx(req *http.Request, sTime int64, err *e.WError, data interface{}) []byte {
	ret := GetResponseData(err, data)

	body := ""
	b_body, ee := ioutil.ReadAll(req.Body)
	if ee == nil {
		body = string(b_body)
	}

	//logReq := HTTPRequest{
	//	Method: req.Method,
	//	URL:    req.RequestURI,
	//	Form:   req.Form,
	//	Body:   body,
	//}

	cost := time.Now().UnixNano() - sTime
	logging.Info( "HANDLE_TIME: %d ms", cost / 1000000)
	logging.Debug( "HANDLE_LOG: url = %s, method: %s, request = %s", req.RequestURI, req.Method, string(body))
	logging.Debug("HANDLE_RESPONSE: response = %s", string(ret))

	return ret
}<commit_msg>print request cost<commit_after>package net

import (
	"bytes"
	"encoding/json"
	"fmt"
	e "gowork/error"
	"gowork/extern/logging"
	"io"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

var (
	HTTP_METHOD_GET    = "GET"
	HTTP_METHOD_PUT    = "PUT"
	HTTP_METHOD_POST   = "POST"
	HTTP_METHOD_PATCH  = "PATCH"
	HTTP_METHOD_DELETE = "DELETE"

	CONTENT_NONE = ""
	CONTENT_JSON = "application/json"
	CONTENT_YAML = "application/yaml"
)

type HTTPRequest struct {
	Method       string
	URL          string
	UserID       string
	X_Auth_Token string
	Form         interface{}
	Body         interface{}
}

type HTTPResponse struct {
	Code int         `json:"code, omitempty"`
	Msg  string      `json:"msg, omitempty"`
	Data interface{} `json:"data, omitempty"`
}

type IRequest interface {
	DoRequest(resp interface{}) *e.WError
}

// warpper
type Responser http.ResponseWriter
type Requester http.Request
type HandlerFunc func(http.ResponseWriter, *http.Request)
type Handler interface {
	ServeHTTP(http.ResponseWriter, *http.Request)
}

func Serve(srvPort string, handler http.Handler) {
	logging.Info("[Serve] Try to listen on port: %s", srvPort)
	go func() {
		err := http.ListenAndServe(srvPort, handler)
		if err != nil {
			logging.Error("[Serve] Listen failed, error = %s", err.Error())
			return
		}
	}()
}

func Health(srvPort string, handler http.Handler) {
	logging.Info("[Health] Try to monitor health condition on port: %s", srvPort)
	go func() {
		err := http.ListenAndServe(srvPort, handler)
		if err != nil {
			logging.Error("[Health] monitor failed, error = %s", err.Error())
			return
		}
	}()
}

func HandleFunc(addr string, handler HandlerFunc) {
	http.HandleFunc(addr, handler)
}

///////////////////////////////////////////////////////////////////////
type Request struct {
	ID      string
	URL     string
	Method  string
	Content string
	Req     *http.Request
}

func NewRequest(id string, target string, method string, content string, contentType string) *Request {
	req := &Request{
		ID:      id,
		URL:     target,
		Method:  method,
		Content: content,
	}

	request, err := http.NewRequest(req.Method, req.URL, strings.NewReader(req.Content))
	if err != nil {
		logging.Error("[NewRequest] Fatal error when create request, error = %s, url = %s", err.Error(), target)
		return nil
	}

	if contentType != CONTENT_NONE {
		request.Header.Set("Content-Type", contentType)
	}

	req.Req = request

	return req
}

func (req *Request) AddHeader(key string, value string) {
	req.Req.Header.Add(key, value)
}

func (req *Request) DoRequest(resp interface{}) (*http.Response, *e.WError) {
	logging.Debug("[Request.DoRequest, id: %s] start connection[to: %s, method: %s, content: %s]", req.ID, req.URL, req.Method, req.Content)
	client := &http.Client{}
	client.Timeout = time.Duration(4 * time.Second)

	response, err := client.Do(req.Req)
	if err != nil {
		logging.Error("[Request.DoRequest] Failed to talk with remote server, error = %s, id: %s", err.Error(), req.ID)
		return nil, e.NewWError(1003, "Failed to request to remote server[url: %s], error = %s", req.URL, err.Error())
	}

	if response.StatusCode < 200 || response.StatusCode >= 300 {
		logging.Error("[Request.DoRequest] Error returns with code: %d, msg: %s", response.StatusCode, response.Status)
		return nil, e.NewWError(1003, "Error returns with code: %d, msg: %s", response.StatusCode, response.Status)
	}

	if resp != nil {
		defer response.Body.Close()

		text, err := ioutil.ReadAll(response.Body)
		if err != nil {
			logging.Error("[Request.DoRequest, id: %s] Failed to read body of response: %v", req.ID, response.Body)
			return nil, e.NewWError(1003, err.Error())
		}

		err = json.Unmarshal(text, &resp)
		if err != nil {
			logging.Error("[Request.DoRequest, id: %s] json unmarshal, error: %s", req.ID, err.Error())
			return nil, e.NewWError(1003, err.Error())
		}

		return nil, nil
	}

	return response, nil
}

func Serialize(source map[string]interface{}) string {
	text, err := json.Marshal(&source)
	if err != nil {
		logging.Error("[Serialize] Failed to convert map to json byte, error: %s", err.Error())
		return ""
	}

	buff := bytes.NewBuffer(text)

	return string(buff.Bytes())
}

func Call(name string, url string, method string, content string, contentType string, resp interface{}) (string, *e.WError) {
	req := NewRequest(name, url, method, content, contentType)
	if req == nil {
		logging.Error("[Call, id: %s] Failed to create Request", name)
		return "", e.NewWError(1003, "Failed to create Request")
	}

	if resp != nil {
		_, err := req.DoRequest(resp)
		if err != nil {
			logging.Error("[Call, id: %s] Failed to do Request, error = %s", name, err.Error())
			return "", err
		}

		return "", nil
	}

	response, err := req.DoRequest(nil)
	if err != nil {
		logging.Error("[Call, id: %s] Failed to do Request, error = %s", name, err.Error())
		return "", err
	}

	text, ee := ioutil.ReadAll(response.Body)
	if ee != nil {
		logging.Error("[Call, id: %s] Failed to read body of response: %v", name, response.Body)
		return "", e.NewWError(1003, ee.Error())
	}

	return string(text), nil
}

func GetRequestBody(req *http.Request, v interface{}) (interface{}, *e.WError) {

	alter := map[string]interface{}{}

	buff := bytes.NewBufferString("")
	_, err := io.Copy(buff, req.Body)
	if err != nil {
		logging.Error("[GetRequestBody] Failed to copy req body error, request = %v, error = %s", req.Body, err.Error())
		return nil, e.NewWError(e.ERR_CODE_IO, "Failed to copy req body, error = %s", err.Error())
	}
	text := buff.String()
	req.Body = ioutil.NopCloser(strings.NewReader(text))

	if v == nil {
		err = json.Unmarshal([]byte(text), alter)
	} else {
		err = json.Unmarshal([]byte(text), v)
	}
	if err != nil {
		logging.Error("[GetRequestBody] Failed to unmarshal json body error, text = %s, error = %s", text, err.Error())
		return nil, e.NewWError(e.ERR_CODE_IO, "Failed to unmarshal json body, error = %s", err.Error())
	}

	return alter, nil
}

func GetResponseData(err *e.WError, data interface{}) []byte {
	resp := &HTTPResponse{}
	if err == nil {
		resp.Code = 0
		resp.Msg = "ok"
	} else {
		resp.Code = err.Code()
		resp.Msg = err.Error()
	}
	resp.Data = data

	r, we := json.Marshal(resp)
	if we != nil {
		logging.Error("[GetResponseData] Failed, %s, data = %v", err.Error(), data)
		panic(fmt.Sprintf("[GetResponseData] Failed, %s", we.Error()))
	}

	return r
}

func LogGetResponseData(req *http.Request, err *e.WError, data interface{}) []byte {
	ret := GetResponseData(err, data)

	body := ""
	b_body, ee := ioutil.ReadAll(req.Body)
	if ee == nil {
		body = string(b_body)
	}

	//logReq := HTTPRequest{
	//	Method: req.Method,
	//	URL:    req.RequestURI,
	//	Form:   req.Form,
	//	Body:   body,
	//}

	logging.Debug( "HANDLE_LOG: url = %s, method: %s, request = %s", req.RequestURI, req.Method, string(body))
	logging.Debug("HANDLE_RESPONSE: response = %s", string(ret))

	return ret
}

func LogGetResponseDataEx(req *http.Request, sTime int64, err *e.WError, data interface{}) []byte {
	ret := GetResponseData(err, data)

	body := ""
	b_body, ee := ioutil.ReadAll(req.Body)
	if ee == nil {
		body = string(b_body)
	}

	//logReq := HTTPRequest{
	//	Method: req.Method,
	//	URL:    req.RequestURI,
	//	Form:   req.Form,
	//	Body:   body,
	//}

	cost := time.Now().UnixNano() - sTime
	logging.Info( "HANDLE_TIME: %d ms", cost / 1e6)
	logging.Info( "HANDLE_LOG: url = %s, method: %s, request = %s", req.RequestURI, req.Method, string(body))
	logging.Debug("HANDLE_RESPONSE: response = %s", string(ret))

	return ret
}<|endoftext|>


<commit_before>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package types

// LocationMetadata contains GPS coordinates
type LocationMetadata struct {
	Altitude  int32   `json:"altitude,omitempty"`
	Longitude float32 `json:"longitude,omitempty"`
	Latitude  float32 `json:"latitude,omitempty"`
}
<commit_msg>Change order of Location metadata<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package types

// LocationMetadata contains GPS coordinates
type LocationMetadata struct {
	Latitude  float32 `json:"latitude,omitempty"`
	Longitude float32 `json:"longitude,omitempty"`
	Altitude  int32   `json:"altitude,omitempty"`
}
<|endoftext|>


<commit_before>package registry

import (
	"github.com/dotcloud/docker/auth"
	"strings"
	"testing"
)
var (
	IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
	TOKEN = []string{"fake-token"}
	REPO = "foo42/bar"
)

type simpleVersionInfo struct {
	name    string
	version string
}

func (v *simpleVersionInfo) Name() string {
	return v.name
}

func (v *simpleVersionInfo) Version() string {
	return v.version
}

func spawnTestRegistry(t *testing.T) *Registry {
	versionInfo := make([]VersionInfo, 0, 4)
	versionInfo = append(versionInfo, &simpleVersionInfo{"docker", "0.0.0test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"go", "test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"git-commit", "test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"kernel", "test"})
	authConfig := &auth.AuthConfig{}
	r, err := NewRegistry("", authConfig, versionInfo...)
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func TestPingRegistryEndpoint(t *testing.T) {
	err := pingRegistryEndpoint(makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
}

func TestGetRemoteHistory(t *testing.T) {
	r := spawnTestRegistry(t)
	hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(hist), 2, "Expected 2 images in history")
	assertEqual(t, hist[0], IMAGE_ID, "Expected " + IMAGE_ID + "as first ancestry")
	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		"Unexpected second ancestry")
}

func TestLookupRemoteImage(t *testing.T) {
	r := spawnTestRegistry(t)
	found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
	assertEqual(t, found, true, "Expected remote lookup to succeed")
	found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
	assertEqual(t, found, false, "Expected remote lookup to fail")
}

func TestGetRemoteImageJSON(t *testing.T) {
	r := spawnTestRegistry(t)
	json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, size, 154, "Expected size 154")
	if len(json) <= 0 {
		t.Fatal("Expected non-empty json")
	}

	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteImageLayer(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	if data == nil {
		t.Fatal("Expected non-nil data result")
	}

	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteTags(t *testing.T) {
	r := spawnTestRegistry(t)
	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(tags), 1, "Expected one tag")
	assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to " + IMAGE_ID)

	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
	if err == nil {
		t.Fatal("Expected error when fetching tags for bogus repo")
	}
}

func TestGetRepositoryData(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRepositoryData(makeURL("/v1/"), "foo42/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
	assertEqual(t, len(data.Endpoints), 1, "Expected one endpoint in Endpoints")
}

func TestPushImageJSONRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := &ImgData{
		ID:	"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
	}

	err := r.PushImageJSONRegistry(imgData, []byte{ 0x42, 0xdf, 0x0 }, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageLayerRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	layer := strings.NewReader("FAKELAYER")
	r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN)
}

func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
	ep, repo, err := ResolveRepositoryName("fooo/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, auth.IndexServerAddress(), "Expected endpoint to be index server address")
	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")

	u := makeURL("")[7:]
	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, "http://" + u + "/v1/", "Expected endpoint to be " + u)
	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
}

func TestPushRegistryTag(t *testing.T) {
	r := spawnTestRegistry(t)
	err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageJSONIndex(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := []*ImgData{
		&ImgData{
			ID:	"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
		},
		&ImgData{
			ID: "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
		},
	}
	ep := makeURL("/v1/")
	repoData, err := r.PushImageJSONIndex(ep, "foo42/bar", imgData, false, nil)
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
	repoData, err = r.PushImageJSONIndex(ep, "foo42/bar", imgData, true, []string{ep})
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
}

func TestSearchRepositories(t *testing.T) {
	r := spawnTestRegistry(t)
	results, err := r.SearchRepositories("supercalifragilisticepsialidocious")
	if err != nil {
		t.Fatal(err)
	}
	if results == nil {
		t.Fatal("Expected non-nil SearchResults object")
	}
	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
}<commit_msg>gofmt<commit_after>package registry

import (
	"github.com/dotcloud/docker/auth"
	"strings"
	"testing"
)

var (
	IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
	TOKEN    = []string{"fake-token"}
	REPO     = "foo42/bar"
)

type simpleVersionInfo struct {
	name    string
	version string
}

func (v *simpleVersionInfo) Name() string {
	return v.name
}

func (v *simpleVersionInfo) Version() string {
	return v.version
}

func spawnTestRegistry(t *testing.T) *Registry {
	versionInfo := make([]VersionInfo, 0, 4)
	versionInfo = append(versionInfo, &simpleVersionInfo{"docker", "0.0.0test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"go", "test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"git-commit", "test"})
	versionInfo = append(versionInfo, &simpleVersionInfo{"kernel", "test"})
	authConfig := &auth.AuthConfig{}
	r, err := NewRegistry("", authConfig, versionInfo...)
	if err != nil {
		t.Fatal(err)
	}
	return r
}

func TestPingRegistryEndpoint(t *testing.T) {
	err := pingRegistryEndpoint(makeURL("/v1/"))
	if err != nil {
		t.Fatal(err)
	}
}

func TestGetRemoteHistory(t *testing.T) {
	r := spawnTestRegistry(t)
	hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(hist), 2, "Expected 2 images in history")
	assertEqual(t, hist[0], IMAGE_ID, "Expected "+IMAGE_ID+"as first ancestry")
	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		"Unexpected second ancestry")
}

func TestLookupRemoteImage(t *testing.T) {
	r := spawnTestRegistry(t)
	found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
	assertEqual(t, found, true, "Expected remote lookup to succeed")
	found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
	assertEqual(t, found, false, "Expected remote lookup to fail")
}

func TestGetRemoteImageJSON(t *testing.T) {
	r := spawnTestRegistry(t)
	json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, size, 154, "Expected size 154")
	if len(json) <= 0 {
		t.Fatal("Expected non-empty json")
	}

	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteImageLayer(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	if data == nil {
		t.Fatal("Expected non-nil data result")
	}

	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN)
	if err == nil {
		t.Fatal("Expected image not found error")
	}
}

func TestGetRemoteTags(t *testing.T) {
	r := spawnTestRegistry(t)
	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(tags), 1, "Expected one tag")
	assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to "+IMAGE_ID)

	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
	if err == nil {
		t.Fatal("Expected error when fetching tags for bogus repo")
	}
}

func TestGetRepositoryData(t *testing.T) {
	r := spawnTestRegistry(t)
	data, err := r.GetRepositoryData(makeURL("/v1/"), "foo42/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
	assertEqual(t, len(data.Endpoints), 1, "Expected one endpoint in Endpoints")
}

func TestPushImageJSONRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := &ImgData{
		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
	}

	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageLayerRegistry(t *testing.T) {
	r := spawnTestRegistry(t)
	layer := strings.NewReader("FAKELAYER")
	r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN)
}

func TestResolveRepositoryName(t *testing.T) {
	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
	ep, repo, err := ResolveRepositoryName("fooo/bar")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, auth.IndexServerAddress(), "Expected endpoint to be index server address")
	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")

	u := makeURL("")[7:]
	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
	if err != nil {
		t.Fatal(err)
	}
	assertEqual(t, ep, "http://"+u+"/v1/", "Expected endpoint to be "+u)
	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
}

func TestPushRegistryTag(t *testing.T) {
	r := spawnTestRegistry(t)
	err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
	if err != nil {
		t.Fatal(err)
	}
}

func TestPushImageJSONIndex(t *testing.T) {
	r := spawnTestRegistry(t)
	imgData := []*ImgData{
		&ImgData{
			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
		},
		&ImgData{
			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
		},
	}
	ep := makeURL("/v1/")
	repoData, err := r.PushImageJSONIndex(ep, "foo42/bar", imgData, false, nil)
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
	repoData, err = r.PushImageJSONIndex(ep, "foo42/bar", imgData, true, []string{ep})
	if err != nil {
		t.Fatal(err)
	}
	if repoData == nil {
		t.Fatal("Expected RepositoryData object")
	}
}

func TestSearchRepositories(t *testing.T) {
	r := spawnTestRegistry(t)
	results, err := r.SearchRepositories("supercalifragilisticepsialidocious")
	if err != nil {
		t.Fatal(err)
	}
	if results == nil {
		t.Fatal("Expected non-nil SearchResults object")
	}
	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			cmd.Process.Kill()
			log.Println("\t kill successful...")
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	err = u.dev.SetFreqCorrection(globalSettings.PPM)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		return
	} else {
		log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("doing cleanup...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						UATDev = nil
					} else {
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						ESDev = nil
					} else {
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<commit_msg>log prints for testing<commit_after>package main

import (
	"log"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"../godump978"
	rtl "github.com/jpoirier/gortlsdr"
)

type UAT struct {
	dev     *rtl.Context
	indexID int
}

type ES struct {
	dev     *rtl.Context
	indexID int
}

var UATDev *UAT
var ESDev *ES

var uat_shutdown chan int
var uat_wg *sync.WaitGroup = &sync.WaitGroup{}

var es_shutdown chan int
var es_wg *sync.WaitGroup = &sync.WaitGroup{}

var maxSignalStrength int

func (e *ES) read() {
	defer es_wg.Done()
	log.Println("Entered ES read() ...")
	cmd := exec.Command("/usr/bin/dump1090", "--net", "--device-index", strconv.Itoa(e.indexID))
	err := cmd.Start()
	if err != nil {
		log.Printf("Error executing /usr/bin/dump1090: %s\n", err.Error())
		return
	}
	log.Println("Executed /usr/bin/dump1090 successfully...")
	for {
		select {
		default:
			time.Sleep(1 * time.Second)
		case <-es_shutdown:
			log.Println("ES read(): shutdown msg received, calling cmd.Process.Kill() ...")
			cmd.Process.Kill()
			log.Println("\t kill successful...")
			return
		}
	}
}

func (u *UAT) read() {
	defer uat_wg.Done()
	log.Println("Entered UAT read() ...")
	var buffer = make([]uint8, rtl.DefaultBufLength)
	for {
		select {
		default:
			nRead, err := u.dev.ReadSync(buffer, rtl.DefaultBufLength)
			if err != nil {
				log.Printf("\tReadSync Failed - error: %s\n", err)
				break
			}
			// log.Printf("\tReadSync %d\n", nRead)
			if nRead > 0 {
				buf := buffer[:nRead]
				godump978.InChan <- buf
			}
		case <-uat_shutdown:
			log.Println("UAT read(): shutdown msg received...")
			return
		}
	}
}

func (e *ES) sdrConfig() (err error) {
	return
}

// Read 978MHz from SDR.
func (u *UAT) sdrConfig() (err error) {
	log.Printf("===== UAT Device name: %s =====\n", rtl.GetDeviceName(u.indexID))
	if u.dev, err = rtl.Open(u.indexID); err != nil {
		log.Printf("\tUAT Open Failed...\n")
		return
	}
	log.Printf("\tGetTunerType: %s\n", u.dev.GetTunerType())

	//---------- Set Tuner Gain ----------
	err = u.dev.SetTunerGainMode(true)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGainMode Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGainMode Successful\n")
	}

	tgain := 480
	err = u.dev.SetTunerGain(tgain)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerGain Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetTunerGain Successful\n")
	}

	//---------- Get/Set Sample Rate ----------
	samplerate := 2083334
	err = u.dev.SetSampleRate(samplerate)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetSampleRate Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetSampleRate - rate: %d\n", samplerate)
	}
	log.Printf("\tGetSampleRate: %d\n", u.dev.GetSampleRate())

	//---------- Get/Set Xtal Freq ----------
	rtlFreq, tunerFreq, err := u.dev.GetXtalFreq()
	if err != nil {
		u.dev.Close()
		log.Printf("\tGetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tGetXtalFreq - Rtl: %d, Tuner: %d\n", rtlFreq, tunerFreq)
	}

	newRTLFreq := 28800000
	newTunerFreq := 28800000
	err = u.dev.SetXtalFreq(newRTLFreq, newTunerFreq)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetXtalFreq Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tSetXtalFreq - Center freq: %d, Tuner freq: %d\n",
			newRTLFreq, newTunerFreq)
	}

	//---------- Get/Set Center Freq ----------
	err = u.dev.SetCenterFreq(978000000)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetCenterFreq 978MHz Failed, error: %s\n", err)
		return
	} else {
		log.Printf("\tSetCenterFreq 978MHz Successful\n")
	}

	log.Printf("\tGetCenterFreq: %d\n", u.dev.GetCenterFreq())

	//---------- Set Bandwidth ----------
	bw := 1000000
	log.Printf("\tSetting Bandwidth: %d\n", bw)
	if err = u.dev.SetTunerBw(bw); err != nil {
		u.dev.Close()
		log.Printf("\tSetTunerBw %d Failed, error: %s\n", bw, err)
		return
	} else {
		log.Printf("\tSetTunerBw %d Successful\n", bw)
	}

	if err = u.dev.ResetBuffer(); err != nil {
		u.dev.Close()
		log.Printf("\tResetBuffer Failed - error: %s\n", err)
		return
	} else {
		log.Printf("\tResetBuffer Successful\n")
	}
	//---------- Get/Set Freq Correction ----------
	freqCorr := u.dev.GetFreqCorrection()
	log.Printf("\tGetFreqCorrection: %d\n", freqCorr)
	err = u.dev.SetFreqCorrection(globalSettings.PPM)
	if err != nil {
		u.dev.Close()
		log.Printf("\tSetFreqCorrection %d Failed, error: %s\n", globalSettings.PPM, err)
		return
	} else {
		log.Printf("\tSetFreqCorrection %d Successful\n", globalSettings.PPM)
	}
	return
}

// Read from the godump978 channel - on or off.
func uatReader() {
	log.Println("Entered uatReader() ...")
	for {
		uat := <-godump978.OutChan
		o, msgtype := parseInput(uat)
		if o != nil && msgtype != 0 {
			relayMessage(msgtype, o)
		}
	}
}

func (u *UAT) shutdown() {
	log.Println("Entered UAT shutdown() ...")
	close(uat_shutdown) // signal to shutdown
	log.Println("UAT shutdown(): closing device ...")
	u.dev.Close() // preempt the blocking ReadSync call
	log.Println("UAT shutdown(): calling uat_wg.Wait() ...")
	uat_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("UAT shutdown(): uat_wg.Wait() returned...")
}

func (e *ES) shutdown() {
	log.Println("Entered ES shutdown() ...")
	close(es_shutdown) // signal to shutdown
	log.Println("ES shutdown(): calling es_wg.Wait() ...")
	es_wg.Wait() // Wait for the goroutine to shutdown
	log.Println("ES shutdown(): es_wg.Wait() returned...")
}

var devMap = map[int]string{0: "", 1: ""}

// Watch for config/device changes.
func sdrWatcher() {
	for {
		time.Sleep(1 * time.Second)
		count := rtl.GetDeviceCount()
		atomic.StoreUint32(&globalStatus.Devices, uint32(count))
		log.Println("DeviceCount...", count)

		// support two and only two dongles
		if count > 2 {
			count = 2
		}

		// cleanup if necessary
		if count < 1 || (!globalSettings.UAT_Enabled && !globalSettings.ES_Enabled) {
			log.Println("doing cleanup...")
			if UATDev != nil {
				UATDev.shutdown()
				UATDev = nil
			}
			if ESDev != nil {
				ESDev.shutdown()
				ESDev = nil
			}
			continue
		}

		if count == 1 {
			if UATDev != nil && ESDev == nil {
				UATDev.indexID = 0
			} else if UATDev == nil && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		ids := []string{"", ""}
		for i := 0; i < count; i++ {
			// manufact, product, serial, err
			_, _, s, _ := rtl.GetDeviceUsbStrings(i)
			ids[i] = s
		}

		// UAT specific handling
		// When count is one, favor UAT in the case where the user
		// has enabled both UAT and ES via the web interface.
		id := 0
		if globalSettings.UAT_Enabled {
			log.Println("globalSettings.UAT_Enabled == true")
			if count == 1 {
				if ESDev != nil {
					ESDev.shutdown()
					ESDev = nil
				}
			} else { // count == 2
				if UATDev == nil && ESDev != nil {
					if ESDev.indexID == 0 {
						id = 1
					}
				}
			}

			if UATDev == nil {
				log.Println("\tUATDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:1090") {
					log.Println("Settings conflict: 978UAT set via WebUI but hardware serial says stratux:1090")
				} else {
					UATDev = &UAT{indexID: id}
					if err := UATDev.sdrConfig(); err != nil {
						UATDev = nil
					} else {
						uat_shutdown = make(chan int)
						uat_wg.Add(1)
						go UATDev.read()
					}
				}
			}
		} else if UATDev != nil {
			UATDev.shutdown()
			UATDev = nil
			if count == 1 && ESDev != nil {
				ESDev.indexID = 0
			}
		}

		// ES specific handling
		id = 0
		if globalSettings.ES_Enabled {
			log.Println("globalSettings.ES_Enabled == true")
			if count == 1 {
				if globalSettings.UAT_Enabled {
					// defer to the UAT handler
					goto End
				}
			} else { // count == 2
				if ESDev == nil && UATDev != nil {
					if UATDev.indexID == 0 {
						id = 1
					}
				}
			}

			if ESDev == nil {
				log.Println("\tESDev == nil")
				// preference check based on stratux
				// hardware serial when it exists
				serial := ids[id]
				if strings.HasPrefix(serial, "stratux:978") {
					log.Println("Settings conflict: 1090ES set via WebUI but hardware serial says stratux:978")
				} else {
					ESDev = &ES{indexID: id}
					if err := ESDev.sdrConfig(); err != nil {
						ESDev = nil
					} else {
						es_shutdown = make(chan int)
						es_wg.Add(1)
						go ESDev.read()
					}
				}
			}
		} else if ESDev != nil {
			ESDev.shutdown()
			ESDev = nil
			if count == 1 && UATDev != nil {
				UATDev.indexID = 0
			}
		}
	End:
	}
}

func sdrInit() {
	go sdrWatcher()
	go uatReader()
	godump978.Dump978Init()
	go godump978.ProcessDataFromChannel()
}
<|endoftext|>