<commit_before>package testSuit

import (
	"bytes"
	"image"
	"image/color"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// TestSuit http request test form
type TestSuit struct {
	Method      string
	URL         string
	Data        url.Values
	Buffer      io.Reader
	ContentType string
	r           *gin.Engine
}

// Do start test
func (ts *TestSuit) Do(handler gin.HandlerFunc) (*httptest.ResponseRecorder, *httptest.ResponseRecorder) {
	var req *http.Request

	if ts.ContentType == "" {
		ts.ContentType = "application/x-www-form-urlencoded"
	}

	if ts.Method == "ALL" {
		if ts.Data != nil {
			encodedData := ts.Data.Encode()

			reqGet, _ := http.NewRequest("GET", ts.URL, nil)
			reqGet.Header.Add("Content-Type", ts.ContentType)
			reqGet.URL.RawQuery = encodedData

			reqPost, _ := http.NewRequest("POST", ts.URL,
				strings.NewReader(encodedData))
			reqPost.Header.Add("Content-Type", ts.ContentType)

			respGet := httptest.NewRecorder()
			respPost := httptest.NewRecorder()
			ts.r.ServeHTTP(respGet, reqGet)
			ts.r.ServeHTTP(respPost, reqPost)

			return respGet, respPost
		}

		req, _ = http.NewRequest(ts.Method, ts.URL, nil)
		req.Header.Add("Content-Type", ts.ContentType)

	} else {
		if ts.Data != nil {

			switch ts.Method {
			case "GET":
				req, _ = http.NewRequest(ts.Method, ts.URL, nil)
				req.URL.RawQuery = ts.Data.Encode()
				req.Header.Add("Content-Type", ts.ContentType)
			case "POST":
				req, _ = http.NewRequest(ts.Method, ts.URL,
					strings.NewReader(ts.Data.Encode()))
				req.Header.Add("Content-Type", ts.ContentType)
			}

		} else if ts.Buffer != nil {
			req, _ = http.NewRequest(ts.Method, ts.URL, ts.Buffer)
			req.Header.Add("Content-Type", ts.ContentType)
		} else {
			req, _ = http.NewRequest(ts.Method, ts.URL, nil)
			req.Header.Add("Content-Type", ts.ContentType)
		}
	}

	resp := httptest.NewRecorder()
	ts.r.ServeHTTP(resp, req)
	return resp, nil
}

// GetGinEngine create gin.Engine with test mode
func GetGinEngine() *gin.Engine {
	gin.SetMode(gin.TestMode)
	r := gin.New()

	return r
}

// GenImage generate randomize image
func GenImage(ext string, width, height int) (*bytes.Buffer, string, error) {
	rand.Seed(time.Now().UTC().UnixNano())

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			img.Set(x, y, color.RGBA{
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
			})
		}
	}

	nameFix := uuid.New().URN()
	buffer := &bytes.Buffer{}
	bufferWriter := multipart.NewWriter(buffer)
	formWriter, err := bufferWriter.CreateFormFile("file", nameFix+".png")
	contentType := bufferWriter.FormDataContentType()

	switch ext {
	case "png":
		png.Encode(formWriter, img)
		bufferWriter.Close()
	case "jpg":
		jpeg.Encode(formWriter, img, nil)
		bufferWriter.Close()
	case "gif":
		gif.Encode(formWriter, img, nil)
		bufferWriter.Close()
	}
	return buffer, contentType, err
}
<commit_msg>export router<commit_after>package testSuit

import (
	"bytes"
	"image"
	"image/color"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"math/rand"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

// TestSuit http request test form
type TestSuit struct {
	Method      string
	URL         string
	Data        url.Values
	Buffer      io.Reader
	ContentType string
	Router      *gin.Engine
}

// Do start test
func (ts *TestSuit) Do(handler gin.HandlerFunc) (*httptest.ResponseRecorder, *httptest.ResponseRecorder) {
	var req *http.Request

	if ts.ContentType == "" {
		ts.ContentType = "application/x-www-form-urlencoded"
	}

	if ts.Method == "ALL" {
		if ts.Data != nil {
			encodedData := ts.Data.Encode()

			reqGet, _ := http.NewRequest("GET", ts.URL, nil)
			reqGet.Header.Add("Content-Type", ts.ContentType)
			reqGet.URL.RawQuery = encodedData

			reqPost, _ := http.NewRequest("POST", ts.URL,
				strings.NewReader(encodedData))
			reqPost.Header.Add("Content-Type", ts.ContentType)

			respGet := httptest.NewRecorder()
			respPost := httptest.NewRecorder()
			ts.Router.ServeHTTP(respGet, reqGet)
			ts.Router.ServeHTTP(respPost, reqPost)

			return respGet, respPost
		}

		req, _ = http.NewRequest(ts.Method, ts.URL, nil)
		req.Header.Add("Content-Type", ts.ContentType)

	} else {
		if ts.Data != nil {

			switch ts.Method {
			case "GET":
				req, _ = http.NewRequest(ts.Method, ts.URL, nil)
				req.URL.RawQuery = ts.Data.Encode()
				req.Header.Add("Content-Type", ts.ContentType)
			case "POST":
				req, _ = http.NewRequest(ts.Method, ts.URL,
					strings.NewReader(ts.Data.Encode()))
				req.Header.Add("Content-Type", ts.ContentType)
			}

		} else if ts.Buffer != nil {
			req, _ = http.NewRequest(ts.Method, ts.URL, ts.Buffer)
			req.Header.Add("Content-Type", ts.ContentType)
		} else {
			req, _ = http.NewRequest(ts.Method, ts.URL, nil)
			req.Header.Add("Content-Type", ts.ContentType)
		}
	}

	resp := httptest.NewRecorder()
	ts.Router.ServeHTTP(resp, req)
	return resp, nil
}

// GetGinEngine create gin.Engine with test mode
func GetGinEngine() *gin.Engine {
	gin.SetMode(gin.TestMode)
	r := gin.New()

	return r
}

// GenImage generate randomize image
func GenImage(ext string, width, height int) (*bytes.Buffer, string, error) {
	rand.Seed(time.Now().UTC().UnixNano())

	img := image.NewRGBA(image.Rect(0, 0, width, height))
	for x := 0; x < width; x++ {
		for y := 0; y < height; y++ {
			img.Set(x, y, color.RGBA{
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
				uint8(rand.Intn(255)),
			})
		}
	}

	nameFix := uuid.New().URN()
	buffer := &bytes.Buffer{}
	bufferWriter := multipart.NewWriter(buffer)
	formWriter, err := bufferWriter.CreateFormFile("file", nameFix+".png")
	contentType := bufferWriter.FormDataContentType()

	switch ext {
	case "png":
		png.Encode(formWriter, img)
		bufferWriter.Close()
	case "jpg":
		jpeg.Encode(formWriter, img, nil)
		bufferWriter.Close()
	case "gif":
		gif.Encode(formWriter, img, nil)
		bufferWriter.Close()
	}
	return buffer, contentType, err
}
<|endoftext|>


<commit_before>package tests

import (
	"plivo/plivo.persistence/redis"
	"plivo/plivo.sms/model"
	"plivo/plivo.sms/repository"
	"testing"
)

func TestSetStop(t *testing.T) {
	redis.Initialize()

	repository.SMSRepository{}.SetStop(model.NewSMS("123456", "234567", "STOP"))

	val, _ := redis.Get("from:234567;to:123456")

	if val != "stop" {
		t.Errorf("Exptected stop, found %s", val)

		t.Fail()
	}

	redis.Delete("from:234567;to:123456")
}
<commit_msg>Added a test for getting the sent sms count<commit_after>package tests

import (
	"plivo/plivo.persistence/redis"
	"plivo/plivo.sms/model"
	"plivo/plivo.sms/repository"
	"testing"
)

func TestSetStop(t *testing.T) {
	redis.Initialize()

	repository.SMSRepository{}.SetStop(model.NewSMS("123456", "234567", "STOP"))

	val, _ := redis.Get("from:234567;to:123456")

	if val != "stop" {
		t.Errorf("Exptected stop, found %s", val)

		t.Fail()
	}

	redis.Delete("from:234567;to:123456")
}

func TestUpdateSentSMSCount(t *testing.T) {
	redis.Initialize()

	repository.SMSRepository{}.UpdateSentSMSCount(model.NewSMS("123456", "234567", "Hello"))
	repository.SMSRepository{}.UpdateSentSMSCount(model.NewSMS("123456", "456789", "hi"))
	repository.SMSRepository{}.UpdateSentSMSCount(model.NewSMS("123456", "987654", "hi there"))

	val, _ := redis.Get("from:123456")

	if val != "3" {
		t.Errorf("Expected %s, got %s", "2", val)
	}

	redis.Delete("from:123456")
}
<|endoftext|>


<commit_before>// +build !windows
// cmpout

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test that a program can survive SIGCHLD.

package main

import "syscall"

func main() {
	syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
	println("survived SIGCHLD")
}
<commit_msg>test: skip SIGCHLD test on Plan 9<commit_after>// +build !plan9,!windows
// cmpout

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test that a program can survive SIGCHLD.

package main

import "syscall"

func main() {
	syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
	println("survived SIGCHLD")
}
<|endoftext|>


<commit_before>package rpc2

type Client struct {
	xp          Transporter
	unwrapError UnwrapErrorFunc
}

func NewClient(xp Transporter, f UnwrapErrorFunc) *Client {
	return &Client{xp, f}
}

func (c *Client) Call(method string, arg interface{}, res interface{}) (err error) {
	var d dispatcher
	c.xp.Run(true)
	if d, err = c.xp.getDispatcher(); err == nil {
		err = d.Call(method, arg, res, c.unwrapError)
	}
	return
}

func (c *Client) Notify(method string, arg interface{}) (err error) {
	var d dispatcher
	c.xp.Run(true)
	if d, err = c.xp.getDispatcher(); err == nil {
		err = d.Notify(method, arg)
	}
	return
}
<commit_msg>comments<commit_after>package rpc2

// Client allows calls and notifies on the given transporter, or any protocol
// type. All will share the same UnwrapErrorFunc hook for unwrapping incoming
// msgpack objects and converting to possible Go-native `Error` types
type Client struct {
	xp          Transporter
	unwrapError UnwrapErrorFunc
}

// NewClient constructs a new client from the given RPC transport and the
// UnwrapErrorFunc.
func NewClient(xp Transporter, f UnwrapErrorFunc) *Client {
	return &Client{xp, f}
}

// Call makes an msgpack RPC call over the transports that's bound to this
// client. The name of the method, and the argument are given. On reply,
// the result field will be populated (if applicable). It returns an Error
// on error, where the error might have been unwrapped from Msgpack via the
// UnwrapErrorFunc in this client.
func (c *Client) Call(method string, arg interface{}, res interface{}) (err error) {
	var d dispatcher
	c.xp.Run(true)
	if d, err = c.xp.getDispatcher(); err == nil {
		err = d.Call(method, arg, res, c.unwrapError)
	}
	return
}

// Notify notifies the server, with the given method and argument. It does not
// wait to hear back for an error. An error might happen in sending the call, in
// which case a native Go Error is returned. The UnwrapErrorFunc in the underlying
// client isn't relevant in this case.
func (c *Client) Notify(method string, arg interface{}) (err error) {
	var d dispatcher
	c.xp.Run(true)
	if d, err = c.xp.getDispatcher(); err == nil {
		err = d.Notify(method, arg)
	}
	return
}
<|endoftext|>


<commit_before>// Package rpctest contains tests for dcrwallet's RPC server and a harness used
// to facilitate the tests by setting up a temporary Simnet node and wallet. The
// RPC client implementation in dcrrpcclient is used exclusively to test the RPC
// server. A single test function, TestMain, is executed by go test, and is
// responsible for setting up test harnesses and running the individual RPC test
// functions.
//
// A Harness, as defined in rpcharness.go, manages a SimNet node and a wallet
// that connects to the node. (*Harness).SetUp does the following:
//   1. Start a new dcrd process with a fresh SimNet chain.
//   2. Create a new temporary wallet connected to the running node.
//   3. Get a new address from the wallet for mining subsidy.
//   4. Restart dcrd with miningaddr set.
//   5. Generate a number of blocks so that testing starts with a spendable
//      balance.
//
// Multiple harnesses may be run concurrently. Temporary folders are created for
// each harness, and cleaned up on shutdown.
//
// The default settings for a harness wallet are:
//    1. Stake mining enabled (--enablestakemining).
//    2. Zero max ticket price.
//    3. High balance to maintain (2000000 DCR).
// Thus, a harness wallet will automatically vote on owned tickets, but not
// automatically purchase tickets.
package rpctest
<commit_msg>Fix comment. (#661)<commit_after>// Package rpctest contains tests for dcrwallet's RPC server and a harness used
// to facilitate the tests by setting up a temporary Simnet node and wallet. The
// RPC client implementation in dcrrpcclient is used exclusively to test the RPC
// server. A single test function, TestMain, is executed by go test, and is
// responsible for setting up test harnesses and running the individual RPC test
// functions.
//
// A Harness, as defined in rpcharness.go, manages a SimNet node and a wallet
// that connects to the node. (*Harness).SetUp does the following:
//   1. Start a new dcrd process with a fresh SimNet chain.
//   2. Create a new temporary wallet connected to the running node.
//   3. Get a new address from the wallet for mining subsidy.
//   4. Restart dcrd with miningaddr set.
//   5. Generate a number of blocks so that testing starts with a spendable
//      balance.
//
// Multiple harnesses may be run concurrently. Temporary folders are created for
// each harness, and cleaned up on shutdown.
//
// The default settings for a harness wallet are:
//    1. Ticket buyer enabled (--enableticketbuyer).
//    2. Zero max ticket price.
//    3. High balance to maintain (2000000 DCR).
// Thus, a harness wallet will automatically vote on owned tickets, but not
// automatically purchase tickets.
package rpctest
<|endoftext|>


<commit_before>package utp

/*
#include "utp.h"
*/
import "C"
import (
	"context"
	"errors"
	"net"
	"time"

	"github.com/anacrolix/missinggo/inproc"
	"github.com/anacrolix/mmsg"
)

type Socket struct {
	pc            net.PacketConn
	ctx           *C.utp_context
	backlog       chan *Conn
	closed        bool
	conns         map[*C.utp_socket]*Conn
	nonUtpReads   chan packet
	writeDeadline time.Time
	readDeadline  time.Time
}

var (
	_ net.PacketConn = (*Socket)(nil)
	_ net.Listener   = (*Socket)(nil)
)

type packet struct {
	b    []byte
	from net.Addr
}

func listenPacket(network, addr string) (pc net.PacketConn, err error) {
	if network == "inproc" {
		return inproc.ListenPacket(network, addr)
	}
	return net.ListenPacket(network, addr)
}

func NewSocket(network, addr string) (*Socket, error) {
	pc, err := listenPacket(network, addr)
	if err != nil {
		return nil, err
	}
	mu.Lock()
	defer mu.Unlock()
	ctx := C.utp_init(2)
	if ctx == nil {
		panic(ctx)
	}
	ctx.setCallbacks()
	if utpLogging {
		ctx.setOption(C.UTP_LOG_NORMAL, 1)
		ctx.setOption(C.UTP_LOG_MTU, 1)
		ctx.setOption(C.UTP_LOG_DEBUG, 1)
	}
	s := &Socket{
		pc:          pc,
		ctx:         ctx,
		backlog:     make(chan *Conn, 5),
		conns:       make(map[*C.utp_socket]*Conn),
		nonUtpReads: make(chan packet, 100),
	}
	libContextToSocket[ctx] = s
	go s.timeoutChecker()
	go s.packetReader()
	return s, nil
}

func (s *Socket) onLibSocketDestroyed(ls *C.utp_socket) {
	delete(s.conns, ls)
}

func (s *Socket) newConn(us *C.utp_socket) *Conn {
	c := &Conn{
		s:         us,
		localAddr: s.pc.LocalAddr(),
	}
	c.cond.L = &mu
	s.conns[us] = c
	c.writeDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
	c.readDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
	return c
}

func (s *Socket) packetReader() {
	mc := mmsg.NewConn(s.pc)
	// Increasing the messages increases the memory use, but also means we can
	// reduces utp_issue_deferred_acks and syscalls which should improve
	// efficiency. On the flip side, not all OSs implement batched reads.
	ms := make([]mmsg.Message, func() int {
		if mc.Err() == nil {
			return 16
		} else {
			return 1
		}
	}())
	for i := range ms {
		// The IPv4 UDP limit is allegedly about 64 KiB, and this message has
		// been seen on receiving on Windows with just 0x1000: wsarecvfrom: A
		// message sent on a datagram socket was larger than the internal
		// message buffer or some other network limit, or the buffer used to
		// receive a datagram into was smaller than the datagram itself.
		ms[i].Buffers = [][]byte{make([]byte, 0x10000)}
	}
	// Some crap OSs like Windoze will raise errors in Reads that don't
	// actually mean we should stop.
	consecutiveErrors := 0
	for {
		// In C, all the reads are processed and when it threatens to block,
		// we're supposed to call utp_issue_deferred_acks.
		n, err := mc.RecvMsgs(ms)
		if n == 1 {
			singleMsgRecvs.Add(1)
		}
		if n > 1 {
			multiMsgRecvs.Add(1)
		}
		if err != nil {
			mu.Lock()
			closed := s.closed
			mu.Unlock()
			if closed {
				// We don't care.
				return
			}
			// See https://github.com/anacrolix/torrent/issues/83. If we get
			// an endless stream of errors (such as the PacketConn being
			// Closed outside of our control, this work around may need to be
			// reconsidered.
			Logger.Printf("ignoring socket read error: %s", err)
			consecutiveErrors++
			if consecutiveErrors >= 100 {
				Logger.Print("too many consecutive errors, closing socket")
				s.Close()
				return
			}
			continue
		}
		consecutiveErrors = 0
		expMap.Add("successful mmsg receive calls", 1)
		expMap.Add("received messages", int64(n))
		s.processReceivedMessages(ms[:n])
	}
}

func (s *Socket) processReceivedMessages(ms []mmsg.Message) {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return
	}
	gotUtp := false
	for _, m := range ms {
		gotUtp = s.processReceivedMessage(m.Buffers[0][:m.N], m.Addr) || gotUtp
	}
	if gotUtp {
		s.afterReceivingUtpMessages()
	}
}

func (s *Socket) afterReceivingUtpMessages() {
	C.utp_issue_deferred_acks(s.ctx)
	// TODO: When is this done in C?
	C.utp_check_timeouts(s.ctx)
}

func (s *Socket) processReceivedMessage(b []byte, addr net.Addr) (utp bool) {
	if s.utpProcessUdp(b, addr) {
		socketUtpPacketsReceived.Add(1)
		return true
	} else {
		s.onReadNonUtp(b, addr)
		return false
	}
}

// Wraps libutp's utp_process_udp, returning relevant information.
func (s *Socket) utpProcessUdp(b []byte, addr net.Addr) (utp bool) {
	sa, sal := netAddrToLibSockaddr(addr)
	if len(b) == 0 {
		// The implementation of utp_process_udp rejects null buffers, and
		// anything smaller than the UTP header size. It's also prone to
		// assert on those, which we don't want to trigger.
		return false
	}
	ret := C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(len(b)), sa, sal)
	switch ret {
	case 1:
		return true
	case 0:
		return false
	default:
		panic(ret)
	}
}

func (s *Socket) timeoutChecker() {
	for {
		mu.Lock()
		if s.closed {
			mu.Unlock()
			return
		}
		// C.utp_issue_deferred_acks(s.ctx)
		C.utp_check_timeouts(s.ctx)
		mu.Unlock()
		time.Sleep(500 * time.Millisecond)
	}
}

func (s *Socket) Close() error {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return nil
	}
	// Calling this deletes the pointer. It must not be referred to after
	// this.
	C.utp_destroy(s.ctx)
	s.ctx = nil
	s.pc.Close()
	close(s.backlog)
	close(s.nonUtpReads)
	s.closed = true
	return nil
}

func (s *Socket) Addr() net.Addr {
	return s.pc.LocalAddr()
}

func (s *Socket) LocalAddr() net.Addr {
	return s.pc.LocalAddr()
}

func (s *Socket) Accept() (net.Conn, error) {
	nc, ok := <-s.backlog
	if !ok {
		return nil, errors.New("closed")
	}
	return nc, nil
}

func (s *Socket) Dial(addr string) (net.Conn, error) {
	return s.DialTimeout(addr, 0)
}

func (s *Socket) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
	ctx := context.Background()
	if timeout != 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, timeout)
		defer cancel()
	}
	return s.DialContext(ctx, "", addr)
}

func (s *Socket) resolveAddr(network, addr string) (net.Addr, error) {
	if network == "" {
		network = s.Addr().Network()
	}
	return resolveAddr(network, addr)
}

func resolveAddr(network, addr string) (net.Addr, error) {
	switch network {
	case "inproc":
		return inproc.ResolveAddr(network, addr)
	default:
		return net.ResolveUDPAddr(network, addr)
	}
}

// Passing an empty network will use the network of the Socket's listener.
func (s *Socket) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
	c, err := s.NewConn()
	if err != nil {
		return nil, err
	}
	err = c.Connect(ctx, network, addr)
	if err != nil {
		c.Close()
		return nil, err
	}
	return c, nil
}

func (s *Socket) NewConn() (*Conn, error) {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return nil, errors.New("socket closed")
	}
	return s.newConn(C.utp_create_socket(s.ctx)), nil
}

func (s *Socket) pushBacklog(c *Conn) {
	select {
	case s.backlog <- c:
	default:
		c.close()
	}
}

func (s *Socket) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
	p, ok := <-s.nonUtpReads
	if !ok {
		err = errors.New("closed")
		return
	}
	n = copy(b, p.b)
	addr = p.from
	return
}

func (s *Socket) onReadNonUtp(b []byte, from net.Addr) {
	socketNonUtpPacketsReceived.Add(1)
	select {
	case s.nonUtpReads <- packet{append([]byte(nil), b...), from}:
	default:
		// log.Printf("dropped non utp packet: no room in buffer")
		nonUtpPacketsDropped.Add(1)
	}
}

func (s *Socket) SetReadDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) SetWriteDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) SetDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) WriteTo(b []byte, addr net.Addr) (int, error) {
	return s.pc.WriteTo(b, addr)
}

func (s *Socket) ReadBufferLen() int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_get_option(s.ctx, C.UTP_RCVBUF))
}

func (s *Socket) WriteBufferLen() int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_get_option(s.ctx, C.UTP_SNDBUF))
}

func (s *Socket) SetWriteBufferLen(len int) {
	mu.Lock()
	defer mu.Unlock()
	i := C.utp_context_set_option(s.ctx, C.UTP_SNDBUF, C.int(len))
	if i != 0 {
		panic(i)
	}
}

func (s *Socket) SetOption(opt Option, val int) int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_set_option(s.ctx, opt, C.int(val)))
}
<commit_msg>Add support for processing packet batches in C<commit_after>package utp

/*
#include "utp.h"
#include <stdbool.h>

struct utp_process_udp_args {
	const byte *buf;
	size_t len;
	const struct sockaddr *sa;
	socklen_t sal;
};

void process_received_messages(utp_context *ctx, struct utp_process_udp_args *args, size_t argslen)
{
	bool gotUtp = false;
	for (size_t i = 0; i < argslen; i++) {
		struct utp_process_udp_args *a = &args[i];
		//if (!a->len) continue;
		if (utp_process_udp(ctx, a->buf, a->len, a->sa, a->sal)) {
			gotUtp = true;
		}
	}
	if (gotUtp) {
		utp_issue_deferred_acks(ctx);
		utp_check_timeouts(ctx);
	}
}
*/
import "C"
import (
	"context"
	"errors"
	"net"
	"time"

	"github.com/anacrolix/missinggo/inproc"
	"github.com/anacrolix/mmsg"
)

type Socket struct {
	pc            net.PacketConn
	ctx           *C.utp_context
	backlog       chan *Conn
	closed        bool
	conns         map[*C.utp_socket]*Conn
	nonUtpReads   chan packet
	writeDeadline time.Time
	readDeadline  time.Time
}

var (
	_ net.PacketConn = (*Socket)(nil)
	_ net.Listener   = (*Socket)(nil)
)

type packet struct {
	b    []byte
	from net.Addr
}

func listenPacket(network, addr string) (pc net.PacketConn, err error) {
	if network == "inproc" {
		return inproc.ListenPacket(network, addr)
	}
	return net.ListenPacket(network, addr)
}

func NewSocket(network, addr string) (*Socket, error) {
	pc, err := listenPacket(network, addr)
	if err != nil {
		return nil, err
	}
	mu.Lock()
	defer mu.Unlock()
	ctx := C.utp_init(2)
	if ctx == nil {
		panic(ctx)
	}
	ctx.setCallbacks()
	if utpLogging {
		ctx.setOption(C.UTP_LOG_NORMAL, 1)
		ctx.setOption(C.UTP_LOG_MTU, 1)
		ctx.setOption(C.UTP_LOG_DEBUG, 1)
	}
	s := &Socket{
		pc:          pc,
		ctx:         ctx,
		backlog:     make(chan *Conn, 5),
		conns:       make(map[*C.utp_socket]*Conn),
		nonUtpReads: make(chan packet, 100),
	}
	libContextToSocket[ctx] = s
	go s.timeoutChecker()
	go s.packetReader()
	return s, nil
}

func (s *Socket) onLibSocketDestroyed(ls *C.utp_socket) {
	delete(s.conns, ls)
}

func (s *Socket) newConn(us *C.utp_socket) *Conn {
	c := &Conn{
		s:         us,
		localAddr: s.pc.LocalAddr(),
	}
	c.cond.L = &mu
	s.conns[us] = c
	c.writeDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
	c.readDeadlineTimer = time.AfterFunc(-1, c.cond.Broadcast)
	return c
}

const maxNumBuffers = 16

func (s *Socket) packetReader() {
	mc := mmsg.NewConn(s.pc)
	// Increasing the messages increases the memory use, but also means we can
	// reduces utp_issue_deferred_acks and syscalls which should improve
	// efficiency. On the flip side, not all OSs implement batched reads.
	ms := make([]mmsg.Message, func() int {
		if mc.Err() == nil {
			return maxNumBuffers
		} else {
			return 1
		}
	}())
	for i := range ms {
		// The IPv4 UDP limit is allegedly about 64 KiB, and this message has
		// been seen on receiving on Windows with just 0x1000: wsarecvfrom: A
		// message sent on a datagram socket was larger than the internal
		// message buffer or some other network limit, or the buffer used to
		// receive a datagram into was smaller than the datagram itself.
		ms[i].Buffers = [][]byte{make([]byte, 0x10000)}
	}
	// Some crap OSs like Windoze will raise errors in Reads that don't
	// actually mean we should stop.
	consecutiveErrors := 0
	for {
		// In C, all the reads are processed and when it threatens to block,
		// we're supposed to call utp_issue_deferred_acks.
		n, err := mc.RecvMsgs(ms)
		if n == 1 {
			singleMsgRecvs.Add(1)
		}
		if n > 1 {
			multiMsgRecvs.Add(1)
		}
		if err != nil {
			mu.Lock()
			closed := s.closed
			mu.Unlock()
			if closed {
				// We don't care.
				return
			}
			// See https://github.com/anacrolix/torrent/issues/83. If we get
			// an endless stream of errors (such as the PacketConn being
			// Closed outside of our control, this work around may need to be
			// reconsidered.
			Logger.Printf("ignoring socket read error: %s", err)
			consecutiveErrors++
			if consecutiveErrors >= 100 {
				Logger.Print("too many consecutive errors, closing socket")
				s.Close()
				return
			}
			continue
		}
		consecutiveErrors = 0
		expMap.Add("successful mmsg receive calls", 1)
		expMap.Add("received messages", int64(n))
		s.processReceivedMessages(ms[:n])
	}
}

func (s *Socket) processReceivedMessages(ms []mmsg.Message) {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return
	}
	if processPacketsInC {
		var args [maxNumBuffers]C.struct_utp_process_udp_args
		for i, m := range ms {
			a := &args[i]
			a.buf = (*C.byte)(&m.Buffers[0][0])
			a.len = C.size_t(m.N)
			a.sa, a.sal = netAddrToLibSockaddr(m.Addr)
		}
		C.process_received_messages(s.ctx, &args[0], C.size_t(len(ms)))
	} else {
		gotUtp := false
		for _, m := range ms {
			gotUtp = s.processReceivedMessage(m.Buffers[0][:m.N], m.Addr) || gotUtp
		}
		if gotUtp {
			s.afterReceivingUtpMessages()
		}
	}
}

func (s *Socket) afterReceivingUtpMessages() {
	C.utp_issue_deferred_acks(s.ctx)
	// TODO: When is this done in C?
	C.utp_check_timeouts(s.ctx)
}

func (s *Socket) processReceivedMessage(b []byte, addr net.Addr) (utp bool) {
	if s.utpProcessUdp(b, addr) {
		socketUtpPacketsReceived.Add(1)
		return true
	} else {
		s.onReadNonUtp(b, addr)
		return false
	}
}

// Process packet batches entirely from C, reducing CGO overhead. Currently
// requires GODEBUG=cgocheck=0.
const processPacketsInC = false

// Wraps libutp's utp_process_udp, returning relevant information.
func (s *Socket) utpProcessUdp(b []byte, addr net.Addr) (utp bool) {
	sa, sal := netAddrToLibSockaddr(addr)
	if len(b) == 0 {
		// The implementation of utp_process_udp rejects null buffers, and
		// anything smaller than the UTP header size. It's also prone to
		// assert on those, which we don't want to trigger.
		return false
	}
	ret := C.utp_process_udp(s.ctx, (*C.byte)(&b[0]), C.size_t(len(b)), sa, sal)
	switch ret {
	case 1:
		return true
	case 0:
		return false
	default:
		panic(ret)
	}
}

func (s *Socket) timeoutChecker() {
	for {
		mu.Lock()
		if s.closed {
			mu.Unlock()
			return
		}
		// C.utp_issue_deferred_acks(s.ctx)
		C.utp_check_timeouts(s.ctx)
		mu.Unlock()
		time.Sleep(500 * time.Millisecond)
	}
}

func (s *Socket) Close() error {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return nil
	}
	// Calling this deletes the pointer. It must not be referred to after
	// this.
	C.utp_destroy(s.ctx)
	s.ctx = nil
	s.pc.Close()
	close(s.backlog)
	close(s.nonUtpReads)
	s.closed = true
	return nil
}

func (s *Socket) Addr() net.Addr {
	return s.pc.LocalAddr()
}

func (s *Socket) LocalAddr() net.Addr {
	return s.pc.LocalAddr()
}

func (s *Socket) Accept() (net.Conn, error) {
	nc, ok := <-s.backlog
	if !ok {
		return nil, errors.New("closed")
	}
	return nc, nil
}

func (s *Socket) Dial(addr string) (net.Conn, error) {
	return s.DialTimeout(addr, 0)
}

func (s *Socket) DialTimeout(addr string, timeout time.Duration) (net.Conn, error) {
	ctx := context.Background()
	if timeout != 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, timeout)
		defer cancel()
	}
	return s.DialContext(ctx, "", addr)
}

func (s *Socket) resolveAddr(network, addr string) (net.Addr, error) {
	if network == "" {
		network = s.Addr().Network()
	}
	return resolveAddr(network, addr)
}

func resolveAddr(network, addr string) (net.Addr, error) {
	switch network {
	case "inproc":
		return inproc.ResolveAddr(network, addr)
	default:
		return net.ResolveUDPAddr(network, addr)
	}
}

// Passing an empty network will use the network of the Socket's listener.
func (s *Socket) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
	c, err := s.NewConn()
	if err != nil {
		return nil, err
	}
	err = c.Connect(ctx, network, addr)
	if err != nil {
		c.Close()
		return nil, err
	}
	return c, nil
}

func (s *Socket) NewConn() (*Conn, error) {
	mu.Lock()
	defer mu.Unlock()
	if s.closed {
		return nil, errors.New("socket closed")
	}
	return s.newConn(C.utp_create_socket(s.ctx)), nil
}

func (s *Socket) pushBacklog(c *Conn) {
	select {
	case s.backlog <- c:
	default:
		c.close()
	}
}

func (s *Socket) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
	p, ok := <-s.nonUtpReads
	if !ok {
		err = errors.New("closed")
		return
	}
	n = copy(b, p.b)
	addr = p.from
	return
}

func (s *Socket) onReadNonUtp(b []byte, from net.Addr) {
	socketNonUtpPacketsReceived.Add(1)
	select {
	case s.nonUtpReads <- packet{append([]byte(nil), b...), from}:
	default:
		// log.Printf("dropped non utp packet: no room in buffer")
		nonUtpPacketsDropped.Add(1)
	}
}

func (s *Socket) SetReadDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) SetWriteDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) SetDeadline(t time.Time) error {
	panic("not implemented")
}

func (s *Socket) WriteTo(b []byte, addr net.Addr) (int, error) {
	return s.pc.WriteTo(b, addr)
}

func (s *Socket) ReadBufferLen() int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_get_option(s.ctx, C.UTP_RCVBUF))
}

func (s *Socket) WriteBufferLen() int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_get_option(s.ctx, C.UTP_SNDBUF))
}

func (s *Socket) SetWriteBufferLen(len int) {
	mu.Lock()
	defer mu.Unlock()
	i := C.utp_context_set_option(s.ctx, C.UTP_SNDBUF, C.int(len))
	if i != 0 {
		panic(i)
	}
}

func (s *Socket) SetOption(opt Option, val int) int {
	mu.Lock()
	defer mu.Unlock()
	return int(C.utp_context_set_option(s.ctx, opt, C.int(val)))
}
<|endoftext|>


<commit_before>package server

import (
	"crypto/tls"
	"net"
	"strconv"
	"strings"
	"sync"
)

// A data socket is used to send non-control data between the client and
// server.
type DataSocket interface {
	Host() string

	Port() int

	// the standard io.Reader interface
	Read(p []byte) (n int, err error)

	// the standard io.Writer interface
	Write(p []byte) (n int, err error)

	// the standard io.Closer interface
	Close() error
}

type ftpActiveSocket struct {
	conn   *net.TCPConn
	host   string
	port   int
	logger Logger
}

func newActiveSocket(remote string, port int, logger Logger, sessionID string) (DataSocket, error) {
	connectTo := net.JoinHostPort(remote, strconv.Itoa(port))

	logger.Print(sessionID, "Opening active data connection to "+connectTo)

	raddr, err := net.ResolveTCPAddr("tcp", connectTo)

	if err != nil {
		logger.Print(sessionID, err)
		return nil, err
	}

	tcpConn, err := net.DialTCP("tcp", nil, raddr)

	if err != nil {
		logger.Print(sessionID, err)
		return nil, err
	}

	socket := new(ftpActiveSocket)
	socket.conn = tcpConn
	socket.host = remote
	socket.port = port
	socket.logger = logger

	return socket, nil
}

func (socket *ftpActiveSocket) Host() string {
	return socket.host
}

func (socket *ftpActiveSocket) Port() int {
	return socket.port
}

func (socket *ftpActiveSocket) Read(p []byte) (n int, err error) {
	return socket.conn.Read(p)
}

func (socket *ftpActiveSocket) Write(p []byte) (n int, err error) {
	return socket.conn.Write(p)
}

func (socket *ftpActiveSocket) Close() error {
	return socket.conn.Close()
}

type ftpPassiveSocket struct {
	conn       net.Conn
	port       int
	host       string
	ingress    chan []byte
	egress     chan []byte
	logger     Logger
	wg         sync.WaitGroup
	err        error
	tlsConfing *tls.Config
}

func newPassiveSocket(host string, port int, logger Logger, sessionID string, tlsConfing *tls.Config) (DataSocket, error) {
	socket := new(ftpPassiveSocket)
	socket.ingress = make(chan []byte)
	socket.egress = make(chan []byte)
	socket.logger = logger
	socket.host = host
	socket.port = port
	if err := socket.GoListenAndServe(sessionID); err != nil {
		return nil, err
	}
	return socket, nil
}

func (socket *ftpPassiveSocket) Host() string {
	return socket.host
}

func (socket *ftpPassiveSocket) Port() int {
	return socket.port
}

func (socket *ftpPassiveSocket) Read(p []byte) (n int, err error) {
	if err := socket.waitForOpenSocket(); err != nil {
		return 0, err
	}
	return socket.conn.Read(p)
}

func (socket *ftpPassiveSocket) Write(p []byte) (n int, err error) {
	if err := socket.waitForOpenSocket(); err != nil {
		return 0, err
	}
	return socket.conn.Write(p)
}

func (socket *ftpPassiveSocket) Close() error {
	//socket.logger.Print("closing passive data socket")
	if socket.conn != nil {
		return socket.conn.Close()
	}
	return nil
}

func (socket *ftpPassiveSocket) GoListenAndServe(sessionID string) (err error) {
	laddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort("", strconv.Itoa(socket.port)))
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	var listener net.Listener
	listener, err = net.ListenTCP("tcp", laddr)
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	add := listener.Addr()
	parts := strings.Split(add.String(), ":")
	port, err := strconv.Atoi(parts[len(parts)-1])
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	socket.port = port
	socket.wg.Add(1)

	if socket.tlsConfing != nil {
		listener = tls.NewListener(listener, socket.tlsConfing)
	}

	go func() {
		conn, err := listener.Accept()
		socket.wg.Done()
		if err != nil {
			socket.err = err
			return
		}
		socket.err = nil
		socket.conn = conn
	}()
	return nil
}

func (socket *ftpPassiveSocket) waitForOpenSocket() error {
	if socket.conn != nil {
		return nil
	}
	socket.wg.Wait()
	return socket.err
}
<commit_msg>Use tlsConfig in passive socket<commit_after>package server

import (
	"crypto/tls"
	"net"
	"strconv"
	"strings"
	"sync"
)

// A data socket is used to send non-control data between the client and
// server.
type DataSocket interface {
	Host() string

	Port() int

	// the standard io.Reader interface
	Read(p []byte) (n int, err error)

	// the standard io.Writer interface
	Write(p []byte) (n int, err error)

	// the standard io.Closer interface
	Close() error
}

type ftpActiveSocket struct {
	conn   *net.TCPConn
	host   string
	port   int
	logger Logger
}

func newActiveSocket(remote string, port int, logger Logger, sessionID string) (DataSocket, error) {
	connectTo := net.JoinHostPort(remote, strconv.Itoa(port))

	logger.Print(sessionID, "Opening active data connection to "+connectTo)

	raddr, err := net.ResolveTCPAddr("tcp", connectTo)

	if err != nil {
		logger.Print(sessionID, err)
		return nil, err
	}

	tcpConn, err := net.DialTCP("tcp", nil, raddr)

	if err != nil {
		logger.Print(sessionID, err)
		return nil, err
	}

	socket := new(ftpActiveSocket)
	socket.conn = tcpConn
	socket.host = remote
	socket.port = port
	socket.logger = logger

	return socket, nil
}

func (socket *ftpActiveSocket) Host() string {
	return socket.host
}

func (socket *ftpActiveSocket) Port() int {
	return socket.port
}

func (socket *ftpActiveSocket) Read(p []byte) (n int, err error) {
	return socket.conn.Read(p)
}

func (socket *ftpActiveSocket) Write(p []byte) (n int, err error) {
	return socket.conn.Write(p)
}

func (socket *ftpActiveSocket) Close() error {
	return socket.conn.Close()
}

type ftpPassiveSocket struct {
	conn       net.Conn
	port       int
	host       string
	ingress    chan []byte
	egress     chan []byte
	logger     Logger
	wg         sync.WaitGroup
	err        error
	tlsConfig  *tls.Config
}

func newPassiveSocket(host string, port int, logger Logger, sessionID string, tlsConfig *tls.Config) (DataSocket, error) {
	socket := new(ftpPassiveSocket)
	socket.ingress = make(chan []byte)
	socket.egress = make(chan []byte)
	socket.logger = logger
	socket.host = host
	socket.port = port
	socket.tlsConfig = tlsConfig
	if err := socket.GoListenAndServe(sessionID); err != nil {
		return nil, err
	}
	return socket, nil
}

func (socket *ftpPassiveSocket) Host() string {
	return socket.host
}

func (socket *ftpPassiveSocket) Port() int {
	return socket.port
}

func (socket *ftpPassiveSocket) Read(p []byte) (n int, err error) {
	if err := socket.waitForOpenSocket(); err != nil {
		return 0, err
	}
	return socket.conn.Read(p)
}

func (socket *ftpPassiveSocket) Write(p []byte) (n int, err error) {
	if err := socket.waitForOpenSocket(); err != nil {
		return 0, err
	}
	return socket.conn.Write(p)
}

func (socket *ftpPassiveSocket) Close() error {
	//socket.logger.Print("closing passive data socket")
	if socket.conn != nil {
		return socket.conn.Close()
	}
	return nil
}

func (socket *ftpPassiveSocket) GoListenAndServe(sessionID string) (err error) {
	laddr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort("", strconv.Itoa(socket.port)))
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	var listener net.Listener
	listener, err = net.ListenTCP("tcp", laddr)
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	add := listener.Addr()
	parts := strings.Split(add.String(), ":")
	port, err := strconv.Atoi(parts[len(parts)-1])
	if err != nil {
		socket.logger.Print(sessionID, err)
		return
	}

	socket.port = port
	socket.wg.Add(1)

	if socket.tlsConfig != nil {
		listener = tls.NewListener(listener, socket.tlsConfig)
	}

	go func() {
		conn, err := listener.Accept()
		socket.wg.Done()
		if err != nil {
			socket.err = err
			return
		}
		socket.err = nil
		socket.conn = conn
	}()
	return nil
}

func (socket *ftpPassiveSocket) waitForOpenSocket() error {
	if socket.conn != nil {
		return nil
	}
	socket.wg.Wait()
	return socket.err
}
<|endoftext|>


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

package pronom

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"
)

type FormatInfo struct {
	Name     string
	Version  string
	MIMEType string
}

type Identifier struct {
	p       *pronom
	Name    string
	Details string
	Infos   map[string]FormatInfo

	EStart int
	EPuids []string // slice of puids that corresponds to the extension matcher's int signatures
	CStart int
	CPuids []string
	BStart int
	BPuids []string         // slice of puids that corresponds to the bytematcher's int signatures
	PuidsB map[string][]int // map of puids to slices of bytematcher int signatures
}

func New(opts ...config.Option) (*Identifier, error) {
	for _, v := range opts {
		v()
	}
	pronom, err := NewPronom()
	if err != nil {
		return nil, err
	}
	return pronom.identifier(), nil
}

func (i *Identifier) Add(m core.Matcher) error {
	return i.p.add(m)
}

func (i *Identifier) Yaml() string {
	return fmt.Sprintf(" - name : %v\n details : %v\n",
		i.Name, i.Details)
}

func (i *Identifier) Save(w io.Writer) (int, error) {
	buf := &bytes.Buffer{}
	enc := gob.NewEncoder(buf)
	err := enc.Encode(i)
	if err != nil {
		return 0, err
	}
	sz := buf.Len()
	_, err = buf.WriteTo(w)
	if err != nil {
		return 0, err
	}
	return sz, nil
}

func Load(r io.Reader) (*Identifier, error) {
	i := &Identifier{}
	dec := gob.NewDecoder(r)
	err := dec.Decode(i)
	if err != nil {
		return nil, err
	}
	return i, nil
}

func (i *Identifier) Recorder() core.Recorder {
	return &Recorder{i, make(pids, 0, 10), 0.1}
}

type Recorder struct {
	*Identifier
	ids    pids
	cscore float64
}

func (r *Recorder) Record(m core.MatcherType, res core.Result) bool {

	switch m {
	default:
		return false
	case core.ExtensionMatcher:
		if res.Index() >= r.EStart && res.Index() < r.EStart+len(r.EPuids) {
			idx := res.Index() - r.EStart
			r.ids = add(r.ids, r.EPuids[idx], r.Infos[r.EPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	case core.ContainerMatcher:
		// add zip default
		if res.Index() < 0 {
			r.cscore *= 1.1
			r.ids = add(r.ids, "x-fmt/263", r.Infos["x-fmt/263"], res.Basis(), r.cscore) // not great to have this hardcoded
			return false
		}
		if res.Index() >= r.CStart && res.Index() < r.CStart+len(r.CPuids) {
			idx := res.Index() - r.CStart
			r.cscore *= 1.1
			r.ids = add(r.ids, r.CPuids[idx], r.Infos[r.CPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	case core.ByteMatcher:
		if res.Index() >= r.BStart && res.Index() < r.BStart+len(r.BPuids) {
			idx := res.Index() - r.BStart
			r.cscore *= 1.1
			r.ids = add(r.ids, r.BPuids[idx], r.Infos[r.BPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	}
}

func (r *Recorder) Satisfied() bool {
	if r.cscore == 0.1 {
		return false
	}
	return true
}

func (r *Recorder) Report(res chan core.Identification) {
	if len(r.ids) > 0 {
		sort.Sort(r.ids)
		conf := r.ids[0].confidence
		// if we've only got extension matches, check if those matches are ruled out by lack of byte match
		// add warnings too
		if conf == 0.1 {
			nids := make([]Identification, 0, len(r.ids))
			for _, v := range r.ids {
				if _, ok := r.PuidsB[v.puid]; !ok {
					v.warning = "match on extension only"
					nids = append(nids, v)
				}
			}
			if len(nids) == 0 {
				poss := make([]string, len(r.ids))
				for i, v := range r.ids {
					poss[i] = v.puid
				}
				nids = []Identification{Identification{"UNKNOWN", "", "", "", nil, fmt.Sprintf("no match; possibilities based on extension are %v", strings.Join(poss, ", ")), 0}}
			}
			r.ids = nids
		}
		res <- r.ids[0]
		if len(r.ids) > 1 {
			for i, v := range r.ids[1:] {
				if v.confidence == conf {
					res <- r.ids[i+1]
				} else {
					break
				}
			}
		}
	} else {
		res <- Identification{"UNKNOWN", "", "", "", nil, "warning: \"no match\"", 0}
	}
}

type Identification struct {
	puid       string
	name       string
	version    string
	mime       string
	basis      []string
	warning    string
	confidence float64
}

func (id Identification) String() string {
	return id.puid
}

func quoteText(s string) string {
	if len(s) == 0 {
		return s
	}
	return "\"" + s + "\""
}

func (id Identification) Yaml() string {
	var basis string
	if len(id.basis) > 0 {
		basis = quoteText(strings.Join(id.basis, "; "))
	}
	return fmt.Sprintf("  - puid    : %v\n    format  : %v\n    version : %v\n    mime    : %v\n    basis   : %v\n    warning : %v\n",
		id.puid, quoteText(id.name), quoteText(id.version), quoteText(id.mime), basis, quoteText(id.warning))
}

func (id Identification) Json() string {
	type jsonid struct {
		Puid    string `json:"puid"`
		Name    string `json:"name"`
		Version string `json:"version"`
		Mime    string `json:"mime"`
		Basis   string `json:"basis"`
		Warning string `json:"warning"`
	}
	var basis string
	if len(id.basis) > 0 {
		basis = strings.Join(id.basis, "; ")
	}
	b, err := json.Marshal(jsonid{id.puid, id.name, id.version, id.mime, basis, id.warning})
	if err != nil {
		return `{
			"puid": "",
			"name": "",
			"version": "",
			"mime": "",
			"basis": "",
			"warning": "json encoding error"
			}`
	}
	return string(b)
}

type pids []Identification

func (p pids) Len() int { return len(p) }

func (p pids) Less(i, j int) bool { return p[j].confidence < p[i].confidence }

func (p pids) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

func add(p pids, f string, info FormatInfo, basis string, c float64) pids {
	for i, v := range p {
		if v.puid == f {
			p[i].confidence += c
			p[i].basis = append(p[i].basis, basis)
			return p
		}
	}
	return append(p, Identification{f, info.Name, info.Version, info.MIMEType, []string{basis}, "", c})
}
<commit_msg>tidying yaml output<commit_after>// Copyright 2014 Richard Lehane. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pronom

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/richardlehane/siegfried/config"
	"github.com/richardlehane/siegfried/pkg/core"
)

type FormatInfo struct {
	Name     string
	Version  string
	MIMEType string
}

type Identifier struct {
	p       *pronom
	Name    string
	Details string
	Infos   map[string]FormatInfo

	EStart int
	EPuids []string // slice of puids that corresponds to the extension matcher's int signatures
	CStart int
	CPuids []string
	BStart int
	BPuids []string         // slice of puids that corresponds to the bytematcher's int signatures
	PuidsB map[string][]int // map of puids to slices of bytematcher int signatures
}

func New(opts ...config.Option) (*Identifier, error) {
	for _, v := range opts {
		v()
	}
	pronom, err := NewPronom()
	if err != nil {
		return nil, err
	}
	return pronom.identifier(), nil
}

func (i *Identifier) Add(m core.Matcher) error {
	return i.p.add(m)
}

func (i *Identifier) Yaml() string {
	return fmt.Sprintf("  - name    : %v\n    details : %v\n",
		i.Name, i.Details)
}

func (i *Identifier) Save(w io.Writer) (int, error) {
	buf := &bytes.Buffer{}
	enc := gob.NewEncoder(buf)
	err := enc.Encode(i)
	if err != nil {
		return 0, err
	}
	sz := buf.Len()
	_, err = buf.WriteTo(w)
	if err != nil {
		return 0, err
	}
	return sz, nil
}

func Load(r io.Reader) (*Identifier, error) {
	i := &Identifier{}
	dec := gob.NewDecoder(r)
	err := dec.Decode(i)
	if err != nil {
		return nil, err
	}
	return i, nil
}

func (i *Identifier) Recorder() core.Recorder {
	return &Recorder{i, make(pids, 0, 10), 0.1}
}

type Recorder struct {
	*Identifier
	ids    pids
	cscore float64
}

func (r *Recorder) Record(m core.MatcherType, res core.Result) bool {

	switch m {
	default:
		return false
	case core.ExtensionMatcher:
		if res.Index() >= r.EStart && res.Index() < r.EStart+len(r.EPuids) {
			idx := res.Index() - r.EStart
			r.ids = add(r.ids, r.Name, r.EPuids[idx], r.Infos[r.EPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	case core.ContainerMatcher:
		// add zip default
		if res.Index() < 0 {
			r.cscore *= 1.1
			r.ids = add(r.ids, r.Name, "x-fmt/263", r.Infos["x-fmt/263"], res.Basis(), r.cscore) // not great to have this hardcoded
			return false
		}
		if res.Index() >= r.CStart && res.Index() < r.CStart+len(r.CPuids) {
			idx := res.Index() - r.CStart
			r.cscore *= 1.1
			r.ids = add(r.ids, r.Name, r.CPuids[idx], r.Infos[r.CPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	case core.ByteMatcher:
		if res.Index() >= r.BStart && res.Index() < r.BStart+len(r.BPuids) {
			idx := res.Index() - r.BStart
			r.cscore *= 1.1
			r.ids = add(r.ids, r.Name, r.BPuids[idx], r.Infos[r.BPuids[idx]], res.Basis(), r.cscore)
			return true
		} else {
			return false
		}
	}
}

func (r *Recorder) Satisfied() bool {
	if r.cscore == 0.1 {
		return false
	}
	return true
}

func (r *Recorder) Report(res chan core.Identification) {
	if len(r.ids) > 0 {
		sort.Sort(r.ids)
		conf := r.ids[0].confidence
		// if we've only got extension matches, check if those matches are ruled out by lack of byte match
		// add warnings too
		if conf == 0.1 {
			nids := make([]Identification, 0, len(r.ids))
			for _, v := range r.ids {
				if _, ok := r.PuidsB[v.puid]; !ok {
					v.warning = "match on extension only"
					nids = append(nids, v)
				}
			}
			if len(nids) == 0 {
				poss := make([]string, len(r.ids))
				for i, v := range r.ids {
					poss[i] = v.puid
				}
				nids = []Identification{Identification{r.Name, "UNKNOWN", "", "", "", nil, fmt.Sprintf("no match; possibilities based on extension are %v", strings.Join(poss, ", ")), 0}}
			}
			r.ids = nids
		}
		res <- r.ids[0]
		if len(r.ids) > 1 {
			for i, v := range r.ids[1:] {
				if v.confidence == conf {
					res <- r.ids[i+1]
				} else {
					break
				}
			}
		}
	} else {
		res <- Identification{r.Name, "UNKNOWN", "", "", "", nil, "no match", 0}
	}
}

type Identification struct {
	identifier string
	puid       string
	name       string
	version    string
	mime       string
	basis      []string
	warning    string
	confidence float64
}

func (id Identification) String() string {
	return id.puid
}

func quoteText(s string) string {
	if len(s) == 0 {
		return s
	}
	return "\"" + s + "\""
}

func (id Identification) Yaml() string {
	var basis string
	if len(id.basis) > 0 {
		basis = quoteText(strings.Join(id.basis, "; "))
	}
	return fmt.Sprintf("  - id      : %v\n    puid    : %v\n    format  : %v\n    version : %v\n    mime    : %v\n    basis   : %v\n    warning : %v\n",
		id.identifier, id.puid, quoteText(id.name), quoteText(id.version), quoteText(id.mime), basis, quoteText(id.warning))
}

func (id Identification) Json() string {
	type jsonid struct {
		Puid    string `json:"puid"`
		Name    string `json:"name"`
		Version string `json:"version"`
		Mime    string `json:"mime"`
		Basis   string `json:"basis"`
		Warning string `json:"warning"`
	}
	var basis string
	if len(id.basis) > 0 {
		basis = strings.Join(id.basis, "; ")
	}
	b, err := json.Marshal(jsonid{id.puid, id.name, id.version, id.mime, basis, id.warning})
	if err != nil {
		return `{
			"puid": "",
			"name": "",
			"version": "",
			"mime": "",
			"basis": "",
			"warning": "json encoding error"
			}`
	}
	return string(b)
}

type pids []Identification

func (p pids) Len() int { return len(p) }

func (p pids) Less(i, j int) bool { return p[j].confidence < p[i].confidence }

func (p pids) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

func add(p pids, id string, f string, info FormatInfo, basis string, c float64) pids {
	for i, v := range p {
		if v.puid == f {
			p[i].confidence += c
			p[i].basis = append(p[i].basis, basis)
			return p
		}
	}
	return append(p, Identification{id, f, info.Name, info.Version, info.MIMEType, []string{basis}, "", c})
}
<|endoftext|>


<commit_before>package config

import (
	"io/ioutil"

	"encoding/json"

	"github.com/golang/glog"
	"github.com/openshift/source-to-image/pkg/sti/api"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// DefaultConfigPath specifies the default location of the STI config file
const DefaultConfigPath = ".stifile"

// Config represents a basic serialization for the STI build options
type Config struct {
	Source    string            `json:"source" yaml:"source"`
	BaseImage string            `json:"baseImage" yaml:"baseImage"`
	Tag       string            `json:"tag" yaml:"tag"`
	Flags     map[string]string `json:"flags,omitempty" yaml:"flags,omitempty"`
}

// Save persists the STI command line arguments into disk
func Save(req *api.Request, cmd *cobra.Command) {
	c := Config{
		BaseImage: req.BaseImage,
		Source:    req.Source,
		Tag:       req.Tag,
	}
	c.Flags = make(map[string]string)
	// Store only flags that has changed
	cmd.Flags().Visit(func(f *pflag.Flag) {
		c.Flags[f.Name] = f.Value.String()
	})
	data, err := json.Marshal(c)
	if err != nil {
		glog.V(1).Infof("Unable to serialize to %s: %v", DefaultConfigPath, err)
		return
	}
	if err := ioutil.WriteFile(DefaultConfigPath, data, 0644); err != nil {
		glog.V(1).Infof("Unable to save %s: %v", DefaultConfigPath, err)
	}
	return
}

// Restore loads the arguments from disk and prefill the Request
func Restore(req *api.Request, cmd *cobra.Command) {
	data, err := ioutil.ReadFile(DefaultConfigPath)
	if err != nil {
		glog.V(1).Infof("Unable to restore %s: %v", err)
		return
	}
	c := Config{}
	if err := json.Unmarshal(data, &c); err != nil {
		glog.V(1).Infof("Unable to parse %s: %v", DefaultConfigPath, err)
		return
	}
	req.BaseImage = c.BaseImage
	req.Source = c.Source
	req.Tag = c.Tag
	for name, value := range c.Flags {
		// Do not change flags that user sets. Allow overriding of stored flags.
		if cmd.Flag(name).Changed {
			continue
		}
		cmd.Flags().Set(name, value)
	}
}
<commit_msg>Initialize Flags on the spot<commit_after>package config

import (
	"io/ioutil"

	"encoding/json"

	"github.com/golang/glog"
	"github.com/openshift/source-to-image/pkg/sti/api"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

// DefaultConfigPath specifies the default location of the STI config file
const DefaultConfigPath = ".stifile"

// Config represents a basic serialization for the STI build options
type Config struct {
	Source    string            `json:"source" yaml:"source"`
	BaseImage string            `json:"baseImage" yaml:"baseImage"`
	Tag       string            `json:"tag" yaml:"tag"`
	Flags     map[string]string `json:"flags,omitempty" yaml:"flags,omitempty"`
}

// Save persists the STI command line arguments into disk
func Save(req *api.Request, cmd *cobra.Command) {
	c := Config{
		BaseImage: req.BaseImage,
		Source:    req.Source,
		Tag:       req.Tag,
		Flags:     make(map[string]string),
	}
	// Store only flags that have changed
	cmd.Flags().Visit(func(f *pflag.Flag) {
		c.Flags[f.Name] = f.Value.String()
	})
	data, err := json.Marshal(c)
	if err != nil {
		glog.V(1).Infof("Unable to serialize to %s: %v", DefaultConfigPath, err)
		return
	}
	if err := ioutil.WriteFile(DefaultConfigPath, data, 0644); err != nil {
		glog.V(1).Infof("Unable to save %s: %v", DefaultConfigPath, err)
	}
	return
}

// Restore loads the arguments from disk and prefill the Request
func Restore(req *api.Request, cmd *cobra.Command) {
	data, err := ioutil.ReadFile(DefaultConfigPath)
	if err != nil {
		glog.V(1).Infof("Unable to restore %s: %v", err)
		return
	}
	c := Config{}
	if err := json.Unmarshal(data, &c); err != nil {
		glog.V(1).Infof("Unable to parse %s: %v", DefaultConfigPath, err)
		return
	}
	req.BaseImage = c.BaseImage
	req.Source = c.Source
	req.Tag = c.Tag
	for name, value := range c.Flags {
		// Do not change flags that user sets. Allow overriding of stored flags.
		if cmd.Flag(name).Changed {
			continue
		}
		cmd.Flags().Set(name, value)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"

	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/service"
)

type TagList struct{}

type tag struct {
	Name             string
	Apps             []string
	ServiceInstances map[string][]string
}

func (t *TagList) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "tag-list",
		Usage: "tag-list",
		Desc:  `Retrieves and shows a list of tags with the respective apps and service instances.`,
	}
}

func (t *TagList) Run(context *cmd.Context, client *cmd.Client) error {
	apps, err := loadApps(client)
	if err != nil {
		return err
	}
	services, err := loadServices(client)
	if err != nil {
		return err
	}
	return t.Show(apps, services, context)
}

func (t *TagList) Show(apps []app, services []service.ServiceModel, context *cmd.Context) error {
	tagList := processTags(apps, services)
	if len(tagList) > 0 {
		table := cmd.NewTable()
		table.Headers = cmd.Row([]string{"Tag", "Apps", "Service Instances"})
		for _, tagName := range sortedTags(tagList) {
			t := tagList[tagName]
			instanceNames := []string{}
			for _, serviceName := range sortedServices(t.ServiceInstances) {
				instances := t.ServiceInstances[serviceName]
				instanceNames = append(instanceNames, fmt.Sprintf("%s: %s", serviceName, strings.Join(instances, ", ")))
			}
			table.AddRow(cmd.Row([]string{t.Name, strings.Join(t.Apps, ", "), strings.Join(instanceNames, "\n")}))
		}
		table.LineSeparator = true
		table.Sort()
		context.Stdout.Write(table.Bytes())
	}
	return nil
}

func loadApps(client *cmd.Client) ([]app, error) {
	result, err := getFromUrl("/apps", client)
	if err != nil {
		return nil, err
	}
	var apps []app
	err = json.Unmarshal(result, &apps)
	return apps, nil
}

func loadServices(client *cmd.Client) ([]service.ServiceModel, error) {
	result, err := getFromUrl("/services", client)
	if err != nil {
		return nil, err
	}
	var services []service.ServiceModel
	err = json.Unmarshal(result, &services)
	return services, nil
}

func getFromUrl(path string, client *cmd.Client) ([]byte, error) {
	url, err := cmd.GetURL(path)
	if err != nil {
		return nil, err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != http.StatusOK {
		return nil, nil
	}
	defer response.Body.Close()
	return ioutil.ReadAll(response.Body)
}

func processTags(apps []app, services []service.ServiceModel) map[string]*tag {
	tagList := make(map[string]*tag)
	for _, app := range apps {
		for _, t := range app.Tags {
			if _, ok := tagList[t]; !ok {
				tagList[t] = &tag{Name: t, Apps: []string{app.Name}}
			} else {
				tagList[t].Apps = append(tagList[t].Apps, app.Name)
			}
		}
	}
	for _, s := range services {
		for _, instance := range s.ServiceInstances {
			for _, t := range instance.Tags {
				if _, ok := tagList[t]; !ok {
					tagList[t] = &tag{Name: t, ServiceInstances: make(map[string][]string)}
				}
				if tagList[t].ServiceInstances == nil {
					tagList[t].ServiceInstances = make(map[string][]string)
				}
				tagList[t].ServiceInstances[s.Service] = append(tagList[t].ServiceInstances[s.Service], instance.Name)
			}
		}
	}
	return tagList
}

func sortedTags(tagList map[string]*tag) []string {
	tagNames := make([]string, len(tagList))
	i := 0
	for t := range tagList {
		tagNames[i] = t
		i++
	}
	sort.Strings(tagNames)
	return tagNames
}

func sortedServices(services map[string][]string) []string {
	serviceNames := make([]string, len(services))
	i := 0
	for s := range services {
		serviceNames[i] = s
		i++
	}
	sort.Strings(serviceNames)
	return serviceNames
}
<commit_msg>client: refactor tag-list<commit_after>// Copyright 2017 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package client

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"sort"
	"strings"

	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/service"
)

type TagList struct{}

type tag struct {
	Name             string
	Apps             []string
	ServiceInstances map[string][]string
}

func (t *TagList) Info() *cmd.Info {
	return &cmd.Info{
		Name:  "tag-list",
		Usage: "tag-list",
		Desc:  `Retrieves and shows a list of tags with the respective apps and service instances.`,
	}
}

func (t *TagList) Run(context *cmd.Context, client *cmd.Client) error {
	apps, err := loadApps(client)
	if err != nil {
		return err
	}
	services, err := loadServices(client)
	if err != nil {
		return err
	}
	return t.Show(apps, services, context)
}

func (t *TagList) Show(apps []app, services []service.ServiceModel, context *cmd.Context) error {
	tagList := processTags(apps, services)
	if len(tagList) > 0 {
		table := cmd.NewTable()
		table.Headers = cmd.Row([]string{"Tag", "Apps", "Service Instances"})
		for _, tagName := range sortedTags(tagList) {
			t := tagList[tagName]
			instanceNames := make([]string, len(t.ServiceInstances))
			for i, serviceName := range sortedServices(t.ServiceInstances) {
				instances := t.ServiceInstances[serviceName]
				instanceNames[i] = fmt.Sprintf("%s: %s", serviceName, strings.Join(instances, ", "))
			}
			table.AddRow(cmd.Row([]string{t.Name, strings.Join(t.Apps, ", "), strings.Join(instanceNames, "\n")}))
		}
		table.LineSeparator = true
		table.Sort()
		context.Stdout.Write(table.Bytes())
	}
	return nil
}

func loadApps(client *cmd.Client) ([]app, error) {
	result, err := getFromURL("/apps", client)
	if err != nil {
		return nil, err
	}
	var apps []app
	err = json.Unmarshal(result, &apps)
	return apps, nil
}

func loadServices(client *cmd.Client) ([]service.ServiceModel, error) {
	result, err := getFromURL("/services", client)
	if err != nil {
		return nil, err
	}
	var services []service.ServiceModel
	err = json.Unmarshal(result, &services)
	return services, nil
}

func getFromURL(path string, client *cmd.Client) ([]byte, error) {
	url, err := cmd.GetURL(path)
	if err != nil {
		return nil, err
	}
	request, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	response, err := client.Do(request)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != http.StatusOK {
		return nil, nil
	}
	defer response.Body.Close()
	return ioutil.ReadAll(response.Body)
}

func processTags(apps []app, services []service.ServiceModel) map[string]*tag {
	tagList := make(map[string]*tag)
	for _, app := range apps {
		for _, t := range app.Tags {
			if _, ok := tagList[t]; !ok {
				tagList[t] = &tag{Name: t, Apps: []string{app.Name}}
			} else {
				tagList[t].Apps = append(tagList[t].Apps, app.Name)
			}
		}
	}
	for _, s := range services {
		for _, instance := range s.ServiceInstances {
			for _, t := range instance.Tags {
				if _, ok := tagList[t]; !ok {
					tagList[t] = &tag{Name: t, ServiceInstances: make(map[string][]string)}
				}
				si := &tagList[t].ServiceInstances
				if *si == nil {
					*si = make(map[string][]string)
				}
				(*si)[s.Service] = append((*si)[s.Service], instance.Name)
			}
		}
	}
	return tagList
}

func sortedTags(tagList map[string]*tag) []string {
	tagNames := make([]string, len(tagList))
	i := 0
	for t := range tagList {
		tagNames[i] = t
		i++
	}
	sort.Strings(tagNames)
	return tagNames
}

func sortedServices(services map[string][]string) []string {
	serviceNames := make([]string, len(services))
	i := 0
	for s := range services {
		serviceNames[i] = s
		i++
	}
	sort.Strings(serviceNames)
	return serviceNames
}
<|endoftext|>


<commit_before>package stripe

import (
	"encoding/json"
)

// SourceStatus represents the possible statuses of a source object.
type SourceStatus string

const (
	// SourceStatusCanceled we canceled the source along with any side-effect
	// it had (returned funds to customers if any were sent).
	SourceStatusCanceled SourceStatus = "canceled"

	// SourceStatusChargeable the source is ready to be charged (once if usage
	// is `single_use`, repeatidly otherwise).
	SourceStatusChargeable SourceStatus = "chargeable"

	// SourceStatusConsumed the source is `single_use` usage and has been
	// charged already.
	SourceStatusConsumed SourceStatus = "consumed"

	// SourceStatusFailed the source is no longer usable.
	SourceStatusFailed SourceStatus = "failed"

	// SourceStatusPending the source is freshly created and not yet
	// chargeable. The flow should indicate how to authenticate it with your
	// customer.
	SourceStatusPending SourceStatus = "pending"
)

// SourceFlow represents the possible flows of a source object.
type SourceFlow string

const (
	// FlowNone no particular authentication is involved the source should
	// become chargeable directly or asyncrhonously.
	FlowNone SourceFlow = "none"

	// FlowReceiver a receiver address should be communicated to the customer
	// to push funds to it.
	FlowReceiver SourceFlow = "receiver"

	// FlowRedirect a redirect is required to authenticate the source.
	FlowRedirect SourceFlow = "redirect"

	// FlowVerification a verification code should be communicated by the
	// customer to authenticate the source.
	FlowVerification SourceFlow = "verification"
)

// SourceUsage represents the possible usages of a source object.
type SourceUsage string

const (
	// UsageReusable the source can be charged multiple times for arbitrary
	// amounts.
	UsageReusable SourceUsage = "reusable"

	// UsageSingleUse the source can only be charged once for the specified
	// amount and currency.
	UsageSingleUse SourceUsage = "single_use"
)

type SourceOwnerParams struct {
	Address *AddressParams `form:"address"`
	Email   string         `form:"email"`
	Name    string         `form:"name"`
	Phone   string         `form:"phone"`
}

type RedirectParams struct {
	ReturnURL string `form:"return_url"`
}

type SourceObjectParams struct {
	Params   `form:"*"`
	Amount   uint64             `form:"amount"`
	Currency Currency           `form:"currency"`
	Customer string             `form:"customer"`
	Flow     SourceFlow         `form:"flow"`
	Owner    *SourceOwnerParams `form:"owner"`
	Redirect *RedirectParams    `form:"redirect"`
	Token    string             `form:"token"`
	Type     string             `form:"type"`
	TypeData map[string]string  `form:"*"`
	Usage    SourceUsage        `form:"usage"`
}

type SourceOwner struct {
	Address         *Address `json:"address,omitempty"`
	Email           string   `json:"email"`
	Name            string   `json:"name"`
	Phone           string   `json:"phone"`
	VerifiedAddress *Address `json:"verified_address,omitempty"`
	VerifiedEmail   string   `json:"verified_email"`
	VerifiedName    string   `json:"verified_name"`
	VerifiedPhone   string   `json:"verified_phone"`
}

// RedirectFlowStatus represents the possible statuses of a redirect flow.
type RedirectFlowStatus string

const (
	RedirectFlowStatusFailed    RedirectFlowStatus = "failed"
	RedirectFlowStatusPending   RedirectFlowStatus = "pending"
	RedirectFlowStatusSucceeded RedirectFlowStatus = "succeeded"
)

// ReceiverFlow informs of the state of a redirect authentication flow.
type RedirectFlow struct {
	ReturnURL string             `json:"return_url"`
	Status    RedirectFlowStatus `json:"status"`
	URL       string             `json:"url"`
}

// RefundAttributesStatus are the possible status of a receiver's refund
// attributes.
type RefundAttributesStatus string

const (
	// RefundAttributesAvailable the refund attributes are available
	RefundAttributesAvailable RefundAttributesStatus = "available"

	// RefundAttributesMissing the refund attributes are missing
	RefundAttributesMissing RefundAttributesStatus = "missing"

	// RefundAttributesRequested the refund attributes have been requested
	RefundAttributesRequested RefundAttributesStatus = "requested"
)

// RefundAttributesMethod are the possible method to retrieve a receiver's
// refund attributes.
type RefundAttributesMethod string

const (
	// RefundAttributesEmail the refund attributes are automatically collected over email
	RefundAttributesEmail RefundAttributesMethod = "email"

	// RefundAttributesManual the refund attributes should be collected by the user
	RefundAttributesManual RefundAttributesMethod = "manual"
)

// ReceiverFlow informs of the state of a receiver authentication flow.
type ReceiverFlow struct {
	Address                string                 `json:"address"`
	AmountCharged          int64                  `json:"amount_charged"`
	AmountReceived         int64                  `json:"amount_received"`
	AmountReturned         int64                  `json:"amount_returned"`
	RefundAttributesMethod RefundAttributesMethod `json:"refund_attributes_method"`
	RefundAttributesStatus RefundAttributesStatus `json:"refund_attributes_status"`
}

// VerificationFlowStatus represents the possible statuses of a verification
// flow.
type VerificationFlowStatus string

const (
	VerificationFlowStatusFailed    VerificationFlowStatus = "failed"
	VerificationFlowStatusPending   VerificationFlowStatus = "pending"
	VerificationFlowStatusSucceeded VerificationFlowStatus = "succeeded"
)

// ReceiverFlow informs of the state of a verification authentication flow.
type VerificationFlow struct {
	AttemptsRemaining uint64             `json:"attempts_remaining"`
	Status            RedirectFlowStatus `json:"status"`
}

type Source struct {
	Amount       int64             `json:"amount"`
	ClientSecret string            `json:"client_secret"`
	Created      int64             `json:"created"`
	Currency     Currency          `json:"currency"`
	Flow         SourceFlow        `json:"flow"`
	ID           string            `json:"id"`
	Live         bool              `json:"livemode"`
	Meta         map[string]string `json:"metadata"`
	Owner        SourceOwner       `json:"owner"`
	Receiver     *ReceiverFlow     `json:"receiver,omitempty"`
	Redirect     *RedirectFlow     `json:"redirect,omitempty"`
	Status       SourceStatus      `json:"status"`
	Type         string            `json:"type"`
	TypeData     map[string]interface{}
	Usage        SourceUsage       `json:"usage"`
	Verification *VerificationFlow `json:"verification,omitempty"`
}

// UnmarshalJSON handles deserialization of an Source. This custom unmarshaling
// is needed to extract the type specific data (accessible under `TypeData`)
// but stored in JSON under a hash named after the `type` of the source.
func (s *Source) UnmarshalJSON(data []byte) error {
	type source Source
	var ss source
	err := json.Unmarshal(data, &ss)
	if err != nil {
		return err
	}
	*s = Source(ss)

	var raw map[string]interface{}
	err = json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	if d, ok := raw[s.Type]; ok {
		if m, ok := d.(map[string]interface{}); ok {
			s.TypeData = m
		}
	}

	return nil
}
<commit_msg>Fix Source creation so that TypeData is passed properly<commit_after>package stripe

import (
	"encoding/json"

	"github.com/stripe/stripe-go/form"
)

// SourceStatus represents the possible statuses of a source object.
type SourceStatus string

const (
	// SourceStatusCanceled we canceled the source along with any side-effect
	// it had (returned funds to customers if any were sent).
	SourceStatusCanceled SourceStatus = "canceled"

	// SourceStatusChargeable the source is ready to be charged (once if usage
	// is `single_use`, repeatidly otherwise).
	SourceStatusChargeable SourceStatus = "chargeable"

	// SourceStatusConsumed the source is `single_use` usage and has been
	// charged already.
	SourceStatusConsumed SourceStatus = "consumed"

	// SourceStatusFailed the source is no longer usable.
	SourceStatusFailed SourceStatus = "failed"

	// SourceStatusPending the source is freshly created and not yet
	// chargeable. The flow should indicate how to authenticate it with your
	// customer.
	SourceStatusPending SourceStatus = "pending"
)

// SourceFlow represents the possible flows of a source object.
type SourceFlow string

const (
	// FlowNone no particular authentication is involved the source should
	// become chargeable directly or asyncrhonously.
	FlowNone SourceFlow = "none"

	// FlowReceiver a receiver address should be communicated to the customer
	// to push funds to it.
	FlowReceiver SourceFlow = "receiver"

	// FlowRedirect a redirect is required to authenticate the source.
	FlowRedirect SourceFlow = "redirect"

	// FlowVerification a verification code should be communicated by the
	// customer to authenticate the source.
	FlowVerification SourceFlow = "verification"
)

// SourceUsage represents the possible usages of a source object.
type SourceUsage string

const (
	// UsageReusable the source can be charged multiple times for arbitrary
	// amounts.
	UsageReusable SourceUsage = "reusable"

	// UsageSingleUse the source can only be charged once for the specified
	// amount and currency.
	UsageSingleUse SourceUsage = "single_use"
)

type SourceOwnerParams struct {
	Address *AddressParams `form:"address"`
	Email   string         `form:"email"`
	Name    string         `form:"name"`
	Phone   string         `form:"phone"`
}

type RedirectParams struct {
	ReturnURL string `form:"return_url"`
}

type SourceObjectParams struct {
	Params   `form:"*"`
	Amount   uint64             `form:"amount"`
	Currency Currency           `form:"currency"`
	Customer string             `form:"customer"`
	Flow     SourceFlow         `form:"flow"`
	Owner    *SourceOwnerParams `form:"owner"`
	Redirect *RedirectParams    `form:"redirect"`
	Token    string             `form:"token"`
	Type     string             `form:"type"`
	TypeData map[string]string  `form:"-"`
	Usage    SourceUsage        `form:"usage"`
}

type SourceOwner struct {
	Address         *Address `json:"address,omitempty"`
	Email           string   `json:"email"`
	Name            string   `json:"name"`
	Phone           string   `json:"phone"`
	VerifiedAddress *Address `json:"verified_address,omitempty"`
	VerifiedEmail   string   `json:"verified_email"`
	VerifiedName    string   `json:"verified_name"`
	VerifiedPhone   string   `json:"verified_phone"`
}

// RedirectFlowStatus represents the possible statuses of a redirect flow.
type RedirectFlowStatus string

const (
	RedirectFlowStatusFailed    RedirectFlowStatus = "failed"
	RedirectFlowStatusPending   RedirectFlowStatus = "pending"
	RedirectFlowStatusSucceeded RedirectFlowStatus = "succeeded"
)

// ReceiverFlow informs of the state of a redirect authentication flow.
type RedirectFlow struct {
	ReturnURL string             `json:"return_url"`
	Status    RedirectFlowStatus `json:"status"`
	URL       string             `json:"url"`
}

// RefundAttributesStatus are the possible status of a receiver's refund
// attributes.
type RefundAttributesStatus string

const (
	// RefundAttributesAvailable the refund attributes are available
	RefundAttributesAvailable RefundAttributesStatus = "available"

	// RefundAttributesMissing the refund attributes are missing
	RefundAttributesMissing RefundAttributesStatus = "missing"

	// RefundAttributesRequested the refund attributes have been requested
	RefundAttributesRequested RefundAttributesStatus = "requested"
)

// RefundAttributesMethod are the possible method to retrieve a receiver's
// refund attributes.
type RefundAttributesMethod string

const (
	// RefundAttributesEmail the refund attributes are automatically collected over email
	RefundAttributesEmail RefundAttributesMethod = "email"

	// RefundAttributesManual the refund attributes should be collected by the user
	RefundAttributesManual RefundAttributesMethod = "manual"
)

// ReceiverFlow informs of the state of a receiver authentication flow.
type ReceiverFlow struct {
	Address                string                 `json:"address"`
	AmountCharged          int64                  `json:"amount_charged"`
	AmountReceived         int64                  `json:"amount_received"`
	AmountReturned         int64                  `json:"amount_returned"`
	RefundAttributesMethod RefundAttributesMethod `json:"refund_attributes_method"`
	RefundAttributesStatus RefundAttributesStatus `json:"refund_attributes_status"`
}

// VerificationFlowStatus represents the possible statuses of a verification
// flow.
type VerificationFlowStatus string

const (
	VerificationFlowStatusFailed    VerificationFlowStatus = "failed"
	VerificationFlowStatusPending   VerificationFlowStatus = "pending"
	VerificationFlowStatusSucceeded VerificationFlowStatus = "succeeded"
)

// ReceiverFlow informs of the state of a verification authentication flow.
type VerificationFlow struct {
	AttemptsRemaining uint64             `json:"attempts_remaining"`
	Status            RedirectFlowStatus `json:"status"`
}

type Source struct {
	Amount       int64             `json:"amount"`
	ClientSecret string            `json:"client_secret"`
	Created      int64             `json:"created"`
	Currency     Currency          `json:"currency"`
	Flow         SourceFlow        `json:"flow"`
	ID           string            `json:"id"`
	Live         bool              `json:"livemode"`
	Meta         map[string]string `json:"metadata"`
	Owner        SourceOwner       `json:"owner"`
	Receiver     *ReceiverFlow     `json:"receiver,omitempty"`
	Redirect     *RedirectFlow     `json:"redirect,omitempty"`
	Status       SourceStatus      `json:"status"`
	Type         string            `json:"type"`
	TypeData     map[string]interface{}
	Usage        SourceUsage       `json:"usage"`
	Verification *VerificationFlow `json:"verification,omitempty"`
}

// AppendTo implements custom encoding logic for SourceObjectParams so that the special
// "TypeData" value for is sent as the correct parameter based on the Source type
func (p *SourceObjectParams) AppendTo(body *form.Values, keyParts []string) {
	for k, vs := range p.TypeData {
		body.Add(form.FormatKey(append(keyParts, p.Type, k)), vs)
	}
}

// UnmarshalJSON handles deserialization of an Source. This custom unmarshaling
// is needed to extract the type specific data (accessible under `TypeData`)
// but stored in JSON under a hash named after the `type` of the source.
func (s *Source) UnmarshalJSON(data []byte) error {
	type source Source
	var ss source
	err := json.Unmarshal(data, &ss)
	if err != nil {
		return err
	}
	*s = Source(ss)

	var raw map[string]interface{}
	err = json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	if d, ok := raw[s.Type]; ok {
		if m, ok := d.(map[string]interface{}); ok {
			s.TypeData = m
		}
	}

	return nil
}
<|endoftext|>


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

package util

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

	"github.com/mitchellh/go-homedir"
)

const authsFilePerm = 0600

// AuthsFileName is where the authentication tokens are stored. Defaults to
// $HOME/.ttnctl/auths.json
var AuthsFileName string

// Auth represents an authentication token
type Auth struct {
	AccessToken  string    `json:"access_token"`
	RefreshToken string    `json:"refresh_token"`
	Email        string    `json:"email"`
	Expires      time.Time `json:"expires"`
}

type auths struct {
	Auths map[string]*Auth `json:"auths"`
}

type token struct {
	AccessToken      string `json:"access_token,omitempty"`
	RefreshToken     string `json:"refresh_token,omitempty"`
	Error            string `json:"error,omitempty"`
	ErrorDescription string `json:"error_description,omitempty"`
	ExpiresIn        int    `json:"expires_in,omitempty"`
}

func init() {
	dir, err := homedir.Dir()
	if err != nil {
		panic(err)
	}
	expanded, err := homedir.Expand(dir)
	if err != nil {
		panic(err)
	}
	AuthsFileName = path.Join(expanded, ".ttnctl/auths.json")
}

// Login attemps to login using the specified credentials on the server
func Login(server, email, password string) (*Auth, error) {
	values := url.Values{
		"grant_type": {"password"},
		"username":   {email},
		"password":   {password},
	}
	return newToken(server, email, values)
}

// Logout deletes the token for the specified server
func Logout(server string) error {
	a, err := loadAuths()
	if err != nil {
		return err
	}
	delete(a.Auths, server)
	if err := saveAuths(a); err != nil {
		return err
	}
	return nil
}

// LoadAuth loads the authentication token for the specified server and attempts
// to refresh the token if it has been expired
func LoadAuth(server string) (*Auth, error) {
	a, err := loadAuths()
	if err != nil {
		return nil, err
	}
	auth, ok := a.Auths[server]
	if !ok {
		return nil, nil
	}
	if time.Now().UTC().After(auth.Expires) {
		return refreshToken(server, auth)
	}
	return auth, nil
}

// NewRequestWithAuth creates a new HTTP request and adds the access token of
// the authenticated user as bearer token
func NewRequestWithAuth(server, method, urlStr string, body io.Reader) (*http.Request, error) {
	auth, err := LoadAuth(server)
	if err != nil {
		return nil, err
	}
	if auth == nil {
		return nil, errors.New("No authentication token found. Please login")
	}
	req, err := http.NewRequest(method, urlStr, body)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("bearer %s", auth.AccessToken))
	return req, nil
}

// RefreshToken refreshes the current token
func RefreshToken(server string) (*Auth, error) {
	auth, err := LoadAuth(server)
	if err != nil {
		return nil, err
	}
	return refreshToken(server, auth)
}

func refreshToken(server string, auth *Auth) (*Auth, error) {
	values := url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {auth.RefreshToken},
	}
	return newToken(server, auth.Email, values)
}

func newToken(server, email string, values url.Values) (*Auth, error) {
	uri := fmt.Sprintf("%s/token", server)
	req, err := http.NewRequest("POST", uri, strings.NewReader(values.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.SetBasicAuth("ttnctl", "")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var t token
	if err := decoder.Decode(&t); err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		if t.Error != "" {
			return nil, errors.New(t.ErrorDescription)
		}
		return nil, errors.New(resp.Status)
	}

	expires := time.Now().UTC().Add(time.Duration(t.ExpiresIn) * time.Second)
	auth, err := saveAuth(server, email, t.AccessToken, t.RefreshToken, expires)
	if err != nil {
		return nil, err
	}

	return auth, nil
}

// saveAuth saves the authentication token for the specified server and e-mail
func saveAuth(server, email, accessToken, refreshToken string, expires time.Time) (*Auth, error) {
	a, err := loadAuths()
	// Ignore error - just create new structure
	if err != nil || a == nil {
		a = &auths{}
	}

	// Initialize the map if not exists and add the token
	auth := &Auth{accessToken, refreshToken, email, expires}
	a.Auths[server] = auth
	if err := saveAuths(a); err != nil {
		return nil, err
	}

	return auth, nil
}

// loadAuths loads the authentication tokens. This function returns an empty
// structure if the file does not exist.
func loadAuths() (*auths, error) {
	if _, err := os.Stat(AuthsFileName); os.IsNotExist(err) {
		return &auths{make(map[string]*Auth)}, nil
	}
	buff, err := ioutil.ReadFile(AuthsFileName)
	if err != nil {
		return nil, err
	}
	var a auths
	if err := json.Unmarshal(buff, &a); err != nil {
		return nil, err
	}
	if a.Auths == nil {
		a.Auths = make(map[string]*Auth)
	}
	return &a, nil
}

func saveAuths(a *auths) error {
	// Marshal and write to disk
	buff, err := json.Marshal(&a)
	if err != nil {
		return err
	}
	if err := os.MkdirAll(path.Dir(AuthsFileName), 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(AuthsFileName, buff, authsFilePerm); err != nil {
		return err
	}
	return nil
}
<commit_msg>Use users token<commit_after>// Copyright © 2016 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.

package util

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

	"github.com/mitchellh/go-homedir"
)

const authsFilePerm = 0600

// AuthsFileName is where the authentication tokens are stored. Defaults to
// $HOME/.ttnctl/auths.json
var AuthsFileName string

// Auth represents an authentication token
type Auth struct {
	AccessToken  string    `json:"access_token"`
	RefreshToken string    `json:"refresh_token"`
	Email        string    `json:"email"`
	Expires      time.Time `json:"expires"`
}

type auths struct {
	Auths map[string]*Auth `json:"auths"`
}

type token struct {
	AccessToken      string `json:"access_token,omitempty"`
	RefreshToken     string `json:"refresh_token,omitempty"`
	Error            string `json:"error,omitempty"`
	ErrorDescription string `json:"error_description,omitempty"`
	ExpiresIn        int    `json:"expires_in,omitempty"`
}

func init() {
	dir, err := homedir.Dir()
	if err != nil {
		panic(err)
	}
	expanded, err := homedir.Expand(dir)
	if err != nil {
		panic(err)
	}
	AuthsFileName = path.Join(expanded, ".ttnctl/auths.json")
}

// Login attemps to login using the specified credentials on the server
func Login(server, email, password string) (*Auth, error) {
	values := url.Values{
		"grant_type": {"password"},
		"username":   {email},
		"password":   {password},
	}
	return newToken(server, email, values)
}

// Logout deletes the token for the specified server
func Logout(server string) error {
	a, err := loadAuths()
	if err != nil {
		return err
	}
	delete(a.Auths, server)
	if err := saveAuths(a); err != nil {
		return err
	}
	return nil
}

// LoadAuth loads the authentication token for the specified server and attempts
// to refresh the token if it has been expired
func LoadAuth(server string) (*Auth, error) {
	a, err := loadAuths()
	if err != nil {
		return nil, err
	}
	auth, ok := a.Auths[server]
	if !ok {
		return nil, nil
	}
	if time.Now().UTC().After(auth.Expires) {
		return refreshToken(server, auth)
	}
	return auth, nil
}

// NewRequestWithAuth creates a new HTTP request and adds the access token of
// the authenticated user as bearer token
func NewRequestWithAuth(server, method, urlStr string, body io.Reader) (*http.Request, error) {
	auth, err := LoadAuth(server)
	if err != nil {
		return nil, err
	}
	if auth == nil {
		return nil, errors.New("No authentication token found. Please login")
	}
	req, err := http.NewRequest(method, urlStr, body)
	if err != nil {
		return nil, err
	}
	req.Header.Add("Authorization", fmt.Sprintf("bearer %s", auth.AccessToken))
	return req, nil
}

// RefreshToken refreshes the current token
func RefreshToken(server string) (*Auth, error) {
	auth, err := LoadAuth(server)
	if err != nil {
		return nil, err
	}
	return refreshToken(server, auth)
}

func refreshToken(server string, auth *Auth) (*Auth, error) {
	values := url.Values{
		"grant_type":    {"refresh_token"},
		"refresh_token": {auth.RefreshToken},
	}
	return newToken(server, auth.Email, values)
}

func newToken(server, email string, values url.Values) (*Auth, error) {
	uri := fmt.Sprintf("%s/users/token", server)
	req, err := http.NewRequest("POST", uri, strings.NewReader(values.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.SetBasicAuth("ttnctl", "")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()
	decoder := json.NewDecoder(resp.Body)
	var t token
	if err := decoder.Decode(&t); err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		if t.Error != "" {
			return nil, errors.New(t.ErrorDescription)
		}
		return nil, errors.New(resp.Status)
	}

	expires := time.Now().UTC().Add(time.Duration(t.ExpiresIn) * time.Second)
	auth, err := saveAuth(server, email, t.AccessToken, t.RefreshToken, expires)
	if err != nil {
		return nil, err
	}

	return auth, nil
}

// saveAuth saves the authentication token for the specified server and e-mail
func saveAuth(server, email, accessToken, refreshToken string, expires time.Time) (*Auth, error) {
	a, err := loadAuths()
	// Ignore error - just create new structure
	if err != nil || a == nil {
		a = &auths{}
	}

	// Initialize the map if not exists and add the token
	auth := &Auth{accessToken, refreshToken, email, expires}
	a.Auths[server] = auth
	if err := saveAuths(a); err != nil {
		return nil, err
	}

	return auth, nil
}

// loadAuths loads the authentication tokens. This function returns an empty
// structure if the file does not exist.
func loadAuths() (*auths, error) {
	if _, err := os.Stat(AuthsFileName); os.IsNotExist(err) {
		return &auths{make(map[string]*Auth)}, nil
	}
	buff, err := ioutil.ReadFile(AuthsFileName)
	if err != nil {
		return nil, err
	}
	var a auths
	if err := json.Unmarshal(buff, &a); err != nil {
		return nil, err
	}
	if a.Auths == nil {
		a.Auths = make(map[string]*Auth)
	}
	return &a, nil
}

func saveAuths(a *auths) error {
	// Marshal and write to disk
	buff, err := json.Marshal(&a)
	if err != nil {
		return err
	}
	if err := os.MkdirAll(path.Dir(AuthsFileName), 0755); err != nil {
		return err
	}
	if err := ioutil.WriteFile(AuthsFileName, buff, authsFilePerm); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"os/exec"
	"path"
	"regexp"
	"runtime"
	"strconv"

	"github.com/nightlyone/lockfile"
	. "gopkg.in/check.v1"
)

func (t *TestSuite) Test_runCommand(c *C) {
	//
	// Test a command that finishes in 0.3 seconds
	//
	cmd := exec.Command("/usr/bin/time", "-p", "/bin/sleep", "0.3")

	// runButts(cmd *exec.Cmd, label string, save bool, gs *godspeed.Godspeed, lock bool, lockDir string)
	retCode, r, time, err := runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)

	stat, ok := <-t.out
	c.Assert(ok, Equals, true)

	timeStatRegex := regexp.MustCompile("^cronner.testCmd.time:([0-9\\.]+)\\|ms$")
	match := timeStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	statFloat, err := strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(statFloat, Equals, time)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	retStatRegex := regexp.MustCompile("^cronner.testCmd.exit_code:([0-9\\.]+)\\|g$")
	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err := strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(0))

	var timely bool

	// assume the command run time will be within 20ms of correct,
	// note sure how tight we can make this window without incurring
	// false-failures.
	if time > 300 && time < 320 {
		timely = true
	}
	c.Assert(timely, Equals, true)

	timeRegex := regexp.MustCompile("((?m)^real[[:space:]]+([0-9\\.]+)$)")
	match = timeRegex.FindAllStringSubmatch(string(r), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 3)
	c.Assert(match[0][2], Equals, "0.30")

	//
	// Test a command that finishes in 1 second
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	timely = false
	retCode = -512
	timeRegex = nil

	cmd = exec.Command("/usr/bin/time", "-p", "/bin/sleep", "1")

	retCode, r, time, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = timeStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	statFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(statFloat, Equals, time)

	if time > 1000 && time < 1020 {
		timely = true
	}
	c.Assert(timely, Equals, true)

	timeRegex = regexp.MustCompile("((?m)^real[[:space:]]+([0-9\\.]+)$)")
	match = timeRegex.FindAllStringSubmatch(string(r), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 3)
	c.Assert(match[0][2], Equals, "1.00")

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(0))

	//
	// Test a valid return code is given
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	retCode = -512

	switch runtime.GOOS {
	case "linux":
		cmd = exec.Command("/bin/false")
	case "darwin":
		cmd = exec.Command("/usr/bin/false")
	}

	retCode, r, time, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, Not(IsNil))
	c.Assert(retCode, Equals, 1)

	_, ok = <-t.out
	c.Assert(ok, Equals, true)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(1))

	//
	// Test that no output is given
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	retCode = -300

	cmd = exec.Command("/bin/echo", "something")

	t.a.AllEvents = false

	retCode, r, _, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)
	c.Check(len(r), Equals, 0)

	// clear the statsd return channel
	_, ok = <-t.out
	c.Assert(ok, Equals, true)
	_, ok = <-t.out
	c.Assert(ok, Equals, true)

	//
	// Test that locking fails properly when unable to acquire lock
	//

	// Reset variables used
	err = nil
	retCode = -512

	lf, err := lockfile.New(path.Join(t.a.LockDir, "cronner-testCmd.lock"))
	c.Assert(err, IsNil)

	err = lf.TryLock()
	c.Assert(err, IsNil)
	defer lf.Unlock()

	t.a.Lock = true

	retCode, _, _, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, Not(IsNil))
	c.Check(err.Error(), Equals, "Locked by other process")
	c.Check(retCode, Equals, 200)
}
<commit_msg>add regression test to ensure lockfile was removed<commit_after>package main

import (
	"os"
	"os/exec"
	"path"
	"regexp"
	"runtime"
	"strconv"

	"github.com/nightlyone/lockfile"
	. "gopkg.in/check.v1"
)

func (t *TestSuite) Test_runCommand(c *C) {
	//
	// Test a command that finishes in 0.3 seconds
	//
	cmd := exec.Command("/usr/bin/time", "-p", "/bin/sleep", "0.3")

	// runButts(cmd *exec.Cmd, label string, save bool, gs *godspeed.Godspeed, lock bool, lockDir string)
	retCode, r, time, err := runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)

	stat, ok := <-t.out
	c.Assert(ok, Equals, true)

	timeStatRegex := regexp.MustCompile("^cronner.testCmd.time:([0-9\\.]+)\\|ms$")
	match := timeStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	statFloat, err := strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(statFloat, Equals, time)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	retStatRegex := regexp.MustCompile("^cronner.testCmd.exit_code:([0-9\\.]+)\\|g$")
	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err := strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(0))

	var timely bool

	// assume the command run time will be within 20ms of correct,
	// note sure how tight we can make this window without incurring
	// false-failures.
	if time > 300 && time < 320 {
		timely = true
	}
	c.Assert(timely, Equals, true)

	timeRegex := regexp.MustCompile("((?m)^real[[:space:]]+([0-9\\.]+)$)")
	match = timeRegex.FindAllStringSubmatch(string(r), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 3)
	c.Assert(match[0][2], Equals, "0.30")

	//
	// Test a command that finishes in 1 second
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	timely = false
	retCode = -512
	timeRegex = nil

	cmd = exec.Command("/usr/bin/time", "-p", "/bin/sleep", "1")

	retCode, r, time, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = timeStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	statFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(statFloat, Equals, time)

	if time > 1000 && time < 1020 {
		timely = true
	}
	c.Assert(timely, Equals, true)

	timeRegex = regexp.MustCompile("((?m)^real[[:space:]]+([0-9\\.]+)$)")
	match = timeRegex.FindAllStringSubmatch(string(r), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 3)
	c.Assert(match[0][2], Equals, "1.00")

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(0))

	//
	// Test a valid return code is given
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	retCode = -512

	switch runtime.GOOS {
	case "linux":
		cmd = exec.Command("/bin/false")
	case "darwin":
		cmd = exec.Command("/usr/bin/false")
	}

	retCode, r, time, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, Not(IsNil))
	c.Assert(retCode, Equals, 1)

	_, ok = <-t.out
	c.Assert(ok, Equals, true)

	stat, ok = <-t.out
	c.Assert(ok, Equals, true)

	match = retStatRegex.FindAllStringSubmatch(string(stat), -1)
	c.Assert(len(match), Equals, 1)
	c.Assert(len(match[0]), Equals, 2)

	retFloat, err = strconv.ParseFloat(match[0][1], 64)
	c.Assert(err, IsNil)
	c.Assert(retFloat, Equals, float64(1))

	//
	// Test that no output is given
	//

	// Reset variables used
	r = nil
	err = nil
	cmd = nil
	time = 0
	match = nil
	retCode = -300

	cmd = exec.Command("/bin/echo", "something")

	t.a.AllEvents = false
	t.a.Lock = true

	lf, err := lockfile.New(path.Join(t.a.LockDir, "cronner-testCmd.lock"))
	c.Assert(err, IsNil)

	retCode, r, _, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, IsNil)
	c.Assert(retCode, Equals, 0)
	c.Check(len(r), Equals, 0)

	// assert that the lockfile was removed
	_, err = os.Stat(string(lf))
	c.Assert(os.IsNotExist(err), Equals, true)

	// clear the statsd return channel
	_, ok = <-t.out
	c.Assert(ok, Equals, true)
	_, ok = <-t.out
	c.Assert(ok, Equals, true)

	//
	// Test that locking fails properly when unable to acquire lock
	//

	// Reset variables used
	err = nil
	retCode = -512

	err = lf.TryLock()
	c.Assert(err, IsNil)
	defer lf.Unlock()

	retCode, _, _, err = runCommand(cmd, t.gs, t.a)
	c.Assert(err, Not(IsNil))
	c.Check(err.Error(), Equals, "Locked by other process")
	c.Check(retCode, Equals, 200)
}
<|endoftext|>