<commit_before>// Package websocketproxy is a reverse proxy for WebSocket connections.
package websocketproxy

import (
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/gorilla/websocket"
)

var (
	// DefaultUpgrader specifies the parameters for upgrading an HTTP
	// connection to a WebSocket connection.
	DefaultUpgrader = &websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	// DefaultDialer is a dialer with all fields set to the default zero values.
	DefaultDialer = websocket.DefaultDialer
)

// WebsocketProxy is an HTTP Handler that takes an incoming WebSocket
// connection and proxies it to another server.
type WebsocketProxy struct {
	// Backend returns the backend URL which the proxy uses to reverse proxy
	// the incoming WebSocket connection. Request is the initial incoming and
	// unmodified request.
	Backend func(*http.Request) *url.URL

	// Upgrader specifies the parameters for upgrading a incoming HTTP
	// connection to a WebSocket connection. If nil, DefaultUpgrader is used.
	Upgrader *websocket.Upgrader

	//  Dialer contains options for connecting to the backend WebSocket server.
	//  If nil, DefaultDialer is used.
	Dialer *websocket.Dialer
}

// ProxyHandler returns a new http.Handler interface that reverse proxies the
// request to the given target.
func ProxyHandler(target *url.URL) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		NewProxy(target).ServeHTTP(rw, req)
	})
}

// NewProxy returns a new Websocket reverse proxy that rewrites the
// URL's to the scheme, host and base path provider in target.
func NewProxy(target *url.URL) *WebsocketProxy {
	backend := func(r *http.Request) *url.URL { return target }
	return &WebsocketProxy{Backend: backend}
}

// ServeHTTP implements the http.Handler that proxies WebSocket connections.
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if w.Backend == nil {
		log.Println("websocketproxy: backend function is not defined")
		http.Error(rw, "internal server error (code: 1)", http.StatusInternalServerError)
		return
	}

	backendURL := w.Backend(req)
	if backendURL == nil {
		log.Println("websocketproxy: backend URL is nil")
		http.Error(rw, "internal server error (code: 2)", http.StatusInternalServerError)
		return
	}

	dialer := w.Dialer
	if w.Dialer == nil {
		dialer = DefaultDialer
	}

	// Pass headers from the incoming request to the dialer to forward them to
	// the final destinations.
	requestHeader := http.Header{}
	requestHeader.Add("Origin", req.Header.Get("Origin"))
	for _, prot := range req.Header[http.CanonicalHeaderKey("Sec-WebSocket-Protocol")] {
		requestHeader.Add("Sec-WebSocket-Protocol", prot)
	}
	for _, cookie := range req.Header[http.CanonicalHeaderKey("Cookie")] {
		requestHeader.Add("Cookie", cookie)
	}

	// Pass X-Forwarded-For headers too, code below is a part of
	// httputil.ReverseProxy. See http://en.wikipedia.org/wiki/X-Forwarded-For
	// for more information
	// TODO: use RFC7239 http://tools.ietf.org/html/rfc7239
	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
		// If we aren't the first proxy retain prior
		// X-Forwarded-For information as a comma+space
		// separated list and fold multiple headers into one.
		if prior, ok := req.Header["X-Forwarded-For"]; ok {
			clientIP = strings.Join(prior, ", ") + ", " + clientIP
		}
		requestHeader.Set("X-Forwarded-For", clientIP)
	}

	// Set the originating protocol of the incoming HTTP request. The SSL might
	// be terminated on our site and because we doing proxy adding this would
	// be helpful for applications on the backend.
	requestHeader.Set("X-Forwarded-Proto", "http")
	if req.TLS != nil {
		requestHeader.Set("X-Forwarded-Proto", "https")
	}

	// Connect to the backend URL, also pass the headers we get from the requst
	// together with the Forwarded headers we prepared above.
	// TODO: support multiplexing on the same backend connection instead of
	// opening a new TCP connection time for each request. This should be
	// optional:
	// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-01
	connBackend, resp, err := dialer.Dial(backendURL.String(), requestHeader)
	if err != nil {
		log.Printf("websocketproxy: couldn't dial to remote backend url %s\n", err)
		return
	}
	defer connBackend.Close()

	upgrader := w.Upgrader
	if w.Upgrader == nil {
		upgrader = DefaultUpgrader
	}

	// Only pass those headers to the upgrader.
	upgradeHeader := http.Header{}
	upgradeHeader.Set("Sec-WebSocket-Protocol",
		resp.Header.Get(http.CanonicalHeaderKey("Sec-WebSocket-Protocol")))
	upgradeHeader.Set("Set-Cookie",
		resp.Header.Get(http.CanonicalHeaderKey("Set-Cookie")))

	// Now upgrade the existing incoming request to a WebSocket connection.
	// Also pass the header that we gathered from the Dial handshake.
	connPub, err := upgrader.Upgrade(rw, req, upgradeHeader)
	if err != nil {
		log.Printf("websocketproxy: couldn't upgrade %s\n", err)
		return
	}
	defer connPub.Close()

	errc := make(chan error, 2)
	cp := func(dst io.Writer, src io.Reader) {
		_, err := io.Copy(dst, src)
		errc <- err
	}

	// Start our proxy now, everything is ready...
	go cp(connBackend.UnderlyingConn(), connPub.UnderlyingConn())
	go cp(connPub.UnderlyingConn(), connBackend.UnderlyingConn())
	<-errc
}
<commit_msg>Added support to proxy paths.<commit_after>// Package websocketproxy is a reverse proxy for WebSocket connections.
package websocketproxy

import (
	"io"
	"log"
	"net"
	"net/http"
	"net/url"
	"strings"

	"github.com/gorilla/websocket"
)

var (
	// DefaultUpgrader specifies the parameters for upgrading an HTTP
	// connection to a WebSocket connection.
	DefaultUpgrader = &websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
	}

	// DefaultDialer is a dialer with all fields set to the default zero values.
	DefaultDialer = websocket.DefaultDialer
)

// WebsocketProxy is an HTTP Handler that takes an incoming WebSocket
// connection and proxies it to another server.
type WebsocketProxy struct {
	// Backend returns the backend URL which the proxy uses to reverse proxy
	// the incoming WebSocket connection. Request is the initial incoming and
	// unmodified request.
	Backend func(*http.Request) *url.URL

	// Upgrader specifies the parameters for upgrading a incoming HTTP
	// connection to a WebSocket connection. If nil, DefaultUpgrader is used.
	Upgrader *websocket.Upgrader

	//  Dialer contains options for connecting to the backend WebSocket server.
	//  If nil, DefaultDialer is used.
	Dialer *websocket.Dialer
}

// ProxyHandler returns a new http.Handler interface that reverse proxies the
// request to the given target.
func ProxyHandler(target *url.URL) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		NewProxy(target).ServeHTTP(rw, req)
	})
}

// NewProxy returns a new Websocket reverse proxy that rewrites the
// URL's to the scheme, host and base path provider in target.
func NewProxy(target *url.URL) *WebsocketProxy {
	backend := func(r *http.Request) *url.URL {
		// Shallow copy
		u := *target
		u.Fragment = r.URL.Fragment
		u.Path = r.URL.Path
		u.RawQuery = r.URL.RawQuery
		return &u
	}
	return &WebsocketProxy{Backend: backend}
}

// ServeHTTP implements the http.Handler that proxies WebSocket connections.
func (w *WebsocketProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	if w.Backend == nil {
		log.Println("websocketproxy: backend function is not defined")
		http.Error(rw, "internal server error (code: 1)", http.StatusInternalServerError)
		return
	}

	backendURL := w.Backend(req)
	if backendURL == nil {
		log.Println("websocketproxy: backend URL is nil")
		http.Error(rw, "internal server error (code: 2)", http.StatusInternalServerError)
		return
	}

	dialer := w.Dialer
	if w.Dialer == nil {
		dialer = DefaultDialer
	}

	// Pass headers from the incoming request to the dialer to forward them to
	// the final destinations.
	requestHeader := http.Header{}
	requestHeader.Add("Origin", req.Header.Get("Origin"))
	for _, prot := range req.Header[http.CanonicalHeaderKey("Sec-WebSocket-Protocol")] {
		requestHeader.Add("Sec-WebSocket-Protocol", prot)
	}
	for _, cookie := range req.Header[http.CanonicalHeaderKey("Cookie")] {
		requestHeader.Add("Cookie", cookie)
	}

	// Pass X-Forwarded-For headers too, code below is a part of
	// httputil.ReverseProxy. See http://en.wikipedia.org/wiki/X-Forwarded-For
	// for more information
	// TODO: use RFC7239 http://tools.ietf.org/html/rfc7239
	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
		// If we aren't the first proxy retain prior
		// X-Forwarded-For information as a comma+space
		// separated list and fold multiple headers into one.
		if prior, ok := req.Header["X-Forwarded-For"]; ok {
			clientIP = strings.Join(prior, ", ") + ", " + clientIP
		}
		requestHeader.Set("X-Forwarded-For", clientIP)
	}

	// Set the originating protocol of the incoming HTTP request. The SSL might
	// be terminated on our site and because we doing proxy adding this would
	// be helpful for applications on the backend.
	requestHeader.Set("X-Forwarded-Proto", "http")
	if req.TLS != nil {
		requestHeader.Set("X-Forwarded-Proto", "https")
	}

	// Connect to the backend URL, also pass the headers we get from the requst
	// together with the Forwarded headers we prepared above.
	// TODO: support multiplexing on the same backend connection instead of
	// opening a new TCP connection time for each request. This should be
	// optional:
	// http://tools.ietf.org/html/draft-ietf-hybi-websocket-multiplexing-01
	connBackend, resp, err := dialer.Dial(backendURL.String(), requestHeader)
	if err != nil {
		log.Printf("websocketproxy: couldn't dial to remote backend url %s\n", err)
		return
	}
	defer connBackend.Close()

	upgrader := w.Upgrader
	if w.Upgrader == nil {
		upgrader = DefaultUpgrader
	}

	// Only pass those headers to the upgrader.
	upgradeHeader := http.Header{}
	upgradeHeader.Set("Sec-WebSocket-Protocol",
		resp.Header.Get(http.CanonicalHeaderKey("Sec-WebSocket-Protocol")))
	upgradeHeader.Set("Set-Cookie",
		resp.Header.Get(http.CanonicalHeaderKey("Set-Cookie")))

	// Now upgrade the existing incoming request to a WebSocket connection.
	// Also pass the header that we gathered from the Dial handshake.
	connPub, err := upgrader.Upgrade(rw, req, upgradeHeader)
	if err != nil {
		log.Printf("websocketproxy: couldn't upgrade %s\n", err)
		return
	}
	defer connPub.Close()

	errc := make(chan error, 2)
	cp := func(dst io.Writer, src io.Reader) {
		_, err := io.Copy(dst, src)
		errc <- err
	}

	// Start our proxy now, everything is ready...
	go cp(connBackend.UnderlyingConn(), connPub.UnderlyingConn())
	go cp(connPub.UnderlyingConn(), connBackend.UnderlyingConn())
	<-errc
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os/exec"
	"time"

	"github.com/elliots/go-wireless/iwlib"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/paypal/gatt"
)

type WifiNetwork struct {
	SSID string `json:"name"`
}

type WifiCredentials struct {
	SSID string `json:"ssid"`
	Key  string `json:"key"`
}

const WLANInterfaceTemplate = "iface wlan0 inet dhcp\n"

func GetSetupRPCRouter(wifi_manager *WifiManager, srv *gatt.Server, pairing_ui *ConsolePairingUI) *JSONRPCRouter {

	rpc_router := &JSONRPCRouter{}
	rpc_router.Init()
	rpc_router.AddHandler("sphere.setup.ping", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pong := JSONRPCResponse{"2.0", request.Id, 1234, nil}
		resp <- pong

		return resp
	})

	rpc_router.AddHandler("sphere.setup.get_visible_wifi_networks", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pairing_ui.DisplayIcon("wifi-searching.gif")

		// Before we search for wifi networks, disable any that are try-fail-ing
		wifi_manager.DisableAllNetworks()

		networks, err := iwlib.GetWirelessNetworks("wlan0")
		if err == nil {
			wifi_networks := make([]WifiNetwork, len(networks))
			for i, network := range networks {
				wifi_networks[i].SSID = network.SSID
			}

			resp <- JSONRPCResponse{"2.0", request.Id, wifi_networks, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, "Could not retrieve WiFi networks", nil}}
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.connect_wifi_network", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pairing_ui.DisplayIcon("wifi-connecting.gif")

		wifi_creds := new(WifiCredentials)
		b, _ := json.Marshal(request.Params[0])
		json.Unmarshal(b, wifi_creds)

		logger.Debugf("Got wifi credentials %v", wifi_creds)

		go func() {
			WriteToFile("/etc/network/interfaces.d/wlan0", WLANInterfaceTemplate)

			states := wifi_manager.WatchState()

			wifi_manager.AddStandardNetwork(wifi_creds.SSID, wifi_creds.Key)
			wifi_manager.Controller.ReloadConfiguration()

			success := true
			for {
				state := <-states
				if state == WifiStateConnected {
					pairing_ui.DisplayIcon("wifi-connected.gif")
					success = true
					break
				} else if state == WifiStateInvalidKey {
					pairing_ui.DisplayIcon("wifi-failed.gif")
					success = false
					break
				}
			}

			wifi_manager.UnwatchState(states)

			if success {
				serial_number, err := exec.Command("/opt/ninjablocks/bin/sphere-serial").Output()
				if err != nil {
					// ow ow ow
				}

				pong := JSONRPCResponse{"2.0", request.Id, string(serial_number), nil}
				resp <- pong
			} else {
				resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, "Could not connect to specified WiFi network, is the key correct?", nil}}
			}
		}()

		return resp
	})

	conn, err := ninja.Connect("sphere-setup-assistant-updates")

	if err != nil {
		logger.FatalErrorf(err, "Failed to connect to mqtt")
	}

	updateService := conn.GetServiceClient("$node/" + config.Serial() + "/updates")
	ledService := conn.GetServiceClient("$node/" + config.Serial() + "/led-controller")

	rpc_router.AddHandler("sphere.setup.start_update", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		err := updateService.Call("start", nil, &response, time.Second*10)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	var lastProgress map[string]interface{}

	updateService.OnEvent("progress", func(progress *map[string]interface{}, topicKeys map[string]string) bool {
		lastProgress = *progress

		logger.Infof("Got update progress: %v", progress)
		return true
	})

	rpc_router.AddHandler("sphere.setup.get_update_progress", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		logger.Infof("Requesting update progress id:%s", request.Id)

		resp <- JSONRPCResponse{"2.0", request.Id, lastProgress, nil}

		logger.Infof("Sent progress %v", lastProgress)

		running, ok := lastProgress["running"]

		// If we have sent back a progress that shows the update is finished... shut down the ble after 5 seconds.
		if ok && running.(bool) == false { /*running:*/
			logger.Infof("Update is finished!")
			go func() {
				time.Sleep(time.Second * 5)
				srv.Close()
			}()
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.display_drawing", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		err := ledService.Call("displayDrawing", request.Params, &response, time.Second*10)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.draw", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		err := ledService.Call("draw", request.Params, &response, time.Second*10)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	return rpc_router
}
<commit_msg>Add some logging to the start_update roc<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os/exec"
	"time"

	"github.com/elliots/go-wireless/iwlib"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/paypal/gatt"
)

type WifiNetwork struct {
	SSID string `json:"name"`
}

type WifiCredentials struct {
	SSID string `json:"ssid"`
	Key  string `json:"key"`
}

const WLANInterfaceTemplate = "iface wlan0 inet dhcp\n"

func GetSetupRPCRouter(wifi_manager *WifiManager, srv *gatt.Server, pairing_ui *ConsolePairingUI) *JSONRPCRouter {

	rpc_router := &JSONRPCRouter{}
	rpc_router.Init()
	rpc_router.AddHandler("sphere.setup.ping", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pong := JSONRPCResponse{"2.0", request.Id, 1234, nil}
		resp <- pong

		return resp
	})

	rpc_router.AddHandler("sphere.setup.get_visible_wifi_networks", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pairing_ui.DisplayIcon("wifi-searching.gif")

		// Before we search for wifi networks, disable any that are try-fail-ing
		wifi_manager.DisableAllNetworks()

		networks, err := iwlib.GetWirelessNetworks("wlan0")
		if err == nil {
			wifi_networks := make([]WifiNetwork, len(networks))
			for i, network := range networks {
				wifi_networks[i].SSID = network.SSID
			}

			resp <- JSONRPCResponse{"2.0", request.Id, wifi_networks, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, "Could not retrieve WiFi networks", nil}}
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.connect_wifi_network", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pairing_ui.DisplayIcon("wifi-connecting.gif")

		wifi_creds := new(WifiCredentials)
		b, _ := json.Marshal(request.Params[0])
		json.Unmarshal(b, wifi_creds)

		logger.Debugf("Got wifi credentials %v", wifi_creds)

		go func() {
			WriteToFile("/etc/network/interfaces.d/wlan0", WLANInterfaceTemplate)

			states := wifi_manager.WatchState()

			wifi_manager.AddStandardNetwork(wifi_creds.SSID, wifi_creds.Key)
			wifi_manager.Controller.ReloadConfiguration()

			success := true
			for {
				state := <-states
				if state == WifiStateConnected {
					pairing_ui.DisplayIcon("wifi-connected.gif")
					success = true
					break
				} else if state == WifiStateInvalidKey {
					pairing_ui.DisplayIcon("wifi-failed.gif")
					success = false
					break
				}
			}

			wifi_manager.UnwatchState(states)

			if success {
				serial_number, err := exec.Command("/opt/ninjablocks/bin/sphere-serial").Output()
				if err != nil {
					// ow ow ow
				}

				pong := JSONRPCResponse{"2.0", request.Id, string(serial_number), nil}
				resp <- pong
			} else {
				resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, "Could not connect to specified WiFi network, is the key correct?", nil}}
			}
		}()

		return resp
	})

	conn, err := ninja.Connect("sphere-setup-assistant-updates")

	if err != nil {
		logger.FatalErrorf(err, "Failed to connect to mqtt")
	}

	updateService := conn.GetServiceClient("$node/" + config.Serial() + "/updates")
	ledService := conn.GetServiceClient("$node/" + config.Serial() + "/led-controller")

	rpc_router.AddHandler("sphere.setup.start_update", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		logger.Infof("Starting update id: %d. Waiting for response....", request.Id)

		err := updateService.Call("start", nil, &response, time.Second*10)

		logger.Infof("Got update start response: %d. %v", request.Id, response)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	var lastProgress map[string]interface{}

	updateService.OnEvent("progress", func(progress *map[string]interface{}, topicKeys map[string]string) bool {
		lastProgress = *progress

		logger.Infof("Got update progress: %v", *progress)
		return true
	})

	rpc_router.AddHandler("sphere.setup.get_update_progress", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		logger.Infof("Requesting update progress id:%s", request.Id)

		resp <- JSONRPCResponse{"2.0", request.Id, lastProgress, nil}

		logger.Infof("Sent progress %v", lastProgress)

		running, ok := lastProgress["running"]

		// If we have sent back a progress that shows the update is finished... shut down the ble after 5 seconds.
		if ok && running.(bool) == false { /*running:*/
			logger.Infof("Update is finished!")
			go func() {
				time.Sleep(time.Second * 5)
				srv.Close()
			}()
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.display_drawing", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		err := ledService.Call("displayDrawing", request.Params, &response, time.Second*10)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	rpc_router.AddHandler("sphere.setup.draw", func(request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		var response json.RawMessage

		err := ledService.Call("draw", request.Params, &response, time.Second*10)

		if err == nil {
			resp <- JSONRPCResponse{"2.0", request.Id, &response, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, fmt.Sprintf("%s", err), nil}}
		}

		return resp
	})

	return rpc_router
}
<|endoftext|>


<commit_before>package render

import (
	"fmt"
	"reflect"
	"sort"
	"strconv"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
)

const (
	mb                 = 1 << 20
	connectionsRank    = 100
	containerImageRank = 4
	containerRank      = 3
	processRank        = 2
	hostRank           = 1
	endpointRank       = 0 // this is the least important table, so sort to bottom
	addressRank        = 0 // also least important; never merged with endpoints
)

// DetailedNode is the data type that's yielded to the JavaScript layer when
// we want deep information about an individual node.
type DetailedNode struct {
	ID         string  `json:"id"`
	LabelMajor string  `json:"label_major"`
	LabelMinor string  `json:"label_minor,omitempty"`
	Pseudo     bool    `json:"pseudo,omitempty"`
	Tables     []Table `json:"tables"`
}

// Table is a dataset associated with a node. It will be displayed in the
// detail panel when a user clicks on a node.
type Table struct {
	Title   string `json:"title"`   // e.g. Bandwidth
	Numeric bool   `json:"numeric"` // should the major column be right-aligned?
	Rank    int    `json:"-"`       // used to sort tables; not emitted.
	Rows    []Row  `json:"rows"`
}

// Row is a single entry in a Table dataset.
type Row struct {
	Key        string `json:"key"`                   // e.g. Ingress
	ValueMajor string `json:"value_major"`           // e.g. 25
	ValueMinor string `json:"value_minor,omitempty"` // e.g. KB/s
}

type tables []Table

func (t tables) Len() int           { return len(t) }
func (t tables) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t tables) Less(i, j int) bool { return t[i].Rank > t[j].Rank }

// MakeDetailedNode transforms a renderable node to a detailed node. It uses
// aggregate metadata, plus the set of origin node IDs, to produce tables.
func MakeDetailedNode(r report.Report, n RenderableNode) DetailedNode {
	tables := tables{}
	{
		rows := []Row{}
		if val, ok := n.AggregateMetadata[KeyMaxConnCountTCP]; ok {
			rows = append(rows, Row{"TCP connections", strconv.FormatInt(int64(val), 10), ""})
		}
		if val, ok := n.AggregateMetadata[KeyBytesIngress]; ok {
			rows = append(rows, Row{"Bytes ingress", strconv.FormatInt(int64(val), 10), ""})
		}
		if val, ok := n.AggregateMetadata[KeyBytesEgress]; ok {
			rows = append(rows, Row{"Bytes egress", strconv.FormatInt(int64(val), 10), ""})
		}
		if len(rows) > 0 {
			tables = append(tables, Table{"Connections", true, connectionsRank, rows})
		}
	}

	// RenderableNode may be the result of merge operation(s), and so may have
	// multiple origins. The ultimate goal here is to generate tables to view
	// in the UI, so we skip the intermediate representations, but we could
	// add them later.
	connections := []Row{}
outer:
	for _, id := range n.Origins {
		if table, ok := OriginTable(r, id); ok {
			// TODO there's a bug that yields duplicate tables. Quick fix.
			for _, existing := range tables {
				if reflect.DeepEqual(existing, table) {
					continue outer
				}
			}
			tables = append(tables, table)
		} else if nmd, ok := r.Endpoint.NodeMetadatas[id]; ok {
			connections = append(connections, connectionDetailsRows(r.Endpoint, id, nmd)...)
		}
	}
	if len(connections) > 0 {
		tables = append(tables, connectionDetailsTable(connections))
	}

	// Sort tables by rank
	sort.Sort(tables)

	return DetailedNode{
		ID:         n.ID,
		LabelMajor: n.LabelMajor,
		LabelMinor: n.LabelMinor,
		Pseudo:     n.Pseudo,
		Tables:     tables,
	}
}

// OriginTable produces a table (to be consumed directly by the UI) based on
// an origin ID, which is (optimistically) a node ID in one of our topologies.
func OriginTable(r report.Report, originID string) (Table, bool) {
	if nmd, ok := r.Address.NodeMetadatas[originID]; ok {
		return addressOriginTable(nmd)
	}
	if nmd, ok := r.Process.NodeMetadatas[originID]; ok {
		return processOriginTable(nmd)
	}
	if nmd, ok := r.Container.NodeMetadatas[originID]; ok {
		return containerOriginTable(nmd)
	}
	if nmd, ok := r.ContainerImage.NodeMetadatas[originID]; ok {
		return containerImageOriginTable(nmd)
	}
	if nmd, ok := r.Host.NodeMetadatas[originID]; ok {
		return hostOriginTable(nmd)
	}
	return Table{}, false
}

func connectionDetailsRows(endpointTopology report.Topology, originID string, nmd report.NodeMetadata) []Row {
	rows := []Row{}
	local := fmt.Sprintf("%s:%s", nmd["addr"], nmd["port"])
	adjacencies := endpointTopology.Adjacency[report.MakeAdjacencyID(originID)]
	sort.Strings(adjacencies)
	for _, adj := range adjacencies {
		if _, address, port, ok := report.ParseEndpointNodeID(adj); ok {
			rows = append(rows, Row{
				Key:        local,
				ValueMajor: fmt.Sprintf("%s:%s", address, port),
			})
		}
	}
	return rows
}

func connectionDetailsTable(connectionRows []Row) Table {
	return Table{
		Title:   "Connection Details",
		Numeric: false,
		Rows:    append([]Row{{Key: "Local", ValueMajor: "Remote"}}, connectionRows...),
		Rank:    endpointRank,
	}
}

func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	if val, ok := nmd["addr"]; ok {
		rows = append(rows, Row{"Address", val, ""})
	}
	return Table{
		Title:   "Origin Address",
		Numeric: false,
		Rows:    rows,
		Rank:    addressRank,
	}, len(rows) > 0
}

func processOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{process.Comm, "Name (comm)"},
		{process.PID, "PID"},
		{process.PPID, "Parent PID"},
		{process.Cmdline, "Command"},
		{process.Threads, "# Threads"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Process",
		Numeric: false,
		Rows:    rows,
		Rank:    processRank,
	}, len(rows) > 0
}

func containerOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{docker.ContainerID, "ID"},
		{docker.ContainerName, "Name"},
		{docker.ImageID, "Image ID"},
		{docker.ContainerPorts, "Ports"},
		{docker.ContainerCreated, "Created"},
		{docker.ContainerCommand, "Command"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	if val, ok := nmd[docker.MemoryUsage]; ok {
		memory, err := strconv.ParseFloat(val, 64)
		if err == nil {
			memoryStr := fmt.Sprintf("%0.2f", memory/float64(mb))
			rows = append(rows, Row{Key: "Memory Usage (MB):", ValueMajor: memoryStr, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Container",
		Numeric: false,
		Rows:    rows,
		Rank:    containerRank,
	}, len(rows) > 0
}

func containerImageOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{docker.ImageID, "Image ID"},
		{docker.ImageName, "Image name"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}
	return Table{
		Title:   "Origin Container Image",
		Numeric: false,
		Rows:    rows,
		Rank:    containerImageRank,
	}, len(rows) > 0
}

func hostOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{host.HostName, "Host name"},
		{host.Load, "Load"},
		{host.OS, "Operating system"},
		{host.KernelVersion, "Kernel version"},
		{host.Uptime, "Uptime"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Host",
		Numeric: false,
		Rows:    rows,
		Rank:    hostRank,
	}, len(rows) > 0
}
<commit_msg>removing duplication checking, which is no longer needed due to connection aggregation<commit_after>package render

import (
	"fmt"
	"sort"
	"strconv"

	"github.com/weaveworks/scope/probe/docker"
	"github.com/weaveworks/scope/probe/host"
	"github.com/weaveworks/scope/probe/process"
	"github.com/weaveworks/scope/report"
)

const (
	mb                 = 1 << 20
	connectionsRank    = 100
	containerImageRank = 4
	containerRank      = 3
	processRank        = 2
	hostRank           = 1
	endpointRank       = 0 // this is the least important table, so sort to bottom
	addressRank        = 0 // also least important; never merged with endpoints
)

// DetailedNode is the data type that's yielded to the JavaScript layer when
// we want deep information about an individual node.
type DetailedNode struct {
	ID         string  `json:"id"`
	LabelMajor string  `json:"label_major"`
	LabelMinor string  `json:"label_minor,omitempty"`
	Pseudo     bool    `json:"pseudo,omitempty"`
	Tables     []Table `json:"tables"`
}

// Table is a dataset associated with a node. It will be displayed in the
// detail panel when a user clicks on a node.
type Table struct {
	Title   string `json:"title"`   // e.g. Bandwidth
	Numeric bool   `json:"numeric"` // should the major column be right-aligned?
	Rank    int    `json:"-"`       // used to sort tables; not emitted.
	Rows    []Row  `json:"rows"`
}

// Row is a single entry in a Table dataset.
type Row struct {
	Key        string `json:"key"`                   // e.g. Ingress
	ValueMajor string `json:"value_major"`           // e.g. 25
	ValueMinor string `json:"value_minor,omitempty"` // e.g. KB/s
}

type tables []Table

func (t tables) Len() int           { return len(t) }
func (t tables) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
func (t tables) Less(i, j int) bool { return t[i].Rank > t[j].Rank }

// MakeDetailedNode transforms a renderable node to a detailed node. It uses
// aggregate metadata, plus the set of origin node IDs, to produce tables.
func MakeDetailedNode(r report.Report, n RenderableNode) DetailedNode {
	tables := tables{}
	{
		rows := []Row{}
		if val, ok := n.AggregateMetadata[KeyMaxConnCountTCP]; ok {
			rows = append(rows, Row{"TCP connections", strconv.FormatInt(int64(val), 10), ""})
		}
		if val, ok := n.AggregateMetadata[KeyBytesIngress]; ok {
			rows = append(rows, Row{"Bytes ingress", strconv.FormatInt(int64(val), 10), ""})
		}
		if val, ok := n.AggregateMetadata[KeyBytesEgress]; ok {
			rows = append(rows, Row{"Bytes egress", strconv.FormatInt(int64(val), 10), ""})
		}
		if len(rows) > 0 {
			tables = append(tables, Table{"Connections", true, connectionsRank, rows})
		}
	}

	// RenderableNode may be the result of merge operation(s), and so may have
	// multiple origins. The ultimate goal here is to generate tables to view
	// in the UI, so we skip the intermediate representations, but we could
	// add them later.
	connections := []Row{}
	for _, id := range n.Origins {
		if table, ok := OriginTable(r, id); ok {
			tables = append(tables, table)
		} else if nmd, ok := r.Endpoint.NodeMetadatas[id]; ok {
			connections = append(connections, connectionDetailsRows(r.Endpoint, id, nmd)...)
		}
	}
	if len(connections) > 0 {
		tables = append(tables, connectionDetailsTable(connections))
	}

	// Sort tables by rank
	sort.Sort(tables)

	return DetailedNode{
		ID:         n.ID,
		LabelMajor: n.LabelMajor,
		LabelMinor: n.LabelMinor,
		Pseudo:     n.Pseudo,
		Tables:     tables,
	}
}

// OriginTable produces a table (to be consumed directly by the UI) based on
// an origin ID, which is (optimistically) a node ID in one of our topologies.
func OriginTable(r report.Report, originID string) (Table, bool) {
	if nmd, ok := r.Address.NodeMetadatas[originID]; ok {
		return addressOriginTable(nmd)
	}
	if nmd, ok := r.Process.NodeMetadatas[originID]; ok {
		return processOriginTable(nmd)
	}
	if nmd, ok := r.Container.NodeMetadatas[originID]; ok {
		return containerOriginTable(nmd)
	}
	if nmd, ok := r.ContainerImage.NodeMetadatas[originID]; ok {
		return containerImageOriginTable(nmd)
	}
	if nmd, ok := r.Host.NodeMetadatas[originID]; ok {
		return hostOriginTable(nmd)
	}
	return Table{}, false
}

func connectionDetailsRows(endpointTopology report.Topology, originID string, nmd report.NodeMetadata) []Row {
	rows := []Row{}
	local := fmt.Sprintf("%s:%s", nmd["addr"], nmd["port"])
	adjacencies := endpointTopology.Adjacency[report.MakeAdjacencyID(originID)]
	sort.Strings(adjacencies)
	for _, adj := range adjacencies {
		if _, address, port, ok := report.ParseEndpointNodeID(adj); ok {
			rows = append(rows, Row{
				Key:        local,
				ValueMajor: fmt.Sprintf("%s:%s", address, port),
			})
		}
	}
	return rows
}

func connectionDetailsTable(connectionRows []Row) Table {
	return Table{
		Title:   "Connection Details",
		Numeric: false,
		Rows:    append([]Row{{Key: "Local", ValueMajor: "Remote"}}, connectionRows...),
		Rank:    endpointRank,
	}
}

func addressOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	if val, ok := nmd["addr"]; ok {
		rows = append(rows, Row{"Address", val, ""})
	}
	return Table{
		Title:   "Origin Address",
		Numeric: false,
		Rows:    rows,
		Rank:    addressRank,
	}, len(rows) > 0
}

func processOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{process.Comm, "Name (comm)"},
		{process.PID, "PID"},
		{process.PPID, "Parent PID"},
		{process.Cmdline, "Command"},
		{process.Threads, "# Threads"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Process",
		Numeric: false,
		Rows:    rows,
		Rank:    processRank,
	}, len(rows) > 0
}

func containerOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{docker.ContainerID, "ID"},
		{docker.ContainerName, "Name"},
		{docker.ImageID, "Image ID"},
		{docker.ContainerPorts, "Ports"},
		{docker.ContainerCreated, "Created"},
		{docker.ContainerCommand, "Command"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	if val, ok := nmd[docker.MemoryUsage]; ok {
		memory, err := strconv.ParseFloat(val, 64)
		if err == nil {
			memoryStr := fmt.Sprintf("%0.2f", memory/float64(mb))
			rows = append(rows, Row{Key: "Memory Usage (MB):", ValueMajor: memoryStr, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Container",
		Numeric: false,
		Rows:    rows,
		Rank:    containerRank,
	}, len(rows) > 0
}

func containerImageOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{docker.ImageID, "Image ID"},
		{docker.ImageName, "Image name"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}
	return Table{
		Title:   "Origin Container Image",
		Numeric: false,
		Rows:    rows,
		Rank:    containerImageRank,
	}, len(rows) > 0
}

func hostOriginTable(nmd report.NodeMetadata) (Table, bool) {
	rows := []Row{}
	for _, tuple := range []struct{ key, human string }{
		{host.HostName, "Host name"},
		{host.Load, "Load"},
		{host.OS, "Operating system"},
		{host.KernelVersion, "Kernel version"},
		{host.Uptime, "Uptime"},
	} {
		if val, ok := nmd[tuple.key]; ok {
			rows = append(rows, Row{Key: tuple.human, ValueMajor: val, ValueMinor: ""})
		}
	}

	return Table{
		Title:   "Origin Host",
		Numeric: false,
		Rows:    rows,
		Rank:    hostRank,
	}, len(rows) > 0
}
<|endoftext|>


<commit_before>package desugar

import "github.com/tisp-lang/tisp/src/lib/ast"

type names map[string]bool

func newNames(ss ...string) names {
	ns := make(names, len(ss))

	for _, s := range ss {
		ns.add(s)
	}

	return ns
}

func (ns names) slice() []string {
	ms := make([]string, 0, len(ns))

	for k := range ns {
		ms = append(ms, k)
	}

	return ms
}

func (ns names) copy() names {
	ms := newNames()

	for k, v := range ns {
		ms[k] = v
	}

	return ms
}

func (ns names) merge(ms names) {
	for k, v := range ms {
		ns[k] = v
	}
}

func (ns names) add(n string) {
	ns[n] = true
}

func (ns names) subtract(ms names) {
	for k := range ms {
		delete(ns, k)
	}
}

func (ns names) include(n string) bool {
	_, ok := ns[n]
	return ok
}

func (ns names) find(x interface{}) names {
	switch x := x.(type) {
	case []interface{}:
		ms := newNames()

		for _, s := range x {
			ms.merge(ns.find(s))
		}

		return ms
	case ast.LetVar:
		ns := ns.copy()
		delete(ns, x.Name())
		return ns.find(x.Expr())
	case ast.LetFunction:
		ns := ns.copy()

		delete(ns, x.Name())
		for _, n := range signatureToNames(x.Signature()).slice() {
			delete(ns, n)
		}

		ms := ns.find(x.Lets())
		ms.merge(ns.find(x.Body()))
		return ms
	case ast.App:
		return newNames(append(ns.find(x.Function()).slice(), ns.find(x.Arguments()).slice()...)...)
	case ast.Arguments:
		ms := newNames()

		for _, p := range x.Positionals() {
			ms.merge(ns.find(p.Value()))
		}

		for _, k := range x.Keywords() {
			ms.merge(ns.find(k.Value()))
		}

		for _, d := range x.ExpandedDicts() {
			ms.merge(ns.find(d))
		}

		return ms
	case ast.Switch:
		ms := ns.find(x.Value())

		for _, c := range x.Cases() {
			ms.merge(ns.find(c.Value()))
		}

		ms.merge(ns.find(x.DefaultCase()))

		return ms
	case string:
		if ns.include(x) {
			return newNames(x)
		}

		return newNames()
	}

	panic("Unreachable")
}
<commit_msg>Refactor names.go<commit_after>package desugar

import "github.com/tisp-lang/tisp/src/lib/ast"

type names map[string]bool

func newNames(ss ...string) names {
	ns := make(names, len(ss))

	for _, s := range ss {
		ns.add(s)
	}

	return ns
}

func (ns names) slice() []string {
	ms := make([]string, 0, len(ns))

	for n := range ns {
		ms = append(ms, n)
	}

	return ms
}

func (ns names) add(n string) {
	ns[n] = true
}

func (ns names) copy() names {
	ms := newNames()

	for n := range ns {
		ms.add(n)
	}

	return ms
}

func (ns names) merge(ms names) {
	for m := range ms {
		ns.add(m)
	}
}

func (ns names) delete(n string) {
	delete(ns, n)
}

func (ns names) subtract(ms names) {
	for m := range ms {
		ns.delete(m)
	}
}

func (ns names) include(n string) bool {
	_, ok := ns[n]
	return ok
}

func (ns names) find(x interface{}) names {
	switch x := x.(type) {
	case []interface{}:
		ms := newNames()

		for _, s := range x {
			ms.merge(ns.find(s))
		}

		return ms
	case ast.LetVar:
		ns := ns.copy()
		ns.delete(x.Name())
		return ns.find(x.Expr())
	case ast.LetFunction:
		ns := ns.copy()

		ns.delete(x.Name())
		for n := range signatureToNames(x.Signature()) {
			ns.delete(n)
		}

		ms := ns.find(x.Lets())
		ms.merge(ns.find(x.Body()))
		return ms
	case ast.App:
		ms := ns.find(x.Function())
		ms.merge(ns.find(x.Arguments()))
		return ms
	case ast.Arguments:
		ms := newNames()

		for _, p := range x.Positionals() {
			ms.merge(ns.find(p.Value()))
		}

		for _, k := range x.Keywords() {
			ms.merge(ns.find(k.Value()))
		}

		for _, d := range x.ExpandedDicts() {
			ms.merge(ns.find(d))
		}

		return ms
	case ast.Switch:
		ms := ns.find(x.Value())

		for _, c := range x.Cases() {
			ms.merge(ns.find(c.Value()))
		}

		ms.merge(ns.find(x.DefaultCase()))

		return ms
	case string:
		if ns.include(x) {
			return newNames(x)
		}

		return newNames()
	}

	panic("Unreachable")
}
<|endoftext|>


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

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"once";
	"os"
)

const (
	MaxFileSize = 8192;	// actual files are closer to 1K
	HeaderSize = 4+16+4*7
)

export var (
	BadZoneinfo = os.NewError("time: malformed zoneinfo");
	NoZoneinfo = os.NewError("time: unknown time zone")
)

// Simple I/O interface to binary blob of data.
type Data struct {
	p *[]byte
}

func (d *Data) Read(n int) *[]byte {
	if d.p == nil || len(d.p) < n {
		d.p = nil;
		return nil
	}
	p := d.p[0:n];
	d.p = d.p[n:len(d.p)];
	return p
}

func (d *Data) Big4() (n uint32, ok bool) {
	p := d.Read(4);
	if p == nil {
		return 0, false
	}
	return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
}

func (d *Data) Byte() (n byte, ok bool) {
	p := d.Read(1);
	if p == nil {
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func ByteString(p *[]byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type Zone struct {
	utcoff int;
	isdst bool;
	name string
}

type Zonetime struct {
	time int32;		// transition time, in seconds since 1970 GMT
	zone *Zone;		// the zone that goes into effect at that time
	isstd, isutc bool;	// ignored - no idea what these mean
}

func ParseZoneinfo(bytes *[]byte) (zt *[]Zonetime, err *os.Error) {
	data1 := Data(bytes);
	data := &data1;

	// 4-byte magic "TZif"
	if magic := data.Read(4); magic == nil || string(magic) != "TZif" {
		return nil, BadZoneinfo
	}

	// 1-byte version, then 15 bytes of padding
	var p *[]byte;
	if p = data.Read(16); p == nil || p[0] != 0 && p[0] != '2' {
		return nil, BadZoneinfo
	}
	vers := p[0];

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota;
		NStdWall;
		NLeap;
		NTime;
		NZone;
		NChar
	)
	var n [6]int;
	for i := 0; i < 6; i++ {
		nn, ok := data.Big4();
		if !ok {
			return nil, BadZoneinfo
		}
		n[i] = int(nn);
	}

	// Transition times.
	txtimes1 := Data(data.Read(n[NTime]*4));
	txtimes := &txtimes1;

	// Time zone indices for transition times.
	txzones := data.Read(n[NTime]);

	// Zone info structures
	zonedata1 := Data(data.Read(n[NZone]*6));
	zonedata := &zonedata1;

	// Time zone abbreviations.
	abbrev := data.Read(n[NChar]);

	// Leap-second time pairs
	leapdata1 := Data(data.Read(n[NLeap]*8));
	leapdata := &leapdata1;

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := data.Read(n[NStdWall]);

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := data.Read(n[NUTCLocal]);

	if data.p == nil {	// ran out of data
		return nil, BadZoneinfo
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	zone := new([]Zone, n[NZone]);
	for i := 0; i < len(zone); i++ {
		var ok bool;
		var n uint32;
		if n, ok = zonedata.Big4(); !ok {
			return nil, BadZoneinfo
		}
		zone[i].utcoff = int(n);
		var b byte;
		if b, ok = zonedata.Byte(); !ok {
			return nil, BadZoneinfo
		}
		zone[i].isdst = b != 0;
		if b, ok = zonedata.Byte(); !ok || int(b) >= len(abbrev) {
			return nil, BadZoneinfo
		}
		zone[i].name = ByteString(abbrev[b:len(abbrev)])
	}

	// Now the transition time info.
	zt = new([]Zonetime, n[NTime]);
	for i := 0; i < len(zt); i++ {
		var ok bool;
		var n uint32;
		if n, ok = txtimes.Big4(); !ok {
			return nil, BadZoneinfo
		}
		zt[i].time = int32(n);
		if int(txzones[i]) >= len(zone) {
			return nil, BadZoneinfo
		}
		zt[i].zone = &zone[txzones[i]];
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, nil
}

func ReadFile(name string, max int) (p *[]byte, err *os.Error) {
	fd, e := os.Open(name, os.O_RDONLY, 0);
	if e != nil {
		return nil, e
	}
	p = new([]byte, max+1)[0:0];
	n := 0;
	for len(p) < max {
		nn, e := fd.Read(p[n:cap(p)]);
		if e != nil {
			fd.Close();
			return nil, e
		}
		if nn == 0 {
			fd.Close();
			return p, nil
		}
		p = p[0:n+nn]
	}
	fd.Close();
	return nil, BadZoneinfo	// too long
}

func ReadZoneinfoFile(name string) (tx *[]Zonetime, err *os.Error) {
	data, e := ReadFile(name, MaxFileSize);
	if e != nil {
		return nil, e
	}
	tx, err = ParseZoneinfo(data);
	return tx, err
}

var zones *[]Zonetime
var zoneerr *os.Error

func SetupZone() {
	// TODO: /etc/localtime is the default time zone info
	// for the system, but libc allows setting an environment
	// variable in order to direct reading a different file
	// (in /usr/share/zoneinfo).  We should check that
	// environment variable.
	zones, zoneerr = ReadZoneinfoFile("/etc/localtime");
}

export func LookupTimezone(sec int64) (zone string, offset int, err *os.Error) {
	once.Do(&SetupZone);
	if zoneerr != nil || zones == nil || len(zones) == 0 {
		return "GMT", 0, zoneerr
	}

	// Binary search for entry with largest time <= sec
	tz := zones;
	for len(tz) > 1 {
		m := len(tz)/2;
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:len(tz)]
		}
	}
	z := tz[0].zone;
	return z.name, z.utcoff, nil
}
<commit_msg>new convert code found error<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
// and ftp://munnari.oz.au/pub/oldtz/

package time

import (
	"once";
	"os"
)

const (
	MaxFileSize = 8192;	// actual files are closer to 1K
	HeaderSize = 4+16+4*7
)

export var (
	BadZoneinfo = os.NewError("time: malformed zoneinfo");
	NoZoneinfo = os.NewError("time: unknown time zone")
)

// Simple I/O interface to binary blob of data.
type Data struct {
	p *[]byte
}

func (d *Data) Read(n int) *[]byte {
	if d.p == nil || len(d.p) < n {
		d.p = nil;
		return nil
	}
	p := d.p[0:n];
	d.p = d.p[n:len(d.p)];
	return p
}

func (d *Data) Big4() (n uint32, ok bool) {
	p := d.Read(4);
	if p == nil {
		return 0, false
	}
	return uint32(p[0]) << 24 | uint32(p[1]) << 16 | uint32(p[2]) << 8 | uint32(p[3]), true
}

func (d *Data) Byte() (n byte, ok bool) {
	p := d.Read(1);
	if p == nil {
		return 0, false
	}
	return p[0], true
}

// Make a string by stopping at the first NUL
func ByteString(p *[]byte) string {
	for i := 0; i < len(p); i++ {
		if p[i] == 0 {
			return string(p[0:i])
		}
	}
	return string(p)
}

// Parsed representation
type Zone struct {
	utcoff int;
	isdst bool;
	name string
}

type Zonetime struct {
	time int32;		// transition time, in seconds since 1970 GMT
	zone *Zone;		// the zone that goes into effect at that time
	isstd, isutc bool;	// ignored - no idea what these mean
}

func ParseZoneinfo(bytes *[]byte) (zt *[]Zonetime, err *os.Error) {
	data1 := Data{bytes};
	data := &data1;

	// 4-byte magic "TZif"
	if magic := data.Read(4); magic == nil || string(magic) != "TZif" {
		return nil, BadZoneinfo
	}

	// 1-byte version, then 15 bytes of padding
	var p *[]byte;
	if p = data.Read(16); p == nil || p[0] != 0 && p[0] != '2' {
		return nil, BadZoneinfo
	}
	vers := p[0];

	// six big-endian 32-bit integers:
	//	number of UTC/local indicators
	//	number of standard/wall indicators
	//	number of leap seconds
	//	number of transition times
	//	number of local time zones
	//	number of characters of time zone abbrev strings
	const (
		NUTCLocal = iota;
		NStdWall;
		NLeap;
		NTime;
		NZone;
		NChar
	)
	var n [6]int;
	for i := 0; i < 6; i++ {
		nn, ok := data.Big4();
		if !ok {
			return nil, BadZoneinfo
		}
		n[i] = int(nn);
	}

	// Transition times.
	txtimes1 := Data{data.Read(n[NTime]*4)};
	txtimes := &txtimes1;

	// Time zone indices for transition times.
	txzones := data.Read(n[NTime]);

	// Zone info structures
	zonedata1 := Data{data.Read(n[NZone]*6)};
	zonedata := &zonedata1;

	// Time zone abbreviations.
	abbrev := data.Read(n[NChar]);

	// Leap-second time pairs
	leapdata1 := Data{data.Read(n[NLeap]*8)};
	leapdata := &leapdata1;

	// Whether tx times associated with local time types
	// are specified as standard time or wall time.
	isstd := data.Read(n[NStdWall]);

	// Whether tx times associated with local time types
	// are specified as UTC or local time.
	isutc := data.Read(n[NUTCLocal]);

	if data.p == nil {	// ran out of data
		return nil, BadZoneinfo
	}

	// If version == 2, the entire file repeats, this time using
	// 8-byte ints for txtimes and leap seconds.
	// We won't need those until 2106.

	// Now we can build up a useful data structure.
	// First the zone information.
	//	utcoff[4] isdst[1] nameindex[1]
	zone := new([]Zone, n[NZone]);
	for i := 0; i < len(zone); i++ {
		var ok bool;
		var n uint32;
		if n, ok = zonedata.Big4(); !ok {
			return nil, BadZoneinfo
		}
		zone[i].utcoff = int(n);
		var b byte;
		if b, ok = zonedata.Byte(); !ok {
			return nil, BadZoneinfo
		}
		zone[i].isdst = b != 0;
		if b, ok = zonedata.Byte(); !ok || int(b) >= len(abbrev) {
			return nil, BadZoneinfo
		}
		zone[i].name = ByteString(abbrev[b:len(abbrev)])
	}

	// Now the transition time info.
	zt = new([]Zonetime, n[NTime]);
	for i := 0; i < len(zt); i++ {
		var ok bool;
		var n uint32;
		if n, ok = txtimes.Big4(); !ok {
			return nil, BadZoneinfo
		}
		zt[i].time = int32(n);
		if int(txzones[i]) >= len(zone) {
			return nil, BadZoneinfo
		}
		zt[i].zone = &zone[txzones[i]];
		if i < len(isstd) {
			zt[i].isstd = isstd[i] != 0
		}
		if i < len(isutc) {
			zt[i].isutc = isutc[i] != 0
		}
	}
	return zt, nil
}

func ReadFile(name string, max int) (p *[]byte, err *os.Error) {
	fd, e := os.Open(name, os.O_RDONLY, 0);
	if e != nil {
		return nil, e
	}
	p = new([]byte, max+1)[0:0];
	n := 0;
	for len(p) < max {
		nn, e := fd.Read(p[n:cap(p)]);
		if e != nil {
			fd.Close();
			return nil, e
		}
		if nn == 0 {
			fd.Close();
			return p, nil
		}
		p = p[0:n+nn]
	}
	fd.Close();
	return nil, BadZoneinfo	// too long
}

func ReadZoneinfoFile(name string) (tx *[]Zonetime, err *os.Error) {
	data, e := ReadFile(name, MaxFileSize);
	if e != nil {
		return nil, e
	}
	tx, err = ParseZoneinfo(data);
	return tx, err
}

var zones *[]Zonetime
var zoneerr *os.Error

func SetupZone() {
	// TODO: /etc/localtime is the default time zone info
	// for the system, but libc allows setting an environment
	// variable in order to direct reading a different file
	// (in /usr/share/zoneinfo).  We should check that
	// environment variable.
	zones, zoneerr = ReadZoneinfoFile("/etc/localtime");
}

export func LookupTimezone(sec int64) (zone string, offset int, err *os.Error) {
	once.Do(&SetupZone);
	if zoneerr != nil || zones == nil || len(zones) == 0 {
		return "GMT", 0, zoneerr
	}

	// Binary search for entry with largest time <= sec
	tz := zones;
	for len(tz) > 1 {
		m := len(tz)/2;
		if sec < int64(tz[m].time) {
			tz = tz[0:m]
		} else {
			tz = tz[m:len(tz)]
		}
	}
	z := tz[0].zone;
	return z.name, z.utcoff, nil
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"strings"

	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/jriddick/geoffrey/irc"
	"github.com/jriddick/geoffrey/msg"
)

// MessageHandler is the function type for
// message handlers
type MessageHandler func(*Bot, *Channel, User, string)

// Bot is the structure for an IRC bot
type Bot struct {
	client          *irc.IRC
	writer          chan<- string
	reader          <-chan *msg.Message
	stop            chan struct{}
	config          Config
	messageHandlers []MessageHandler
	channels        map[string]*Channel
}

// Config is the configuration structure for Bot
type Config struct {
	Hostname           string
	Port               int
	Secure             bool
	InsecureSkipVerify bool
	Nick               string
	User               string
	Name               string
	Channels           []string
	Timeout            int
	TimeoutLimit       int
	ReconnectLimit     int
}

// NewBot creates a new bot
func NewBot(config Config) *Bot {
	// Create the bot
	bot := &Bot{
		client: irc.NewIRC(irc.Config{
			Hostname:           config.Hostname,
			Port:               config.Port,
			Secure:             config.Secure,
			InsecureSkipVerify: config.InsecureSkipVerify,
			Timeout:            time.Second * time.Duration(config.Timeout),
			TimeoutLimit:       config.TimeoutLimit,
		}),
		config:   config,
		channels: make(map[string]*Channel),
		stop:     make(chan struct{}),
	}

	return bot
}

// Connect will connect the bot to the server
func (b *Bot) Connect() error {
	// Connect the client
	if err := b.client.Connect(); err != nil {
		return err
	}

	// Get the reader and writer channels
	b.writer = b.client.Writer()
	b.reader = b.client.Reader()

	return nil
}

// Handler will start processing messages
func (b *Bot) Handler() {
	for {
		select {
		case <-b.stop:
			// Send quit message
			b.writer <- "QUIT :Closed"

			// Disconnect the client
			b.client.Disconnect()
			break
		case msg := <-b.reader:
			// Log all messages
			log.Debugln(msg.String())

			// Send nick and user after connecting
			if msg.Trailing == "*** Looking up your hostname..." {
				b.writer <- fmt.Sprintf("NICK %s", b.config.Nick)
				b.writer <- fmt.Sprintf("USER %s 0 * :%s", b.config.User, b.config.Name)
				continue
			}

			// Answer PING with PONG
			if msg.Command == "PING" {
				b.writer <- fmt.Sprintf("PONG :%s", msg.Trailing)
				continue
			}

			// Join channels when ready
			if msg.Command == irc.RPL_WELCOME {
				for _, channel := range b.config.Channels {
					b.Join(channel)
				}
				continue
			}

			// Handle JOINs
			if msg.Command == "JOIN" {
				// Add the channel if we just joined it
				if msg.Prefix.Name == b.config.Nick {
					// Add the channel
					b.AddChannel(msg.Trailing)
				} else {
					// Add the user
					b.channels[msg.Trailing].AddUser(msg.Prefix.Name)
				}
			}

			// Check if this is a name reply
			if msg.Command == irc.RPL_NAMREPLY {
				for _, nick := range strings.Split(msg.Trailing, " ") {
					if nick != b.config.Nick {
						b.channels[msg.Params[2]].AddUser(nick)
					}
				}
			}

			// Handle PARTs
			if msg.Command == "PART" {
				// Remove the user
				b.channels[msg.Params[0]].RemoveUser(msg.Prefix.Name)
			}

			// Let our handlers handle PRIVMSG
			if msg.Command == "PRIVMSG" {
				// Get the channel
				channel := b.channels[msg.Params[0]]

				// Get the sender
				sender := channel.Users[msg.Prefix.Name]

				// Run the handlers
				go func() {
					for _, handler := range b.messageHandlers {
						go handler(b, channel, sender, msg.Trailing)
					}
				}()
				continue
			}
		}
	}
}

// Send will send the given message to the given receiver
func (b *Bot) Send(recv, msg string) {
	b.writer <- fmt.Sprintf("PRIVMSG %s :%s", recv, msg)
}

// Join will join the given channel
func (b *Bot) Join(channel string) {
	// Make sure we have a hashtag
	if !strings.HasPrefix(channel, "#") {
		channel = "#" + channel
	}

	// Send the join command
	b.writer <- fmt.Sprintf("JOIN %s", channel)
}

// AddChannel will add channel to list of joined channels
func (b *Bot) AddChannel(channel string) {
	// Make sure we do not replace any existing channels
	if _, ok := b.channels[channel]; ok {
		return
	}

	// Add the channel to the list
	b.channels[channel] = &Channel{
		Name: channel,
		bot:  b,
	}
}

// OnMessage registeres a new PRIVMSG handler
func (b *Bot) OnMessage(handler MessageHandler) {
	b.messageHandlers = append(b.messageHandlers, handler)
}

// Close will close the bot
func (b *Bot) Close() {
	close(b.stop)
}
<commit_msg>added support for running lua functions as handlers<commit_after>package bot

import (
	"fmt"
	"strings"

	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/jriddick/geoffrey/irc"
	"github.com/jriddick/geoffrey/msg"
	"github.com/yuin/gopher-lua"
)

// MessageHandler is the function type for
// message handlers
type MessageHandler func(*Bot, string)

// Bot is the structure for an IRC bot
type Bot struct {
	client             *irc.IRC
	writer             chan<- string
	reader             <-chan *msg.Message
	stop               chan struct{}
	config             Config
	messageHandlers    []MessageHandler
	messageHandlersLua []*lua.LFunction
	channels           map[string]*Channel
	state              *lua.LState
}

// Config is the configuration structure for Bot
type Config struct {
	Hostname           string
	Port               int
	Secure             bool
	InsecureSkipVerify bool
	Nick               string
	User               string
	Name               string
	Channels           []string
	Timeout            int
	TimeoutLimit       int
	ReconnectLimit     int
}

// NewBot creates a new bot
func NewBot(config Config, state *lua.LState) *Bot {
	// Create the bot
	bot := &Bot{
		client: irc.NewIRC(irc.Config{
			Hostname:           config.Hostname,
			Port:               config.Port,
			Secure:             config.Secure,
			InsecureSkipVerify: config.InsecureSkipVerify,
			Timeout:            time.Second * time.Duration(config.Timeout),
			TimeoutLimit:       config.TimeoutLimit,
		}),
		config:   config,
		channels: make(map[string]*Channel),
		stop:     make(chan struct{}),
		state:    state,
	}

	// Register the bot struct
	RegisterBot(state)

	return bot
}

// Connect will connect the bot to the server
func (b *Bot) Connect() error {
	// Connect the client
	if err := b.client.Connect(); err != nil {
		return err
	}

	// Get the reader and writer channels
	b.writer = b.client.Writer()
	b.reader = b.client.Reader()

	return nil
}

// Handler will start processing messages
func (b *Bot) Handler() {
	for {
		select {
		case <-b.stop:
			// Send quit message
			b.writer <- "QUIT :Closed"

			// Disconnect the client
			b.client.Disconnect()
			break
		case msg := <-b.reader:
			// Log all messages
			log.Debugln(msg.String())

			// Send nick and user after connecting
			if msg.Trailing == "*** Looking up your hostname..." {
				b.writer <- fmt.Sprintf("NICK %s", b.config.Nick)
				b.writer <- fmt.Sprintf("USER %s 0 * :%s", b.config.User, b.config.Name)
				continue
			}

			// Answer PING with PONG
			if msg.Command == "PING" {
				b.writer <- fmt.Sprintf("PONG :%s", msg.Trailing)
				continue
			}

			// Join channels when ready
			if msg.Command == irc.RPL_WELCOME {
				for _, channel := range b.config.Channels {
					b.Join(channel)
				}
				continue
			}

			// Let our handlers handle PRIVMSG
			if msg.Command == "PRIVMSG" {
				// Run the handlers
				go func() {
					for _, handler := range b.messageHandlers {
						go handler(b, msg.Trailing)
					}
				}()

				// Run the lua handlers
				go func(state *lua.LState, bot *Bot) {
					for _, handler := range b.messageHandlersLua {
						// Push the handler function
						state.Push(handler)

						// Create the metatable for our bot
						value := state.NewUserData()
						value.Value = bot
						state.SetMetatable(value, state.GetTypeMetatable("bot"))

						// Push the bot
						state.Push(value)

						// Push the message
						state.Push(lua.LString(msg.Trailing))

						// Call the function
						state.Call(2, 0)

						// Close the thread
						state.Close()
					}
				}(b.state.NewThread(), b)

				continue
			}
		}
	}
}

// Send will send the given message to the given receiver
func (b *Bot) Send(recv, msg string) {
	b.writer <- fmt.Sprintf("PRIVMSG %s :%s", recv, msg)
}

// Join will join the given channel
func (b *Bot) Join(channel string) {
	// Make sure we have a hashtag
	if !strings.HasPrefix(channel, "#") {
		channel = "#" + channel
	}

	// Send the join command
	b.writer <- fmt.Sprintf("JOIN %s", channel)
}

// AddChannel will add channel to list of joined channels
func (b *Bot) AddChannel(channel string) {
	// Make sure we do not replace any existing channels
	if _, ok := b.channels[channel]; ok {
		return
	}

	// Add the channel to the list
	b.channels[channel] = &Channel{
		Name: channel,
		bot:  b,
	}
}

// OnMessage registeres a new PRIVMSG handler
func (b *Bot) OnMessage(handler MessageHandler) {
	b.messageHandlers = append(b.messageHandlers, handler)
}

func (b *Bot) OnMessageLua(handler *lua.LFunction) {
	b.messageHandlersLua = append(b.messageHandlersLua, handler)
}

// Close will close the bot
func (b *Bot) Close() {
	close(b.stop)
}
<|endoftext|>


<commit_before>package dht

import (
	"net"
	"testing"

	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/util"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func testMarshalUnmarshalMsg(t *testing.T, m Msg, expected string) {
	b, err := bencode.Marshal(m)
	require.NoError(t, err)
	assert.Equal(t, expected, string(b))
	var _m Msg
	err = bencode.Unmarshal([]byte(expected), &_m)
	assert.NoError(t, err)
	assert.EqualValues(t, m, _m)
	assert.EqualValues(t, m.A, _m.A)
	assert.EqualValues(t, m.R, _m.R)
}

func TestMarshalUnmarshalMsg(t *testing.T) {
	testMarshalUnmarshalMsg(t, Msg{}, "d1:t0:1:y0:e")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "q",
		Q: "ping",
		T: "hi",
	}, "d1:q4:ping1:t2:hi1:y1:qe")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "e",
		T: "42",
		E: &KRPCError{Code: 200, Msg: "fuck"},
	}, "d1:eli200e4:fucke1:t2:421:y1:ee")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{},
	}, "d1:rd2:id0:e1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{
			Nodes: CompactIPv4NodeInfo{
				NodeInfo{
					Addr: newDHTAddr(&net.UDPAddr{
						IP:   net.IPv4(1, 2, 3, 4).To4(),
						Port: 0x1234,
					}),
				},
			},
		},
	}, "d1:rd2:id0:5:nodes26:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x124e1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{
			Values: []util.CompactPeer{
				util.CompactPeer{
					IP:   net.IPv4(1, 2, 3, 4).To4(),
					Port: 0x5678,
				},
			},
		},
	}, "d1:rd2:id0:6:valuesl6:\x01\x02\x03\x04\x56\x78ee1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x03",
		R: &Return{
			ID: "\xeb\xff6isQ\xffJ\xec)ͺ\xab\xf2\xfb\xe3F|\xc2g",
		},
		IP: util.CompactPeer{net.IPv4(124, 168, 180, 8).To4(), 62844},
	}, "d2:ip6:|\xa8\xb4\b\xf5|1:rd2:id20:\xeb\xff6isQ\xffJ\xec)ͺ\xab\xf2\xfb\xe3F|\xc2ge1:t1:\x031:y1:re")
}

func TestUnmarshalGetPeersResponse(t *testing.T) {
	var msg Msg
	err := bencode.Unmarshal([]byte("d1:rd6:valuesl6:\x01\x02\x03\x04\x05\x066:\x07\x08\x09\x0a\x0b\x0ce5:nodes52:\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07ee"), &msg)
	require.NoError(t, err)
	assert.Len(t, msg.R.Values, 2)
	assert.Len(t, msg.R.Nodes, 2)
	assert.Nil(t, msg.E)
}
<commit_msg>go vet<commit_after>package dht

import (
	"net"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/anacrolix/torrent/bencode"
	"github.com/anacrolix/torrent/util"
)

func testMarshalUnmarshalMsg(t *testing.T, m Msg, expected string) {
	b, err := bencode.Marshal(m)
	require.NoError(t, err)
	assert.Equal(t, expected, string(b))
	var _m Msg
	err = bencode.Unmarshal([]byte(expected), &_m)
	assert.NoError(t, err)
	assert.EqualValues(t, m, _m)
	assert.EqualValues(t, m.A, _m.A)
	assert.EqualValues(t, m.R, _m.R)
}

func TestMarshalUnmarshalMsg(t *testing.T) {
	testMarshalUnmarshalMsg(t, Msg{}, "d1:t0:1:y0:e")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "q",
		Q: "ping",
		T: "hi",
	}, "d1:q4:ping1:t2:hi1:y1:qe")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "e",
		T: "42",
		E: &KRPCError{Code: 200, Msg: "fuck"},
	}, "d1:eli200e4:fucke1:t2:421:y1:ee")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{},
	}, "d1:rd2:id0:e1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{
			Nodes: CompactIPv4NodeInfo{
				NodeInfo{
					Addr: newDHTAddr(&net.UDPAddr{
						IP:   net.IPv4(1, 2, 3, 4).To4(),
						Port: 0x1234,
					}),
				},
			},
		},
	}, "d1:rd2:id0:5:nodes26:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x124e1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x8c%",
		R: &Return{
			Values: []util.CompactPeer{
				util.CompactPeer{
					IP:   net.IPv4(1, 2, 3, 4).To4(),
					Port: 0x5678,
				},
			},
		},
	}, "d1:rd2:id0:6:valuesl6:\x01\x02\x03\x04\x56\x78ee1:t2:\x8c%1:y1:re")
	testMarshalUnmarshalMsg(t, Msg{
		Y: "r",
		T: "\x03",
		R: &Return{
			ID: "\xeb\xff6isQ\xffJ\xec)ͺ\xab\xf2\xfb\xe3F|\xc2g",
		},
		IP: util.CompactPeer{
			IP:   net.IPv4(124, 168, 180, 8).To4(),
			Port: 62844,
		},
	}, "d2:ip6:|\xa8\xb4\b\xf5|1:rd2:id20:\xeb\xff6isQ\xffJ\xec)ͺ\xab\xf2\xfb\xe3F|\xc2ge1:t1:\x031:y1:re")
}

func TestUnmarshalGetPeersResponse(t *testing.T) {
	var msg Msg
	err := bencode.Unmarshal([]byte("d1:rd6:valuesl6:\x01\x02\x03\x04\x05\x066:\x07\x08\x09\x0a\x0b\x0ce5:nodes52:\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x02\x03\x04\x05\x06\x07\x08\x09\x02\x03\x04\x05\x06\x07ee"), &msg)
	require.NoError(t, err)
	assert.Len(t, msg.R.Values, 2)
	assert.Len(t, msg.R.Nodes, 2)
	assert.Nil(t, msg.E)
}
<|endoftext|>


<commit_before>package wlclient

import (
	"bytes"
	"encoding/json"
	"net/url"
	"strconv"
	"time"
)

type Task struct {
	ID              int        `json:"id,omitempty"`
	ListID          int        `json:"list_id,omitempty"`
	Title           string     `json:"title,omitempty"`
	CreatedByID     int        `json:"created_by_id,omitempty"`
	Revision        int        `json:"revision,omitempty"`
	CreatedAt       *time.Time `json:"created_at,omitempty"`
	AssigneID       *int       `json:"assigne_id,omitempty"`
	Completed       *bool      `json:"completed,omitempty"`
	RecurrenceType  *string    `json:"recurrence_type,omitempty"`
	RecurrenceCount *int       `json:"recurrence_count,omitempty"`
	DueDate         *time.Time `json:"due_date,omitempty"`
	Starred         *bool      `json:"starred,omitempty"`
}

func (c *Client) CreateTask(in *Task) (out *Task, err error) {
	b, err := json.Marshal(in)
	if err != nil {
		return nil, err
	}
	return out, c.load("POST", "tasks", bytes.NewReader(b), &out)
}

type TaskOpt struct {
	ListID *int
}

func ListID(id int) func(*TaskOpt) {
	return func(o *TaskOpt) {
		o.ListID = &id
	}
}

func (t *TaskOpt) Encode() string {
	v := url.Values{}
	if t.ListID != nil {
		v.Add("list_id", strconv.Itoa(*t.ListID))
	}
	return v.Encode()
}

type Tasks []*Task

func (list Tasks) Len() int {
	return len(list)
}

func (list Tasks) Swap(a, b int) {
	list[a], list[b] = list[b], list[a]
}

func (list Tasks) Less(a, b int) bool {
	if list[a].CreatedAt == nil {
		return true
	} else if list[b].CreatedAt == nil {
		return false
	}
	return list[a].CreatedAt.Before(*list[b].CreatedAt)
}

func (c *Client) Tasks(opts ...func(*TaskOpt)) (out Tasks, err error) {
	i := &TaskOpt{}

	for _, f := range opts {
		f(i)
	}
	path := "tasks"
	if enc := i.Encode(); enc != "" {
		path += "?" + enc
	}
	return out, c.load("GET", path, nil, &out)

}

func (c *Client) Task(id int) (t *Task, err error) {
	return t, c.load("GET", "tasks/"+strconv.Itoa(id), nil, &t)
}

func (c *Client) DeleteTask(id int) error {
	t, err := c.Task(id)
	if err != nil {
		return err
	}
	_, err = c.request("DELETE", "tasks/"+strconv.Itoa(id)+"?revision="+strconv.Itoa(t.Revision), nil)
	return err
}

func (c *Client) CompleteTask(id int) error {
	return c.UpdateTask(&UpdateTask{ID: id, Completed: b2p(true)})
}

type UpdateTask struct {
	ID        int     `json:"id,omitempty"`
	Revision  int     `json:"revision,omitempty"`
	Completed *bool   `json:"completed,omitempty"`
	Title     *string `json:"title,omitempty"`
}

func (c *Client) UpdateTask(update *UpdateTask) error {
	t, err := c.Task(update.ID)
	if err != nil {
		return err
	}
	update.Revision = t.Revision
	b, err := json.Marshal(update)
	if err != nil {
		return err
	}
	_, err = c.request("PATCH", "tasks/"+strconv.Itoa(update.ID), bytes.NewReader(b))
	return err
}
<commit_msg>due date can be non-date field<commit_after>package wlclient

import (
	"bytes"
	"encoding/json"
	"net/url"
	"strconv"
	"time"
)

type Task struct {
	ID              int        `json:"id,omitempty"`
	ListID          int        `json:"list_id,omitempty"`
	Title           string     `json:"title,omitempty"`
	CreatedByID     int        `json:"created_by_id,omitempty"`
	Revision        int        `json:"revision,omitempty"`
	CreatedAt       *time.Time `json:"created_at,omitempty"`
	AssigneID       *int       `json:"assigne_id,omitempty"`
	Completed       *bool      `json:"completed,omitempty"`
	RecurrenceType  *string    `json:"recurrence_type,omitempty"`
	RecurrenceCount *int       `json:"recurrence_count,omitempty"`
	DueDate         *string    `json:"due_date,omitempty"`
	Starred         *bool      `json:"starred,omitempty"`
}

func (c *Client) CreateTask(in *Task) (out *Task, err error) {
	b, err := json.Marshal(in)
	if err != nil {
		return nil, err
	}
	return out, c.load("POST", "tasks", bytes.NewReader(b), &out)
}

type TaskOpt struct {
	ListID *int
}

func ListID(id int) func(*TaskOpt) {
	return func(o *TaskOpt) {
		o.ListID = &id
	}
}

func (t *TaskOpt) Encode() string {
	v := url.Values{}
	if t.ListID != nil {
		v.Add("list_id", strconv.Itoa(*t.ListID))
	}
	return v.Encode()
}

type Tasks []*Task

func (list Tasks) Len() int {
	return len(list)
}

func (list Tasks) Swap(a, b int) {
	list[a], list[b] = list[b], list[a]
}

func (list Tasks) Less(a, b int) bool {
	if list[a].CreatedAt == nil {
		return true
	} else if list[b].CreatedAt == nil {
		return false
	}
	return list[a].CreatedAt.Before(*list[b].CreatedAt)
}

func (c *Client) Tasks(opts ...func(*TaskOpt)) (out Tasks, err error) {
	i := &TaskOpt{}

	for _, f := range opts {
		f(i)
	}
	path := "tasks"
	if enc := i.Encode(); enc != "" {
		path += "?" + enc
	}
	return out, c.load("GET", path, nil, &out)

}

func (c *Client) Task(id int) (t *Task, err error) {
	return t, c.load("GET", "tasks/"+strconv.Itoa(id), nil, &t)
}

func (c *Client) DeleteTask(id int) error {
	t, err := c.Task(id)
	if err != nil {
		return err
	}
	_, err = c.request("DELETE", "tasks/"+strconv.Itoa(id)+"?revision="+strconv.Itoa(t.Revision), nil)
	return err
}

func (c *Client) CompleteTask(id int) error {
	return c.UpdateTask(&UpdateTask{ID: id, Completed: b2p(true)})
}

type UpdateTask struct {
	ID        int     `json:"id,omitempty"`
	Revision  int     `json:"revision,omitempty"`
	Completed *bool   `json:"completed,omitempty"`
	Title     *string `json:"title,omitempty"`
}

func (c *Client) UpdateTask(update *UpdateTask) error {
	t, err := c.Task(update.ID)
	if err != nil {
		return err
	}
	update.Revision = t.Revision
	b, err := json.Marshal(update)
	if err != nil {
		return err
	}
	_, err = c.request("PATCH", "tasks/"+strconv.Itoa(update.ID), bytes.NewReader(b))
	return err
}
<|endoftext|>


<commit_before>// Copyright 2015 Google LLC.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package http supports network connections to HTTP servers.
// This package is not intended for use by end developers. Use the
// google.golang.org/api/option package to configure API clients.
package http

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
	"time"

	"go.opencensus.io/plugin/ochttp"
	"golang.org/x/oauth2"
	"google.golang.org/api/googleapi/transport"
	"google.golang.org/api/internal"
	"google.golang.org/api/option"
	"google.golang.org/api/transport/cert"
	"google.golang.org/api/transport/http/internal/propagation"
	"google.golang.org/api/transport/internal/dca"
)

// NewClient returns an HTTP client for use communicating with a Google cloud
// service, configured with the given ClientOptions. It also returns the endpoint
// for the service as specified in the options.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*http.Client, string, error) {
	settings, err := newSettings(opts)
	if err != nil {
		return nil, "", err
	}
	clientCertSource, endpoint, err := dca.GetClientCertificateSourceAndEndpoint(settings)
	if err != nil {
		return nil, "", err
	}
	// TODO(cbro): consider injecting the User-Agent even if an explicit HTTP client is provided?
	if settings.HTTPClient != nil {
		return settings.HTTPClient, endpoint, nil
	}
	trans, err := newTransport(ctx, defaultBaseTransport(ctx, clientCertSource), settings)
	if err != nil {
		return nil, "", err
	}
	return &http.Client{Transport: trans}, endpoint, nil
}

// NewTransport creates an http.RoundTripper for use communicating with a Google
// cloud service, configured with the given ClientOptions. Its RoundTrip method delegates to base.
func NewTransport(ctx context.Context, base http.RoundTripper, opts ...option.ClientOption) (http.RoundTripper, error) {
	settings, err := newSettings(opts)
	if err != nil {
		return nil, err
	}
	if settings.HTTPClient != nil {
		return nil, errors.New("transport/http: WithHTTPClient passed to NewTransport")
	}
	return newTransport(ctx, base, settings)
}

func newTransport(ctx context.Context, base http.RoundTripper, settings *internal.DialSettings) (http.RoundTripper, error) {
	paramTransport := &parameterTransport{
		base:          base,
		userAgent:     settings.UserAgent,
		quotaProject:  settings.QuotaProject,
		requestReason: settings.RequestReason,
	}
	var trans http.RoundTripper = paramTransport
	trans = addOCTransport(trans, settings)
	switch {
	case settings.NoAuth:
		// Do nothing.
	case settings.APIKey != "":
		trans = &transport.APIKey{
			Transport: trans,
			Key:       settings.APIKey,
		}
	default:
		creds, err := internal.Creds(ctx, settings)
		if err != nil {
			return nil, err
		}
		if paramTransport.quotaProject == "" {
			paramTransport.quotaProject = internal.QuotaProjectFromCreds(creds)
		}

		ts := creds.TokenSource
		if settings.TokenSource != nil {
			ts = settings.TokenSource
		}
		trans = &oauth2.Transport{
			Base:   trans,
			Source: ts,
		}
	}
	return trans, nil
}

func newSettings(opts []option.ClientOption) (*internal.DialSettings, error) {
	var o internal.DialSettings
	for _, opt := range opts {
		opt.Apply(&o)
	}
	if err := o.Validate(); err != nil {
		return nil, err
	}
	if o.GRPCConn != nil {
		return nil, errors.New("unsupported gRPC connection specified")
	}
	return &o, nil
}

type parameterTransport struct {
	userAgent     string
	quotaProject  string
	requestReason string

	base http.RoundTripper
}

func (t *parameterTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	rt := t.base
	if rt == nil {
		return nil, errors.New("transport: no Transport specified")
	}
	newReq := *req
	newReq.Header = make(http.Header)
	for k, vv := range req.Header {
		newReq.Header[k] = vv
	}
	if t.userAgent != "" {
		// TODO(cbro): append to existing User-Agent header?
		newReq.Header.Set("User-Agent", t.userAgent)
	}

	// Attach system parameters into the header
	if t.quotaProject != "" {
		newReq.Header.Set("X-Goog-User-Project", t.quotaProject)
	}
	if t.requestReason != "" {
		newReq.Header.Set("X-Goog-Request-Reason", t.requestReason)
	}

	return rt.RoundTrip(&newReq)
}

// Set at init time by dial_appengine.go. If nil, we're not on App Engine.
var appengineUrlfetchHook func(context.Context) http.RoundTripper

// defaultBaseTransport returns the base HTTP transport.
// On App Engine, this is urlfetch.Transport.
// Otherwise, use a default transport, taking most defaults from
// http.DefaultTransport.
// If TLSCertificate is available, set TLSClientConfig as well.
func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source) http.RoundTripper {
	if appengineUrlfetchHook != nil {
		return appengineUrlfetchHook(ctx)
	}

	// Copy http.DefaultTransport except for MaxIdleConnsPerHost setting,
	// which is increased due to reported performance issues under load in the GCS
	// client. Transport.Clone is only available in Go 1.13 and up.
	trans := clonedTransport(http.DefaultTransport)
	if trans == nil {
		trans = fallbackBaseTransport()
	}
	trans.MaxIdleConnsPerHost = 100

	if clientCertSource != nil {
		trans.TLSClientConfig = &tls.Config{
			GetClientCertificate: clientCertSource,
		}
	}

	return trans
}

// fallbackBaseTransport is used in <go1.13 as well as in the rare case if
// http.DefaultTransport has been reassigned something that's not a
// *http.Transport.
func fallbackBaseTransport() *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		MaxIdleConnsPerHost:   100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
}

func addOCTransport(trans http.RoundTripper, settings *internal.DialSettings) http.RoundTripper {
	if settings.TelemetryDisabled {
		return trans
	}
	return &ochttp.Transport{
		Base:        trans,
		Propagation: &propagation.HTTPFormat{},
	}
}
<commit_msg>transport/http: fix impersonation credential error (#797)<commit_after>// Copyright 2015 Google LLC.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package http supports network connections to HTTP servers.
// This package is not intended for use by end developers. Use the
// google.golang.org/api/option package to configure API clients.
package http

import (
	"context"
	"crypto/tls"
	"errors"
	"net"
	"net/http"
	"time"

	"go.opencensus.io/plugin/ochttp"
	"golang.org/x/oauth2"
	"google.golang.org/api/googleapi/transport"
	"google.golang.org/api/internal"
	"google.golang.org/api/option"
	"google.golang.org/api/transport/cert"
	"google.golang.org/api/transport/http/internal/propagation"
	"google.golang.org/api/transport/internal/dca"
)

// NewClient returns an HTTP client for use communicating with a Google cloud
// service, configured with the given ClientOptions. It also returns the endpoint
// for the service as specified in the options.
func NewClient(ctx context.Context, opts ...option.ClientOption) (*http.Client, string, error) {
	settings, err := newSettings(opts)
	if err != nil {
		return nil, "", err
	}
	clientCertSource, endpoint, err := dca.GetClientCertificateSourceAndEndpoint(settings)
	if err != nil {
		return nil, "", err
	}
	// TODO(cbro): consider injecting the User-Agent even if an explicit HTTP client is provided?
	if settings.HTTPClient != nil {
		return settings.HTTPClient, endpoint, nil
	}
	trans, err := newTransport(ctx, defaultBaseTransport(ctx, clientCertSource), settings)
	if err != nil {
		return nil, "", err
	}
	return &http.Client{Transport: trans}, endpoint, nil
}

// NewTransport creates an http.RoundTripper for use communicating with a Google
// cloud service, configured with the given ClientOptions. Its RoundTrip method delegates to base.
func NewTransport(ctx context.Context, base http.RoundTripper, opts ...option.ClientOption) (http.RoundTripper, error) {
	settings, err := newSettings(opts)
	if err != nil {
		return nil, err
	}
	if settings.HTTPClient != nil {
		return nil, errors.New("transport/http: WithHTTPClient passed to NewTransport")
	}
	return newTransport(ctx, base, settings)
}

func newTransport(ctx context.Context, base http.RoundTripper, settings *internal.DialSettings) (http.RoundTripper, error) {
	paramTransport := &parameterTransport{
		base:          base,
		userAgent:     settings.UserAgent,
		quotaProject:  settings.QuotaProject,
		requestReason: settings.RequestReason,
	}
	var trans http.RoundTripper = paramTransport
	trans = addOCTransport(trans, settings)
	switch {
	case settings.NoAuth:
		// Do nothing.
	case settings.APIKey != "":
		trans = &transport.APIKey{
			Transport: trans,
			Key:       settings.APIKey,
		}
	default:
		creds, err := internal.Creds(ctx, settings)
		if err != nil {
			return nil, err
		}
		if paramTransport.quotaProject == "" {
			paramTransport.quotaProject = internal.QuotaProjectFromCreds(creds)
		}

		ts := creds.TokenSource
		if settings.ImpersonationConfig == nil && settings.TokenSource != nil {
			ts = settings.TokenSource
		}
		trans = &oauth2.Transport{
			Base:   trans,
			Source: ts,
		}
	}
	return trans, nil
}

func newSettings(opts []option.ClientOption) (*internal.DialSettings, error) {
	var o internal.DialSettings
	for _, opt := range opts {
		opt.Apply(&o)
	}
	if err := o.Validate(); err != nil {
		return nil, err
	}
	if o.GRPCConn != nil {
		return nil, errors.New("unsupported gRPC connection specified")
	}
	return &o, nil
}

type parameterTransport struct {
	userAgent     string
	quotaProject  string
	requestReason string

	base http.RoundTripper
}

func (t *parameterTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	rt := t.base
	if rt == nil {
		return nil, errors.New("transport: no Transport specified")
	}
	newReq := *req
	newReq.Header = make(http.Header)
	for k, vv := range req.Header {
		newReq.Header[k] = vv
	}
	if t.userAgent != "" {
		// TODO(cbro): append to existing User-Agent header?
		newReq.Header.Set("User-Agent", t.userAgent)
	}

	// Attach system parameters into the header
	if t.quotaProject != "" {
		newReq.Header.Set("X-Goog-User-Project", t.quotaProject)
	}
	if t.requestReason != "" {
		newReq.Header.Set("X-Goog-Request-Reason", t.requestReason)
	}

	return rt.RoundTrip(&newReq)
}

// Set at init time by dial_appengine.go. If nil, we're not on App Engine.
var appengineUrlfetchHook func(context.Context) http.RoundTripper

// defaultBaseTransport returns the base HTTP transport.
// On App Engine, this is urlfetch.Transport.
// Otherwise, use a default transport, taking most defaults from
// http.DefaultTransport.
// If TLSCertificate is available, set TLSClientConfig as well.
func defaultBaseTransport(ctx context.Context, clientCertSource cert.Source) http.RoundTripper {
	if appengineUrlfetchHook != nil {
		return appengineUrlfetchHook(ctx)
	}

	// Copy http.DefaultTransport except for MaxIdleConnsPerHost setting,
	// which is increased due to reported performance issues under load in the GCS
	// client. Transport.Clone is only available in Go 1.13 and up.
	trans := clonedTransport(http.DefaultTransport)
	if trans == nil {
		trans = fallbackBaseTransport()
	}
	trans.MaxIdleConnsPerHost = 100

	if clientCertSource != nil {
		trans.TLSClientConfig = &tls.Config{
			GetClientCertificate: clientCertSource,
		}
	}

	return trans
}

// fallbackBaseTransport is used in <go1.13 as well as in the rare case if
// http.DefaultTransport has been reassigned something that's not a
// *http.Transport.
func fallbackBaseTransport() *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		DialContext: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			DualStack: true,
		}).DialContext,
		MaxIdleConns:          100,
		MaxIdleConnsPerHost:   100,
		IdleConnTimeout:       90 * time.Second,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	}
}

func addOCTransport(trans http.RoundTripper, settings *internal.DialSettings) http.RoundTripper {
	if settings.TelemetryDisabled {
		return trans
	}
	return &ochttp.Transport{
		Base:        trans,
		Propagation: &propagation.HTTPFormat{},
	}
}
<|endoftext|>


<commit_before>// Package transport implements an encrypted and authenticated bytestream
// connection. The key-exchange is like SIGMA-I, with the exception that
// instead of unvirersally verifiable signatures, nacl/box between one party's
// ephemeral key and the other's long-term key is used for authentication (this
// provides deniability). Subsequent messages are encrypted using nacl/box with
// the message counter as an implicit nonce.
package transport

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"time"

	"code.google.com/p/go.crypto/nacl/box"
)

// Conn is an encrypted and authenticated connection that is NOT concurrency-safe
type Conn struct {
	unencrypted           net.Conn
	readNonce, writeNonce uint64
	key                   [32]byte
	readBuf, writeBuf     []byte
	maxFrameSize          int
}

var nullNonce = [24]byte{}

// Handshake establishes an encrypted and authenticated connection. unencrypted
// is the underlying connection that will be used for the handshake and the
// following calls to ReadFrame and WriteFrame. The connection should not be
// used after calling Handshake. pk and sk are the Curve25519 public and
// private keys of the caller. If expectedPK is not nil, pk will not be
// revealed to the other party unless they prove that they hold the secret key
// that corresponds to expectedPK.  Note that both sides of a connection using
// this option will result in a deadlock. The public key of the other party is
// returned along with the wrapped connection.
func Handshake(unencrypted net.Conn, pk, sk, expectedPK *[32]byte, maxFrameSize int) (*Conn, *[32]byte, error) {
	ourEphemeralPublic, ourEphemeralSecret, err := box.GenerateKey(rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	var theirEphemeralPublic, theirPK [32]byte
	var readErr, writeErr error
	writeDone, readDone := make(chan struct{}), make(chan chan struct{})
	go func() { _, writeErr = unencrypted.Write(ourEphemeralPublic[:]); close(writeDone) }()
	go func() { _, readErr = io.ReadFull(unencrypted, theirEphemeralPublic[:]); close(readDone) }()
	if <-writeDone; writeErr != nil {
		return nil, nil, writeErr
	}
	if <-readDone; readErr != nil {
		return nil, nil, readErr
	}

	ret := &Conn{unencrypted: unencrypted, maxFrameSize: maxFrameSize,
		readBuf:  make([]byte, binary.MaxVarintLen64+box.Overhead+maxFrameSize),
		writeBuf: make([]byte, binary.MaxVarintLen64+box.Overhead+maxFrameSize)}
	if bytes.Compare(ourEphemeralPublic[:], theirEphemeralPublic[:]) < 0 {
		ret.writeNonce = 1
	} else {
		ret.readNonce = 1
	}
	box.Precompute(&ret.key, &theirEphemeralPublic, ourEphemeralSecret)

	writeDone, readDone = make(chan struct{}), make(chan chan struct{})
	go func() {
		defer close(readDone)
		var theirHandshake [32 + (box.Overhead + 32 + 32)]byte // theirPK, box(theirEphPK, ourEphPK)
		if _, readErr = ret.ReadFrame(theirHandshake[:]); readErr != nil {
			return
		}
		copy(theirPK[:], theirHandshake[:32])
		hs, ok := box.Open(nil, theirHandshake[32:], &nullNonce, &theirPK, ourEphemeralSecret)
		if !ok || !bytes.Equal(hs, append(theirEphemeralPublic[:], ourEphemeralPublic[:]...)) {
			readErr = errors.New("authentication failed (ephemeral pk mismatch)")
			println("ok", ok)
			return
		}
		if expectedPK != nil && !bytes.Equal(theirPK[:], expectedPK[:]) {
			readErr = errors.New("authentication failed (observed pk != expected pk)")
			return
		}
	}()
	go func() {
		defer close(writeDone)
		ourHandshake := box.Seal(pk[:], append(ourEphemeralPublic[:], theirEphemeralPublic[:]...),
			&nullNonce, &theirEphemeralPublic, sk)
		if expectedPK != nil {
			if <-readDone; readErr != nil { // only talk to the right server
				return
			}
		}
		_, writeErr = ret.WriteFrame(ourHandshake)
	}()
	if <-readDone; readErr != nil {
		return nil, nil, readErr
	}
	if <-writeDone; writeErr != nil {
		return nil, nil, writeErr
	}
	for i := range ourEphemeralSecret {
		ourEphemeralSecret[i] = 0
	}
	return ret, &theirPK, nil
}

// WriteFrame(b) writes the frame to the connection in a length-value-encoded
// for so it can be read using ReadFrame on the other side. Returns len(b).
func (c *Conn) WriteFrame(b []byte) (int, error) {
	if len(b) > c.maxFrameSize {
		return 0, errors.New("write frame too large")
	}
	var nonce [24]byte
	binary.LittleEndian.PutUint64(nonce[:], c.writeNonce)
	c.writeNonce += 2
	i := binary.PutUvarint(c.writeBuf, uint64(box.Overhead+len(b)))
	buf := box.SealAfterPrecomputation(c.writeBuf[:i], b, &nonce, &c.key)
	if _, err := c.unencrypted.Write(buf); err != nil {
		return 0, err
	}
	return len(b), nil
}

type byteReader struct{ io.Reader }

func (r byteReader) ReadByte() (byte, error) {
	var ret [1]byte
	_, err := io.ReadFull(r, ret[:])
	return ret[0], err
}

// ReadFrame(b) reads a single frame into b and returns an integer n such that
// b[:n] is the frame after possibly modifying b. If b does not have enough
// space (maxFrameSize bytes), this function may panic.
func (c *Conn) ReadFrame(b []byte) (int, error) {
	var nonce [24]byte
	binary.LittleEndian.PutUint64(nonce[:], c.readNonce)
	c.readNonce += 2
	size, err := binary.ReadUvarint(byteReader{c.unencrypted})
	if err != nil {
		return 0, err
	}
	if _, err := io.ReadFull(c.unencrypted, c.readBuf[:size]); err != nil {
		return 0, err
	}
	b2, ok := box.OpenAfterPrecomputation(b[:0], c.readBuf[:size], &nonce, &c.key)
	if !ok {
		return 0, errors.New("authentication failed")
	}
	if &b[0] != &b2[0] {
		panic("ReadFrame buffer space accounting failed")
	}
	return int(size - box.Overhead), nil
}

func (c *Conn) Close() error {
	for i := range c.key {
		c.key[i] = 0
	}
	return c.unencrypted.Close()
}

func (c *Conn) SetDeadline(t time.Time) error      { return c.unencrypted.SetDeadline(t) }
func (c *Conn) SetWriteDeadline(t time.Time) error { return c.unencrypted.SetWriteDeadline(t) }
func (c *Conn) SetReadDeadline(t time.Time) error  { return c.unencrypted.SetReadDeadline(t) }
<commit_msg>remove debug print from transport<commit_after>// Package transport implements an encrypted and authenticated bytestream
// connection. The key-exchange is like SIGMA-I, with the exception that
// instead of unvirersally verifiable signatures, nacl/box between one party's
// ephemeral key and the other's long-term key is used for authentication (this
// provides deniability). Subsequent messages are encrypted using nacl/box with
// the message counter as an implicit nonce.
package transport

import (
	"bytes"
	"crypto/rand"
	"encoding/binary"
	"errors"
	"io"
	"net"
	"time"

	"code.google.com/p/go.crypto/nacl/box"
)

// Conn is an encrypted and authenticated connection that is NOT concurrency-safe
type Conn struct {
	unencrypted           net.Conn
	readNonce, writeNonce uint64
	key                   [32]byte
	readBuf, writeBuf     []byte
	maxFrameSize          int
}

var nullNonce = [24]byte{}

// Handshake establishes an encrypted and authenticated connection. unencrypted
// is the underlying connection that will be used for the handshake and the
// following calls to ReadFrame and WriteFrame. The connection should not be
// used after calling Handshake. pk and sk are the Curve25519 public and
// private keys of the caller. If expectedPK is not nil, pk will not be
// revealed to the other party unless they prove that they hold the secret key
// that corresponds to expectedPK.  Note that both sides of a connection using
// this option will result in a deadlock. The public key of the other party is
// returned along with the wrapped connection.
func Handshake(unencrypted net.Conn, pk, sk, expectedPK *[32]byte, maxFrameSize int) (*Conn, *[32]byte, error) {
	ourEphemeralPublic, ourEphemeralSecret, err := box.GenerateKey(rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	var theirEphemeralPublic, theirPK [32]byte
	var readErr, writeErr error
	writeDone, readDone := make(chan struct{}), make(chan chan struct{})
	go func() { _, writeErr = unencrypted.Write(ourEphemeralPublic[:]); close(writeDone) }()
	go func() { _, readErr = io.ReadFull(unencrypted, theirEphemeralPublic[:]); close(readDone) }()
	if <-writeDone; writeErr != nil {
		return nil, nil, writeErr
	}
	if <-readDone; readErr != nil {
		return nil, nil, readErr
	}

	ret := &Conn{unencrypted: unencrypted, maxFrameSize: maxFrameSize,
		readBuf:  make([]byte, binary.MaxVarintLen64+box.Overhead+maxFrameSize),
		writeBuf: make([]byte, binary.MaxVarintLen64+box.Overhead+maxFrameSize)}
	if bytes.Compare(ourEphemeralPublic[:], theirEphemeralPublic[:]) < 0 {
		ret.writeNonce = 1
	} else {
		ret.readNonce = 1
	}
	box.Precompute(&ret.key, &theirEphemeralPublic, ourEphemeralSecret)

	writeDone, readDone = make(chan struct{}), make(chan chan struct{})
	go func() {
		defer close(readDone)
		var theirHandshake [32 + (box.Overhead + 32 + 32)]byte // theirPK, box(theirEphPK, ourEphPK)
		if _, readErr = ret.ReadFrame(theirHandshake[:]); readErr != nil {
			return
		}
		copy(theirPK[:], theirHandshake[:32])
		hs, ok := box.Open(nil, theirHandshake[32:], &nullNonce, &theirPK, ourEphemeralSecret)
		if !ok || !bytes.Equal(hs, append(theirEphemeralPublic[:], ourEphemeralPublic[:]...)) {
			readErr = errors.New("authentication failed (ephemeral pk mismatch)")
			return
		}
		if expectedPK != nil && !bytes.Equal(theirPK[:], expectedPK[:]) {
			readErr = errors.New("authentication failed (observed pk != expected pk)")
			return
		}
	}()
	go func() {
		defer close(writeDone)
		ourHandshake := box.Seal(pk[:], append(ourEphemeralPublic[:], theirEphemeralPublic[:]...),
			&nullNonce, &theirEphemeralPublic, sk)
		if expectedPK != nil {
			if <-readDone; readErr != nil { // only talk to the right server
				return
			}
		}
		_, writeErr = ret.WriteFrame(ourHandshake)
	}()
	if <-readDone; readErr != nil {
		return nil, nil, readErr
	}
	if <-writeDone; writeErr != nil {
		return nil, nil, writeErr
	}
	for i := range ourEphemeralSecret {
		ourEphemeralSecret[i] = 0
	}
	return ret, &theirPK, nil
}

// WriteFrame(b) writes the frame to the connection in a length-value-encoded
// for so it can be read using ReadFrame on the other side. Returns len(b).
func (c *Conn) WriteFrame(b []byte) (int, error) {
	if len(b) > c.maxFrameSize {
		return 0, errors.New("write frame too large")
	}
	var nonce [24]byte
	binary.LittleEndian.PutUint64(nonce[:], c.writeNonce)
	c.writeNonce += 2
	i := binary.PutUvarint(c.writeBuf, uint64(box.Overhead+len(b)))
	buf := box.SealAfterPrecomputation(c.writeBuf[:i], b, &nonce, &c.key)
	if _, err := c.unencrypted.Write(buf); err != nil {
		return 0, err
	}
	return len(b), nil
}

type byteReader struct{ io.Reader }

func (r byteReader) ReadByte() (byte, error) {
	var ret [1]byte
	_, err := io.ReadFull(r, ret[:])
	return ret[0], err
}

// ReadFrame(b) reads a single frame into b and returns an integer n such that
// b[:n] is the frame after possibly modifying b. If b does not have enough
// space (maxFrameSize bytes), this function may panic.
func (c *Conn) ReadFrame(b []byte) (int, error) {
	var nonce [24]byte
	binary.LittleEndian.PutUint64(nonce[:], c.readNonce)
	c.readNonce += 2
	size, err := binary.ReadUvarint(byteReader{c.unencrypted})
	if err != nil {
		return 0, err
	}
	if _, err := io.ReadFull(c.unencrypted, c.readBuf[:size]); err != nil {
		return 0, err
	}
	b2, ok := box.OpenAfterPrecomputation(b[:0], c.readBuf[:size], &nonce, &c.key)
	if !ok {
		return 0, errors.New("authentication failed")
	}
	if &b[0] != &b2[0] {
		panic("ReadFrame buffer space accounting failed")
	}
	return int(size - box.Overhead), nil
}

func (c *Conn) Close() error {
	for i := range c.key {
		c.key[i] = 0
	}
	return c.unencrypted.Close()
}

func (c *Conn) SetDeadline(t time.Time) error      { return c.unencrypted.SetDeadline(t) }
func (c *Conn) SetWriteDeadline(t time.Time) error { return c.unencrypted.SetWriteDeadline(t) }
func (c *Conn) SetReadDeadline(t time.Time) error  { return c.unencrypted.SetReadDeadline(t) }
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"github.com/oleiade/trousseau"
	"os"
)

func main() {
	app := cli.NewApp()

	app.Name = "trousseau"
	app.Usage = "handles an encrypted keys store"
	app.Version = trousseau.TROUSSEAU_VERSION
	app.Commands = []cli.Command{
		trousseau.CreateCommand(),
		trousseau.PushCommand(),
		trousseau.PullCommand(),
		trousseau.ExportCommand(),
		trousseau.ImportCommand(),
		trousseau.AddRecipientCommand(),
		trousseau.RemoveRecipientCommand(),
		trousseau.SetCommand(),
		trousseau.GetCommand(),
		trousseau.DelCommand(),
		trousseau.KeysCommand(),
		trousseau.ShowCommand(),
		trousseau.MetaCommand(),
	}

	app.Run(os.Args)
}
<commit_msg>Add password flag registration as global option [ref #13]<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"github.com/oleiade/trousseau"
	"os"
)

func main() {
	app := cli.NewApp()

	app.Name = "trousseau"
	app.Usage = "handles an encrypted keys store"
	app.Version = trousseau.TROUSSEAU_VERSION
	app.Commands = []cli.Command{
		trousseau.CreateCommand(),
		trousseau.PushCommand(),
		trousseau.PullCommand(),
		trousseau.ExportCommand(),
		trousseau.ImportCommand(),
		trousseau.AddRecipientCommand(),
		trousseau.RemoveRecipientCommand(),
		trousseau.SetCommand(),
		trousseau.GetCommand(),
		trousseau.DelCommand(),
		trousseau.KeysCommand(),
		trousseau.ShowCommand(),
		trousseau.MetaCommand(),
	}

    // Application global options
	app.Flags = []cli.Flag{
        trousseau.PasswordFlag(),
	}

	app.Run(os.Args)
}
<|endoftext|>