<commit_before>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn   *tls.Conn
	queue  chan PushNotification
	errors chan *BadPushNotification
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() *Response {
	return new(Response)
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan *BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start reader goroutine
	responses := make(chan *Response, ResponseQueueSize)
	go conn.reader(responses)
	//Start limbo goroutine
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() {
	//We can't just close the main queue channel, because retries might still need to be sent there.
	//
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		pn, ok := <-conn.queue
		if !ok {
			//That means the Connection is stopped
			//close sent?
			return
		} else {
			//If not connected, connect
			if conn.conn == nil {
				for {
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						break
					}
				}
			}
			//Then send the push notification
			//TODO(draaglom): Do buffering as per the APNS docs
			payload, err := pn.ToBytes()
			if err != nil {
				//Should report this on the bad notifications channel probably
			} else {
				_, err = conn.conn.Write(payload)
				if err != nil {
					//Disconnect?
				} else {
					sent <- pn
				}
			}

		}
	}
}

func (conn *Connection) reader(responses chan<- *Response) {
	buffer := make([]byte, 6)
	for {
		_, err := conn.conn.Read(buffer)
		if err != nil {
			log.Println("APNS: Error reading from connection: ", err)
			conn.conn.Close()
			return
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	limbo := make(chan PushNotification, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	timeNextNotification := true
	for {
		select {
		case pn := <-sent:
			//Drop it into the array
			limbo <- pn
			if timeNextNotification {
				//Is there a cleaner way of doing this?
				go func(pn PushNotification) {
					<-time.After(TimeoutSeconds * time.Second)
					successResp := newResponse()
					successResp.Identifier = pn.Identifier
					responses <- *successResp
				}(pn)
				timeNextNotification = false
			}
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			switch {
			case resp.Status == 0:
				//Status 0 is a "success" response generated by a timeout in the library.
				for pn := range limbo {
					//Drop all the notifications until we get to the timed-out one.
					//(and leave the others in limbo)
					if pn.Identifier == resp.Identifier {
						break
					}
				}
			default:
				hit := false
				for pn := range limbo {
					switch {
					case pn.Identifier != resp.Identifier && !hit:
						//We haven't seen the identified notification yet
						//so these are all successful (drop silently)
					case pn.Identifier == resp.Identifier:
						hit = true
						if resp.Status != 10 {
							//It was an error, we should report this on the error channel
							bad := BadPushNotification{PushNotification: pn, Status: resp.Status}
							go func(bad BadPushNotification) {
								errors <- bad
							}(bad)
						}
					case pn.Identifier != resp.Identifier && hit:
						//We've already seen the identified notification,
						//so these should be requeued
						conn.Enqueue(&pn)
					}
				}
			}
		case <-ticker.C:
			timeNextNotification = true
		}
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	return nil
}
<commit_msg>add a constructor for Connection<commit_after>package apns

import (
	"crypto/tls"
	"encoding/binary"
	"log"
	"time"
)

//ResponseQueueSize indicates how many APNS responses may be buffered.
var ResponseQueueSize = 10000

//SentBufferSize is the maximum number of sent notifications which may be buffered.
var SentBufferSize = 10000

var maxBackoff = 20 * time.Second

//Connection represents a single connection to APNS.
type Connection struct {
	Client
	conn   *tls.Conn
	queue  chan PushNotification
	errors chan *BadPushNotification
}

//NewConnection initializes an APNS connection. Use Connection.Start() to actually start sending notifications.
func NewConnection(client *Client) *Connection {
	c := new(Connection)
	c.Client = *client
	queue := make(chan PushNotification)
	errors := make(chan *BadPushNotification)
	c.queue = queue
	c.errors = errors
	return c
}

//Response is a reply from APNS - see apns.ApplePushResponses.
type Response struct {
	Status     uint8
	Identifier uint32
}

func newResponse() *Response {
	return new(Response)
}

//BadPushNotification represents a notification which APNS didn't like.
type BadPushNotification struct {
	PushNotification
	Status uint8
}

//Enqueue adds a push notification to the end of the "sending" queue.
func (conn *Connection) Enqueue(pn *PushNotification) {
	go func(pn *PushNotification) {
		conn.queue <- *pn
	}(pn)
}

//Errors gives you a channel of the push notifications Apple rejected.
func (conn *Connection) Errors() (errors <-chan *BadPushNotification) {
	return conn.errors
}

//Start initiates a connection to APNS and asnchronously sends notifications which have been queued.
func (conn *Connection) Start() error {
	//Connect to APNS. The reason this is here as well as in sender is that this probably catches any unavoidable errors in a synchronous fashion, while in sender it can reconnect after temporary errors (which should work most of the time.)
	err := conn.connect()
	if err != nil {
		return err
	}
	//Start sender goroutine
	sent := make(chan PushNotification)
	go conn.sender(conn.queue, sent)
	//Start reader goroutine
	responses := make(chan *Response, ResponseQueueSize)
	go conn.reader(responses)
	//Start limbo goroutine
	return nil
}

//Stop gracefully closes the connection - it waits for the sending queue to clear, and then shuts down.
func (conn *Connection) Stop() {
	//We can't just close the main queue channel, because retries might still need to be sent there.
	//
}

func (conn *Connection) sender(queue <-chan PushNotification, sent chan PushNotification) {
	defer conn.conn.Close()
	var backoff = time.Duration(100)
	for {
		pn, ok := <-conn.queue
		if !ok {
			//That means the Connection is stopped
			//close sent?
			return
		} else {
			//If not connected, connect
			if conn.conn == nil {
				for {
					err := conn.connect()
					if err != nil {
						//Exponential backoff up to a limit
						log.Println("APNS: Error connecting to server: ", err)
						backoff = backoff * 2
						if backoff > maxBackoff {
							backoff = maxBackoff
						}
						time.Sleep(backoff)
					} else {
						backoff = 100
						break
					}
				}
			}
			//Then send the push notification
			//TODO(draaglom): Do buffering as per the APNS docs
			payload, err := pn.ToBytes()
			if err != nil {
				//Should report this on the bad notifications channel probably
			} else {
				_, err = conn.conn.Write(payload)
				if err != nil {
					//Disconnect?
				} else {
					sent <- pn
				}
			}

		}
	}
}

func (conn *Connection) reader(responses chan<- *Response) {
	buffer := make([]byte, 6)
	for {
		_, err := conn.conn.Read(buffer)
		if err != nil {
			log.Println("APNS: Error reading from connection: ", err)
			conn.conn.Close()
			return
		}
		resp := newResponse()
		resp.Identifier = binary.BigEndian.Uint32(buffer[2:6])
		resp.Status = uint8(buffer[1])
		responses <- resp
	}
}

func (conn *Connection) limbo(sent <-chan PushNotification, responses chan Response, errors chan BadPushNotification, queue chan PushNotification) {
	limbo := make(chan PushNotification, SentBufferSize)
	ticker := time.NewTicker(1 * time.Second)
	timeNextNotification := true
	for {
		select {
		case pn := <-sent:
			//Drop it into the array
			limbo <- pn
			if timeNextNotification {
				//Is there a cleaner way of doing this?
				go func(pn PushNotification) {
					<-time.After(TimeoutSeconds * time.Second)
					successResp := newResponse()
					successResp.Identifier = pn.Identifier
					responses <- *successResp
				}(pn)
				timeNextNotification = false
			}
		case resp, ok := <-responses:
			if !ok {
				//If the responses channel is closed,
				//that means we're shutting down the connection.
			}
			switch {
			case resp.Status == 0:
				//Status 0 is a "success" response generated by a timeout in the library.
				for pn := range limbo {
					//Drop all the notifications until we get to the timed-out one.
					//(and leave the others in limbo)
					if pn.Identifier == resp.Identifier {
						break
					}
				}
			default:
				hit := false
				for pn := range limbo {
					switch {
					case pn.Identifier != resp.Identifier && !hit:
						//We haven't seen the identified notification yet
						//so these are all successful (drop silently)
					case pn.Identifier == resp.Identifier:
						hit = true
						if resp.Status != 10 {
							//It was an error, we should report this on the error channel
							bad := BadPushNotification{PushNotification: pn, Status: resp.Status}
							go func(bad BadPushNotification) {
								errors <- bad
							}(bad)
						}
					case pn.Identifier != resp.Identifier && hit:
						//We've already seen the identified notification,
						//so these should be requeued
						conn.Enqueue(&pn)
					}
				}
			}
		case <-ticker.C:
			timeNextNotification = true
		}
	}
}

func (conn *Connection) connect() error {
	if conn.conn != nil {
		conn.conn.Close()
	}

	var cert tls.Certificate
	var err error
	if len(conn.CertificateBase64) == 0 && len(conn.KeyBase64) == 0 {
		// The user did not specify raw block contents, so check the filesystem.
		cert, err = tls.LoadX509KeyPair(conn.CertificateFile, conn.KeyFile)
	} else {
		// The user provided the raw block contents, so use that.
		cert, err = tls.X509KeyPair([]byte(conn.CertificateBase64), []byte(conn.KeyBase64))
	}

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	tlsConn, err := tls.Dial("tcp", conn.Gateway, conf)
	if err != nil {
		return err
	}
	err = tlsConn.Handshake()
	if err != nil {
		_ = tlsConn.Close()
		return err
	}
	conn.conn = tlsConn
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2018, OpenCensus 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 ocagent

import (
	"math/rand"
	"sync/atomic"
	"time"
)

const (
	sDisconnected int32 = 5 + iota
	sConnected
)

func (ae *Exporter) setStateDisconnected() {
	atomic.StoreInt32(&ae.connectionState, sDisconnected)
	select {
	case ae.disconnectedCh <- true:
	default:
	}
}

func (ae *Exporter) setStateConnected() {
	atomic.StoreInt32(&ae.connectionState, sConnected)
}

func (ae *Exporter) connected() bool {
	return atomic.LoadInt32(&ae.connectionState) == sConnected
}

const defaultConnReattemptPeriod = 10 * time.Second

func (ae *Exporter) indefiniteBackgroundConnection() error {
	defer func() {
		ae.backgroundConnectionDoneCh <- true
	}()

	connReattemptPeriod := ae.reconnectionPeriod
	if connReattemptPeriod <= 0 {
		connReattemptPeriod = defaultConnReattemptPeriod
	}

	// No strong seeding required, nano time can
	// already help with pseudo uniqueness.
	rng := rand.New(rand.NewSource(time.Now().UnixNano() + rand.Int63n(1024)))

	// maxJitter: 1 + (70% of the connectionReattemptPeriod)
	maxJitter := int64(1 + 0.7*float64(connReattemptPeriod))

	for {
		// Otherwise these will be the normal scenarios to enable
		// reconnections if we trip out.
		// 1. If we've stopped, return entirely
		// 2. Otherwise block until we are disconnected, and
		//    then retry connecting
		select {
		case <-ae.stopCh:
			return errStopped

		case <-ae.disconnectedCh:
			// Normal scenario that we'll wait for
		}

		if err := ae.connect(); err == nil {
			ae.setStateConnected()
		} else {
			ae.setStateDisconnected()
		}

		// Apply some jitter to avoid lockstep retrials of other
		// agent-exporters. Lockstep retrials could result in an
		// innocent DDOS, by clogging the machine's resources and network.
		jitter := time.Duration(rng.Int63n(maxJitter))
		<-time.After(connReattemptPeriod + jitter)
	}
}

func (ae *Exporter) connect() error {
	cc, err := ae.dialToAgent()
	if err != nil {
		return err
	}
	return ae.enableConnectionStreams(cc)
}
<commit_msg>indefiniteBackgroundConnection shouldn't hold Stop() after attempt to connect (#62)<commit_after>// Copyright 2018, OpenCensus 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 ocagent

import (
	"math/rand"
	"sync/atomic"
	"time"
)

const (
	sDisconnected int32 = 5 + iota
	sConnected
)

func (ae *Exporter) setStateDisconnected() {
	atomic.StoreInt32(&ae.connectionState, sDisconnected)
	select {
	case ae.disconnectedCh <- true:
	default:
	}
}

func (ae *Exporter) setStateConnected() {
	atomic.StoreInt32(&ae.connectionState, sConnected)
}

func (ae *Exporter) connected() bool {
	return atomic.LoadInt32(&ae.connectionState) == sConnected
}

const defaultConnReattemptPeriod = 10 * time.Second

func (ae *Exporter) indefiniteBackgroundConnection() error {
	defer func() {
		ae.backgroundConnectionDoneCh <- true
	}()

	connReattemptPeriod := ae.reconnectionPeriod
	if connReattemptPeriod <= 0 {
		connReattemptPeriod = defaultConnReattemptPeriod
	}

	// No strong seeding required, nano time can
	// already help with pseudo uniqueness.
	rng := rand.New(rand.NewSource(time.Now().UnixNano() + rand.Int63n(1024)))

	// maxJitter: 1 + (70% of the connectionReattemptPeriod)
	maxJitter := int64(1 + 0.7*float64(connReattemptPeriod))

	for {
		// Otherwise these will be the normal scenarios to enable
		// reconnections if we trip out.
		// 1. If we've stopped, return entirely
		// 2. Otherwise block until we are disconnected, and
		//    then retry connecting
		select {
		case <-ae.stopCh:
			return errStopped

		case <-ae.disconnectedCh:
			// Normal scenario that we'll wait for
		}

		if err := ae.connect(); err == nil {
			ae.setStateConnected()
		} else {
			ae.setStateDisconnected()
		}

		// Apply some jitter to avoid lockstep retrials of other
		// agent-exporters. Lockstep retrials could result in an
		// innocent DDOS, by clogging the machine's resources and network.
		jitter := time.Duration(rng.Int63n(maxJitter))
		select {
		case <-ae.stopCh:
			return errStopped
		case <-time.After(connReattemptPeriod + jitter):
		}
	}
}

func (ae *Exporter) connect() error {
	cc, err := ae.dialToAgent()
	if err != nil {
		return err
	}
	return ae.enableConnectionStreams(cc)
}
<|endoftext|>


<commit_before>package spdy

import (
  "bufio"
  "crypto/tls"
  "fmt"
  "log"
  "net/http"
  "net/url"
  "runtime"
  "sync"
  "time"
)

type connection struct {
  sync.RWMutex
  remoteAddr          string // network address of remote side
  server              *Server
  conn                *tls.Conn
  buf                 *bufio.Reader
  tlsState            *tls.ConnectionState
  tlsConfig           *tls.Config
  streams             map[uint32]*stream
  streamInputs        map[uint32]chan<- []byte
  streamOutputs       [8]chan Frame
  compressor          *Compressor
  decompressor        *Decompressor
  receivedSettings    []*Setting
  nextServerStreamID  uint32 // even
  nextClientStreamID  uint32 // odd
  goaway              bool
  version             int
  numInvalidStreamIDs int
}

func (conn *connection) send() {
  for {
    frame := conn.selectFrameToSend()
    err := frame.WriteHeaders(conn.compressor)
    if err != nil {
      panic(err)
    }
    err = frame.WriteTo(conn.conn)
    if err != nil {
      panic(err)
    }
  }
}

func (conn *connection) selectFrameToSend() (frame Frame) {
  // Try in priority order first.
  for i := 0; i < 8; i++ {
    select {
    case frame = <-conn.streamOutputs[i]:
      return frame
    default:
    }
  }

  // Wait for any frame.
  select {
  case frame = <-conn.streamOutputs[0]:
    return frame
  case frame = <-conn.streamOutputs[1]:
    return frame
  case frame = <-conn.streamOutputs[2]:
    return frame
  case frame = <-conn.streamOutputs[3]:
    return frame
  case frame = <-conn.streamOutputs[4]:
    return frame
  case frame = <-conn.streamOutputs[5]:
    return frame
  case frame = <-conn.streamOutputs[6]:
    return frame
  case frame = <-conn.streamOutputs[7]:
    return frame
  }

  panic("Unreachable")
}

func (conn *connection) newStream(frame *SynStreamFrame, input <-chan []byte,
  output chan<- Frame) *stream {

  stream := new(stream)
  stream.conn = conn
  stream.streamID = frame.StreamID
  stream.state = STATE_OPEN
  if frame.Flags&FLAG_FIN != 0 {
    stream.state = STATE_HALF_CLOSED_THERE
  }
  stream.priority = frame.Priority
  stream.input = input
  stream.output = output
  stream.handler = DefaultServeMux
  stream.certificates = make([]Certificate, 1)
  stream.headers = make(Header)
  stream.settings = make([]*Setting, 1)
  stream.unidirectional = frame.Flags&FLAG_UNIDIRECTIONAL != 0
  stream.version = conn.version
  stream.contentLength = -1

  headers := frame.Headers
  rawUrl := headers.Get(":scheme") + "://" + headers.Get(":host") + headers.Get(":path")
  url, err := url.Parse(rawUrl)
  if err != nil {
    panic(err)
  }
  major, minor, ok := http.ParseHTTPVersion(headers.Get(":version"))
  if !ok {
    panic("Invalid HTTP version: " + headers.Get(":version"))
  }
  stream.request = &Request{
    Method:     headers.Get(":method"),
    URL:        url,
    Proto:      headers.Get(":version"),
    ProtoMajor: major,
    ProtoMinor: minor,
    Header:     headers,
    Host:       url.Host,
    RequestURI: url.Path,
    TLS:        conn.tlsState,
  }

  return stream
}

func (conn *connection) WriteFrame(frame Frame) error {
  return nil
}

func (conn *connection) handleSynStream(frame *SynStreamFrame) {
  conn.RLock()
  defer func() { conn.RUnlock() }()

  // Check stream creation is allowed.
  if conn.goaway {
    return
  }

  // Check version.
  if frame.Version != uint16(conn.version) {

    // This is currently strict; only one version allowed per connection.
    log.Printf("Error: Received frame with SPDY version %d on connection with version %d.\n",
      frame.Version, conn.version)
    if frame.Version > SPDY_VERSION {
      log.Printf("Error: Received frame with SPDY version %d, which is not supported.\n",
        frame.Version)
    }
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_UNSUPPORTED_VERSION
    conn.WriteFrame(reply)
    return
  }

  protocolError := func() {
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
  }

  // Check Stream ID is odd.
  if frame.StreamID&1 == 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be odd.\n",
      frame.StreamID)
    protocolError()
    return
  }

  // Check Stream ID is the right number.
  if frame.StreamID != conn.nextClientStreamID+2 && frame.StreamID != 1 &&
    conn.nextClientStreamID != 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be %d.\n",
      frame.StreamID, conn.nextClientStreamID+2)
    protocolError()
    return
  }

  // Check Stream ID is not too large.
  if frame.StreamID > MAX_STREAM_ID {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which is too large.\n",
      frame.StreamID)
    protocolError()
    return
  }

  // Stream ID is fine.

  // Create and start new stream.
  conn.RUnlock()
  conn.Lock()
  input := make(chan []byte)
  conn.streamInputs[frame.StreamID] = input
  if frame.Flags&FLAG_FIN != 0 {
    close(input)
  }
  conn.streams[frame.StreamID] = conn.newStream(frame, input, conn.streamOutputs[frame.Priority])
  conn.Unlock()
  conn.RLock()

  go func() { conn.streams[frame.StreamID].run() }()

  return
}

func (conn *connection) handleDataFrame(frame *DataFrame) {
  conn.RLock()
  defer func() { conn.RUnlock() }()

  // Check Stream ID is odd.
  if frame.StreamID&1 == 0 {
    log.Printf("Error: Received DATA with Stream ID %d, which should be odd.\n",
      frame.StreamID)
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
    return
  }

  // Check stream is open.
  if frame.StreamID != conn.nextClientStreamID+2 && frame.StreamID != 1 &&
    conn.nextClientStreamID != 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be %d.\n",
      frame.StreamID, conn.nextClientStreamID+2)
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
    return
  }

  // Stream ID is fine.

  // Send data to stream.
  conn.streamInputs[frame.StreamID] <- frame.Data

  // Handle flags.
  if frame.Flags&FLAG_FIN != 0 {
    stream := conn.streams[frame.StreamID]
    stream.Lock()
    stream.state = STATE_HALF_CLOSED_THERE
    close(conn.streamInputs[frame.StreamID])
    stream.Unlock()
  }

  return
}

func (conn *connection) readFrames() {
  if d := conn.server.ReadTimeout; d != 0 {
    conn.conn.SetReadDeadline(time.Now().Add(d))
  }
  if d := conn.server.WriteTimeout; d != 0 {
    defer func() {
      conn.conn.SetWriteDeadline(time.Now().Add(d))
    }()
  }

  for {
    frame, err := ReadFrame(conn.buf)
    if err != nil {
      // TODO: handle error
      panic(err)
    }
    err = frame.ReadHeaders(conn.decompressor)
    if err != nil {
      panic(err)
    }

    if DebugMode {
      fmt.Println("Received Frame:")
      fmt.Println(frame)
    }

  FrameHandling:
    switch frame := frame.(type) {
    default:
      panic(fmt.Sprintf("unexpected frame type %T", frame))

    /*** COMPLETE! ***/
    case *SynStreamFrame:
      conn.handleSynStream(frame)

    case *SynReplyFrame:
      log.Println("Got SYN_REPLY")

    case *RstStreamFrame:
      log.Printf("Received RST_STREAM on stream %d with status %q.\n", frame.StreamID,
        StatusCodeText(int(frame.StatusCode)))

      /*** COMPLETE! ***/
    case *SettingsFrame:
      if conn.receivedSettings == nil {
        conn.receivedSettings = frame.Settings
      } else {
        for _, new := range frame.Settings {
          for i, old := range conn.receivedSettings {
            if new.ID == old.ID {
              conn.receivedSettings[i] = new
            }
          }
          conn.receivedSettings = append(conn.receivedSettings, new)
        }
      }
      // TODO: Perhaps add some handling by the server here?

    /*** COMPLETE! ***/
    case *PingFrame:
      // Check Ping ID is odd.
      if frame.PingID&1 == 0 {
        log.Printf("Error: Received PING with Stream ID %d, which should be odd.\n", frame.PingID)
        reply := new(RstStreamFrame)
        reply.Version = SPDY_VERSION
        reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
        conn.WriteFrame(reply)
        break FrameHandling
      }
      log.Println("Received PING. Replying...")
      conn.WriteFrame(frame)

    case *GoawayFrame:
      // Check version.
      if frame.Version != uint16(conn.version) {
        log.Printf("Warning: Received frame with SPDY version %d on connection with version %d.\n",
          frame.Version, conn.version)
        if frame.Version > SPDY_VERSION {
          log.Printf("Error: Received frame with SPDY version %d, which is not supported.\n",
            frame.Version)
          reply := new(RstStreamFrame)
          reply.Version = SPDY_VERSION
          reply.StatusCode = RST_STREAM_UNSUPPORTED_VERSION
          conn.WriteFrame(reply)
          break FrameHandling
        }
      }

      // TODO: inform push streams that they haven't been processed if
      // the last good stream ID is less than their ID.

      conn.Lock()
      conn.goaway = true
      conn.Unlock()

    case *HeadersFrame:
      log.Println("Got HEADERS")

    case *WindowUpdateFrame:
      log.Println("Got WINDOW_UPDATE")

    case *CredentialFrame:
      log.Println("Got CREDENTIAL")

      /*** COMPLETE! ***/
    case *DataFrame:
      conn.handleDataFrame(frame)
    }
  }
}

func (conn *connection) serve() {
  defer func() {
    if err := recover(); err != nil {
      const size = 4096
      buf := make([]byte, size)
      buf = buf[:runtime.Stack(buf, false)]
      log.Printf("spdy: panic serving %v: %v\n%s", conn.remoteAddr, err, buf)
    }
  }()

  go func() { conn.send() }()
  if conn.server.GlobalSettings != nil {
    settings := new(SettingsFrame)
    settings.Version = uint16(conn.version)
    settings.Settings = conn.server.GlobalSettings
    conn.streamOutputs[3] <- settings
  }
  conn.readFrames()
}

func acceptDefaultSPDYv2(srv *http.Server, tlsConn *tls.Conn, _ http.Handler) {
  server := new(Server)
  server.TLSConfig = srv.TLSConfig
  acceptSPDYv2(server, tlsConn, nil)
}

func acceptSPDYv2(server *Server, tlsConn *tls.Conn, _ http.Handler) {
  conn := newConn(tlsConn)
  conn.server = server
  conn.tlsConfig = server.TLSConfig
  conn.version = 2

  conn.serve()
}

func acceptDefaultSPDYv3(srv *http.Server, tlsConn *tls.Conn, _ http.Handler) {
  server := new(Server)
  server.TLSConfig = srv.TLSConfig
  acceptSPDYv3(server, tlsConn, nil)
}

func acceptSPDYv3(server *Server, tlsConn *tls.Conn, _ http.Handler) {
  conn := newConn(tlsConn)
  conn.server = server
  conn.tlsConfig = server.TLSConfig
  conn.version = 3

  conn.serve()
}

func newConn(tlsConn *tls.Conn) *connection {
  conn := new(connection)
  conn.remoteAddr = tlsConn.RemoteAddr().String()
  conn.conn = tlsConn
  conn.buf = bufio.NewReader(tlsConn)
  conn.tlsState = new(tls.ConnectionState)
  *conn.tlsState = tlsConn.ConnectionState()
  conn.compressor = new(Compressor)
  conn.decompressor = new(Decompressor)
  conn.streams = make(map[uint32]*stream)
  conn.streamInputs = make(map[uint32]chan<- []byte)
  conn.streamOutputs = [8]chan Frame{}
  conn.streamOutputs[0] = make(chan Frame)
  conn.streamOutputs[1] = make(chan Frame)
  conn.streamOutputs[2] = make(chan Frame)
  conn.streamOutputs[3] = make(chan Frame)
  conn.streamOutputs[4] = make(chan Frame)
  conn.streamOutputs[5] = make(chan Frame)
  conn.streamOutputs[6] = make(chan Frame)
  conn.streamOutputs[7] = make(chan Frame)

  return conn
}
<commit_msg>Minor formatting change<commit_after>package spdy

import (
  "bufio"
  "crypto/tls"
  "fmt"
  "log"
  "net/http"
  "net/url"
  "runtime"
  "sync"
  "time"
)

type connection struct {
  sync.RWMutex
  remoteAddr          string // network address of remote side
  server              *Server
  conn                *tls.Conn
  buf                 *bufio.Reader
  tlsState            *tls.ConnectionState
  tlsConfig           *tls.Config
  streams             map[uint32]*stream
  streamInputs        map[uint32]chan<- []byte
  streamOutputs       [8]chan Frame
  compressor          *Compressor
  decompressor        *Decompressor
  receivedSettings    []*Setting
  nextServerStreamID  uint32 // even
  nextClientStreamID  uint32 // odd
  goaway              bool
  version             int
  numInvalidStreamIDs int
}

func (conn *connection) send() {
  for {
    frame := conn.selectFrameToSend()
    err := frame.WriteHeaders(conn.compressor)
    if err != nil {
      panic(err)
    }
    err = frame.WriteTo(conn.conn)
    if err != nil {
      panic(err)
    }
  }
}

func (conn *connection) selectFrameToSend() (frame Frame) {
  // Try in priority order first.
  for i := 0; i < 8; i++ {
    select {
    case frame = <-conn.streamOutputs[i]:
      return frame
    default:
    }
  }

  // Wait for any frame.
  select {
  case frame = <-conn.streamOutputs[0]:
    return frame
  case frame = <-conn.streamOutputs[1]:
    return frame
  case frame = <-conn.streamOutputs[2]:
    return frame
  case frame = <-conn.streamOutputs[3]:
    return frame
  case frame = <-conn.streamOutputs[4]:
    return frame
  case frame = <-conn.streamOutputs[5]:
    return frame
  case frame = <-conn.streamOutputs[6]:
    return frame
  case frame = <-conn.streamOutputs[7]:
    return frame
  }

  panic("Unreachable")
}

func (conn *connection) newStream(frame *SynStreamFrame, input <-chan []byte,
  output chan<- Frame) *stream {

  stream := new(stream)
  stream.conn = conn
  stream.streamID = frame.StreamID
  stream.state = STATE_OPEN
  if frame.Flags&FLAG_FIN != 0 {
    stream.state = STATE_HALF_CLOSED_THERE
  }
  stream.priority = frame.Priority
  stream.input = input
  stream.output = output
  stream.handler = DefaultServeMux
  stream.certificates = make([]Certificate, 1)
  stream.headers = make(Header)
  stream.settings = make([]*Setting, 1)
  stream.unidirectional = frame.Flags&FLAG_UNIDIRECTIONAL != 0
  stream.version = conn.version
  stream.contentLength = -1

  headers := frame.Headers
  rawUrl := headers.Get(":scheme") + "://" + headers.Get(":host") + headers.Get(":path")
  url, err := url.Parse(rawUrl)
  if err != nil {
    panic(err)
  }
  major, minor, ok := http.ParseHTTPVersion(headers.Get(":version"))
  if !ok {
    panic("Invalid HTTP version: " + headers.Get(":version"))
  }
  stream.request = &Request{
    Method:     headers.Get(":method"),
    URL:        url,
    Proto:      headers.Get(":version"),
    ProtoMajor: major,
    ProtoMinor: minor,
    Header:     headers,
    Host:       url.Host,
    RequestURI: url.Path,
    TLS:        conn.tlsState,
  }

  return stream
}

func (conn *connection) WriteFrame(frame Frame) error {
  return nil
}

func (conn *connection) handleSynStream(frame *SynStreamFrame) {
  conn.RLock()
  defer func() { conn.RUnlock() }()

  // Check stream creation is allowed.
  if conn.goaway {
    return
  }

  // Check version.
  if frame.Version != uint16(conn.version) {

    // This is currently strict; only one version allowed per connection.
    log.Printf("Error: Received frame with SPDY version %d on connection with version %d.\n",
      frame.Version, conn.version)
    if frame.Version > SPDY_VERSION {
      log.Printf("Error: Received frame with SPDY version %d, which is not supported.\n",
        frame.Version)
    }
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_UNSUPPORTED_VERSION
    conn.WriteFrame(reply)
    return
  }

  protocolError := func() {
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
  }

  // Check Stream ID is odd.
  if frame.StreamID&1 == 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be odd.\n",
      frame.StreamID)
    protocolError()
    return
  }

  // Check Stream ID is the right number.
  if frame.StreamID != conn.nextClientStreamID+2 && frame.StreamID != 1 &&
    conn.nextClientStreamID != 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be %d.\n",
      frame.StreamID, conn.nextClientStreamID+2)
    protocolError()
    return
  }

  // Check Stream ID is not too large.
  if frame.StreamID > MAX_STREAM_ID {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which is too large.\n",
      frame.StreamID)
    protocolError()
    return
  }

  // Stream ID is fine.

  // Create and start new stream.
  conn.RUnlock()
  conn.Lock()
  input := make(chan []byte)
  conn.streamInputs[frame.StreamID] = input
  if frame.Flags&FLAG_FIN != 0 {
    close(input)
  }
  conn.streams[frame.StreamID] = conn.newStream(frame, input, conn.streamOutputs[frame.Priority])
  conn.Unlock()
  conn.RLock()

  go func() { conn.streams[frame.StreamID].run() }()

  return
}

func (conn *connection) handleDataFrame(frame *DataFrame) {
  conn.RLock()
  defer func() { conn.RUnlock() }()

  // Check Stream ID is odd.
  if frame.StreamID&1 == 0 {
    log.Printf("Error: Received DATA with Stream ID %d, which should be odd.\n",
      frame.StreamID)
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
    return
  }

  // Check stream is open.
  if frame.StreamID != conn.nextClientStreamID+2 && frame.StreamID != 1 &&
    conn.nextClientStreamID != 0 {
    log.Printf("Error: Received SYN_STREAM with Stream ID %d, which should be %d.\n",
      frame.StreamID, conn.nextClientStreamID+2)
    reply := new(RstStreamFrame)
    reply.Version = SPDY_VERSION
    reply.StreamID = frame.StreamID
    reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
    conn.WriteFrame(reply)
    return
  }

  // Stream ID is fine.

  // Send data to stream.
  conn.streamInputs[frame.StreamID] <- frame.Data

  // Handle flags.
  if frame.Flags&FLAG_FIN != 0 {
    stream := conn.streams[frame.StreamID]
    stream.Lock()
    stream.state = STATE_HALF_CLOSED_THERE
    close(conn.streamInputs[frame.StreamID])
    stream.Unlock()
  }

  return
}

func (conn *connection) readFrames() {
  if d := conn.server.ReadTimeout; d != 0 {
    conn.conn.SetReadDeadline(time.Now().Add(d))
  }
  if d := conn.server.WriteTimeout; d != 0 {
    defer func() {
      conn.conn.SetWriteDeadline(time.Now().Add(d))
    }()
  }

  for {
    frame, err := ReadFrame(conn.buf)
    if err != nil {
      // TODO: handle error
      panic(err)
    }
    err = frame.ReadHeaders(conn.decompressor)
    if err != nil {
      panic(err)
    }

    if DebugMode {
      fmt.Println("Received Frame:")
      fmt.Println(frame)
    }

  FrameHandling:
    switch frame := frame.(type) {
    default:
      panic(fmt.Sprintf("unexpected frame type %T", frame))

    /*** COMPLETE! ***/
    case *SynStreamFrame:
      conn.handleSynStream(frame)

    case *SynReplyFrame:
      log.Println("Got SYN_REPLY")

    case *RstStreamFrame:
      code := StatusCodeText(int(frame.StatusCode))
      log.Printf("Received RST_STREAM on stream %d with status %q.\n", frame.StreamID, code)

    /*** COMPLETE! ***/
    case *SettingsFrame:
      if conn.receivedSettings == nil {
        conn.receivedSettings = frame.Settings
      } else {
        for _, new := range frame.Settings {
          for i, old := range conn.receivedSettings {
            if new.ID == old.ID {
              conn.receivedSettings[i] = new
            }
          }
          conn.receivedSettings = append(conn.receivedSettings, new)
        }
      }
      // TODO: Perhaps add some handling by the server here?

    /*** COMPLETE! ***/
    case *PingFrame:
      // Check Ping ID is odd.
      if frame.PingID&1 == 0 {
        log.Printf("Error: Received PING with Stream ID %d, which should be odd.\n", frame.PingID)
        reply := new(RstStreamFrame)
        reply.Version = SPDY_VERSION
        reply.StatusCode = RST_STREAM_PROTOCOL_ERROR
        conn.WriteFrame(reply)
        break FrameHandling
      }
      log.Println("Received PING. Replying...")
      conn.WriteFrame(frame)

    case *GoawayFrame:
      // Check version.
      if frame.Version != uint16(conn.version) {
        log.Printf("Warning: Received frame with SPDY version %d on connection with version %d.\n",
          frame.Version, conn.version)
        if frame.Version > SPDY_VERSION {
          log.Printf("Error: Received frame with SPDY version %d, which is not supported.\n",
            frame.Version)
          reply := new(RstStreamFrame)
          reply.Version = SPDY_VERSION
          reply.StatusCode = RST_STREAM_UNSUPPORTED_VERSION
          conn.WriteFrame(reply)
          break FrameHandling
        }
      }

      // TODO: inform push streams that they haven't been processed if
      // the last good stream ID is less than their ID.

      conn.Lock()
      conn.goaway = true
      conn.Unlock()

    case *HeadersFrame:
      log.Println("Got HEADERS")

    case *WindowUpdateFrame:
      log.Println("Got WINDOW_UPDATE")

    case *CredentialFrame:
      log.Println("Got CREDENTIAL")

      /*** COMPLETE! ***/
    case *DataFrame:
      conn.handleDataFrame(frame)
    }
  }
}

func (conn *connection) serve() {
  defer func() {
    if err := recover(); err != nil {
      const size = 4096
      buf := make([]byte, size)
      buf = buf[:runtime.Stack(buf, false)]
      log.Printf("spdy: panic serving %v: %v\n%s", conn.remoteAddr, err, buf)
    }
  }()

  go func() { conn.send() }()
  if conn.server.GlobalSettings != nil {
    settings := new(SettingsFrame)
    settings.Version = uint16(conn.version)
    settings.Settings = conn.server.GlobalSettings
    conn.streamOutputs[3] <- settings
  }
  conn.readFrames()
}

func acceptDefaultSPDYv2(srv *http.Server, tlsConn *tls.Conn, _ http.Handler) {
  server := new(Server)
  server.TLSConfig = srv.TLSConfig
  acceptSPDYv2(server, tlsConn, nil)
}

func acceptSPDYv2(server *Server, tlsConn *tls.Conn, _ http.Handler) {
  conn := newConn(tlsConn)
  conn.server = server
  conn.tlsConfig = server.TLSConfig
  conn.version = 2

  conn.serve()
}

func acceptDefaultSPDYv3(srv *http.Server, tlsConn *tls.Conn, _ http.Handler) {
  server := new(Server)
  server.TLSConfig = srv.TLSConfig
  acceptSPDYv3(server, tlsConn, nil)
}

func acceptSPDYv3(server *Server, tlsConn *tls.Conn, _ http.Handler) {
  conn := newConn(tlsConn)
  conn.server = server
  conn.tlsConfig = server.TLSConfig
  conn.version = 3

  conn.serve()
}

func newConn(tlsConn *tls.Conn) *connection {
  conn := new(connection)
  conn.remoteAddr = tlsConn.RemoteAddr().String()
  conn.conn = tlsConn
  conn.buf = bufio.NewReader(tlsConn)
  conn.tlsState = new(tls.ConnectionState)
  *conn.tlsState = tlsConn.ConnectionState()
  conn.compressor = new(Compressor)
  conn.decompressor = new(Decompressor)
  conn.streams = make(map[uint32]*stream)
  conn.streamInputs = make(map[uint32]chan<- []byte)
  conn.streamOutputs = [8]chan Frame{}
  conn.streamOutputs[0] = make(chan Frame)
  conn.streamOutputs[1] = make(chan Frame)
  conn.streamOutputs[2] = make(chan Frame)
  conn.streamOutputs[3] = make(chan Frame)
  conn.streamOutputs[4] = make(chan Frame)
  conn.streamOutputs[5] = make(chan Frame)
  conn.streamOutputs[6] = make(chan Frame)
  conn.streamOutputs[7] = make(chan Frame)

  return conn
}
<|endoftext|>


<commit_before>package tape

import (
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/labstack/echo"
)

// Exce exce
var Exce = new(Exception)

// Exception throw exception
type Exception struct{}

// OK throw exception if !ok
func (e Exception) OK(ok bool, message interface{}) {
	if !ok {
		panic(message)
	}
}

// Err throw exception if err!=nil
func (e Exception) Err(err error, message interface{}) {
	if err != nil {
		if message == "" {
			switch {
			case strings.HasPrefix(err.Error(), "Error 1046"):
				message = "查询表名错误"
			case strings.HasPrefix(err.Error(), "Error 1049"):
				message = "查询库名错误"
			case strings.HasPrefix(err.Error(), "Error 1054"):
				message = "查询列名错误"
			case strings.HasPrefix(err.Error(), "Error 1062"):
				message = "写入数据重复"
			case strings.HasPrefix(err.Error(), "Error 1064"):
				message = "查询语句错误"
			case strings.HasPrefix(err.Error(), "sql:"):
				message = "查询数据失败"
			case strings.HasPrefix(err.Error(), "code=400,message=Unmarshal type error"):
				message = "数据类型错误"
			default:
				message = err.Error()
			}
		}
		fmt.Println(reflect.TypeOf(err), err.Error(), message)
		panic(message)
	}
}

// Catch throw exception if recover err
func (e Exception) Catch(ctx echo.Context) func() {
	return func() {
		if r := recover(); r != nil {
			ctx.JSON(http.StatusOK, Hash{
				STATUS:  FAIL,
				MESSAGE: r,
			})
		}
	}
}
<commit_msg>add exec<commit_after>package tape

import (
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/labstack/echo"
)

// Exce exce
var Exce = new(Exception)

// Exception throw exception
type Exception struct{}

// OK throw exception if !ok
func (e Exception) OK(ok bool, message interface{}) {
	if !ok {
		panic(message)
	}
}

// Err throw exception if err!=nil
func (e Exception) Err(err error, message interface{}) {
	if err != nil {
		if message == "" {
			switch {
			case strings.HasPrefix(err.Error(), "Error 1046"):
				message = "查询表名错误"
			case strings.HasPrefix(err.Error(), "Error 1049"):
				message = "查询库名错误"
			case strings.HasPrefix(err.Error(), "Error 1054"):
				message = "查询列名错误"
			case strings.HasPrefix(err.Error(), "Error 1062"):
				message = "写入数据重复"
			case strings.HasPrefix(err.Error(), "Error 1064"):
				message = "查询语句错误"
			case strings.HasPrefix(err.Error(), "sql:"):
				message = "查询数据失败"
			case strings.HasPrefix(err.Error(), "code=400,message=Unmarshal type error"):
				message = "数据类型错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unavailable desc"):
				message = "连接服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unknown desc"):
				message = "调用服务错误"
			case strings.HasPrefix(err.Error(), "rpc error: code = Unimplemented desc"):
				message = "解析服务错误"
			default:
				message = err.Error()
			}
		}
		fmt.Println(reflect.TypeOf(err), err.Error(), message)
		panic(message)
	}
}

// Catch throw exception if recover err
func (e Exception) Catch(ctx echo.Context) func() {
	return func() {
		if r := recover(); r != nil {
			ctx.JSON(http.StatusOK, Hash{
				STATUS:  FAIL,
				MESSAGE: r,
			})
		}
	}
}
<|endoftext|>


<commit_before>package goconsularis

import (
	consul "github.com/armon/consul-api"
	log "github.com/cihub/seelog"
	"strconv"
	"time"
)

//Register service and keep it registered.
func RegisterService(name string, port int, ttl int) {
	go registerService(name, port, ttl)
}

func registerCheckTtl(name string, ttl int, agent *consul.Agent) {
	reg := &consul.AgentCheckRegistration{
		Name: name,
	}
	reg.TTL = strconv.Itoa(ttl) + "s"

	if err := agent.CheckRegister(reg); err != nil {
		log.Error("Failed to register check: ", err)
	}
}

//continue to register a service preferably ran in a go routine.
func registerService(name string, port int, ttl int) {

	reportInterval := make(chan bool, 1)
	go func() {
		for {
			time.Sleep(time.Duration(ttl) / 2 * time.Second)
			reportInterval <- true
		}
	}()

	client, err := consul.NewClient(consul.DefaultConfig())
	if nil != err {
		log.Error("Failed to get consul client")
	}
	agent := client.Agent()

	serviceRegister(name, port, ttl, agent)
	for {
		select {
		case <-reportInterval: //report registration
			{
				servicePassing(name, agent)

			}
		}
	}

}

func servicePassing(name string, agent *consul.Agent) {
	agent.Pass("service:"+name, "Service up and ready!")
}

func serviceRegister(name string, port int, ttl int, agent *consul.Agent) {
	reg := &consul.AgentServiceRegistration{
		Name: name,
		Port: port,
		Check: &consul.AgentServiceCheck{
			TTL: strconv.Itoa(ttl) + "s",
		},
	}
	if err := agent.ServiceRegister(reg); err != nil {
		log.Error("err: ", err)
	}
}
<commit_msg>fix typo<commit_after>package goconsularis

import (
	consul "github.com/armon/consul-api"
	log "github.com/cihub/seelog"
	"strconv"
	"time"
)

//Register service and keep it registered.
func RegisterService(name string, port int, ttl int) {
	go registerService(name, port, ttl)
}

func registerCheckTtl(name string, ttl int, agent *consul.Agent) {
	reg := &consul.AgentCheckRegistration{
		Name: name,
	}
	reg.TTL = strconv.Itoa(ttl) + "s"

	if err := agent.CheckRegister(reg); err != nil {
		log.Error("Failed to register check: ", err)
	}
}

//continue to register a service preferably ran in a go routine.
func registerService(name string, port int, ttl int) {

	reportInterval := make(chan bool, 1)
	go func() {
		for {
			time.Sleep(time.Duration(ttl) / 2 * time.Second)
			reportInterval <- true
		}
	}()

	client, err := consul.NewClient(consul.DefaultConfig())
	if nil != err {
		log.Error("Failed to get consul client")
	}
	agent := client.Agent()

	serviceRegister(name, port, ttl, agent)
	for {
		select {
		case <-reportInterval: //report registration
			{
				servicePassing(name, agent)

			}
		}
	}

}

func servicePassing(name string, agent *consul.Agent) {
	agent.PassTTL("service:"+name, "Service up and ready!")
}

func serviceRegister(name string, port int, ttl int, agent *consul.Agent) {
	reg := &consul.AgentServiceRegistration{
		Name: name,
		Port: port,
		Check: &consul.AgentServiceCheck{
			TTL: strconv.Itoa(ttl) + "s",
		},
	}
	if err := agent.ServiceRegister(reg); err != nil {
		log.Error("err: ", err)
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 @ z3q.net.
 * name : base_c
 * author : jarryliu
 * date : -- :
 * description :
 * history :
 */
package restapi

import (
	"github.com/jsix/gof"
	"go2o/src/app/cache"
	"go2o/src/app/util"
	"go2o/src/core/domain/interface/merchant"
	"gopkg.in/labstack/echo.v1"
	"net/http"
	"strconv"
)

// 获取存储
func GetStorage() gof.Storage {
	return sto
}

// 获取传入的商户接口编号和密钥
func getUserInfo(ctx *echo.Context) (string, string) {
	r := ctx.Request()
	apiId := r.FormValue("merchant_id")
	apiSecret := r.FormValue("secret")
	if len(apiId) == 0 {
		apiId = r.URL.Query().Get("merchant_id")
	}

    //todo: 兼容partner_id  ,将删除
	if len(apiId) == 0{
		apiId = r.FormValue("partner_id")
		if len(apiId) == 0{
			apiId = r.URL.Query().Get("partner_id")
		}
	}

	if len(apiSecret) == 0 {
		apiSecret = r.URL.Query().Get("secret")
	}
	return apiId, apiSecret
}

// 检查是否有权限调用接口(商户)
func chkMerchantApiSecret(ctx *echo.Context) bool {
	i, s := getUserInfo(ctx)
	ok, merchantId := CheckApiPermission(i, s)
	if ok {
		ctx.Set("merchant_id", merchantId)
	}
	return ok
}

// 检查会员令牌信息
func checkMemberToken(ctx *echo.Context) bool {
	r := ctx.Request()
	sto := gof.CurrentApp.Storage()
	memberId, _ := strconv.Atoi(r.FormValue("member_id"))
	token := r.FormValue("member_token")

	if util.CompareMemberApiToken(sto, memberId, token) {
		ctx.Set("member_id", memberId)
		return true
	}
	return false
}

// 获取商户编号
func getMerchantId(ctx *echo.Context) int {
	return ctx.Get("merchant_id").(int)
}

// 获取会员编号
func GetMemberId(ctx *echo.Context) int {
	return ctx.Get("member_id").(int)
}

func ApiTest(ctx *echo.Context) error {
	return ctx.String(http.StatusOK, "It's working!")
}

// 检查是否有权限
func CheckApiPermission(apiId string, secret string) (ok bool, merchantId int) {
	if len(apiId) != 0 && len(secret) != 0 {
		var merchantId int = cache.GetMerchantIdByApiId(apiId)
		var apiInfo *merchant.ApiInfo = cache.GetMerchantApiInfo(merchantId)
		if apiInfo != nil {
			return apiInfo.ApiSecret == secret, merchantId
		}
	}
	return false, merchantId
}
<commit_msg>fmt<commit_after>/**
 * Copyright 2015 @ z3q.net.
 * name : base_c
 * author : jarryliu
 * date : -- :
 * description :
 * history :
 */
package restapi

import (
	"github.com/jsix/gof"
	"go2o/src/app/cache"
	"go2o/src/app/util"
	"go2o/src/core/domain/interface/merchant"
	"gopkg.in/labstack/echo.v1"
	"net/http"
	"strconv"
)

// 获取存储
func GetStorage() gof.Storage {
	return sto
}

// 获取传入的商户接口编号和密钥
func getUserInfo(ctx *echo.Context) (string, string) {
	r := ctx.Request()
	apiId := r.FormValue("merchant_id")
	apiSecret := r.FormValue("secret")
	if len(apiId) == 0 {
		apiId = r.URL.Query().Get("merchant_id")
	}

	//todo: 兼容partner_id  ,将删除
	if len(apiId) == 0 {
		apiId = r.FormValue("partner_id")
		if len(apiId) == 0 {
			apiId = r.URL.Query().Get("partner_id")
		}
	}

	if len(apiSecret) == 0 {
		apiSecret = r.URL.Query().Get("secret")
	}
	return apiId, apiSecret
}

// 检查是否有权限调用接口(商户)
func chkMerchantApiSecret(ctx *echo.Context) bool {
	i, s := getUserInfo(ctx)
	ok, merchantId := CheckApiPermission(i, s)
	if ok {
		ctx.Set("merchant_id", merchantId)
	}
	return ok
}

// 检查会员令牌信息
func checkMemberToken(ctx *echo.Context) bool {
	r := ctx.Request()
	sto := gof.CurrentApp.Storage()
	memberId, _ := strconv.Atoi(r.FormValue("member_id"))
	token := r.FormValue("member_token")

	if util.CompareMemberApiToken(sto, memberId, token) {
		ctx.Set("member_id", memberId)
		return true
	}
	return false
}

// 获取商户编号
func getMerchantId(ctx *echo.Context) int {
	return ctx.Get("merchant_id").(int)
}

// 获取会员编号
func GetMemberId(ctx *echo.Context) int {
	return ctx.Get("member_id").(int)
}

func ApiTest(ctx *echo.Context) error {
	return ctx.String(http.StatusOK, "It's working!")
}

// 检查是否有权限
func CheckApiPermission(apiId string, secret string) (ok bool, merchantId int) {
	if len(apiId) != 0 && len(secret) != 0 {
		var merchantId int = cache.GetMerchantIdByApiId(apiId)
		var apiInfo *merchant.ApiInfo = cache.GetMerchantApiInfo(merchantId)
		if apiInfo != nil {
			return apiInfo.ApiSecret == secret, merchantId
		}
	}
	return false, merchantId
}
<|endoftext|>


<commit_before>package sequencer

import (
	"testing"

	"gitlab.com/gomidi/midi/v2"
	"gitlab.com/gomidi/midi/v2/smf"
)

func TestAddEvents(t *testing.T) {
	var s Song
	var sm smf.SMF
	ticks := smf.MetricTicks(960)

	sm.TimeFormat = ticks
	var tr0, tr1 smf.Track

	qn := ticks.Ticks4th()

	var m = smf.MetaMeter
	tr0.Add(0, smf.MetaTrackSequenceName("testmkbars"))

	// bar 0
	tr0.Add(0, m(3, 4))
	// bar 1
	tr0.Add(qn*3, midi.NoteOn(1, 60, 110))
	// bar 2
	tr0.Add(qn*2, m(4, 4))
	tr0.Add(qn*2, midi.NoteOff(1, 60))
	// bar 2 rest & bar 3
	tr0.Add(qn*6, m(3, 4))
	// bar 4 & 5
	tr0.Close(qn * 6)
	sm.Add(tr0)
	// 3/4 3/4 4/4 4/4 3/4 3/4

	// bar 0
	tr1.Add(qn, midi.NoteOn(2, 60, 120))
	tr1.Add(qn, midi.ControlChange(1, 22, 105))
	// bar 1
	// bar 2
	tr1.Add(qn*4, midi.NoteOff(2, 60))
	tr1.Close(0)
	sm.Add(tr1)

	si := smfimport{&s, sm}

	si.mkBars()
	si.addEvents()

	if len(s.TrackNames) != 2 {
		t.Errorf("len(s.Tracks) = %v // expected %v", len(s.TrackNames), 2)
	}

	bars := s.Bars()

	if len(bars) != 6 {
		t.Errorf("len(s.Bars()) = %v // expected %v", len(bars), 6)
	}

	if len(bars[0].Events) != 2 {
		t.Errorf("len(bars[0].Events) = %v // expected %v", len(bars[0].Events), 2)
	}

	got := bars[0].Events[0].Inspect()
	expected := `Event{TrackNo:1, Pos:8, Duration:40, Message: NoteOn channel: 2 key: 60 velocity: 120, absTicks: 960}`

	if got != expected {
		t.Errorf("bars[0].Events[0].Inspect() = %q // expected %q", got, expected)
	}

	got = bars[0].Events[1].Inspect()
	expected = `Event{TrackNo:1, Pos:16, Duration:0, Message: ControlChange channel: 1 controller: 22 value: 105, absTicks: 1920}`

	if got != expected {
		t.Errorf("bars[0].Events[1].Inspect() = %q // expected %q", got, expected)
	}

	if len(bars[1].Events) != 1 {
		t.Errorf("len(bars[1].Events) = %v // expected %v", len(bars[1].Events), 1)
	}

	got = bars[1].Events[0].Inspect()
	expected = `Event{TrackNo:0, Pos:0, Duration:32, Message: NoteOn channel: 1 key: 60 velocity: 110, absTicks: 2880}`

	if got != expected {
		t.Errorf("bars[1].Events[0].Inspect() = %q // expected %q", got, expected)
	}

	if len(bars[2].Events) != 0 {
		t.Errorf("len(bars[2].Events) = %v // expected %v", len(bars[2].Events), 0)
	}

}
<commit_msg>use sequencer.New<commit_after>package sequencer

import (
	"testing"

	"gitlab.com/gomidi/midi/v2"
	"gitlab.com/gomidi/midi/v2/smf"
)

func TestAddEvents(t *testing.T) {
	var s = New()
	var sm smf.SMF
	ticks := smf.MetricTicks(960)

	sm.TimeFormat = ticks
	var tr0, tr1 smf.Track

	qn := ticks.Ticks4th()

	var m = smf.MetaMeter
	tr0.Add(0, smf.MetaTrackSequenceName("testmkbars"))

	// bar 0
	tr0.Add(0, m(3, 4))
	// bar 1
	tr0.Add(qn*3, midi.NoteOn(1, 60, 110))
	// bar 2
	tr0.Add(qn*2, m(4, 4))
	tr0.Add(qn*2, midi.NoteOff(1, 60))
	// bar 2 rest & bar 3
	tr0.Add(qn*6, m(3, 4))
	// bar 4 & 5
	tr0.Close(qn * 6)
	sm.Add(tr0)
	// 3/4 3/4 4/4 4/4 3/4 3/4

	// bar 0
	tr1.Add(qn, midi.NoteOn(2, 60, 120))
	tr1.Add(qn, midi.ControlChange(1, 22, 105))
	// bar 1
	// bar 2
	tr1.Add(qn*4, midi.NoteOff(2, 60))
	tr1.Close(0)
	sm.Add(tr1)

	si := smfimport{s, sm}

	si.mkBars()
	si.addEvents()

	if len(s.TrackNames) != 2 {
		t.Errorf("len(s.Tracks) = %v // expected %v", len(s.TrackNames), 2)
	}

	bars := s.Bars()

	if len(bars) != 6 {
		t.Errorf("len(s.Bars()) = %v // expected %v", len(bars), 6)
	}

	if len(bars[0].Events) != 2 {
		t.Errorf("len(bars[0].Events) = %v // expected %v", len(bars[0].Events), 2)
	}

	got := bars[0].Events[0].Inspect()
	expected := `Event{TrackNo:1, Pos:8, Duration:40, Message: NoteOn channel: 2 key: 60 velocity: 120, absTicks: 960}`

	if got != expected {
		t.Errorf("bars[0].Events[0].Inspect() = %q // expected %q", got, expected)
	}

	got = bars[0].Events[1].Inspect()
	expected = `Event{TrackNo:1, Pos:16, Duration:0, Message: ControlChange channel: 1 controller: 22 value: 105, absTicks: 1920}`

	if got != expected {
		t.Errorf("bars[0].Events[1].Inspect() = %q // expected %q", got, expected)
	}

	if len(bars[1].Events) != 1 {
		t.Errorf("len(bars[1].Events) = %v // expected %v", len(bars[1].Events), 1)
	}

	got = bars[1].Events[0].Inspect()
	expected = `Event{TrackNo:0, Pos:0, Duration:32, Message: NoteOn channel: 1 key: 60 velocity: 110, absTicks: 2880}`

	if got != expected {
		t.Errorf("bars[1].Events[0].Inspect() = %q // expected %q", got, expected)
	}

	if len(bars[2].Events) != 0 {
		t.Errorf("len(bars[2].Events) = %v // expected %v", len(bars[2].Events), 0)
	}

}
<|endoftext|>


<commit_before>package mprabbitmq

import (
	"flag"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/michaelklishin/rabbit-hole"
)

var graphdef = map[string]mp.Graphs{
	"rabbitmq.queue": {
		Label: "RabbitMQ Queue",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "messages", Label: "Total", Diff: false},
			{Name: "ready", Label: "Ready", Diff: false},
			{Name: "unacknowledged", Label: "Unacknowledged", Diff: false},
		},
	},
	"rabbitmq.message": {
		Label: "RabbitMQ Message",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "publish", Label: "Publish", Diff: false},
		},
	},
}

// RabbitMQPlugin metrics
type RabbitMQPlugin struct {
	URI      string
	User     string
	Password string
	TempFile string
}

// FetchMetrics interface for mackerelplugin
func (r RabbitMQPlugin) FetchMetrics() (map[string]interface{}, error) {
	rmqc, err := rabbithole.NewClient(r.URI, r.User, r.Password)
	if err != nil {
		return nil, err
	}
	res, err := rmqc.Overview()
	if err != nil {
		return nil, err
	}

	return r.parseStats(*res)
}

func (r RabbitMQPlugin) parseStats(res rabbithole.Overview) (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	stat["messages"] = float64(res.QueueTotals.Messages)
	stat["ready"] = float64(res.QueueTotals.MessagesReady)
	stat["unacknowledged"] = float64(res.QueueTotals.MessagesUnacknowledged)
	stat["publish"] = float64(res.MessageStats.PublishDetails.Rate)

	return stat, nil

}

// GraphDefinition interface for mackerel plugin
func (r RabbitMQPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

// Do the plugin
func Do() {
	optURI := flag.String("uri", "http://localhost:15672", "URI")
	optUser := flag.String("user", "guest", "User")
	optPass := flag.String("password", "guest", "Password")
	flag.Parse()

	var rabbitmq RabbitMQPlugin

	rabbitmq.URI = *optURI
	rabbitmq.User = *optUser
	rabbitmq.Password = *optPass

	helper := mp.NewMackerelPlugin(rabbitmq)

	helper.Run()
}
<commit_msg>update mackerel-plugin-rabbitmq for setting password via environment variable.<commit_after>package mprabbitmq

import (
	"flag"
	"os"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
	"github.com/michaelklishin/rabbit-hole"
)

var graphdef = map[string]mp.Graphs{
	"rabbitmq.queue": {
		Label: "RabbitMQ Queue",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "messages", Label: "Total", Diff: false},
			{Name: "ready", Label: "Ready", Diff: false},
			{Name: "unacknowledged", Label: "Unacknowledged", Diff: false},
		},
	},
	"rabbitmq.message": {
		Label: "RabbitMQ Message",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "publish", Label: "Publish", Diff: false},
		},
	},
}

// RabbitMQPlugin metrics
type RabbitMQPlugin struct {
	URI      string
	User     string
	Password string
	TempFile string
}

// FetchMetrics interface for mackerelplugin
func (r RabbitMQPlugin) FetchMetrics() (map[string]interface{}, error) {
	rmqc, err := rabbithole.NewClient(r.URI, r.User, r.Password)
	if err != nil {
		return nil, err
	}
	res, err := rmqc.Overview()
	if err != nil {
		return nil, err
	}

	return r.parseStats(*res)
}

func (r RabbitMQPlugin) parseStats(res rabbithole.Overview) (map[string]interface{}, error) {
	stat := make(map[string]interface{})

	stat["messages"] = float64(res.QueueTotals.Messages)
	stat["ready"] = float64(res.QueueTotals.MessagesReady)
	stat["unacknowledged"] = float64(res.QueueTotals.MessagesUnacknowledged)
	stat["publish"] = float64(res.MessageStats.PublishDetails.Rate)

	return stat, nil

}

// GraphDefinition interface for mackerel plugin
func (r RabbitMQPlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

// Do the plugin
func Do() {
	defaultPass := "guest"
	if v, ok := os.LookupEnv("RABBITMQ_PASSWORD"); ok {
		defaultPass = v
	}

	optURI := flag.String("uri", "http://localhost:15672", "URI")
	optUser := flag.String("user", "guest", "User")
	optPass := flag.String("password", defaultPass, "Password")
	flag.Parse()

	var rabbitmq RabbitMQPlugin

	rabbitmq.URI = *optURI
	rabbitmq.User = *optUser
	rabbitmq.Password = *optPass

	helper := mp.NewMackerelPlugin(rabbitmq)

	helper.Run()
}
<|endoftext|>


<commit_before>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package util

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
)

type Reader struct {
	buf *bufio.Reader
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{buf: bufio.NewReader(rd)}
}

func (r *Reader) Discard(n int) (discarded int, err error) {
	return r.buf.Discard(n)
}

// Read reads data into p.
// It returns the number of bytes read into p.
// The bytes are taken from at most one Read on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (r *Reader) Read(p []byte) (n int, err error) {
	return r.buf.Read(p)
}

// ReadAll reads from Reader until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from Reader until EOF, it does not treat an EOF from Read
// as an error to be reported.
func (r *Reader) ReadAll() ([]byte, error) {
	return ioutil.ReadAll(r.buf)
}

// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (r *Reader) ReadByte() (byte, error) {
	return r.buf.ReadByte()
}

// ReadSeveralBytes reads n bytes.
func (r *Reader) ReadSeveralBytes(n int) ([]byte, error) {
	if n == 0 {
		return nil, nil
	}

	peeked, err := r.buf.Peek(n)
	if err != nil {
		return nil, err
	}

	if _, err := r.buf.Discard(n); err != nil {
		return nil, err
	}

	return peeked, nil
}

// ReadTillDelim reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and NOT including the delimiter.
// If ReadTillDelim encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillDelim returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelim(delim byte) ([]byte, error) {
	read, err := r.buf.ReadBytes(delim)
	if err != nil || read == nil || len(read) == 0 {
		return read, err
	}
	err = r.buf.UnreadByte()
	return read[:len(read)-1], err
}

// ReadTillDelims reads until the first occurrence of delims in the input,
// returning a slice containing the data up to and NOT including the delimiters.
// If ReadTillDelims encounters an error before finding a delimiters,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillAndWithDelims returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelims(delims []byte) ([]byte, error) {
	if len(delims) == 0 {
		return r.ReadAll()
	}
	if len(delims) == 1 {
		return r.ReadTillDelim(delims[0])
	}

	buf := make([]byte, 0)
	for {
		read, err := r.ReadTillDelim(delims[0])
		if err != nil {
			return buf, err
		}
		buf = append(buf, read...)

		peeked, err := r.buf.Peek(len(delims))
		if err != nil {
			return buf, err
		}

		if bytes.Equal(peeked, delims) {
			break
		}

		b, err := r.ReadByte()
		if err != nil {
			return buf, err
		}
		buf = append(buf, b)
	}

	return buf, nil
}

// Reset discards any buffered data, resets all state,
// and switches the buffered reader to read from r.
func (r *Reader) Reset(rd io.Reader) {
	r.buf.Reset(rd)
}
<commit_msg>Add doc to reader.Discard<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package util

import (
	"bufio"
	"bytes"
	"io"
	"io/ioutil"
)

type Reader struct {
	buf *bufio.Reader
}

func NewReader(rd io.Reader) *Reader {
	return &Reader{buf: bufio.NewReader(rd)}
}

// Discard skips the next n bytes, returning the number of bytes discarded.
// If Discard skips fewer than n bytes, it also returns an error.
func (r *Reader) Discard(n int) (discarded int, err error) {
	return r.buf.Discard(n)
}

// Read reads data into p.
// It returns the number of bytes read into p.
// The bytes are taken from at most one Read on the underlying Reader,
// hence n may be less than len(p).
// At EOF, the count will be zero and err will be io.EOF.
func (r *Reader) Read(p []byte) (n int, err error) {
	return r.buf.Read(p)
}

// ReadAll reads from Reader until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from Reader until EOF, it does not treat an EOF from Read
// as an error to be reported.
func (r *Reader) ReadAll() ([]byte, error) {
	return ioutil.ReadAll(r.buf)
}

// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (r *Reader) ReadByte() (byte, error) {
	return r.buf.ReadByte()
}

// ReadSeveralBytes reads n bytes.
func (r *Reader) ReadSeveralBytes(n int) ([]byte, error) {
	if n == 0 {
		return nil, nil
	}

	peeked, err := r.buf.Peek(n)
	if err != nil {
		return nil, err
	}

	if _, err := r.buf.Discard(n); err != nil {
		return nil, err
	}

	return peeked, nil
}

// ReadTillDelim reads until the first occurrence of delim in the input,
// returning a slice containing the data up to and NOT including the delimiter.
// If ReadTillDelim encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillDelim returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelim(delim byte) ([]byte, error) {
	read, err := r.buf.ReadBytes(delim)
	if err != nil || read == nil || len(read) == 0 {
		return read, err
	}
	err = r.buf.UnreadByte()
	return read[:len(read)-1], err
}

// ReadTillDelims reads until the first occurrence of delims in the input,
// returning a slice containing the data up to and NOT including the delimiters.
// If ReadTillDelims encounters an error before finding a delimiters,
// it returns the data read before the error and the error itself (often io.EOF).
// ReadTillAndWithDelims returns err != nil if and only if the returned data does not end in
// delim.
func (r *Reader) ReadTillDelims(delims []byte) ([]byte, error) {
	if len(delims) == 0 {
		return r.ReadAll()
	}
	if len(delims) == 1 {
		return r.ReadTillDelim(delims[0])
	}

	buf := make([]byte, 0)
	for {
		read, err := r.ReadTillDelim(delims[0])
		if err != nil {
			return buf, err
		}
		buf = append(buf, read...)

		peeked, err := r.buf.Peek(len(delims))
		if err != nil {
			return buf, err
		}

		if bytes.Equal(peeked, delims) {
			break
		}

		b, err := r.ReadByte()
		if err != nil {
			return buf, err
		}
		buf = append(buf, b)
	}

	return buf, nil
}

// Reset discards any buffered data, resets all state,
// and switches the buffered reader to read from r.
func (r *Reader) Reset(rd io.Reader) {
	r.buf.Reset(rd)
}
<|endoftext|>


<commit_before>package sirius

type EID string
type ExtensionConfig map[string]interface{}

type Extension interface {
	Run(Message, ExtensionConfig) (MessageAction, error)
}

type ExtensionLoader interface {
	Load(EID) (Extension, error)
}

// Read fetches a value of any type for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}
	return def
}

// String fetches a string value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) String(key string, def string) string {
	if val, ok := cfg[key]; ok {
		if s, ok := val.(string); ok {
			return s
		}
	}
	return def
}

// Integer fetches an integer value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Integer(key string, def int) int {
	if val, ok := cfg[key]; ok {
		if i, ok := val.(int); ok {
			return i
		}
	}
	return def
}

// Boolean fetches a boolean value for key.
// Returns false if key is not set.
func (cfg ExtensionConfig) Boolean(key string) bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return b
		case int:
			// Require explicit 0 or 1
			if b == 0 {
				return false
			} else if b == 1 {
				return true
			}
		}
	}
	return false
}

// Float fetches a float value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Float(key string, def float64) float64 {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return float64(f)
		case float64:
			return f
		}
	}
	return def
}

// List fetches a list value for key.
// Returns an empty list if key is not set.
func (cfg ExtensionConfig) List(key string) []string {
	var list []string

	if val, ok := cfg[key]; ok {
		switch l := val.(type) {
		case []interface{}:
			for _, lv := range l {
				if s, ok := lv.(string); ok {
					list = append(list, s)
				}
			}
			return list
		case []string:
			return l
		}
	}
	return []string{}
}
<commit_msg>Use switch instead of else if chain<commit_after>package sirius

type EID string
type ExtensionConfig map[string]interface{}

type Extension interface {
	Run(Message, ExtensionConfig) (MessageAction, error)
}

type ExtensionLoader interface {
	Load(EID) (Extension, error)
}

// Read fetches a value of any type for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Read(key string, def interface{}) interface{} {
	if val, ok := cfg[key]; ok {
		return val
	}
	return def
}

// String fetches a string value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) String(key string, def string) string {
	if val, ok := cfg[key]; ok {
		if s, ok := val.(string); ok {
			return s
		}
	}
	return def
}

// Integer fetches an integer value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Integer(key string, def int) int {
	if val, ok := cfg[key]; ok {
		if i, ok := val.(int); ok {
			return i
		}
	}
	return def
}

// Boolean fetches a boolean value for key.
// Returns false if key is not set.
func (cfg ExtensionConfig) Boolean(key string) bool {
	if val, ok := cfg[key]; ok {
		switch b := val.(type) {
		case bool:
			return b
		case int:
			// Require explicit 0 or 1
			switch b {
			case 0:
				return false
			case 1:
				return true
			}
		}
	}
	return false
}

// Float fetches a float value for key.
// Returns def if key is not set.
func (cfg ExtensionConfig) Float(key string, def float64) float64 {
	if val, ok := cfg[key]; ok {
		switch f := val.(type) {
		case float32:
			return float64(f)
		case float64:
			return f
		}
	}
	return def
}

// List fetches a list value for key.
// Returns an empty list if key is not set.
func (cfg ExtensionConfig) List(key string) []string {
	var list []string

	if val, ok := cfg[key]; ok {
		switch l := val.(type) {
		case []interface{}:
			for _, lv := range l {
				if s, ok := lv.(string); ok {
					list = append(list, s)
				}
			}
			return list
		case []string:
			return l
		}
	}
	return []string{}
}
<|endoftext|>


<commit_before>package utils

import (
	"bytes"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/ChimeraCoder/anaconda"
)

func Timestamp() string {
	return time.Now().UTC().Format("2006.01.02 15:04:05") + ": "
}

func GetAudioFilePath(text string) string {
	var filename string
	if text[0] == '#' {
		filename = strings.SplitN(text, "#", 2)[1]
	} else {
		filename = strings.SplitN(text, " ", 2)[1]
	}

	var formats = []string{".ogg", ".mp3", ".wav"}

	for _, format := range formats {
		if _, err := os.Stat("./sounds/" + filename + format); err == nil {
			return "./sounds/" + filename + format
		}
	}
	return ""
}

///Twitter
func TwitterFormatForAudio(twit anaconda.Tweet) string {
	str := "котик " + twit.User.ScreenName + ". " + strings.Replace(twit.Text, "\n", "\\n", -1)

	re := regexp.MustCompile("http[s]?:\\/\\/t\\.co\\/.*?([ ]|$)")
	str = re.ReplaceAllString(str, "")
	str = strings.Replace(str, "/", "", -1)

	return str
}

func TwitterFormatForText(twit anaconda.Tweet) string {
	return "@" + twit.User.Name + ": " + twit.Text
}

///ClosingBuffer
type ClosingBuffer struct {
	*bytes.Buffer
}

func (cb *ClosingBuffer) Close() (err error) {
	return
}
<commit_msg>twitter fix<commit_after>package utils

import (
	"bytes"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/ChimeraCoder/anaconda"
)

func Timestamp() string {
	return time.Now().UTC().Format("2006.01.02 15:04:05") + ": "
}

func GetAudioFilePath(text string) string {
	var filename string
	if text[0] == '#' {
		filename = strings.SplitN(text, "#", 2)[1]
	} else {
		filename = strings.SplitN(text, " ", 2)[1]
	}

	var formats = []string{".ogg", ".mp3", ".wav"}

	for _, format := range formats {
		if _, err := os.Stat("./sounds/" + filename + format); err == nil {
			return "./sounds/" + filename + format
		}
	}
	return ""
}

///Twitter
func TwitterFormatForAudio(twit anaconda.Tweet) string {
	var str string

	if twit.Lang == "en" {
		str = "kitten "
	} else {
		str = "котик "
	}
	str = "котик " + twit.User.ScreenName + ". " + strings.Replace(twit.Text, "\n", "\\n", -1)

	re := regexp.MustCompile("http[s]?:\\/\\/t\\.co\\/.*?([ ]|$)")
	str = re.ReplaceAllString(str, "")
	str = strings.Replace(str, "/", "", -1)

	return str
}

func TwitterFormatForText(twit anaconda.Tweet) string {
	return "@" + twit.User.ScreenName + ": " + twit.Text
}

///ClosingBuffer
type ClosingBuffer struct {
	*bytes.Buffer
}

func (cb *ClosingBuffer) Close() (err error) {
	return
}
<|endoftext|>


<commit_before>/*
 Package feed provides an RSS and Atom feed fetcher.

 They are parsed into an object tree which is a hybrid of both the RSS and Atom
 standards.

 Supported feeds are:
 	- RSS v0.91, 0.91 and 2.0
 	- Atom 1.0

 The package allows us to maintain cache timeout management. This prevents
 querying the servers for feed updates too often. Apart from setting a cache
 timeout manually, the package also optionally adheres to the TTL, SkipDays and
 SkipHours values specified in RSS feeds.

 Because the object structure is a hybrid between both RSS and Atom specs, not
 all fields will be filled when requesting either an RSS or Atom feed. As many
 shared fields as possible are used but some of them simply do not occur in
 either the RSS or Atom spec.
*/
package feed

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"

	xmlx "github.com/jteeuwen/go-pkg-xmlx"
)

const userAgent = "riviera golang"

type ItemHandler func(f *Feed, ch *Channel, newitems []*Item)

type Feed struct {
	// Custom cache timeout.
	cacheTimeout time.Duration

	// Type of feed. Rss, Atom, etc
	format string

	// Channels with content.
	channels []*Channel

	// Url from which this feed was created.
	url string

	// Known containing a list of known Items and Channels for this instance
	known Database

	// A notification function, used to notify the host when a new item
	// has been found for a given channel.
	itemhandler ItemHandler

	// Last time content was fetched. Used in conjunction with CacheTimeout
	// to ensure we don't get content too often.
	lastupdate time.Time
}

func New(cachetimeout time.Duration, ih ItemHandler, database Database) *Feed {
	v := new(Feed)
	v.cacheTimeout = cachetimeout
	v.format = "none"
	v.known = database
	v.itemhandler = ih
	return v
}

// Fetch retrieves the feed's latest content if necessary.
//
// The charset parameter overrides the xml decoder's CharsetReader.
// This allows us to specify a custom character encoding conversion
// routine when dealing with non-utf8 input. Supply 'nil' to use the
// default from Go's xml package.
//
// The client parameter allows the use of arbitrary network connections, for
// example the Google App Engine "URL Fetch" service.
func (f *Feed) Fetch(uri string, client *http.Client, charset xmlx.CharsetFunc) (int, error) {
	if !f.CanUpdate() {
		return -1, nil
	}

	f.url = uri

	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return -1, err
	}

	req.Header.Set("User-Agent", userAgent)

	resp, err := client.Do(req)
	if err != nil {
		return -1, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return resp.StatusCode, nil
	}

	return resp.StatusCode, f.load(resp.Body, charset)
}

func Parse(r io.Reader, charset xmlx.CharsetFunc) (chs []*Channel, err error) {
	doc := xmlx.New()

	if err = doc.LoadStream(r, charset); err != nil {
		return
	}

	format, version := GetVersionInfo(doc)
	if ok := testVersions(format, version); !ok {
		err = errors.New(fmt.Sprintf("Unsupported feed: %s, version: %+v", format, version))
		return
	}

	return buildFeed(format, doc)
}

func (f *Feed) load(r io.Reader, charset xmlx.CharsetFunc) (err error) {
	f.channels, err = Parse(r, charset)
	if err != nil || len(f.channels) == 0 {
		return
	}

	// reset cache timeout values according to feed specified values (TTL)
	if f.cacheTimeout < time.Minute*time.Duration(f.channels[0].TTL) {
		f.cacheTimeout = time.Minute * time.Duration(f.channels[0].TTL)
	}

	f.notifyListeners()
	return
}

func (f *Feed) notifyListeners() {
	for _, channel := range f.channels {
		var newitems []*Item

		for _, item := range channel.Items {
			if !f.known.Contains(item.Key()) {
				newitems = append(newitems, item)
			}
		}

		if len(newitems) > 0 && f.itemhandler != nil {
			f.itemhandler(f, channel, newitems)
		}
	}
}

// This function returns true or false, depending on whether the CacheTimeout
// value has expired or not. Additionally, it will ensure that we adhere to the
// RSS spec's SkipDays and SkipHours values. If this function returns true, you
// can be sure that a fresh feed update will be performed.
func (f *Feed) CanUpdate() bool {
	// Make sure we are not within the specified cache-limit.
	// This ensures we don't request data too often.
	utc := time.Now().UTC()
	if utc.Sub(f.lastupdate) < f.cacheTimeout {
		return false
	}

	// If skipDays or skipHours are set in the RSS feed, use these to see if
	// we can update.
	if len(f.channels) == 1 && f.format == "rss" {
		if len(f.channels[0].SkipDays) > 0 {
			for _, v := range f.channels[0].SkipDays {
				if time.Weekday(v) == utc.Weekday() {
					return false
				}
			}
		}

		if len(f.channels[0].SkipHours) > 0 {
			for _, v := range f.channels[0].SkipHours {
				if v == utc.Hour() {
					return false
				}
			}
		}
	}

	f.lastupdate = utc
	return true
}

// Returns the number of seconds needed to elapse
// before the feed should update.
func (f *Feed) DurationTillUpdate() time.Duration {
	return f.cacheTimeout - time.Now().UTC().Sub(f.lastupdate)
}

func buildFeed(format string, doc *xmlx.Document) ([]*Channel, error) {
	switch format {
	case "atom":
		return readAtom(doc)
	default:
		return readRss2(doc)
	}
}

func testVersions(format string, version [2]int) bool {
	switch format {
	case "rss":
		if version[0] > 2 || (version[0] == 2 && version[1] > 0) {
			return false
		}

	case "atom":
		if version[0] > 1 || (version[0] == 1 && version[1] > 0) {
			return false
		}

	default:
		return false
	}

	return true
}

func GetVersionInfo(doc *xmlx.Document) (string, [2]int) {
	if node := doc.SelectNode("http://www.w3.org/2005/Atom", "feed"); node != nil {
		return "atom", [2]int{1, 0}
	}

	if node := doc.SelectNode("", "rss"); node != nil {
		version := node.As("", "version")
		p := strings.Index(version, ".")
		major, _ := strconv.Atoi(version[0:p])
		minor, _ := strconv.Atoi(version[p+1 : len(version)])

		return "rss", [2]int{major, minor}
	}

	// issue#5: Some documents have an RDF root node instead of rss.
	if node := doc.SelectNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF"); node != nil {
		return "rss", [2]int{1, 1}
	}

	return "unknown", [2]int{0, 0}
}
<commit_msg>Add If-Modified-Since header when fetching<commit_after>/*
 Package feed provides an RSS and Atom feed fetcher.

 They are parsed into an object tree which is a hybrid of both the RSS and Atom
 standards.

 Supported feeds are:
 	- RSS v0.91, 0.91 and 2.0
 	- Atom 1.0

 The package allows us to maintain cache timeout management. This prevents
 querying the servers for feed updates too often. Apart from setting a cache
 timeout manually, the package also optionally adheres to the TTL, SkipDays and
 SkipHours values specified in RSS feeds.

 Because the object structure is a hybrid between both RSS and Atom specs, not
 all fields will be filled when requesting either an RSS or Atom feed. As many
 shared fields as possible are used but some of them simply do not occur in
 either the RSS or Atom spec.
*/
package feed

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"

	xmlx "github.com/jteeuwen/go-pkg-xmlx"
)

const userAgent = "riviera golang"

type ItemHandler func(f *Feed, ch *Channel, newitems []*Item)

type Feed struct {
	// Custom cache timeout.
	cacheTimeout time.Duration

	// Type of feed. Rss, Atom, etc
	format string

	// Channels with content.
	channels []*Channel

	// Url from which this feed was created.
	url string

	// Known containing a list of known Items and Channels for this instance
	known Database

	// A notification function, used to notify the host when a new item
	// has been found for a given channel.
	itemhandler ItemHandler

	// Last time content was fetched. Used in conjunction with CacheTimeout
	// to ensure we don't get content too often.
	lastupdate time.Time
}

func New(cachetimeout time.Duration, ih ItemHandler, database Database) *Feed {
	v := new(Feed)
	v.cacheTimeout = cachetimeout
	v.format = "none"
	v.known = database
	v.itemhandler = ih
	return v
}

// Fetch retrieves the feed's latest content if necessary.
//
// The charset parameter overrides the xml decoder's CharsetReader.
// This allows us to specify a custom character encoding conversion
// routine when dealing with non-utf8 input. Supply 'nil' to use the
// default from Go's xml package.
//
// The client parameter allows the use of arbitrary network connections, for
// example the Google App Engine "URL Fetch" service.
func (f *Feed) Fetch(uri string, client *http.Client, charset xmlx.CharsetFunc) (int, error) {
	if !f.CanUpdate() {
		return -1, nil
	}

	f.url = uri

	req, err := http.NewRequest("GET", uri, nil)
	if err != nil {
		return -1, err
	}

	req.Header.Set("User-Agent", userAgent)
	req.Header.Set("If-Modified-Since", f.lastupdate.Format(time.RFC1123))

	resp, err := client.Do(req)
	if err != nil {
		return -1, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return resp.StatusCode, nil
	}

	return resp.StatusCode, f.load(resp.Body, charset)
}

func Parse(r io.Reader, charset xmlx.CharsetFunc) (chs []*Channel, err error) {
	doc := xmlx.New()

	if err = doc.LoadStream(r, charset); err != nil {
		return
	}

	format, version := GetVersionInfo(doc)
	if ok := testVersions(format, version); !ok {
		err = errors.New(fmt.Sprintf("Unsupported feed: %s, version: %+v", format, version))
		return
	}

	return buildFeed(format, doc)
}

func (f *Feed) load(r io.Reader, charset xmlx.CharsetFunc) (err error) {
	f.channels, err = Parse(r, charset)
	if err != nil || len(f.channels) == 0 {
		return
	}

	// reset cache timeout values according to feed specified values (TTL)
	if f.cacheTimeout < time.Minute*time.Duration(f.channels[0].TTL) {
		f.cacheTimeout = time.Minute * time.Duration(f.channels[0].TTL)
	}

	f.notifyListeners()
	return
}

func (f *Feed) notifyListeners() {
	for _, channel := range f.channels {
		var newitems []*Item

		for _, item := range channel.Items {
			if !f.known.Contains(item.Key()) {
				newitems = append(newitems, item)
			}
		}

		if len(newitems) > 0 && f.itemhandler != nil {
			f.itemhandler(f, channel, newitems)
		}
	}
}

// This function returns true or false, depending on whether the CacheTimeout
// value has expired or not. Additionally, it will ensure that we adhere to the
// RSS spec's SkipDays and SkipHours values. If this function returns true, you
// can be sure that a fresh feed update will be performed.
func (f *Feed) CanUpdate() bool {
	// Make sure we are not within the specified cache-limit.
	// This ensures we don't request data too often.
	utc := time.Now().UTC()
	if utc.Sub(f.lastupdate) < f.cacheTimeout {
		return false
	}

	// If skipDays or skipHours are set in the RSS feed, use these to see if
	// we can update.
	if len(f.channels) == 1 && f.format == "rss" {
		if len(f.channels[0].SkipDays) > 0 {
			for _, v := range f.channels[0].SkipDays {
				if time.Weekday(v) == utc.Weekday() {
					return false
				}
			}
		}

		if len(f.channels[0].SkipHours) > 0 {
			for _, v := range f.channels[0].SkipHours {
				if v == utc.Hour() {
					return false
				}
			}
		}
	}

	f.lastupdate = utc
	return true
}

// Returns the number of seconds needed to elapse
// before the feed should update.
func (f *Feed) DurationTillUpdate() time.Duration {
	return f.cacheTimeout - time.Now().UTC().Sub(f.lastupdate)
}

func buildFeed(format string, doc *xmlx.Document) ([]*Channel, error) {
	switch format {
	case "atom":
		return readAtom(doc)
	default:
		return readRss2(doc)
	}
}

func testVersions(format string, version [2]int) bool {
	switch format {
	case "rss":
		if version[0] > 2 || (version[0] == 2 && version[1] > 0) {
			return false
		}

	case "atom":
		if version[0] > 1 || (version[0] == 1 && version[1] > 0) {
			return false
		}

	default:
		return false
	}

	return true
}

func GetVersionInfo(doc *xmlx.Document) (string, [2]int) {
	if node := doc.SelectNode("http://www.w3.org/2005/Atom", "feed"); node != nil {
		return "atom", [2]int{1, 0}
	}

	if node := doc.SelectNode("", "rss"); node != nil {
		version := node.As("", "version")
		p := strings.Index(version, ".")
		major, _ := strconv.Atoi(version[0:p])
		minor, _ := strconv.Atoi(version[p+1 : len(version)])

		return "rss", [2]int{major, minor}
	}

	// issue#5: Some documents have an RDF root node instead of rss.
	if node := doc.SelectNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "RDF"); node != nil {
		return "rss", [2]int{1, 1}
	}

	return "unknown", [2]int{0, 0}
}
<|endoftext|>


<commit_before>package file

type File struct {
	Id         int64
	ParentId   int64
	Checksum   string
	Resolution string
}
<commit_msg>Defined the database tags for the file struct<commit_after>package file

type File struct {
	Id         int64  `db:"id"`
	ParentId   int64  `db:"parent_id"`
	Checksum   string `db:"checksum"`
	Resolution string `db:"resolution"`
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.73"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.40", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<commit_msg>fnlb: 0.0.74 release [skip ci]<commit_after>package main

import (
	"context"
	"crypto/tls"
	"flag"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/coreos/go-semver/semver"
	"github.com/fnproject/fn/fnlb/lb"
	"github.com/sirupsen/logrus"
)

const VERSION = "0.0.74"

func main() {
	// XXX (reed): normalize
	fnodes := flag.String("nodes", "", "comma separated list of functions nodes")
	minAPIVersion := flag.String("min-api-version", "0.0.41", "minimal node API to accept")

	var conf lb.Config
	flag.StringVar(&conf.DBurl, "db", "sqlite3://:memory:", "backend to store nodes, default to in memory")
	flag.StringVar(&conf.Listen, "listen", ":8081", "port to run on")
	flag.IntVar(&conf.HealthcheckInterval, "hc-interval", 3, "how often to check f(x) nodes, in seconds")
	flag.StringVar(&conf.HealthcheckEndpoint, "hc-path", "/version", "endpoint to determine node health")
	flag.IntVar(&conf.HealthcheckUnhealthy, "hc-unhealthy", 2, "threshold of failed checks to declare node unhealthy")
	flag.IntVar(&conf.HealthcheckTimeout, "hc-timeout", 5, "timeout of healthcheck endpoint, in seconds")
	flag.StringVar(&conf.ZipkinURL, "zipkin", "", "zipkin endpoint to send traces")
	flag.Parse()

	conf.MinAPIVersion = semver.New(*minAPIVersion)

	if len(*fnodes) > 0 {
		// starting w/o nodes is fine too
		conf.Nodes = strings.Split(*fnodes, ",")
	}

	conf.Transport = &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 120 * time.Second,
		}).Dial,
		MaxIdleConnsPerHost: 512,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig: &tls.Config{
			ClientSessionCache: tls.NewLRUClientSessionCache(4096),
		},
	}

	g, err := lb.NewAllGrouper(conf)
	if err != nil {
		logrus.WithError(err).Fatal("error setting up grouper")
	}

	r := lb.NewConsistentRouter(conf)
	k := func(r *http.Request) (string, error) {
		return r.URL.Path, nil
	}

	h := lb.NewProxy(k, g, r, conf)
	h = g.Wrap(h) // add/del/list endpoints
	h = r.Wrap(h) // stats / dash endpoint

	err = serve(conf.Listen, h)
	if err != nil {
		logrus.WithError(err).Fatal("server error")
	}
}

func serve(addr string, handler http.Handler) error {
	server := &http.Server{Addr: addr, Handler: handler}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		for sig := range ch {
			logrus.WithFields(logrus.Fields{"signal": sig}).Info("received signal")
			server.Shutdown(context.Background()) // safe shutdown
			return
		}
	}()
	return server.ListenAndServe()
}
<|endoftext|>


<commit_before>package logrusx

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

type (
	MistifyFormatter struct{}
	FieldError       struct {
		Error   error
		Message string
	}
)

func (f *MistifyFormatter) Format(entry *log.Entry) ([]byte, error) {
	for k, v := range entry.Data {
		if err, ok := v.(error); ok {
			entry.Data[k] = FieldError{err, err.Error()}
		}
	}
	d := new(log.JSONFormatter)
	return d.Format(entry)
}
<commit_msg>[MIST-372] Cleaner and more fun<commit_after>package logrusx

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

type (
	MistifyFormatter struct {
		log.JSONFormatter
	}
	FieldError struct {
		Error   error
		Message string
	}
)

func (f *MistifyFormatter) Format(entry *log.Entry) ([]byte, error) {
	for k, v := range entry.Data {
		if err, ok := v.(error); ok {
			entry.Data[k] = FieldError{err, err.Error()}
		}
	}
	return f.JSONFormatter.Format(entry)
}
<|endoftext|>


<commit_before>package ligno

import (
	"bytes"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

// Formatter is interface for converting log record to string representation.
type Formatter interface {
	Format(record Record) string
}

// DefaultFormatter converts log record to simple string for printing.
type DefaultFormatter struct{}

// defaultTimeFormat is formatting string for time for DefaultFormatter
const defaultTimeFormat = "2006-01-02 15:05:06.0000"

// Format converts provided log record to format suitable for printing in one line.
// String produced resembles traditional log message.
func (df *DefaultFormatter) Format(record Record) string {
	time := record.Time().Format(defaultTimeFormat)
	delete(record, TimeKey)
	level := record.Level()
	delete(record, LevelKey)
	event := record.Event()
	delete(record, EventKey)
	var buff bytes.Buffer

	keys := make([]string, 0, len(record))
	for k, _ := range record {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for i := 0; i < len(keys); i++ {
		k := keys[i]
		v := strconv.Quote(fmt.Sprintf("%+v", record[k]))
		if strings.IndexFunc(k, needsQuote) >= 0 || k == "" {
			k = strconv.Quote(k)
		}
		buff.WriteString(fmt.Sprintf("%s=%+v", k, v))
		if i < len(keys)-1 {
			buff.WriteString(" ")
		}
	}
	return fmt.Sprintf("%-25s %-10s %-15s [%s]", time, level, event, buff.String())
}

// defaultFormatter is instance of DefaultFormatter.
var defaultFormatter = &DefaultFormatter{}

// Needs quote determines if provided rune is such that word that contains this
// rune needs to be quoted.
func needsQuote(r rune) bool {
	return r == ' ' || r == '"' || r == '\\' || r == '=' ||
		!unicode.IsPrint(r)
}

// JSONFormatter is simple formatter that only marshals log record to json.
type JSONFormatter struct{}

// Format returns JSON representation of provided record.
func (jf *JSONFormatter) Format(record Record) string {
	d, err := json.MarshalIndent(record, "", "    ")
	if err != nil {
		panic(err)
	}
	return string(d)
}
<commit_msg>Remove unneeded loop parameter<commit_after>package ligno

import (
	"bytes"
	"encoding/json"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

// Formatter is interface for converting log record to string representation.
type Formatter interface {
	Format(record Record) string
}

// DefaultFormatter converts log record to simple string for printing.
type DefaultFormatter struct{}

// defaultTimeFormat is formatting string for time for DefaultFormatter
const defaultTimeFormat = "2006-01-02 15:05:06.0000"

// Format converts provided log record to format suitable for printing in one line.
// String produced resembles traditional log message.
func (df *DefaultFormatter) Format(record Record) string {
	time := record.Time().Format(defaultTimeFormat)
	delete(record, TimeKey)
	level := record.Level()
	delete(record, LevelKey)
	event := record.Event()
	delete(record, EventKey)
	var buff bytes.Buffer

	keys := make([]string, 0, len(record))
	for k := range record {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	for i := 0; i < len(keys); i++ {
		k := keys[i]
		v := strconv.Quote(fmt.Sprintf("%+v", record[k]))
		if strings.IndexFunc(k, needsQuote) >= 0 || k == "" {
			k = strconv.Quote(k)
		}
		buff.WriteString(fmt.Sprintf("%s=%+v", k, v))
		if i < len(keys)-1 {
			buff.WriteString(" ")
		}
	}
	return fmt.Sprintf("%-25s %-10s %-15s [%s]", time, level, event, buff.String())
}

// defaultFormatter is instance of DefaultFormatter.
var defaultFormatter = &DefaultFormatter{}

// Needs quote determines if provided rune is such that word that contains this
// rune needs to be quoted.
func needsQuote(r rune) bool {
	return r == ' ' || r == '"' || r == '\\' || r == '=' ||
		!unicode.IsPrint(r)
}

// JSONFormatter is simple formatter that only marshals log record to json.
type JSONFormatter struct{}

// Format returns JSON representation of provided record.
func (jf *JSONFormatter) Format(record Record) string {
	d, err := json.MarshalIndent(record, "", "    ")
	if err != nil {
		panic(err)
	}
	return string(d)
}
<|endoftext|>