<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/rcrowley/go-metrics"
	"github.com/rcrowley/go-metrics/librato"
	"github.com/vmihailenco/redis/v2"
)

var config Config
var client *redis.Client

type stringslice []string

func (s *stringslice) String() string {
	return fmt.Sprint(*s)
}

func (s *stringslice) Set(value string) error {
	for _, ss := range strings.Split(value, ",") {
		*s = append(*s, ss)
	}
	return nil
}

type Config struct {
	SensordURLs   stringslice
	Port          string
	RedisURL      string
	Retention     int64
	LibratoEmail  string
	LibratoToken  string
	LibratoSource string
}

type Check struct {
	ID  string `json:"id"`
	URL string `json:"url"`
}

type Measurement struct {
	Check             Check   `json:"check"`
	ID                string  `json:"id"`
	Location          string  `json:"location"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	HTTPStatus        int     `json:"http_status,omitempty"`
	LocalIP           string  `json:"local_ip,omitempty"`
	PrimaryIP         string  `json:"primary_ip,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	SizeDownload      float64 `json:"size_download,omitempty"`
}

func (m *Measurement) record() {
	s, _ := json.Marshal(m)
	z := redis.Z{Score: float64(m.T), Member: string(s)}
	r := client.ZAdd(getRedisKey(m.Check.ID), z)
	if r.Err() != nil {
		log.Fatalf("Error while recording measurement %s: %v\n", m.ID, r.Err())
	}
}

func trimMeasurements(checkID string, seconds int64) {
	now := time.Now()
	epoch := now.Unix() - seconds
	r := client.ZRemRangeByScore(getRedisKey(checkID), "-inf", strconv.FormatInt(epoch, 10))
	if r.Err() != nil {
		log.Fatalf("Error while trimming check_id %s: %v\n", checkID, r.Err())
	}
}

func getRedisKey(checkID string) string {
	return "measurements:" + checkID
}

func getMeasurementsByRange(checkID string, r int64) []Measurement {
	now := time.Now()
	from := now.Unix() - r

	return getMeasurementsFrom(checkID, from)
}

func getMeasurementsFrom(checkID string, from int64) []Measurement {
	vals, err := client.ZRevRangeByScore(getRedisKey(checkID), redis.ZRangeByScore{
		Min: strconv.FormatInt(from, 10),
		Max: "+inf",
	}).Result()

	if err != nil {
		panic(err)
	}

	measurements := make([]Measurement, 0, 100)

	for _, v := range vals {
		var m Measurement
		json.Unmarshal([]byte(v), &m)
		measurements = append(measurements, m)
	}

	return measurements
}

func getFormValueWithDefault(req *http.Request, key string, def string) string {
	s := req.FormValue(key)
	if s != "" {
		return s
	}
	return def
}

func connectToRedis(config Config) {
	u, err := url.Parse(config.RedisURL)
	if err != nil {
		panic(err)
	}

	client = redis.NewTCPClient(&redis.Options{
		Addr:     u.Host,
		Password: "", // no password set
		DB:       0,  // use default DB
	})
}

func httpServer(config Config) {
	t := metrics.NewTimer()
	metrics.Register("canaryd.get_measurements", t)

	h := func(res http.ResponseWriter, req *http.Request) {
		t.Time(func() {
			vars := mux.Vars(req)
			checkID := vars["check_id"]
			rS := getFormValueWithDefault(req, "range", "10")

			r, err := strconv.ParseInt(rS, 10, 64)
			if err != nil {
				panic(nil)
			}
			log.Printf("fn=getMeasurements ip=%s range=%d\n", req.RemoteAddr, r)
			res.Header().Set("Content-Type", "application/json")
			json.NewEncoder(res).Encode(getMeasurementsByRange(checkID, r))
		})
	}

	r := mux.NewRouter()
	r.HandleFunc("/checks/{check_id}/measurements", h).Methods("GET")
	http.Handle("/", r)

	log.Printf("fn=main listening=true port=%s\n", config.Port)

	err := http.ListenAndServe(":"+config.Port, nil)
	if err != nil {
		panic(err)
	}
}

func ingest(url string, toRecorder chan Measurement) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return errors.New(fmt.Sprintf("fn=ingestor url=%s connect=failed status_code=%d", url, res.StatusCode))
	}

	log.Printf("fn=ingestor url=%s connect=success\n", url)

	rd := bufio.NewReader(res.Body)
	dec := json.NewDecoder(rd)

	for {
		var m Measurement
		err = dec.Decode(&m)
		if err != nil {
			return err
		}
		toRecorder <- m
	}
}

func ingestor(url string, toRecorder chan Measurement) {
	for {
		err := ingest(url, toRecorder)
		log.Println(err)
		time.Sleep(1000 * time.Millisecond)
	}
}

func recorder(config Config, toRecorder chan Measurement) {
	recordTimer := metrics.NewTimer()
	metrics.Register("canaryd.record", recordTimer)

	trimTimer := metrics.NewTimer()
	metrics.Register("canaryd.trim", trimTimer)

	for {
		m := <-toRecorder
		recordTimer.Time(func() { m.record() })
		trimTimer.Time(func() { trimMeasurements(m.Check.ID, config.Retention) })
	}
}

func init() {
	flag.StringVar(&config.Port, "port", "5000", "port the HTTP server should bind to")
	flag.StringVar(&config.RedisURL, "redis_url", "redis://localhost:6379", "redis url")
	flag.Int64Var(&config.Retention, "retention", 60, "second of each measurement to keep")
	flag.Var(&config.SensordURLs, "sensord_url", "List of sensors")

	config.LibratoEmail = os.Getenv("LIBRATO_EMAIL")
	config.LibratoToken = os.Getenv("LIBRATO_TOKEN")
	config.LibratoSource = os.Getenv("LIBRATO_SOURCE")
}

func main() {
	flag.Parse()

	toRecorder := make(chan Measurement)

	if config.LibratoEmail != "" && config.LibratoToken != "" && config.LibratoSource != "" {
		log.Println("fn=main metircs=librato")
		go librato.Librato(metrics.DefaultRegistry,
			10e9,                  // interval
			config.LibratoEmail,   // account owner email address
			config.LibratoToken,   // Librato API token
			config.LibratoSource,  // source
			[]float64{50, 95, 99}, // precentiles to send
			time.Millisecond,      // time unit
		)
	}

	connectToRedis(config)

	go httpServer(config)
	go recorder(config, toRecorder)

	for _, url := range config.SensordURLs {
		go ingestor(url, toRecorder)
	}

	select {}
}
<commit_msg>Add CORS headers<commit_after>package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gorilla/mux"
	"github.com/rcrowley/go-metrics"
	"github.com/rcrowley/go-metrics/librato"
	"github.com/vmihailenco/redis/v2"
)

var config Config
var client *redis.Client

type stringslice []string

func (s *stringslice) String() string {
	return fmt.Sprint(*s)
}

func (s *stringslice) Set(value string) error {
	for _, ss := range strings.Split(value, ",") {
		*s = append(*s, ss)
	}
	return nil
}

type Config struct {
	SensordURLs   stringslice
	Port          string
	RedisURL      string
	Retention     int64
	LibratoEmail  string
	LibratoToken  string
	LibratoSource string
}

type Check struct {
	ID  string `json:"id"`
	URL string `json:"url"`
}

type Measurement struct {
	Check             Check   `json:"check"`
	ID                string  `json:"id"`
	Location          string  `json:"location"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	HTTPStatus        int     `json:"http_status,omitempty"`
	LocalIP           string  `json:"local_ip,omitempty"`
	PrimaryIP         string  `json:"primary_ip,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	SizeDownload      float64 `json:"size_download,omitempty"`
}

func (m *Measurement) record() {
	s, _ := json.Marshal(m)
	z := redis.Z{Score: float64(m.T), Member: string(s)}
	r := client.ZAdd(getRedisKey(m.Check.ID), z)
	if r.Err() != nil {
		log.Fatalf("Error while recording measurement %s: %v\n", m.ID, r.Err())
	}
}

func trimMeasurements(checkID string, seconds int64) {
	now := time.Now()
	epoch := now.Unix() - seconds
	r := client.ZRemRangeByScore(getRedisKey(checkID), "-inf", strconv.FormatInt(epoch, 10))
	if r.Err() != nil {
		log.Fatalf("Error while trimming check_id %s: %v\n", checkID, r.Err())
	}
}

func getRedisKey(checkID string) string {
	return "measurements:" + checkID
}

func getMeasurementsByRange(checkID string, r int64) []Measurement {
	now := time.Now()
	from := now.Unix() - r

	return getMeasurementsFrom(checkID, from)
}

func getMeasurementsFrom(checkID string, from int64) []Measurement {
	vals, err := client.ZRevRangeByScore(getRedisKey(checkID), redis.ZRangeByScore{
		Min: strconv.FormatInt(from, 10),
		Max: "+inf",
	}).Result()

	if err != nil {
		panic(err)
	}

	measurements := make([]Measurement, 0, 100)

	for _, v := range vals {
		var m Measurement
		json.Unmarshal([]byte(v), &m)
		measurements = append(measurements, m)
	}

	return measurements
}

func getFormValueWithDefault(req *http.Request, key string, def string) string {
	s := req.FormValue(key)
	if s != "" {
		return s
	}
	return def
}

func connectToRedis(config Config) {
	u, err := url.Parse(config.RedisURL)
	if err != nil {
		panic(err)
	}

	client = redis.NewTCPClient(&redis.Options{
		Addr:     u.Host,
		Password: "", // no password set
		DB:       0,  // use default DB
	})
}

func httpServer(config Config) {
	t := metrics.NewTimer()
	metrics.Register("canaryd.get_measurements", t)

	h := func(res http.ResponseWriter, req *http.Request) {
		t.Time(func() {
			vars := mux.Vars(req)
			checkID := vars["check_id"]
			rS := getFormValueWithDefault(req, "range", "10")

			r, err := strconv.ParseInt(rS, 10, 64)
			if err != nil {
				panic(nil)
			}
			log.Printf("fn=getMeasurements ip=%s range=%d\n", req.RemoteAddr, r)
			res.Header().Set("Access-Control-Allow-Origin", "*")
			res.Header().Set("Access-Control-Allow-Methods", "GET")
			res.Header().Set("Content-Type", "application/json")
			json.NewEncoder(res).Encode(getMeasurementsByRange(checkID, r))
		})
	}

	r := mux.NewRouter()
	r.HandleFunc("/checks/{check_id}/measurements", h).Methods("GET")
	http.Handle("/", r)

	log.Printf("fn=main listening=true port=%s\n", config.Port)

	err := http.ListenAndServe(":"+config.Port, nil)
	if err != nil {
		panic(err)
	}
}

func ingest(url string, toRecorder chan Measurement) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.StatusCode != 200 {
		return errors.New(fmt.Sprintf("fn=ingestor url=%s connect=failed status_code=%d", url, res.StatusCode))
	}

	log.Printf("fn=ingestor url=%s connect=success\n", url)

	rd := bufio.NewReader(res.Body)
	dec := json.NewDecoder(rd)

	for {
		var m Measurement
		err = dec.Decode(&m)
		if err != nil {
			return err
		}
		toRecorder <- m
	}
}

func ingestor(url string, toRecorder chan Measurement) {
	for {
		err := ingest(url, toRecorder)
		log.Println(err)
		time.Sleep(1000 * time.Millisecond)
	}
}

func recorder(config Config, toRecorder chan Measurement) {
	recordTimer := metrics.NewTimer()
	metrics.Register("canaryd.record", recordTimer)

	trimTimer := metrics.NewTimer()
	metrics.Register("canaryd.trim", trimTimer)

	for {
		m := <-toRecorder
		recordTimer.Time(func() { m.record() })
		trimTimer.Time(func() { trimMeasurements(m.Check.ID, config.Retention) })
	}
}

func init() {
	flag.StringVar(&config.Port, "port", "5000", "port the HTTP server should bind to")
	flag.StringVar(&config.RedisURL, "redis_url", "redis://localhost:6379", "redis url")
	flag.Int64Var(&config.Retention, "retention", 60, "second of each measurement to keep")
	flag.Var(&config.SensordURLs, "sensord_url", "List of sensors")

	config.LibratoEmail = os.Getenv("LIBRATO_EMAIL")
	config.LibratoToken = os.Getenv("LIBRATO_TOKEN")
	config.LibratoSource = os.Getenv("LIBRATO_SOURCE")
}

func main() {
	flag.Parse()

	toRecorder := make(chan Measurement)

	if config.LibratoEmail != "" && config.LibratoToken != "" && config.LibratoSource != "" {
		log.Println("fn=main metircs=librato")
		go librato.Librato(metrics.DefaultRegistry,
			10e9,                  // interval
			config.LibratoEmail,   // account owner email address
			config.LibratoToken,   // Librato API token
			config.LibratoSource,  // source
			[]float64{50, 95, 99}, // precentiles to send
			time.Millisecond,      // time unit
		)
	}

	connectToRedis(config)

	go httpServer(config)
	go recorder(config, toRecorder)

	for _, url := range config.SensordURLs {
		go ingestor(url, toRecorder)
	}

	select {}
}
<|endoftext|>


<commit_before>package socks5

import (
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"time"
)

const (
	ConnectCommand   = uint8(1)
	BindCommand      = uint8(2)
	AssociateCommand = uint8(3)
	ipv4Address      = uint8(1)
	fqdnAddress      = uint8(3)
	ipv6Address      = uint8(4)
)

const (
	successReply uint8 = iota
	serverFailure
	ruleFailure
	networkUnreachable
	hostUnreachable
	connectionRefused
	ttlExpired
	commandNotSupported
	addrTypeNotSupported
)

var (
	unrecognizedAddrType = fmt.Errorf("Unrecognized address type")
)

// AddressRewriter is used to rewrite a destination transparently
type AddressRewriter interface {
	Rewrite(request *Request) *AddrSpec
}

// AddrSpec is used to return the target AddrSpec
// which may be specified as IPv4, IPv6, or a FQDN
type AddrSpec struct {
	FQDN string
	IP   net.IP
	Port int
}

func (a *AddrSpec) String() string {
	if a.FQDN != "" {
		return fmt.Sprintf("%s (%s):%d", a.FQDN, a.IP, a.Port)
	}
	return fmt.Sprintf("%s:%d", a.IP, a.Port)
}

// A Request represents request received by a server
type Request struct {
	// Protocol version
	Version uint8
	// Requested command
	Command uint8
	// AuthContext provided during negotiation
	AuthContext *AuthContext
	// AddrSpec of the the network that sent the request
	RemoteAddr *AddrSpec
	// AddrSpec of the desired destination
	DestAddr *AddrSpec
	// AddrSpec of the actual destination (might be affected by rewrite)
	realDestAddr *AddrSpec
	bufConn      io.Reader
}

type conn interface {
	Write([]byte) (int, error)
	RemoteAddr() net.Addr
}

// NewRequest creates a new Request from the tcp connection
func NewRequest(bufConn io.Reader) (*Request, error) {
	// Read the version byte
	header := []byte{0, 0, 0}
	if _, err := io.ReadAtLeast(bufConn, header, 3); err != nil {
		return nil, fmt.Errorf("Failed to get command version: %v", err)
	}

	// Ensure we are compatible
	if header[0] != socks5Version {
		return nil, fmt.Errorf("Unsupported command version: %v", header[0])
	}

	// Read in the destination address
	dest, err := readAddrSpec(bufConn)
	if err != nil {
		return nil, err
	}

	request := &Request{
		Version:  socks5Version,
		Command:  header[1],
		DestAddr: dest,
		bufConn:  bufConn,
	}

	return request, nil
}

// handleRequest is used for request processing after authentication
func (s *Server) handleRequest(req *Request, conn conn) error {
	// Resolve the address if we have a FQDN
	dest := req.DestAddr
	if dest.FQDN != "" {
		addr, err := s.config.Resolver.Resolve(dest.FQDN)
		if err != nil {
			if err := sendReply(conn, hostUnreachable, nil); err != nil {
				return fmt.Errorf("Failed to send reply: %v", err)
			}
			return fmt.Errorf("Failed to resolve destination '%v': %v", dest.FQDN, err)
		}
		dest.IP = addr
	}

	// Apply any address rewrites
	req.realDestAddr = req.DestAddr
	if s.config.Rewriter != nil {
		req.realDestAddr = s.config.Rewriter.Rewrite(req)
	}

	// Switch on the command
	switch req.Command {
	case ConnectCommand:
		return s.handleConnect(conn, req)
	case BindCommand:
		return s.handleBind(conn, req)
	case AssociateCommand:
		return s.handleAssociate(conn, req)
	default:
		if err := sendReply(conn, commandNotSupported, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Unsupported command: %v", req.Command)
	}
}

// handleConnect is used to handle a connect command
func (s *Server) handleConnect(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Connect to %v blocked by rules", req.DestAddr)
	}

	// Attempt to connect
	addr := fmt.Sprintf("%v:%d", req.realDestAddr.IP, req.realDestAddr.Port)
	dial := s.config.Dial
	if dial == nil {
		dial = net.Dial
	}
	target, err := dial("tcp", addr)
	if err != nil {
		msg := err.Error()
		resp := hostUnreachable
		if strings.Contains(msg, "refused") {
			resp = connectionRefused
		} else if strings.Contains(msg, "network is unreachable") {
			resp = networkUnreachable
		}
		if err := sendReply(conn, resp, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Connect to %v failed: %v", req.DestAddr, err)
	}
	defer target.Close()

	// Send success
	local := target.LocalAddr().(*net.TCPAddr)
	bind := AddrSpec{IP: local.IP, Port: local.Port}
	if err := sendReply(conn, successReply, &bind); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}

	// Start proxying
	errCh := make(chan error, 2)
	go proxy("target", target, req.bufConn, errCh, s.config.Logger)
	go proxy("client", conn, target, errCh, s.config.Logger)

	// Wait
	select {
	case e := <-errCh:
		return e
	}
}

// handleBind is used to handle a connect command
func (s *Server) handleBind(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Bind to %v blocked by rules", req.DestAddr)
	}

	// TODO: Support bind
	if err := sendReply(conn, commandNotSupported, nil); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}
	return nil
}

// handleAssociate is used to handle a connect command
func (s *Server) handleAssociate(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Associate to %v blocked by rules", req.DestAddr)
	}

	// TODO: Support associate
	if err := sendReply(conn, commandNotSupported, nil); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}
	return nil
}

// readAddrSpec is used to read AddrSpec.
// Expects an address type byte, follwed by the address and port
func readAddrSpec(r io.Reader) (*AddrSpec, error) {
	d := &AddrSpec{}

	// Get the address type
	addrType := []byte{0}
	if _, err := r.Read(addrType); err != nil {
		return nil, err
	}

	// Handle on a per type basis
	switch addrType[0] {
	case ipv4Address:
		addr := make([]byte, 4)
		if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
			return nil, err
		}
		d.IP = net.IP(addr)

	case ipv6Address:
		addr := make([]byte, 16)
		if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
			return nil, err
		}
		d.IP = net.IP(addr)

	case fqdnAddress:
		if _, err := r.Read(addrType); err != nil {
			return nil, err
		}
		addrLen := int(addrType[0])
		fqdn := make([]byte, addrLen)
		if _, err := io.ReadAtLeast(r, fqdn, addrLen); err != nil {
			return nil, err
		}
		d.FQDN = string(fqdn)

	default:
		return nil, unrecognizedAddrType
	}

	// Read the port
	port := []byte{0, 0}
	if _, err := io.ReadAtLeast(r, port, 2); err != nil {
		return nil, err
	}
	d.Port = (int(port[0]) << 8) | int(port[1])

	return d, nil
}

// sendReply is used to send a reply message
func sendReply(w io.Writer, resp uint8, addr *AddrSpec) error {
	// Format the address
	var addrType uint8
	var addrBody []byte
	var addrPort uint16
	switch {
	case addr == nil:
		addrType = ipv4Address
		addrBody = []byte{0, 0, 0, 0}
		addrPort = 0

	case addr.FQDN != "":
		addrType = fqdnAddress
		addrBody = append([]byte{byte(len(addr.FQDN))}, addr.FQDN...)
		addrPort = uint16(addr.Port)

	case addr.IP.To4() != nil:
		addrType = ipv4Address
		addrBody = []byte(addr.IP.To4())
		addrPort = uint16(addr.Port)

	case addr.IP.To16() != nil:
		addrType = ipv6Address
		addrBody = []byte(addr.IP.To16())
		addrPort = uint16(addr.Port)

	default:
		return fmt.Errorf("Failed to format address: %v", addr)
	}

	// Format the message
	msg := make([]byte, 6+len(addrBody))
	msg[0] = socks5Version
	msg[1] = resp
	msg[2] = 0 // Reserved
	msg[3] = addrType
	copy(msg[4:], addrBody)
	msg[4+len(addrBody)] = byte(addrPort >> 8)
	msg[4+len(addrBody)+1] = byte(addrPort & 0xff)

	// Send the message
	_, err := w.Write(msg)
	return err
}

// proxy is used to suffle data from src to destination, and sends errors
// down a dedicated channel
func proxy(name string, dst io.Writer, src io.Reader, errCh chan error, logger *log.Logger) {
	// Copy
	n, err := io.Copy(dst, src)

	// Log, and sleep. This is jank but allows the otherside
	// to finish a pending copy
	logger.Printf("[DEBUG] socks: Copied %d bytes to %s", n, name)
	time.Sleep(10 * time.Millisecond)

	// Send any errors
	errCh <- err
}
<commit_msg>Cleaned up address construction<commit_after>package socks5

import (
	"fmt"
	"io"
	"log"
	"net"
	"strings"
	"time"
)

const (
	ConnectCommand   = uint8(1)
	BindCommand      = uint8(2)
	AssociateCommand = uint8(3)
	ipv4Address      = uint8(1)
	fqdnAddress      = uint8(3)
	ipv6Address      = uint8(4)
)

const (
	successReply uint8 = iota
	serverFailure
	ruleFailure
	networkUnreachable
	hostUnreachable
	connectionRefused
	ttlExpired
	commandNotSupported
	addrTypeNotSupported
)

var (
	unrecognizedAddrType = fmt.Errorf("Unrecognized address type")
)

// AddressRewriter is used to rewrite a destination transparently
type AddressRewriter interface {
	Rewrite(request *Request) *AddrSpec
}

// AddrSpec is used to return the target AddrSpec
// which may be specified as IPv4, IPv6, or a FQDN
type AddrSpec struct {
	FQDN string
	IP   net.IP
	Port int
}

func (a *AddrSpec) String() string {
	if a.FQDN != "" {
		return fmt.Sprintf("%s (%s):%d", a.FQDN, a.IP, a.Port)
	}
	return fmt.Sprintf("%s:%d", a.IP, a.Port)
}

// A Request represents request received by a server
type Request struct {
	// Protocol version
	Version uint8
	// Requested command
	Command uint8
	// AuthContext provided during negotiation
	AuthContext *AuthContext
	// AddrSpec of the the network that sent the request
	RemoteAddr *AddrSpec
	// AddrSpec of the desired destination
	DestAddr *AddrSpec
	// AddrSpec of the actual destination (might be affected by rewrite)
	realDestAddr *AddrSpec
	bufConn      io.Reader
}

type conn interface {
	Write([]byte) (int, error)
	RemoteAddr() net.Addr
}

// NewRequest creates a new Request from the tcp connection
func NewRequest(bufConn io.Reader) (*Request, error) {
	// Read the version byte
	header := []byte{0, 0, 0}
	if _, err := io.ReadAtLeast(bufConn, header, 3); err != nil {
		return nil, fmt.Errorf("Failed to get command version: %v", err)
	}

	// Ensure we are compatible
	if header[0] != socks5Version {
		return nil, fmt.Errorf("Unsupported command version: %v", header[0])
	}

	// Read in the destination address
	dest, err := readAddrSpec(bufConn)
	if err != nil {
		return nil, err
	}

	request := &Request{
		Version:  socks5Version,
		Command:  header[1],
		DestAddr: dest,
		bufConn:  bufConn,
	}

	return request, nil
}

// handleRequest is used for request processing after authentication
func (s *Server) handleRequest(req *Request, conn conn) error {
	// Resolve the address if we have a FQDN
	dest := req.DestAddr
	if dest.FQDN != "" {
		addr, err := s.config.Resolver.Resolve(dest.FQDN)
		if err != nil {
			if err := sendReply(conn, hostUnreachable, nil); err != nil {
				return fmt.Errorf("Failed to send reply: %v", err)
			}
			return fmt.Errorf("Failed to resolve destination '%v': %v", dest.FQDN, err)
		}
		dest.IP = addr
	}

	// Apply any address rewrites
	req.realDestAddr = req.DestAddr
	if s.config.Rewriter != nil {
		req.realDestAddr = s.config.Rewriter.Rewrite(req)
	}

	// Switch on the command
	switch req.Command {
	case ConnectCommand:
		return s.handleConnect(conn, req)
	case BindCommand:
		return s.handleBind(conn, req)
	case AssociateCommand:
		return s.handleAssociate(conn, req)
	default:
		if err := sendReply(conn, commandNotSupported, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Unsupported command: %v", req.Command)
	}
}

// handleConnect is used to handle a connect command
func (s *Server) handleConnect(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Connect to %v blocked by rules", req.DestAddr)
	}

	// Attempt to connect
	addr := (&net.TCPAddr{IP: req.realDestAddr.IP, Port: req.realDestAddr.Port}).String()
	dial := s.config.Dial
	if dial == nil {
		dial = net.Dial
	}
	target, err := dial("tcp", addr)
	if err != nil {
		msg := err.Error()
		resp := hostUnreachable
		if strings.Contains(msg, "refused") {
			resp = connectionRefused
		} else if strings.Contains(msg, "network is unreachable") {
			resp = networkUnreachable
		}
		if err := sendReply(conn, resp, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Connect to %v failed: %v", req.DestAddr, err)
	}
	defer target.Close()

	// Send success
	local := target.LocalAddr().(*net.TCPAddr)
	bind := AddrSpec{IP: local.IP, Port: local.Port}
	if err := sendReply(conn, successReply, &bind); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}

	// Start proxying
	errCh := make(chan error, 2)
	go proxy("target", target, req.bufConn, errCh, s.config.Logger)
	go proxy("client", conn, target, errCh, s.config.Logger)

	// Wait
	select {
	case e := <-errCh:
		return e
	}
}

// handleBind is used to handle a connect command
func (s *Server) handleBind(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Bind to %v blocked by rules", req.DestAddr)
	}

	// TODO: Support bind
	if err := sendReply(conn, commandNotSupported, nil); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}
	return nil
}

// handleAssociate is used to handle a connect command
func (s *Server) handleAssociate(conn conn, req *Request) error {
	// Check if this is allowed
	if !s.config.Rules.Allow(req) {
		if err := sendReply(conn, ruleFailure, nil); err != nil {
			return fmt.Errorf("Failed to send reply: %v", err)
		}
		return fmt.Errorf("Associate to %v blocked by rules", req.DestAddr)
	}

	// TODO: Support associate
	if err := sendReply(conn, commandNotSupported, nil); err != nil {
		return fmt.Errorf("Failed to send reply: %v", err)
	}
	return nil
}

// readAddrSpec is used to read AddrSpec.
// Expects an address type byte, follwed by the address and port
func readAddrSpec(r io.Reader) (*AddrSpec, error) {
	d := &AddrSpec{}

	// Get the address type
	addrType := []byte{0}
	if _, err := r.Read(addrType); err != nil {
		return nil, err
	}

	// Handle on a per type basis
	switch addrType[0] {
	case ipv4Address:
		addr := make([]byte, 4)
		if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
			return nil, err
		}
		d.IP = net.IP(addr)

	case ipv6Address:
		addr := make([]byte, 16)
		if _, err := io.ReadAtLeast(r, addr, len(addr)); err != nil {
			return nil, err
		}
		d.IP = net.IP(addr)

	case fqdnAddress:
		if _, err := r.Read(addrType); err != nil {
			return nil, err
		}
		addrLen := int(addrType[0])
		fqdn := make([]byte, addrLen)
		if _, err := io.ReadAtLeast(r, fqdn, addrLen); err != nil {
			return nil, err
		}
		d.FQDN = string(fqdn)

	default:
		return nil, unrecognizedAddrType
	}

	// Read the port
	port := []byte{0, 0}
	if _, err := io.ReadAtLeast(r, port, 2); err != nil {
		return nil, err
	}
	d.Port = (int(port[0]) << 8) | int(port[1])

	return d, nil
}

// sendReply is used to send a reply message
func sendReply(w io.Writer, resp uint8, addr *AddrSpec) error {
	// Format the address
	var addrType uint8
	var addrBody []byte
	var addrPort uint16
	switch {
	case addr == nil:
		addrType = ipv4Address
		addrBody = []byte{0, 0, 0, 0}
		addrPort = 0

	case addr.FQDN != "":
		addrType = fqdnAddress
		addrBody = append([]byte{byte(len(addr.FQDN))}, addr.FQDN...)
		addrPort = uint16(addr.Port)

	case addr.IP.To4() != nil:
		addrType = ipv4Address
		addrBody = []byte(addr.IP.To4())
		addrPort = uint16(addr.Port)

	case addr.IP.To16() != nil:
		addrType = ipv6Address
		addrBody = []byte(addr.IP.To16())
		addrPort = uint16(addr.Port)

	default:
		return fmt.Errorf("Failed to format address: %v", addr)
	}

	// Format the message
	msg := make([]byte, 6+len(addrBody))
	msg[0] = socks5Version
	msg[1] = resp
	msg[2] = 0 // Reserved
	msg[3] = addrType
	copy(msg[4:], addrBody)
	msg[4+len(addrBody)] = byte(addrPort >> 8)
	msg[4+len(addrBody)+1] = byte(addrPort & 0xff)

	// Send the message
	_, err := w.Write(msg)
	return err
}

// proxy is used to suffle data from src to destination, and sends errors
// down a dedicated channel
func proxy(name string, dst io.Writer, src io.Reader, errCh chan error, logger *log.Logger) {
	// Copy
	n, err := io.Copy(dst, src)

	// Log, and sleep. This is jank but allows the otherside
	// to finish a pending copy
	logger.Printf("[DEBUG] socks: Copied %d bytes to %s", n, name)
	time.Sleep(10 * time.Millisecond)

	// Send any errors
	errCh <- err
}
<|endoftext|>


<commit_before>package sarama

import (
	"encoding/binary"
	"fmt"
	"io"
)

type protocolBody interface {
	encoder
	versionedDecoder
	key() int16
	version() int16
	requiredVersion() KafkaVersion
}

type request struct {
	correlationID int32
	clientID      string
	body          protocolBody
}

func (r *request) encode(pe packetEncoder) (err error) {
	pe.push(&lengthField{})
	pe.putInt16(r.body.key())
	pe.putInt16(r.body.version())
	pe.putInt32(r.correlationID)
	err = pe.putString(r.clientID)
	if err != nil {
		return err
	}
	err = r.body.encode(pe)
	if err != nil {
		return err
	}
	return pe.pop()
}

func (r *request) decode(pd packetDecoder) (err error) {
	var key int16
	if key, err = pd.getInt16(); err != nil {
		return err
	}
	var version int16
	if version, err = pd.getInt16(); err != nil {
		return err
	}
	if r.correlationID, err = pd.getInt32(); err != nil {
		return err
	}
	r.clientID, err = pd.getString()

	r.body = allocateBody(key, version)
	if r.body == nil {
		return PacketDecodingError{fmt.Sprintf("unknown request key (%d)", key)}
	}
	return r.body.decode(pd, version)
}

func decodeRequest(r io.Reader) (req *request, bytesRead int, err error) {
	lengthBytes := make([]byte, 4)
	if _, err := io.ReadFull(r, lengthBytes); err != nil {
		return nil, bytesRead, err
	}
	bytesRead += len(lengthBytes)

	length := int32(binary.BigEndian.Uint32(lengthBytes))
	if length <= 4 || length > MaxRequestSize {
		return nil, bytesRead, PacketDecodingError{fmt.Sprintf("message of length %d too large or too small", length)}
	}

	encodedReq := make([]byte, length)
	if _, err := io.ReadFull(r, encodedReq); err != nil {
		return nil, bytesRead, err
	}
	bytesRead += len(encodedReq)

	req = &request{}
	if err := decode(encodedReq, req); err != nil {
		return nil, bytesRead, err
	}
	return req, bytesRead, nil
}

const apiKeyProduce = 0
const apiKeyFetch = 1
const apiKeyListOffsets = 2
const apiKeyMetadata = 3
const apiKeyOffsetCommit = 8
const apiKeyOffsetFetch = 9
const apiKeyFindCoordinator = 10
const apiKeyJoinGroup = 11
const apiKeyHeartbeat = 12
const apiKeyLeaveGroup = 13
const apiKeySyncGroup = 14
const apiKeyDescribeGroups = 15
const apiKeyListGroups = 16
const apiKeySaslHandshake = 17
const apiKeyApiVersions = 18

func allocateBody(key, version int16) protocolBody {
	switch key {
	case apiKeyProduce:
		return &ProduceRequest{}
	case apiKeyFetch:
		return &FetchRequest{}
	case apiKeyListOffsets:
		return &OffsetRequest{Version: version}
	case apiKeyMetadata:
		return &MetadataRequest{}
	case apiKeyOffsetCommit:
		return &OffsetCommitRequest{Version: version}
	case apiKeyOffsetFetch:
		return &OffsetFetchRequest{}
	case apiKeyFindCoordinator:
		return &FindCoordinatorRequest{}
	case apiKeyJoinGroup:
		return &JoinGroupRequest{}
	case apiKeyHeartbeat:
		return &HeartbeatRequest{}
	case apiKeyLeaveGroup:
		return &LeaveGroupRequest{}
	case apiKeySyncGroup:
		return &SyncGroupRequest{}
	case apiKeyDescribeGroups:
		return &DescribeGroupsRequest{}
	case apiKeyListGroups:
		return &ListGroupsRequest{}
	case apiKeySaslHandshake:
		return &SaslHandshakeRequest{}
	case apiKeyApiVersions:
		return &ApiVersionsRequest{}
	case 19:
		return &CreateTopicsRequest{}
	case 20:
		return &DeleteTopicsRequest{}
	case 21:
		return &DeleteRecordsRequest{}
	case 22:
		return &InitProducerIDRequest{}
	case 24:
		return &AddPartitionsToTxnRequest{}
	case 25:
		return &AddOffsetsToTxnRequest{}
	case 26:
		return &EndTxnRequest{}
	case 28:
		return &TxnOffsetCommitRequest{}
	case 29:
		return &DescribeAclsRequest{}
	case 30:
		return &CreateAclsRequest{}
	case 31:
		return &DeleteAclsRequest{}
	case 32:
		return &DescribeConfigsRequest{}
	case 33:
		return &AlterConfigsRequest{}
	case 37:
		return &CreatePartitionsRequest{}
	}
	return nil
}
<commit_msg>use one const block for api keys<commit_after>package sarama

import (
	"encoding/binary"
	"fmt"
	"io"
)

type protocolBody interface {
	encoder
	versionedDecoder
	key() int16
	version() int16
	requiredVersion() KafkaVersion
}

type request struct {
	correlationID int32
	clientID      string
	body          protocolBody
}

func (r *request) encode(pe packetEncoder) (err error) {
	pe.push(&lengthField{})
	pe.putInt16(r.body.key())
	pe.putInt16(r.body.version())
	pe.putInt32(r.correlationID)
	err = pe.putString(r.clientID)
	if err != nil {
		return err
	}
	err = r.body.encode(pe)
	if err != nil {
		return err
	}
	return pe.pop()
}

func (r *request) decode(pd packetDecoder) (err error) {
	var key int16
	if key, err = pd.getInt16(); err != nil {
		return err
	}
	var version int16
	if version, err = pd.getInt16(); err != nil {
		return err
	}
	if r.correlationID, err = pd.getInt32(); err != nil {
		return err
	}
	r.clientID, err = pd.getString()

	r.body = allocateBody(key, version)
	if r.body == nil {
		return PacketDecodingError{fmt.Sprintf("unknown request key (%d)", key)}
	}
	return r.body.decode(pd, version)
}

func decodeRequest(r io.Reader) (req *request, bytesRead int, err error) {
	lengthBytes := make([]byte, 4)
	if _, err := io.ReadFull(r, lengthBytes); err != nil {
		return nil, bytesRead, err
	}
	bytesRead += len(lengthBytes)

	length := int32(binary.BigEndian.Uint32(lengthBytes))
	if length <= 4 || length > MaxRequestSize {
		return nil, bytesRead, PacketDecodingError{fmt.Sprintf("message of length %d too large or too small", length)}
	}

	encodedReq := make([]byte, length)
	if _, err := io.ReadFull(r, encodedReq); err != nil {
		return nil, bytesRead, err
	}
	bytesRead += len(encodedReq)

	req = &request{}
	if err := decode(encodedReq, req); err != nil {
		return nil, bytesRead, err
	}
	return req, bytesRead, nil
}

const (
	apiKeyProduce         = 0
	apiKeyFetch           = 1
	apiKeyListOffsets     = 2
	apiKeyMetadata        = 3
	apiKeyOffsetCommit    = 8
	apiKeyOffsetFetch     = 9
	apiKeyFindCoordinator = 10
	apiKeyJoinGroup       = 11
	apiKeyHeartbeat       = 12
	apiKeyLeaveGroup      = 13
	apiKeySyncGroup       = 14
	apiKeyDescribeGroups  = 15
	apiKeyListGroups      = 16
	apiKeySaslHandshake   = 17
	apiKeyApiVersions     = 18
)

func allocateBody(key, version int16) protocolBody {
	switch key {
	case apiKeyProduce:
		return &ProduceRequest{}
	case apiKeyFetch:
		return &FetchRequest{}
	case apiKeyListOffsets:
		return &OffsetRequest{Version: version}
	case apiKeyMetadata:
		return &MetadataRequest{}
	case apiKeyOffsetCommit:
		return &OffsetCommitRequest{Version: version}
	case apiKeyOffsetFetch:
		return &OffsetFetchRequest{}
	case apiKeyFindCoordinator:
		return &FindCoordinatorRequest{}
	case apiKeyJoinGroup:
		return &JoinGroupRequest{}
	case apiKeyHeartbeat:
		return &HeartbeatRequest{}
	case apiKeyLeaveGroup:
		return &LeaveGroupRequest{}
	case apiKeySyncGroup:
		return &SyncGroupRequest{}
	case apiKeyDescribeGroups:
		return &DescribeGroupsRequest{}
	case apiKeyListGroups:
		return &ListGroupsRequest{}
	case apiKeySaslHandshake:
		return &SaslHandshakeRequest{}
	case apiKeyApiVersions:
		return &ApiVersionsRequest{}
	case 19:
		return &CreateTopicsRequest{}
	case 20:
		return &DeleteTopicsRequest{}
	case 21:
		return &DeleteRecordsRequest{}
	case 22:
		return &InitProducerIDRequest{}
	case 24:
		return &AddPartitionsToTxnRequest{}
	case 25:
		return &AddOffsetsToTxnRequest{}
	case 26:
		return &EndTxnRequest{}
	case 28:
		return &TxnOffsetCommitRequest{}
	case 29:
		return &DescribeAclsRequest{}
	case 30:
		return &CreateAclsRequest{}
	case 31:
		return &DeleteAclsRequest{}
	case 32:
		return &DescribeConfigsRequest{}
	case 33:
		return &AlterConfigsRequest{}
	case 37:
		return &CreatePartitionsRequest{}
	}
	return nil
}
<|endoftext|>


<commit_before>package kafka

type requestAPI interface {
	key() int16
	version() int16
	expectResponse() bool
}

type requestEncoder interface {
	encoder
	requestAPI
}

type request struct {
	correlation_id int32
	id             *string
	body           requestEncoder
}

func (r *request) encode(pe packetEncoder) {
	pe.pushLength32()
	pe.putInt16(r.body.key())
	pe.putInt16(r.body.version())
	pe.putInt32(r.correlation_id)
	pe.putString(r.id)
	r.body.encode(pe)
	pe.pop()
}
<commit_msg>Simply interfaces slightly<commit_after>package kafka

type requestEncoder interface {
	encoder
	key() int16
	version() int16
	expectResponse() bool
}

type request struct {
	correlation_id int32
	id             *string
	body           requestEncoder
}

func (r *request) encode(pe packetEncoder) {
	pe.pushLength32()
	pe.putInt16(r.body.key())
	pe.putInt16(r.body.version())
	pe.putInt32(r.correlation_id)
	pe.putString(r.id)
	r.body.encode(pe)
	pe.pop()
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/franela/goreq"
)

func init() {
	goreq.SetConnectTimeout(15 * time.Second)
	goreq.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{RootCAs: getCACerts()}
}

func apiRequestBase(authToken string) *goreq.Request {
	req := goreq.Request{
		Uri:       apiURL(),
		ShowDebug: debugging,
		Insecure:  !shouldVerifyHost(apiURL()),
	}
	if authToken != "" {
		req.AddHeader("Authorization", "Bearer "+authToken)
	}
	if os.Getenv("HEROKU_HEADERS") != "" {
		var h map[string]string
		json.Unmarshal([]byte(os.Getenv("HEROKU_HEADERS")), &h)
		for k, v := range h {
			req.AddHeader(k, v)
		}
	}
	return &req
}

func apiRequest(authToken string) *goreq.Request {
	req := apiRequestBase(authToken)
	req.AddHeader("Accept", "application/vnd.heroku+json; version=3")
	return req
}

func shouldVerifyHost(host string) bool {
	return !strings.HasSuffix(host, "herokudev.com")
}

func getCACerts() *x509.CertPool {
	certs := x509.NewCertPool()
	path := filepath.Join(AppDir(), "cacert.pem")
	data, err := ioutil.ReadFile(path)
	if err != nil {
		downloadCert(path)
		data, err = ioutil.ReadFile(path)
		if err != nil {
			PrintError(err)
			return nil
		}
	}
	ok := certs.AppendCertsFromPEM(data)
	if !ok {
		Warn("Error parsing " + path)
		return nil
	}
	return certs
}

func downloadCert(path string) {
	f, err := os.Create(path)
	if err != nil {
		PrintError(err)
		return
	}
	res, err := goreq.Request{
		Uri:       "https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		PrintError(err)
		return
	}
	defer res.Body.Close()
	defer f.Close()
	io.Copy(f, res.Body)
}
<commit_msg>use HEROKU_SSL_VERIFY env var<commit_after>package main

import (
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/franela/goreq"
)

func init() {
	goreq.SetConnectTimeout(15 * time.Second)
	goreq.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{RootCAs: getCACerts()}
}

func apiRequestBase(authToken string) *goreq.Request {
	req := goreq.Request{
		Uri:       apiURL(),
		ShowDebug: debugging,
		Insecure:  !shouldVerifyHost(apiURL()),
	}
	if authToken != "" {
		req.AddHeader("Authorization", "Bearer "+authToken)
	}
	if os.Getenv("HEROKU_HEADERS") != "" {
		var h map[string]string
		json.Unmarshal([]byte(os.Getenv("HEROKU_HEADERS")), &h)
		for k, v := range h {
			req.AddHeader(k, v)
		}
	}
	return &req
}

func apiRequest(authToken string) *goreq.Request {
	req := apiRequestBase(authToken)
	req.AddHeader("Accept", "application/vnd.heroku+json; version=3")
	return req
}

func shouldVerifyHost(host string) bool {
	return !(os.Getenv("HEROKU_SSL_VERIFY") == "disable" || strings.HasSuffix(host, "herokudev.com"))
}

func getCACerts() *x509.CertPool {
	certs := x509.NewCertPool()
	path := filepath.Join(AppDir(), "cacert.pem")
	data, err := ioutil.ReadFile(path)
	if err != nil {
		downloadCert(path)
		data, err = ioutil.ReadFile(path)
		if err != nil {
			PrintError(err)
			return nil
		}
	}
	ok := certs.AppendCertsFromPEM(data)
	if !ok {
		Warn("Error parsing " + path)
		return nil
	}
	return certs
}

func downloadCert(path string) {
	f, err := os.Create(path)
	if err != nil {
		PrintError(err)
		return
	}
	res, err := goreq.Request{
		Uri:       "https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt",
		ShowDebug: debugging,
	}.Do()
	if err != nil {
		PrintError(err)
		return
	}
	defer res.Body.Close()
	defer f.Close()
	io.Copy(f, res.Body)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"net/url"
	"strings"
)

type errorRedirectRequest interface {
	// 処理後に飛ばすリダイレクト先 URI を返す。
	redirectUri() *url.URL
}

// ブラウザからのリクエスト。
type browserRequest struct {
	sess string
}

func newBrowserRequest(r *http.Request) *browserRequest {
	var sess string
	if cook, err := r.Cookie(cookSess); err != nil {
		if err != http.ErrNoCookie {
			err = erro.Wrap(err)
			log.Err(erro.Unwrap(err))
			log.Debug(err)
		}
	} else {
		sess = cook.Value
	}
	return &browserRequest{sess: sess}
}

func (this *browserRequest) session() string {
	return this.sess
}

// スペース区切りのフォーム値を集合にして返す。
func formValueSet(r *http.Request, key string) map[string]bool {
	s := r.FormValue(key)
	set := map[string]bool{}
	for _, v := range strings.Split(s, " ") {
		set[v] = true
	}
	return set
}

// フォーム値用にスペース区切りにして返す。
func valueSetToForm(v map[string]bool) string {
	buff := ""
	for v, ok := range v {
		if !ok || v == "" {
			continue
		}

		if len(buff) > 0 {
			buff += " "
		}
		buff += v
	}
	return buff
}
<commit_msg>要らないインターフェースを削除<commit_after>package main

import (
	"github.com/realglobe-Inc/go-lib-rg/erro"
	"net/http"
	"strings"
)

// ブラウザからのリクエスト。
type browserRequest struct {
	sess string
}

func newBrowserRequest(r *http.Request) *browserRequest {
	var sess string
	if cook, err := r.Cookie(cookSess); err != nil {
		if err != http.ErrNoCookie {
			err = erro.Wrap(err)
			log.Err(erro.Unwrap(err))
			log.Debug(err)
		}
	} else {
		sess = cook.Value
	}
	return &browserRequest{sess: sess}
}

func (this *browserRequest) session() string {
	return this.sess
}

// スペース区切りのフォーム値を集合にして返す。
func formValueSet(r *http.Request, key string) map[string]bool {
	s := r.FormValue(key)
	set := map[string]bool{}
	for _, v := range strings.Split(s, " ") {
		set[v] = true
	}
	return set
}

// フォーム値用にスペース区切りにして返す。
func valueSetToForm(v map[string]bool) string {
	buff := ""
	for v, ok := range v {
		if !ok || v == "" {
			continue
		}

		if len(buff) > 0 {
			buff += " "
		}
		buff += v
	}
	return buff
}
<|endoftext|>


<commit_before>package goes

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Requester implements Request which builds an HTTP request for Elasticsearch
type Requester interface {
	// Request should set the URL and Body (if needed). The host of the URL will be overwritten by the client.
	Request() (*http.Request, error)
}

// Request holds a single request to elasticsearch
type Request struct {
	// A search query
	Query interface{}

	// Which index to search into
	IndexList []string

	// Which type to search into
	TypeList []string

	// HTTP Method to user (GET, POST ...)
	Method string

	// Which api keyword (_search, _bulk, etc) to use
	API string

	// Bulk data
	BulkData []byte

	// Request body
	Body []byte

	// A list of extra URL arguments
	ExtraArgs url.Values

	// Used for the id field when indexing a document
	ID string
}

// URL builds a URL for a Request
func (req *Request) URL() *url.URL {
	var path string
	if len(req.IndexList) > 0 {
		path = "/" + strings.Join(req.IndexList, ",")
	}

	if len(req.TypeList) > 0 {
		path += "/" + strings.Join(req.TypeList, ",")
	}

	// XXX : for indexing documents using the normal (non bulk) API
	if len(req.ID) > 0 {
		path += "/" + req.ID
	}

	path += "/" + req.API

	u := url.URL{
		//Scheme:   "http",
		//Host:     fmt.Sprintf("%s:%s", req.Conn.Host, req.Conn.Port),
		Path:     path,
		RawQuery: req.ExtraArgs.Encode(),
	}

	return &u
}

// Request generates an http.Request based on the contents of the Request struct
func (req *Request) Request() (*http.Request, error) {
	postData := []byte{}

	// XXX : refactor this
	if len(req.Body) > 0 {
		postData = req.Body
	} else if req.API == "_bulk" {
		postData = req.BulkData
	} else {
		b, err := json.Marshal(req.Query)
		if err != nil {
			return nil, err
		}
		postData = b
	}

	reader := ioutil.NopCloser(bytes.NewReader(postData))

	newReq, err := http.NewRequest(req.Method, "", nil)
	if err != nil {
		return nil, err
	}
	newReq.URL = req.URL()
	newReq.Body = reader
	newReq.ContentLength = int64(len(postData))

	if req.Method == "POST" || req.Method == "PUT" {
		newReq.Header.Set("Content-Type", "application/json")
	}
	return newReq, nil
}

var _ Requester = (*Request)(nil)
<commit_msg>If no body is supplied, don't send 'null' as body<commit_after>package goes

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)

// Requester implements Request which builds an HTTP request for Elasticsearch
type Requester interface {
	// Request should set the URL and Body (if needed). The host of the URL will be overwritten by the client.
	Request() (*http.Request, error)
}

// Request holds a single request to elasticsearch
type Request struct {
	// A search query
	Query interface{}

	// Which index to search into
	IndexList []string

	// Which type to search into
	TypeList []string

	// HTTP Method to user (GET, POST ...)
	Method string

	// Which api keyword (_search, _bulk, etc) to use
	API string

	// Bulk data
	BulkData []byte

	// Request body
	Body []byte

	// A list of extra URL arguments
	ExtraArgs url.Values

	// Used for the id field when indexing a document
	ID string
}

// URL builds a URL for a Request
func (req *Request) URL() *url.URL {
	var path string
	if len(req.IndexList) > 0 {
		path = "/" + strings.Join(req.IndexList, ",")
	}

	if len(req.TypeList) > 0 {
		path += "/" + strings.Join(req.TypeList, ",")
	}

	// XXX : for indexing documents using the normal (non bulk) API
	if len(req.ID) > 0 {
		path += "/" + req.ID
	}

	path += "/" + req.API

	u := url.URL{
		//Scheme:   "http",
		//Host:     fmt.Sprintf("%s:%s", req.Conn.Host, req.Conn.Port),
		Path:     path,
		RawQuery: req.ExtraArgs.Encode(),
	}

	return &u
}

// Request generates an http.Request based on the contents of the Request struct
func (req *Request) Request() (*http.Request, error) {
	postData := []byte{}

	// XXX : refactor this
	if len(req.Body) > 0 {
		postData = req.Body
	} else if req.API == "_bulk" {
		postData = req.BulkData
	} else if req.Body != nil {
		b, err := json.Marshal(req.Query)
		if err != nil {
			return nil, err
		}
		postData = b
	}

	newReq, err := http.NewRequest(req.Method, "", nil)
	if err != nil {
		return nil, err
	}
	newReq.URL = req.URL()
	newReq.Body = ioutil.NopCloser(bytes.NewReader(postData))
	newReq.ContentLength = int64(len(postData))

	if req.Method == "POST" || req.Method == "PUT" {
		newReq.Header.Set("Content-Type", "application/json")
	}
	return newReq, nil
}

var _ Requester = (*Request)(nil)
<|endoftext|>


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

// Package captcha a middleware that provides captcha service for Macaron.
package captcha

import (
	"fmt"
	"html/template"
	"path"
	"strings"

	"github.com/Unknwon/com"
	"github.com/go-macaron/cache"
	"gopkg.in/macaron.v1"
)

const _VERSION = "0.1.0"

func Version() string {
	return _VERSION
}

var (
	defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
)

// Captcha represents a captcha service.
type Captcha struct {
	store            cache.Cache
	SubURL           string
	URLPrefix        string
	FieldIdName      string
	FieldCaptchaName string
	StdWidth         int
	StdHeight        int
	ChallengeNums    int
	Expiration       int64
	CachePrefix      string
}

// generate key string
func (c *Captcha) key(id string) string {
	return c.CachePrefix + id
}

// generate rand chars with default chars
func (c *Captcha) genRandChars() string {
	return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
}

// tempalte func for output html
func (c *Captcha) CreateHtml() template.HTML {
	value, err := c.CreateCaptcha()
	if err != nil {
		panic(fmt.Errorf("fail to create captcha: %v", err))
	}
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">

	`, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value))
}

// create a new captcha id
func (c *Captcha) CreateCaptcha() (string, error) {
	id := string(com.RandomCreateBytes(15))
	if err := c.store.Put(c.key(id), c.genRandChars(), c.Expiration); err != nil {
		return "", err
	}
	return id, nil
}

// verify from a request
func (c *Captcha) VerifyReq(req macaron.Request) bool {
	req.ParseForm()
	return c.Verify(req.Form.Get(c.FieldIdName), req.Form.Get(c.FieldCaptchaName))
}

// direct verify id and challenge string
func (c *Captcha) Verify(id string, challenge string) bool {
	if len(challenge) == 0 || len(id) == 0 {
		return false
	}

	var chars string

	key := c.key(id)

	if v, ok := c.store.Get(key).(string); ok {
		chars = v
	} else {
		return false
	}

	defer c.store.Delete(key)

	if len(chars) != len(challenge) {
		return false
	}

	// verify challenge
	for i, c := range []byte(chars) {
		if c != challenge[i]-48 {
			return false
		}
	}

	return true
}

type Options struct {
	// Suburl path. Default is empty.
	SubURL string
	// URL prefix of getting captcha pictures. Default is "/captcha/".
	URLPrefix string
	// Hidden input element ID. Default is "captcha_id".
	FieldIdName string
	// User input value element name in request form. Default is "captcha".
	FieldCaptchaName string
	// Challenge number. Default is 6.
	ChallengeNums int
	// Captcha image width. Default is 240.
	Width int
	// Captcha image height. Default is 80.
	Height int
	// Captcha expiration time in seconds. Default is 600.
	Expiration int64
	// Cache key prefix captcha characters. Default is "captcha_".
	CachePrefix string
}

func prepareOptions(options []Options) Options {
	var opt Options
	if len(options) > 0 {
		opt = options[0]
	}

	opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")

	// Defaults.
	if len(opt.URLPrefix) == 0 {
		opt.URLPrefix = "/captcha/"
	} else if opt.URLPrefix[len(opt.URLPrefix)-1] != '/' {
		opt.URLPrefix += "/"
	}
	if len(opt.FieldIdName) == 0 {
		opt.FieldIdName = "captcha_id"
	}
	if len(opt.FieldCaptchaName) == 0 {
		opt.FieldCaptchaName = "captcha"
	}
	if opt.ChallengeNums == 0 {
		opt.ChallengeNums = 6
	}
	if opt.Width == 0 {
		opt.Width = stdWidth
	}
	if opt.Height == 0 {
		opt.Height = stdHeight
	}
	if opt.Expiration == 0 {
		opt.Expiration = 600
	}
	if len(opt.CachePrefix) == 0 {
		opt.CachePrefix = "captcha_"
	}

	return opt
}

// NewCaptcha initializes and returns a captcha with given options.
func NewCaptcha(opt Options) *Captcha {
	return &Captcha{
		SubURL:           opt.SubURL,
		URLPrefix:        opt.URLPrefix,
		FieldIdName:      opt.FieldIdName,
		FieldCaptchaName: opt.FieldCaptchaName,
		StdWidth:         opt.Width,
		StdHeight:        opt.Height,
		ChallengeNums:    opt.ChallengeNums,
		Expiration:       opt.Expiration,
		CachePrefix:      opt.CachePrefix,
	}
}

// Captchaer is a middleware that maps a captcha.Captcha service into the Macaron handler chain.
// An single variadic captcha.Options struct can be optionally provided to configure.
// This should be register after cache.Cacher.
func Captchaer(options ...Options) macaron.Handler {
	return func(ctx *macaron.Context, cache cache.Cache) {
		cpt := NewCaptcha(prepareOptions(options))
		cpt.store = cache

		if strings.HasPrefix(ctx.Req.URL.Path, cpt.URLPrefix) {
			var chars string
			id := path.Base(ctx.Req.URL.Path)
			if i := strings.Index(id, "."); i > -1 {
				id = id[:i]
			}
			key := cpt.key(id)

			// Reload captcha.
			if len(ctx.Query("reload")) > 0 {
				chars = cpt.genRandChars()
				if err := cpt.store.Put(key, chars, cpt.Expiration); err != nil {
					ctx.Status(500)
					ctx.Write([]byte("captcha reload error"))
					panic(fmt.Errorf("reload captcha: %v", err))
				}
			} else {
				if v, ok := cpt.store.Get(key).(string); ok {
					chars = v
				} else {
					ctx.Status(404)
					ctx.Write([]byte("captcha not found"))
					return
				}
			}

			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil {
				panic(fmt.Errorf("write captcha: %v", err))
			}
			return
		}

		ctx.Data["Captcha"] = cpt
		ctx.Map(cpt)
	}
}
<commit_msg>new CreateHTML method<commit_after>// Copyright 2013 Beego Authors
// Copyright 2014 The Macaron Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

// Package captcha a middleware that provides captcha service for Macaron.
package captcha

import (
	"fmt"
	"html/template"
	"path"
	"strings"

	"github.com/Unknwon/com"
	"github.com/go-macaron/cache"
	"gopkg.in/macaron.v1"
)

const _VERSION = "0.1.0"

func Version() string {
	return _VERSION
}

var (
	defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
)

// Captcha represents a captcha service.
type Captcha struct {
	store            cache.Cache
	SubURL           string
	URLPrefix        string
	FieldIdName      string
	FieldCaptchaName string
	StdWidth         int
	StdHeight        int
	ChallengeNums    int
	Expiration       int64
	CachePrefix      string
}

// generate key string
func (c *Captcha) key(id string) string {
	return c.CachePrefix + id
}

// generate rand chars with default chars
func (c *Captcha) genRandChars() string {
	return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
}

// CreateHTML outputs HTML for display and fetch new captcha images.
func (c *Captcha) CreateHTML() template.HTML {
	value, err := c.CreateCaptcha()
	if err != nil {
		panic(fmt.Errorf("fail to create captcha: %v", err))
	}
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%[1]s" value="%[2]s">

	`, c.FieldIdName, value, c.SubURL, c.URLPrefix))
}

// DEPRECATED
func (c *Captcha) CreateHtml() template.HTML {
	return c.CreateHTML()
}

// create a new captcha id
func (c *Captcha) CreateCaptcha() (string, error) {
	id := string(com.RandomCreateBytes(15))
	if err := c.store.Put(c.key(id), c.genRandChars(), c.Expiration); err != nil {
		return "", err
	}
	return id, nil
}

// verify from a request
func (c *Captcha) VerifyReq(req macaron.Request) bool {
	req.ParseForm()
	return c.Verify(req.Form.Get(c.FieldIdName), req.Form.Get(c.FieldCaptchaName))
}

// direct verify id and challenge string
func (c *Captcha) Verify(id string, challenge string) bool {
	if len(challenge) == 0 || len(id) == 0 {
		return false
	}

	var chars string

	key := c.key(id)

	if v, ok := c.store.Get(key).(string); ok {
		chars = v
	} else {
		return false
	}

	defer c.store.Delete(key)

	if len(chars) != len(challenge) {
		return false
	}

	// verify challenge
	for i, c := range []byte(chars) {
		if c != challenge[i]-48 {
			return false
		}
	}

	return true
}

type Options struct {
	// Suburl path. Default is empty.
	SubURL string
	// URL prefix of getting captcha pictures. Default is "/captcha/".
	URLPrefix string
	// Hidden input element ID. Default is "captcha_id".
	FieldIdName string
	// User input value element name in request form. Default is "captcha".
	FieldCaptchaName string
	// Challenge number. Default is 6.
	ChallengeNums int
	// Captcha image width. Default is 240.
	Width int
	// Captcha image height. Default is 80.
	Height int
	// Captcha expiration time in seconds. Default is 600.
	Expiration int64
	// Cache key prefix captcha characters. Default is "captcha_".
	CachePrefix string
}

func prepareOptions(options []Options) Options {
	var opt Options
	if len(options) > 0 {
		opt = options[0]
	}

	opt.SubURL = strings.TrimSuffix(opt.SubURL, "/")

	// Defaults.
	if len(opt.URLPrefix) == 0 {
		opt.URLPrefix = "/captcha/"
	} else if opt.URLPrefix[len(opt.URLPrefix)-1] != '/' {
		opt.URLPrefix += "/"
	}
	if len(opt.FieldIdName) == 0 {
		opt.FieldIdName = "captcha_id"
	}
	if len(opt.FieldCaptchaName) == 0 {
		opt.FieldCaptchaName = "captcha"
	}
	if opt.ChallengeNums == 0 {
		opt.ChallengeNums = 6
	}
	if opt.Width == 0 {
		opt.Width = stdWidth
	}
	if opt.Height == 0 {
		opt.Height = stdHeight
	}
	if opt.Expiration == 0 {
		opt.Expiration = 600
	}
	if len(opt.CachePrefix) == 0 {
		opt.CachePrefix = "captcha_"
	}

	return opt
}

// NewCaptcha initializes and returns a captcha with given options.
func NewCaptcha(opt Options) *Captcha {
	return &Captcha{
		SubURL:           opt.SubURL,
		URLPrefix:        opt.URLPrefix,
		FieldIdName:      opt.FieldIdName,
		FieldCaptchaName: opt.FieldCaptchaName,
		StdWidth:         opt.Width,
		StdHeight:        opt.Height,
		ChallengeNums:    opt.ChallengeNums,
		Expiration:       opt.Expiration,
		CachePrefix:      opt.CachePrefix,
	}
}

// Captchaer is a middleware that maps a captcha.Captcha service into the Macaron handler chain.
// An single variadic captcha.Options struct can be optionally provided to configure.
// This should be register after cache.Cacher.
func Captchaer(options ...Options) macaron.Handler {
	return func(ctx *macaron.Context, cache cache.Cache) {
		cpt := NewCaptcha(prepareOptions(options))
		cpt.store = cache

		if strings.HasPrefix(ctx.Req.URL.Path, cpt.URLPrefix) {
			var chars string
			id := path.Base(ctx.Req.URL.Path)
			if i := strings.Index(id, "."); i > -1 {
				id = id[:i]
			}
			key := cpt.key(id)

			// Reload captcha.
			if len(ctx.Query("reload")) > 0 {
				chars = cpt.genRandChars()
				if err := cpt.store.Put(key, chars, cpt.Expiration); err != nil {
					ctx.Status(500)
					ctx.Write([]byte("captcha reload error"))
					panic(fmt.Errorf("reload captcha: %v", err))
				}
			} else {
				if v, ok := cpt.store.Get(key).(string); ok {
					chars = v
				} else {
					ctx.Status(404)
					ctx.Write([]byte("captcha not found"))
					return
				}
			}

			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil {
				panic(fmt.Errorf("write captcha: %v", err))
			}
			return
		}

		ctx.Data["Captcha"] = cpt
		ctx.Map(cpt)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/deadsy/libusb"
	"image"
	"math/rand"
)

const (
	AX206_VID = 0x1908 // Hacked frames USB Vendor ID
	AX206_PID = 0x0102 // Hacked frames USB Product ID

	USBCMD_SETPROPERTY = 0x01 // USB command: Set property
	USBCMD_BLIT        = 0x12 // USB command: Blit to screen

	ENDP_OUT = 0x01
	ENDP_IN  = 0x81
)

func main() {

	log.SetOutput(os.Stderr)
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	var ctx libusb.Context
	err := libusb.Init(&ctx)
	if err != nil {
		log.Fatal(err)
	}
	defer libusb.Exit(ctx)

	hdl := libusb.Open_Device_With_VID_PID(ctx, AX206_VID, AX206_PID)
	if hdl == nil {
		log.Fatal("Failed to open device")
	}
	defer libusb.Close(hdl)

	libusb.Set_Auto_Detach_Kernel_Driver(hdl, true)

	if err = libusb.Claim_Interface(hdl, 0); err != nil {
		log.Fatal("Claim interface: ", err)
		return
	}
	defer libusb.Release_Interface(hdl, 0)

	/*
		dev := libusb.Get_Device(hdl)
		dd, err := libusb.Get_Device_Descriptor(dev)
		if err != nil {
			log.Fatal(err)
		}
		pp.Println(dd)

		// record information on input endpoints
		for i := 0; i < int(dd.BNumConfigurations); i++ {
			cd, err := libusb.Get_Config_Descriptor(dev, uint8(i))
			if err != nil {
				log.Fatal(err)
			}
			pp.Println(cd)

			libusb.Free_Config_Descriptor(cd)
		}
	*/

	w, h, err := GetParams(hdl)
	if err != nil {
		log.Fatal("LcdParams: ", err)
	}
	fmt.Printf("Got LCD dimensions: %dx%d\n", w, h)

	for i := range [8]struct{}{} {
		if err := SetBrightness(hdl, i); err != nil {
			log.Fatal(err)
		}
		time.Sleep(time.Microsecond * 500)
	}

	rand.Seed(time.Now().Unix())
	r := image.Rect(0, 0, 319, 239)
	buf := make([]byte, (r.Max.X-r.Min.X+1)*(r.Max.Y-r.Min.Y+1)*2)

	for _ = range [50]struct{}{} {
		for i := range buf {
			buf[i] = byte(rand.Int())
		}
		err = Blit(hdl, r, buf)
		if err != nil {
			log.Fatal(err)
		}
	}

}

func GetParams(udev libusb.Device_Handle) (width, height int, err error) {
	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 2, 0, 0,
		0, 0, 0, 0,
		0, 0, 0, 0,
	}
	data, err := ScsiRead(udev, cmd, 5)
	if err != nil {
		return 0, 0, err
	}
	width = int(data[0]) | int(data[1])<<8
	height = int(data[2]) | int(data[3])<<8
	return width, height, nil
}

func SetBrightness(udev libusb.Device_Handle, lvl int) error {
	if lvl < 0 {
		lvl = 0
	}
	if lvl > 7 {
		lvl = 7
	}

	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 6, USBCMD_SETPROPERTY,
		1, 0, // PROPERTY_BRIGHTNESS
		byte(lvl), byte(lvl >> 8),
		0, 0, 0, 0, 0,
	}

	return ScsiWrite(udev, cmd, nil)
}

func Blit(udev libusb.Device_Handle, r image.Rectangle, data []byte) error {

	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 6, USBCMD_BLIT,
		byte(r.Min.X), byte(r.Min.X >> 8),
		byte(r.Min.Y), byte(r.Min.Y >> 8),
		byte(r.Max.X), byte(r.Max.X >> 8),
		byte(r.Max.Y), byte(r.Max.Y >> 8),
		0,
	}
	return ScsiWrite(udev, cmd, data)
}

/*
static
unsigned char g_excmd[16] = {
0xcd, 0, 0, 0,
0, 6, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0
};

void dpf_ax_screen_blit(DPFAXHANDLE h, const unsigned char *buf, short rect[4])
{
unsigned long len = (rect[2] - rect[0]) * (rect[3] - rect[1]);
len <<= 1;
unsigned char *cmd = g_excmd;

cmd[6] = USBCMD_BLIT;
cmd[7] = rect[0];
cmd[8] = rect[0] >> 8;
cmd[9] = rect[1];
cmd[10] = rect[1] >> 8;
cmd[11] = rect[2] - 1;
cmd[12] = (rect[2] - 1) >> 8;
cmd[13] = rect[3] - 1;
cmd[14] = (rect[3] - 1) >> 8;
cmd[15] = 0;

wrap_scsi((DPFContext *) h, cmd, sizeof(g_excmd), DIR_OUT, (unsigned char *) buf, len);
}
*/

const scsiTimeout = 1000

func scsiCmdPrepare(cmd []byte, blockLen int, out bool) []byte {
	var bmCBWFlags byte
	if out {
		bmCBWFlags = 0x00
	} else {
		bmCBWFlags = 0x80
	}
	buf := []byte{
		0x55, 0x53, 0x42, 0x43, // dCBWSignature
		0xde, 0xad, 0xbe, 0xef, // dCBWTag
		byte(blockLen), byte(blockLen >> 8), byte(blockLen >> 16), byte(blockLen >> 24), // dCBWLength (4 byte)
		bmCBWFlags,     // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out
		0x00,           // bCBWLUN
		byte(len(cmd)), // bCBWCBLength

		// SCSI cmd: (15)
		0xcd, 0x00, 0x00, 0x00,
		0x00, 0x06, 0x11, 0xf8,
		0x70, 0x00, 0x40, 0x00,
		0x00, 0x00, 0x00, 0x00,
	}

	copy(buf[15:], cmd)

	log.Print("SCSI cmd: ", cmd)
	log.Print("SCSI command: ", buf)
	return buf
}

func scsiGetAck(udev libusb.Device_Handle) error {
	buf := []byte{
		0, 0, 0, 0,
		0, 0, 0, 0,
		0, 0, 0, 0,
		0,
	}
	// Get ACK
	log.Print("[ACK] Read ACK from device")
	ack, err := libusb.Bulk_Transfer(udev, ENDP_IN, buf, scsiTimeout)
	if err != nil {
		return err
	}
	log.Print("[ACK] data ", ack)

	if string(ack[:4]) != "USBS" {
		return fmt.Errorf("Got invalid reply")
	}
	// pass back return code set by peer:
	// return ansbuf[12];
	return nil
}

func ScsiWrite(hdl libusb.Device_Handle, cmd []byte, data []byte) error {
	var err error

	// Write command to device
	log.Print("[WRITE] Write command to device")
	_, err = libusb.Bulk_Transfer(hdl, ENDP_OUT, scsiCmdPrepare(cmd, len(data), true), scsiTimeout)
	if err != nil {
		return err
	}

	// Write data to device
	if data != nil {
		log.Print("[WRITE] Write data to device")
		out, err := libusb.Bulk_Transfer(hdl, ENDP_OUT, data, scsiTimeout)
		if err != nil {
			return err
		}
		log.Print(out)
	}

	return scsiGetAck(hdl)
}

func ScsiRead(hdl libusb.Device_Handle, cmd []byte, blockLen int) ([]byte, error) {
	var err error

	// Write command to device
	log.Print("[READ] Write command to device")
	_, err = libusb.Bulk_Transfer(hdl, ENDP_OUT, scsiCmdPrepare(cmd, blockLen, false), scsiTimeout)
	if err != nil {
		return nil, err
	}

	log.Print("[READ] Read data from device")
	// Read data from device
	data1 := make([]byte, blockLen, blockLen)
	data, err := libusb.Bulk_Transfer(hdl, ENDP_IN, data1, scsiTimeout)
	if err != nil {
		return nil, err
	}
	log.Print("[READ] data ", data)

	err = scsiGetAck(hdl)
	if err != nil {
		return data, err
	}

	return data, nil
}
<commit_msg>dpf: incapsulated operations to struct<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/deadsy/libusb"
	"image"
	"math/rand"
)

func main() {

	log.SetOutput(os.Stderr)
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	dpf, err := OpenDpf()
	if err != nil {
		log.Fatal(err)
	}

	w, h, err := dpf.GetDimensions()
	if err != nil {
		log.Fatal("LcdParams: ", err)
	}
	fmt.Printf("Got LCD dimensions: %dx%d\n", w, h)

	if err := dpf.Brightness(7); err != nil {
		log.Fatal(err)
	}

	rand.Seed(time.Now().Unix())
	r := image.Rect(0, 0, w-1, h-1)
	bufSize := w*h*2
	buf := make([]byte, bufSize, bufSize)
	bufEmpty := make([]byte, bufSize, bufSize)

	for _ = range [5]struct{}{} {
		for i := range buf {
			buf[i] = byte(rand.Int())
		}
		err = dpf.Blit(r, buf)
		if err != nil {
			log.Fatal(err)
		}
		err = dpf.Blit(r, bufEmpty)
		if err != nil {
			log.Fatal(err)
		}
	}

	err = dpf.Blit(r, buf)
	if err != nil {
		log.Fatal(err)
	}

}

const (
	AX206_VID = 0x1908 // Hacked frames USB Vendor ID
	AX206_PID = 0x0102 // Hacked frames USB Product ID

	USBCMD_SETPROPERTY = 0x01 // USB command: Set property
	USBCMD_BLIT        = 0x12 // USB command: Blit to screen

	AX206_INTERFACE = 0x00
	AX206_ENDP_OUT = 0x01
	AX206_ENDP_IN = 0x81
)

type DPF struct {
	Width int
	Height int
	Debug bool

	ctx libusb.Context
	udev libusb.Device_Handle
	hasCtx bool
	hasUdev bool
	hasClaim bool
}

func OpenDpf() (*DPF, error) {
	vid := uint16(AX206_VID)
	pid := uint16(AX206_PID)
	dpf := new(DPF)

	err := libusb.Init(&dpf.ctx)
	if err != nil {
		return nil, err
	}
	dpf.hasCtx = true

	dpf.udev = libusb.Open_Device_With_VID_PID(dpf.ctx, vid, pid)
	if dpf.udev == nil {
		return nil, fmt.Errorf("Failed to open device [%04x:%04x] (may be no permission?)", vid, pid)
	}
	dpf.hasUdev = true

	libusb.Set_Auto_Detach_Kernel_Driver(dpf.udev, true)

	if err = libusb.Claim_Interface(dpf.udev, AX206_INTERFACE); err != nil {
		return nil, fmt.Errorf("Can't claim interface: %v", err)
	}
	dpf.hasClaim = true

	return dpf, nil
}

func (dpf *DPF) Close() {
	if dpf.hasClaim {
		libusb.Release_Interface(dpf.udev, AX206_INTERFACE)
	}
	if dpf.hasUdev {
		libusb.Close(dpf.udev)
	}
	if dpf.hasCtx {
		libusb.Exit(dpf.ctx)
		dpf.hasCtx = false
	}
}

func (dpf *DPF) GetDimensions() (width, height int, err error) {
	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 2, 0, 0,
		0, 0, 0, 0,
		0, 0, 0, 0,
	}
	data, err := dpf.scsiRead(cmd, 5)
	if err != nil {
		return 0, 0, err
	}
	width = int(data[0]) | int(data[1])<<8
	height = int(data[2]) | int(data[3])<<8
	return width, height, nil
}

func (dpf *DPF) Brightness(lvl int) error {
	if lvl < 0 {
		lvl = 0
	}
	if lvl > 7 {
		lvl = 7
	}

	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 6, USBCMD_SETPROPERTY,
		1, 0, // PROPERTY_BRIGHTNESS
		byte(lvl), byte(lvl >> 8),
		0, 0, 0, 0, 0,
	}

	return dpf.scsiWrite(cmd, nil)
}

func (dpf *DPF) Blit(r image.Rectangle, data []byte) error {

	cmd := []byte{
		0xcd, 0, 0, 0,
		0, 6, USBCMD_BLIT,
		byte(r.Min.X), byte(r.Min.X >> 8),
		byte(r.Min.Y), byte(r.Min.Y >> 8),
		byte(r.Max.X), byte(r.Max.X >> 8),
		byte(r.Max.Y), byte(r.Max.Y >> 8),
		0,
	}
	return dpf.scsiWrite(cmd, data)
}

const scsiTimeout = 1000

func (dpf *DPF) scsiCmdPrepare(cmd []byte, blockLen int, out bool) []byte {
	var bmCBWFlags byte
	if out {
		bmCBWFlags = 0x00
	} else {
		bmCBWFlags = 0x80
	}
	buf := []byte{
		0x55, 0x53, 0x42, 0x43, // dCBWSignature
		0xde, 0xad, 0xbe, 0xef, // dCBWTag
		byte(blockLen), byte(blockLen >> 8), byte(blockLen >> 16), byte(blockLen >> 24), // dCBWLength (4 byte)
		bmCBWFlags,     // bmCBWFlags: 0x80: data in (dev to host), 0x00: Data out
		0x00,           // bCBWLUN
		byte(len(cmd)), // bCBWCBLength

		// SCSI cmd: (15)
		0xcd, 0x00, 0x00, 0x00,
		0x00, 0x06, 0x11, 0xf8,
		0x70, 0x00, 0x40, 0x00,
		0x00, 0x00, 0x00, 0x00,
	}

	copy(buf[15:], cmd)

	if dpf.Debug {
		log.Print("SCSI cmd: ", cmd)
		log.Print("SCSI command: ", buf)
	}
	return buf
}

func (dpf *DPF) scsiGetAck() error {
	buf := []byte{
		0, 0, 0, 0,
		0, 0, 0, 0,
		0, 0, 0, 0,
		0,
	}
	// Get ACK
	if dpf.Debug {
		log.Print("[ACK] Read ACK from device")
	}
	ack, err := libusb.Bulk_Transfer(dpf.udev, AX206_ENDP_IN, buf, scsiTimeout)
	if err != nil {
		return err
	}
	if dpf.Debug {
		log.Print("[ACK] data ", ack)
	}

	if string(ack[:4]) != "USBS" {
		return fmt.Errorf("Got invalid reply")
	}
	// pass back return code set by peer:
	// return ansbuf[12];
	return nil
}

func (dpf *DPF) scsiWrite(cmd []byte, data []byte) error {
	var err error

	// Write command to device
	if dpf.Debug {
		log.Print("[WRITE] Write command to device")
	}
	_, err = libusb.Bulk_Transfer(dpf.udev, AX206_ENDP_OUT, dpf.scsiCmdPrepare(cmd, len(data), true), scsiTimeout)
	if err != nil {
		return err
	}

	// Write data to device
	if data != nil {
		if dpf.Debug {
			log.Print("[WRITE] Write data to device")
		}
		_, err := libusb.Bulk_Transfer(dpf.udev, AX206_ENDP_OUT, data, scsiTimeout)
		if err != nil {
			return err
		}
	}

	return dpf.scsiGetAck()
}

func (dpf *DPF) scsiRead(cmd []byte, blockLen int) ([]byte, error) {
	var err error

	// Write command to device
	if dpf.Debug {
		log.Print("[READ] Write command to device")
	}
	_, err = libusb.Bulk_Transfer(dpf.udev, AX206_ENDP_OUT, dpf.scsiCmdPrepare(cmd, blockLen, false), scsiTimeout)
	if err != nil {
		return nil, err
	}

	if dpf.Debug {
		log.Print("[READ] Read data from device")
	}
	// Read data from device
	data1 := make([]byte, blockLen, blockLen)
	data, err := libusb.Bulk_Transfer(dpf.udev, AX206_ENDP_IN, data1, scsiTimeout)
	if err != nil {
		return nil, err
	}
	if dpf.Debug {
		log.Print("[READ] data ", data)
	}

	err = dpf.scsiGetAck()
	if err != nil {
		return data, err
	}

	return data, nil
}

<|endoftext|>


<commit_before>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/Sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/query/g"
	"github.com/Cepave/open-falcon-backend/modules/query/utils"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"funcation_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"conf/js", "js"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"conf/lambdaSetup.json", "config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<commit_msg>fixed missing configure issue for js loading problem<commit_after>package conf

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"reflect"
	"sync"

	log "github.com/Sirupsen/logrus"

	"github.com/Cepave/open-falcon-backend/modules/query/g"
	"github.com/Cepave/open-falcon-backend/modules/query/utils"
)

type Gconfig struct {
	Funcations []FunConfig
}

type FunConfig struct {
	FuncationName string   `json:"funcation_name"`
	FilePath      string   `json:"file_path"`
	Params        []string `json:"params"`
	Description   string   `json:"description"`
	Codes         string   `json:"-"`
}

var (
	gconfig     []*FunConfig
	configLock  = new(sync.RWMutex)
	confpath    *string
	FunctionMap map[string]*FunConfig
)

func Config() map[string]*FunConfig {
	configLock.RLock()
	defer configLock.RUnlock()
	return FunctionMap
}

func functionMapGen() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"../config/js", "config/js", "conf/js", "js"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("load js files got error, currentPaht: %s , please check your code tree and make is correct!", currentPath)
	}

	FunctionMap = map[string]*FunConfig{}
	for _, v := range gconfig {
		contain := jsFileReader(fmt.Sprintf("%s/%s", f, v.FilePath))
		v.Codes = contain
		FunctionMap[v.FuncationName] = v
	}
}

func ReadConf() {
	currentPath := g.Config().RootDir
	possiblePath := []string{"conf/lambdaSetup.json", "config/lambdaSetup.json", "../config/lambdaSetup.json"}
	f := ""
	for _, pa := range possiblePath {
		paf := fmt.Sprintf("%s/%s", currentPath, pa)
		if _, err := os.Stat(paf); err != nil {
			log.Debugf("can't not load file from: %s", paf)
		} else {
			f = paf
			break
		}
	}
	if f == "" {
		log.Fatalf("lambdaSetup.json not found, currentPaht: %s", currentPath)
	}

	confpath = &f
	dat, err := ioutil.ReadFile(f)
	if err != nil {
		log.Println(err)
	}
	var myconf []*FunConfig
	json.Unmarshal(dat, &myconf)
	if len(myconf) == 0 {
		log.Println("conf file is empty or format is wrong, please check it!")
	}
	gconfig = myconf
	functionMapGen()
}

func Reload() {
	configLock.RLock()
	ReadConf()
	defer configLock.RUnlock()
}

func GetFunc(key string) *FunConfig {
	return FunctionMap[key]
}

func GetAvaibleFun() []string {
	return utils.GetMapKeys(reflect.ValueOf(FunctionMap).MapKeys())
}
<|endoftext|>


<commit_before>package influxdb

import (
	"reflect"
	"testing"
	"time"
)

func TestShardWrite(t *testing.T) {
	// Enable when shard can convert a WritePointsRequest to stored data.
	// Needs filed encoding/types saved on the shard
	t.Skip("not implemented yet")

	sh := &Shard{ID: 1}

	pt := Point{
		Name:      "cpu",
		Tags:      map[string]string{"host": "server"},
		Timestamp: time.Unix(1, 2),
		Fields:    map[string]interface{}{"value": 1.0},
	}
	pr := &WritePointsRequest{
		Database:        "foo",
		RetentionPolicy: "default",
		Points: []Point{
			pt},
	}

	if err := sh.Write(pr); err != nil {
		t.Errorf("LocalWriter.Write() failed: %v", err)
	}

	p, err := sh.Read(pt.Timestamp)
	if err != nil {
		t.Fatalf("LocalWriter.Read() failed: %v", err)
	}

	if exp := 1; len(p) != exp {
		t.Fatalf("LocalWriter.Read() points len mismatch. got %v, exp %v", len(p), exp)
	}

	if !reflect.DeepEqual(p[0], pt) {
		t.Fatalf("LocalWriter.Read() point mismatch. got %v, exp %v", p[0], pt)
	}
}
<commit_msg>Fix broken merge<commit_after>package influxdb

import (
	"reflect"
	"testing"
	"time"
)

func TestShardWrite(t *testing.T) {
	// Enable when shard can convert a WritePointsRequest to stored data.
	// Needs filed encoding/types saved on the shard
	t.Skip("not implemented yet")

	sh := &Shard{ID: 1}

	pt := Point{
		Name:   "cpu",
		Tags:   map[string]string{"host": "server"},
		Time:   time.Unix(1, 2),
		Fields: map[string]interface{}{"value": 1.0},
	}
	pr := &WritePointsRequest{
		Database:        "foo",
		RetentionPolicy: "default",
		Points: []Point{
			pt},
	}

	if err := sh.Write(pr); err != nil {
		t.Errorf("LocalWriter.Write() failed: %v", err)
	}

	p, err := sh.Read(pt.Time)
	if err != nil {
		t.Fatalf("LocalWriter.Read() failed: %v", err)
	}

	if exp := 1; len(p) != exp {
		t.Fatalf("LocalWriter.Read() points len mismatch. got %v, exp %v", len(p), exp)
	}

	if !reflect.DeepEqual(p[0], pt) {
		t.Fatalf("LocalWriter.Read() point mismatch. got %v, exp %v", p[0], pt)
	}
}
<|endoftext|>


<commit_before>package meta

import (
	"fmt"
	"reflect"
)

// 全局值容器
var GlobalValueContainer = NewDefaultValueContainer()

// 值提供器
type ValueGenerator struct {
	Strings []string           //用于验证的字符串信息
	Func    func() interface{} //值生成方法
}

// 默认值提供器,仅根据类型提供对象,不提供字符串值,因此无法用于字段校验
type DefaultValueProvider struct {
	ValueGenerator *ValueGenerator
}

// String 根据名称和类型返回相应的字符串值
func (this *DefaultValueProvider) String() []string {
	return this.ValueGenerator.Strings
}

// Value 根据名称和类型返回相应的解析后的对象
func (this *DefaultValueProvider) Value() interface{} {
	return this.ValueGenerator.Func()
}

// 默认值容器
type DefaultValueContainer struct {
	NameContainer map[string]*ValueGenerator //名称容器
	TypeContainer map[string]*ValueGenerator //类型容器
}

// NewDefaultValueContainer 创建默认值容器
func NewDefaultValueContainer() *DefaultValueContainer {
	return &DefaultValueContainer{
		make(map[string]*ValueGenerator),
		make(map[string]*ValueGenerator),
	}
}

// Contains 检查值容器是否包含能够生成指定名称和类型的ValueProvider
func (this *DefaultValueContainer) Contains(name string, t reflect.Type) (ValueProvider, bool) {
	var f, ok = this.NameContainer[name]
	if ok {
		return &DefaultValueProvider{f}, ok
	}
	f, ok = this.TypeContainer[t.String()]
	if ok {
		return &DefaultValueProvider{f}, ok
	}
	return nil, false
}

// Register 注册指定名称或类型的生成器
//  name:
//    1.非空字符串:表示注册的是指定名称的生成器
//    2.非接口类型的值:表示注册的是指定非接口类型的生成器
//    3.值为nil的接口指针(例如:(*interface{})(nil)):表示注册的是指定接口类型的生成器
//    4.nil:自动按照generator参数判断应该生成哪种生成器
//  generator:
//    1.有一个返回值的函数:如果函数具有参数,则参数自动注入,在name为nil时将返回值作为生成器的类型
//    2.非接口类型的值(非指针):直接使用该值作为生成器的返回值,在name为nil时将值类型作为生成器的类型
//    3.非接口类型的指针(非nil):直接使用该值作为生成器的返回值,在name为nil时将指针类型作为生成器的类型
//    4.结构体的指针(为nil):则生成器自动创建该结构体的实例,并自动注入相应字段的值,在name为nil时将指针类型作为生成器的类型
func (this *DefaultValueContainer) Register(name interface{}, generator interface{}) error {
	if generator == nil {
		return ErrorMustBeStructPointer.Format("nil").Error()
	}
	var t = reflect.TypeOf(generator)
	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Interface {
		//generator不能是接口指针
		return ErrorInvalidGenerator.Format(t.String()).Error()
	}
	var f *ValueGenerator = nil
	var fName = ""
	var err error = nil
	//chan, func, interface, map, pointer, or slice value
	var v = reflect.ValueOf(generator)
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		{
			if v.IsNil() {
				// generator为nil时
				if !IsStructPtrType(t) {
					return ErrorMustBeStructPointer.Format(t.String()).Error()
				}
				//非接口类型的指针(为nil),不记录该类型的生成器,自动注入
				f, fName, err = this.pointer(generator)
				break
			}
		}
		fallthrough
	default:
		{
			if t.Kind() == reflect.Func {
				//函数
				f, fName, err = this.function(generator)
			} else {
				//非接口类型的值(非指针) 非接口类型的指针(为nil)
				f, fName, err = this.instance(generator)
			}
			if err != nil {
				return err
			}
		}
	}
	var isStringName bool
	if name != nil {
		fName, isStringName = this.TranslateName(name)
	}
	//注册生成方法
	if isStringName {
		this.NameContainer[fName] = f
	} else {
		this.TypeContainer[fName] = f
	}
	return nil

}

// function 生成函数类型的GenerateFunc
//  generator:必须是有一个返回值的函数
//  return:(生成函数,返回值的类型全名,错误)
func (this *DefaultValueContainer) function(generator interface{}) (*ValueGenerator, string, error) {
	var value = reflect.ValueOf(generator)
	var m, err = AnalyzeMethod("", &value)
	if err != nil {
		return nil, "", err
	}
	if len(m.Return) != 1 {
		return nil, "", ErrorInvalidFunction.Error()
	}
	return &ValueGenerator{
		[]string{m.Return[0].String()},
		func() interface{} {
			var ins, err = m.Generate(this)
			if err != nil {
				return nil
			}
			var inss, ok = ins.([]interface{})
			if !ok || len(inss) != 1 {
				return nil
			}
			return inss[0]
		},
	}, m.Return[0].String(), nil
}

// instance 生成函数类型的GenerateFunc
//  generator:必须是不为nil的值
//  return:(生成函数,类型全名,错误)
func (this *DefaultValueContainer) instance(generator interface{}) (*ValueGenerator, string, error) {
	return &ValueGenerator{
		[]string{fmt.Sprint(generator)},
		func() interface{} {
			return generator
		},
	}, reflect.TypeOf(generator).String(), nil
}

// pointer 生成结构体指针类型的GenerateFunc
//  generator:必须是结构体指针类型
//  return:(生成函数,返回值的类型全名,错误)
func (this *DefaultValueContainer) pointer(generator interface{}) (*ValueGenerator, string, error) {
	var ptr = reflect.TypeOf(generator)
	var t = ptr.Elem()
	var g, err = AnalyzeStruct(t)
	if err != nil {
		return nil, "", err
	}
	var m = g.(*StructMetadata)
	return &ValueGenerator{
		[]string{ptr.String()},
		func() interface{} {
			var vp, ok = this.Contains(t.String(), t)
			if ok {
				//如果注册了generator的结构体类型,则使用相应的vp
				var v = vp.Value()
				var inst = reflect.New(t)
				inst.Elem().Set(reflect.ValueOf(v))
				return inst.Interface()
			} else {
				//没有注册相应结构体类型则自动创建
				var ins, err = m.New(this)
				if err != nil {
					return nil
				}
				return ins
			}
		},
	}, ptr.String(), nil
}

// Delete 删除指定名称或类型的生成器
//  name:
//    1.非空字符串:表示注册的是指定名称的生成器
//    2.非接口类型的值:表示注册的是指定非接口类型的生成器
//    3.值为nil的接口指针(例如:(*interface{})(nil)):表示注册的是指定接口类型的生成器
func (this *DefaultValueContainer) Delete(name interface{}) {
	if name == nil {
		return
	}
	var trueName, isStringName = this.TranslateName(name)
	if isStringName {
		delete(this.NameContainer, trueName)
	} else {
		delete(this.TypeContainer, trueName)
	}
}

// TranslateName 将name转换为字符串类型
//  name:不能为nil
//  return:(名称或类型字符串,name是否是非空字符串)
func (this *DefaultValueContainer) TranslateName(name interface{}) (string, bool) {
	if name == nil {
		return "", false
	}
	var value, ok = name.(string)
	if value != "" && ok {
		return value, true
	}
	var t = reflect.TypeOf(name)
	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Interface {
		return t.Elem().String(), false
	}
	return t.String(), false
}
<commit_msg>DefaultValueContainer增加直接获取实例的方法<commit_after>package meta

import (
	"fmt"
	"reflect"
)

// 全局值容器
var GlobalValueContainer = NewDefaultValueContainer()

// 值提供器
type ValueGenerator struct {
	Strings []string           //用于验证的字符串信息
	Func    func() interface{} //值生成方法
}

// 默认值提供器,仅根据类型提供对象,不提供字符串值,因此无法用于字段校验
type DefaultValueProvider struct {
	ValueGenerator *ValueGenerator
}

// String 根据名称和类型返回相应的字符串值
func (this *DefaultValueProvider) String() []string {
	return this.ValueGenerator.Strings
}

// Value 根据名称和类型返回相应的解析后的对象
func (this *DefaultValueProvider) Value() interface{} {
	return this.ValueGenerator.Func()
}

// 默认值容器
type DefaultValueContainer struct {
	NameContainer map[string]*ValueGenerator //名称容器
	TypeContainer map[string]*ValueGenerator //类型容器
}

// NewDefaultValueContainer 创建默认值容器
func NewDefaultValueContainer() *DefaultValueContainer {
	return &DefaultValueContainer{
		make(map[string]*ValueGenerator),
		make(map[string]*ValueGenerator),
	}
}

// Contains 检查值容器是否包含能够生成指定名称和类型的ValueProvider
func (this *DefaultValueContainer) Contains(name string, t reflect.Type) (ValueProvider, bool) {
	var f, ok = this.NameContainer[name]
	if ok {
		return &DefaultValueProvider{f}, ok
	}
	f, ok = this.TypeContainer[t.String()]
	if ok {
		return &DefaultValueProvider{f}, ok
	}
	return nil, false
}

// Value 根据name生成相应的实例
//  name:
//    1.非空字符串:表示使用指定名称的生成器生成实例
//    2.非接口类型的值:表示使用指定非接口类型的生成器生成实例
//    3.值为nil的接口指针(例如:(*interface{})(nil)):表示使用指定接口类型的生成器生成实例
func (this *DefaultValueContainer) Value(name interface{}) (interface{}, bool) {
	if name == nil {
		return nil, false
	}
	var trueName, isStringName = this.TranslateName(name)
	var vg *ValueGenerator
	var ok bool
	if isStringName {
		vg, ok = this.NameContainer[trueName]
	} else {
		vg, ok = this.TypeContainer[trueName]
	}
	if ok {
		return vg.Func(), true
	}
	return nil, false
}

// Value 根据类型全名生成相应的实例
func (this *DefaultValueContainer) TypeValue(typeFullName string) (interface{}, bool) {
	var vg, ok = this.TypeContainer[typeFullName]
	if ok {
		return vg.Func(), true
	}
	return nil, false
}

// Register 注册指定名称或类型的生成器
//  name:
//    1.非空字符串:表示注册的是指定名称的生成器
//    2.非接口类型的值:表示注册的是指定非接口类型的生成器
//    3.值为nil的接口指针(例如:(*interface{})(nil)):表示注册的是指定接口类型的生成器
//    4.nil:自动按照generator参数判断应该生成哪种生成器
//  generator:
//    1.有一个返回值的函数:如果函数具有参数,则参数自动注入,在name为nil时将返回值作为生成器的类型
//    2.非接口类型的值(非指针):直接使用该值作为生成器的返回值,在name为nil时将值类型作为生成器的类型
//    3.非接口类型的指针(非nil):直接使用该值作为生成器的返回值,在name为nil时将指针类型作为生成器的类型
//    4.结构体的指针(为nil):则生成器自动创建该结构体的实例,并自动注入相应字段的值,在name为nil时将指针类型作为生成器的类型
func (this *DefaultValueContainer) Register(name interface{}, generator interface{}) error {
	if generator == nil {
		return ErrorMustBeStructPointer.Format("nil").Error()
	}
	var t = reflect.TypeOf(generator)
	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Interface {
		//generator不能是接口指针
		return ErrorInvalidGenerator.Format(t.String()).Error()
	}
	var f *ValueGenerator = nil
	var fName = ""
	var err error = nil
	//chan, func, interface, map, pointer, or slice value
	var v = reflect.ValueOf(generator)
	switch v.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		{
			if v.IsNil() {
				// generator为nil时
				if !IsStructPtrType(t) {
					return ErrorMustBeStructPointer.Format(t.String()).Error()
				}
				//非接口类型的指针(为nil),不记录该类型的生成器,自动注入
				f, fName, err = this.pointer(generator)
				break
			}
		}
		fallthrough
	default:
		{
			if t.Kind() == reflect.Func {
				//函数
				f, fName, err = this.function(generator)
			} else {
				//非接口类型的值(非指针) 非接口类型的指针(为nil)
				f, fName, err = this.instance(generator)
			}
			if err != nil {
				return err
			}
		}
	}
	var isStringName bool
	if name != nil {
		fName, isStringName = this.TranslateName(name)
	}
	//注册生成方法
	if isStringName {
		this.NameContainer[fName] = f
	} else {
		this.TypeContainer[fName] = f
	}
	return nil

}

// function 生成函数类型的GenerateFunc
//  generator:必须是有一个返回值的函数
//  return:(生成函数,返回值的类型全名,错误)
func (this *DefaultValueContainer) function(generator interface{}) (*ValueGenerator, string, error) {
	var value = reflect.ValueOf(generator)
	var m, err = AnalyzeMethod("", &value)
	if err != nil {
		return nil, "", err
	}
	if len(m.Return) != 1 {
		return nil, "", ErrorInvalidFunction.Error()
	}
	return &ValueGenerator{
		[]string{m.Return[0].String()},
		func() interface{} {
			var ins, err = m.Generate(this)
			if err != nil {
				return nil
			}
			var inss, ok = ins.([]interface{})
			if !ok || len(inss) != 1 {
				return nil
			}
			return inss[0]
		},
	}, m.Return[0].String(), nil
}

// instance 生成函数类型的GenerateFunc
//  generator:必须是不为nil的值
//  return:(生成函数,类型全名,错误)
func (this *DefaultValueContainer) instance(generator interface{}) (*ValueGenerator, string, error) {
	return &ValueGenerator{
		[]string{fmt.Sprint(generator)},
		func() interface{} {
			return generator
		},
	}, reflect.TypeOf(generator).String(), nil
}

// pointer 生成结构体指针类型的GenerateFunc
//  generator:必须是结构体指针类型
//  return:(生成函数,返回值的类型全名,错误)
func (this *DefaultValueContainer) pointer(generator interface{}) (*ValueGenerator, string, error) {
	var ptr = reflect.TypeOf(generator)
	var t = ptr.Elem()
	var g, err = AnalyzeStruct(t)
	if err != nil {
		return nil, "", err
	}
	var m = g.(*StructMetadata)
	return &ValueGenerator{
		[]string{ptr.String()},
		func() interface{} {
			var vp, ok = this.Contains(t.String(), t)
			if ok {
				//如果注册了generator的结构体类型,则使用相应的vp
				var v = vp.Value()
				var inst = reflect.New(t)
				inst.Elem().Set(reflect.ValueOf(v))
				return inst.Interface()
			} else {
				//没有注册相应结构体类型则自动创建
				var ins, err = m.New(this)
				if err != nil {
					return nil
				}
				return ins
			}
		},
	}, ptr.String(), nil
}

// Delete 删除指定名称或类型的生成器
//  name:
//    1.非空字符串:表示注册的是指定名称的生成器
//    2.非接口类型的值:表示注册的是指定非接口类型的生成器
//    3.值为nil的接口指针(例如:(*interface{})(nil)):表示注册的是指定接口类型的生成器
func (this *DefaultValueContainer) Delete(name interface{}) {
	if name == nil {
		return
	}
	var trueName, isStringName = this.TranslateName(name)
	if isStringName {
		delete(this.NameContainer, trueName)
	} else {
		delete(this.TypeContainer, trueName)
	}
}

// TranslateName 将name转换为字符串类型
//  name:不能为nil
//  return:(名称或类型字符串,name是否是非空字符串)
func (this *DefaultValueContainer) TranslateName(name interface{}) (string, bool) {
	if name == nil {
		return "", false
	}
	var value, ok = name.(string)
	if value != "" && ok {
		return value, true
	}
	var t = reflect.TypeOf(name)
	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Interface {
		return t.Elem().String(), false
	}
	return t.String(), false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
)

type fish int

var FISH fish

func (f fish) Hook() string {
	return ""
}

func (f fish) Escape(str string) string {
	if str == "" {
		return "''"
	}
	in := []byte(str)
	out := ""
	i := 0
	l := len(in)

	hex := func(char byte) {
		out += fmt.Sprintf("\\x%02x", char)
	}

	backslash := func(char byte) {
		out += string([]byte{BACKSLASH, char})
	}

	escaped := func(str string) {
		out += str
	}

	quoted := func(char byte) {
		out += string([]byte{char})
	}

	literal := func(char byte) {
		out += string([]byte{char})
	}

	for i < l {
		char := in[i]
		switch {
		case char == TAB:
			escaped(`\t`)
		case char == LF:
			escaped(`\n`)
		case char == CR:
			escaped(`\r`)
		case char <= US:
			hex(char)
		case char <= AMPERSTAND:
			quoted(char)
		case char == SINGLE_QUOTE:
			backslash(char)
		case char <= PLUS:
			quoted(char)
		case char <= NINE:
			literal(char)
		case char <= QUESTION:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char == OPEN_BRACKET:
			quoted(char)
		case char == BACKSLASH:
			backslash(char)
		case char <= CLOSE_BRACKET:
			quoted(char)
		case char == UNDERSCORE:
			literal(char)
		case char <= BACKTICK:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char <= TILDA:
			quoted(char)
		case char == DEL:
			hex(char)
		default:
			hex(char)
		}
		i += 1
	}

	return out
}

func (f fish) Export(key, value string) string {
	return "set -x -g " + f.Escape(key) + " " + f.Escape(value) + ";"
}

func (f fish) Unset(key string) string {
	return "set -e -g " + f.Escape(key) + ";"
}
<commit_msg>Try to add a `direnv hook fish` command<commit_after>package main

import (
	"fmt"
)

type fish int

var FISH fish

func (f fish) Hook() string {
	return `
function direnv-export --on-event fish_prompt;
	eval (direnv export fish)
end
`
}

func (f fish) Escape(str string) string {
	if str == "" {
		return "''"
	}
	in := []byte(str)
	out := ""
	i := 0
	l := len(in)

	hex := func(char byte) {
		out += fmt.Sprintf("\\x%02x", char)
	}

	backslash := func(char byte) {
		out += string([]byte{BACKSLASH, char})
	}

	escaped := func(str string) {
		out += str
	}

	quoted := func(char byte) {
		out += string([]byte{char})
	}

	literal := func(char byte) {
		out += string([]byte{char})
	}

	for i < l {
		char := in[i]
		switch {
		case char == TAB:
			escaped(`\t`)
		case char == LF:
			escaped(`\n`)
		case char == CR:
			escaped(`\r`)
		case char <= US:
			hex(char)
		case char <= AMPERSTAND:
			quoted(char)
		case char == SINGLE_QUOTE:
			backslash(char)
		case char <= PLUS:
			quoted(char)
		case char <= NINE:
			literal(char)
		case char <= QUESTION:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char == OPEN_BRACKET:
			quoted(char)
		case char == BACKSLASH:
			backslash(char)
		case char <= CLOSE_BRACKET:
			quoted(char)
		case char == UNDERSCORE:
			literal(char)
		case char <= BACKTICK:
			quoted(char)
		case char <= LOWERCASE_Z:
			literal(char)
		case char <= TILDA:
			quoted(char)
		case char == DEL:
			hex(char)
		default:
			hex(char)
		}
		i += 1
	}

	return out
}

func (f fish) Export(key, value string) string {
	return "set -x -g " + f.Escape(key) + " " + f.Escape(value) + ";"
}

func (f fish) Unset(key string) string {
	return "set -e -g " + f.Escape(key) + ";"
}
<|endoftext|>