<commit_before>package main

import (
	"database/sql"
	"flag"
	"fmt"
	"log"
	"os"

	"strings"
	"time"

	env "github.com/segmentio/go-env"

	redshift "github.com/Clever/s3-to-redshift/redshift"
	s3filepath "github.com/Clever/s3-to-redshift/s3filepath"
)

var (
	// things we are likely to change when running the worker normally are flags
	inputSchemaName = flag.String("schema", "mongo", "what target schema we load into")
	inputTables     = flag.String("tables", "", "target tables to run on, comma separated")
	inputBucket     = flag.String("bucket", "metrics", "bucket to load from, not including s3:// protocol")
	truncate        = flag.Bool("truncate", false, "do we truncate the table before inserting")
	force           = flag.Bool("force", false, "do we refresh the data even if it's already handled?")
	dataDate        = flag.String("date", "", "data date we should process, must be full RFC3339")
	configFile      = flag.String("config", "", "schema & table config to use in YAML format")
	// things which will would strongly suggest launching as a second worker are env vars
	// also the secrets ... shhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
	host               = os.Getenv("REDSHIFT_HOST")
	port               = os.Getenv("REDSHIFT_PORT")
	dbName             = env.MustGet("REDSHIFT_DB")
	user               = env.MustGet("REDSHIFT_USER")
	pwd                = env.MustGet("REDSHIFT_PASSWORD")
	awsRegion          = env.MustGet("AWS_REGION")
	awsAccessKeyID     = env.MustGet("AWS_ACCESS_KEY_ID")
	awsSecretAccessKey = env.MustGet("AWS_SECRET_ACCESS_KEY")
)

func fatalIfErr(err error, msg string) {
	if err != nil {
		panic(fmt.Sprintf("%s: %s", msg, err)) // TODO: kayvee
	}
}

// in a transaction, truncate, create or update, and then copy from the s3 JSON file
// yell loudly if there is anything different in the target table compared to config (different distkey, etc)
func runCopy(db *redshift.Redshift, inputConf s3filepath.S3File, inputTable redshift.Table, targetTable *redshift.Table, truncate bool) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	// TRUNCATE for dimension tables, but not fact tables
	if truncate && targetTable != nil {
		log.Println("truncating table!")
		if err = db.Truncate(tx, inputConf.Schema, inputTable.Name); err != nil {
			return fmt.Errorf("err running truncate table: %s", err)
		}
	}
	if targetTable == nil {
		if err = db.CreateTable(tx, inputTable); err != nil {
			return fmt.Errorf("err running create table: %s", err)
		}
	} else {
		if err = db.UpdateTable(tx, *targetTable, inputTable); err != nil {
			return fmt.Errorf("err running update table: %s", err)
		}
	}

	// COPY direct into it, ok to do since we're in a transaction
	// assuming that we always want to copy from s3 and have gzip, so last 2 params are true
	// if we want to change that, we should figure this out from the filename
	gzip := false
	if strings.Contains(inputConf.Suffix, "gz") {
		gzip = true
	}
	if err = db.JSONCopy(tx, inputConf, true, gzip); err != nil {
		return fmt.Errorf("err running JSON copy: %s", err)
	}

	if err = tx.Commit(); err != nil {
		return fmt.Errorf("err committing transaction: %s", err)
	}
	return nil
}

// This worker finds the latest file in s3 and uploads it to redshift
// If the destination table does not exist, the worker creates it
// If the destination table lacks columns, the worker creates those as well
// The worker also uses a column in the data to figure out whether the s3 data is
// newer than what already exists.
func main() {
	flag.Parse()

	// use an custom bucket type for testablitity
	bucket := s3filepath.S3Bucket{*inputBucket, awsRegion, awsAccessKeyID, awsSecretAccessKey}

	timeout := 10 // can parameterize later if this is an issue
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "5439"
	}
	db, err := redshift.NewRedshift(host, port, dbName, user, pwd, timeout)
	fatalIfErr(err, "error getting redshift instance")

	// for each table passed in - likely we could goroutine this out
	for _, t := range strings.Split(*inputTables, ",") {
		log.Printf("attempting to run on schema: %s table: %s", *inputSchemaName, t)
		// override most recent data file
		if *dataDate == "" {
			panic("No date provided")
		}
		parsedDate, err := time.Parse(time.RFC3339, *dataDate)
		fatalIfErr(err, fmt.Sprintf("issue parsing date: %s", *dataDate))
		inputConf, err := s3filepath.CreateS3File(s3filepath.S3PathChecker{}, bucket, *inputSchemaName, t, *configFile, parsedDate)
		fatalIfErr(err, "Issue getting data file from s3")
		inputTable, err := db.GetTableFromConf(*inputConf) // allow passing explicit config later
		fatalIfErr(err, "Issue getting table from input")

		// figure out what the current state of the table is to determine if the table is already up to date
		targetTable, lastTargetData, err := db.GetTableMetadata(inputConf.Schema, inputConf.Table, inputTable.Meta.DataDateColumn)
		if err != nil && err != sql.ErrNoRows { // ErrNoRows is fine, just means the table doesn't exist
			fatalIfErr(err, "Error getting existing latest table metadata") // use fatalIfErr to stay the same
		}

		// unless --force, don't update unless input data is new
		if lastTargetData != nil && !inputConf.DataDate.After(*lastTargetData) {
			if *force == false {
				log.Printf("Recent data already exists in db: %s", *lastTargetData)
				return
			}
			log.Printf("Forcing update of inputTable: %s", inputConf.Table)
		}

		fatalIfErr(runCopy(db, *inputConf, *inputTable, targetTable, *truncate), "Issue running copy")
		// DON'T NEED TO CREATE VIEWS - will be handled by the refresh script
		log.Printf("done with table: %s.%s", inputConf.Schema, t)
	}
	log.Println("done with full run")
}
<commit_msg>Related to IP-518- close the db session properly<commit_after>package main

import (
	"database/sql"
	"flag"
	"fmt"
	"log"
	"os"

	"strings"
	"time"

	env "github.com/segmentio/go-env"

	redshift "github.com/Clever/s3-to-redshift/redshift"
	s3filepath "github.com/Clever/s3-to-redshift/s3filepath"
)

var (
	// things we are likely to change when running the worker normally are flags
	inputSchemaName = flag.String("schema", "mongo", "what target schema we load into")
	inputTables     = flag.String("tables", "", "target tables to run on, comma separated")
	inputBucket     = flag.String("bucket", "metrics", "bucket to load from, not including s3:// protocol")
	truncate        = flag.Bool("truncate", false, "do we truncate the table before inserting")
	force           = flag.Bool("force", false, "do we refresh the data even if it's already handled?")
	dataDate        = flag.String("date", "", "data date we should process, must be full RFC3339")
	configFile      = flag.String("config", "", "schema & table config to use in YAML format")
	// things which will would strongly suggest launching as a second worker are env vars
	// also the secrets ... shhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
	host               = os.Getenv("REDSHIFT_HOST")
	port               = os.Getenv("REDSHIFT_PORT")
	dbName             = env.MustGet("REDSHIFT_DB")
	user               = env.MustGet("REDSHIFT_USER")
	pwd                = env.MustGet("REDSHIFT_PASSWORD")
	awsRegion          = env.MustGet("AWS_REGION")
	awsAccessKeyID     = env.MustGet("AWS_ACCESS_KEY_ID")
	awsSecretAccessKey = env.MustGet("AWS_SECRET_ACCESS_KEY")
)

func fatalIfErr(err error, msg string) {
	if err != nil {
		panic(fmt.Sprintf("%s: %s", msg, err)) // TODO: kayvee
	}
}

// in a transaction, truncate, create or update, and then copy from the s3 JSON file
// yell loudly if there is anything different in the target table compared to config (different distkey, etc)
func runCopy(db *redshift.Redshift, inputConf s3filepath.S3File, inputTable redshift.Table, targetTable *redshift.Table, truncate bool) error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	// TRUNCATE for dimension tables, but not fact tables
	if truncate && targetTable != nil {
		log.Println("truncating table!")
		if err = db.Truncate(tx, inputConf.Schema, inputTable.Name); err != nil {
			return fmt.Errorf("err running truncate table: %s", err)
		}
	}
	if targetTable == nil {
		if err = db.CreateTable(tx, inputTable); err != nil {
			return fmt.Errorf("err running create table: %s", err)
		}
	} else {
		if err = db.UpdateTable(tx, *targetTable, inputTable); err != nil {
			return fmt.Errorf("err running update table: %s", err)
		}
	}

	// COPY direct into it, ok to do since we're in a transaction
	// assuming that we always want to copy from s3 and have gzip, so last 2 params are true
	// if we want to change that, we should figure this out from the filename
	gzip := false
	if strings.Contains(inputConf.Suffix, "gz") {
		gzip = true
	}
	if err = db.JSONCopy(tx, inputConf, true, gzip); err != nil {
		return fmt.Errorf("err running JSON copy: %s", err)
	}

	if err = tx.Commit(); err != nil {
		return fmt.Errorf("err committing transaction: %s", err)
	}
	if err = db.Close(); err != nil {
		return fmt.Errorf("issue closing db connection after tx commit")
	}
	return nil
}

// This worker finds the latest file in s3 and uploads it to redshift
// If the destination table does not exist, the worker creates it
// If the destination table lacks columns, the worker creates those as well
// The worker also uses a column in the data to figure out whether the s3 data is
// newer than what already exists.
func main() {
	flag.Parse()

	// use an custom bucket type for testablitity
	bucket := s3filepath.S3Bucket{*inputBucket, awsRegion, awsAccessKeyID, awsSecretAccessKey}

	timeout := 10 // can parameterize later if this is an issue
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "5439"
	}
	db, err := redshift.NewRedshift(host, port, dbName, user, pwd, timeout)
	fatalIfErr(err, "error getting redshift instance")

	// for each table passed in - likely we could goroutine this out
	for _, t := range strings.Split(*inputTables, ",") {
		log.Printf("attempting to run on schema: %s table: %s", *inputSchemaName, t)
		// override most recent data file
		if *dataDate == "" {
			panic("No date provided")
		}
		parsedDate, err := time.Parse(time.RFC3339, *dataDate)
		fatalIfErr(err, fmt.Sprintf("issue parsing date: %s", *dataDate))
		inputConf, err := s3filepath.CreateS3File(s3filepath.S3PathChecker{}, bucket, *inputSchemaName, t, *configFile, parsedDate)
		fatalIfErr(err, "Issue getting data file from s3")
		inputTable, err := db.GetTableFromConf(*inputConf) // allow passing explicit config later
		fatalIfErr(err, "Issue getting table from input")

		// figure out what the current state of the table is to determine if the table is already up to date
		targetTable, lastTargetData, err := db.GetTableMetadata(inputConf.Schema, inputConf.Table, inputTable.Meta.DataDateColumn)
		if err != nil && err != sql.ErrNoRows { // ErrNoRows is fine, just means the table doesn't exist
			fatalIfErr(err, "Error getting existing latest table metadata") // use fatalIfErr to stay the same
		}

		// unless --force, don't update unless input data is new
		if lastTargetData != nil && !inputConf.DataDate.After(*lastTargetData) {
			if *force == false {
				log.Printf("Recent data already exists in db: %s", *lastTargetData)
				return
			}
			log.Printf("Forcing update of inputTable: %s", inputConf.Table)
		}

		fatalIfErr(runCopy(db, *inputConf, *inputTable, targetTable, *truncate), "Issue running copy")
		// DON'T NEED TO CREATE VIEWS - will be handled by the refresh script
		log.Printf("done with table: %s.%s", inputConf.Schema, t)
	}
	log.Println("done with full run")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"os"
	"pfi/sensorbee/sensorbee/client"
	"pfi/sensorbee/sensorbee/server"
	"time"
)

type commandGenerator func() cli.Command

func init() {
	// TODO
	time.Local = time.UTC
}

func main() {
	app := setUpApp([]commandGenerator{
		server.SetUpRunCommand,
		client.SetUpCMDLineToolCommand,
	})

	// TODO plugin registration and logging
	/*
		if err := plugin.Register(); err != nil {
			fmt.Println("plugin registration error")
			return
		}
	*/

	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}

func setUpApp(cmds []commandGenerator) *cli.App {
	app := cli.NewApp()
	app.Name = "sensorbee"
	app.Usage = "SenserBee"
	app.Version = "0.0.1" // TODO get dynamic, will be get from external file
	app.Flags = []cli.Flag{
		cli.StringFlag{ // TODO get configuration from external file
			Name:   "config, c",
			Value:  "/etc/sersorbee/sensorbee.config",
			Usage:  "path to the config file",
			EnvVar: "SENSORBEE_CONFIG",
		},
	}
	app.Before = appBeforeHook

	for _, c := range cmds {
		app.Commands = append(app.Commands, c())
	}
	return app
}

func appBeforeHook(c *cli.Context) error {
	if err := loadConfig(c); err != nil {
		return err
	}
	return nil
}

func loadConfig(c *cli.Context) error {
	// TODO load configuration file (YAML)
	return nil
}
<commit_msg>remove comment outed code that register scouter pluing<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"os"
	// _ "pfi/scouter-snippets/plugin"
	"pfi/sensorbee/sensorbee/client"
	"pfi/sensorbee/sensorbee/server"
	"time"
)

type commandGenerator func() cli.Command

func init() {
	// TODO
	time.Local = time.UTC
}

func main() {
	app := setUpApp([]commandGenerator{
		server.SetUpRunCommand,
		client.SetUpCMDLineToolCommand,
	})

	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}

func setUpApp(cmds []commandGenerator) *cli.App {
	app := cli.NewApp()
	app.Name = "sensorbee"
	app.Usage = "SenserBee"
	app.Version = "0.0.1" // TODO get dynamic, will be get from external file
	app.Flags = []cli.Flag{
		cli.StringFlag{ // TODO get configuration from external file
			Name:   "config, c",
			Value:  "/etc/sersorbee/sensorbee.config",
			Usage:  "path to the config file",
			EnvVar: "SENSORBEE_CONFIG",
		},
	}
	app.Before = appBeforeHook

	for _, c := range cmds {
		app.Commands = append(app.Commands, c())
	}
	return app
}

func appBeforeHook(c *cli.Context) error {
	if err := loadConfig(c); err != nil {
		return err
	}
	return nil
}

func loadConfig(c *cli.Context) error {
	// TODO load configuration file (YAML)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sort"
	"sync"
	"time"

	"github.com/Impyy/tox4go/bootstrap"
	"github.com/Impyy/tox4go/crypto"
	"github.com/Impyy/tox4go/dht"
	"github.com/Impyy/tox4go/dht/ping"
	"github.com/Impyy/tox4go/relay"
	"github.com/Impyy/tox4go/transport"
)

const (
	probeRate   = 1 * time.Minute
	refreshRate = 5 * time.Minute
)

var (
	lastScan     int64
	lastRefresh  int64
	udpTransport *transport.UDPTransport
	tcpTransport *transport.TCPTransport
	ident        *dht.Ident
	nodes        = []*toxNode{}
	nodesMutex   = sync.Mutex{}
	tcpPorts     = []int{443, 3389, 33445}
	pings        = new(ping.Collection)
	pingsMutex   = sync.Mutex{}
)

func init() {
	var err error
	ident, err = dht.NewIdent()
	if err != nil {
		panic(err)
	}

	udpTransport, err = transport.NewUDPTransport("udp", ":33450")
	if err != nil {
		panic(err)
	}
	udpTransport.Handle(dht.PacketIDSendNodes, handleSendNodesPacket)
	udpTransport.Handle(bootstrap.PacketIDBootstrapInfo, handleBootstrapInfoPacket)

	/*tcpTransport, err = transport.NewTCPTransport("tcp", ":33450")
	if err != nil {
		panic(err)
	}*/
}

func main() {
	if parseFlags() {
		return
	}

	if err := loadCountries(); err != nil {
		log.Fatalf("error loading countries.json: %s", err.Error())
	}

	//handle stop signal
	interruptChan := make(chan os.Signal)
	signal.Notify(interruptChan, os.Interrupt)

	//setup http server
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", httpListenPort))
	if err != nil {
		log.Fatalf("error in net.Listen: %s", err.Error())
	}
	serveMux := http.NewServeMux()
	serveMux.HandleFunc("/", handleHTTPRequest)
	serveMux.HandleFunc("/json", handleJSONRequest)
	go func() {
		err := http.Serve(listener, serveMux)
		if err != nil {
			log.Printf("http server error: %s\n", err.Error())
			interruptChan <- os.Interrupt
		}
	}()

	//listen for tox packets
	go func() {
		err := udpTransport.Listen()
		if err != nil {
			log.Printf("udp transport error: %s\n", err.Error())
			interruptChan <- os.Interrupt
		}
	}()
	//go tcpTransport.Listen()

	err = refreshNodes()
	if err != nil {
		log.Fatal(err.Error())
	}
	probeNodes()

	probeTicker := time.NewTicker(probeRate)
	refreshTicker := time.NewTicker(refreshRate)
	updateTicker := time.NewTicker(30 * time.Second)
	run := true

	for run {
		select {
		case <-interruptChan:
			fmt.Printf("killing routines\n")
			probeTicker.Stop()
			refreshTicker.Stop()
			updateTicker.Stop()
			udpTransport.Stop()
			//tcpTransport.Stop()
			listener.Close()
			run = false
		case <-probeTicker.C:
			// we want an empty ping list at the start of every probe
			pingsMutex.Lock()
			pings.Clear(false)
			pingsMutex.Unlock()

			nodesMutex.Lock()
			err := probeNodes()
			nodesMutex.Unlock()
			if err != nil {
				log.Printf("error while trying to probe nodes: %s", err.Error())
			}
		case <-refreshTicker.C:
			err := refreshNodes()
			if err != nil {
				log.Printf("error while trying to refresh nodes: %s", err.Error())
			}
		case <-updateTicker.C:
			pingsMutex.Lock()
			pings.Clear(true)
			pingsMutex.Unlock()

			nodesMutex.Lock()
			for _, node := range nodes {
				if time.Now().Sub(time.Unix(node.LastPing, 0)) > time.Minute*2 {
					node.UDPStatus = false
				}
			}
			sort.Stable(nodeSlice(nodes))
			nodesMutex.Unlock()
		}
	}
}

func refreshNodes() error {
	parsedNodes, err := parseNodes()
	if err != nil {
		return err
	}

	nodesMutex.Lock()
	for _, freshNode := range parsedNodes {
		found := false
		for i, node := range nodes {
			if freshNode.PublicKey == node.PublicKey {
				freshNode.LastPing = node.LastPing
				freshNode.UDPStatus = node.UDPStatus
				freshNode.TCPStatus = node.TCPStatus
				freshNode.TCPPorts = node.TCPPorts
				freshNode.MOTD = node.MOTD
				freshNode.Version = node.Version
				nodes[i] = freshNode
				found = true
				break
			}
		}

		if !found {
			nodes = append(nodes, freshNode)
		}
	}
	sort.Stable(nodeSlice(nodes))
	nodesMutex.Unlock()

	lastRefresh = time.Now().Unix()
	return nil
}

func probeNodes() error {
	for _, node := range nodes {
		err := getBootstrapInfo(node)
		if err != nil {
			fmt.Println(err.Error())
		}

		err = getNodes(node)
		if err != nil {
			fmt.Println(err.Error())
		}

		ports := tcpPorts
		exists := false
		for _, i := range ports {
			if i == node.Port {
				exists = true
			}
		}
		if !exists {
			ports = append(ports, node.Port)
		}

		go probeNodeTCPPorts(node, ports)
	}

	lastScan = time.Now().Unix()
	return nil
}

func probeNodeTCPPorts(node *toxNode, ports []int) {
	c := make(chan int)
	for _, port := range ports {
		go func(p int) {
			conn, err := connectTCP(node, p)
			if err != nil {
				fmt.Printf("%s\n", err.Error())
				c <- -1
			} else {
				err := tcpHandshake(node, conn)
				if err != nil {
					fmt.Printf("%s\n", err.Error())
					c <- -1
				} else {
					c <- p
				}
			}
		}(port)
	}

	nodesMutex.Lock()
	node.TCPPorts = []int{}

	for i := 0; i < len(ports); i++ {
		port := <-c
		if port != -1 {
			fmt.Printf("tcp port for %s: %d\n", node.Maintainer, port)
			node.TCPPorts = append(node.TCPPorts, port)
		}
	}
	if len(node.TCPPorts) > 0 {
		node.LastPing = time.Now().Unix()
	}
	node.TCPStatus = len(node.TCPPorts) > 0
	sort.Stable(nodeSlice(nodes))
	nodesMutex.Unlock()
}

func tcpHandshake(node *toxNode, conn *net.TCPConn) error {
	nodePublicKey := new([crypto.PublicKeySize]byte)
	decPublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}
	copy(nodePublicKey[:], decPublicKey)

	relayConn, err := relay.NewConnection()
	if err != nil {
		return err
	}

	req, err := relayConn.StartHandshake()
	if err != nil {
		return err
	}

	reqBytes, err := req.MarshalBinary()
	if err != nil {
		return err
	}

	encryptedReqBytes, nonce, err := ident.EncryptBlob(reqBytes, nodePublicKey)
	if err != nil {
		return err
	}

	reqPacket := &relay.HandshakeRequestPacket{
		PublicKey: ident.PublicKey,
		Nonce:     nonce,
		Payload:   encryptedReqBytes,
	}

	reqPacketBytes, err := reqPacket.MarshalBinary()
	if err != nil {
		return err
	}

	conn.SetReadDeadline(time.Now().Add(2 * time.Second))
	_, err = conn.Write(reqPacketBytes)
	if err != nil {
		return err
	}

	buffer := make([]byte, 96)
	left := len(buffer)
	for left > 0 {
		read, readErr := conn.Read(buffer[len(buffer)-left:])
		if readErr != nil {
			return readErr
		}
		left -= read
	}

	res := relay.HandshakeResponsePacket{}
	err = res.UnmarshalBinary(buffer)
	if err != nil {
		return err
	}

	decryptedBytes, err := ident.DecryptBlob(res.Payload, nodePublicKey, res.Nonce)
	if err != nil {
		return err
	}

	resPacket := &relay.HandshakePayload{}
	err = resPacket.UnmarshalBinary(decryptedBytes)
	if err != nil {
		return err
	}

	return relayConn.EndHandshake(resPacket)
}

func getNodes(node *toxNode) error {
	nodePublicKey := new([crypto.PublicKeySize]byte)
	decPublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}
	copy(nodePublicKey[:], decPublicKey)

	ping, err := pings.AddNew(nodePublicKey)
	if err != nil {
		return err
	}

	packet := &dht.GetNodesPacket{
		PublicKey: ident.PublicKey,
		PingID:    ping.ID,
	}

	dhtPacket, err := ident.EncryptPacket(transport.Packet(packet), nodePublicKey)
	if err != nil {
		return err
	}

	payload, err := dhtPacket.MarshalBinary()
	if err != nil {
		return err
	}

	return sendToUDP(payload, node)
}

func getBootstrapInfo(node *toxNode) error {
	packet, err := bootstrap.ConstructPacket(&bootstrap.InfoRequestPacket{})
	if err != nil {
		return err
	}

	payload, err := packet.MarshalBinary()
	if err != nil {
		return err
	}

	return sendToUDP(payload, node)
}

func sendToUDP(data []byte, node *toxNode) error {
	addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", node.Ipv4Address, node.Port))
	if err != nil {
		return err
	}

	return udpTransport.Send(
		&transport.Message{
			Data: data,
			Addr: &net.UDPAddr{
				IP:   addr.IP,
				Port: node.Port,
			},
		},
	)
}

func connectTCP(node *toxNode, port int) (*net.TCPConn, error) {
	dialer := net.Dialer{}
	dialer.Deadline = time.Now().Add(2 * time.Second)

	tempConn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", node.Ipv4Address, port))
	if err != nil {
		return nil, err
	}

	conn, ok := tempConn.(*net.TCPConn)
	if !ok {
		return nil, errors.New("not a tcp conn")
	}

	return conn, nil
}

func handleSendNodesPacket(msg *transport.Message) error {
	dhtPacket := &dht.Packet{}
	err := dhtPacket.UnmarshalBinary(msg.Data)
	if err != nil {
		return err
	}

	decryptedPacket, err := ident.DecryptPacket(dhtPacket)
	if err != nil {
		return err
	}

	packet, ok := decryptedPacket.(*dht.SendNodesPacket)
	if !ok {
		return nil
	}

	pingsMutex.Lock()
	nodesMutex.Lock()
	if pings.Find(dhtPacket.SenderPublicKey, packet.PingID, true) != nil {
		for _, node := range nodes {
			publicKey, err := hex.DecodeString(node.PublicKey)
			if err != nil {
				continue
			}

			if bytes.Equal(publicKey, dhtPacket.SenderPublicKey[:]) {
				node.UDPStatus = true
				node.LastPing = time.Now().Unix()
				break
			}
		}
	}
	sort.Stable(nodeSlice(nodes))
	pingsMutex.Unlock()
	nodesMutex.Unlock()

	return nil
}

func handleBootstrapInfoPacket(msg *transport.Message) error {
	bootstrapPacket := &bootstrap.Packet{}
	err := bootstrapPacket.UnmarshalBinary(msg.Data)
	if err != nil {
		return err
	}

	transPacket, err := bootstrap.DestructPacket(bootstrapPacket)
	if err != nil {
		return err
	}

	packet, ok := transPacket.(*bootstrap.InfoResponsePacket)
	if !ok {
		return errors.New("wtf")
	}

	nodesMutex.Lock()
	for _, node := range nodes {
		if node.Ipv4Address == msg.Addr.IP.String() ||
			node.Ipv6Address == msg.Addr.IP.String() {
			node.MOTD = packet.MOTD
			node.Version = fmt.Sprintf("%d", packet.Version)
			break
		}
	}
	nodesMutex.Unlock()

	return nil
}
<commit_msg>Don't forget to close the connection handles<commit_after>package main

import (
	"bytes"
	"encoding/hex"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sort"
	"sync"
	"time"

	"github.com/Impyy/tox4go/bootstrap"
	"github.com/Impyy/tox4go/crypto"
	"github.com/Impyy/tox4go/dht"
	"github.com/Impyy/tox4go/dht/ping"
	"github.com/Impyy/tox4go/relay"
	"github.com/Impyy/tox4go/transport"
)

const (
	probeRate   = 1 * time.Minute
	refreshRate = 5 * time.Minute
)

var (
	lastScan     int64
	lastRefresh  int64
	udpTransport *transport.UDPTransport
	tcpTransport *transport.TCPTransport
	ident        *dht.Ident
	nodes        = []*toxNode{}
	nodesMutex   = sync.Mutex{}
	tcpPorts     = []int{443, 3389, 33445}
	pings        = new(ping.Collection)
	pingsMutex   = sync.Mutex{}
)

func init() {
	var err error
	ident, err = dht.NewIdent()
	if err != nil {
		panic(err)
	}

	udpTransport, err = transport.NewUDPTransport("udp", ":33450")
	if err != nil {
		panic(err)
	}
	udpTransport.Handle(dht.PacketIDSendNodes, handleSendNodesPacket)
	udpTransport.Handle(bootstrap.PacketIDBootstrapInfo, handleBootstrapInfoPacket)

	/*tcpTransport, err = transport.NewTCPTransport("tcp", ":33450")
	if err != nil {
		panic(err)
	}*/
}

func main() {
	if parseFlags() {
		return
	}

	if err := loadCountries(); err != nil {
		log.Fatalf("error loading countries.json: %s", err.Error())
	}

	//handle stop signal
	interruptChan := make(chan os.Signal)
	signal.Notify(interruptChan, os.Interrupt)

	//setup http server
	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", httpListenPort))
	if err != nil {
		log.Fatalf("error in net.Listen: %s", err.Error())
	}
	serveMux := http.NewServeMux()
	serveMux.HandleFunc("/", handleHTTPRequest)
	serveMux.HandleFunc("/json", handleJSONRequest)
	go func() {
		err := http.Serve(listener, serveMux)
		if err != nil {
			log.Printf("http server error: %s\n", err.Error())
			interruptChan <- os.Interrupt
		}
	}()

	//listen for tox packets
	go func() {
		err := udpTransport.Listen()
		if err != nil {
			log.Printf("udp transport error: %s\n", err.Error())
			interruptChan <- os.Interrupt
		}
	}()
	//go tcpTransport.Listen()

	err = refreshNodes()
	if err != nil {
		log.Fatal(err.Error())
	}
	probeNodes()

	probeTicker := time.NewTicker(probeRate)
	refreshTicker := time.NewTicker(refreshRate)
	updateTicker := time.NewTicker(30 * time.Second)
	run := true

	for run {
		select {
		case <-interruptChan:
			fmt.Printf("killing routines\n")
			probeTicker.Stop()
			refreshTicker.Stop()
			updateTicker.Stop()
			udpTransport.Stop()
			//tcpTransport.Stop()
			listener.Close()
			run = false
		case <-probeTicker.C:
			// we want an empty ping list at the start of every probe
			pingsMutex.Lock()
			pings.Clear(false)
			pingsMutex.Unlock()

			nodesMutex.Lock()
			err := probeNodes()
			nodesMutex.Unlock()
			if err != nil {
				log.Printf("error while trying to probe nodes: %s", err.Error())
			}
		case <-refreshTicker.C:
			err := refreshNodes()
			if err != nil {
				log.Printf("error while trying to refresh nodes: %s", err.Error())
			}
		case <-updateTicker.C:
			pingsMutex.Lock()
			pings.Clear(true)
			pingsMutex.Unlock()

			nodesMutex.Lock()
			for _, node := range nodes {
				if time.Now().Sub(time.Unix(node.LastPing, 0)) > time.Minute*2 {
					node.UDPStatus = false
				}
			}
			sort.Stable(nodeSlice(nodes))
			nodesMutex.Unlock()
		}
	}
}

func refreshNodes() error {
	parsedNodes, err := parseNodes()
	if err != nil {
		return err
	}

	nodesMutex.Lock()
	for _, freshNode := range parsedNodes {
		found := false
		for i, node := range nodes {
			if freshNode.PublicKey == node.PublicKey {
				freshNode.LastPing = node.LastPing
				freshNode.UDPStatus = node.UDPStatus
				freshNode.TCPStatus = node.TCPStatus
				freshNode.TCPPorts = node.TCPPorts
				freshNode.MOTD = node.MOTD
				freshNode.Version = node.Version
				nodes[i] = freshNode
				found = true
				break
			}
		}

		if !found {
			nodes = append(nodes, freshNode)
		}
	}
	sort.Stable(nodeSlice(nodes))
	nodesMutex.Unlock()

	lastRefresh = time.Now().Unix()
	return nil
}

func probeNodes() error {
	for _, node := range nodes {
		err := getBootstrapInfo(node)
		if err != nil {
			fmt.Println(err.Error())
		}

		err = getNodes(node)
		if err != nil {
			fmt.Println(err.Error())
		}

		ports := tcpPorts
		exists := false
		for _, i := range ports {
			if i == node.Port {
				exists = true
			}
		}
		if !exists {
			ports = append(ports, node.Port)
		}

		go probeNodeTCPPorts(node, ports)
	}

	lastScan = time.Now().Unix()
	return nil
}

func probeNodeTCPPorts(node *toxNode, ports []int) {
	c := make(chan int)
	for _, port := range ports {
		go func(p int) {
			conn, err := connectTCP(node, p)
			if err != nil {
				fmt.Printf("%s\n", err.Error())
				c <- -1
				return
			}

			err = tcpHandshake(node, conn)
			if err != nil {
				fmt.Printf("%s\n", err.Error())
				c <- -1
			} else {
				c <- p
			}
			conn.Close()
		}(port)
	}

	nodesMutex.Lock()
	node.TCPPorts = []int{}

	for i := 0; i < len(ports); i++ {
		port := <-c
		if port != -1 {
			fmt.Printf("tcp port for %s: %d\n", node.Maintainer, port)
			node.TCPPorts = append(node.TCPPorts, port)
		}
	}
	if len(node.TCPPorts) > 0 {
		node.LastPing = time.Now().Unix()
	}
	node.TCPStatus = len(node.TCPPorts) > 0
	sort.Stable(nodeSlice(nodes))
	nodesMutex.Unlock()
}

func tcpHandshake(node *toxNode, conn *net.TCPConn) error {
	nodePublicKey := new([crypto.PublicKeySize]byte)
	decPublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}
	copy(nodePublicKey[:], decPublicKey)

	relayConn, err := relay.NewConnection()
	if err != nil {
		return err
	}

	req, err := relayConn.StartHandshake()
	if err != nil {
		return err
	}

	reqBytes, err := req.MarshalBinary()
	if err != nil {
		return err
	}

	encryptedReqBytes, nonce, err := ident.EncryptBlob(reqBytes, nodePublicKey)
	if err != nil {
		return err
	}

	reqPacket := &relay.HandshakeRequestPacket{
		PublicKey: ident.PublicKey,
		Nonce:     nonce,
		Payload:   encryptedReqBytes,
	}

	reqPacketBytes, err := reqPacket.MarshalBinary()
	if err != nil {
		return err
	}

	conn.SetReadDeadline(time.Now().Add(2 * time.Second))
	_, err = conn.Write(reqPacketBytes)
	if err != nil {
		return err
	}

	buffer := make([]byte, 96)
	left := len(buffer)
	for left > 0 {
		read, readErr := conn.Read(buffer[len(buffer)-left:])
		if readErr != nil {
			return readErr
		}
		left -= read
	}

	res := relay.HandshakeResponsePacket{}
	err = res.UnmarshalBinary(buffer)
	if err != nil {
		return err
	}

	decryptedBytes, err := ident.DecryptBlob(res.Payload, nodePublicKey, res.Nonce)
	if err != nil {
		return err
	}

	resPacket := &relay.HandshakePayload{}
	err = resPacket.UnmarshalBinary(decryptedBytes)
	if err != nil {
		return err
	}

	return relayConn.EndHandshake(resPacket)
}

func getNodes(node *toxNode) error {
	nodePublicKey := new([crypto.PublicKeySize]byte)
	decPublicKey, err := hex.DecodeString(node.PublicKey)
	if err != nil {
		return err
	}
	copy(nodePublicKey[:], decPublicKey)

	ping, err := pings.AddNew(nodePublicKey)
	if err != nil {
		return err
	}

	packet := &dht.GetNodesPacket{
		PublicKey: ident.PublicKey,
		PingID:    ping.ID,
	}

	dhtPacket, err := ident.EncryptPacket(transport.Packet(packet), nodePublicKey)
	if err != nil {
		return err
	}

	payload, err := dhtPacket.MarshalBinary()
	if err != nil {
		return err
	}

	return sendToUDP(payload, node)
}

func getBootstrapInfo(node *toxNode) error {
	packet, err := bootstrap.ConstructPacket(&bootstrap.InfoRequestPacket{})
	if err != nil {
		return err
	}

	payload, err := packet.MarshalBinary()
	if err != nil {
		return err
	}

	return sendToUDP(payload, node)
}

func sendToUDP(data []byte, node *toxNode) error {
	addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", node.Ipv4Address, node.Port))
	if err != nil {
		return err
	}

	return udpTransport.Send(
		&transport.Message{
			Data: data,
			Addr: &net.UDPAddr{
				IP:   addr.IP,
				Port: node.Port,
			},
		},
	)
}

func connectTCP(node *toxNode, port int) (*net.TCPConn, error) {
	dialer := net.Dialer{}
	dialer.Deadline = time.Now().Add(2 * time.Second)

	tempConn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", node.Ipv4Address, port))
	if err != nil {
		return nil, err
	}

	conn, ok := tempConn.(*net.TCPConn)
	if !ok {
		return nil, errors.New("not a tcp conn")
	}

	return conn, nil
}

func handleSendNodesPacket(msg *transport.Message) error {
	dhtPacket := &dht.Packet{}
	err := dhtPacket.UnmarshalBinary(msg.Data)
	if err != nil {
		return err
	}

	decryptedPacket, err := ident.DecryptPacket(dhtPacket)
	if err != nil {
		return err
	}

	packet, ok := decryptedPacket.(*dht.SendNodesPacket)
	if !ok {
		return nil
	}

	pingsMutex.Lock()
	nodesMutex.Lock()
	if pings.Find(dhtPacket.SenderPublicKey, packet.PingID, true) != nil {
		for _, node := range nodes {
			publicKey, err := hex.DecodeString(node.PublicKey)
			if err != nil {
				continue
			}

			if bytes.Equal(publicKey, dhtPacket.SenderPublicKey[:]) {
				node.UDPStatus = true
				node.LastPing = time.Now().Unix()
				break
			}
		}
	}
	sort.Stable(nodeSlice(nodes))
	pingsMutex.Unlock()
	nodesMutex.Unlock()

	return nil
}

func handleBootstrapInfoPacket(msg *transport.Message) error {
	bootstrapPacket := &bootstrap.Packet{}
	err := bootstrapPacket.UnmarshalBinary(msg.Data)
	if err != nil {
		return err
	}

	transPacket, err := bootstrap.DestructPacket(bootstrapPacket)
	if err != nil {
		return err
	}

	packet, ok := transPacket.(*bootstrap.InfoResponsePacket)
	if !ok {
		return errors.New("wtf")
	}

	nodesMutex.Lock()
	for _, node := range nodes {
		if node.Ipv4Address == msg.Addr.IP.String() ||
			node.Ipv6Address == msg.Addr.IP.String() {
			node.MOTD = packet.MOTD
			node.Version = fmt.Sprintf("%d", packet.Version)
			break
		}
	}
	nodesMutex.Unlock()

	return nil
}
<|endoftext|>


<commit_before>package http

import "net/http"

// RequestData holds http.ResponseWriter and http.Request
type RequestData struct {
	responseWriter http.ResponseWriter
	request        *http.Request
	params         []string
}
<commit_msg>remove unused<commit_after><|endoftext|>


<commit_before>// +build s3test

package s3

import (
	"bytes"
	"github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"testing"

	. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }

type TestSuite struct {
	service S3Service
}

var _ = Suite(&TestSuite{})

const (
	ENV_TEST_AWS_ACCESS_KEY = "RANCHER_TEST_AWS_ACCESS_KEY_ID"
	ENV_TEST_AWS_SECRET_KEY = "RANCHER_TEST_AWS_SECRET_ACCESS_KEY"
	ENV_TEST_AWS_REGION     = "RANCHER_TEST_AWS_REGION"
	ENV_TEST_AWS_BUCKET     = "RANCHER_TEST_AWS_BUCKET"
)

func (s *TestSuite) SetUpSuite(c *C) {
	logrus.SetLevel(logrus.DebugLevel)
	logrus.SetOutput(os.Stderr)

	s.service.Keys.AccessKey = os.Getenv(ENV_TEST_AWS_ACCESS_KEY)
	s.service.Keys.SecretKey = os.Getenv(ENV_TEST_AWS_SECRET_KEY)
	s.service.Region = os.Getenv(ENV_TEST_AWS_REGION)
	s.service.Bucket = os.Getenv(ENV_TEST_AWS_BUCKET)

	c.Assert(s.service.Keys.AccessKey, Not(Equals), "")
	c.Assert(s.service.Keys.SecretKey, Not(Equals), "")
	c.Assert(s.service.Region, Not(Equals), "")
	c.Assert(s.service.Bucket, Not(Equals), "")
}

func (s *TestSuite) TestFuncs(c *C) {
	var err error
	body := []byte("this is only a test file")

	key := "test_file"
	key1 := "test_file_1"
	key2 := "test_file_2"

	err = s.service.PutObject(key1, bytes.NewReader(body))
	c.Assert(err, IsNil)
	err = s.service.PutObject(key2, bytes.NewReader(body))
	c.Assert(err, IsNil)

	objs, err := s.service.ListObjects(key)
	c.Assert(err, IsNil)
	c.Assert(objs, HasLen, 2)

	r, err := s.service.GetObject(key1)
	c.Assert(err, IsNil)

	newBody, err := ioutil.ReadAll(r)
	c.Assert(err, IsNil)
	c.Assert(newBody, DeepEquals, body)

	err = s.service.DeleteObjects([]string{key})
	c.Assert(err, IsNil)

	objs, err = s.service.ListObjects(key)
	c.Assert(err, IsNil)
	c.Assert(objs, HasLen, 0)
}
<commit_msg>s3: Enable s3 test in CI<commit_after>package s3

import (
	"bytes"
	"github.com/Sirupsen/logrus"
	"io/ioutil"
	"os"
	"testing"

	. "gopkg.in/check.v1"
)

func Test(t *testing.T) { TestingT(t) }

type TestSuite struct {
	service S3Service
}

var _ = Suite(&TestSuite{})

const (
	ENV_TEST_AWS_ACCESS_KEY = "RANCHER_TEST_AWS_ACCESS_KEY_ID"
	ENV_TEST_AWS_SECRET_KEY = "RANCHER_TEST_AWS_SECRET_ACCESS_KEY"
	ENV_TEST_AWS_REGION     = "RANCHER_TEST_AWS_REGION"
	ENV_TEST_AWS_BUCKET     = "RANCHER_TEST_AWS_BUCKET"
)

func (s *TestSuite) SetUpSuite(c *C) {
	logrus.SetLevel(logrus.DebugLevel)
	logrus.SetOutput(os.Stderr)

	s.service.Keys.AccessKey = os.Getenv(ENV_TEST_AWS_ACCESS_KEY)
	s.service.Keys.SecretKey = os.Getenv(ENV_TEST_AWS_SECRET_KEY)
	s.service.Region = os.Getenv(ENV_TEST_AWS_REGION)
	s.service.Bucket = os.Getenv(ENV_TEST_AWS_BUCKET)

	c.Assert(s.service.Keys.AccessKey, Not(Equals), "")
	c.Assert(s.service.Keys.SecretKey, Not(Equals), "")
	c.Assert(s.service.Region, Not(Equals), "")
	c.Assert(s.service.Bucket, Not(Equals), "")
}

func (s *TestSuite) TestFuncs(c *C) {
	var err error
	body := []byte("this is only a test file")

	key := "test_file"
	key1 := "test_file_1"
	key2 := "test_file_2"

	err = s.service.PutObject(key1, bytes.NewReader(body))
	c.Assert(err, IsNil)
	err = s.service.PutObject(key2, bytes.NewReader(body))
	c.Assert(err, IsNil)

	objs, err := s.service.ListObjects(key)
	c.Assert(err, IsNil)
	c.Assert(objs, HasLen, 2)

	r, err := s.service.GetObject(key1)
	c.Assert(err, IsNil)

	newBody, err := ioutil.ReadAll(r)
	c.Assert(err, IsNil)
	c.Assert(newBody, DeepEquals, body)

	err = s.service.DeleteObjects([]string{key})
	c.Assert(err, IsNil)

	objs, err = s.service.ListObjects(key)
	c.Assert(err, IsNil)
	c.Assert(objs, HasLen, 0)
}
<|endoftext|>


<commit_before>package gehirndns

import (
	"time"
)

type (
	IPv4        string
	IPv6        string
	HostName    string
	MailAddress string
	RecordId    string
	RecordType  string
	Seconds     int64
	Priority    uint64
)

func (s Seconds) Duration() time.Duration {
	return time.Duration(s) * time.Second
}

type IRecord interface {
	GetId() RecordId
	GetHostName() HostName
	GetType() RecordType
	GetTTL() Seconds
}

type record struct {
	Id       RecordId `json:"ID,omitempty"`
	Name     HostName `json:",omitempty"`
	HostName HostName
	Type     RecordType `json:"Type"`
	TTL      Seconds    `json:"TTL"`
}

func (r *record) GetId() RecordId {
	return r.Id
}

func (r *record) GetHostName() HostName {
	if len(r.Name) > 0 {
		return r.Name
	}

	return r.HostName
}

func (r *record) GetType() RecordType {
	return r.Type
}

func (r *record) GetTTL() Seconds {
	return r.TTL
}

type SOARecord struct {
	Mname            HostName    `json:"MNAME"`
	Rname            MailAddress `json:"RNAME"`
	Serial           uint
	Refresh          Seconds
	Retry            Seconds
	Expire           Seconds
	NegativeCacheTTL Seconds
	record
}

type NSRecord struct {
	NameServer HostName
	record
}

type ARecord struct {
	IPAddress IPv4 `json:"IPAddress"`
	record
}

type AAAARecord struct {
	IPAddress IPv6 `json:"IPAddress"`
	record
}

type CNAMERecord struct {
	AliasTo HostName `json:"AliasTo"`
	record
}

type MXRecord struct {
	MailServer HostName
	Priority   Priority
	record
}

type TXTRecord struct {
	Value string
	record
}

type SRVRecord struct {
	Priority Priority
	Weight   uint
	Port     uint
	Target   HostName
	record
}
<commit_msg>update IRecord interface and its implementation<commit_after>package gehirndns

import (
	"time"
)

type (
	IPv4        string
	IPv6        string
	HostName    string
	MailAddress string
	RecordType  string
	Priority    uint64
)

type Seconds int64

func (s Seconds) Duration() time.Duration {
	return time.Duration(s) * time.Second
}

type RecordId string

func (id RecordId) String() string {
	return string(id)
}

type IRecord interface {
	GetId() RecordId
	GetHostName() HostName
	SetHostName(HostName)
	GetName() HostName
	clearName()
	GetType() RecordType
	GetTTL() Seconds
	SetTTL(Seconds)
}

type record struct {
	Id       RecordId `json:"ID,omitempty"`
	Name     HostName `json:",omitempty"`
	HostName HostName
	Type     RecordType `json:"Type"`
	TTL      Seconds    `json:"TTL"`
}

func (r *record) GetId() RecordId {
	return r.Id
}

func (r *record) GetHostName() HostName {
	return r.HostName
}

func (r *record) SetHostName(name HostName) {
	r.HostName = name
}

func (r *record) GetName() HostName {
	return r.Name
}

func (r *record) clearName() {
	r.Name = ""
}

func (r *record) GetType() RecordType {
	return r.Type
}

func (r *record) GetTTL() Seconds {
	return r.TTL
}

func (r *record) SetTTL(ttl Seconds) {
	r.TTL = ttl
}

type SOARecord struct {
	Mname            HostName    `json:"MNAME"`
	Rname            MailAddress `json:"RNAME"`
	Serial           uint
	Refresh          Seconds
	Retry            Seconds
	Expire           Seconds
	NegativeCacheTTL Seconds
	record
}

type NSRecord struct {
	NameServer HostName
	record
}

type ARecord struct {
	IPAddress IPv4 `json:"IPAddress"`
	record
}

type AAAARecord struct {
	IPAddress IPv6 `json:"IPAddress"`
	record
}

type CNAMERecord struct {
	AliasTo HostName `json:"AliasTo"`
	record
}

type MXRecord struct {
	MailServer HostName
	Priority   Priority
	record
}

type TXTRecord struct {
	Value string
	record
}

type SRVRecord struct {
	Priority Priority
	Weight   uint
	Port     uint
	Target   HostName
	record
}
<|endoftext|>


<commit_before>// +build windows

package windows

import (
	"net"

	"github.com/mackerelio/golib/logging"
	"github.com/mackerelio/mackerel-agent/util/windows"
	mkr "github.com/mackerelio/mackerel-client-go"
)

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

var interfaceLogger = logging.GetLogger("spec.interface")

// Generate XXX
func (g *InterfaceGenerator) Generate() ([]mkr.Interface, error) {
	var results []mkr.Interface

	ifs, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	ai, err := windows.GetAdapterList()
	if err != nil {
		return nil, err
	}

	for _, ifi := range ifs {
		if ifi.Flags&net.FlagLoopback != 0 {
			continue
		}

		name := ifi.Name
		for ; ai != nil; ai = ai.Next {
			if ifi.Index == int(ai.Index) {
				s, err := windows.AnsiBytePtrToString(&ai.Description[0])
				if err == nil && s != "" {
					name = s
				}
			}
		}

		addrs, err := ifi.Addrs()
		if err != nil {
			return nil, err
		}
		ipv4Addresses := []string{}
		ipv6Addresses := []string{}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPAddr:
				ip = v.IP
			case *net.IPNet:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			if ipv4 := ip.To4(); ipv4 != nil {
				ipv4Addresses = append(ipv4Addresses, ipv4.String())
				continue
			}
			if ipv6 := ip.To16(); ipv6 != nil {
				ipv6Addresses = append(ipv6Addresses, ipv6.String())
			}
		}

		if len(ipv4Addresses) > 0 || len(ipv6Addresses) > 0 {
			results = append(results, mkr.Interface{
				Name:          name,
				IPv4Addresses: ipv4Addresses,
				IPv6Addresses: ipv6Addresses,
				MacAddress:    ifi.HardwareAddr.String(),
			})
		}
	}
	return results, nil
}
<commit_msg>spec/windows: skip unnamed network interface<commit_after>// +build windows

package windows

import (
	"net"

	"github.com/mackerelio/golib/logging"
	"github.com/mackerelio/mackerel-agent/util/windows"
	mkr "github.com/mackerelio/mackerel-client-go"
)

// InterfaceGenerator XXX
type InterfaceGenerator struct {
}

var interfaceLogger = logging.GetLogger("spec.interface")

// Generate XXX
func (g *InterfaceGenerator) Generate() ([]mkr.Interface, error) {
	var results []mkr.Interface

	ifs, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	ai, err := windows.GetAdapterList()
	if err != nil {
		return nil, err
	}

	for _, ifi := range ifs {
		if ifi.Flags&net.FlagLoopback != 0 {
			continue
		}

		// XXX occur mojibake when containing multi-byte strings
		name := ifi.Name
		for ; ai != nil; ai = ai.Next {
			if ifi.Index == int(ai.Index) {
				name = windows.BytePtrToString(&ai.Description[0])
			}
		}
		if name == "" {
			continue
		}

		addrs, err := ifi.Addrs()
		if err != nil {
			return nil, err
		}
		ipv4Addresses := []string{}
		ipv6Addresses := []string{}
		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPAddr:
				ip = v.IP
			case *net.IPNet:
				ip = v.IP
			}
			if ip == nil || ip.IsLoopback() {
				continue
			}
			if ipv4 := ip.To4(); ipv4 != nil {
				ipv4Addresses = append(ipv4Addresses, ipv4.String())
				continue
			}
			if ipv6 := ip.To16(); ipv6 != nil {
				ipv6Addresses = append(ipv6Addresses, ipv6.String())
			}
		}

		if len(ipv4Addresses) > 0 || len(ipv6Addresses) > 0 {
			results = append(results, mkr.Interface{
				Name:          name,
				IPv4Addresses: ipv4Addresses,
				IPv6Addresses: ipv6Addresses,
				MacAddress:    ifi.HardwareAddr.String(),
			})
		}
	}
	return results, nil
}
<|endoftext|>


<commit_before>package finder

import (
	"os/exec"
	"io"
	"strings"
	"github.com/mpppk/hlb/service"
	"strconv"
)

type FilterStringer interface {
	FilterString() string
}

type Linker interface {
	GetURL() string
}

type FilterableURL struct {
	String string
	URL string
}

func (f *FilterableURL) GetURL() string{
	return f.URL
}

func (f *FilterableURL) FilterString() string{
	return f.String
}

type FilterableIssue struct {
	service.Issue
}

func (f *FilterableIssue) GetURL() string{
	return f.GetHTMLURL()
}

func (f *FilterableIssue) FilterString() string{
	return "#" + strconv.Itoa(f.GetNumber()) + " " + f.GetTitle()
}

func ToFilterableIssues(issues []service.Issue) (fis []*FilterableIssue) {
	for _, issue := range issues {
		fi := &FilterableIssue{Issue: issue}
		fis = append(fis, fi)
	}
	return fis
}

type FilterablePullRequest struct {
	service.PullRequest
}

func (f *FilterablePullRequest) GetURL() string{
	return f.GetHTMLURL()
}

func (f *FilterablePullRequest) FilterString() string{
	return "!" + strconv.Itoa(f.GetNumber()) + " " + f.GetTitle()
}

func ToFilterablePullRequests(pulls []service.PullRequest) (fis []*FilterablePullRequest) {
	for _, pull := range pulls {
		fp := &FilterablePullRequest{PullRequest: pull}
		fis = append(fis, fp)
	}
	return fis
}

func PipeToPeco(texts []string) (string, error) {
	cmd := exec.Command("peco")
	stdin, _ := cmd.StdinPipe()
	io.WriteString(stdin, strings.Join(texts, "\n"))
	stdin.Close()
	out, err := cmd.Output()

	if err != nil {
		return "", err
	}

	return strings.Trim(string(out), " \n"), nil
}

func Find(stringers []FilterStringer) ([]FilterStringer, error){
	strs := []string{}

	for _, stringer := range stringers {
		strs = append(strs, stringer.FilterString())
	}

	selectedStr, err := PipeToPeco(strs)
	if err != nil {
		return nil, err
	}

	selectedStringers := []FilterStringer{}
	for _, stringer := range stringers {
		if stringer.FilterString() == selectedStr {
			selectedStringers = append(selectedStringers, stringer)
		}
	}
	return selectedStringers, nil
}
<commit_msg>Ignore error if peco is exited by Esc key<commit_after>package finder

import (
	"os/exec"
	"io"
	"strings"
	"github.com/mpppk/hlb/service"
	"strconv"
)

type FilterStringer interface {
	FilterString() string
}

type Linker interface {
	GetURL() string
}

type FilterableURL struct {
	String string
	URL string
}

func (f *FilterableURL) GetURL() string{
	return f.URL
}

func (f *FilterableURL) FilterString() string{
	return f.String
}

type FilterableIssue struct {
	service.Issue
}

func (f *FilterableIssue) GetURL() string{
	return f.GetHTMLURL()
}

func (f *FilterableIssue) FilterString() string{
	return "#" + strconv.Itoa(f.GetNumber()) + " " + f.GetTitle()
}

func ToFilterableIssues(issues []service.Issue) (fis []*FilterableIssue) {
	for _, issue := range issues {
		fi := &FilterableIssue{Issue: issue}
		fis = append(fis, fi)
	}
	return fis
}

type FilterablePullRequest struct {
	service.PullRequest
}

func (f *FilterablePullRequest) GetURL() string{
	return f.GetHTMLURL()
}

func (f *FilterablePullRequest) FilterString() string{
	return "!" + strconv.Itoa(f.GetNumber()) + " " + f.GetTitle()
}

func ToFilterablePullRequests(pulls []service.PullRequest) (fis []*FilterablePullRequest) {
	for _, pull := range pulls {
		fp := &FilterablePullRequest{PullRequest: pull}
		fis = append(fis, fp)
	}
	return fis
}

func PipeToPeco(texts []string) (string, error) {
	cmd := exec.Command("peco")
	stdin, _ := cmd.StdinPipe()
	io.WriteString(stdin, strings.Join(texts, "\n"))
	stdin.Close()
	out, err := cmd.Output()

	// If peco is exited by Esc key, err return with exit status 1
	if err != nil && err.Error() != "exit status 1" {
		return "", err
	}

	return strings.Trim(string(out), " \n"), nil
}

func Find(stringers []FilterStringer) ([]FilterStringer, error){
	strs := []string{}

	for _, stringer := range stringers {
		strs = append(strs, stringer.FilterString())
	}

	selectedStr, err := PipeToPeco(strs)
	if err != nil {
		return nil, err
	}

	selectedStringers := []FilterStringer{}
	for _, stringer := range stringers {
		if stringer.FilterString() == selectedStr {
			selectedStringers = append(selectedStringers, stringer)
		}
	}
	return selectedStringers, nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sort"
	"github.com/lann/mpris2"
)

func main() {
	log.SetFlags(0)

	var playerName string
	flag.StringVar(&playerName, "player", "", "media player to control")
	flag.Parse()

	cmd := flag.Arg(0)
	if cmd == "" {
		log.Fatalf("Usage: %s [<options>] <cmd> [<params>]", os.Args[0])
	}

	conn, err := mpris2.Connect()
	if err != nil {
		log.Fatal(err)
	}

	if cmd == "list" {
		names, err := conn.ListMediaPlayers()
		if err != nil {
			log.Fatal(err)
		}

		for _, name := range names {
			fmt.Println(name)
		}
		os.Exit(0)
	}

	var mp *mpris2.MediaPlayer
	if playerName == "" {
		mp, err = conn.GetFirstMediaPlayer()
	} else {
		mp = conn.GetMediaPlayer(playerName)
	}

	if err != nil {
		log.Fatal(err)
	}

	switch cmd {
	case "play":
		err = mp.Play()
	case "pause":
		err = mp.Pause()
	case "playpause":
		err = mp.PlayPause()
	case "stop":
		err = mp.Stop()
	case "prev":
		err = mp.Previous()
	case "next":
		err = mp.Next()

	case "seek":
		if flag.NArg() != 2 {
			log.Fatalf("Usage: %s seek <offset>", os.Args[0])
		}

		var offset int64
		_, err = fmt.Sscan(flag.Arg(1), &offset)
		if err == nil {
			err = mp.Seek(offset)
		}

	case "open":
		if flag.NArg() != 2 {
			log.Fatalf("usage: %s open <uri>", os.Args[0])
		}

		err = mp.OpenUri(flag.Arg(1))

	case "identity":
		var identity string
		identity, err = mp.Identity()
		if err == nil {
			fmt.Println(identity)
		}

	case "desktop":
		var name string
		name, err = mp.DesktopEntry()
		if len(name) > 0 {
			fmt.Printf("/usr/share/applications/%s.desktop\n", name)
		}

	case "status":
		var status string
		status, err = mp.PlaybackStatus()
		if err == nil {
			fmt.Println(status)
		}

	case "pos":
		var pos int64
		pos, err = mp.Position()
		if err == nil {
			fmt.Println(pos)
		}

    case "metadata":
		var data mpris2.Metadata
		data, err = mp.Metadata()
		if err == nil {
			if flag.NArg() > 1 {
				for _, k := range flag.Args()[1:] {
					fmt.Println(data[k])
				}
			} else {
				keys := make([]string, len(data))
				i := 0
				maxLen := 0
				for k := range data {
					keys[i] = k
					i++
					if len(k) > maxLen {
						maxLen = len(k)
					}
				}

				sort.Strings(keys)

				for _, k := range keys {
					fmt.Printf("%-*s  %v\n", maxLen, k, data[k])
				}
			}
		}

	default:
		log.Fatalf("Unknown cmd %s", cmd)
	}

	if err != nil {
		log.Fatal(err)
	}

	return
}<commit_msg>Rename GetFirstMediaPlayer -> GetAnyMediaPlayer<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"sort"
	"github.com/lann/mpris2"
)

func main() {
	log.SetFlags(0)

	var playerName string
	flag.StringVar(&playerName, "player", "", "media player to control")
	flag.Parse()

	cmd := flag.Arg(0)
	if cmd == "" {
		log.Fatalf("Usage: %s [<options>] <cmd> [<params>]", os.Args[0])
	}

	conn, err := mpris2.Connect()
	if err != nil {
		log.Fatal(err)
	}

	if cmd == "list" {
		names, err := conn.ListMediaPlayers()
		if err != nil {
			log.Fatal(err)
		}

		for _, name := range names {
			fmt.Println(name)
		}
		os.Exit(0)
	}

	var mp *mpris2.MediaPlayer
	if playerName == "" {
		mp, err = conn.GetAnyMediaPlayer()
	} else {
		mp = conn.GetMediaPlayer(playerName)
	}

	if err != nil {
		log.Fatal(err)
	}

	switch cmd {
	case "play":
		err = mp.Play()
	case "pause":
		err = mp.Pause()
	case "playpause":
		err = mp.PlayPause()
	case "stop":
		err = mp.Stop()
	case "prev":
		err = mp.Previous()
	case "next":
		err = mp.Next()

	case "seek":
		if flag.NArg() != 2 {
			log.Fatalf("Usage: %s seek <offset>", os.Args[0])
		}

		var offset int64
		_, err = fmt.Sscan(flag.Arg(1), &offset)
		if err == nil {
			err = mp.Seek(offset)
		}

	case "open":
		if flag.NArg() != 2 {
			log.Fatalf("usage: %s open <uri>", os.Args[0])
		}

		err = mp.OpenUri(flag.Arg(1))

	case "identity":
		var identity string
		identity, err = mp.Identity()
		if err == nil {
			fmt.Println(identity)
		}

	case "desktop":
		var name string
		name, err = mp.DesktopEntry()
		if len(name) > 0 {
			fmt.Printf("/usr/share/applications/%s.desktop\n", name)
		}

	case "status":
		var status string
		status, err = mp.PlaybackStatus()
		if err == nil {
			fmt.Println(status)
		}

	case "pos":
		var pos int64
		pos, err = mp.Position()
		if err == nil {
			fmt.Println(pos)
		}

    case "metadata":
		var data mpris2.Metadata
		data, err = mp.Metadata()
		if err == nil {
			if flag.NArg() > 1 {
				for _, k := range flag.Args()[1:] {
					fmt.Println(data[k])
				}
			} else {
				keys := make([]string, len(data))
				i := 0
				maxLen := 0
				for k := range data {
					keys[i] = k
					i++
					if len(k) > maxLen {
						maxLen = len(k)
					}
				}

				sort.Strings(keys)

				for _, k := range keys {
					fmt.Printf("%-*s  %v\n", maxLen, k, data[k])
				}
			}
		}

	default:
		log.Fatalf("Unknown cmd %s", cmd)
	}

	if err != nil {
		log.Fatal(err)
	}

	return
}<|endoftext|>


<commit_before>package validation

import (
	"encoding/base64"
	"fmt"
	"regexp"
	"strings"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/structure"
)

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotEmpty(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if v == "" {
		return nil, []error{fmt.Errorf("expected %q to not be an empty string, got %v", k, i)}
	}

	return nil, nil
}

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotWhiteSpace(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if strings.TrimSpace(v) == "" {
		return nil, []error{fmt.Errorf("expected %q to not be an empty string or whitespace", k)}
	}

	return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string has no characters
func StringIsEmpty(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if v != "" {
		return nil, []error{fmt.Errorf("expected %q to be an empty string: got %v", k, v)}
	}

	return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string is composed of entirely whitespace
func StringIsWhiteSpace(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if strings.TrimSpace(v) != "" {
		return nil, []error{fmt.Errorf("expected %q to be an empty string or whitespace: got %v", k, v)}
	}

	return nil, nil
}

// StringLenBetween returns a SchemaValidateFunc which tests if the provided value
// is of type string and has length between min and max (inclusive)
func StringLenBetween(min, max int) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		if len(v) < min || len(v) > max {
			errors = append(errors, fmt.Errorf("expected length of %s to be in the range (%d - %d), got %s", k, min, max, v))
		}

		return warnings, errors
	}
}

// StringMatch returns a SchemaValidateFunc which tests if the provided value
// matches a given regexp. Optionally an error message can be provided to
// return something friendlier than "must match some globby regexp".
func StringMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) ([]string, []error) {
		v, ok := i.(string)
		if !ok {
			return nil, []error{fmt.Errorf("expected type of %s to be string", k)}
		}

		if ok := r.MatchString(v); !ok {
			if message != "" {
				return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)}

			}
			return nil, []error{fmt.Errorf("expected value of %s to match regular expression %q, got %v", k, r, i)}
		}
		return nil, nil
	}
}

// StringDoesNotMatch returns a SchemaValidateFunc which tests if the provided value
// does not match a given regexp. Optionally an error message can be provided to
// return something friendlier than "must not match some globby regexp".
func StringDoesNotMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) ([]string, []error) {
		v, ok := i.(string)
		if !ok {
			return nil, []error{fmt.Errorf("expected type of %s to be string", k)}
		}

		if ok := r.MatchString(v); ok {
			if message != "" {
				return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)}

			}
			return nil, []error{fmt.Errorf("expected value of %s to not match regular expression %q, got %v", k, r, i)}
		}
		return nil, nil
	}
}

// StringInSlice returns a SchemaValidateFunc which tests if the provided value
// is of type string and matches the value of an element in the valid slice
// will test with in lower case if ignoreCase is true
func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		for _, str := range valid {
			if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) {
				return warnings, errors
			}
		}

		errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, valid, v))
		return warnings, errors
	}
}

// StringDoesNotContainAny returns a SchemaValidateFunc which validates that the
// provided value does not contain any of the specified Unicode code points in chars.
func StringDoesNotContainAny(chars string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		if strings.ContainsAny(v, chars) {
			es = append(es, fmt.Errorf("expected value of %s to not contain any of %q, got %v", k, chars, i))
			return warnings, errors
		}

		return warnings, errors
	}
}

// StringIsBase64 is a ValidateFunc that ensures a string can be parsed as Base64
func StringIsBase64(i interface{}, k string) (warnings []string, errors []error) {
	// Empty string is not allowed
	if warnings, errors = StringIsNotEmpty(i, k); len(errors) > 0 {
		return
	}

	// NoEmptyStrings checks it is a string
	v, _ := i.(string)

	if _, err := base64.StdEncoding.DecodeString(v); err != nil {
		errors = append(errors, fmt.Errorf("expected %q to be a base64 string, got %v", k, v))
	}

	return warnings, errors
}

// ValidateJsonString is a SchemaValidateFunc which tests to make sure the
// supplied string is valid JSON.
//
// Deprecated: use StringIsJSON instead
func ValidateJsonString(i interface{}, k string) (warnings []string, errors []error) {
	return StringIsJSON(i, k)
}

// ValidateJsonString is a SchemaValidateFunc which tests to make sure the supplied string is valid JSON.
func StringIsJSON(i interface{}, k string) (warnings []string, errors []error) {
	v, ok := i.(string)
	if !ok {
		errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
		return warnings, errors
	}

	if _, err := structure.NormalizeJsonString(v); err != nil {
		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
	}

	return warnings, errors
}

// ValidateRegexp returns a SchemaValidateFunc which tests to make sure the
// supplied string is a valid regular expression.
func ValidateRegexp(i interface{}, k string) (warnings []string, errors []error) {
	return StringIsValidRegExp(i, k)
}

// ValidateRegexp returns a SchemaValidateFunc which tests to make sure the supplied string is a valid regular expression.
func StringIsValidRegExp(i interface{}, k string) (warnings []string, errors []error) {
	v, ok := i.(string)
	if !ok {
		errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
		return warnings, errors
	}

	if _, err := regexp.Compile(v); err != nil {
		errors = append(errors, fmt.Errorf("%q: %s", k, err))
	}

	return warnings, errors
}
<commit_msg>post merge cleanup<commit_after>package validation

import (
	"encoding/base64"
	"fmt"
	"regexp"
	"strings"

	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/helper/structure"
)

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotEmpty(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if v == "" {
		return nil, []error{fmt.Errorf("expected %q to not be an empty string, got %v", k, i)}
	}

	return nil, nil
}

// StringIsNotEmpty is a ValidateFunc that ensures a string is not empty or consisting entirely of whitespace characters
func StringIsNotWhiteSpace(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if strings.TrimSpace(v) == "" {
		return nil, []error{fmt.Errorf("expected %q to not be an empty string or whitespace", k)}
	}

	return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string has no characters
func StringIsEmpty(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if v != "" {
		return nil, []error{fmt.Errorf("expected %q to be an empty string: got %v", k, v)}
	}

	return nil, nil
}

// StringIsEmpty is a ValidateFunc that ensures a string is composed of entirely whitespace
func StringIsWhiteSpace(i interface{}, k string) ([]string, []error) {
	v, ok := i.(string)
	if !ok {
		return nil, []error{fmt.Errorf("expected type of %q to be string", k)}
	}

	if strings.TrimSpace(v) != "" {
		return nil, []error{fmt.Errorf("expected %q to be an empty string or whitespace: got %v", k, v)}
	}

	return nil, nil
}

// StringLenBetween returns a SchemaValidateFunc which tests if the provided value
// is of type string and has length between min and max (inclusive)
func StringLenBetween(min, max int) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		if len(v) < min || len(v) > max {
			errors = append(errors, fmt.Errorf("expected length of %s to be in the range (%d - %d), got %s", k, min, max, v))
		}

		return warnings, errors
	}
}

// StringMatch returns a SchemaValidateFunc which tests if the provided value
// matches a given regexp. Optionally an error message can be provided to
// return something friendlier than "must match some globby regexp".
func StringMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) ([]string, []error) {
		v, ok := i.(string)
		if !ok {
			return nil, []error{fmt.Errorf("expected type of %s to be string", k)}
		}

		if ok := r.MatchString(v); !ok {
			if message != "" {
				return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)}

			}
			return nil, []error{fmt.Errorf("expected value of %s to match regular expression %q, got %v", k, r, i)}
		}
		return nil, nil
	}
}

// StringDoesNotMatch returns a SchemaValidateFunc which tests if the provided value
// does not match a given regexp. Optionally an error message can be provided to
// return something friendlier than "must not match some globby regexp".
func StringDoesNotMatch(r *regexp.Regexp, message string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) ([]string, []error) {
		v, ok := i.(string)
		if !ok {
			return nil, []error{fmt.Errorf("expected type of %s to be string", k)}
		}

		if ok := r.MatchString(v); ok {
			if message != "" {
				return nil, []error{fmt.Errorf("invalid value for %s (%s)", k, message)}

			}
			return nil, []error{fmt.Errorf("expected value of %s to not match regular expression %q, got %v", k, r, i)}
		}
		return nil, nil
	}
}

// StringInSlice returns a SchemaValidateFunc which tests if the provided value
// is of type string and matches the value of an element in the valid slice
// will test with in lower case if ignoreCase is true
func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		for _, str := range valid {
			if v == str || (ignoreCase && strings.ToLower(v) == strings.ToLower(str)) {
				return warnings, errors
			}
		}

		errors = append(errors, fmt.Errorf("expected %s to be one of %v, got %s", k, valid, v))
		return warnings, errors
	}
}

// StringDoesNotContainAny returns a SchemaValidateFunc which validates that the
// provided value does not contain any of the specified Unicode code points in chars.
func StringDoesNotContainAny(chars string) schema.SchemaValidateFunc {
	return func(i interface{}, k string) (warnings []string, errors []error) {
		v, ok := i.(string)
		if !ok {
			errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
			return warnings, errors
		}

		if strings.ContainsAny(v, chars) {
			errors = append(errors, fmt.Errorf("expected value of %s to not contain any of %q, got %v", k, chars, i))
			return warnings, errors
		}

		return warnings, errors
	}
}

// StringIsBase64 is a ValidateFunc that ensures a string can be parsed as Base64
func StringIsBase64(i interface{}, k string) (warnings []string, errors []error) {
	// Empty string is not allowed
	if warnings, errors = StringIsNotEmpty(i, k); len(errors) > 0 {
		return
	}

	// NoEmptyStrings checks it is a string
	v, _ := i.(string)

	if _, err := base64.StdEncoding.DecodeString(v); err != nil {
		errors = append(errors, fmt.Errorf("expected %q to be a base64 string, got %v", k, v))
	}

	return warnings, errors
}

// ValidateJsonString is a SchemaValidateFunc which tests to make sure the
// supplied string is valid JSON.
//
// Deprecated: use StringIsJSON instead
func ValidateJsonString(i interface{}, k string) (warnings []string, errors []error) {
	return StringIsJSON(i, k)
}

// ValidateJsonString is a SchemaValidateFunc which tests to make sure the supplied string is valid JSON.
func StringIsJSON(i interface{}, k string) (warnings []string, errors []error) {
	v, ok := i.(string)
	if !ok {
		errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
		return warnings, errors
	}

	if _, err := structure.NormalizeJsonString(v); err != nil {
		errors = append(errors, fmt.Errorf("%q contains an invalid JSON: %s", k, err))
	}

	return warnings, errors
}

// ValidateRegexp returns a SchemaValidateFunc which tests to make sure the
// supplied string is a valid regular expression.
func ValidateRegexp(i interface{}, k string) (warnings []string, errors []error) {
	return StringIsValidRegExp(i, k)
}

// ValidateRegexp returns a SchemaValidateFunc which tests to make sure the supplied string is a valid regular expression.
func StringIsValidRegExp(i interface{}, k string) (warnings []string, errors []error) {
	v, ok := i.(string)
	if !ok {
		errors = append(errors, fmt.Errorf("expected type of %s to be string", k))
		return warnings, errors
	}

	if _, err := regexp.Compile(v); err != nil {
		errors = append(errors, fmt.Errorf("%q: %s", k, err))
	}

	return warnings, errors
}
<|endoftext|>


<commit_before>//
// Copyright 2016-2018 Bryan T. Meyers <bmeyers@datadrake.com>
//
// 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 git

import (
    "bufio"
    "bytes"
    "github.com/DataDrake/cuppa/results"
    "io"
    "os/exec"
    "regexp"
    "strings"
)

// SourceRegex is the regex for Git sources
var SourceRegex = regexp.MustCompile("^(?:git|)?(.+)(?:\\.git)?$")

// Provider provides a common interface for each of the backend providers
type Provider struct {}

func (p Provider) Name() string {
    return "Git"
}

// Latest finds the newest release for a Git package
func (p Provider) Latest(name string) (*results.Result, results.Status){
    cmd := exec.Command("git", "ls-remote", "--tags", name)
    buff := new(bytes.Buffer)
    cmd.Stdout = buff
    read := bufio.NewReader(buff)
    err := cmd.Run()
    line, _, err := read.ReadLine()
    var r *results.Result
    pieces := strings.Split(name, "/")
    repoName := strings.Split(pieces[len(pieces)-1], ".")[0]
    for err == nil {
        pieces := strings.Split(string(line), "/")
        tag := pieces[0]
        if len(pieces) > 1 {
            tag = pieces[len(pieces)-1]
        }
        if !strings.HasSuffix(tag, "{}") {
            r = &results.Result{
                Name: repoName,
                Version: tag,
                Location: "git|" + name,
            }
        }
        line, _, err = read.ReadLine()
    }
    if err != io.EOF || r == nil{
        return nil, results.NotFound
    }
    return r, results.OK
}

// Match checks to see if this provider can handle this kind of query
func (p Provider) Match(query string) string {
    sm := SourceRegex.FindStringSubmatch(query)
    if len(sm) != 2 {
        return ""
    }
    pieces := strings.Split(sm[1], "|")
    if len(pieces) > 1 {
        return pieces[1]
    }
    return pieces[0]
}

// Releases finds all matching releases for a Git package
func (p Provider) Releases(name string) (*results.ResultSet, results.Status) {
    cmd := exec.Command("git", "ls-remote", "--tags", name)
    buff := new(bytes.Buffer)
    cmd.Stdout = buff
    read := bufio.NewReader(buff)
    err := cmd.Run()
    line, _, err := read.ReadLine()
    var r *results.Result
    pieces := strings.Split(name, "/")
    repoName := strings.Split(pieces[len(pieces)-1], ".")[0]
    rs := results.NewResultSet(repoName)
    for err == nil {
        pieces := strings.Split(string(line), "/")
        tag := pieces[0]
        if len(pieces) > 1 {
            tag = pieces[len(pieces)-1]
        }
        if !strings.HasSuffix(tag, "{}") {
            r = &results.Result{
                Name: repoName,
                Version: tag,
                Location: "git|" + name,
            }
            rs.AddResult(r)
        }
        line, _, err = read.ReadLine()
    }
    if err != io.EOF || rs.Len() == 0 {
        return nil, results.NotFound
    }
    return rs, results.OK
}
<commit_msg>Vastly improve git matching<commit_after>//
// Copyright 2016-2018 Bryan T. Meyers <bmeyers@datadrake.com>
//
// 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 git

import (
    "bufio"
    "bytes"
    "github.com/DataDrake/cuppa/results"
    "io"
    "os/exec"
    "strings"
)

// Provider provides a common interface for each of the backend providers
type Provider struct {}

func (p Provider) Name() string {
    return "Git"
}

// Latest finds the newest release for a Git package
func (p Provider) Latest(name string) (*results.Result, results.Status){
    cmd := exec.Command("git", "ls-remote", "--tags", name)
    buff := new(bytes.Buffer)
    cmd.Stdout = buff
    read := bufio.NewReader(buff)
    err := cmd.Run()
    line, _, err := read.ReadLine()
    var r *results.Result
    pieces := strings.Split(name, "/")
    repoName := strings.Split(pieces[len(pieces)-1], ".")[0]
    for err == nil {
        pieces := strings.Split(string(line), "/")
        tag := pieces[0]
        if len(pieces) > 1 {
            tag = pieces[len(pieces)-1]
        }
        if !strings.HasSuffix(tag, "{}") {
            r = &results.Result{
                Name: repoName,
                Version: tag,
                Location: "git|" + name,
            }
        }
        line, _, err = read.ReadLine()
    }
    if err != io.EOF || r == nil{
        return nil, results.NotFound
    }
    return r, results.OK
}

// Match checks to see if this provider can handle this kind of query
func (p Provider) Match(query string) string {
    if strings.HasPrefix(query, "git|") || strings.HasSuffix(query, ".git") {
        pieces := strings.Split(query, "|")
        if len(pieces) > 1 {
            return pieces[1]
        }
        return pieces[0]
    }
    return ""
}

// Releases finds all matching releases for a Git package
func (p Provider) Releases(name string) (*results.ResultSet, results.Status) {
    cmd := exec.Command("git", "ls-remote", "--tags", name)
    buff := new(bytes.Buffer)
    cmd.Stdout = buff
    read := bufio.NewReader(buff)
    err := cmd.Run()
    line, _, err := read.ReadLine()
    var r *results.Result
    pieces := strings.Split(name, "/")
    repoName := strings.Split(pieces[len(pieces)-1], ".")[0]
    rs := results.NewResultSet(repoName)
    for err == nil {
        pieces := strings.Split(string(line), "/")
        tag := pieces[0]
        if len(pieces) > 1 {
            tag = pieces[len(pieces)-1]
        }
        if !strings.HasSuffix(tag, "{}") {
            r = &results.Result{
                Name: repoName,
                Version: tag,
                Location: "git|" + name,
            }
            rs.AddResult(r)
        }
        line, _, err = read.ReadLine()
    }
    if err != io.EOF || rs.Len() == 0 {
        return nil, results.NotFound
    }
    return rs, results.OK
}
<|endoftext|>


<commit_before>package backend

import (
	"encoding/json"
	"github.com/op/go-logging"
	"io/ioutil"
	"os"
	"path/filepath"
)

var (
	log = logging.MustGetLogger("lovebeat")
)

type FileBackend struct {
	path string
}

func (r FileBackend) viewFile(name string) string {
	return filepath.Join(r.path, "views", name+".json")
}
func (r FileBackend) serviceFile(name string) string {
	return filepath.Join(r.path, "services", name+".json")
}

func (r FileBackend) readViewFile(name string, fname string) *StoredView {
	view := &StoredView{
		Name:   name,
		State:  STATE_OK,
		Regexp: "^$",
	}

	data, err := ioutil.ReadFile(fname)
	if err == nil {
		json.Unmarshal(data, &view)
	}

	return view
}

func (r FileBackend) loadView(name string) *StoredView {
	return r.readViewFile(name, r.viewFile(name))
}

func (r FileBackend) SaveService(service *StoredService) {
	b, _ := json.Marshal(service)
	filename := r.serviceFile(service.Name)
	log.Debug("Writing %s", filename)
	ioutil.WriteFile(filename, b, 0644)
}

func (r FileBackend) SaveView(view *StoredView) {
	b, _ := json.Marshal(view)
	filename := r.viewFile(view.Name)
	log.Debug("Writing %s", filename)
	ioutil.WriteFile(filename, b, 0644)
}

func (r FileBackend) readServiceFile(name string, fname string) *StoredService {
	service := &StoredService{
		Name:           name,
		LastValue:      -1,
		LastBeat:       -1,
		LastUpdated:    -1,
		WarningTimeout: -1,
		ErrorTimeout:   -1,
		State:          STATE_PAUSED,
	}

	data, err := ioutil.ReadFile(fname)
	if err == nil {
		json.Unmarshal(data, &service)
	}

	return service
}

func (r FileBackend) loadService(name string) *StoredService {
	return r.readServiceFile(name, r.serviceFile(name))
}

func (r FileBackend) LoadServices() []*StoredService {
	var ret []*StoredService

	matches, _ := filepath.Glob(filepath.Join(r.path, "services", "*.json"))
	for _, fname := range matches {
		svc := r.readServiceFile("", fname)
		ret = append(ret, svc)
		log.Debug("Found service %s", svc.Name)
	}
	return ret
}

func (r FileBackend) LoadViews() []*StoredView {
	var ret []*StoredView

	matches, _ := filepath.Glob(filepath.Join(r.path, "views", "*.json"))
	for _, fname := range matches {
		view := r.readViewFile("", fname)
		ret = append(ret, view)
		log.Debug("Found view %s", view.Name)
	}
	return ret
}

func (r FileBackend) DeleteService(name string) {
	os.Remove(r.serviceFile(name))
}

func (r FileBackend) DeleteView(name string) {
	os.Remove(r.viewFile(name))
}

func NewFileBackend(path string) Backend {
	os.MkdirAll(filepath.Join(path, "views"), 0755)
	os.MkdirAll(filepath.Join(path, "services"), 0755)
	return &FileBackend{path: path}
}
<commit_msg>New 'snapshot' file backend<commit_after>package backend

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"encoding/json"
	"github.com/op/go-logging"
	"os"
	"path/filepath"
	"time"
)

const (
	EXPIRY_INTERVAL    = 60
	MAX_PENDING_WRITES = 1000
)

var (
	RECORD_SERVICE = []byte("SERV\t")
	RECORD_VIEW    = []byte("VIEW\t")
	NEWLINE        = []byte("\n")
)

var (
	log = logging.MustGetLogger("lovebeat")
)

type FileBackend struct {
	path     string
	q        chan update
	services map[string]*StoredService
	views    map[string]*StoredView
}

func (f FileBackend) SaveService(service *StoredService) {
	f.q <- update{setService: service}
}

func (f FileBackend) SaveView(view *StoredView) {
	f.q <- update{setView: view}
}

func (r FileBackend) LoadServices() []*StoredService {
	v := make([]*StoredService, len(r.services))
	idx := 0
	for _, value := range r.services {
		v[idx] = value
		idx++
	}
	return v
}

func (r FileBackend) LoadViews() []*StoredView {
	v := make([]*StoredView, len(r.views))
	idx := 0
	for _, value := range r.views {
		v[idx] = value
		idx++
	}
	return v
}

func (f FileBackend) DeleteService(name string) {
	f.q <- update{deleteService: name}
}

func (f FileBackend) DeleteView(name string) {
	f.q <- update{deleteView: name}
}

func (f FileBackend) loadService(data []byte) {
	service := &StoredService{}
	json.Unmarshal(data, &service)
	f.services[service.Name] = service
}

func (f FileBackend) loadView(data []byte) {
	view := &StoredView{}
	json.Unmarshal(data, &view)
	f.views[view.Name] = view
}

func (f FileBackend) filename() string {
	return filepath.Join(f.path, "lovebeat-data.gz")
}

func (f FileBackend) readAll() {
	start := time.Now()
	s := f.filename()
	fi, err := os.Open(s)
	if err != nil {
		log.Error("Couldn't find any old database to read\n")
		return
	}
	gz, err := gzip.NewReader(fi)
	if err != nil {
		log.Error("Couldn't read from database\n")
		return
	}

	buf := bufio.NewReader(gz)
	for {
		line, err := buf.ReadBytes('\n')
		if err != nil {
			break
		}
		if bytes.HasPrefix(line, RECORD_SERVICE) {
			f.loadService(line[5:])
		} else if bytes.HasPrefix(line, RECORD_VIEW) {
			f.loadView(line[5:])
		} else {
			log.Info("Found unexpected line in database - skipping")
		}
	}
	duration := time.Since(start)
	log.Info("Loaded %d items in %d ms", len(f.services)+len(f.views),
		duration.Nanoseconds()/1000000)
}

func (f FileBackend) saveAll() {
	start := time.Now()
	s := f.filename() + ".new"
	fi, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640)
	if err != nil {
		log.Error("Error creating file\n")
		return
	}
	gz := gzip.NewWriter(fi)

	for _, service := range f.services {
		b, _ := json.Marshal(service)
		gz.Write(RECORD_SERVICE)
		gz.Write(b)
		gz.Write(NEWLINE)
	}
	for _, view := range f.views {
		b, _ := json.Marshal(view)
		gz.Write(RECORD_VIEW)
		gz.Write(b)
		gz.Write(NEWLINE)
	}
	gz.Close()
	fi.Close()
	if err = os.Rename(s, f.filename()); err != nil {
		log.Error("Failed to overwrite database")
		return
	}
	duration := time.Since(start)
	log.Info("Saved %d items in %d ms", len(f.services)+len(f.views),
		duration.Nanoseconds()/1000000)
}

type update struct {
	setService    *StoredService
	setView       *StoredView
	deleteService string
	deleteView    string
}

func (f FileBackend) fileSaver() {
	period := time.Duration(EXPIRY_INTERVAL) * time.Second
	ticker := time.NewTicker(period)
	for {
		select {
		case <-ticker.C:
			f.saveAll()
		case upd := <-f.q:
			if upd.setService != nil {
				f.services[upd.setService.Name] = upd.setService
			}
			if upd.deleteService != "" {
				delete(f.services, upd.deleteService)
			}
			if upd.setView != nil {
				f.views[upd.setView.Name] = upd.setView
			}
			if upd.deleteView != "" {
				delete(f.views, upd.deleteView)
			}
		}
	}
}

func NewFileBackend(path string) Backend {
	var q = make(chan update, MAX_PENDING_WRITES)
	be := FileBackend{
		path:     path,
		q:        q,
		services: make(map[string]*StoredService),
		views:    make(map[string]*StoredView),
	}
	be.readAll()
	go be.fileSaver()
	return be
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package obfs4

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"git.torproject.org/pluggable-transports/goptlib.git"
	"git.torproject.org/pluggable-transports/obfs4.git/common/csrand"
	"git.torproject.org/pluggable-transports/obfs4.git/common/drbg"
	"git.torproject.org/pluggable-transports/obfs4.git/common/ntor"
)

const (
	stateFile = "obfs4_state.json"
)

type jsonServerState struct {
	NodeID     string `json:"node-id"`
	PrivateKey string `json:"private-key"`
	PublicKey  string `json:"public-key"`
	DrbgSeed   string `json:"drbgSeed"`
}

type obfs4ServerState struct {
	nodeID      *ntor.NodeID
	identityKey *ntor.Keypair
	drbgSeed    *drbg.Seed
}

func serverStateFromArgs(stateDir string, args *pt.Args) (*obfs4ServerState, error) {
	var js jsonServerState
	var nodeIDOk, privKeyOk, seedOk bool

	js.NodeID, nodeIDOk = args.Get(nodeIDArg)
	js.PrivateKey, privKeyOk = args.Get(privateKeyArg)
	js.DrbgSeed, seedOk = args.Get(seedArg)

	if !privKeyOk && !nodeIDOk && !seedOk {
		if err := jsonServerStateFromFile(stateDir, &js); err != nil {
			return nil, err
		}
	} else if !privKeyOk {
		return nil, fmt.Errorf("missing argument '%s'", privateKeyArg)
	} else if !nodeIDOk {
		return nil, fmt.Errorf("missing argument '%s'", nodeIDArg)
	} else if !seedOk {
		return nil, fmt.Errorf("missing argument '%s'", seedArg)
	}

	return serverStateFromJSONServerState(&js)
}

func serverStateFromJSONServerState(js *jsonServerState) (*obfs4ServerState, error) {
	var err error

	st := new(obfs4ServerState)
	if st.nodeID, err = ntor.NodeIDFromBase64(js.NodeID); err != nil {
		return nil, err
	}
	if st.identityKey, err = ntor.KeypairFromBase64(js.PrivateKey); err != nil {
		return nil, err
	}
	var rawSeed []byte
	if rawSeed, err = base64.StdEncoding.DecodeString(js.DrbgSeed); err != nil {
		return nil, err
	}
	if st.drbgSeed, err = drbg.SeedFromBytes(rawSeed); err != nil {
		return nil, err
	}

	return st, nil
}

func jsonServerStateFromFile(stateDir string, js *jsonServerState) error {
	f, err := ioutil.ReadFile(path.Join(stateDir, stateFile))
	if err != nil {
		if os.IsNotExist(err) {
			if err = newJSONServerState(stateDir, js); err == nil {
				return nil
			}
		}
		return err
	}

	if err = json.Unmarshal(f, js); err != nil {
		return err
	}

	return nil
}

func newJSONServerState(stateDir string, js *jsonServerState) (err error) {
	// Generate everything a server needs, using the cryptographic PRNG.
	var st obfs4ServerState
	rawID := make([]byte, ntor.NodeIDLength)
	if err = csrand.Bytes(rawID); err != nil {
		return
	}
	if st.nodeID, err = ntor.NewNodeID(rawID); err != nil {
		return
	}
	if st.identityKey, err = ntor.NewKeypair(false); err != nil {
		return
	}
	if st.drbgSeed, err = drbg.NewSeed(); err != nil {
		return
	}

	// Encode it into JSON format and write the state file.
	js.NodeID = st.nodeID.Base64()
	js.PrivateKey = st.identityKey.Private().Base64()
	js.PublicKey = st.identityKey.Public().Base64()
	js.DrbgSeed = st.drbgSeed.Base64()

	var encoded []byte
	if encoded, err = json.Marshal(js); err != nil {
		return
	}

	if err = ioutil.WriteFile(path.Join(stateDir, stateFile), encoded, 0600); err != nil {
		return err
	}

	return nil
}
<commit_msg>Change the drbg seed field in the state file.<commit_after>/*
 * Copyright (c) 2014, Yawning Angel <yawning at torproject dot org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

package obfs4

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"git.torproject.org/pluggable-transports/goptlib.git"
	"git.torproject.org/pluggable-transports/obfs4.git/common/csrand"
	"git.torproject.org/pluggable-transports/obfs4.git/common/drbg"
	"git.torproject.org/pluggable-transports/obfs4.git/common/ntor"
)

const (
	stateFile = "obfs4_state.json"
)

type jsonServerState struct {
	NodeID     string `json:"node-id"`
	PrivateKey string `json:"private-key"`
	PublicKey  string `json:"public-key"`
	DrbgSeed   string `json:"drbg-seed"`
}

type obfs4ServerState struct {
	nodeID      *ntor.NodeID
	identityKey *ntor.Keypair
	drbgSeed    *drbg.Seed
}

func serverStateFromArgs(stateDir string, args *pt.Args) (*obfs4ServerState, error) {
	var js jsonServerState
	var nodeIDOk, privKeyOk, seedOk bool

	js.NodeID, nodeIDOk = args.Get(nodeIDArg)
	js.PrivateKey, privKeyOk = args.Get(privateKeyArg)
	js.DrbgSeed, seedOk = args.Get(seedArg)

	if !privKeyOk && !nodeIDOk && !seedOk {
		if err := jsonServerStateFromFile(stateDir, &js); err != nil {
			return nil, err
		}
	} else if !privKeyOk {
		return nil, fmt.Errorf("missing argument '%s'", privateKeyArg)
	} else if !nodeIDOk {
		return nil, fmt.Errorf("missing argument '%s'", nodeIDArg)
	} else if !seedOk {
		return nil, fmt.Errorf("missing argument '%s'", seedArg)
	}

	return serverStateFromJSONServerState(&js)
}

func serverStateFromJSONServerState(js *jsonServerState) (*obfs4ServerState, error) {
	var err error

	st := new(obfs4ServerState)
	if st.nodeID, err = ntor.NodeIDFromBase64(js.NodeID); err != nil {
		return nil, err
	}
	if st.identityKey, err = ntor.KeypairFromBase64(js.PrivateKey); err != nil {
		return nil, err
	}
	var rawSeed []byte
	if rawSeed, err = base64.StdEncoding.DecodeString(js.DrbgSeed); err != nil {
		return nil, err
	}
	if st.drbgSeed, err = drbg.SeedFromBytes(rawSeed); err != nil {
		return nil, err
	}

	return st, nil
}

func jsonServerStateFromFile(stateDir string, js *jsonServerState) error {
	f, err := ioutil.ReadFile(path.Join(stateDir, stateFile))
	if err != nil {
		if os.IsNotExist(err) {
			if err = newJSONServerState(stateDir, js); err == nil {
				return nil
			}
		}
		return err
	}

	if err = json.Unmarshal(f, js); err != nil {
		return err
	}

	return nil
}

func newJSONServerState(stateDir string, js *jsonServerState) (err error) {
	// Generate everything a server needs, using the cryptographic PRNG.
	var st obfs4ServerState
	rawID := make([]byte, ntor.NodeIDLength)
	if err = csrand.Bytes(rawID); err != nil {
		return
	}
	if st.nodeID, err = ntor.NewNodeID(rawID); err != nil {
		return
	}
	if st.identityKey, err = ntor.NewKeypair(false); err != nil {
		return
	}
	if st.drbgSeed, err = drbg.NewSeed(); err != nil {
		return
	}

	// Encode it into JSON format and write the state file.
	js.NodeID = st.nodeID.Base64()
	js.PrivateKey = st.identityKey.Private().Base64()
	js.PublicKey = st.identityKey.Public().Base64()
	js.DrbgSeed = st.drbgSeed.Base64()

	var encoded []byte
	if encoded, err = json.Marshal(js); err != nil {
		return
	}

	if err = ioutil.WriteFile(path.Join(stateDir, stateFile), encoded, 0600); err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package cuid

import (
	"fmt"
	"reflect"
	"regexp"
	"testing"
)

func Test_CUIDType(t *testing.T) {
	c := New()
	if reflect.TypeOf(c).Name() != "string" {
		t.Error("Incorrect CUID type")
	}
}

func Test_CUIDFormat(t *testing.T) {
	c := New()
	format := regexp.MustCompile(fmt.Sprintf("c[0-9a-z]{%d}", 6*BLOCK_SIZE))
	if !format.MatchString(c) {
		t.Error("Incorrect format")
	}
}

func Test_CUIDCollisions(t *testing.T) {
	ids := map[string]bool{}
	for i := 0; i < 600000; i++ {
		id := New()
		if ids[id] == true {
			t.Errorf("Collision detected, at iteration %d", i)
		}
		ids[id] = true
	}
}

func Test_SlugType(t *testing.T) {
	s := NewSlug()
	if reflect.TypeOf(s).Name() != "string" {
		t.Error("Incorrect CUID type")
	}
}

func Test_SlugFormat(t *testing.T) {

}

func Benchmark_CUIDGeneration(b *testing.B) {
	for i := 0; i < b.N; i++ {
		New()
	}
}
<commit_msg>Removed useless tests.<commit_after>package cuid

import (
	"fmt"
	"reflect"
	"regexp"
	"testing"
)

func Test_CUIDType(t *testing.T) {
	c := New()
	if reflect.TypeOf(c).Name() != "string" {
		t.Error("Incorrect CUID type")
	}
}

func Test_CUIDFormat(t *testing.T) {
	c := New()
	format := regexp.MustCompile(fmt.Sprintf("c[0-9a-z]{%d}", 6*BLOCK_SIZE))
	if !format.MatchString(c) {
		t.Error("Incorrect format")
	}
}

func Test_CUIDCollisions(t *testing.T) {
	ids := map[string]bool{}
	for i := 0; i < 600000; i++ {
		id := New()
		if ids[id] == true {
			t.Errorf("Collision detected, at iteration %d", i)
		}
		ids[id] = true
	}
}

func Benchmark_CUIDGeneration(b *testing.B) {
	for i := 0; i < b.N; i++ {
		New()
	}
}
<|endoftext|>