<commit_before>package main

import (
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)

const MAX_NUMBER_THREADS = 8
const CONNECTION_TIMEOUT = time.Hour

type connectionMap struct {
	receiver           map[string]net.Conn
	sender             map[string]net.Conn
	metadata           map[string]string
	potentialReceivers map[string]struct{}
	sync.RWMutex
}

func (c *connectionMap) IsSenderConnected(key string) (found bool) {
	c.RLock()
	defer c.RUnlock()
	_, found = c.sender[key]
	return
}

func (c *connectionMap) IsPotentialReceiverConnected(key string) (found bool) {
	c.RLock()
	defer c.RUnlock()
	_, found = c.potentialReceivers[key]
	return
}

type Relay struct {
	connections         connectionMap
	Debug               bool
	NumberOfConnections int
}

func NewRelay(flags *Flags) *Relay {
	r := new(Relay)
	r.Debug = flags.Debug
	r.NumberOfConnections = MAX_NUMBER_THREADS
	log.SetFormatter(&log.TextFormatter{})
	if r.Debug {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.WarnLevel)
	}
	return r
}

func (r *Relay) Run() {
	r.connections = connectionMap{}
	r.connections.Lock()
	r.connections.receiver = make(map[string]net.Conn)
	r.connections.sender = make(map[string]net.Conn)
	r.connections.metadata = make(map[string]string)
	r.connections.potentialReceivers = make(map[string]struct{})
	r.connections.Unlock()
	r.runServer()
}

func (r *Relay) runServer() {
	logger := log.WithFields(log.Fields{
		"function": "main",
	})
	logger.Debug("Initializing")
	var wg sync.WaitGroup
	wg.Add(r.NumberOfConnections)
	for id := 0; id < r.NumberOfConnections; id++ {
		go r.listenerThread(id, &wg)
	}
	wg.Wait()
}

func (r *Relay) listenerThread(id int, wg *sync.WaitGroup) {
	logger := log.WithFields(log.Fields{
		"function": "listenerThread:" + strconv.Itoa(27000+id),
	})

	defer wg.Done()
	err := r.listener(id)
	if err != nil {
		logger.Error(err)
	}
}

func (r *Relay) listener(id int) (err error) {
	port := strconv.Itoa(27001 + id)
	logger := log.WithFields(log.Fields{
		"function": "listener" + ":" + port,
	})
	server, err := net.Listen("tcp", "0.0.0.0:"+port)
	if err != nil {
		return errors.Wrap(err, "Error listening on "+":"+port)
	}
	defer server.Close()
	logger.Debug("waiting for connections")
	//Spawn a new goroutine whenever a client connects
	for {
		connection, err := server.Accept()
		if err != nil {
			return errors.Wrap(err, "problem accepting connection")
		}
		logger.Debugf("Client %s connected", connection.RemoteAddr().String())
		go r.clientCommuncation(id, connection)
	}
}

func (r *Relay) clientCommuncation(id int, connection net.Conn) {
	sendMessage("who?", connection)

	m := strings.Split(receiveMessage(connection), ".")
	connectionType, codePhrase, metaData := m[0], m[1], m[2]
	key := codePhrase + "-" + strconv.Itoa(id)
	logger := log.WithFields(log.Fields{
		"id":         id,
		"codePhrase": codePhrase,
	})

	if connectionType == "s" { // sender connection
		if r.connections.IsSenderConnected(key) {
			sendMessage("no", connection)
			return
		}
		logger.Debug("got sender")
		r.connections.Lock()
		r.connections.metadata[key] = metaData
		r.connections.sender[key] = connection
		r.connections.Unlock()
		// wait for receiver
		receiversAddress := ""
		isTimeout := time.Duration(0)
		for {
			if CONNECTION_TIMEOUT <= isTimeout {
				sendMessage("timeout", connection)
				break
			}
			r.connections.RLock()
			if _, ok := r.connections.receiver[key]; ok {
				receiversAddress = r.connections.receiver[key].RemoteAddr().String()
				logger.Debug("got receiver")
				r.connections.RUnlock()
				break
			}
			r.connections.RUnlock()
			time.Sleep(100 * time.Millisecond)
			isTimeout += 100 * time.Millisecond
		}
		logger.Debug("telling sender ok")
		sendMessage(receiversAddress, connection)
		logger.Debug("preparing pipe")
		r.connections.Lock()
		con1 := r.connections.sender[key]
		con2 := r.connections.receiver[key]
		r.connections.Unlock()
		logger.Debug("piping connections")
		Pipe(con1, con2)
		logger.Debug("done piping")
		r.connections.Lock()
		delete(r.connections.sender, key)
		delete(r.connections.receiver, key)
		delete(r.connections.metadata, key)
		delete(r.connections.potentialReceivers, key)
		r.connections.Unlock()
		logger.Debug("deleted sender and receiver")
	} else { //receiver connection "r"
		if r.connections.IsPotentialReceiverConnected(key) {
			sendMessage("no", connection)
			return
		}

		// add as a potential receiver
		r.connections.Lock()
		r.connections.potentialReceivers[key] = struct{}{}
		r.connections.Unlock()
		// wait for sender's metadata
		sendersAddress := ""
		for {
			r.connections.RLock()
			if _, ok := r.connections.metadata[key]; ok {
				if _, ok2 := r.connections.sender[key]; ok2 {
					sendersAddress = r.connections.sender[key].RemoteAddr().String()
					logger.Debug("got sender meta data")
					r.connections.RUnlock()
					break
				}
			}
			r.connections.RUnlock()
			if connectionType == "c" {
				sendMessage("0-0-0-0.0.0.0", connection)
				return
			}
			time.Sleep(100 * time.Millisecond)
		}
		// send  meta data
		r.connections.RLock()
		sendMessage(r.connections.metadata[key]+"-"+sendersAddress, connection)
		r.connections.RUnlock()
		// check for receiver's consent
		consent := receiveMessage(connection)
		logger.Debugf("consent: %s", consent)
		if consent == "ok" {
			logger.Debug("got consent")
			r.connections.Lock()
			r.connections.receiver[key] = connection
			r.connections.Unlock()
		}
	}
	return
}

func sendMessage(message string, connection net.Conn) {
	message = fillString(message, BUFFERSIZE)
	connection.Write([]byte(message))
}

func receiveMessage(connection net.Conn) string {
	messageByte := make([]byte, BUFFERSIZE)
	connection.Read(messageByte)
	return strings.Replace(string(messageByte), ":", "", -1)
}

func fillString(retunString string, toLength int) string {
	for {
		lengthString := len(retunString)
		if lengthString < toLength {
			retunString = retunString + ":"
			continue
		}
		break
	}
	return retunString
}

// chanFromConn creates a channel from a Conn object, and sends everything it
//  Read()s from the socket to the channel.
func chanFromConn(conn net.Conn) chan []byte {
	c := make(chan []byte)

	go func() {
		b := make([]byte, BUFFERSIZE)

		for {
			n, err := conn.Read(b)
			if n > 0 {
				res := make([]byte, n)
				// Copy the buffer so it doesn't get changed while read by the recipient.
				copy(res, b[:n])
				c <- res
			}
			if err != nil {
				c <- nil
				break
			}
		}
	}()

	return c
}

// Pipe creates a full-duplex pipe between the two sockets and transfers data from one to the other.
func Pipe(conn1 net.Conn, conn2 net.Conn) {
	chan1 := chanFromConn(conn1)
	chan2 := chanFromConn(conn2)

	for {
		select {
		case b1 := <-chan1:
			if b1 == nil {
				return
			} else {
				conn2.Write(b1)
			}
		case b2 := <-chan2:
			if b2 == nil {
				return
			} else {
				conn1.Write(b2)
			}
		}
	}
}
<commit_msg>disallow connections without the proper messaging<commit_after>package main

import (
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)

const MAX_NUMBER_THREADS = 8
const CONNECTION_TIMEOUT = time.Hour

type connectionMap struct {
	receiver           map[string]net.Conn
	sender             map[string]net.Conn
	metadata           map[string]string
	potentialReceivers map[string]struct{}
	sync.RWMutex
}

func (c *connectionMap) IsSenderConnected(key string) (found bool) {
	c.RLock()
	defer c.RUnlock()
	_, found = c.sender[key]
	return
}

func (c *connectionMap) IsPotentialReceiverConnected(key string) (found bool) {
	c.RLock()
	defer c.RUnlock()
	_, found = c.potentialReceivers[key]
	return
}

type Relay struct {
	connections         connectionMap
	Debug               bool
	NumberOfConnections int
}

func NewRelay(flags *Flags) *Relay {
	r := new(Relay)
	r.Debug = flags.Debug
	r.NumberOfConnections = MAX_NUMBER_THREADS
	log.SetFormatter(&log.TextFormatter{})
	if r.Debug {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.WarnLevel)
	}
	return r
}

func (r *Relay) Run() {
	r.connections = connectionMap{}
	r.connections.Lock()
	r.connections.receiver = make(map[string]net.Conn)
	r.connections.sender = make(map[string]net.Conn)
	r.connections.metadata = make(map[string]string)
	r.connections.potentialReceivers = make(map[string]struct{})
	r.connections.Unlock()
	r.runServer()
}

func (r *Relay) runServer() {
	logger := log.WithFields(log.Fields{
		"function": "main",
	})
	logger.Debug("Initializing")
	var wg sync.WaitGroup
	wg.Add(r.NumberOfConnections)
	for id := 0; id < r.NumberOfConnections; id++ {
		go r.listenerThread(id, &wg)
	}
	wg.Wait()
}

func (r *Relay) listenerThread(id int, wg *sync.WaitGroup) {
	logger := log.WithFields(log.Fields{
		"function": "listenerThread:" + strconv.Itoa(27000+id),
	})

	defer wg.Done()
	err := r.listener(id)
	if err != nil {
		logger.Error(err)
	}
}

func (r *Relay) listener(id int) (err error) {
	port := strconv.Itoa(27001 + id)
	logger := log.WithFields(log.Fields{
		"function": "listener" + ":" + port,
	})
	server, err := net.Listen("tcp", "0.0.0.0:"+port)
	if err != nil {
		return errors.Wrap(err, "Error listening on "+":"+port)
	}
	defer server.Close()
	logger.Debug("waiting for connections")
	//Spawn a new goroutine whenever a client connects
	for {
		connection, err := server.Accept()
		if err != nil {
			return errors.Wrap(err, "problem accepting connection")
		}
		logger.Debugf("Client %s connected", connection.RemoteAddr().String())
		go r.clientCommuncation(id, connection)
	}
}

func (r *Relay) clientCommuncation(id int, connection net.Conn) {
	sendMessage("who?", connection)

	m := strings.Split(receiveMessage(connection), ".")
	if len(m) != 3 {
		sendMessage("not enough information", connection)
		return
	}
	connectionType, codePhrase, metaData := m[0], m[1], m[2]
	key := codePhrase + "-" + strconv.Itoa(id)
	logger := log.WithFields(log.Fields{
		"id":         id,
		"codePhrase": codePhrase,
	})

	if connectionType == "s" { // sender connection
		if r.connections.IsSenderConnected(key) {
			sendMessage("no", connection)
			return
		}
		logger.Debug("got sender")
		r.connections.Lock()
		r.connections.metadata[key] = metaData
		r.connections.sender[key] = connection
		r.connections.Unlock()
		// wait for receiver
		receiversAddress := ""
		isTimeout := time.Duration(0)
		for {
			if CONNECTION_TIMEOUT <= isTimeout {
				sendMessage("timeout", connection)
				break
			}
			r.connections.RLock()
			if _, ok := r.connections.receiver[key]; ok {
				receiversAddress = r.connections.receiver[key].RemoteAddr().String()
				logger.Debug("got receiver")
				r.connections.RUnlock()
				break
			}
			r.connections.RUnlock()
			time.Sleep(100 * time.Millisecond)
			isTimeout += 100 * time.Millisecond
		}
		logger.Debug("telling sender ok")
		sendMessage(receiversAddress, connection)
		logger.Debug("preparing pipe")
		r.connections.Lock()
		con1 := r.connections.sender[key]
		con2 := r.connections.receiver[key]
		r.connections.Unlock()
		logger.Debug("piping connections")
		Pipe(con1, con2)
		logger.Debug("done piping")
		r.connections.Lock()
		delete(r.connections.sender, key)
		delete(r.connections.receiver, key)
		delete(r.connections.metadata, key)
		delete(r.connections.potentialReceivers, key)
		r.connections.Unlock()
		logger.Debug("deleted sender and receiver")
	} else { //receiver connection "r"
		if r.connections.IsPotentialReceiverConnected(key) {
			sendMessage("no", connection)
			return
		}

		// add as a potential receiver
		r.connections.Lock()
		r.connections.potentialReceivers[key] = struct{}{}
		r.connections.Unlock()
		// wait for sender's metadata
		sendersAddress := ""
		for {
			r.connections.RLock()
			if _, ok := r.connections.metadata[key]; ok {
				if _, ok2 := r.connections.sender[key]; ok2 {
					sendersAddress = r.connections.sender[key].RemoteAddr().String()
					logger.Debug("got sender meta data")
					r.connections.RUnlock()
					break
				}
			}
			r.connections.RUnlock()
			if connectionType == "c" {
				sendMessage("0-0-0-0.0.0.0", connection)
				return
			}
			time.Sleep(100 * time.Millisecond)
		}
		// send  meta data
		r.connections.RLock()
		sendMessage(r.connections.metadata[key]+"-"+sendersAddress, connection)
		r.connections.RUnlock()
		// check for receiver's consent
		consent := receiveMessage(connection)
		logger.Debugf("consent: %s", consent)
		if consent == "ok" {
			logger.Debug("got consent")
			r.connections.Lock()
			r.connections.receiver[key] = connection
			r.connections.Unlock()
		}
	}
	return
}

func sendMessage(message string, connection net.Conn) {
	message = fillString(message, BUFFERSIZE)
	connection.Write([]byte(message))
}

func receiveMessage(connection net.Conn) string {
	messageByte := make([]byte, BUFFERSIZE)
	connection.Read(messageByte)
	return strings.Replace(string(messageByte), ":", "", -1)
}

func fillString(retunString string, toLength int) string {
	for {
		lengthString := len(retunString)
		if lengthString < toLength {
			retunString = retunString + ":"
			continue
		}
		break
	}
	return retunString
}

// chanFromConn creates a channel from a Conn object, and sends everything it
//  Read()s from the socket to the channel.
func chanFromConn(conn net.Conn) chan []byte {
	c := make(chan []byte)

	go func() {
		b := make([]byte, BUFFERSIZE)

		for {
			n, err := conn.Read(b)
			if n > 0 {
				res := make([]byte, n)
				// Copy the buffer so it doesn't get changed while read by the recipient.
				copy(res, b[:n])
				c <- res
			}
			if err != nil {
				c <- nil
				break
			}
		}
	}()

	return c
}

// Pipe creates a full-duplex pipe between the two sockets and transfers data from one to the other.
func Pipe(conn1 net.Conn, conn2 net.Conn) {
	chan1 := chanFromConn(conn1)
	chan2 := chanFromConn(conn2)

	for {
		select {
		case b1 := <-chan1:
			if b1 == nil {
				return
			} else {
				conn2.Write(b1)
			}
		case b2 := <-chan2:
			if b2 == nil {
				return
			} else {
				conn1.Write(b2)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

package restful

import (
	"net/http"
	"strings"
)

// Signature of a function that can be bound to a Route.
type RouteFunction func(*Request, *Response)

// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction.
type Route struct {
	Method   string
	Produces []string
	Consumes []string
	Path     string // webservice root path + described path
	Function RouteFunction
	Filters  []FilterFunction

	// cached values for dispatching
	relativePath string
	pathParts    []string
	pathExpr     *pathExpression // cached compilation of relativePath as RegExp

	// documentation
	Doc                     string
	Operation               string
	ParameterDocs           []*Parameter
	ReadSample, WriteSample interface{} // structs that model an example request or response payload
}

// Initialize for Route
func (self *Route) postBuild() {
	self.pathParts = tokenizePath(self.Path)
}

// Create Request and Response from their http versions
func (self *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) {
	params := self.extractParameters(httpRequest.URL.Path)
	accept := httpRequest.Header.Get(HEADER_Accept)
	wrappedRequest := &Request{httpRequest, params}
	wrappedResponse := &Response{httpWriter, accept, self.Produces}
	return wrappedRequest, wrappedResponse
}

// Extract any path parameters from the the request URL path and call the function
func (self *Route) dispatch(wrappedRequest *Request, wrappedResponse *Response) {
	if len(self.Filters) > 0 {
		chain := FilterChain{Filters: self.Filters, Target: self.Function}
		chain.ProcessFilter(wrappedRequest, wrappedResponse)
	} else {
		// unfiltered
		self.Function(wrappedRequest, wrappedResponse)
	}
}

// Return whether the mimeType matches to what this Route can produce.
func (self Route) matchesAccept(mimeTypesWithQuality string) bool {
	parts := strings.Split(mimeTypesWithQuality, ",")
	for _, each := range parts {
		withoutQuality := strings.Split(each, ";")[0]
		if withoutQuality == "*/*" {
			return true
		}
		for _, other := range self.Produces {
			if other == withoutQuality {
				return true
			}
		}
	}
	return false
}

// Return whether the mimeType matches to what this Route can consume.
func (self Route) matchesContentType(mimeTypes string) bool {
	parts := strings.Split(mimeTypes, ",")
	for _, each := range parts {
		var contentType string
		if strings.Contains(each, ";") {
			contentType = strings.Split(each, ";")[0]
		} else {
			contentType = each
		}
		for _, other := range self.Consumes {
			if other == "*/*" || other == contentType {
				return true
			}
		}
	}
	return false
}

// Extract the parameters from the request url path
func (self Route) extractParameters(urlPath string) map[string]string {
	urlParts := tokenizePath(urlPath)
	pathParameters := map[string]string{}
	for i, key := range self.pathParts {
		var value string
		if i >= len(urlParts) {
			value = ""
		} else {
			value = urlParts[i]
		}
		if strings.HasPrefix(key, "{") { // path-parameter
			pathParameters[strings.Trim(key, "{}")] = value
		}
	}
	return pathParameters
}

// Tokenize an URL path using the slash separator ; the result does not have empty tokens
func tokenizePath(path string) []string {
	if "/" == path {
		return []string{}
	}
	return strings.Split(strings.Trim(path, "/"), "/")
}

// for debugging
func (r Route) String() string {
	return r.Method + " " + r.Path
}
<commit_msg>fix problem with spaces in composite Accept or Content-Type headers<commit_after>// Copyright 2012 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

package restful

import (
	"net/http"
	"strings"
)

// Signature of a function that can be bound to a Route.
type RouteFunction func(*Request, *Response)

// Route binds a HTTP Method,Path,Consumes combination to a RouteFunction.
type Route struct {
	Method   string
	Produces []string
	Consumes []string
	Path     string // webservice root path + described path
	Function RouteFunction
	Filters  []FilterFunction

	// cached values for dispatching
	relativePath string
	pathParts    []string
	pathExpr     *pathExpression // cached compilation of relativePath as RegExp

	// documentation
	Doc                     string
	Operation               string
	ParameterDocs           []*Parameter
	ReadSample, WriteSample interface{} // structs that model an example request or response payload
}

// Initialize for Route
func (self *Route) postBuild() {
	self.pathParts = tokenizePath(self.Path)
}

// Create Request and Response from their http versions
func (self *Route) wrapRequestResponse(httpWriter http.ResponseWriter, httpRequest *http.Request) (*Request, *Response) {
	params := self.extractParameters(httpRequest.URL.Path)
	accept := httpRequest.Header.Get(HEADER_Accept)
	wrappedRequest := &Request{httpRequest, params}
	wrappedResponse := &Response{httpWriter, accept, self.Produces}
	return wrappedRequest, wrappedResponse
}

// Extract any path parameters from the the request URL path and call the function
func (self *Route) dispatch(wrappedRequest *Request, wrappedResponse *Response) {
	if len(self.Filters) > 0 {
		chain := FilterChain{Filters: self.Filters, Target: self.Function}
		chain.ProcessFilter(wrappedRequest, wrappedResponse)
	} else {
		// unfiltered
		self.Function(wrappedRequest, wrappedResponse)
	}
}

// Return whether the mimeType matches to what this Route can produce.
func (self Route) matchesAccept(mimeTypesWithQuality string) bool {
	parts := strings.Split(mimeTypesWithQuality, ",")
	for _, each := range parts {
		var withoutQuality string
		if strings.Contains(each, ";") {
			withoutQuality = strings.Trim(strings.Split(each, ";")[0], " ")
		} else {
			withoutQuality = each
		}
		if withoutQuality == "*/*" {
			return true
		}
		for _, other := range self.Produces {
			if other == withoutQuality {
				return true
			}
		}
	}
	return false
}

// Return whether the mimeType matches to what this Route can consume.
func (self Route) matchesContentType(mimeTypes string) bool {
	parts := strings.Split(mimeTypes, ",")
	for _, each := range parts {
		var contentType string
		if strings.Contains(each, ";") {
			contentType = strings.Trim(strings.Split(each, ";")[0], " ")
		} else {
			contentType = each
		}
		for _, other := range self.Consumes {
			if other == "*/*" || other == contentType {
				return true
			}
		}
	}
	return false
}

// Extract the parameters from the request url path
func (self Route) extractParameters(urlPath string) map[string]string {
	urlParts := tokenizePath(urlPath)
	pathParameters := map[string]string{}
	for i, key := range self.pathParts {
		var value string
		if i >= len(urlParts) {
			value = ""
		} else {
			value = urlParts[i]
		}
		if strings.HasPrefix(key, "{") { // path-parameter
			pathParameters[strings.Trim(key, "{}")] = value
		}
	}
	return pathParameters
}

// Tokenize an URL path using the slash separator ; the result does not have empty tokens
func tokenizePath(path string) []string {
	if "/" == path {
		return []string{}
	}
	return strings.Split(strings.Trim(path, "/"), "/")
}

// for debugging
func (r Route) String() string {
	return r.Method + " " + r.Path
}
<|endoftext|>


<commit_before>package gogo

import (
	"net/http"
	"net/url"
	"path"
	"time"

	"github.com/golib/httprouter"
)

type AppRoute struct {
	Handlers []Middleware

	prefix string
	server *AppServer
}

// NewAppRoute creates a new app route with specified prefix and server
func NewAppRoute(prefix string, server *AppServer) *AppRoute {
	return &AppRoute{
		prefix: prefix,
		server: server,
	}
}

// Use registers new middlewares to the route
// TODO: ignore duplicated middlewares?
func (r *AppRoute) Use(middlewares ...Middleware) {
	r.Handlers = append(r.Handlers, middlewares...)
}

// Group returns a new app route group which has the same prefix path and middlewares
func (r *AppRoute) Group(prefix string, middlewares ...Middleware) *AppRoute {
	return &AppRoute{
		Handlers: r.combineHandlers(middlewares...),
		prefix:   r.calculatePrefix(prefix),
		server:   r.server,
	}
}

// Handle registers a new resource with its handler
func (r *AppRoute) Handle(method string, path string, handler Middleware) {
	uri := r.calculatePrefix(path)
	handlers := r.combineHandlers(handler)

	r.server.router.Handle(method, uri, func(resp http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := r.server.new(resp, req, NewAppParams(req, params), handlers)

		t := time.Now()
		ctx.Logger.Print("Started ", req.Method, " ", r.filterParameters(req.URL))

		ctx.Next()
		ctx.Response.FlushHeader()

		ctx.Logger.Print("Completed ", ctx.Response.Status(), " ", http.StatusText(ctx.Response.Status()), " in ", time.Now().Sub(t).String())

		r.server.reuse(ctx)
	})
}

// MockHandle mocks a new resource with specified response and handler, useful for testing
func (r *AppRoute) MockHandle(method string, path string, response http.ResponseWriter, handler Middleware) {
	uri := r.calculatePrefix(path)
	handlers := r.combineHandlers(handler)

	r.server.router.Handle(method, uri, func(resp http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := r.server.new(response, req, NewAppParams(req, params), handlers)

		t := time.Now()
		ctx.Logger.Infof(`Started %s "%s"`, req.Method, r.filterParameters(req.URL))

		ctx.Next()
		ctx.Response.FlushHeader()

		ctx.Logger.Infof("Completed %d in %v", ctx.Response.Status(), time.Now().Sub(t))

		r.server.reuse(ctx)
	})
}

// PUT is a shortcut of route.Handle("PUT", path, handler)
func (r *AppRoute) PUT(path string, handler Middleware) {
	r.Handle("PUT", path, handler)
}

// POST is a shortcut of route.Handle("POST", path, handler)
func (r *AppRoute) POST(path string, handler Middleware) {
	r.Handle("POST", path, handler)
}

// GET is a shortcut of route.Handle("GET", path, handler)
func (r *AppRoute) GET(path string, handler Middleware) {
	r.Handle("GET", path, handler)
}

// PATCH is a shortcut of route.Handle("PATCH", path, handler)
func (r *AppRoute) PATCH(path string, handler Middleware) {
	r.Handle("PATCH", path, handler)
}

// DELETE is a shortcut of route.Handle("DELETE", path, handler)
func (r *AppRoute) DELETE(path string, handler Middleware) {
	r.Handle("DELETE", path, handler)
}

// HEAD is a shortcut of route.Handle("HEAD", path, handler)
func (r *AppRoute) HEAD(path string, handler Middleware) {
	r.Handle("HEAD", path, handler)
}

// OPTIONS is a shortcut of route.Handle("OPTIONS", path, handler)
func (r *AppRoute) OPTIONS(path string, handler Middleware) {
	r.Handle("OPTIONS", path, handler)
}

// Any is a shortcut for all request methods
func (r *AppRoute) Any(path string, handler Middleware) {
	r.Handle("PUT", path, handler)
	r.Handle("POST", path, handler)
	r.Handle("GET", path, handler)
	r.Handle("PATCH", path, handler)
	r.Handle("DELETE", path, handler)
	r.Handle("HEAD", path, handler)
	r.Handle("OPTIONS", path, handler)
}

// Static serves files from the given dir
func (r *AppRoute) Static(path, root string) {
	if path[len(path)-1] != '/' {
		path += "/"
	}
	path += "*filepath"

	r.server.router.ServeFiles(path, http.Dir(root))
}

func (r *AppRoute) combineHandlers(handlers ...Middleware) []Middleware {
	combined := make([]Middleware, 0, len(r.Handlers)+len(handlers))
	combined = append(combined, r.Handlers...)
	combined = append(combined, handlers...)

	return combined
}

func (r *AppRoute) calculatePrefix(suffix string) string {
	if len(suffix) == 0 {
		return r.prefix
	}

	prefix := path.Join(r.prefix, suffix)

	// adjust path.Join side effect
	if suffix[len(suffix)-1] == '/' && prefix[len(prefix)-1] != '/' {
		prefix += "/"
	}

	return prefix
}

func (r *AppRoute) filterParameters(lru *url.URL) string {
	s := lru.Path

	query := lru.Query()
	if len(query) > 0 {
		for _, key := range r.server.filterParams {
			if _, ok := query[key]; ok {
				query.Set(key, "[FILTERED]")
			}
		}

		s += "?" + query.Encode()
	}

	return s
}
<commit_msg>refactor router logs<commit_after>package gogo

import (
	"net/http"
	"net/url"
	"path"
	"time"

	"github.com/golib/httprouter"
)

type AppRoute struct {
	Handlers []Middleware

	prefix string
	server *AppServer
}

// NewAppRoute creates a new app route with specified prefix and server
func NewAppRoute(prefix string, server *AppServer) *AppRoute {
	return &AppRoute{
		prefix: prefix,
		server: server,
	}
}

// Use registers new middlewares to the route
// TODO: ignore duplicated middlewares?
func (r *AppRoute) Use(middlewares ...Middleware) {
	r.Handlers = append(r.Handlers, middlewares...)
}

// Group returns a new app route group which has the same prefix path and middlewares
func (r *AppRoute) Group(prefix string, middlewares ...Middleware) *AppRoute {
	return &AppRoute{
		Handlers: r.combineHandlers(middlewares...),
		prefix:   r.calculatePrefix(prefix),
		server:   r.server,
	}
}

// Handle registers a new resource with its handler
func (r *AppRoute) Handle(method string, path string, handler Middleware) {
	uri := r.calculatePrefix(path)
	handlers := r.combineHandlers(handler)

	r.server.router.Handle(method, uri, func(resp http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := r.server.new(resp, req, NewAppParams(req, params), handlers)

		t := time.Now()
		ctx.Logger.Print("Started ", req.Method, " ", r.filterParameters(req.URL))

		ctx.Next()
		ctx.Response.FlushHeader()

		ctx.Logger.Print("Completed ", ctx.Response.Status(), " ", http.StatusText(ctx.Response.Status()), " in ", time.Now().Sub(t).String())

		r.server.reuse(ctx)
	})
}

// MockHandle mocks a new resource with specified response and handler, useful for testing
func (r *AppRoute) MockHandle(method string, path string, response http.ResponseWriter, handler Middleware) {
	uri := r.calculatePrefix(path)
	handlers := r.combineHandlers(handler)

	r.server.router.Handle(method, uri, func(resp http.ResponseWriter, req *http.Request, params httprouter.Params) {
		ctx := r.server.new(response, req, NewAppParams(req, params), handlers)

		ctx.Logger.Infof(`Started %s "%s"`, req.Method, r.filterParameters(req.URL))

		ctx.Next()
		ctx.Response.FlushHeader()

		ctx.Logger.Infof("Completed %d in %v", ctx.Response.Status(), time.Since(ctx.startedAt))

		r.server.reuse(ctx)
	})
}

// PUT is a shortcut of route.Handle("PUT", path, handler)
func (r *AppRoute) PUT(path string, handler Middleware) {
	r.Handle("PUT", path, handler)
}

// POST is a shortcut of route.Handle("POST", path, handler)
func (r *AppRoute) POST(path string, handler Middleware) {
	r.Handle("POST", path, handler)
}

// GET is a shortcut of route.Handle("GET", path, handler)
func (r *AppRoute) GET(path string, handler Middleware) {
	r.Handle("GET", path, handler)
}

// PATCH is a shortcut of route.Handle("PATCH", path, handler)
func (r *AppRoute) PATCH(path string, handler Middleware) {
	r.Handle("PATCH", path, handler)
}

// DELETE is a shortcut of route.Handle("DELETE", path, handler)
func (r *AppRoute) DELETE(path string, handler Middleware) {
	r.Handle("DELETE", path, handler)
}

// HEAD is a shortcut of route.Handle("HEAD", path, handler)
func (r *AppRoute) HEAD(path string, handler Middleware) {
	r.Handle("HEAD", path, handler)
}

// OPTIONS is a shortcut of route.Handle("OPTIONS", path, handler)
func (r *AppRoute) OPTIONS(path string, handler Middleware) {
	r.Handle("OPTIONS", path, handler)
}

// Any is a shortcut for all request methods
func (r *AppRoute) Any(path string, handler Middleware) {
	r.Handle("PUT", path, handler)
	r.Handle("POST", path, handler)
	r.Handle("GET", path, handler)
	r.Handle("PATCH", path, handler)
	r.Handle("DELETE", path, handler)
	r.Handle("HEAD", path, handler)
	r.Handle("OPTIONS", path, handler)
}

// Static serves files from the given dir
func (r *AppRoute) Static(path, root string) {
	if path[len(path)-1] != '/' {
		path += "/"
	}
	path += "*filepath"

	r.server.router.ServeFiles(path, http.Dir(root))
}

func (r *AppRoute) combineHandlers(handlers ...Middleware) []Middleware {
	combined := make([]Middleware, 0, len(r.Handlers)+len(handlers))
	combined = append(combined, r.Handlers...)
	combined = append(combined, handlers...)

	return combined
}

func (r *AppRoute) calculatePrefix(suffix string) string {
	if len(suffix) == 0 {
		return r.prefix
	}

	prefix := path.Join(r.prefix, suffix)

	// adjust path.Join side effect
	if suffix[len(suffix)-1] == '/' && prefix[len(prefix)-1] != '/' {
		prefix += "/"
	}

	return prefix
}

func (r *AppRoute) filterParameters(lru *url.URL) string {
	s := lru.Path

	query := lru.Query()
	if len(query) > 0 {
		for _, key := range r.server.filterParams {
			if _, ok := query[key]; ok {
				query.Set(key, "[FILTERED]")
			}
		}

		s += "?" + query.Encode()
	}

	return s
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/binary"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/dchest/siphash"
	"github.com/hashicorp/golang-lru"
	"github.com/miekg/dns"
)

const (
	// BayesianAverageC Constant for the Bayesian average for the RTT
	BayesianAverageC = 10
	// MaxFailures Maximum number of unanswered queries before a server is marked as dead for VacuumPeriod
	MaxFailures = 10
	// MinTTL Minimum TTL
	MinTTL = 60
	// MaxTTL Maximum TTL
	MaxTTL = 604800
	// VacuumPeriod Vacuum period in seconds
	VacuumPeriod = 30
)

// SipHashKey SipHash secret key
type SipHashKey struct {
	k1 uint64
	k2 uint64
}

// UpstreamServer Upstream server
type UpstreamServer struct {
	addr     string
	failures uint
	offline  bool
}

// UpstreamServers List of upstream servers
type UpstreamServers struct {
	lock    sync.RWMutex
	servers []UpstreamServer
	live    []string
}

// UpstreamRTT Keep track of the mean RTT
type UpstreamRTT struct {
	lock  sync.Mutex
	RTT   float64
	count float64
}

var (
	address            = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	upstreamServersStr = flag.String("upstream", "8.8.8.8:53", "Comma-delimited list of upstream servers")
	upstreamServers    *UpstreamServers
	cacheSize          = flag.Int("cachesize", 10000000, "Cache size (default=10000000)")
	memSize            = flag.Uint64("memsize", 1*1024, "Memory size in MB (default=1GB)")
	minLabelsCount     = flag.Int("minlabels", 2, "Minimum number of labels (default=2)")
	cache              *lru.ARCCache
	sipHashKey         = SipHashKey{k1: 0, k2: 0}
	pending            = uint32(0)
	maxClients         = flag.Uint("maxclients", 10000, "Maximum number of simultaneous clients (default=10000)")
	maxRTT             = flag.Float64("maxrtt", 0.25, "Maximum mean RTT for upstream queries before marking a server as dead")
	upstreamRtt        UpstreamRTT
)

func parseUpstreamServers(str string) (*UpstreamServers, error) {
	servers := []UpstreamServer{}
	live := []string{}
	for _, addr := range strings.Split(str, ",") {
		server := UpstreamServer{addr: addr}
		servers = append(servers, server)
		live = append(live, addr)
	}
	res := UpstreamServers{servers: servers, live: live}
	return &res, nil
}

func randUint64() uint64 {
	buf := make([]byte, 8)
	length, err := rand.Read(buf)
	if err != nil || length != len(buf) {
		log.Fatal("RNG failure")
	}
	return binary.LittleEndian.Uint64(buf)
}

func main() {
	flag.Parse()
	*memSize *= 1024 * 1024
	if *cacheSize < 2 {
		log.Fatal("Cache size too small")
	}
	cache, _ = lru.NewARC(*cacheSize)
	upstreamServers, _ = parseUpstreamServers(*upstreamServersStr)
	sipHashKey = SipHashKey{k1: randUint64(), k2: randUint64()}
	fmt.Println("RPDNS")
	dns.HandleFunc(".", route)
	udpServer := &dns.Server{Addr: *address, Net: "udp"}
	tcpServer := &dns.Server{Addr: *address, Net: "tcp"}
	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	go func() {
		log.Fatal(tcpServer.ListenAndServe())
	}()
	vacuumThread()
}

// CacheKey Key for a cache entry
type CacheKey struct {
	Name   string `dns:"cdomain-name"`
	Qtype  uint16
	DNSSEC bool
}

// CacheVal Value for a cache entry
type CacheVal struct {
	ValidUntil time.Time
	Response   *dns.Msg
}

func getKey(req *dns.Msg) (*CacheKey, error) {
	questions := req.Question
	if len(questions) != 1 {
		return nil, errors.New("Invalid number of questions")
	}
	question := questions[0]
	if question.Qclass != dns.ClassINET {
		return nil, errors.New("Unsupported question class")
	}
	if dns.CountLabel(question.Name) < *minLabelsCount {
		return nil, errors.New("Not enough labels")
	}
	dnssec := false
	for _, extra := range req.Extra {
		if extra.Header().Rrtype == dns.TypeOPT {
			dnssec = extra.(*dns.OPT).Do()
		}
	}
	CacheKey := CacheKey{Name: strings.ToLower(question.Name),
		Qtype: question.Qtype, DNSSEC: dnssec}
	return &CacheKey, nil
}

func getMaxPayloadSize(req *dns.Msg) uint16 {
	opt := req.IsEdns0()
	if opt == nil {
		return dns.MinMsgSize
	}
	maxPayloadSize := opt.UDPSize()
	if maxPayloadSize < dns.MinMsgSize {
		maxPayloadSize = dns.MinMsgSize
	}
	return maxPayloadSize
}

func pickUpstream(req *dns.Msg) (*string, error) {
	name := strings.ToLower(req.Question[0].Name)
	h := siphash.Hash(sipHashKey.k1, sipHashKey.k2, []byte(name))
	upstreamServers.lock.RLock()
	liveCount := uint64(len(upstreamServers.live))
	if liveCount <= 0 {
		upstreamServers.lock.RUnlock()
		return nil, errors.New("All upstream servers are down")
	}
	i := h / (math.MaxUint64 / liveCount)
	if i >= liveCount {
		i = liveCount - 1
	}
	res := upstreamServers.live[i]
	upstreamServers.lock.RUnlock()
	return &res, nil
}

func markFailed(addr string) {
	upstreamServers.lock.Lock()
	defer upstreamServers.lock.Unlock()
	for i, server := range upstreamServers.servers {
		if server.addr != addr {
			continue
		}
		if server.offline {
			return
		}
		upstreamServers.servers[i].failures++
		if upstreamServers.servers[i].failures < MaxFailures {
			return
		}
		break
	}
	servers := upstreamServers.servers
	live := []string{}
	for i, server := range upstreamServers.servers {
		if server.addr == addr {
			servers[i].offline = true
		} else if server.offline == false {
			live = append(live, server.addr)
		}
	}
	upstreamServers.servers = servers
	upstreamServers.live = live
	log.Printf("[%v] is unresponsive", addr)
}

func resetRTT() {
	upstreamRtt.lock.Lock()
	defer upstreamRtt.lock.Unlock()
	upstreamRtt.count = 0.0
	upstreamRtt.RTT = 0.0
}

func resetUpstreamServers() {
	upstreamServers.lock.Lock()
	defer upstreamServers.lock.Unlock()
	servers := upstreamServers.servers
	if len(servers) == len(upstreamServers.live) {
		return
	}
	live := []string{}
	for i, server := range upstreamServers.servers {
		servers[i].failures = 0
		servers[i].offline = false
		live = append(live, server.addr)
	}
	upstreamServers.servers = servers
	upstreamServers.live = live
	resetRTT()
}

func syncResolve(req *dns.Msg) (*dns.Msg, time.Duration, error) {
	curPending := atomic.AddUint32(&pending, uint32(1))
	defer atomic.AddUint32(&pending, ^uint32(0))
	if uint(curPending) > *maxClients {
		return nil, 0, errors.New("Too many clients")
	}
	addr, err := pickUpstream(req)
	if err != nil {
		return nil, 0, err
	}
	client := &dns.Client{Net: "udp"}
	client.SingleInflight = true
	resolved, rtt, err := client.Exchange(req, *addr)
	if err != nil {
		markFailed(*addr)
		return nil, 0, err
	}
	if resolved.Truncated {
		client = &dns.Client{Net: "tcp"}
		client.SingleInflight = true
		resolved, rtt, err = client.Exchange(req, *addr)
	}
	upstreamRtt.lock.Lock()
	upstreamRtt.count++
	upstreamRtt.RTT += rtt.Seconds()
	meanRTT := upstreamRtt.RTT / (upstreamRtt.count + BayesianAverageC)
	upstreamRtt.lock.Unlock()
	if meanRTT > *maxRTT {
		markFailed(*addr)
	}
	return resolved, rtt, nil
}

func resolve(req *dns.Msg, dnssec bool) (*dns.Msg, error) {
	extra2 := []dns.RR{}
	for _, extra := range req.Extra {
		if extra.Header().Rrtype != dns.TypeOPT {
			extra2 = append(extra2, extra)
		}
	}
	req.Extra = extra2
	req.SetEdns0(dns.MaxMsgSize, dnssec)
	resolved, _, err := syncResolve(req)
	if err != nil {
		return nil, err
	}
	resolved.Compress = true
	return resolved, nil
}

func getMinTTL(resp *dns.Msg) time.Duration {
	ttl := uint32(MaxTTL)
	for _, rr := range resp.Answer {
		if rr.Header().Ttl < ttl {
			ttl = rr.Header().Ttl
		}
	}
	if ttl < MinTTL {
		ttl = MaxTTL
	}
	return time.Duration(ttl) * time.Second
}

func sendTruncated(w dns.ResponseWriter, msgHdr dns.MsgHdr) {
	emptyResp := new(dns.Msg)
	emptyResp.MsgHdr = msgHdr
	emptyResp.Truncated = true
	w.WriteMsg(emptyResp)
}

func vacuumThread() {
	for {
		time.Sleep(VacuumPeriod * time.Second)
		resetUpstreamServers()
		memStats := new(runtime.MemStats)
		runtime.ReadMemStats(memStats)
		if memStats.Alloc > (*memSize)*1024*1024 {
			cache.Purge()
		}
	}
}

func failWithRcode(w dns.ResponseWriter, r *dns.Msg, rCode int) {
	m := new(dns.Msg)
	m.SetRcode(r, rCode)
	w.WriteMsg(m)
}

func handleSpecialNames(w dns.ResponseWriter, req *dns.Msg) bool {
	question := req.Question[0]
	if question.Qtype != dns.TypeANY {
		return false
	}
	m := new(dns.Msg)
	m.Id = req.Id
	hinfo := new(dns.HINFO)
	hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO,
		Class: dns.ClassINET, Ttl: 86400}
	hinfo.Cpu = "ANY is not supported any more"
	hinfo.Os = "See draft-jabley-dnsop-refuse-any"
	m.Answer = []dns.RR{hinfo}
	w.WriteMsg(m)
	return true
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	keyP, err := getKey(req)
	if err != nil {
		failWithRcode(w, req, dns.RcodeRefused)
		return
	}
	if handleSpecialNames(w, req) {
		return
	}
	maxPayloadSize := getMaxPayloadSize(req)
	var resp *dns.Msg
	cacheValP, _ := cache.Get(*keyP)
	if cacheValP != nil {
		cacheVal := cacheValP.(CacheVal)
		remaining := -time.Since(cacheVal.ValidUntil)
		if remaining > 0 {
			resp = cacheVal.Response.Copy()
			resp.Id = req.Id
			resp.Question = req.Question
		}
	}
	if resp == nil {
		resp, err = resolve(req, keyP.DNSSEC)
		if err != nil {
			dns.HandleFailed(w, req)
			return
		}
		validUntil := time.Now().Add(getMinTTL(resp))
		cache.Add(*keyP, CacheVal{ValidUntil: validUntil, Response: resp})
	}
	packed, _ := resp.Pack()
	packedLen := len(packed)
	if uint16(packedLen) > maxPayloadSize {
		sendTruncated(w, resp.MsgHdr)
	} else {
		w.WriteMsg(resp)
	}
}
<commit_msg>Remove default values from flag descriptions<commit_after>package main

import (
	"crypto/rand"
	"encoding/binary"
	"errors"
	"flag"
	"fmt"
	"log"
	"math"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/dchest/siphash"
	"github.com/hashicorp/golang-lru"
	"github.com/miekg/dns"
)

const (
	// BayesianAverageC Constant for the Bayesian average for the RTT
	BayesianAverageC = 10
	// MaxFailures Maximum number of unanswered queries before a server is marked as dead for VacuumPeriod
	MaxFailures = 10
	// MinTTL Minimum TTL
	MinTTL = 60
	// MaxTTL Maximum TTL
	MaxTTL = 604800
	// VacuumPeriod Vacuum period in seconds
	VacuumPeriod = 30
)

// SipHashKey SipHash secret key
type SipHashKey struct {
	k1 uint64
	k2 uint64
}

// UpstreamServer Upstream server
type UpstreamServer struct {
	addr     string
	failures uint
	offline  bool
}

// UpstreamServers List of upstream servers
type UpstreamServers struct {
	lock    sync.RWMutex
	servers []UpstreamServer
	live    []string
}

// UpstreamRTT Keep track of the mean RTT
type UpstreamRTT struct {
	lock  sync.Mutex
	RTT   float64
	count float64
}

var (
	address            = flag.String("listen", ":53", "Address to listen to (TCP and UDP)")
	upstreamServersStr = flag.String("upstream", "8.8.8.8:53,8.8.4.4:53", "Comma-delimited list of upstream servers")
	upstreamServers    *UpstreamServers
	cacheSize          = flag.Int("cachesize", 10000000, "Cache size")
	memSize            = flag.Uint64("memsize", 1*1024, "Memory size in MB")
	minLabelsCount     = flag.Int("minlabels", 2, "Minimum number of labels")
	cache              *lru.ARCCache
	sipHashKey         = SipHashKey{k1: 0, k2: 0}
	pending            = uint32(0)
	maxClients         = flag.Uint("maxclients", 10000, "Maximum number of simultaneous clients")
	maxRTT             = flag.Float64("maxrtt", 0.25, "Maximum mean RTT for upstream queries before marking a server as dead")
	upstreamRtt        UpstreamRTT
)

func parseUpstreamServers(str string) (*UpstreamServers, error) {
	servers := []UpstreamServer{}
	live := []string{}
	for _, addr := range strings.Split(str, ",") {
		server := UpstreamServer{addr: addr}
		servers = append(servers, server)
		live = append(live, addr)
	}
	res := UpstreamServers{servers: servers, live: live}
	return &res, nil
}

func randUint64() uint64 {
	buf := make([]byte, 8)
	length, err := rand.Read(buf)
	if err != nil || length != len(buf) {
		log.Fatal("RNG failure")
	}
	return binary.LittleEndian.Uint64(buf)
}

func main() {
	flag.Parse()
	*memSize *= 1024 * 1024
	if *cacheSize < 2 {
		log.Fatal("Cache size too small")
	}
	cache, _ = lru.NewARC(*cacheSize)
	upstreamServers, _ = parseUpstreamServers(*upstreamServersStr)
	sipHashKey = SipHashKey{k1: randUint64(), k2: randUint64()}
	fmt.Println("RPDNS")
	dns.HandleFunc(".", route)
	udpServer := &dns.Server{Addr: *address, Net: "udp"}
	tcpServer := &dns.Server{Addr: *address, Net: "tcp"}
	go func() {
		log.Fatal(udpServer.ListenAndServe())
	}()
	go func() {
		log.Fatal(tcpServer.ListenAndServe())
	}()
	vacuumThread()
}

// CacheKey Key for a cache entry
type CacheKey struct {
	Name   string `dns:"cdomain-name"`
	Qtype  uint16
	DNSSEC bool
}

// CacheVal Value for a cache entry
type CacheVal struct {
	ValidUntil time.Time
	Response   *dns.Msg
}

func getKey(req *dns.Msg) (*CacheKey, error) {
	questions := req.Question
	if len(questions) != 1 {
		return nil, errors.New("Invalid number of questions")
	}
	question := questions[0]
	if question.Qclass != dns.ClassINET {
		return nil, errors.New("Unsupported question class")
	}
	if dns.CountLabel(question.Name) < *minLabelsCount {
		return nil, errors.New("Not enough labels")
	}
	dnssec := false
	for _, extra := range req.Extra {
		if extra.Header().Rrtype == dns.TypeOPT {
			dnssec = extra.(*dns.OPT).Do()
		}
	}
	CacheKey := CacheKey{Name: strings.ToLower(question.Name),
		Qtype: question.Qtype, DNSSEC: dnssec}
	return &CacheKey, nil
}

func getMaxPayloadSize(req *dns.Msg) uint16 {
	opt := req.IsEdns0()
	if opt == nil {
		return dns.MinMsgSize
	}
	maxPayloadSize := opt.UDPSize()
	if maxPayloadSize < dns.MinMsgSize {
		maxPayloadSize = dns.MinMsgSize
	}
	return maxPayloadSize
}

func pickUpstream(req *dns.Msg) (*string, error) {
	name := strings.ToLower(req.Question[0].Name)
	h := siphash.Hash(sipHashKey.k1, sipHashKey.k2, []byte(name))
	upstreamServers.lock.RLock()
	liveCount := uint64(len(upstreamServers.live))
	if liveCount <= 0 {
		upstreamServers.lock.RUnlock()
		return nil, errors.New("All upstream servers are down")
	}
	i := h / (math.MaxUint64 / liveCount)
	if i >= liveCount {
		i = liveCount - 1
	}
	res := upstreamServers.live[i]
	upstreamServers.lock.RUnlock()
	return &res, nil
}

func markFailed(addr string) {
	upstreamServers.lock.Lock()
	defer upstreamServers.lock.Unlock()
	for i, server := range upstreamServers.servers {
		if server.addr != addr {
			continue
		}
		if server.offline {
			return
		}
		upstreamServers.servers[i].failures++
		if upstreamServers.servers[i].failures < MaxFailures {
			return
		}
		break
	}
	servers := upstreamServers.servers
	live := []string{}
	for i, server := range upstreamServers.servers {
		if server.addr == addr {
			servers[i].offline = true
		} else if server.offline == false {
			live = append(live, server.addr)
		}
	}
	upstreamServers.servers = servers
	upstreamServers.live = live
	log.Printf("[%v] is unresponsive", addr)
}

func resetRTT() {
	upstreamRtt.lock.Lock()
	defer upstreamRtt.lock.Unlock()
	upstreamRtt.count = 0.0
	upstreamRtt.RTT = 0.0
}

func resetUpstreamServers() {
	upstreamServers.lock.Lock()
	defer upstreamServers.lock.Unlock()
	servers := upstreamServers.servers
	if len(servers) == len(upstreamServers.live) {
		return
	}
	live := []string{}
	for i, server := range upstreamServers.servers {
		servers[i].failures = 0
		servers[i].offline = false
		live = append(live, server.addr)
	}
	upstreamServers.servers = servers
	upstreamServers.live = live
	resetRTT()
}

func syncResolve(req *dns.Msg) (*dns.Msg, time.Duration, error) {
	curPending := atomic.AddUint32(&pending, uint32(1))
	defer atomic.AddUint32(&pending, ^uint32(0))
	if uint(curPending) > *maxClients {
		return nil, 0, errors.New("Too many clients")
	}
	addr, err := pickUpstream(req)
	if err != nil {
		return nil, 0, err
	}
	client := &dns.Client{Net: "udp"}
	client.SingleInflight = true
	resolved, rtt, err := client.Exchange(req, *addr)
	if err != nil {
		markFailed(*addr)
		return nil, 0, err
	}
	if resolved.Truncated {
		client = &dns.Client{Net: "tcp"}
		client.SingleInflight = true
		resolved, rtt, err = client.Exchange(req, *addr)
	}
	upstreamRtt.lock.Lock()
	upstreamRtt.count++
	upstreamRtt.RTT += rtt.Seconds()
	meanRTT := upstreamRtt.RTT / (upstreamRtt.count + BayesianAverageC)
	upstreamRtt.lock.Unlock()
	if meanRTT > *maxRTT {
		markFailed(*addr)
	}
	return resolved, rtt, nil
}

func resolve(req *dns.Msg, dnssec bool) (*dns.Msg, error) {
	extra2 := []dns.RR{}
	for _, extra := range req.Extra {
		if extra.Header().Rrtype != dns.TypeOPT {
			extra2 = append(extra2, extra)
		}
	}
	req.Extra = extra2
	req.SetEdns0(dns.MaxMsgSize, dnssec)
	resolved, _, err := syncResolve(req)
	if err != nil {
		return nil, err
	}
	resolved.Compress = true
	return resolved, nil
}

func getMinTTL(resp *dns.Msg) time.Duration {
	ttl := uint32(MaxTTL)
	for _, rr := range resp.Answer {
		if rr.Header().Ttl < ttl {
			ttl = rr.Header().Ttl
		}
	}
	if ttl < MinTTL {
		ttl = MaxTTL
	}
	return time.Duration(ttl) * time.Second
}

func sendTruncated(w dns.ResponseWriter, msgHdr dns.MsgHdr) {
	emptyResp := new(dns.Msg)
	emptyResp.MsgHdr = msgHdr
	emptyResp.Truncated = true
	w.WriteMsg(emptyResp)
}

func vacuumThread() {
	for {
		time.Sleep(VacuumPeriod * time.Second)
		resetUpstreamServers()
		memStats := new(runtime.MemStats)
		runtime.ReadMemStats(memStats)
		if memStats.Alloc > (*memSize)*1024*1024 {
			cache.Purge()
		}
	}
}

func failWithRcode(w dns.ResponseWriter, r *dns.Msg, rCode int) {
	m := new(dns.Msg)
	m.SetRcode(r, rCode)
	w.WriteMsg(m)
}

func handleSpecialNames(w dns.ResponseWriter, req *dns.Msg) bool {
	question := req.Question[0]
	if question.Qtype != dns.TypeANY {
		return false
	}
	m := new(dns.Msg)
	m.Id = req.Id
	hinfo := new(dns.HINFO)
	hinfo.Hdr = dns.RR_Header{Name: question.Name, Rrtype: dns.TypeHINFO,
		Class: dns.ClassINET, Ttl: 86400}
	hinfo.Cpu = "ANY is not supported any more"
	hinfo.Os = "See draft-jabley-dnsop-refuse-any"
	m.Answer = []dns.RR{hinfo}
	w.WriteMsg(m)
	return true
}

func route(w dns.ResponseWriter, req *dns.Msg) {
	keyP, err := getKey(req)
	if err != nil {
		failWithRcode(w, req, dns.RcodeRefused)
		return
	}
	if handleSpecialNames(w, req) {
		return
	}
	maxPayloadSize := getMaxPayloadSize(req)
	var resp *dns.Msg
	cacheValP, _ := cache.Get(*keyP)
	if cacheValP != nil {
		cacheVal := cacheValP.(CacheVal)
		remaining := -time.Since(cacheVal.ValidUntil)
		if remaining > 0 {
			resp = cacheVal.Response.Copy()
			resp.Id = req.Id
			resp.Question = req.Question
		}
	}
	if resp == nil {
		resp, err = resolve(req, keyP.DNSSEC)
		if err != nil {
			dns.HandleFailed(w, req)
			return
		}
		validUntil := time.Now().Add(getMinTTL(resp))
		cache.Add(*keyP, CacheVal{ValidUntil: validUntil, Response: resp})
	}
	packed, _ := resp.Pack()
	packedLen := len(packed)
	if uint16(packedLen) > maxPayloadSize {
		sendTruncated(w, resp.MsgHdr)
	} else {
		w.WriteMsg(resp)
	}
}
<|endoftext|>


<commit_before>package privileges

type Rules struct {
	owner string
	group string
	rules uint16
}

func NewRules(owner, group, rules string) (*Rules, error) {
	if !validRules(rules) {
		return nil, errBadRulesString
	}

	var a uint16
	for i := 1; i < 4; i++ {
		a = a<<4 | uint16(rules[i]-'0')
	}
	r := new(Rules)
	r.owner = owner
	r.group = group
	r.rules = a
	return r, nil
}

func validRules(rules string) bool {
	if len(rules) != 4 || rules[0] != '0' {
		return false
	}
	for i := 1; i < 4; i++ {
		if rules[i] < '0' || rules[i] > '7' {
			return false
		}
	}
	return true
}

// Rules returns the octal representation of the file's permissions (0777)
func (r *Rules) Rules() string {
	a := []byte("0")
	for i := 2; i >= 0; i-- {
		a = append(a, byte(r.rules>>(4*uint(i))&7+'0'))
	}
	return string(a)
}

// Owner returns a string naming the user owner identified by the permissions
func (r *Rules) Owner() string {
	return r.owner
}

// Group returns a string naming the group identified by the permissions
func (r *Rules) Group() string {
	return r.group
}

func (r *Rules) Symbolic(directory bool) string {
	sym := []byte("----------")
	if directory {
		sym[0] = 'd'
	}

	if r.rules>>10&1 == 1 {
		sym[1] = 'r'
	}

	if r.rules>>9&1 == 1 {
		sym[2] = 'w'
	}

	if r.rules>>8&1 == 1 {
		sym[3] = 'x'
	}

	if r.rules>>6&1 == 1 {
		sym[4] = 'r'
	}

	if r.rules>>5&1 == 1 {
		sym[5] = 'w'
	}

	if r.rules>>4&1 == 1 {
		sym[6] = 'x'
	}

	if r.rules>>2&1 == 1 {
		sym[7] = 'r'
	}

	if r.rules>>1&1 == 1 {
		sym[8] = 'w'
	}

	if r.rules>>0&1 == 1 {
		sym[9] = 'x'
	}

	sym = append(sym, ' ')
	sym = append(sym, []byte(r.owner)...)

	sym = append(sym, ' ')
	sym = append(sym, []byte(r.group)...)

	return string(sym)
}
<commit_msg>minor changes<commit_after>package privileges

type Rules struct {
	owner string
	group string
	rules uint16
}

func (r *Rules) Rules() *Rules {
	return r
}

func (r *Rules) Read(args ...string) interface{} {
	return nil
}

func (r *Rules) Write(args ...string) interface{} {
	return nil
}

func (r *Rules) Exec(args ...string) interface{} {
	return nil
}

func NewRules(owner, group, rules string) (*Rules, error) {
	if !validRules(rules) {
		return nil, errBadRulesString
	}

	var a uint16
	for i := 1; i < 4; i++ {
		a = a<<4 | uint16(rules[i]-'0')
	}
	r := new(Rules)
	r.owner = owner
	r.group = group
	r.rules = a
	return r, nil
}

func validRules(rules string) bool {
	if len(rules) != 4 || rules[0] != '0' {
		return false
	}
	for i := 1; i < 4; i++ {
		if rules[i] < '0' || rules[i] > '7' {
			return false
		}
	}
	return true
}

// Rules returns the octal representation of the file's permissions (0777)
func (r *Rules) Octal() string {
	a := []byte("0")
	for i := 2; i >= 0; i-- {
		a = append(a, byte(r.rules>>(4*uint(i))&7+'0'))
	}
	return string(a)
}

// Owner returns a string naming the user owner identified by the permissions
func (r *Rules) Owner() string {
	return r.owner
}

// Group returns a string naming the group identified by the permissions
func (r *Rules) Group() string {
	return r.group
}

func (r *Rules) Symbolic(directory bool) string {
	sym := []byte("----------")
	if directory {
		sym[0] = 'd'
	}

	if r.rules>>10&1 == 1 {
		sym[1] = 'r'
	}

	if r.rules>>9&1 == 1 {
		sym[2] = 'w'
	}

	if r.rules>>8&1 == 1 {
		sym[3] = 'x'
	}

	if r.rules>>6&1 == 1 {
		sym[4] = 'r'
	}

	if r.rules>>5&1 == 1 {
		sym[5] = 'w'
	}

	if r.rules>>4&1 == 1 {
		sym[6] = 'x'
	}

	if r.rules>>2&1 == 1 {
		sym[7] = 'r'
	}

	if r.rules>>1&1 == 1 {
		sym[8] = 'w'
	}

	if r.rules>>0&1 == 1 {
		sym[9] = 'x'
	}

	sym = append(sym, ' ')
	sym = append(sym, []byte(r.owner)...)

	sym = append(sym, ' ')
	sym = append(sym, []byte(r.group)...)

	return string(sym)
}
<|endoftext|>


<commit_before>package models

import (
	"os"
	"time"

	"github.com/go-martini/martini"
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

type Model struct {
	ID        int64 `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}

var DB gorm.DB

func init() {
	var err error

	switch martini.Env {
	case "production":
		DB, err = gorm.Open("postgres", os.Getenv("DSN"))
		if err != nil {
			panic(err)
		}

		DB.DB()
		DB.DB().Ping()
		DB.DB().SetMaxIdleConns(100)
		DB.DB().SetMaxOpenConns(100)
	default:
		DB, err = gorm.Open("sqlite3", os.Getenv("DSN"))
		if err != nil {
			panic(err)
		}

		DB.DB()
		DB.LogMode(true)
	}

	DB.AutoMigrate(&Dict{}, &Tag{}, &Category{}, &Image{})

	InitSeed()
}

func InitSeed() {
	cate := new(Category)
	DB.Where(Category{Name: "アイドル・女優"}).
		Attrs(Category{Yomi: "あいどるじょゆう", Romaji: "aidorujoyu", Gyou: "a", Prefix: "diva"}).
		FirstOrCreate(&cate)
	cate = new(Category)
	DB.Where(Category{Name: "漫画・アニメ"}).
		Attrs(Category{Yomi: "まんがあにめ", Romaji: "mangaanime", Gyou: "ma", Prefix: "anime"}).
		FirstOrCreate(&cate)
	cate = new(Category)
	DB.Where(Category{Name: "漫画・アニメキャラ"}).
		Attrs(Category{Yomi: "まんがあにめきゃら", Romaji: "mangaanimekyara", Gyou: "ma", Prefix: "character"}).
		FirstOrCreate(&cate)
}
<commit_msg>modify seed data for development<commit_after>package models

import (
	"crypto/rand"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"time"

	"github.com/go-martini/martini"
	"github.com/ikeikeikeike/gopkg/rdm"
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

type Model struct {
	ID        int64 `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}

var DB gorm.DB

func init() {
	var err error

	switch martini.Env {
	case "production":
		DB, err = gorm.Open("postgres", os.Getenv("DSN"))
		if err != nil {
			panic(err)
		}

		DB.DB()
		DB.DB().Ping()
		DB.DB().SetMaxIdleConns(100)
		DB.DB().SetMaxOpenConns(100)
	default:
		DB, err = gorm.Open("sqlite3", os.Getenv("DSN"))
		if err != nil {
			panic(err)
		}

		DB.DB()
		DB.LogMode(true)
	}

	DB.AutoMigrate(&Dict{}, &Tag{}, &Category{}, &Image{})

	InitSeed()
}

func InitSeed() {
	cate := new(Category)
	DB.Where(Category{Name: "ノンカテゴリー"}).
		Attrs(Category{Yomi: "のんかてごり", Romaji: "nonkategori", Gyou: "no", Prefix: "none"}).
		FirstOrCreate(&cate)

	cate = new(Category)
	DB.Where(Category{Name: "アイドル・女優"}).
		Attrs(Category{Yomi: "あいどるじょゆう", Romaji: "aidorujoyu", Gyou: "a", Prefix: "diva"}).
		FirstOrCreate(&cate)

	cate = new(Category)
	DB.Where(Category{Name: "漫画・アニメ"}).
		Attrs(Category{Yomi: "まんがあにめ", Romaji: "mangaanime", Gyou: "ma", Prefix: "anime"}).
		FirstOrCreate(&cate)

	cate = new(Category)
	DB.Where(Category{Name: "漫画・アニメキャラ"}).
		Attrs(Category{Yomi: "まんがあにめきゃら", Romaji: "mangaanimekyara", Gyou: "ma", Prefix: "character"}).
		FirstOrCreate(&cate)

	if martini.Env != "production" {

		basePath, _ := os.Getwd()
		bytes, err := ioutil.ReadFile(path.Join(basePath, "template.txt"))

		i := 0
		for i < 100 {
			name := letterCombinePtn(7)

			content := ""
			if err == nil {
				content = fmt.Sprintf(string(bytes), name)
			}

			c := &Category{}
			DB.First(c, int64(rdm.RandomNumber(1, 5)))

			d := new(Dict)
			DB.Where(Dict{Name: name}).
				Attrs(Dict{
				Yomi:     letterCombinePtn(3),
				Prefix:   letterCombinePtn(7),
				Content:  content,
				Category: c,
			}).
				FirstOrCreate(&d)
			i++
		}
	}
}

func letterCombinePtn(n int) string {
	const letters = "abcdefg" // 7P7=7*6*5*4*3*2*1=5040
	var bytes = make([]byte, n)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = letters[b%byte(len(letters))]
	}
	return string(bytes)
}
<|endoftext|>


<commit_before>// tsadmin/database
package database

import (
	"database/sql"
	"fmt"
	"log"
	"strconv"

	_ "github.com/go-sql-driver/mysql"
)

type Database struct {
	Name     string `json:"name"`
	Host     string `json:"host"`
	Port     int    `json:"port"`
	User     string `json:"username"`
	Password string `json:"password"`
}

type DatabaseStatus struct {
	Metadata  DatabaseMetadata  `json:"metadata"`
	Metrics   DatabaseMetrics   `json:"metrics"`
	Variables DatabaseVariables `json:"variables"`
}

type DatabaseMetadata struct {
	Name string `json:"name"`
	Host string `json:"host"`
	Port int    `json:"port"`
}

type DatabaseMetrics struct {
	CurrentConnections          int `json:"current_connections"`
	ConnectionsPerSecond        int `json:"connections_per_second"`
	AbortedConnectionsPerSecond int `json:"aborted_connections_per_second"`
	QueriesPerSecond            int `json:"queries_per_second"`
	ReadsPerSecond              int `json:"reads_per_second"`
	WritesPerSecond             int `json:"writes_per_second"`
	Uptime                      int `json:"uptime"`
	connections                 int
	abortedConnections          int
	queries                     int
	reads                       int
	writes                      int
}

type DatabaseVariables struct {
	MaxConnections int `json:"max_connections"`
}

func (db *Database) String() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/performance_schema", db.User, db.Password, db.Host, db.Port)
}

func Status(db Database, previous *DatabaseStatus) (*DatabaseStatus, error) {
	status := &DatabaseStatus{
		Metadata: DatabaseMetadata{
			Name: db.Name,
			Host: db.Host,
			Port: db.Port,
		},
		Metrics:   DatabaseMetrics{},
		Variables: DatabaseVariables{},
	}

	// Fetch the metrics
	err := execQuery(db, "metrics", previous, status)

	if err != nil {
		return nil, err
	}

	// Fetch the variables
	err = execQuery(db, "variables", previous, status)

	if err != nil {
		return nil, err
	}

	return status, nil
}

// Execute a query on the given database for looking up metrics/variables
func execQuery(db Database, queryType string, previous *DatabaseStatus, status *DatabaseStatus) error {
	var (
		key   string
		value string
		table string
	)

	// Fetch all the db metrics/variables
	if queryType == "metrics" {
		table = "GLOBAL_STATUS"
	} else if queryType == "variables" {
		table = "GLOBAL_VARIABLES"
	} else {
		log.Fatal("Unknown queryType")
	}

	// Connect to the database
	conn, err := sql.Open("mysql", db.String())

	if err != nil {
		return err
	}

	defer conn.Close()

	// Fetch all the db metrics
	rows, err := conn.Query(fmt.Sprintf("SELECT VARIABLE_NAME AS 'key', VARIABLE_VALUE AS 'value' FROM %s", table))

	// Handle query errors
	if err != nil {
		return err
	}

	defer rows.Close()

	// Loop each metric/variable in the server status
	for rows.Next() {
		err := rows.Scan(&key, &value)

		// Handle row reading errors
		if err != nil {
			return err
		}

		// Process the metrics/variables
		if queryType == "metrics" {
			err = processMetric(previous, status, key, value)
		} else {
			err = processVariable(status, key, value)
		}

		if err != nil {
			return err
		}
	}

	// Do some final processing of the metrics
	err = postProcessMetrics(previous, status)

	if err != nil {
		return err
	}

	// Check for any remaining errors
	err = rows.Err()

	return err
}

// Process metric returned from the GLOBAL_STATUS table
func processMetric(previous *DatabaseStatus, status *DatabaseStatus, key string, value string) error {
	var (
		err                error
		currentConnections int
		connections        int
		diff               int
		abortedConnections int
		queries            int
		uptime             int
		readWriteValue     int
	)

	switch key {
	// Current connections
	case "THREADS_CONNECTED":
		currentConnections, err = strconv.Atoi(value)
		status.Metrics.CurrentConnections = currentConnections
	// Connections per second
	case "CONNECTIONS":
		connections, err = strconv.Atoi(value)

		// If we don't have a previous value for the total connections
		// then cps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.connections == 0 {
			status.Metrics.ConnectionsPerSecond = 0
			status.Metrics.connections = connections
		// Otherwise the value of cps is the diff between the current
		// and previous count of connections
		} else {
			diff = connections - previous.Metrics.connections

			// cps can never be below 0..
			if diff > 0 {
				status.Metrics.ConnectionsPerSecond = diff
			} else {
				status.Metrics.ConnectionsPerSecond = 0
			}

			status.Metrics.connections = connections
		}
	// Aborted connections per second
	case "ABORTED_CONNECTS":
		abortedConnections, err = strconv.Atoi(value)

		// If we don't have a previous value for the total aborted connections
		// then acps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.abortedConnections == 0 {
			status.Metrics.AbortedConnectionsPerSecond = 0
			status.Metrics.abortedConnections = abortedConnections
		// Otherwise the value of acps is the diff between the current
		// and previous count of connections
		} else {
			diff = abortedConnections - previous.Metrics.abortedConnections

			// acps can never be below 0..
			if diff > 0 {
				status.Metrics.AbortedConnectionsPerSecond = diff
			} else {
				status.Metrics.AbortedConnectionsPerSecond = 0
			}

			status.Metrics.abortedConnections = abortedConnections
		}
	// Queries per second
	case "QUERIES":
		queries, err = strconv.Atoi(value)

		// If we don't have a previous value for the total queries
		// then qps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.queries == 0 {
			status.Metrics.QueriesPerSecond = 0
			status.Metrics.queries = queries
		// Otherwise the value of qps is the diff between the current
		// and previous count of queries
		} else {
			diff = queries - previous.Metrics.queries

			// qps can never be below 0..
			if diff > 0 {
				status.Metrics.QueriesPerSecond = diff
			} else {
				status.Metrics.QueriesPerSecond = 0
			}

			status.Metrics.queries = queries
		}
	// Read/Writes per second
	case "COM_SELECT", "COM_INSERT_SELECT", "COM_REPLACE_SELECT", "COM_DELETE", "COM_INSERT", "COM_UPDATE", "COM_REPLACE":
		readWriteValue, err = strconv.Atoi(value)

		// Reads
		if key == "COM_SELECT" || key == "COM_INSERT_SELECT" || key == "COM_REPLACE_SELECT" {
			status.Metrics.reads += readWriteValue

			// Reads/Writes
			if key == "COM_INSERT_SELECT" || key == "COM_REPLACE_SELECT" {
				status.Metrics.writes += readWriteValue
			}
		// Writes
		} else {
			status.Metrics.writes += readWriteValue
		}
	// Uptime
	case "UPTIME":
		uptime, err = strconv.Atoi(value)
		status.Metrics.Uptime = uptime
	}

	if err != nil {
		return err
	} else {
		return nil
	}
}

// Process variables returned from the GLOBAL_VARIABLES table
func processVariable(status *DatabaseStatus, key string, value string) error {
	var (
		err            error
		maxConnections int
	)

	// Max allowed connections
	if key == "MAX_CONNECTIONS" {
		maxConnections, err = strconv.Atoi(value)
		status.Variables.MaxConnections = maxConnections
	}

	if err != nil {
		return err
	}

	return nil
}

// Post processing of metrics
func postProcessMetrics(previous *DatabaseStatus, status *DatabaseStatus) error {
	var diff int

	// If we don't have a previous value for the total reads
	// then rps is technically 0 as we don't know it yet
	if previous != nil {
		// Calculate the RPS
		diff = status.Metrics.reads - previous.Metrics.reads

		// rps can never be below 0..
		if diff > 0 {
			status.Metrics.ReadsPerSecond = diff
		} else {
			status.Metrics.ReadsPerSecond = 0
		}

		// Calculate the WPS
		diff = status.Metrics.writes - previous.Metrics.writes

		// wps can never be below 0..
		if diff > 0 {
			status.Metrics.WritesPerSecond = diff
		} else {
			status.Metrics.WritesPerSecond = 0
		}
	}

	return nil
}
<commit_msg>Fix for MySQL 5.7<commit_after>// tsadmin/database
package database

import (
	"database/sql"
	"fmt"
	"log"
	"strconv"

	_ "github.com/go-sql-driver/mysql"
)

type Database struct {
	Name     string `json:"name"`
	Host     string `json:"host"`
	Port     int    `json:"port"`
	User     string `json:"username"`
	Password string `json:"password"`
}

type DatabaseStatus struct {
	Metadata  DatabaseMetadata  `json:"metadata"`
	Metrics   DatabaseMetrics   `json:"metrics"`
	Variables DatabaseVariables `json:"variables"`
}

type DatabaseMetadata struct {
	Name string `json:"name"`
	Host string `json:"host"`
	Port int    `json:"port"`
}

type DatabaseMetrics struct {
	CurrentConnections          int `json:"current_connections"`
	ConnectionsPerSecond        int `json:"connections_per_second"`
	AbortedConnectionsPerSecond int `json:"aborted_connections_per_second"`
	QueriesPerSecond            int `json:"queries_per_second"`
	ReadsPerSecond              int `json:"reads_per_second"`
	WritesPerSecond             int `json:"writes_per_second"`
	Uptime                      int `json:"uptime"`
	connections                 int
	abortedConnections          int
	queries                     int
	reads                       int
	writes                      int
}

type DatabaseVariables struct {
	MaxConnections int `json:"max_connections"`
}

func (db *Database) String() string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/information_schema", db.User, db.Password, db.Host, db.Port)
}

func Status(db Database, previous *DatabaseStatus) (*DatabaseStatus, error) {
	status := &DatabaseStatus{
		Metadata: DatabaseMetadata{
			Name: db.Name,
			Host: db.Host,
			Port: db.Port,
		},
		Metrics:   DatabaseMetrics{},
		Variables: DatabaseVariables{},
	}

	// Fetch the metrics
	err := execQuery(db, "metrics", previous, status)

	if err != nil {
		return nil, err
	}

	// Fetch the variables
	err = execQuery(db, "variables", previous, status)

	if err != nil {
		return nil, err
	}

	return status, nil
}

// Execute a query on the given database for looking up metrics/variables
func execQuery(db Database, queryType string, previous *DatabaseStatus, status *DatabaseStatus) error {
	var (
		key   string
		value string
		table string
	)

	// Fetch all the db metrics/variables
	if queryType == "metrics" {
		table = "GLOBAL_STATUS"
	} else if queryType == "variables" {
		table = "GLOBAL_VARIABLES"
	} else {
		log.Fatal("Unknown queryType")
	}

	// Connect to the database
	conn, err := sql.Open("mysql", db.String())

	if err != nil {
		return err
	}

	defer conn.Close()

	// Put MySQL in 5.6 compatability mode as the location of some of the metrics has chagned in 5.7
	_, err = conn.Query("SET GLOBAL show_compatibility_56 = ON")

	if err != nil {
		return err
	}

	// Fetch all the db metrics
	rows, err := conn.Query(fmt.Sprintf("SELECT VARIABLE_NAME AS 'key', VARIABLE_VALUE AS 'value' FROM %s", table))

	// Handle query errors
	if err != nil {
		return err
	}

	defer rows.Close()

	// Loop each metric/variable in the server status
	for rows.Next() {
		err := rows.Scan(&key, &value)

		// Handle row reading errors
		if err != nil {
			return err
		}

		// Process the metrics/variables
		if queryType == "metrics" {
			err = processMetric(previous, status, key, value)
		} else {
			err = processVariable(status, key, value)
		}

		if err != nil {
			return err
		}
	}

	// Do some final processing of the metrics
	err = postProcessMetrics(previous, status)

	if err != nil {
		return err
	}

	// Check for any remaining errors
	err = rows.Err()

	return err
}

// Process metric returned from the GLOBAL_STATUS table
func processMetric(previous *DatabaseStatus, status *DatabaseStatus, key string, value string) error {
	var (
		err                error
		currentConnections int
		connections        int
		diff               int
		abortedConnections int
		queries            int
		uptime             int
		readWriteValue     int
	)

	switch key {
	// Current connections
	case "THREADS_CONNECTED":
		currentConnections, err = strconv.Atoi(value)
		status.Metrics.CurrentConnections = currentConnections
	// Connections per second
	case "CONNECTIONS":
		connections, err = strconv.Atoi(value)

		// If we don't have a previous value for the total connections
		// then cps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.connections == 0 {
			status.Metrics.ConnectionsPerSecond = 0
			status.Metrics.connections = connections
		// Otherwise the value of cps is the diff between the current
		// and previous count of connections
		} else {
			diff = connections - previous.Metrics.connections

			// cps can never be below 0..
			if diff > 0 {
				status.Metrics.ConnectionsPerSecond = diff
			} else {
				status.Metrics.ConnectionsPerSecond = 0
			}

			status.Metrics.connections = connections
		}
	// Aborted connections per second
	case "ABORTED_CONNECTS":
		abortedConnections, err = strconv.Atoi(value)

		// If we don't have a previous value for the total aborted connections
		// then acps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.abortedConnections == 0 {
			status.Metrics.AbortedConnectionsPerSecond = 0
			status.Metrics.abortedConnections = abortedConnections
		// Otherwise the value of acps is the diff between the current
		// and previous count of connections
		} else {
			diff = abortedConnections - previous.Metrics.abortedConnections

			// acps can never be below 0..
			if diff > 0 {
				status.Metrics.AbortedConnectionsPerSecond = diff
			} else {
				status.Metrics.AbortedConnectionsPerSecond = 0
			}

			status.Metrics.abortedConnections = abortedConnections
		}
	// Queries per second
	case "QUERIES":
		queries, err = strconv.Atoi(value)

		// If we don't have a previous value for the total queries
		// then qps is technically 0 as we don't know it yet
		if previous == nil || previous.Metrics.queries == 0 {
			status.Metrics.QueriesPerSecond = 0
			status.Metrics.queries = queries
		// Otherwise the value of qps is the diff between the current
		// and previous count of queries
		} else {
			diff = queries - previous.Metrics.queries

			// qps can never be below 0..
			if diff > 0 {
				status.Metrics.QueriesPerSecond = diff
			} else {
				status.Metrics.QueriesPerSecond = 0
			}

			status.Metrics.queries = queries
		}
	// Read/Writes per second
	case "COM_SELECT", "COM_INSERT_SELECT", "COM_REPLACE_SELECT", "COM_DELETE", "COM_INSERT", "COM_UPDATE", "COM_REPLACE":
		readWriteValue, err = strconv.Atoi(value)

		// Reads
		if key == "COM_SELECT" || key == "COM_INSERT_SELECT" || key == "COM_REPLACE_SELECT" {
			status.Metrics.reads += readWriteValue

			// Reads/Writes
			if key == "COM_INSERT_SELECT" || key == "COM_REPLACE_SELECT" {
				status.Metrics.writes += readWriteValue
			}
		// Writes
		} else {
			status.Metrics.writes += readWriteValue
		}
	// Uptime
	case "UPTIME":
		uptime, err = strconv.Atoi(value)
		status.Metrics.Uptime = uptime
	}

	if err != nil {
		return err
	} else {
		return nil
	}
}

// Process variables returned from the GLOBAL_VARIABLES table
func processVariable(status *DatabaseStatus, key string, value string) error {
	var (
		err            error
		maxConnections int
	)

	// Max allowed connections
	if key == "MAX_CONNECTIONS" {
		maxConnections, err = strconv.Atoi(value)
		status.Variables.MaxConnections = maxConnections
	}

	if err != nil {
		return err
	}

	return nil
}

// Post processing of metrics
func postProcessMetrics(previous *DatabaseStatus, status *DatabaseStatus) error {
	var diff int

	// If we don't have a previous value for the total reads
	// then rps is technically 0 as we don't know it yet
	if previous != nil {
		// Calculate the RPS
		diff = status.Metrics.reads - previous.Metrics.reads

		// rps can never be below 0..
		if diff > 0 {
			status.Metrics.ReadsPerSecond = diff
		} else {
			status.Metrics.ReadsPerSecond = 0
		}

		// Calculate the WPS
		diff = status.Metrics.writes - previous.Metrics.writes

		// wps can never be below 0..
		if diff > 0 {
			status.Metrics.WritesPerSecond = diff
		} else {
			status.Metrics.WritesPerSecond = 0
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package database

import (
	"database/sql"
)

type Table struct {
	name         string
	schema       string
	columns      map[string]string
	nameReady    bool
	schemaReady  bool
	columnsReady bool
}

func (t *Table) SetName(name string) {
	if !t.nameReady {
		t.name = name
		t.nameReady = true
	}
}

func (t *Table) SetSchema(schema string) {
	if !t.schemaReady {
		t.schema = schema
		t.schemaReady = true
	}
}

func (t *Table) SetColumns(columns map[string]string) {
	if !t.columnsReady {
		t.columns = columns
		t.columnsReady = true
	}
}

func (t *Table) Name() string {
	return t.name
}

func (t *Table) Column(a string) string {
	return t.columns[a]
}

type DB struct {
	name string
	DB   *sql.DB
}

func New() *DB {
	return &DB{}
}

func (db *DB) SetName(name string) {
	db.name = name
}
<commit_msg>Added needed interfaces to database<commit_after>package database

import (
	"database/sql"
)

type Scanner interface {
	Scan(...interface{}) error
}

type Rower interface {
	Scanner
	Next() bool
	Columns() ([]string, error)
	Close() error
}

type Table struct {
	name         string
	schema       string
	columns      map[string]string
	nameReady    bool
	schemaReady  bool
	columnsReady bool
}

func (t *Table) SetName(name string) {
	if !t.nameReady {
		t.name = name
		t.nameReady = true
	}
}

func (t *Table) SetSchema(schema string) {
	if !t.schemaReady {
		t.schema = schema
		t.schemaReady = true
	}
}

func (t *Table) SetColumns(columns map[string]string) {
	if !t.columnsReady {
		t.columns = columns
		t.columnsReady = true
	}
}

func (t *Table) Name() string {
	return t.name
}

func (t *Table) Column(a string) string {
	return t.columns[a]
}

type DB struct {
	*sql.DB
	name string
}

func New() *DB {
	return &DB{}
}

func (db *DB) SetName(name string) {
	db.name = name
}
<|endoftext|>


<commit_before>// pcsclite binding
//
// http://pcsclite.alioth.debian.org/pcsclite.html
// http://pcsclite.alioth.debian.org/api/group__API.html
//
package scard

// #cgo pkg-config: libpcsclite
// #include <stdlib.h>
// #include <winscard.h>
import "C"

import (
	"bytes"
	"unsafe"
)

// Version returns the libpcsclite version string
func Version() string {
	return C.PCSCLITE_VERSION_NUMBER
}

type Context struct {
	ctx C.SCARDCONTEXT
}

type Card struct {
	handle         C.SCARDHANDLE
	activeProtocol Protocol
}

type Protocol uint32

const (
	PROTOCOL_UNDEFINED Protocol = C.SCARD_PROTOCOL_UNDEFINED
	PROTOCOL_T0        Protocol = C.SCARD_PROTOCOL_T0
	PROTOCOL_T1        Protocol = C.SCARD_PROTOCOL_T1
	PROTOCOL_RAW       Protocol = C.SCARD_PROTOCOL_RAW
	PROTOCOL_ANY       Protocol = C.SCARD_PROTOCOL_ANY
)

type ShareMode uint32

const (
	SHARE_EXCLUSIVE ShareMode = C.SCARD_SHARE_EXCLUSIVE
	SHARE_SHARED    ShareMode = C.SCARD_SHARE_SHARED
	SHARE_DIRECT    ShareMode = C.SCARD_SHARE_DIRECT
)

type Disposition uint32

const (
	LEAVE_CARD   Disposition = C.SCARD_LEAVE_CARD
	RESET_CARD   Disposition = C.SCARD_RESET_CARD
	UNPOWER_CARD Disposition = C.SCARD_UNPOWER_CARD
	EJECT_CARD   Disposition = C.SCARD_EJECT_CARD
)

type CardStatus struct {
	Reader         string
	State          uint32
	ActiveProtocol Protocol
	ATR            []byte
}

type ReaderState struct {
	Reader       string
	UserData     interface{}
	CurrentState StateFlag
	EventState   StateFlag
	// TODO: ATR
}

type StateFlag uint32

const (
	STATE_UNAWARE     StateFlag = C.SCARD_STATE_UNAWARE
	STATE_IGNORE      StateFlag = C.SCARD_STATE_IGNORE
	STATE_CHANGED     StateFlag = C.SCARD_STATE_CHANGED
	STATE_UNKNOWN     StateFlag = C.SCARD_STATE_UNKNOWN
	STATE_UNAVAULABLE StateFlag = C.SCARD_STATE_UNAVAILABLE
	STATE_EMPTY       StateFlag = C.SCARD_STATE_EMPTY
	STATE_PRESENT     StateFlag = C.SCARD_STATE_PRESENT
	STATE_ATRMATCH    StateFlag = C.SCARD_STATE_ATRMATCH
	STATE_EXCLUSIVE   StateFlag = C.SCARD_STATE_EXCLUSIVE
	STATE_INUSE       StateFlag = C.SCARD_STATE_INUSE
	STATE_MUTE        StateFlag = C.SCARD_STATE_MUTE
	STATE_UNPOWERED   StateFlag = C.SCARD_STATE_UNPOWERED
)

type Timeout uint32

const (
	INFINITE Timeout = C.INFINITE
)

// wraps SCardEstablishContext
func EstablishContext() (*Context, error) {
	var ctx Context

	r := C.SCardEstablishContext(C.SCARD_SCOPE_SYSTEM, nil, nil, &ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	return &ctx, nil
}

// wraps SCardIsValidContext
func (ctx *Context) IsValid() (bool, error) {
	r := C.SCardIsValidContext(ctx.ctx)
	switch r {
	case C.SCARD_S_SUCCESS:
		return true, nil
	case C.SCARD_E_INVALID_HANDLE:
		return false, nil
	default:
		return false, newError(r)
	}
	panic("unreachable")
}

// wraps SCardCancel
func (ctx *Context) Cancel() error {
	r := C.SCardCancel(ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardReleaseContext
func (ctx *Context) Release() error {
	r := C.SCardReleaseContext(ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardListReaders
func (ctx *Context) ListReaders() ([]string, error) {
	var needed C.DWORD

	r := C.SCardListReaders(ctx.ctx, nil, nil, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	data := make([]byte, needed)
	cdata := (*C.char)(unsafe.Pointer(&data[0]))

	r = C.SCardListReaders(ctx.ctx, nil, cdata, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	var readers []string
	for _, b := range bytes.Split(data, []byte{0}) {
		if len(b) > 0 {
			readers = append(readers, string(b))
		}
	}

	return readers, nil
}

// wraps SCardGetStatusChange
func (ctx *Context) GetStatusChange(readerStates []ReaderState, timeout Timeout) error {

	crs := make([]C.SCARD_READERSTATE, len(readerStates))

	for i := range readerStates {
		crs[i].szReader = C.CString(readerStates[i].Reader)
		defer C.free(unsafe.Pointer(crs[i].szReader))
		crs[i].dwCurrentState = C.DWORD(readerStates[i].CurrentState)
	}

	r := C.SCardGetStatusChange(ctx.ctx, C.DWORD(timeout),
		(C.LPSCARD_READERSTATE)(unsafe.Pointer(&crs[0])),
		C.DWORD(len(crs)))

	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}

	for i := range readerStates {
		readerStates[i].EventState = StateFlag(crs[i].dwEventState)
	}

	return nil
}

// wraps SCardConnect
func (ctx *Context) Connect(reader string, mode ShareMode, proto Protocol) (*Card, error) {
	var card Card
	var activeProtocol C.DWORD

	creader := C.CString(reader)
	defer C.free(unsafe.Pointer(creader))

	r := C.SCardConnect(ctx.ctx, creader, C.DWORD(mode), C.DWORD(proto), &card.handle, &activeProtocol)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	card.activeProtocol = Protocol(activeProtocol)
	return &card, nil
}

// wraps SCardDisconnect
func (card *Card) Disconnect(d Disposition) error {
	r := C.SCardDisconnect(card.handle, C.DWORD(d))
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardReconnect
func (card *Card) Reconnect(mode ShareMode, protocol Protocol, init Disposition) error {
	var activeProtocol C.DWORD

	r := C.SCardReconnect(card.handle, C.DWORD(mode), C.DWORD(protocol), C.DWORD(init), &activeProtocol)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}

	card.activeProtocol = Protocol(activeProtocol)

	return nil
}

// wraps SCardBeginTransaction
func (card *Card) BeginTransaction() error {
	r := C.SCardBeginTransaction(card.handle)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardEndTransaction
func (card *Card) EndTransaction(d Disposition) error {
	r := C.SCardEndTransaction(card.handle, C.DWORD(d))
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardStatus
func (card *Card) Status() (*CardStatus, error) {
	var reader [C.MAX_READERNAME + 1]byte
	var readerLen = C.DWORD(len(reader))
	var state, proto C.DWORD
	var atr [C.MAX_ATR_SIZE]byte
	var atrLen = C.DWORD(len(atr))

	r := C.SCardStatus(card.handle, (C.LPSTR)(unsafe.Pointer(&reader[0])), &readerLen, &state, &proto, (*C.BYTE)(&atr[0]), &atrLen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	status := &CardStatus{
		Reader:         string(reader[0:readerLen]),
		State:          uint32(state),
		ActiveProtocol: Protocol(proto),
		ATR:            atr[0:atrLen],
	}

	return status, nil
}

// wraps SCardTransmit
func (card *Card) Transmit(cmd []byte) ([]byte, error) {
	var sendpci *C.SCARD_IO_REQUEST
	var recvpci C.SCARD_IO_REQUEST

	switch card.activeProtocol {
	case PROTOCOL_T0:
		sendpci = &C.g_rgSCardT0Pci
	case PROTOCOL_T1:
		sendpci = &C.g_rgSCardT1Pci
	case PROTOCOL_RAW:
		sendpci = &C.g_rgSCardRawPci
	default:
		panic("unknown protocol")
	}

	var recv [C.MAX_BUFFER_SIZE_EXTENDED]byte
	var recvlen C.DWORD = C.DWORD(len(recv))

	r := C.SCardTransmit(card.handle, sendpci, (*C.BYTE)(&cmd[0]), C.DWORD(len(cmd)), &recvpci, (*C.BYTE)(&recv[0]), &recvlen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}

// wraps SCardControl
func (card *Card) Control(ctrl uint32, cmd []byte) ([]byte, error) {
	var recv [C.MAX_BUFFER_SIZE_EXTENDED]byte
	var recvlen C.DWORD

	r := C.SCardControl(card.handle, C.DWORD(ctrl),
		(C.LPCVOID)(unsafe.Pointer(&cmd[0])), C.DWORD(len(cmd)),
		(C.LPVOID)(unsafe.Pointer(&recv[0])), C.DWORD(len(recv)), &recvlen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}
// TODO: SCardListReaderGroups
// TODO: SCardFreeMemory
// TODO: SCardGetAttrib
// TODO: SCardSetAttrib
<commit_msg>add SCardListReaderGroups wrapper<commit_after>// pcsclite binding
//
// http://pcsclite.alioth.debian.org/pcsclite.html
// http://pcsclite.alioth.debian.org/api/group__API.html
//
package scard

// #cgo pkg-config: libpcsclite
// #include <stdlib.h>
// #include <winscard.h>
import "C"

import (
	"bytes"
	"unsafe"
)

// Version returns the libpcsclite version string
func Version() string {
	return C.PCSCLITE_VERSION_NUMBER
}

type Context struct {
	ctx C.SCARDCONTEXT
}

type Card struct {
	handle         C.SCARDHANDLE
	activeProtocol Protocol
}

type Protocol uint32

const (
	PROTOCOL_UNDEFINED Protocol = C.SCARD_PROTOCOL_UNDEFINED
	PROTOCOL_T0        Protocol = C.SCARD_PROTOCOL_T0
	PROTOCOL_T1        Protocol = C.SCARD_PROTOCOL_T1
	PROTOCOL_RAW       Protocol = C.SCARD_PROTOCOL_RAW
	PROTOCOL_ANY       Protocol = C.SCARD_PROTOCOL_ANY
)

type ShareMode uint32

const (
	SHARE_EXCLUSIVE ShareMode = C.SCARD_SHARE_EXCLUSIVE
	SHARE_SHARED    ShareMode = C.SCARD_SHARE_SHARED
	SHARE_DIRECT    ShareMode = C.SCARD_SHARE_DIRECT
)

type Disposition uint32

const (
	LEAVE_CARD   Disposition = C.SCARD_LEAVE_CARD
	RESET_CARD   Disposition = C.SCARD_RESET_CARD
	UNPOWER_CARD Disposition = C.SCARD_UNPOWER_CARD
	EJECT_CARD   Disposition = C.SCARD_EJECT_CARD
)

type CardStatus struct {
	Reader         string
	State          uint32
	ActiveProtocol Protocol
	ATR            []byte
}

type ReaderState struct {
	Reader       string
	UserData     interface{}
	CurrentState StateFlag
	EventState   StateFlag
	// TODO: ATR
}

type StateFlag uint32

const (
	STATE_UNAWARE     StateFlag = C.SCARD_STATE_UNAWARE
	STATE_IGNORE      StateFlag = C.SCARD_STATE_IGNORE
	STATE_CHANGED     StateFlag = C.SCARD_STATE_CHANGED
	STATE_UNKNOWN     StateFlag = C.SCARD_STATE_UNKNOWN
	STATE_UNAVAULABLE StateFlag = C.SCARD_STATE_UNAVAILABLE
	STATE_EMPTY       StateFlag = C.SCARD_STATE_EMPTY
	STATE_PRESENT     StateFlag = C.SCARD_STATE_PRESENT
	STATE_ATRMATCH    StateFlag = C.SCARD_STATE_ATRMATCH
	STATE_EXCLUSIVE   StateFlag = C.SCARD_STATE_EXCLUSIVE
	STATE_INUSE       StateFlag = C.SCARD_STATE_INUSE
	STATE_MUTE        StateFlag = C.SCARD_STATE_MUTE
	STATE_UNPOWERED   StateFlag = C.SCARD_STATE_UNPOWERED
)

type Timeout uint32

const (
	INFINITE Timeout = C.INFINITE
)

// wraps SCardEstablishContext
func EstablishContext() (*Context, error) {
	var ctx Context

	r := C.SCardEstablishContext(C.SCARD_SCOPE_SYSTEM, nil, nil, &ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	return &ctx, nil
}

// wraps SCardIsValidContext
func (ctx *Context) IsValid() (bool, error) {
	r := C.SCardIsValidContext(ctx.ctx)
	switch r {
	case C.SCARD_S_SUCCESS:
		return true, nil
	case C.SCARD_E_INVALID_HANDLE:
		return false, nil
	default:
		return false, newError(r)
	}
	panic("unreachable")
}

// wraps SCardCancel
func (ctx *Context) Cancel() error {
	r := C.SCardCancel(ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardReleaseContext
func (ctx *Context) Release() error {
	r := C.SCardReleaseContext(ctx.ctx)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardListReaders
func (ctx *Context) ListReaders() ([]string, error) {
	var needed C.DWORD

	r := C.SCardListReaders(ctx.ctx, nil, nil, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	data := make([]byte, needed)
	cdata := (*C.char)(unsafe.Pointer(&data[0]))

	r = C.SCardListReaders(ctx.ctx, nil, cdata, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	var readers []string
	for _, b := range bytes.Split(data, []byte{0}) {
		if len(b) > 0 {
			readers = append(readers, string(b))
		}
	}

	return readers, nil
}

// wraps SCardListReaderGroups
func (ctx *Context) ListReaderGroups() ([]string, error) {
	var needed C.DWORD

	r := C.SCardListReaderGroups(ctx.ctx, nil, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	data := make([]byte, needed)
	cdata := (*C.char)(unsafe.Pointer(&data[0]))

	r = C.SCardListReaderGroups(ctx.ctx, cdata, &needed)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	var groups []string
	for _, b := range bytes.Split(data, []byte{0}) {
		if len(b) > 0 {
			groups = append(groups, string(b))
		}
	}

	return groups, nil
}

// wraps SCardGetStatusChange
func (ctx *Context) GetStatusChange(readerStates []ReaderState, timeout Timeout) error {

	crs := make([]C.SCARD_READERSTATE, len(readerStates))

	for i := range readerStates {
		crs[i].szReader = C.CString(readerStates[i].Reader)
		defer C.free(unsafe.Pointer(crs[i].szReader))
		crs[i].dwCurrentState = C.DWORD(readerStates[i].CurrentState)
	}

	r := C.SCardGetStatusChange(ctx.ctx, C.DWORD(timeout),
		(C.LPSCARD_READERSTATE)(unsafe.Pointer(&crs[0])),
		C.DWORD(len(crs)))

	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}

	for i := range readerStates {
		readerStates[i].EventState = StateFlag(crs[i].dwEventState)
	}

	return nil
}

// wraps SCardConnect
func (ctx *Context) Connect(reader string, mode ShareMode, proto Protocol) (*Card, error) {
	var card Card
	var activeProtocol C.DWORD

	creader := C.CString(reader)
	defer C.free(unsafe.Pointer(creader))

	r := C.SCardConnect(ctx.ctx, creader, C.DWORD(mode), C.DWORD(proto), &card.handle, &activeProtocol)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	card.activeProtocol = Protocol(activeProtocol)
	return &card, nil
}

// wraps SCardDisconnect
func (card *Card) Disconnect(d Disposition) error {
	r := C.SCardDisconnect(card.handle, C.DWORD(d))
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardReconnect
func (card *Card) Reconnect(mode ShareMode, protocol Protocol, init Disposition) error {
	var activeProtocol C.DWORD

	r := C.SCardReconnect(card.handle, C.DWORD(mode), C.DWORD(protocol), C.DWORD(init), &activeProtocol)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}

	card.activeProtocol = Protocol(activeProtocol)

	return nil
}

// wraps SCardBeginTransaction
func (card *Card) BeginTransaction() error {
	r := C.SCardBeginTransaction(card.handle)
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardEndTransaction
func (card *Card) EndTransaction(d Disposition) error {
	r := C.SCardEndTransaction(card.handle, C.DWORD(d))
	if r != C.SCARD_S_SUCCESS {
		return newError(r)
	}
	return nil
}

// wraps SCardStatus
func (card *Card) Status() (*CardStatus, error) {
	var reader [C.MAX_READERNAME + 1]byte
	var readerLen = C.DWORD(len(reader))
	var state, proto C.DWORD
	var atr [C.MAX_ATR_SIZE]byte
	var atrLen = C.DWORD(len(atr))

	r := C.SCardStatus(card.handle, (C.LPSTR)(unsafe.Pointer(&reader[0])), &readerLen, &state, &proto, (*C.BYTE)(&atr[0]), &atrLen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	status := &CardStatus{
		Reader:         string(reader[0:readerLen]),
		State:          uint32(state),
		ActiveProtocol: Protocol(proto),
		ATR:            atr[0:atrLen],
	}

	return status, nil
}

// wraps SCardTransmit
func (card *Card) Transmit(cmd []byte) ([]byte, error) {
	var sendpci *C.SCARD_IO_REQUEST
	var recvpci C.SCARD_IO_REQUEST

	switch card.activeProtocol {
	case PROTOCOL_T0:
		sendpci = &C.g_rgSCardT0Pci
	case PROTOCOL_T1:
		sendpci = &C.g_rgSCardT1Pci
	case PROTOCOL_RAW:
		sendpci = &C.g_rgSCardRawPci
	default:
		panic("unknown protocol")
	}

	var recv [C.MAX_BUFFER_SIZE_EXTENDED]byte
	var recvlen C.DWORD = C.DWORD(len(recv))

	r := C.SCardTransmit(card.handle, sendpci, (*C.BYTE)(&cmd[0]), C.DWORD(len(cmd)), &recvpci, (*C.BYTE)(&recv[0]), &recvlen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}

// wraps SCardControl
func (card *Card) Control(ctrl uint32, cmd []byte) ([]byte, error) {
	var recv [C.MAX_BUFFER_SIZE_EXTENDED]byte
	var recvlen C.DWORD

	r := C.SCardControl(card.handle, C.DWORD(ctrl),
		(C.LPCVOID)(unsafe.Pointer(&cmd[0])), C.DWORD(len(cmd)),
		(C.LPVOID)(unsafe.Pointer(&recv[0])), C.DWORD(len(recv)), &recvlen)
	if r != C.SCARD_S_SUCCESS {
		return nil, newError(r)
	}

	rsp := make([]byte, recvlen)
	copy(rsp, recv[0:recvlen])

	return rsp, nil
}
// TODO: SCardFreeMemory
// TODO: SCardGetAttrib
// TODO: SCardSetAttrib
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/jinzhu/gorm"
)

// Registered players
type Player struct {
	gorm.Model

	// user defined name, ex. joe
	Name string

	// password hash
	PasswordHash string
}
<commit_msg>models/player: helpers for creating and checking for players<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/bboozzoo/q3stats/store"
	"github.com/jinzhu/gorm"
)

// Registered players
type Player struct {
	gorm.Model

	// user defined name, ex. joe
	Name string

	// password hash
	PasswordHash string
}

// create new player returning its ID
func NewPlayer(store store.DB, name string, passwordhash string) uint {
	player := Player{
		Name:         name,
		PasswordHash: passwordhash,
	}

	db := store.Conn()

	db.Create(&player)

	return player.ID
}

func HasPlayer(store store.DB, name string) bool {
	db := store.Conn()

	var player Player

	notfound := db.Where(&Player{Name: name}).
		First(&player).
		RecordNotFound()

	if notfound == true {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package dbus

import (
	"testing"
)

// TestActivation forks out a copy of activation.go example and reads back two
// strings from the pipes that are passed in.
func TestGetUnitProperties(t *testing.T) {
	conn, err := New()
	if err != nil {
		t.Fatal(err)
	}
	//defer conn.Close()

	unit := "-.mount"

	info, err := conn.GetUnitProperties(unit)
	if err != nil {
		t.Fatal(err)
	}

	names := info["Wants"].([]string)

	if len(names) < 1 {
		t.Fatal("/ is unwanted")
	}

	if names[0] != "system.slice" {
		t.Fatal("unexpected wants for /")
	}
}
<commit_msg>feat(dbus): add test for starting and stopping units<commit_after>package dbus

import (
	"os"
	"path/filepath"
	"testing"
)

func setupConn(t *testing.T) *Conn {
	conn, err := New()
	if err != nil {
		t.Fatal(err)
	}

	return conn
}

// Ensure that basic unit starting and stopping works.
func TestStartStopUnit(t *testing.T) {
	target := "/run/systemd/system/start-stop.service"
	conn := setupConn(t)

	// Blindly remove the symlink in case it exists
	err := os.Remove(target)

	// 1. Enable the unit
	abs, err := filepath.Abs("../fixtures/start-stop.service")
	if err != nil {
		t.Fatal(err)
	}

	fixture := []string{abs}

	install, changes, err := conn.EnableUnitFiles(fixture, true, true)

	if install != false {
		t.Fatal("Install was true")
	}

	if len(changes) < 1 {
		t.Fatal("Expected one change, got %v", changes)
	}

	if changes[0].Filename != target {
		t.Fatal("Unexpected target filename")
	}

	// 2. Start the unit
	job, err := conn.StartUnit(filepath.Base(target), "replace")
	if err != nil {
		t.Fatal(err)
	}

	if job != "done" {
		t.Fatal("Job is not done, %v", job)
	}

	units, err := conn.ListUnits()

	var unit *UnitStatus
	for _, u := range units {
		if u.Name == filepath.Base(target) {
			unit = &u
		}
	}

	if unit == nil {
		t.Fatalf("Test unit not found in list")
	}

	if unit.ActiveState != "active" {
		t.Fatalf("Test unit not active")
	}

	// 3. Stop the unit
	job, err = conn.StopUnit(filepath.Base(target), "replace")
	if err != nil {
		t.Fatal(err)
	}

	units, err = conn.ListUnits()

	unit = nil
	for _, u := range units {
		if u.Name == filepath.Base(target) {
			unit = &u
		}
	}

	if unit != nil {
		t.Fatalf("Test unit found in list, should be stopped")
	}
}

// TestGetUnitProperties reads the `-.mount` which should exist on all systemd
// systems and ensures that one of its properties is valid.
func TestGetUnitProperties(t *testing.T) {
	conn := setupConn(t)

	unit := "-.mount"

	info, err := conn.GetUnitProperties(unit)
	if err != nil {
		t.Fatal(err)
	}

	names := info["Wants"].([]string)

	if len(names) < 1 {
		t.Fatal("/ is unwanted")
	}

	if names[0] != "system.slice" {
		t.Fatal("unexpected wants for /")
	}

}
<|endoftext|>