<commit_before>package kafka_avro

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	avro "github.com/elodina/go-avro"
	kafkaavro "github.com/elodina/go-kafka-avro"
	"github.com/gliderlabs/logspout/router"
	"gopkg.in/Shopify/sarama.v1"
)

var messageSchema = `{
  "type": "record",
  "name": "LogLine",
  "fields": [
    {"name": "timestamp", "type": "string"},
    {"name": "container_name", "type": "string"},
    {"name": "source", "type": "string"},
    {"name": "line", "type": "string"}
  ]
}`

func init() {
	router.AdapterFactories.Register(NewKafkaAvroAdapter, "kafka_avro")
}

type KafkaAvroAdapter struct {
	route    *router.Route
	brokers  []string
	topic    string
	schema   avro.Schema
	registry *kafkaavro.KafkaAvroEncoder
	producer sarama.AsyncProducer
}

func NewKafkaAvroAdapter(route *router.Route) (router.LogAdapter, error) {
	brokers := readBrokers(route.Address)
	if len(brokers) == 0 {
		return nil, errorf("The Kafka broker host:port is missing. Did you specify it as a route address?")
	}

	topic := readTopic(route.Address, route.Options)
	if topic == "" {
		return nil, errorf("The Kafka topic is missing. Did you specify it as a route option?")
	}

	schemaUrl := readSchemaRegistryUrl(route.Options)
	if schemaUrl == "" {
		return nil, errorf("The schema registry url is missing. Did you specify it as a route option?")
	}

	registry := kafkaavro.NewKafkaAvroEncoder(schemaUrl)

	var schema avro.Schema
	schema, err := avro.ParseSchema(messageSchema)
	if err != nil {
		return nil, errorf("The schema could not be parsed")
	}

	if os.Getenv("DEBUG") != "" {
		log.Printf("Starting Kafka producer for address: %s, topic: %s.\n", brokers, topic)
	}

	var retries int
	retries, err = strconv.Atoi(os.Getenv("KAFKA_CONNECT_RETRIES"))
	if err != nil {
		retries = 3
	}
	var producer sarama.AsyncProducer
	for i := 0; i < retries; i++ {
		producer, err = sarama.NewAsyncProducer(brokers, newConfig())
		if err != nil {
			if os.Getenv("DEBUG") != "" {
				log.Println("Couldn't create Kafka producer. Retrying...", err)
			}
			if i == retries-1 {
				return nil, errorf("Couldn't create Kafka producer. %v", err)
			}
		} else {
			time.Sleep(1 * time.Second)
		}
	}

	return &KafkaAvroAdapter{
		route:    route,
		brokers:  brokers,
		topic:    topic,
		registry: registry,
		schema:   schema,
		producer: producer,
	}, nil
}

func (a *KafkaAvroAdapter) Stream(logstream chan *router.Message) {
	defer a.producer.Close()
	for rm := range logstream {
		message, err := a.formatMessage(rm)
		if err != nil {
			log.Println("kafka:", err)
			a.route.Close()
			break
		}

		a.producer.Input() <- message
	}
}

func newConfig() *sarama.Config {
	config := sarama.NewConfig()
	config.ClientID = "logspout"
	config.Producer.Return.Errors = false
	config.Producer.Return.Successes = false
	config.Producer.Flush.Frequency = 1 * time.Second
	config.Producer.RequiredAcks = sarama.WaitForLocal

	if opt := os.Getenv("KAFKA_COMPRESSION_CODEC"); opt != "" {
		switch opt {
		case "gzip":
			config.Producer.Compression = sarama.CompressionGZIP
		case "snappy":
			config.Producer.Compression = sarama.CompressionSnappy
		}
	}

	return config
}

func (a *KafkaAvroAdapter) formatMessage(message *router.Message) (*sarama.ProducerMessage, error) {
	var encoder sarama.Encoder

	record := avro.NewGenericRecord(a.schema)
	record.Set("timestamp", message.Time)
	record.Set("container_name", message.Container.Name)
	record.Set("source", message.Source)
	record.Set("line", message.Data)

	b, err := a.registry.Encode(record)
	if err != nil {
		return nil, err
	}

	encoder = sarama.ByteEncoder(b)

	return &sarama.ProducerMessage{
		Topic: a.topic,
		Value: encoder,
	}, nil
}

func readBrokers(address string) []string {
	if strings.Contains(address, "/") {
		slash := strings.Index(address, "/")
		address = address[:slash]
	}

	return strings.Split(address, ",")
}

func readTopic(address string, options map[string]string) string {
	var topic string
	if !strings.Contains(address, "/") {
		topic = options["topic"]
	} else {
		slash := strings.Index(address, "/")
		topic = address[slash+1:]
	}

	return topic
}

func readSchemaRegistryUrl(options map[string]string) string {
	var url string
	if _, ok := options["schema_registry_url"]; ok {
		url = options["schema_registry_url"]
	}
	return url
}

func errorf(format string, a ...interface{}) (err error) {
	err = fmt.Errorf(format, a...)
	if os.Getenv("DEBUG") != "" {
		fmt.Println(err.Error())
	}
	return
}
<commit_msg>add debugging<commit_after>package kafka_avro

import (
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	avro "github.com/elodina/go-avro"
	kafkaavro "github.com/elodina/go-kafka-avro"
	"github.com/gliderlabs/logspout/router"
	"gopkg.in/Shopify/sarama.v1"
)

var messageSchema = `{
  "type": "record",
  "name": "LogLine",
  "fields": [
    {"name": "timestamp", "type": "string"},
    {"name": "container_name", "type": "string"},
    {"name": "source", "type": "string"},
    {"name": "line", "type": "string"}
  ]
}`

func init() {
	router.AdapterFactories.Register(NewKafkaAvroAdapter, "kafka_avro")
}

type KafkaAvroAdapter struct {
	route    *router.Route
	brokers  []string
	topic    string
	schema   avro.Schema
	registry *kafkaavro.KafkaAvroEncoder
	producer sarama.AsyncProducer
}

func NewKafkaAvroAdapter(route *router.Route) (router.LogAdapter, error) {
	brokers := readBrokers(route.Address)
	if len(brokers) == 0 {
		return nil, errorf("The Kafka broker host:port is missing. Did you specify it as a route address?")
	}

	topic := readTopic(route.Address, route.Options)
	if topic == "" {
		return nil, errorf("The Kafka topic is missing. Did you specify it as a route option?")
	}

	schemaUrl := readSchemaRegistryUrl(route.Options)
	if schemaUrl == "" {
		return nil, errorf("The schema registry url is missing. Did you specify it as a route option?")
	}

	registry := kafkaavro.NewKafkaAvroEncoder(schemaUrl)

	var schema avro.Schema
	schema, err := avro.ParseSchema(messageSchema)
	if err != nil {
		return nil, errorf("The schema could not be parsed")
	}

	if os.Getenv("DEBUG") != "" {
		log.Printf("Starting Kafka producer for address: %s, topic: %s.\n", brokers, topic)
	}

	var retries int
	retries, err = strconv.Atoi(os.Getenv("KAFKA_CONNECT_RETRIES"))
	if err != nil {
		retries = 3
	}
	var producer sarama.AsyncProducer
	for i := 0; i < retries; i++ {
		producer, err = sarama.NewAsyncProducer(brokers, newConfig())
		if err != nil {
			if os.Getenv("DEBUG") != "" {
				log.Println("Couldn't create Kafka producer. Retrying...", err)
			}
			if i == retries-1 {
				return nil, errorf("Couldn't create Kafka producer. %v", err)
			}
		} else {
			time.Sleep(1 * time.Second)
		}
	}

	return &KafkaAvroAdapter{
		route:    route,
		brokers:  brokers,
		topic:    topic,
		registry: registry,
		schema:   schema,
		producer: producer,
	}, nil
}

func (a *KafkaAvroAdapter) Stream(logstream chan *router.Message) {
	defer a.producer.Close()
	for rm := range logstream {
		message, err := a.formatMessage(rm)
		if err != nil {
			log.Println("kafka:", err)
			a.route.Close()
			break
		}

		a.producer.Input() <- message
	}
}

func newConfig() *sarama.Config {
	config := sarama.NewConfig()
	config.ClientID = "logspout"
	config.Producer.Return.Errors = false
	config.Producer.Return.Successes = false
	config.Producer.Flush.Frequency = 1 * time.Second
	config.Producer.RequiredAcks = sarama.WaitForLocal

	if opt := os.Getenv("KAFKA_COMPRESSION_CODEC"); opt != "" {
		switch opt {
		case "gzip":
			config.Producer.Compression = sarama.CompressionGZIP
		case "snappy":
			config.Producer.Compression = sarama.CompressionSnappy
		}
	}

	return config
}

func (a *KafkaAvroAdapter) formatMessage(message *router.Message) (*sarama.ProducerMessage, error) {
	var encoder sarama.Encoder

	record := avro.NewGenericRecord(a.schema)
	record.Set("timestamp", message.Time.String())
	record.Set("container_name", message.Container.Name)
	record.Set("source", message.Source)
	record.Set("line", message.Data)

	b, err := a.registry.Encode(record)
	if err != nil {
		return nil, err
	}
	debug(b)

	encoder = sarama.ByteEncoder(b)

	return &sarama.ProducerMessage{
		Topic: a.topic,
		Value: encoder,
	}, nil
}

func readBrokers(address string) []string {
	if strings.Contains(address, "/") {
		slash := strings.Index(address, "/")
		address = address[:slash]
	}

	return strings.Split(address, ",")
}

func readTopic(address string, options map[string]string) string {
	var topic string
	if !strings.Contains(address, "/") {
		topic = options["topic"]
	} else {
		slash := strings.Index(address, "/")
		topic = address[slash+1:]
	}

	return topic
}

func readSchemaRegistryUrl(options map[string]string) string {
	var url string
	if _, ok := options["schema_registry_url"]; ok {
		url = options["schema_registry_url"]
	}
	return url
}

func errorf(format string, a ...interface{}) (err error) {
	err = fmt.Errorf(format, a...)
	if os.Getenv("DEBUG") != "" {
		fmt.Println(err.Error())
	}
	return
}

func debug(v ...interface{}) {
	if os.Getenv("DEBUG") != "" {
		log.Println(v...)
	}
}
<|endoftext|>


<commit_before>package service

import (
	"bytes"
	"context"
	"database/sql"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// KeyAuthUserID to use in context.
const KeyAuthUserID key = "auth_user_id"

const (
	verificationCodeLifespan = time.Minute * 15
	tokenLifespan            = time.Hour * 24 * 14
)

var (
	// ErrUnimplemented denotes a not implemented functionality.
	ErrUnimplemented = errors.New("unimplemented")
	// ErrUnauthenticated denotes no authenticated user in context.
	ErrUnauthenticated = errors.New("unauthenticated")
	// ErrInvalidRedirectURI denotes an invalid redirect uri.
	ErrInvalidRedirectURI = errors.New("invalid redirect uri")
	// ErrInvalidVerificationCode denotes an invalid verification code.
	ErrInvalidVerificationCode = errors.New("invalid verification code")
	// ErrVerificationCodeNotFound denotes a not found verification code.
	ErrVerificationCodeNotFound = errors.New("verification code not found")
)

var rxUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")

var magicLinkMailTmpl *template.Template

type key string

// TokenOutput response.
type TokenOutput struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expiresAt"`
}

// DevLoginOutput response.
type DevLoginOutput struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expiresAt"`
	AuthUser  User      `json:"authUser"`
}

// SendMagicLink to login without passwords.
func (s *Service) SendMagicLink(ctx context.Context, email, redirectURI string) error {
	email = strings.TrimSpace(email)
	if !rxEmail.MatchString(email) {
		return ErrInvalidEmail
	}

	uri, err := url.ParseRequestURI(redirectURI)
	if err != nil {
		return ErrInvalidRedirectURI
	}

	var verificationCode string
	err = s.db.QueryRowContext(ctx, `
		INSERT INTO verification_codes (user_id) VALUES (
			(SELECT id FROM users WHERE email = $1)
		) RETURNING id`, email).Scan(&verificationCode)
	if isForeignKeyViolation(err) {
		return ErrUserNotFound
	}

	if err != nil {
		return fmt.Errorf("could not insert verification code: %v", err)
	}

	magicLink := s.origin
	magicLink.Path = "/api/auth_redirect"
	q := magicLink.Query()
	q.Set("verification_code", verificationCode)
	q.Set("redirect_uri", uri.String())
	magicLink.RawQuery = q.Encode()

	if magicLinkMailTmpl == nil {
		magicLinkMailTmpl, err = template.ParseFiles("web/template/mail/magic-link.html")
		if err != nil {
			return fmt.Errorf("could not parse magic link mail template: %v", err)
		}
	}

	var b bytes.Buffer
	if err = magicLinkMailTmpl.Execute(&b, map[string]interface{}{
		"MagicLink": magicLink.String(),
		"Minutes":   int(verificationCodeLifespan.Minutes()),
	}); err != nil {
		return fmt.Errorf("could not execute magic link mail template: %v", err)
	}

	if err = s.sender.Send(email, "Magic Link", b.String()); err != nil {
		return fmt.Errorf("could not send magic link: %v", err)
	}

	go s.deleteVerificationCodeWhenExpires(verificationCode)

	return nil
}

// AuthURI to be redirected to and complete the login flow.
// It contains the token in the hash fragment.
func (s *Service) AuthURI(ctx context.Context, verificationCode, redirectURI string) (string, error) {
	verificationCode = strings.TrimSpace(verificationCode)
	if !rxUUID.MatchString(verificationCode) {
		return "", ErrInvalidVerificationCode
	}

	uri, err := url.ParseRequestURI(redirectURI)
	if err != nil {
		return "", ErrInvalidRedirectURI
	}

	var uid int64
	err = s.db.QueryRowContext(ctx, `
		DELETE FROM verification_codes WHERE id = $1
		RETURNING user_id`, verificationCode).Scan(&uid)
	if err == sql.ErrNoRows {
		return "", ErrVerificationCodeNotFound
	}

	if err != nil {
		return "", fmt.Errorf("could not delete verification code: %v", err)
	}

	token, err := s.codec.EncodeToString(strconv.FormatInt(uid, 10))
	if err != nil {
		return "", fmt.Errorf("could not create token: %v", err)
	}

	exp, err := time.Now().Add(tokenLifespan).MarshalText()
	if err != nil {
		return "", fmt.Errorf("could not marshall token expiration timestamp: %v", err)
	}

	f := url.Values{}
	f.Set("token", token)
	f.Set("expires_at", string(exp))
	uri.Fragment = f.Encode()

	return uri.String(), nil
}

// DevLogin is a login for development purposes only.
func (s *Service) DevLogin(ctx context.Context, email string) (DevLoginOutput, error) {
	var out DevLoginOutput

	if s.origin.Hostname() != "localhost" {
		return out, ErrUnimplemented
	}

	email = strings.TrimSpace(email)
	if !rxEmail.MatchString(email) {
		return out, ErrInvalidEmail
	}

	var avatar sql.NullString
	query := "SELECT id, username, avatar FROM users WHERE email = $1"
	err := s.db.QueryRowContext(ctx, query, email).Scan(&out.AuthUser.ID, &out.AuthUser.Username, &avatar)

	if err == sql.ErrNoRows {
		return out, ErrUserNotFound
	}

	if err != nil {
		return out, fmt.Errorf("could not query select user: %v", err)
	}

	out.AuthUser.AvatarURL = s.avatarURL(avatar)

	out.Token, err = s.codec.EncodeToString(strconv.FormatInt(out.AuthUser.ID, 10))
	if err != nil {
		return out, fmt.Errorf("could not create token: %v", err)
	}

	out.ExpiresAt = time.Now().Add(tokenLifespan)

	return out, nil
}

// AuthUserIDFromToken decodes the token into a user ID.
func (s *Service) AuthUserIDFromToken(token string) (int64, error) {
	str, err := s.codec.DecodeToString(token)
	if err != nil {
		return 0, fmt.Errorf("could not decode token: %v", err)
	}

	i, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return 0, fmt.Errorf("could not parse auth user id from token: %v", err)
	}

	return i, nil
}

// AuthUser is the current authenticated user.
func (s *Service) AuthUser(ctx context.Context) (User, error) {
	var u User
	uid, ok := ctx.Value(KeyAuthUserID).(int64)
	if !ok {
		return u, ErrUnauthenticated
	}

	return s.userByID(ctx, uid)
}

// Token to authenticate requests.
func (s *Service) Token(ctx context.Context) (TokenOutput, error) {
	var out TokenOutput
	uid, ok := ctx.Value(KeyAuthUserID).(int64)
	if !ok {
		return out, ErrUnauthenticated
	}

	var err error
	out.Token, err = s.codec.EncodeToString(strconv.FormatInt(uid, 10))
	if err != nil {
		return out, fmt.Errorf("could not create token: %v", err)
	}

	out.ExpiresAt = time.Now().Add(tokenLifespan)

	return out, nil
}

func (s *Service) deleteVerificationCodeWhenExpires(code string) {
	<-time.After(verificationCodeLifespan)
	if _, err := s.db.Exec("DELETE FROM verification_codes WHERE id = $1", code); err != nil {
		log.Printf("could not delete expired verification code: %v\n", err)
	}
}
<commit_msg>change: shorter var names<commit_after>package service

import (
	"bytes"
	"context"
	"database/sql"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

// KeyAuthUserID to use in context.
const KeyAuthUserID key = "auth_user_id"

const (
	verificationCodeLifespan = time.Minute * 15
	tokenLifespan            = time.Hour * 24 * 14
)

var (
	// ErrUnimplemented denotes a not implemented functionality.
	ErrUnimplemented = errors.New("unimplemented")
	// ErrUnauthenticated denotes no authenticated user in context.
	ErrUnauthenticated = errors.New("unauthenticated")
	// ErrInvalidRedirectURI denotes an invalid redirect uri.
	ErrInvalidRedirectURI = errors.New("invalid redirect uri")
	// ErrInvalidVerificationCode denotes an invalid verification code.
	ErrInvalidVerificationCode = errors.New("invalid verification code")
	// ErrVerificationCodeNotFound denotes a not found verification code.
	ErrVerificationCodeNotFound = errors.New("verification code not found")
)

var rxUUID = regexp.MustCompile("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")

var magicLinkMailTmpl *template.Template

type key string

// TokenOutput response.
type TokenOutput struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expiresAt"`
}

// DevLoginOutput response.
type DevLoginOutput struct {
	Token     string    `json:"token"`
	ExpiresAt time.Time `json:"expiresAt"`
	AuthUser  User      `json:"authUser"`
}

// SendMagicLink to login without passwords.
func (s *Service) SendMagicLink(ctx context.Context, email, redirectURI string) error {
	email = strings.TrimSpace(email)
	if !rxEmail.MatchString(email) {
		return ErrInvalidEmail
	}

	uri, err := url.ParseRequestURI(redirectURI)
	if err != nil {
		return ErrInvalidRedirectURI
	}

	var code string
	err = s.db.QueryRowContext(ctx, `
		INSERT INTO verification_codes (user_id) VALUES (
			(SELECT id FROM users WHERE email = $1)
		) RETURNING id`, email).Scan(&code)
	if isForeignKeyViolation(err) {
		return ErrUserNotFound
	}

	if err != nil {
		return fmt.Errorf("could not insert verification code: %v", err)
	}

	link := s.origin
	link.Path = "/api/auth_redirect"
	q := link.Query()
	q.Set("verification_code", code)
	q.Set("redirect_uri", uri.String())
	link.RawQuery = q.Encode()

	if magicLinkMailTmpl == nil {
		magicLinkMailTmpl, err = template.ParseFiles("web/template/mail/magic-link.html")
		if err != nil {
			return fmt.Errorf("could not parse magic link mail template: %v", err)
		}
	}

	var b bytes.Buffer
	if err = magicLinkMailTmpl.Execute(&b, map[string]interface{}{
		"MagicLink": link.String(),
		"Minutes":   int(verificationCodeLifespan.Minutes()),
	}); err != nil {
		return fmt.Errorf("could not execute magic link mail template: %v", err)
	}

	if err = s.sender.Send(email, "Magic Link", b.String()); err != nil {
		return fmt.Errorf("could not send magic link: %v", err)
	}

	go s.deleteVerificationCodeWhenExpires(code)

	return nil
}

// AuthURI to be redirected to and complete the login flow.
// It contains the token in the hash fragment.
func (s *Service) AuthURI(ctx context.Context, verificationCode, redirectURI string) (string, error) {
	verificationCode = strings.TrimSpace(verificationCode)
	if !rxUUID.MatchString(verificationCode) {
		return "", ErrInvalidVerificationCode
	}

	uri, err := url.ParseRequestURI(redirectURI)
	if err != nil {
		return "", ErrInvalidRedirectURI
	}

	var uid int64
	err = s.db.QueryRowContext(ctx, `
		DELETE FROM verification_codes WHERE id = $1
		RETURNING user_id`, verificationCode).Scan(&uid)
	if err == sql.ErrNoRows {
		return "", ErrVerificationCodeNotFound
	}

	if err != nil {
		return "", fmt.Errorf("could not delete verification code: %v", err)
	}

	token, err := s.codec.EncodeToString(strconv.FormatInt(uid, 10))
	if err != nil {
		return "", fmt.Errorf("could not create token: %v", err)
	}

	exp, err := time.Now().Add(tokenLifespan).MarshalText()
	if err != nil {
		return "", fmt.Errorf("could not marshall token expiration timestamp: %v", err)
	}

	f := url.Values{}
	f.Set("token", token)
	f.Set("expires_at", string(exp))
	uri.Fragment = f.Encode()

	return uri.String(), nil
}

// DevLogin is a login for development purposes only.
func (s *Service) DevLogin(ctx context.Context, email string) (DevLoginOutput, error) {
	var out DevLoginOutput

	if s.origin.Hostname() != "localhost" {
		return out, ErrUnimplemented
	}

	email = strings.TrimSpace(email)
	if !rxEmail.MatchString(email) {
		return out, ErrInvalidEmail
	}

	var avatar sql.NullString
	query := "SELECT id, username, avatar FROM users WHERE email = $1"
	err := s.db.QueryRowContext(ctx, query, email).Scan(&out.AuthUser.ID, &out.AuthUser.Username, &avatar)

	if err == sql.ErrNoRows {
		return out, ErrUserNotFound
	}

	if err != nil {
		return out, fmt.Errorf("could not query select user: %v", err)
	}

	out.AuthUser.AvatarURL = s.avatarURL(avatar)

	out.Token, err = s.codec.EncodeToString(strconv.FormatInt(out.AuthUser.ID, 10))
	if err != nil {
		return out, fmt.Errorf("could not create token: %v", err)
	}

	out.ExpiresAt = time.Now().Add(tokenLifespan)

	return out, nil
}

// AuthUserIDFromToken decodes the token into a user ID.
func (s *Service) AuthUserIDFromToken(token string) (int64, error) {
	str, err := s.codec.DecodeToString(token)
	if err != nil {
		return 0, fmt.Errorf("could not decode token: %v", err)
	}

	i, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		return 0, fmt.Errorf("could not parse auth user id from token: %v", err)
	}

	return i, nil
}

// AuthUser is the current authenticated user.
func (s *Service) AuthUser(ctx context.Context) (User, error) {
	var u User
	uid, ok := ctx.Value(KeyAuthUserID).(int64)
	if !ok {
		return u, ErrUnauthenticated
	}

	return s.userByID(ctx, uid)
}

// Token to authenticate requests.
func (s *Service) Token(ctx context.Context) (TokenOutput, error) {
	var out TokenOutput
	uid, ok := ctx.Value(KeyAuthUserID).(int64)
	if !ok {
		return out, ErrUnauthenticated
	}

	var err error
	out.Token, err = s.codec.EncodeToString(strconv.FormatInt(uid, 10))
	if err != nil {
		return out, fmt.Errorf("could not create token: %v", err)
	}

	out.ExpiresAt = time.Now().Add(tokenLifespan)

	return out, nil
}

func (s *Service) deleteVerificationCodeWhenExpires(code string) {
	<-time.After(verificationCodeLifespan)
	if _, err := s.db.Exec("DELETE FROM verification_codes WHERE id = $1", code); err != nil {
		log.Printf("could not delete expired verification code: %v\n", err)
	}
}
<|endoftext|>


<commit_before>package glisp

type GlispFunction func(*Glisp, int)
<commit_msg>basic comparison functions<commit_after>package glisp

import (
	"errors"
	"fmt"
	"bytes"
)

var WrongNargs error = errors.New("wrong number of arguments")

type GlispFunction func(*Glisp, SexpSymbol, int) error
type GlispUserFunction func(*Glisp, string, []Sexp) (Sexp, error)

func MakeUserFunction(fun GlispUserFunction) GlispFunction {
	return func(glisp *Glisp, sym SexpSymbol, nargs int) error {
		arr, err := glisp.datastack.PopExpressions(nargs)
		if err != nil {
			return err
		}
		res, err := fun(glisp, sym.name, arr)
		if err != nil {
			return err
		}
		glisp.datastack.PushExpr(res)
		return nil
	}
}

func signum(f SexpFloat) int {
	if f > 0 {
		return 1
	}
	if f < 0 {
		return -1
	}
	return 0
}

func compareFloat(f SexpFloat, expr Sexp) (int, error) {
	switch e := expr.(type) {
	case SexpInt:
		return signum(f - SexpFloat(e)), nil
	case SexpUint:
		return signum(f - SexpFloat(e)), nil
	case SexpFloat:
		return signum(f - e), nil
	case SexpChar:
		return signum(f - SexpFloat(e)), nil
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", f, expr)
	return 0, errors.New(errmsg)
}

func compareInt(i SexpInt, expr Sexp) (int, error) {
	switch e := expr.(type) {
	case SexpInt:
		return signum(SexpFloat(i - e)), nil
	case SexpUint:
		return signum(SexpFloat(i - SexpInt(e))), nil
	case SexpFloat:
		return signum(SexpFloat(i) - e), nil
	case SexpChar:
		return signum(SexpFloat(i - SexpInt(e))), nil
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", i, expr)
	return 0, errors.New(errmsg)
}

func compareUint(u SexpUint, expr Sexp) (int, error) {
	switch e := expr.(type) {
	case SexpInt:
		return signum(SexpFloat(SexpInt(u) - e)), nil
	case SexpUint:
		return signum(SexpFloat(u - e)), nil
	case SexpFloat:
		return signum(SexpFloat(u) - e), nil
	case SexpChar:
		return signum(SexpFloat(u - SexpUint(e))), nil
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", u, expr)
	return 0, errors.New(errmsg)
}

func compareChar(c SexpChar, expr Sexp) (int, error) {
	switch e := expr.(type) {
	case SexpInt:
		return signum(SexpFloat(SexpInt(c) - e)), nil
	case SexpUint:
		return signum(SexpFloat(SexpUint(c) - e)), nil
	case SexpFloat:
		return signum(SexpFloat(c) - e), nil
	case SexpChar:
		return signum(SexpFloat(c - e)), nil
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", c, expr)
	return 0, errors.New(errmsg)
}

func compareString(s SexpStr, expr Sexp) (int, error) {
	switch e := expr.(type) {
	case SexpStr:
		return bytes.Compare([]byte(s), []byte(e)), nil
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", s, expr)
	return 0, errors.New(errmsg)
}

func Compare(a Sexp, b Sexp) (int, error) {
	switch at := a.(type) {
	case SexpInt:
		return compareInt(at, b)
	case SexpUint:
		return compareUint(at, b)
	case SexpChar:
		return compareChar(at, b)
	case SexpFloat:
		return compareFloat(at, b)
	case SexpStr:
		return compareString(at, b)
	}
	errmsg := fmt.Sprintf("cannot compare %T to %T", a, b)
	return 0, errors.New(errmsg)
}

func CompareFunction(glisp *Glisp, sym SexpSymbol, nargs int) error {
	if nargs != 2 {
		return WrongNargs
	}
	arr, err := glisp.datastack.PopExpressions(nargs)
	if err != nil {
		return err
	}
	res, err := Compare(arr[0], arr[1])
	if err != nil {
		return err
	}

	cond := false
	switch sym.name {
	case "<":
		cond = res < 0
	case ">":
		cond = res > 0
	case "<=":
		cond = res <= 0
	case ">=":
		cond = res >= 0
	case "=":
		cond = res == 0
	case "not=":
		cond = res != 0
	}
	glisp.datastack.PushExpr(SexpBool(cond))

	return nil
}

/*func ArithFunction(glisp *Glisp, sym SexpSymbol, nargs int) error {
	arr, err := glisp.datastack.PopExpressions(nargs)
	if err != nil {
		return err
	}
}*/

var BuiltinFunctions = map[string]GlispFunction {
	"<" : CompareFunction,
	">" : CompareFunction,
	"<=": CompareFunction,
	">=": CompareFunction,
	"=" : CompareFunction,
	"not=": CompareFunction,
}
<|endoftext|>


<commit_before>package focker

import (
	"io"
	"log"
	"os"

	"github.com/hatofmonkeys/cloudfocker/buildpack"
	"github.com/hatofmonkeys/cloudfocker/config"
	"github.com/hatofmonkeys/cloudfocker/docker"
	df "github.com/hatofmonkeys/cloudfocker/dockerfile"
	"github.com/hatofmonkeys/cloudfocker/stager"
	"github.com/hatofmonkeys/cloudfocker/utils"
)

type Focker struct {
	Stdout *io.PipeReader
}

func NewFocker() *Focker {
	return &Focker{}
}

func (Focker) DockerVersion(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.PrintVersion(cli, Stdout, stdoutpipe, writer)
}

func (Focker) ImportRootfsImage(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.ImportRootfsImage(cli, Stdout, stdoutpipe, writer, utils.GetRootfsUrl())
}

func (Focker) WriteDockerfile(writer io.Writer) {
	dockerfile := df.NewDockerfile()
	dockerfile.Create()
	dockerfile.Write(writer)
}

func (Focker) BuildImage(writer io.Writer) {
	dockerfile := df.NewDockerfile()
	dockerfile.Create()
	dockerfile.Persist(cloudFockerfileLocation())
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.BuildImage(cli, Stdout, stdoutpipe, writer, cloudFockerfileLocation())
}

func (f Focker) RunContainer(writer io.Writer) {
	f.BuildImage(writer)
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.RunContainer(cli, Stdout, stdoutpipe, writer)
}

func (f Focker) StopContainer(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.StopContainer(cli, Stdout, stdoutpipe, writer)
	f.DeleteContainer(writer, "cloudfocker-container")
}

func (Focker) DeleteContainer(writer io.Writer, name string) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.DeleteContainer(cli, Stdout, stdoutpipe, writer, name)
}

func (Focker) AddBuildpack(writer io.Writer, url string, buildpackDirOptional ...string) {
	buildpackDir := utils.Cloudfockerhome() + "/buildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	buildpack.Add(writer, url, buildpackDir)
}

func (f Focker) RunStager(writer io.Writer, appDir string, buildpackDirOptional ...string) {
	buildpackDir := utils.Cloudfockerhome() + "/buildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	if err := utils.CreateAndCleanAppDirs(utils.Cloudfockerhome()); err != nil {
		log.Fatalf(" %s", err)
	}
	if err := utils.AtLeastOneBuildpackIn(buildpackDir); err != nil {
		log.Fatalf(" %s", err)
	}
	if err := utils.CopyFockerBinaryToOwnDir(utils.Cloudfockerhome()); err != nil {
		log.Fatalf(" %s", err)
	}
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	runConfig := config.NewStageRunConfig(appDir)
	docker.RunConfiguredContainer(cli, Stdout, stdoutpipe, writer, runConfig)
	f.DeleteContainer(writer, runConfig.ContainerName)
}

func (Focker) StageApp(writer io.Writer, buildpackDirOptional ...string) error {
	buildpackDir := "/tmp/cloudfockerbuildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	buildpackRunner := stager.NewBuildpackRunner(buildpackDir)
	err := stager.RunBuildpack(writer, buildpackRunner)
	return err
}

func cloudFockerfileLocation() (location string) {
	pwd, err := os.Getwd()
	if err != nil {
		log.Fatalf(" %s", err)
	}
	location = pwd + "/CloudFockerfile"
	return
}
<commit_msg>move staging fs prep to function<commit_after>package focker

import (
	"io"
	"log"
	"os"

	"github.com/hatofmonkeys/cloudfocker/buildpack"
	"github.com/hatofmonkeys/cloudfocker/config"
	"github.com/hatofmonkeys/cloudfocker/docker"
	df "github.com/hatofmonkeys/cloudfocker/dockerfile"
	"github.com/hatofmonkeys/cloudfocker/stager"
	"github.com/hatofmonkeys/cloudfocker/utils"
)

type Focker struct {
	Stdout *io.PipeReader
}

func NewFocker() *Focker {
	return &Focker{}
}

func (Focker) DockerVersion(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.PrintVersion(cli, Stdout, stdoutpipe, writer)
}

func (Focker) ImportRootfsImage(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.ImportRootfsImage(cli, Stdout, stdoutpipe, writer, utils.GetRootfsUrl())
}

func (Focker) WriteDockerfile(writer io.Writer) {
	dockerfile := df.NewDockerfile()
	dockerfile.Create()
	dockerfile.Write(writer)
}

func (Focker) BuildImage(writer io.Writer) {
	dockerfile := df.NewDockerfile()
	dockerfile.Create()
	dockerfile.Persist(cloudFockerfileLocation())
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.BuildImage(cli, Stdout, stdoutpipe, writer, cloudFockerfileLocation())
}

func (f Focker) RunContainer(writer io.Writer) {
	f.BuildImage(writer)
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.RunContainer(cli, Stdout, stdoutpipe, writer)
}

func (f Focker) StopContainer(writer io.Writer) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.StopContainer(cli, Stdout, stdoutpipe, writer)
	f.DeleteContainer(writer, "cloudfocker-container")
}

func (Focker) DeleteContainer(writer io.Writer, name string) {
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	docker.DeleteContainer(cli, Stdout, stdoutpipe, writer, name)
}

func (Focker) AddBuildpack(writer io.Writer, url string, buildpackDirOptional ...string) {
	buildpackDir := utils.Cloudfockerhome() + "/buildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	buildpack.Add(writer, url, buildpackDir)
}

func (f Focker) RunStager(writer io.Writer, appDir string, buildpackDirOptional ...string) {
	buildpackDir := utils.Cloudfockerhome() + "/buildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	prepareStagingFilesystem(utils.Cloudfockerhome(), buildpackDir)
	cli, Stdout, stdoutpipe := docker.GetNewClient()
	runConfig := config.NewStageRunConfig(appDir)
	docker.RunConfiguredContainer(cli, Stdout, stdoutpipe, writer, runConfig)
	f.DeleteContainer(writer, runConfig.ContainerName)
}

func (Focker) StageApp(writer io.Writer, buildpackDirOptional ...string) error {
	buildpackDir := "/tmp/cloudfockerbuildpacks"
	if len(buildpackDirOptional) > 0 {
		buildpackDir = buildpackDirOptional[0]
	}
	buildpackRunner := stager.NewBuildpackRunner(buildpackDir)
	err := stager.RunBuildpack(writer, buildpackRunner)
	return err
}

func cloudFockerfileLocation() (location string) {
	pwd, err := os.Getwd()
	if err != nil {
		log.Fatalf(" %s", err)
	}
	location = pwd + "/CloudFockerfile"
	return
}

func prepareStagingFilesystem(cloudfockerhome string, buildpackDir string) {
	if err := utils.CreateAndCleanAppDirs(cloudfockerhome); err != nil {
		log.Fatalf(" %s", err)
	}
	if err := utils.AtLeastOneBuildpackIn(buildpackDir); err != nil {
		log.Fatalf(" %s", err)
	}
	if err := utils.CopyFockerBinaryToOwnDir(cloudfockerhome); err != nil {
		log.Fatalf(" %s", err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Davin Hills. All rights reserved.
// MIT license. License details can be found in the LICENSE file.

// Package shelltask implements a set of tasks to interact with the shell.
// Each task is intended to do one discrete thing such as file copy or rename.
package shelltask

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/dshills/goauto"
)

type shellTask struct {
	cmd       string
	args      []string
	transform goauto.Transformer
}

// NewShellTask returns a goauto.Tasker which calls out to the shell with the command cmd and arguments arg
// the goauto.TaskInfo.Target will be the last argument and is equal to goauto.TaskInfo.Src
// goauto.TaskInfo.Target is set to goauto.TaskInfo.Src
func NewShellTask(cmd string, args ...string) goauto.Tasker {
	return &shellTask{cmd: cmd, args: args, transform: goauto.Identity}
}

// NewShellTaskT returns a goauto.Tasker which calls out to the shell with the command cmd and arguments arg
// the goauto.TaskInfo.Target will be the last argument and is generated by transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewShellTaskT(transform goauto.Transformer, cmd string, args ...string) goauto.Tasker {
	return &shellTask{cmd: cmd, args: args, transform: transform}
}

// Run will execute the task
func (st *shellTask) Run(info *goauto.TaskInfo) (err error) {
	t0 := time.Now()
	info.Target = st.transform(info.Src)
	info.Buf.Reset()
	targs := append(st.args, info.Target)
	cmd := exec.Command(st.cmd, targs...)
	cmd.Stdout = &info.Buf
	cmd.Stderr = info.Terr

	defer func() {
		fmt.Fprint(info.Tout, info.Buf)
		if err != nil && info.Verbose {
			t1 := time.Now()
			fmt.Fprintf(info.Tout, ">>> %v %v %v\n", st.cmd, st.args, t1.Sub(t0))
		}
	}()
	err = cmd.Run()
	return
}

// NewCatTask returns a goauto.Tasker which writes the file contents to goauto.TaskInfo.Buf and goauto.TaskInfo.Tout
// after running transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewCatTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, cat)
}

func cat(info *goauto.TaskInfo) (err error) {
	in, err := os.Open(info.Target)
	if err != nil {
		return
	}
	defer func() {
		err = in.Close()
	}()
	info.Buf.Reset()
	_, err = info.Buf.ReadFrom(in)
	if err != nil {
		return
	}
	fmt.Fprint(info.Tout, info.Buf)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> cat %v", info.Target)
	}
	return
}

// NewRemoveTask returns a goauto.Tasker which will delete the file named transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewRemoveTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, remove)
}

func remove(info *goauto.TaskInfo) (err error) {
	err = os.Remove(info.Target)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> Remove %v", info.Target)
	}
	return
}

// NewMoveTask returns a goauto.Tasker which will rename a file from goauto.TaskInfo.Target to transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewMoveTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, move)
}

func move(info *goauto.TaskInfo) (err error) {
	err = os.Rename(info.Src, info.Target)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> Renaming %v to %v", info.Src, info.Target)
	}
	return
}

// NewMkdirTask returns a goauto.Tasker which makes a new dir named transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is not reset
func NewMkdirTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, mkdir)
}

func mkdir(info *goauto.TaskInfo) (err error) {
	dir := info.Target
	info.Target = info.Src
	if err = os.Mkdir(dir, 0755); err != nil && !os.IsExist(err) {
		return
	}
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> mkdir %v\n", dir)
	}
	return
}

// NewCopyTask returns a goauto.Tasker that copies the file contents of goauto.TaskInfo.Src to transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewCopyTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, fcopy)
}

func fcopy(info *goauto.TaskInfo) (err error) {
	in, err := os.Open(info.Src)
	if err != nil {
		return
	}
	defer func() {
		err = in.Close()
	}()

	out, err := os.Create(info.Target)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
		if err != nil && info.Verbose {
			fmt.Fprintf(info.Tout, ">>> Copy %v to %v\n", info.Src, info.Target)
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}

	return out.Sync()
}

// NewWFCompleteTask returns a task that simply outputs a Workflow completed message
// for those of us who like a little feedback
func NewWFCompleteTask(name string) goauto.Tasker {
	return NewShellTask("echo", ">> "+name+" complete")
}
<commit_msg>Added a echo task and new line task for output formatting.<commit_after>// Copyright 2015 Davin Hills. All rights reserved.
// MIT license. License details can be found in the LICENSE file.

// Package shelltask implements a set of tasks to interact with the shell.
// Each task is intended to do one discrete thing such as file copy or rename.
package shelltask

import (
	"fmt"
	"io"
	"os"
	"os/exec"
	"time"

	"github.com/dshills/goauto"
)

type shellTask struct {
	cmd       string
	args      []string
	transform goauto.Transformer
}

// NewShellTask returns a goauto.Tasker which calls out to the shell with the command cmd and arguments arg
// the goauto.TaskInfo.Target will be the last argument and is equal to goauto.TaskInfo.Src
// goauto.TaskInfo.Target is set to goauto.TaskInfo.Src
func NewShellTask(cmd string, args ...string) goauto.Tasker {
	return &shellTask{cmd: cmd, args: args, transform: goauto.Identity}
}

// NewShellTaskT returns a goauto.Tasker which calls out to the shell with the command cmd and arguments arg
// the goauto.TaskInfo.Target will be the last argument and is generated by transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewShellTaskT(transform goauto.Transformer, cmd string, args ...string) goauto.Tasker {
	return &shellTask{cmd: cmd, args: args, transform: transform}
}

// Run will execute the task
func (st *shellTask) Run(info *goauto.TaskInfo) (err error) {
	t0 := time.Now()
	info.Target = st.transform(info.Src)
	info.Buf.Reset()
	targs := append(st.args, info.Target)
	cmd := exec.Command(st.cmd, targs...)
	cmd.Stdout = &info.Buf
	cmd.Stderr = info.Terr

	defer func() {
		fmt.Fprint(info.Tout, info.Buf.String())
		if err != nil && info.Verbose {
			t1 := time.Now()
			fmt.Fprintf(info.Tout, ">>> %v %v %v\n", st.cmd, st.args, t1.Sub(t0))
		}
	}()
	err = cmd.Run()
	return
}

// NewCatTask returns a goauto.Tasker which writes the file contents to goauto.TaskInfo.Buf and goauto.TaskInfo.Tout
// after running transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewCatTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, cat)
}

func cat(info *goauto.TaskInfo) (err error) {
	in, err := os.Open(info.Target)
	if err != nil {
		return
	}
	defer func() {
		err = in.Close()
	}()
	info.Buf.Reset()
	_, err = info.Buf.ReadFrom(in)
	if err != nil {
		return
	}
	fmt.Fprint(info.Tout, info.Buf)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> cat %v", info.Target)
	}
	return
}

// NewRemoveTask returns a goauto.Tasker which will delete the file named transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewRemoveTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, remove)
}

func remove(info *goauto.TaskInfo) (err error) {
	err = os.Remove(info.Target)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> Remove %v", info.Target)
	}
	return
}

// NewMoveTask returns a goauto.Tasker which will rename a file from goauto.TaskInfo.Target to transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewMoveTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, move)
}

func move(info *goauto.TaskInfo) (err error) {
	err = os.Rename(info.Src, info.Target)
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> Renaming %v to %v", info.Src, info.Target)
	}
	return
}

// NewMkdirTask returns a goauto.Tasker which makes a new dir named transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is not reset
func NewMkdirTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, mkdir)
}

func mkdir(info *goauto.TaskInfo) (err error) {
	dir := info.Target
	info.Target = info.Src
	if err = os.Mkdir(dir, 0755); err != nil && !os.IsExist(err) {
		return
	}
	if err != nil && info.Verbose {
		fmt.Fprintf(info.Tout, ">>> mkdir %v\n", dir)
	}
	return
}

// NewCopyTask returns a goauto.Tasker that copies the file contents of goauto.TaskInfo.Src to transform(goauto.TaskInfo.Src)
// goauto.TaskInfo.Target is set to transform(goauto.TaskInfo.Src)
func NewCopyTask(t goauto.Transformer) goauto.Tasker {
	return goauto.NewTask(t, fcopy)
}

func fcopy(info *goauto.TaskInfo) (err error) {
	in, err := os.Open(info.Src)
	if err != nil {
		return
	}
	defer func() {
		err = in.Close()
	}()

	out, err := os.Create(info.Target)
	if err != nil {
		return
	}
	defer func() {
		cerr := out.Close()
		if err == nil {
			err = cerr
		}
		if err != nil && info.Verbose {
			fmt.Fprintf(info.Tout, ">>> Copy %v to %v\n", info.Src, info.Target)
		}
	}()
	if _, err = io.Copy(out, in); err != nil {
		return
	}

	return out.Sync()
}

// NewEchoTask returns a task that echos args
// for those of us who like a little feedback
func NewEchoTask(args ...string) goauto.Tasker {
	return NewShellTask("echo", args...)
}

type lineTask struct{}

// NewLineTask returns a task the inserts a new blank line in the output
func NewLineTask() goauto.Tasker {
	return &lineTask{}
}

// Run will execute the task
func (lt *lineTask) Run(info *goauto.TaskInfo) (err error) {
	fmt.Fprintln(info.Tout)
	return
}
<|endoftext|>


<commit_before>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

// TermsSetQuery returns any documents that match with at least
// one or more of the provided terms. The terms are not analyzed
// and thus must match exactly. The number of terms that must
// match varies per document and is either controlled by a
// minimum should match field or computed per document in a
// minimum should match script.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/6.2/query-dsl-terms-set-query.html
type TermsSetQuery struct {
	name                     string
	values                   []interface{}
	minimumShouldMatchField  string
	minimumShouldMatchScript *Script
	queryName                string
	boost                    *float64
}

// NewTermsSetQuery creates and initializes a new TermsSetQuery.
func NewTermsSetQuery(name string, values ...interface{}) *TermsSetQuery {
	q := &TermsSetQuery{
		name: name,
	}
	if len(values) > 0 {
		q.values = append(q.values, values...)
	}
	return q
}

// MinimumShouldMatchField specifies the field to match.
func (q *TermsSetQuery) MinimumShouldMatchField(minimumShouldMatchField string) *TermsSetQuery {
	q.minimumShouldMatchField = minimumShouldMatchField
	return q
}

// MinimumShouldMatchScript specifies the script to match.
func (q *TermsSetQuery) MinimumShouldMatchScript(minimumShouldMatchScript *Script) *TermsSetQuery {
	q.minimumShouldMatchScript = minimumShouldMatchScript
	return q
}

// Boost sets the boost for this query.
func (q *TermsSetQuery) Boost(boost float64) *TermsSetQuery {
	q.boost = &boost
	return q
}

// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *TermsSetQuery) QueryName(queryName string) *TermsSetQuery {
	q.queryName = queryName
	return q
}

// Source creates the query source for the term query.
func (q *TermsSetQuery) Source() (interface{}, error) {
	// {"terms_set":{"codes":{"terms":["abc","def"],"minimum_should_match_field":"required_matches"}}}
	source := make(map[string]interface{})
	inner := make(map[string]interface{})
	params := make(map[string]interface{})
	inner[q.name] = params
	source["terms_set"] = inner

	// terms
	params["terms"] = q.values

	// minimum_should_match_field
	if match := q.minimumShouldMatchField; match != "" {
		params["minimum_should_match_field"] = match
	}

	// minimum_should_match_script
	if match := q.minimumShouldMatchScript; match != nil {
		src, err := match.Source()
		if err != nil {
			return nil, err
		}
		params["minimum_should_match_script"] = src
	}

	// Common parameters for all queries
	if q.boost != nil {
		params["boost"] = *q.boost
	}
	if q.queryName != "" {
		params["_name"] = q.queryName
	}

	return source, nil
}
<commit_msg>Initialize TermsSetQuery values<commit_after>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

// TermsSetQuery returns any documents that match with at least
// one or more of the provided terms. The terms are not analyzed
// and thus must match exactly. The number of terms that must
// match varies per document and is either controlled by a
// minimum should match field or computed per document in a
// minimum should match script.
//
// For more details, see
// https://www.elastic.co/guide/en/elasticsearch/reference/6.2/query-dsl-terms-set-query.html
type TermsSetQuery struct {
	name                     string
	values                   []interface{}
	minimumShouldMatchField  string
	minimumShouldMatchScript *Script
	queryName                string
	boost                    *float64
}

// NewTermsSetQuery creates and initializes a new TermsSetQuery.
func NewTermsSetQuery(name string, values ...interface{}) *TermsSetQuery {
	q := &TermsSetQuery{
		name:   name,
		values: make([]interface{}, 0),
	}
	if len(values) > 0 {
		q.values = append(q.values, values...)
	}
	return q
}

// MinimumShouldMatchField specifies the field to match.
func (q *TermsSetQuery) MinimumShouldMatchField(minimumShouldMatchField string) *TermsSetQuery {
	q.minimumShouldMatchField = minimumShouldMatchField
	return q
}

// MinimumShouldMatchScript specifies the script to match.
func (q *TermsSetQuery) MinimumShouldMatchScript(minimumShouldMatchScript *Script) *TermsSetQuery {
	q.minimumShouldMatchScript = minimumShouldMatchScript
	return q
}

// Boost sets the boost for this query.
func (q *TermsSetQuery) Boost(boost float64) *TermsSetQuery {
	q.boost = &boost
	return q
}

// QueryName sets the query name for the filter that can be used
// when searching for matched_filters per hit
func (q *TermsSetQuery) QueryName(queryName string) *TermsSetQuery {
	q.queryName = queryName
	return q
}

// Source creates the query source for the term query.
func (q *TermsSetQuery) Source() (interface{}, error) {
	// {"terms_set":{"codes":{"terms":["abc","def"],"minimum_should_match_field":"required_matches"}}}
	source := make(map[string]interface{})
	inner := make(map[string]interface{})
	params := make(map[string]interface{})
	inner[q.name] = params
	source["terms_set"] = inner

	// terms
	params["terms"] = q.values

	// minimum_should_match_field
	if match := q.minimumShouldMatchField; match != "" {
		params["minimum_should_match_field"] = match
	}

	// minimum_should_match_script
	if match := q.minimumShouldMatchScript; match != nil {
		src, err := match.Source()
		if err != nil {
			return nil, err
		}
		params["minimum_should_match_script"] = src
	}

	// Common parameters for all queries
	if q.boost != nil {
		params["boost"] = *q.boost
	}
	if q.queryName != "" {
		params["_name"] = q.queryName
	}

	return source, nil
}
<|endoftext|>


<commit_before>package mqtt

import (
	"bytes"
	proto "github.com/huin/mqtt"
	"github.com/jeffallen/mqtt"
	"golang.org/x/net/context"
	"net"
)

type Config struct {
	Host string
	Port string
	User string
	Pass string
	CID  string
}

type MQTT struct {
	Config
	Messages chan Publish
	cl       *mqtt.ClientConn
}

type Publish struct {
	Topic string
	ID    uint16
	Msg   string
}

func New(cfg Config) *MQTT {
	return &MQTT{
		Config: cfg,
		Messages:   make(chan Publish),
	}
}

func (m *MQTT) Connect(ctx context.Context) error {
	conn, err := net.Dial("tcp", m.Host+":"+m.Port)

	if err != nil {
		panic(err)
	}

	m.cl = mqtt.NewClientConn(conn)
	m.cl.ClientId = m.CID

	err = m.cl.Connect(m.User, m.Pass)

	if err != nil {
		return err
	}

	go m.listen(ctx)

	return nil
}

func (m *MQTT) Subscribe(topic string) {

	sub := []proto.TopicQos{
		{
			Topic: topic,
			Qos:   proto.QosAtLeastOnce,
		},
	}

	m.cl.Subscribe(sub)
}

func (m *MQTT) listen(ctx context.Context) {
Listen:
	for {
		select {
		case <-ctx.Done():
			break Listen
		case p := <-m.cl.Incoming:
			m.receive(p)
		}
	}
}

func (m *MQTT) receive(p *proto.Publish) {
	buf := new(bytes.Buffer)

	if err := p.Payload.WritePayload(buf); err != nil {
		panic(err)
	}

	pb := Publish{
		Topic: p.TopicName,
		ID:    p.MessageId,
		Msg:   buf.String(),
	}

	m.Messages <- pb
}
<commit_msg>Avoid null pointer dereference when trying to subscribe to topic “” (empty string)<commit_after>package mqtt

import (
	"bytes"
	proto "github.com/huin/mqtt"
	"github.com/jeffallen/mqtt"
	"golang.org/x/net/context"
	"net"
)

type Config struct {
	Host string
	Port string
	User string
	Pass string
	CID  string
}

type MQTT struct {
	Config
	Messages chan Publish
	cl       *mqtt.ClientConn
}

type Publish struct {
	Topic string
	ID    uint16
	Msg   string
}

func New(cfg Config) *MQTT {
	return &MQTT{
		Config: cfg,
		Messages:   make(chan Publish),
	}
}

func (m *MQTT) Connect(ctx context.Context) error {
	conn, err := net.Dial("tcp", m.Host+":"+m.Port)

	if err != nil {
		panic(err)
	}

	m.cl = mqtt.NewClientConn(conn)
	m.cl.ClientId = m.CID

	err = m.cl.Connect(m.User, m.Pass)

	if err != nil {
		return err
	}

	go m.listen(ctx)

	return nil
}

func (m *MQTT) Subscribe(topic string) {
	if topic == "" {
		return
	}

	sub := []proto.TopicQos{
		{
			Topic: topic,
			Qos:   proto.QosAtLeastOnce,
		},
	}

	m.cl.Subscribe(sub)
}

func (m *MQTT) listen(ctx context.Context) {
Listen:
	for {
		select {
		case <-ctx.Done():
			break Listen
		case p := <-m.cl.Incoming:
			m.receive(p)
		}
	}
}

func (m *MQTT) receive(p *proto.Publish) {
	buf := new(bytes.Buffer)

	if err := p.Payload.WritePayload(buf); err != nil {
		panic(err)
	}

	pb := Publish{
		Topic: p.TopicName,
		ID:    p.MessageId,
		Msg:   buf.String(),
	}

	m.Messages <- pb
}
<|endoftext|>


<commit_before>package freeze

import (
	"fmt"
	"time"

	"github.com/google/go-github/github"
	"github.com/parkr/auto-reply/ctx"
)

var (
	TooOld    = time.Now().Add(-365 * 24 * time.Hour).Format("2006-01-02")
	LabelName = "frozen-due-to-age"
)

func AllTooOldIssues(context *ctx.Context, owner, repo string) ([]github.Issue, error) {
	issues := []github.Issue{}
	query := fmt.Sprintf("repo:%s/%s is:closed -label:%v updated:<=%s", owner, repo, LabelName, TooOld)
	fmt.Println(query)
	opts := &github.SearchOptions{
		Sort:  "created",
		Order: "asc",
		ListOptions: github.ListOptions{
			PerPage: 500,
		},
	}

	for {
		result, resp, err := context.GitHub.Search.Issues(query, opts)
		if err != nil {
			return nil, err
		}

		if *result.Total == 0 {
			return nil, nil
		}

		issues = append(issues, result.Issues...)

		if resp.NextPage == 0 {
			break
		}
		opts.ListOptions.Page = resp.NextPage
	}

	return issues, nil
}

func Freeze(context *ctx.Context, owner, repo string, issueNum int) error {
	_, err := context.GitHub.Issues.Lock(owner, repo, issueNum)
	if err != nil {
		return err
	}
	_, _, err = context.GitHub.Issues.AddLabelsToIssue(owner, repo, issueNum, []string{LabelName})
	return err
}
<commit_msg>freeze: return the issues we have if the search result shows 0 issues<commit_after>package freeze

import (
	"fmt"
	"time"

	"github.com/google/go-github/github"
	"github.com/parkr/auto-reply/ctx"
)

var (
	TooOld    = time.Now().Add(-365 * 24 * time.Hour).Format("2006-01-02")
	LabelName = "frozen-due-to-age"
)

func AllTooOldIssues(context *ctx.Context, owner, repo string) ([]github.Issue, error) {
	issues := []github.Issue{}
	query := fmt.Sprintf("repo:%s/%s is:closed -label:%v updated:<=%s", owner, repo, LabelName, TooOld)
	fmt.Println(query)
	opts := &github.SearchOptions{
		Sort:  "created",
		Order: "asc",
		ListOptions: github.ListOptions{
			PerPage: 500,
		},
	}

	for {
		result, resp, err := context.GitHub.Search.Issues(query, opts)
		if err != nil {
			return nil, err
		}

		if *result.Total == 0 {
			return issues, nil
		}

		issues = append(issues, result.Issues...)

		if resp.NextPage == 0 {
			break
		}
		opts.ListOptions.Page = resp.NextPage
	}

	return issues, nil
}

func Freeze(context *ctx.Context, owner, repo string, issueNum int) error {
	_, err := context.GitHub.Issues.Lock(owner, repo, issueNum)
	if err != nil {
		return err
	}
	_, _, err = context.GitHub.Issues.AddLabelsToIssue(owner, repo, issueNum, []string{LabelName})
	return err
}
<|endoftext|>


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

// Package ui provides http request handlers for the Pi client WebApp

package ui

import (
	"bytes"
	"fmt"
	"net/http"
	"os/exec"
)

func doShutdown() (string, error) {
	// Issue the system shutdown command and return the command line output,
	// which, if successful, it will be the standard system message. This
	// works on the pi b/c the default user has sudo privilege; on another
	// client device, this needs to be changed, else a sudoers update is needed.
	shutdownCmd := []string{"sudo", "poweroff"}
	cmd := exec.Command(shutdownCmd[0], shutdownCmd[1:]...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()

	fmt.Printf("Shutdown stdout: %s\n", out.String())
	fmt.Printf("Shutdown stderr: %s\n", err.Error())
	return out.String(), err
}

// Issue the shutdown and write back the system command output
func ShutdownClientHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		result, err := doShutdown()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintf(w, result)
	}
}
<commit_msg>Confirmed client shutdown button through webapp works<commit_after>// Copyright Banrai LLC. All rights reserved. Use of this source code is
// governed by the license that can be found in the LICENSE file.

// Package ui provides http request handlers for the Pi client WebApp

package ui

import (
	"bytes"
	"fmt"
	"net/http"
	"os/exec"
)

func doShutdown() (string, error) {
	// Issue the system shutdown command and return the command line output,
	// which, if successful, it will be the standard system message. This
	// works on the pi b/c the default user has sudo privilege; on another
	// client device, this needs to be changed, else a sudoers update is needed.
	shutdownCmd := []string{"sudo", "poweroff"}
	cmd := exec.Command(shutdownCmd[0], shutdownCmd[1:]...)

	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()

	return out.String(), err
}

// Issue the shutdown and write back the system command output
func ShutdownClientHandler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		result, err := doShutdown()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintf(w, result)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package msg

// IMPORTANT: You need a very good reason to change this file, because changes
// might break compatibility between different message formats!

import (
	"bytes"
	"encoding/binary"
	"io"

	"github.com/mutecomm/mute/log"
)

// ReadFirstOuterHeader reads the first outer header from the base64 decoder r
// and returns the version and the preHeader for further processing. This
// function is intended to be used outside the msg package to allow to check
// for incompatible message format changes down the line.
func ReadFirstOuterHeader(r io.Reader) (version uint16, preHeader []byte, err error) {
	var (
		Type        uint8
		PLen        uint16
		PacketCount uint32
	)
	// read Type
	if err := binary.Read(r, binary.BigEndian, &Type); err != nil {
		return 0, nil, err
	}
	if Type != 1 {
		return 0, nil, log.Error(ErrNotPreHeader)
	}
	// read Plen
	if err := binary.Read(r, binary.BigEndian, &PLen); err != nil {
		return 0, nil, log.Error(err)
	}
	// read PacketCount
	if err := binary.Read(r, binary.BigEndian, &PacketCount); err != nil {
		return 0, nil, log.Error(err)
	}
	if PacketCount != 0 {
		return 0, nil, log.Error(ErrWrongCount)
	}
	// read inner packet
	preHeader = make([]byte, PLen)
	if _, err := io.ReadFull(r, preHeader); err != nil {
		return 0, nil, log.Error(err)
	}
	// parse version
	if err := binary.Read(bytes.NewBuffer(preHeader), binary.BigEndian, &version); err != nil {
		return 0, nil, log.Error(err)
	}
	return
}
<commit_msg>msg: use defined type<commit_after>// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package msg

// IMPORTANT: You need a very good reason to change this file, because changes
// might break compatibility between different message formats!

import (
	"bytes"
	"encoding/binary"
	"io"

	"github.com/mutecomm/mute/log"
)

// ReadFirstOuterHeader reads the first outer header from the base64 decoder r
// and returns the version and the preHeader for further processing. This
// function is intended to be used outside the msg package to allow to check
// for incompatible message format changes down the line.
func ReadFirstOuterHeader(r io.Reader) (version uint16, preHeader []byte, err error) {
	var (
		Type        uint8
		PLen        uint16
		PacketCount uint32
	)
	// read Type
	if err := binary.Read(r, binary.BigEndian, &Type); err != nil {
		return 0, nil, err
	}
	if Type != preHeaderPacket {
		return 0, nil, log.Error(ErrNotPreHeader)
	}
	// read Plen
	if err := binary.Read(r, binary.BigEndian, &PLen); err != nil {
		return 0, nil, log.Error(err)
	}
	// read PacketCount
	if err := binary.Read(r, binary.BigEndian, &PacketCount); err != nil {
		return 0, nil, log.Error(err)
	}
	if PacketCount != 0 {
		return 0, nil, log.Error(ErrWrongCount)
	}
	// read inner packet
	preHeader = make([]byte, PLen)
	if _, err := io.ReadFull(r, preHeader); err != nil {
		return 0, nil, log.Error(err)
	}
	// parse version
	if err := binary.Read(bytes.NewBuffer(preHeader), binary.BigEndian, &version); err != nil {
		return 0, nil, log.Error(err)
	}
	return
}
<|endoftext|>


<commit_before>package memory

import (
	"context"
	"testing"
	"time"
)

func shouldTakeAbout(t *testing.T, fn func(), expDur time.Duration, sloppynessFactor int) {
	// on Dieter's laptop:
	// takes about <=15 micros for add/wait sequences
	// takes about 150micros for a add + blocking wait
	slop := time.Duration(sloppynessFactor) * time.Microsecond
	pre := time.Now()
	fn()
	dur := time.Since(pre)
	if dur > expDur+slop || dur < expDur-slop {
		t.Fatalf("was supposed to take %s, but took %s", expDur, dur)
	}
}

func TestTimeLimiter(t *testing.T) {
	window := 100 * time.Millisecond
	limit := 10 * time.Millisecond

	ctx, cancel := context.WithCancel(context.Background())
	tl := NewTimeLimiter(ctx, window, limit)

	// TEST 1 : Start first window by doing work and seeing when it starts blocking
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(500 * time.Microsecond) // spent: 500micros
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(time.Millisecond) // spent: 1.5 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(8 * time.Millisecond) // spent: 9.5 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(400 * time.Microsecond) // spent: 9.9 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(300 * time.Microsecond) // spent: 10.2 ms

	// since almost no time has passed, have to wait full window
	shouldTakeAbout(t, tl.Wait, 100*time.Millisecond, 500)

	// TEST 2 : Now that we waited until a full window, should be able to up to limit work again
	tl.Add(5 * time.Millisecond) // spent: 5 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(4 * time.Millisecond) // spent: 9 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(4 * time.Millisecond) // spent: 13 ms
	shouldTakeAbout(t, tl.Wait, 100*time.Millisecond, 500)

	// TEST 3 : Now that we waited until a full window, should be able to up to limit work again
	// but this time we cancel, so we don't have to wait as long
	tl.Add(5 * time.Millisecond) // spent: 5 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(4 * time.Millisecond) // spent: 9 ms
	shouldTakeAbout(t, tl.Wait, 0, 50)

	tl.Add(4 * time.Millisecond) // spent: 13 ms

	time.AfterFunc(50*time.Millisecond, cancel)
	shouldTakeAbout(t, tl.Wait, 50*time.Millisecond, 500)
}
<commit_msg>upon test failure, show message to locate failure<commit_after>package memory

import (
	"context"
	"testing"
	"time"
)

func shouldTakeAbout(t *testing.T, fn func(), expDur time.Duration, sloppynessFactor int, info string) {
	// on Dieter's laptop:
	// takes about <=15 micros for add/wait sequences
	// takes about 150micros for a add + blocking wait
	slop := time.Duration(sloppynessFactor) * time.Microsecond
	pre := time.Now()
	fn()
	dur := time.Since(pre)
	if dur > expDur+slop || dur < expDur-slop {
		t.Fatalf("scenario %s. was supposed to take %s, but took %s", info, expDur, dur)
	}
}

func TestTimeLimiter(t *testing.T) {
	window := 100 * time.Millisecond
	limit := 10 * time.Millisecond

	ctx, cancel := context.WithCancel(context.Background())
	tl := NewTimeLimiter(ctx, window, limit)

	// TEST 1 : Start first window by doing work and seeing when it starts blocking
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 1: work done: 0 - wait should be 0")

	tl.Add(500 * time.Microsecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 1: work done: 500micros - wait should be 0")

	tl.Add(time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 1: work done: 1.5ms - wait should be 0")

	tl.Add(8 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 1: work done: 9.5ms - wait should be 0")

	tl.Add(400 * time.Microsecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 1: work done: 9.9ms - wait should be 0")

	tl.Add(300 * time.Microsecond)

	shouldTakeAbout(t, tl.Wait, 100*time.Millisecond, 500, "window 1: work done: 10.2ms - almost no time has passed, so wait should be full window")

	// TEST 2 : Now that we waited until a full window, should be able to up to limit work again
	tl.Add(5 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 2: work done: 5ms - wait should be 0")

	tl.Add(4 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 2: work done: 9ms - wait should be 0")

	tl.Add(4 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 100*time.Millisecond, 500, "window 2: work done: 13ms - wait should be 100ms")

	// TEST 3 : Now that we waited until a full window, should be able to up to limit work again
	// but this time we cancel, so we don't have to wait as long
	tl.Add(5 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 3: work done: 5ms - wait should be 0")

	tl.Add(4 * time.Millisecond)
	shouldTakeAbout(t, tl.Wait, 0, 50, "window 3: work done: 9ms - wait should be 0")

	tl.Add(4 * time.Millisecond)

	time.AfterFunc(50*time.Millisecond, cancel)
	shouldTakeAbout(t, tl.Wait, 50*time.Millisecond, 500, "window 3: work done: 13ms, canceling after 50ms - wait should be 50ms")
}
<|endoftext|>


<commit_before>// Package multihash is the Go implementation of
// https://github.com/multiformats/multihash, or self-describing
// hashes.
package multihash

import (
	"encoding/hex"
	"errors"
	"fmt"
	"math"

	b58 "github.com/mr-tron/base58/base58"
	"github.com/multiformats/go-varint"
)

// errors
var (
	ErrUnknownCode      = errors.New("unknown multihash code")
	ErrTooShort         = errors.New("multihash too short. must be >= 2 bytes")
	ErrTooLong          = errors.New("multihash too long. must be < 129 bytes")
	ErrLenNotSupported  = errors.New("multihash does not yet support digests longer than 127 bytes")
	ErrInvalidMultihash = errors.New("input isn't valid multihash")

	ErrVarintBufferShort = errors.New("uvarint: buffer too small")
	ErrVarintTooLong     = errors.New("uvarint: varint too big (max 64bit)")
)

// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
type ErrInconsistentLen struct {
	dm *DecodedMultihash
}

func (e ErrInconsistentLen) Error() string {
	return fmt.Sprintf("multihash length inconsistent: expected %d, got %d", e.dm.Length, len(e.dm.Digest))
}

// constants
const (
	IDENTITY = 0x00
	// Deprecated: use IDENTITY
	ID         = IDENTITY
	SHA1       = 0x11
	SHA2_256   = 0x12
	SHA2_512   = 0x13
	SHA3_224   = 0x17
	SHA3_256   = 0x16
	SHA3_384   = 0x15
	SHA3_512   = 0x14
	SHA3       = SHA3_512
	KECCAK_224 = 0x1A
	KECCAK_256 = 0x1B
	KECCAK_384 = 0x1C
	KECCAK_512 = 0x1D

	SHAKE_128 = 0x18
	SHAKE_256 = 0x19

	BLAKE2B_MIN = 0xb201
	BLAKE2B_MAX = 0xb240
	BLAKE2S_MIN = 0xb241
	BLAKE2S_MAX = 0xb260

	MD5 = 0xd5

	DBL_SHA2_256 = 0x56

	MURMUR3_128 = 0x22
	// Deprecated: use MURMUR3_128
	MURMUR3 = MURMUR3_128

	SHA2_256_TRUNC254_PADDED  = 0x1012
	X11                       = 0x1100
	POSEIDON_BLS12_381_A1_FC1 = 0xb401
)

func init() {
	// Add blake2b (64 codes)
	for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
		n := c - BLAKE2B_MIN + 1
		name := fmt.Sprintf("blake2b-%d", n*8)
		Names[name] = c
		Codes[c] = name
	}

	// Add blake2s (32 codes)
	for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
		n := c - BLAKE2S_MIN + 1
		name := fmt.Sprintf("blake2s-%d", n*8)
		Names[name] = c
		Codes[c] = name
	}
}

// Names maps the name of a hash to the code
var Names = map[string]uint64{
	"identity":                  IDENTITY,
	"sha1":                      SHA1,
	"sha2-256":                  SHA2_256,
	"sha2-512":                  SHA2_512,
	"sha3":                      SHA3_512,
	"sha3-224":                  SHA3_224,
	"sha3-256":                  SHA3_256,
	"sha3-384":                  SHA3_384,
	"sha3-512":                  SHA3_512,
	"dbl-sha2-256":              DBL_SHA2_256,
	"murmur3-128":               MURMUR3_128,
	"keccak-224":                KECCAK_224,
	"keccak-256":                KECCAK_256,
	"keccak-384":                KECCAK_384,
	"keccak-512":                KECCAK_512,
	"shake-128":                 SHAKE_128,
	"shake-256":                 SHAKE_256,
	"sha2-256-trunc254-padded":  SHA2_256_TRUNC254_PADDED,
	"x11":                       X11,
	"md5":                       MD5,
	"poseidon-bls12_381-a2-fc1": POSEIDON_BLS12_381_A1_FC1,
}

// Codes maps a hash code to it's name
var Codes = map[uint64]string{
	IDENTITY:                  "identity",
	SHA1:                      "sha1",
	SHA2_256:                  "sha2-256",
	SHA2_512:                  "sha2-512",
	SHA3_224:                  "sha3-224",
	SHA3_256:                  "sha3-256",
	SHA3_384:                  "sha3-384",
	SHA3_512:                  "sha3-512",
	DBL_SHA2_256:              "dbl-sha2-256",
	MURMUR3_128:               "murmur3-128",
	KECCAK_224:                "keccak-224",
	KECCAK_256:                "keccak-256",
	KECCAK_384:                "keccak-384",
	KECCAK_512:                "keccak-512",
	SHAKE_128:                 "shake-128",
	SHAKE_256:                 "shake-256",
	SHA2_256_TRUNC254_PADDED:  "sha2-256-trunc254-padded",
	X11:                       "x11",
	POSEIDON_BLS12_381_A1_FC1: "poseidon-bls12_381-a2-fc1",
	MD5:                       "md5",
}

func uvarint(buf []byte) (uint64, []byte, error) {
	n, c, err := varint.FromUvarint(buf)
	if err != nil {
		return n, buf, err
	}

	if c == 0 {
		return n, buf, ErrVarintBufferShort
	} else if c < 0 {
		return n, buf[-c:], ErrVarintTooLong
	} else {
		return n, buf[c:], nil
	}
}

// DecodedMultihash represents a parsed multihash and allows
// easy access to the different parts of a multihash.
type DecodedMultihash struct {
	Code   uint64
	Name   string
	Length int    // Length is just int as it is type of len() opearator
	Digest []byte // Digest holds the raw multihash bytes
}

// Multihash is byte slice with the following form:
// <hash function code><digest size><hash function output>.
// See the spec for more information.
type Multihash []byte

// HexString returns the hex-encoded representation of a multihash.
func (m *Multihash) HexString() string {
	return hex.EncodeToString([]byte(*m))
}

// String is an alias to HexString().
func (m *Multihash) String() string {
	return m.HexString()
}

// FromHexString parses a hex-encoded multihash.
func FromHexString(s string) (Multihash, error) {
	b, err := hex.DecodeString(s)
	if err != nil {
		return Multihash{}, err
	}

	return Cast(b)
}

// B58String returns the B58-encoded representation of a multihash.
func (m Multihash) B58String() string {
	return b58.Encode([]byte(m))
}

// FromB58String parses a B58-encoded multihash.
func FromB58String(s string) (m Multihash, err error) {
	b, err := b58.Decode(s)
	if err != nil {
		return Multihash{}, ErrInvalidMultihash
	}

	return Cast(b)
}

// Cast casts a buffer onto a multihash, and returns an error
// if it does not work.
func Cast(buf []byte) (Multihash, error) {
	_, err := Decode(buf)
	if err != nil {
		return Multihash{}, err
	}

	return Multihash(buf), nil
}

// Decode parses multihash bytes into a DecodedMultihash.
func Decode(buf []byte) (*DecodedMultihash, error) {
	rlen, code, hdig, err := readMultihashFromBuf(buf)
	if err != nil {
		return nil, err
	}

	dm := &DecodedMultihash{
		Code:   code,
		Name:   Codes[code],
		Length: len(hdig),
		Digest: hdig,
	}

	if len(buf) != rlen {
		return nil, ErrInconsistentLen{dm}
	}

	return dm, nil
}

// Encode a hash digest along with the specified function code.
// Note: the length is derived from the length of the digest itself.
func Encode(buf []byte, code uint64) ([]byte, error) {
	// REVIEW: if we remove the strict ValidCode check, this can no longer error.  Change signiture?
	// REVIEW: this function always causes heap allocs... but when used, this value is almost always going to be appended to another buffer (either as part of CID creation, or etc) -- should this whole function be rethought and alternatives offered?

	newBuf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(uint64(len(buf)))+len(buf))
	n := varint.PutUvarint(newBuf, code)
	n += varint.PutUvarint(newBuf[n:], uint64(len(buf)))

	copy(newBuf[n:], buf)
	return newBuf, nil
}

// EncodeName is like Encode() but providing a string name
// instead of a numeric code. See Names for allowed values.
func EncodeName(buf []byte, name string) ([]byte, error) {
	return Encode(buf, Names[name])
}

// readMultihashFromBuf reads a multihash from the given buffer, returning the
// individual pieces of the multihash.
// Note: the returned digest is a slice over the passed in data and should be
// copied if the buffer will be reused
func readMultihashFromBuf(buf []byte) (int, uint64, []byte, error) {
	bufl := len(buf)
	if bufl < 2 {
		return 0, 0, nil, ErrTooShort
	}

	var err error
	var code, length uint64

	code, buf, err = uvarint(buf)
	if err != nil {
		return 0, 0, nil, err
	}

	length, buf, err = uvarint(buf)
	if err != nil {
		return 0, 0, nil, err
	}

	if length > math.MaxInt32 {
		return 0, 0, nil, errors.New("digest too long, supporting only <= 2^31-1")
	}
	if int(length) > len(buf) {
		return 0, 0, nil, errors.New("length greater than remaining number of bytes in buffer")
	}

	rlen := (bufl - len(buf)) + int(length)
	return rlen, code, buf[:length], nil
}

// MHFromBytes reads a multihash from the given byte buffer, returning the
// number of bytes read as well as the multihash
func MHFromBytes(buf []byte) (int, Multihash, error) {
	nr, _, _, err := readMultihashFromBuf(buf)
	if err != nil {
		return 0, nil, err
	}

	return nr, Multihash(buf[:nr]), nil
}
<commit_msg>Resolving review topics around Encode function.<commit_after>// Package multihash is the Go implementation of
// https://github.com/multiformats/multihash, or self-describing
// hashes.
package multihash

import (
	"encoding/hex"
	"errors"
	"fmt"
	"math"

	b58 "github.com/mr-tron/base58/base58"
	"github.com/multiformats/go-varint"
)

// errors
var (
	ErrUnknownCode      = errors.New("unknown multihash code")
	ErrTooShort         = errors.New("multihash too short. must be >= 2 bytes")
	ErrTooLong          = errors.New("multihash too long. must be < 129 bytes")
	ErrLenNotSupported  = errors.New("multihash does not yet support digests longer than 127 bytes")
	ErrInvalidMultihash = errors.New("input isn't valid multihash")

	ErrVarintBufferShort = errors.New("uvarint: buffer too small")
	ErrVarintTooLong     = errors.New("uvarint: varint too big (max 64bit)")
)

// ErrInconsistentLen is returned when a decoded multihash has an inconsistent length
type ErrInconsistentLen struct {
	dm *DecodedMultihash
}

func (e ErrInconsistentLen) Error() string {
	return fmt.Sprintf("multihash length inconsistent: expected %d, got %d", e.dm.Length, len(e.dm.Digest))
}

// constants
const (
	IDENTITY = 0x00
	// Deprecated: use IDENTITY
	ID         = IDENTITY
	SHA1       = 0x11
	SHA2_256   = 0x12
	SHA2_512   = 0x13
	SHA3_224   = 0x17
	SHA3_256   = 0x16
	SHA3_384   = 0x15
	SHA3_512   = 0x14
	SHA3       = SHA3_512
	KECCAK_224 = 0x1A
	KECCAK_256 = 0x1B
	KECCAK_384 = 0x1C
	KECCAK_512 = 0x1D

	SHAKE_128 = 0x18
	SHAKE_256 = 0x19

	BLAKE2B_MIN = 0xb201
	BLAKE2B_MAX = 0xb240
	BLAKE2S_MIN = 0xb241
	BLAKE2S_MAX = 0xb260

	MD5 = 0xd5

	DBL_SHA2_256 = 0x56

	MURMUR3_128 = 0x22
	// Deprecated: use MURMUR3_128
	MURMUR3 = MURMUR3_128

	SHA2_256_TRUNC254_PADDED  = 0x1012
	X11                       = 0x1100
	POSEIDON_BLS12_381_A1_FC1 = 0xb401
)

func init() {
	// Add blake2b (64 codes)
	for c := uint64(BLAKE2B_MIN); c <= BLAKE2B_MAX; c++ {
		n := c - BLAKE2B_MIN + 1
		name := fmt.Sprintf("blake2b-%d", n*8)
		Names[name] = c
		Codes[c] = name
	}

	// Add blake2s (32 codes)
	for c := uint64(BLAKE2S_MIN); c <= BLAKE2S_MAX; c++ {
		n := c - BLAKE2S_MIN + 1
		name := fmt.Sprintf("blake2s-%d", n*8)
		Names[name] = c
		Codes[c] = name
	}
}

// Names maps the name of a hash to the code
var Names = map[string]uint64{
	"identity":                  IDENTITY,
	"sha1":                      SHA1,
	"sha2-256":                  SHA2_256,
	"sha2-512":                  SHA2_512,
	"sha3":                      SHA3_512,
	"sha3-224":                  SHA3_224,
	"sha3-256":                  SHA3_256,
	"sha3-384":                  SHA3_384,
	"sha3-512":                  SHA3_512,
	"dbl-sha2-256":              DBL_SHA2_256,
	"murmur3-128":               MURMUR3_128,
	"keccak-224":                KECCAK_224,
	"keccak-256":                KECCAK_256,
	"keccak-384":                KECCAK_384,
	"keccak-512":                KECCAK_512,
	"shake-128":                 SHAKE_128,
	"shake-256":                 SHAKE_256,
	"sha2-256-trunc254-padded":  SHA2_256_TRUNC254_PADDED,
	"x11":                       X11,
	"md5":                       MD5,
	"poseidon-bls12_381-a2-fc1": POSEIDON_BLS12_381_A1_FC1,
}

// Codes maps a hash code to it's name
var Codes = map[uint64]string{
	IDENTITY:                  "identity",
	SHA1:                      "sha1",
	SHA2_256:                  "sha2-256",
	SHA2_512:                  "sha2-512",
	SHA3_224:                  "sha3-224",
	SHA3_256:                  "sha3-256",
	SHA3_384:                  "sha3-384",
	SHA3_512:                  "sha3-512",
	DBL_SHA2_256:              "dbl-sha2-256",
	MURMUR3_128:               "murmur3-128",
	KECCAK_224:                "keccak-224",
	KECCAK_256:                "keccak-256",
	KECCAK_384:                "keccak-384",
	KECCAK_512:                "keccak-512",
	SHAKE_128:                 "shake-128",
	SHAKE_256:                 "shake-256",
	SHA2_256_TRUNC254_PADDED:  "sha2-256-trunc254-padded",
	X11:                       "x11",
	POSEIDON_BLS12_381_A1_FC1: "poseidon-bls12_381-a2-fc1",
	MD5:                       "md5",
}

func uvarint(buf []byte) (uint64, []byte, error) {
	n, c, err := varint.FromUvarint(buf)
	if err != nil {
		return n, buf, err
	}

	if c == 0 {
		return n, buf, ErrVarintBufferShort
	} else if c < 0 {
		return n, buf[-c:], ErrVarintTooLong
	} else {
		return n, buf[c:], nil
	}
}

// DecodedMultihash represents a parsed multihash and allows
// easy access to the different parts of a multihash.
type DecodedMultihash struct {
	Code   uint64
	Name   string
	Length int    // Length is just int as it is type of len() opearator
	Digest []byte // Digest holds the raw multihash bytes
}

// Multihash is byte slice with the following form:
// <hash function code><digest size><hash function output>.
// See the spec for more information.
type Multihash []byte

// HexString returns the hex-encoded representation of a multihash.
func (m *Multihash) HexString() string {
	return hex.EncodeToString([]byte(*m))
}

// String is an alias to HexString().
func (m *Multihash) String() string {
	return m.HexString()
}

// FromHexString parses a hex-encoded multihash.
func FromHexString(s string) (Multihash, error) {
	b, err := hex.DecodeString(s)
	if err != nil {
		return Multihash{}, err
	}

	return Cast(b)
}

// B58String returns the B58-encoded representation of a multihash.
func (m Multihash) B58String() string {
	return b58.Encode([]byte(m))
}

// FromB58String parses a B58-encoded multihash.
func FromB58String(s string) (m Multihash, err error) {
	b, err := b58.Decode(s)
	if err != nil {
		return Multihash{}, ErrInvalidMultihash
	}

	return Cast(b)
}

// Cast casts a buffer onto a multihash, and returns an error
// if it does not work.
func Cast(buf []byte) (Multihash, error) {
	_, err := Decode(buf)
	if err != nil {
		return Multihash{}, err
	}

	return Multihash(buf), nil
}

// Decode parses multihash bytes into a DecodedMultihash.
func Decode(buf []byte) (*DecodedMultihash, error) {
	rlen, code, hdig, err := readMultihashFromBuf(buf)
	if err != nil {
		return nil, err
	}

	dm := &DecodedMultihash{
		Code:   code,
		Name:   Codes[code],
		Length: len(hdig),
		Digest: hdig,
	}

	if len(buf) != rlen {
		return nil, ErrInconsistentLen{dm}
	}

	return dm, nil
}

// Encode a hash digest along with the specified function code.
// Note: the length is derived from the length of the digest itself.
//
// The error return is legacy; it is always nil.
func Encode(buf []byte, code uint64) ([]byte, error) {
	// FUTURE: this function always causes heap allocs... but when used, this value is almost always going to be appended to another buffer (either as part of CID creation, or etc) -- should this whole function be rethought and alternatives offered?
	newBuf := make([]byte, varint.UvarintSize(code)+varint.UvarintSize(uint64(len(buf)))+len(buf))
	n := varint.PutUvarint(newBuf, code)
	n += varint.PutUvarint(newBuf[n:], uint64(len(buf)))

	copy(newBuf[n:], buf)
	return newBuf, nil
}

// EncodeName is like Encode() but providing a string name
// instead of a numeric code. See Names for allowed values.
func EncodeName(buf []byte, name string) ([]byte, error) {
	return Encode(buf, Names[name])
}

// readMultihashFromBuf reads a multihash from the given buffer, returning the
// individual pieces of the multihash.
// Note: the returned digest is a slice over the passed in data and should be
// copied if the buffer will be reused
func readMultihashFromBuf(buf []byte) (int, uint64, []byte, error) {
	bufl := len(buf)
	if bufl < 2 {
		return 0, 0, nil, ErrTooShort
	}

	var err error
	var code, length uint64

	code, buf, err = uvarint(buf)
	if err != nil {
		return 0, 0, nil, err
	}

	length, buf, err = uvarint(buf)
	if err != nil {
		return 0, 0, nil, err
	}

	if length > math.MaxInt32 {
		return 0, 0, nil, errors.New("digest too long, supporting only <= 2^31-1")
	}
	if int(length) > len(buf) {
		return 0, 0, nil, errors.New("length greater than remaining number of bytes in buffer")
	}

	rlen := (bufl - len(buf)) + int(length)
	return rlen, code, buf[:length], nil
}

// MHFromBytes reads a multihash from the given byte buffer, returning the
// number of bytes read as well as the multihash
func MHFromBytes(buf []byte) (int, Multihash, error) {
	nr, _, _, err := readMultihashFromBuf(buf)
	if err != nil {
		return 0, nil, err
	}

	return nr, Multihash(buf[:nr]), nil
}
<|endoftext|>


<commit_before>// Keybase file system

package main

import (
	"flag"
	_ "fmt"
	"log"

	_ "github.com/hanwen/go-fuse/fuse"
	"github.com/hanwen/go-fuse/fuse/nodefs"
	libkb "github.com/keybase/go-libkb"
	libkbfs "github.com/keybase/go-libkbfs-priv"
	_ "github.com/ugorji/go/codec"
)

func main() {
	flag.Parse()
	if len(flag.Args()) < 1 {
		log.Fatal("Usage:\n  kbfs MOUNTPOINT")
	}

	// set up fake FS
	root := &libkbfs.FSNode{Node: nodefs.NewDefaultNode()}

	server, _, err := nodefs.MountRoot(flag.Arg(0), root, nil)
	if err != nil {
		log.Fatalf("Mount fail: %v\n", err)
	}

	server.SetDebug(true)
	libkb.G.Init()
	libkb.G.ConfigureLogging()
	libkb.G.ConfigureCaches()
	libkb.G.ConfigureAPI()
	server.Serve()
}
<commit_msg>Lookup, getattr, and mkdir all work!<commit_after>// Keybase file system

package main

import (
	"flag"
	_ "fmt"
	"log"

	"github.com/hanwen/go-fuse/fuse/nodefs"
	libkb "github.com/keybase/go-libkb"
	libkbfs "github.com/keybase/go-libkbfs-priv"
)

func main() {
	flag.Parse()
	if len(flag.Args()) < 1 {
		log.Fatal("Usage:\n  kbfs MOUNTPOINT")
	}

	config := libkbfs.NewConfigLocal()
	root := libkbfs.NewFuseRoot(config)

	server, _, err := nodefs.MountRoot(flag.Arg(0), root, nil)
	if err != nil {
		log.Fatalf("Mount fail: %v\n", err)
	}

	server.SetDebug(true)
	libkb.G.Init()
	libkb.G.ConfigureLogging()
	libkb.G.ConfigureCaches()
	libkb.G.ConfigureAPI()
	server.Serve()
}
<|endoftext|>


<commit_before>// Package tcpkeepalive implements additional TCP keepalive control beyond what
// is currently offered by the net pkg.
//
// Only Linux >= 2.4 and OS X >= 10.8 are supported at this point, but
// patches for additional platforms are welcome.
package tcpkeepalive

import (
	"fmt"
	"net"

	"time"
)

// EnableKeepAlive enables TCP keepalive for the given conn, which must be a
// *tcp.TCPConn. The returned Conn allows overwriting the default keepalive
// parameters used by the operating system.
func EnableKeepAlive(conn net.Conn) (*Conn, error) {
	tcp, ok := conn.(*net.TCPConn)
	if !ok {
		return nil, fmt.Errorf("Bad conn type: %T", conn)
	}
	if err := tcp.SetKeepAlive(true); err != nil {
		return nil, err
	}
	file, err := tcp.File()
	if err != nil {
		return nil, err
	}
	fd := int(file.Fd())
	return &Conn{TCPConn: tcp, fd: fd}, nil
}

// Conn adds additional TCP keepalive control to a *net.TCPConn.
type Conn struct {
	*net.TCPConn
	fd int
}

// The time (in seconds) the connection needs to remain idle before TCP starts
// sending keepalive probes.
func (c *Conn) SetIdle(d time.Duration) error {
	return setIdle(c.fd, secs(d))
}

// The maximum number of keepalive probes TCP should send before dropping the
// connection.
func (c *Conn) SetCount(n int) error {
	return setCount(c.fd, n)
}

// The time (in seconds) between individual keepalive probes.
func (c *Conn) SetInterval(d time.Duration) error {
	return setInterval(c.fd, secs(d))
}

func secs(d time.Duration) int {
	d += (time.Second - time.Nanosecond)
	return int(d.Seconds())
}
<commit_msg>Rename<commit_after>// Package tcpkeepalive implements additional TCP keepalive control beyond what
// is currently offered by the net pkg.
//
// Only Linux >= 2.4 and OS X >= 10.8 are supported at this point, but
// patches for additional platforms are welcome.
package tcpkeepalive

import (
	"fmt"
	"net"

	"time"
)

// EnableKeepAlive enables TCP keepalive for the given conn, which must be a
// *tcp.TCPConn. The returned Conn allows overwriting the default keepalive
// parameters used by the operating system.
func EnableKeepAlive(conn net.Conn) (*Conn, error) {
	tcp, ok := conn.(*net.TCPConn)
	if !ok {
		return nil, fmt.Errorf("Bad conn type: %T", conn)
	}
	if err := tcp.SetKeepAlive(true); err != nil {
		return nil, err
	}
	file, err := tcp.File()
	if err != nil {
		return nil, err
	}
	fd := int(file.Fd())
	return &Conn{TCPConn: tcp, fd: fd}, nil
}

// Conn adds additional TCP keepalive control to a *net.TCPConn.
type Conn struct {
	*net.TCPConn
	fd int
}

// SetKeepAliveIdle sets the time (in seconds) the connection needs to remain
// idle before TCP starts sending keepalive probes.
func (c *Conn) SetKeepAliveIdle(d time.Duration) error {
	return setIdle(c.fd, secs(d))
}

// SetKeepAliveCount sets the maximum number of keepalive probes TCP should
// send before dropping the connection.
func (c *Conn) SetKeepAliveCount(n int) error {
	return setCount(c.fd, n)
}

// SetKeepAliveInterval sets the time (in seconds) between individual keepalive
// probes.
func (c *Conn) SetKeepAliveInterval(d time.Duration) error {
	return setInterval(c.fd, secs(d))
}

func secs(d time.Duration) int {
	d += (time.Second - time.Nanosecond)
	return int(d.Seconds())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package nat

import (
	"encoding/json"
	"errors"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/ernestio/ernestaws/credentials"
)

// Collection ....
type Collection struct {
	ProviderType       string            `json:"_provider"`
	ComponentType      string            `json:"_component"`
	ComponentID        string            `json:"_component_id"`
	State              string            `json:"_state"`
	Action             string            `json:"_action"`
	Service            string            `json:"service"`
	AWSAccessKeyID     string            `json:"aws_access_key_id"`
	AWSSecretAccessKey string            `json:"aws_secret_access_key"`
	DatacenterRegion   string            `json:"datacenter_region"`
	Tags               map[string]string `json:"tags"`
	Results            []interface{}     `json:"components"`
	ErrorMessage       string            `json:"error,omitempty"`
	Subject            string            `json:"-"`
	Body               []byte            `json:"-"`
	CryptoKey          string            `json:"-"`
}

// GetBody : Gets the body for this event
func (col *Collection) GetBody() []byte {
	var err error
	if col.Body, err = json.Marshal(col); err != nil {
		log.Println(err.Error())
	}
	return col.Body
}

// GetSubject : Gets the subject for this event
func (col *Collection) GetSubject() string {
	return col.Subject
}

// Process : starts processing the current message
func (col *Collection) Process() (err error) {
	if err := json.Unmarshal(col.Body, &col); err != nil {
		col.Error(err)
		return err
	}

	if err := col.Validate(); err != nil {
		col.Error(err)
		return err
	}

	return nil
}

// Error : Will respond the current event with an error
func (col *Collection) Error(err error) {
	log.Printf("Error: %s", err.Error())
	col.ErrorMessage = err.Error()
	col.State = "errored"

	col.Body, err = json.Marshal(col)
}

// Complete : sets the state of the event to completed
func (col *Collection) Complete() {
	col.State = "completed"
}

// Validate checks if all criteria are met
func (col *Collection) Validate() error {
	if col.AWSAccessKeyID == "" || col.AWSSecretAccessKey == "" {
		return ErrDatacenterCredentialsInvalid
	}

	return nil
}

// Get : Gets a object on aws
func (col *Collection) Get() error {
	return errors.New(col.Subject + " not supported")
}

// Create : Creates an object on aws
func (col *Collection) Create() error {
	return errors.New(col.Subject + " not supported")
}

// Update : Updates an object on aws
func (col *Collection) Update() error {
	return errors.New(col.Subject + " not supported")
}

// Delete : Delete an object on aws
func (col *Collection) Delete() error {
	return errors.New(col.Subject + " not supported")
}

// Find : Find nat gateways on aws
func (col *Collection) Find() error {
	svc := col.getEC2Client()

	resp, err := svc.DescribeNatGateways(nil)
	if err != nil {
		return err
	}

	// As tags aren't supported on nat gw's, we append all items to be filtered later.
	for _, ng := range resp.NatGateways {
		var name string

		networks, err := col.getRoutedNetworks(ng.NatGatewayId)
		if err != nil {
			return err
		}

		for _, network := range networks {
			name, err = col.getGatewayName(network)
			if err != nil {
				return err
			}

			if name != "" {
				break
			}
		}

		e := toEvent(ng, name)
		e.RoutedNetworkAWSIDs = networks

		col.Results = append(col.Results, e)
	}

	return nil
}

func (col *Collection) getEC2Client() *ec2.EC2 {
	creds, _ := credentials.NewStaticCredentials(col.AWSAccessKeyID, col.AWSSecretAccessKey, col.CryptoKey)
	return ec2.New(session.New(), &aws.Config{
		Region:      aws.String(col.DatacenterRegion),
		Credentials: creds,
	})
}

func mapFilters(tags map[string]string) []*ec2.Filter {
	var f []*ec2.Filter

	for key, val := range tags {
		f = append(f, &ec2.Filter{
			Name:   aws.String("tag:" + key),
			Values: []*string{aws.String(val)},
		})
	}

	return f
}

func getPublicAllocation(addresses []*ec2.NatGatewayAddress) (*string, *string) {
	for _, a := range addresses {
		if a.PublicIp != nil {
			return a.AllocationId, a.PublicIp
		}
	}
	return nil, nil
}

func (col *Collection) getRoutedNetworks(gatewayID *string) ([]*string, error) {
	var f []*ec2.Filter
	var ids []*string

	svc := col.getEC2Client()

	f = append(f, &ec2.Filter{
		Name:   aws.String("route.nat-gateway-id"),
		Values: []*string{gatewayID},
	})

	req := &ec2.DescribeRouteTablesInput{
		Filters: f,
	}

	resp, err := svc.DescribeRouteTables(req)
	if err != nil {
		return ids, err
	}

	for _, rt := range resp.RouteTables {
		for _, assoc := range rt.Associations {
			if assoc.SubnetId != nil {
				ids = append(ids, assoc.SubnetId)
			}
		}
	}

	return ids, err
}

func (col *Collection) getGatewayName(networkID *string) (string, error) {
	nw, err := col.getNetwork(networkID)
	if err != nil {
		return "", err
	}

	tags := mapEC2Tags(nw.Tags)
	name := tags["ernest.nat_gateway"]

	return name, nil
}

func (col *Collection) getNetwork(id *string) (*ec2.Subnet, error) {
	svc := col.getEC2Client()

	req := &ec2.DescribeSubnetsInput{
		SubnetIds: []*string{id},
	}

	resp, err := svc.DescribeSubnets(req)
	if err != nil {
		return nil, err
	}

	if len(resp.Subnets) != 1 {
		return nil, errors.New("could not find referenced nat gateway subnet")
	}

	return resp.Subnets[0], nil
}

func mapEC2Tags(input []*ec2.Tag) map[string]string {
	t := make(map[string]string)

	for _, tag := range input {
		t[*tag.Key] = *tag.Value
	}

	return t
}

// ToEvent converts an ec2 nat gateway object to an ernest event
func toEvent(ng *ec2.NatGateway, name string) *Event {
	id, ip := getPublicAllocation(ng.NatGatewayAddresses)

	e := &Event{
		ProviderType:           "aws",
		ComponentType:          "nat",
		ComponentID:            "nat::" + name,
		Name:                   aws.String(name),
		VpcID:                  *ng.VpcId,
		NatGatewayAWSID:        ng.NatGatewayId,
		PublicNetworkAWSID:     ng.SubnetId,
		NatGatewayAllocationID: id,
		NatGatewayAllocationIP: ip,
		//RoutedNetworksAWSIDs
		//InternetGatewayID
	}
	return e
}
<commit_msg>ommiting nat gateways on query that have no tagged name<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package nat

import (
	"encoding/json"
	"errors"
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/ernestio/ernestaws/credentials"
)

// Collection ....
type Collection struct {
	ProviderType       string            `json:"_provider"`
	ComponentType      string            `json:"_component"`
	ComponentID        string            `json:"_component_id"`
	State              string            `json:"_state"`
	Action             string            `json:"_action"`
	Service            string            `json:"service"`
	AWSAccessKeyID     string            `json:"aws_access_key_id"`
	AWSSecretAccessKey string            `json:"aws_secret_access_key"`
	DatacenterRegion   string            `json:"datacenter_region"`
	Tags               map[string]string `json:"tags"`
	Results            []interface{}     `json:"components"`
	ErrorMessage       string            `json:"error,omitempty"`
	Subject            string            `json:"-"`
	Body               []byte            `json:"-"`
	CryptoKey          string            `json:"-"`
}

// GetBody : Gets the body for this event
func (col *Collection) GetBody() []byte {
	var err error
	if col.Body, err = json.Marshal(col); err != nil {
		log.Println(err.Error())
	}
	return col.Body
}

// GetSubject : Gets the subject for this event
func (col *Collection) GetSubject() string {
	return col.Subject
}

// Process : starts processing the current message
func (col *Collection) Process() (err error) {
	if err := json.Unmarshal(col.Body, &col); err != nil {
		col.Error(err)
		return err
	}

	if err := col.Validate(); err != nil {
		col.Error(err)
		return err
	}

	return nil
}

// Error : Will respond the current event with an error
func (col *Collection) Error(err error) {
	log.Printf("Error: %s", err.Error())
	col.ErrorMessage = err.Error()
	col.State = "errored"

	col.Body, err = json.Marshal(col)
}

// Complete : sets the state of the event to completed
func (col *Collection) Complete() {
	col.State = "completed"
}

// Validate checks if all criteria are met
func (col *Collection) Validate() error {
	if col.AWSAccessKeyID == "" || col.AWSSecretAccessKey == "" {
		return ErrDatacenterCredentialsInvalid
	}

	return nil
}

// Get : Gets a object on aws
func (col *Collection) Get() error {
	return errors.New(col.Subject + " not supported")
}

// Create : Creates an object on aws
func (col *Collection) Create() error {
	return errors.New(col.Subject + " not supported")
}

// Update : Updates an object on aws
func (col *Collection) Update() error {
	return errors.New(col.Subject + " not supported")
}

// Delete : Delete an object on aws
func (col *Collection) Delete() error {
	return errors.New(col.Subject + " not supported")
}

// Find : Find nat gateways on aws
func (col *Collection) Find() error {
	svc := col.getEC2Client()

	resp, err := svc.DescribeNatGateways(nil)
	if err != nil {
		return err
	}

	// As tags aren't supported on nat gw's, we append all items to be filtered later.
	for _, ng := range resp.NatGateways {
		var name string

		networks, err := col.getRoutedNetworks(ng.NatGatewayId)
		if err != nil {
			return err
		}

		for _, network := range networks {
			name, err = col.getGatewayName(network)
			if err != nil {
				return err
			}

			if name != "" {
				break
			}
		}

		e := toEvent(ng, name)
		e.RoutedNetworkAWSIDs = networks

		if name != "" {
			col.Results = append(col.Results, e)
		}
	}

	return nil
}

func (col *Collection) getEC2Client() *ec2.EC2 {
	creds, _ := credentials.NewStaticCredentials(col.AWSAccessKeyID, col.AWSSecretAccessKey, col.CryptoKey)
	return ec2.New(session.New(), &aws.Config{
		Region:      aws.String(col.DatacenterRegion),
		Credentials: creds,
	})
}

func mapFilters(tags map[string]string) []*ec2.Filter {
	var f []*ec2.Filter

	for key, val := range tags {
		f = append(f, &ec2.Filter{
			Name:   aws.String("tag:" + key),
			Values: []*string{aws.String(val)},
		})
	}

	return f
}

func getPublicAllocation(addresses []*ec2.NatGatewayAddress) (*string, *string) {
	for _, a := range addresses {
		if a.PublicIp != nil {
			return a.AllocationId, a.PublicIp
		}
	}
	return nil, nil
}

func (col *Collection) getRoutedNetworks(gatewayID *string) ([]*string, error) {
	var f []*ec2.Filter
	var ids []*string

	svc := col.getEC2Client()

	f = append(f, &ec2.Filter{
		Name:   aws.String("route.nat-gateway-id"),
		Values: []*string{gatewayID},
	})

	req := &ec2.DescribeRouteTablesInput{
		Filters: f,
	}

	resp, err := svc.DescribeRouteTables(req)
	if err != nil {
		return ids, err
	}

	for _, rt := range resp.RouteTables {
		for _, assoc := range rt.Associations {
			if assoc.SubnetId != nil {
				ids = append(ids, assoc.SubnetId)
			}
		}
	}

	return ids, err
}

func (col *Collection) getGatewayName(networkID *string) (string, error) {
	nw, err := col.getNetwork(networkID)
	if err != nil {
		return "", err
	}

	tags := mapEC2Tags(nw.Tags)
	name := tags["ernest.nat_gateway"]

	return name, nil
}

func (col *Collection) getNetwork(id *string) (*ec2.Subnet, error) {
	svc := col.getEC2Client()

	req := &ec2.DescribeSubnetsInput{
		SubnetIds: []*string{id},
	}

	resp, err := svc.DescribeSubnets(req)
	if err != nil {
		return nil, err
	}

	if len(resp.Subnets) != 1 {
		return nil, errors.New("could not find referenced nat gateway subnet")
	}

	return resp.Subnets[0], nil
}

func mapEC2Tags(input []*ec2.Tag) map[string]string {
	t := make(map[string]string)

	for _, tag := range input {
		t[*tag.Key] = *tag.Value
	}

	return t
}

// ToEvent converts an ec2 nat gateway object to an ernest event
func toEvent(ng *ec2.NatGateway, name string) *Event {
	id, ip := getPublicAllocation(ng.NatGatewayAddresses)

	e := &Event{
		ProviderType:           "aws",
		ComponentType:          "nat",
		ComponentID:            "nat::" + name,
		Name:                   aws.String(name),
		VpcID:                  *ng.VpcId,
		NatGatewayAWSID:        ng.NatGatewayId,
		PublicNetworkAWSID:     ng.SubnetId,
		NatGatewayAllocationID: id,
		NatGatewayAllocationIP: ip,
		//RoutedNetworksAWSIDs
		//InternetGatewayID
	}
	return e
}
<|endoftext|>