<commit_before>package gosql

import (
	"bytes"
	"fmt"
	. "github.com/suboat/go-sql-kit"
	"strings"
)

type ValueStringFunc func(*QueryValue) string

type SQLQuery struct {
	RuleMapping
	QueryRoot
	valueStringFunc ValueStringFunc
}

func NewSQLQuery() *SQLQuery {
	return new(SQLQuery).AllowCommonKey().SetValueFormat(nil)
}

func (s *SQLQuery) AllowCommonKey() *SQLQuery {
	s.Allow(QueryKeyAnd, QueryKeyOr,
		QueryKeyEq, QueryKeyNe,
		QueryKeyLt, QueryKeyLte,
		QueryKeyGt, QueryKeyGte,
	)
	return s
}

func (s *SQLQuery) SetValueFormat(f ValueStringFunc) *SQLQuery {
	if f != nil {
		s.valueStringFunc = f
	} else {
		s.valueStringFunc = s.ValueString
	}
	return s
}

func (s *SQLQuery) String(alias ...string) string {
	if s.Values == nil || len(s.Values) == 0 {
		return ""
	}
	set := make([]string, 0, len(s.Values))
	for _, iv := range s.Values {
		if v, ok := iv.(*QueryElem); ok {
			if str := s.elemString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		}
	}
	if len(set) != 0 {
		return "WHERE " + strings.Join(set, " AND ")
	}
	return ""
}

func (s *SQLQuery) elemString(elem *QueryElem, alias ...string) string {
	if !s.IsAllowed(elem.Key) {
		return ""
	}
	set := make([]string, 0, len(elem.Values))
	for _, iv := range elem.Values {
		if v, ok := iv.(*QueryElem); ok {
			if str := s.elemString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		} else if v, ok := iv.(*QueryValue); ok {
			if str := s.valueString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		}
	}
	if len(set) == 0 {
		return ""
	} else if elem.IsAnonymous() {
		if len(set) == 1 {
			return set[0]
		} else if elem.RelKey == QueryKeyOr {
			return fmt.Sprintf("(%v)", strings.Join(set, " OR "))
		}
		return fmt.Sprintf("(%v)", strings.Join(set, " AND "))
	} else {
		switch elem.Key {
		case QueryKeyAnd:
			return strings.Join(set, " AND ")
		case QueryKeyOr:
			if len(set) == 1 {
				return set[0]
			}
			return fmt.Sprintf("(%v)", strings.Join(set, " OR "))
		}
	}
	return ""
}

func (s *SQLQuery) valueString(v *QueryValue, alias ...string) string {
	if v == nil {
	} else if !s.IsAllowed(v.Field) {
	} else if v.Field = s.GetMapping(v.Field); len(v.Field) != 0 {
		if len(alias) != 0 {
			v.Field = fmt.Sprintf("%v.%v", alias[0], v.Field)
		}
		return s.valueStringFunc(v)
	}
	return ""

}

func (s *SQLQuery) ValueString(v *QueryValue) string {
	opera := ""
	switch v.Key {
	case QueryKeyEq:
		opera = "="
	case QueryKeyNe:
		opera = "<>"
	case QueryKeyLt:
		opera = "<"
	case QueryKeyLte:
		opera = "<="
	case QueryKeyGt:
		opera = ">"
	case QueryKeyGte:
		opera = ">="
	case QueryKeyLike:
		return fmt.Sprintf("%v LIKE '%%%v%%'", v.Field, v.Value)
	case QueryKeyIn:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) == 0 {
				return ""
			}
			var sb bytes.Buffer
			sb.WriteString(fmt.Sprintf("%v IN (", v.Field))
			l := len(vs)
			for i, vi := range vs {
				switch vi.(type) {
				case int, int8, int16, int32, int64, float32, float64:
					sb.WriteString(fmt.Sprintf("%v", vi))
				default:
					sb.WriteString(fmt.Sprintf("'%v'", vi))
				}
				if i+1 < l {
					sb.WriteString(", ")
				}
			}
			sb.WriteString(")")
			return sb.String()
		}
		return ""
	case QueryKeyBetween:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) < 2 {
				return ""
			}
			switch vs[0].(type) {
			case int, int8, int16, int32, int64, float32, float64:
				return fmt.Sprintf("%v BETWEEN %v AND %v", v.Field, vs[0], vs[1])
			default:
				return fmt.Sprintf("%v BETWEEN '%v' AND '%v'", v.Field, vs[0], vs[1])
			}
		}
		return ""
	case QueryKeyNotBetween:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) < 2 {
				return ""
			}
			switch vs[0].(type) {
			case int, int8, int16, int32, int64, float32, float64:
				return fmt.Sprintf("%v NOT BETWEEN %v AND %v", v.Field, vs[0], vs[1])
			default:
				return fmt.Sprintf("%v NOT BETWEEN '%v' AND '%v'", v.Field, vs[0], vs[1])
			}
		}
		return ""
	default:
		return ""
	}
	switch v.Value.(type) {
	case int, int8, int16, int32, int64, float32, float64:
		return fmt.Sprintf("%v%v%v", v.Field, opera, v.Value)
	default:
		return fmt.Sprintf("%v%v'%v'", v.Field, opera, v.Value)
	}
}

func (s *SQLQuery) JSONtoSQLString(str string, alias ...string) (string, error) {
	if err := s.ParseJSONString(str); err != nil {
		return "", err
	}
	return s.String(alias...), nil
}

func (s *SQLQuery) SQLString(m map[string]interface{}, alias ...string) (string, error) {
	if err := s.Parse(m); err != nil {
		return "", err
	}
	return s.String(alias...), nil
}
<commit_msg>fix: query<commit_after>package gosql

import (
	"bytes"
	"fmt"
	. "github.com/suboat/go-sql-kit"
	"strings"
)

type ValueStringFunc func(*QueryValue) string

type SQLQuery struct {
	RuleMapping
	QueryRoot
	valueStringFunc ValueStringFunc
}

func NewSQLQuery() *SQLQuery {
	return new(SQLQuery).AllowCommonKey().SetValueFormat(nil)
}

func (s *SQLQuery) AllowCommonKey() *SQLQuery {
	s.Allow(QueryKeyAnd, QueryKeyOr,
		QueryKeyEq, QueryKeyNe,
		QueryKeyLt, QueryKeyLte,
		QueryKeyGt, QueryKeyGte,
		QueryKeyIn, QueryKeyBetween, QueryKeyNotBetween,
	)
	return s
}

func (s *SQLQuery) SetValueFormat(f ValueStringFunc) *SQLQuery {
	if f != nil {
		s.valueStringFunc = f
	} else {
		s.valueStringFunc = s.ValueString
	}
	return s
}

func (s *SQLQuery) String(alias ...string) string {
	if s.Values == nil || len(s.Values) == 0 {
		return ""
	}
	set := make([]string, 0, len(s.Values))
	for _, iv := range s.Values {
		if v, ok := iv.(*QueryElem); ok {
			if str := s.elemString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		}
	}
	if len(set) != 0 {
		return "WHERE " + strings.Join(set, " AND ")
	}
	return ""
}

func (s *SQLQuery) elemString(elem *QueryElem, alias ...string) string {
	if !s.IsAllowed(elem.Key) {
		return ""
	}
	set := make([]string, 0, len(elem.Values))
	for _, iv := range elem.Values {
		if v, ok := iv.(*QueryElem); ok {
			if str := s.elemString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		} else if v, ok := iv.(*QueryValue); ok {
			if str := s.valueString(v, alias...); len(str) != 0 {
				set = append(set, str)
			}
		}
	}
	if len(set) == 0 {
		return ""
	} else if elem.IsAnonymous() {
		if len(set) == 1 {
			return set[0]
		} else if elem.RelKey == QueryKeyOr {
			return fmt.Sprintf("(%v)", strings.Join(set, " OR "))
		}
		return fmt.Sprintf("(%v)", strings.Join(set, " AND "))
	} else {
		switch elem.Key {
		case QueryKeyAnd:
			return strings.Join(set, " AND ")
		case QueryKeyOr:
			if len(set) == 1 {
				return set[0]
			}
			return fmt.Sprintf("(%v)", strings.Join(set, " OR "))
		}
	}
	return ""
}

func (s *SQLQuery) valueString(v *QueryValue, alias ...string) string {
	if v == nil {
	} else if !s.IsAllowed(v.Field) {
	} else if v.Field = s.GetMapping(v.Field); len(v.Field) != 0 {
		if len(alias) != 0 {
			v.Field = fmt.Sprintf("%v.%v", alias[0], v.Field)
		}
		return s.valueStringFunc(v)
	}
	return ""

}

func (s *SQLQuery) ValueString(v *QueryValue) string {
	opera := ""
	switch v.Key {
	case QueryKeyEq:
		opera = "="
	case QueryKeyNe:
		opera = "<>"
	case QueryKeyLt:
		opera = "<"
	case QueryKeyLte:
		opera = "<="
	case QueryKeyGt:
		opera = ">"
	case QueryKeyGte:
		opera = ">="
	case QueryKeyLike:
		return fmt.Sprintf("%v LIKE '%%%v%%'", v.Field, v.Value)
	case QueryKeyIn:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) == 0 {
				return ""
			}
			var sb bytes.Buffer
			sb.WriteString(fmt.Sprintf("%v IN (", v.Field))
			l := len(vs)
			for i, vi := range vs {
				switch vi.(type) {
				case int, int8, int16, int32, int64, float32, float64:
					sb.WriteString(fmt.Sprintf("%v", vi))
				default:
					sb.WriteString(fmt.Sprintf("'%v'", vi))
				}
				if i+1 < l {
					sb.WriteString(", ")
				}
			}
			sb.WriteString(")")
			return sb.String()
		}
		return ""
	case QueryKeyBetween:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) < 2 {
				return ""
			}
			switch vs[0].(type) {
			case int, int8, int16, int32, int64, float32, float64:
				return fmt.Sprintf("%v BETWEEN %v AND %v", v.Field, vs[0], vs[1])
			default:
				return fmt.Sprintf("%v BETWEEN '%v' AND '%v'", v.Field, vs[0], vs[1])
			}
		}
		return ""
	case QueryKeyNotBetween:
		if vs, ok := v.Value.([]interface{}); ok {
			if vs == nil || len(vs) < 2 {
				return ""
			}
			switch vs[0].(type) {
			case int, int8, int16, int32, int64, float32, float64:
				return fmt.Sprintf("%v NOT BETWEEN %v AND %v", v.Field, vs[0], vs[1])
			default:
				return fmt.Sprintf("%v NOT BETWEEN '%v' AND '%v'", v.Field, vs[0], vs[1])
			}
		}
		return ""
	default:
		return ""
	}
	switch v.Value.(type) {
	case int, int8, int16, int32, int64, float32, float64:
		return fmt.Sprintf("%v%v%v", v.Field, opera, v.Value)
	default:
		return fmt.Sprintf("%v%v'%v'", v.Field, opera, v.Value)
	}
}

func (s *SQLQuery) JSONtoSQLString(str string, alias ...string) (string, error) {
	if err := s.ParseJSONString(str); err != nil {
		return "", err
	}
	return s.String(alias...), nil
}

func (s *SQLQuery) SQLString(m map[string]interface{}, alias ...string) (string, error) {
	if err := s.Parse(m); err != nil {
		return "", err
	}
	return s.String(alias...), nil
}
<|endoftext|>


<commit_before>package main // import "github.com/ethernetdan/wedirect"

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/ethernetdan/cloudflare"
)

const defaultConfigFile = "config.json"

var (
	config   Config
	store    DomainStore
	cf       *cloudflare.Client
	recordId string
)

func init() {
	configFile := defaultConfigFile
	if configFileEnv := os.Getenv("CONFIG_FILE"); len(configFileEnv) != 0 {
		configFile = configFileEnv
	}

	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Panicf("Could not read configuration file: %v", err)
	}

	err = json.Unmarshal(data, &config)
	if err != nil {
		log.Panicf("Could not unmarshal configuration struct from file `%s`: %v", configFile, err)
	}
}

func main() {
	log.Infof("Starting up Popular DNS for domain `%s`...", config.Domain)

	cfClient, err := cloudflare.NewClient(config.CloudFlareEmail, config.CloudFlareToken)
	if err != nil {
		log.Panicf("Could not create CloudFlare client for email `%s`: %v", config.CloudFlareEmail, err)
	} else {
		cf = cfClient
	}

	record, err := createOrGetRecord(config.Domain, config.Domain)
	if err != nil {
		log.Panic(err)
	} else {
		recordId = record.Id
	}

	store = NewDomainStore(config.FirebaseURL, config.FirebaseAuth)

	http.HandleFunc("/", view)
	http.HandleFunc("/set", set)
	http.ListenAndServe(":8080", nil)
}

type PageData struct {
	Domain        string
	CurrentDomain string
	History       []Domain
}

func set(w http.ResponseWriter, r *http.Request) {
	domain := r.FormValue("domain")

	// check if valid domain
	if addrs, err := net.LookupIP(domain); err != nil {
		err = fmt.Errorf("Failed to resolve entered host(%s): %v", domain, err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else if len(addrs) < 1 {
		err = fmt.Errorf("No IPs associated with host `%s`", domain)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	err := updateRecord(config.Domain, recordId, config.Domain, domain)
	if err != nil {
		err = fmt.Errorf("Failed to update record: %v", err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	err = store.Set(domain)
	if err != nil {
		err = fmt.Errorf("Failed to persist update info: %v", err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "Successfully switched to %s", domain)
}

func view(w http.ResponseWriter, r *http.Request) {
	currentDomain, err := store.Domain()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	history, err := store.History()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	pageData := PageData{
		Domain:        config.Domain,
		CurrentDomain: currentDomain,
		History:       history,
	}
	renderTemplate(w, "home", &pageData)
}

func renderTemplate(w http.ResponseWriter, tmpl string, d *PageData) {
	t, _ := template.ParseFiles(tmpl + ".html")
	t.Execute(w, d)
}
<commit_msg>clean up server<commit_after>package main // import "github.com/ethernetdan/wedirect"

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/ethernetdan/cloudflare"
)

const defaultConfigFile = "config.json"

var (
	config   Config
	store    DomainStore
	cf       *cloudflare.Client
	recordId string
)

func init() {
	configFile := defaultConfigFile
	if configFileEnv := os.Getenv("CONFIG_FILE"); len(configFileEnv) != 0 {
		configFile = configFileEnv
	}

	data, err := ioutil.ReadFile(configFile)
	if err != nil {
		log.Panicf("Could not read configuration file: %v", err)
	}

	err = json.Unmarshal(data, &config)
	if err != nil {
		log.Panicf("Could not unmarshal configuration struct from file `%s`: %v", configFile, err)
	}
}

func main() {
	log.Infof("Starting up Popular DNS for domain `%s`...", config.Domain)

	cfClient, err := cloudflare.NewClient(config.CloudFlareEmail, config.CloudFlareToken)
	if err != nil {
		log.Panicf("Could not create CloudFlare client for email `%s`: %v", config.CloudFlareEmail, err)
	} else {
		cf = cfClient
	}

	record, err := createOrGetRecord(config.Domain, config.Domain)
	if err != nil {
		log.Panic(err)
	} else {
		recordId = record.Id
	}

	store = NewDomainStore(config.FirebaseURL, config.FirebaseAuth)

	http.HandleFunc("/", view)
	http.HandleFunc("/set", set)
	http.ListenAndServe(":8080", nil)

}

type PageData struct {
	Domain        string
	CurrentDomain string
	History       []Domain
}

func set(w http.ResponseWriter, r *http.Request) {
	domain := r.FormValue("domain")

	// check if valid domain
	if addrs, err := net.LookupIP(domain); err != nil {
		err = fmt.Errorf("Failed to resolve entered host(%s): %v", domain, err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	} else if len(addrs) < 1 {
		err = fmt.Errorf("No IPs associated with host `%s`", domain)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	err := updateRecord(config.Domain, recordId, config.Domain, domain)
	if err != nil {
		err = fmt.Errorf("Failed to update record: %v", err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusNotFound)
		return
	}

	err = store.Set(domain)
	if err != nil {
		err = fmt.Errorf("Failed to persist update info: %v", err)
		log.Error(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	fmt.Fprintf(w, "Successfully switched to %s", domain)
}

func view(w http.ResponseWriter, r *http.Request) {
	currentDomain, err := store.Domain()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	history, err := store.History()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	pageData := PageData{
		Domain:        config.Domain,
		CurrentDomain: currentDomain,
		History:       history,
	}
	renderTemplate(w, "home", &pageData)
}

func renderTemplate(w http.ResponseWriter, tmpl string, d *PageData) {
	t, _ := template.ParseFiles(tmpl + ".html")
	t.Execute(w, d)
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"text/template"
)

var serverTmpl = new(template.Template)

func init() {
	template.Must(serverTmpl.New("main").Parse(`

		<title>{{.Title}} :: Main</title>

Unimplemented.

`))
}

func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		log.Printf("Got %q request for %q", req.Method, req.URL)

		h.ServeHTTP(rw, req)
	})
}

func tmplHandler(t string) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		err := serverTmpl.ExecuteTemplate(rw, t, map[string]interface{}{
			"Req":   req,
			"Title": "PS2 Average Login Times",
		})
		if err != nil {
			log.Printf("Failed to execute %q: %v", t, err)
		}
	})
}

func server() {
	const (
		ServerAddr = ":8080"
	)

	http.Handle("/", logHandler(tmplHandler("main")))

	log.Printf("Starting server at %q...", ServerAddr)
	err := http.ListenAndServe(ServerAddr, nil)
	if err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
<commit_msg>Show average on page.<commit_after>package main

import (
	"log"
	"net/http"
	"text/template"
)

var serverTmpl = new(template.Template)

func init() {
	serverTmpl.Funcs(template.FuncMap{
		"average": func() string {
			return (<-average).String()
		},
	})

	template.Must(serverTmpl.New("main").Parse(`

		<title>{{.Title}} :: Main</title>

Current average: {{average}}

`))
}

func logHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		log.Printf("Got %q request for %q", req.Method, req.URL)

		h.ServeHTTP(rw, req)
	})
}

func tmplHandler(t string) http.Handler {
	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		err := serverTmpl.ExecuteTemplate(rw, t, map[string]interface{}{
			"Req":   req,
			"Title": "PS2 Average Login Times",
		})
		if err != nil {
			log.Printf("Failed to execute %q: %v", t, err)
		}
	})
}

func server() {
	const (
		ServerAddr = ":8080"
	)

	http.Handle("/", logHandler(tmplHandler("main")))

	log.Printf("Starting server at %q...", ServerAddr)
	err := http.ListenAndServe(ServerAddr, nil)
	if err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"compress/zlib"
	"flag"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"strconv"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "Hello\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	dump, _ := httputil.DumpRequest(req, false)
	log.Println(string(dump))

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
	} else {
		log.Println(buf.String())
	}

	io.WriteString(w, `{"status":"ok"}`)
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	dump, _ := httputil.DumpRequest(req, false)
	log.Println(string(dump))

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
	} else {
		log.Println(buf.String())
	}

	io.WriteString(w, "hello, world!\n")

}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<commit_msg>Attempt to post a metric to InfluxDB<commit_after>package main

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"strconv"
)

var port = flag.Int("port", 8080, "which port to listen on")
var authApiKey string

func handleApiKey(w http.ResponseWriter, req *http.Request) bool {
	if req.UserAgent() == "Datadog-Status-Check" {
		io.WriteString(w, "Hello\n")
		return true
	}
	err := req.ParseForm()
	if err != nil {
		log.Println("Error parsing form:", err)
		http.Error(w, err.Error(), 500)
		return true
	}
	values := req.Form
	api_key := values.Get("api_key")
	delete(values, "api_key")
	if len(authApiKey) > 0 && api_key != authApiKey {
		log.Println("Got bad API key:", api_key)
		http.Error(w, "Bad API Key", 403)
		return true
	}
	return false
}

func handleApi(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	dump, _ := httputil.DumpRequest(req, false)
	log.Println(string(dump))

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	} else {
		log.Println(buf.String())
	}

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func handleIntake(w http.ResponseWriter, req *http.Request) {
	if handleApiKey(w, req) {
		return
	}

	dump, _ := httputil.DumpRequest(req, false)
	log.Println(string(dump))

	body := req.Body
	if req.Header.Get("Content-Encoding") == "deflate" {
		var err error
		body, err = zlib.NewReader(body)
		if err != nil {
			log.Println(err)
			io.WriteString(w, `{"status":"failed"}`)
			return
		}
	}
	buf := bytes.NewBuffer([]byte{})
	_, err := io.Copy(buf, body)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	data := make(map[string]interface{})
	err = json.Unmarshal(buf.Bytes(), &data)
	if err != nil {
		log.Println(err)
		io.WriteString(w, `{"status":"failed"}`)
		return
	}

	for key, _ := range data {
		fmt.Println(key)
	}

	host := data["internalHostname"].(string)
	go pushStat(host, "system.load.1", data["system.load.1"].(float64))
	go pushStat(host, "system.load.5", data["system.load.5"].(float64))
	go pushStat(host, "system.load.15", data["system.load.15"].(float64))

	w.Header().Set("Content-Type", "application/json")
	io.WriteString(w, `{"status":"ok"}`)
}

func pushStat(host, key string, value float64) {
	log.Printf("[%s] %s: %f", host, key, value)

	body := bytes.NewBufferString(`[{"name" : "` + key + `","columns" : ["value", "host"],"points" : [[` + strconv.FormatFloat(value, 'f', 4, 64) + `, "` + host + `"]]}]`)
	resp, err := http.Post("http://localhost:8086/db/datadog/series?u=root&p=root", "application/json", body)
	if err != nil {
		log.Println(err)
	} else {
		log.Println(resp)
	}
}

func main() {
	flag.Parse()
	authApiKey = os.Getenv("API_KEY")
	if len(authApiKey) == 0 {
		log.Println("Warning: API_KEY is blank")
	}

	log.Println("dd-house listening on", *port)

	http.HandleFunc("/intake", handleIntake)
	http.HandleFunc("/api/v1/series/", handleApi)
	log.Fatal(http.ListenAndServe(":"+strconv.Itoa(*port), nil))
}
<|endoftext|>


<commit_before>// Copyright 2012 Kamil Kisiel. All rights reserved.
// Use of this source code is governed by the MIT
// license which can be found in the LICENSE file.

/*
Package sqlstruct provides some convenience functions for using structs with
the Go standard library's database/sql package.

The package matches struct field names to SQL query column names. A field can
also specify a matching column with "sql" tag, if it's different from field
name.  Unexported fields or fields marked with `sql:"-"` are ignored, just like
with "encoding/json" package.

For example:

    type T struct {
        F1 string
        F2 string `sql:"field2"`
        F3 string `sql:"-"`
    }

    rows, err := db.Query(fmt.Sprintf("SELECT %s FROM tablename", sqlstruct.Columns(T{})))
    ...

    for rows.Next() {
    	var t T
        err = sqlstruct.Scan(&t, rows)
        ...
    }

    err = rows.Err() // get any errors encountered during iteration

Aliased tables in a SQL statement may be scanned into a specific structure identified
by the same alias, using the ColumnsAliased and ScanAliased functions:

    type User struct {
        Id int `sql:"id"`
        Username string `sql:"username"`
        Email string `sql:"address"`
        Name string `sql:"name"`
        HomeAddress *Address `sql:"-"`
    }

    type Address struct {
        Id int `sql:"id"`
        City string `sql:"city"`
        Street string `sql:"address"`
    }

    ...

    var user User
    var address Address
    sql := `
SELECT %s, %s FROM users AS u
INNER JOIN address AS a ON a.id = u.address_id
WHERE u.username = ?
`
    sql = fmt.Sprintf(sql, sqlstruct.ColumnsAliased(*user, "u"), sqlstruct.ColumnsAliased(*address, "a"))
    rows, err := db.Query(sql, "gedi")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    if rows.Next() {
        err = sqlstruct.ScanAliased(&user, rows, "u")
        if err != nil {
            log.Fatal(err)
        }
        err = sqlstruct.ScanAliased(&address, rows, "a")
        if err != nil {
            log.Fatal(err)
        }
        user.HomeAddress = address
    }
    fmt.Printf("%+v", *user)
    // output: "{Id:1 Username:gedi Email:gediminas.morkevicius@gmail.com Name:Gedas HomeAddress:0xc21001f570}"
    fmt.Printf("%+v", *user.HomeAddress)
    // output: "{Id:2 City:Vilnius Street:Plento 34}"

*/
package sqlstruct

import (
	"bytes"
	"database/sql"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"sync"
)

// NameMapper is the function used to convert struct fields which do not have sql tags
// into database column names.
//
// The default mapper converts field names to lower case. If instead you would prefer
// field names converted to snake case, simply assign sqlstruct.ToSnakeCase to the variable:
//
//		sqlstruct.NameMapper = sqlstruct.ToSnakeCase
//
// Alternatively for a custom mapping, any func(string) string can be used instead.
var NameMapper func(string) string = strings.ToLower

// A cache of fieldInfos to save reflecting every time. Inspried by encoding/xml
var finfos map[reflect.Type]fieldInfo
var finfoLock sync.RWMutex

// TagName is the name of the tag to use on struct fields
var TagName = "sql"

// fieldInfo is a mapping of field tag values to their indices
type fieldInfo map[string][]int

func init() {
	finfos = make(map[reflect.Type]fieldInfo)
}

// Rows defines the interface of types that are scannable with the Scan function.
// It is implemented by the sql.Rows type from the standard library
type Rows interface {
	Scan(...interface{}) error
	Columns() ([]string, error)
}

// getFieldInfo creates a fieldInfo for the provided type. Fields that are not tagged
// with the "sql" tag and unexported fields are not included.
func getFieldInfo(typ reflect.Type) fieldInfo {
	finfoLock.RLock()
	finfo, ok := finfos[typ]
	finfoLock.RUnlock()
	if ok {
		return finfo
	}

	finfo = make(fieldInfo)

	n := typ.NumField()
	for i := 0; i < n; i++ {
		f := typ.Field(i)
		tag := f.Tag.Get(TagName)

		// Skip unexported fields or fields marked with "-"
		if f.PkgPath != "" || tag == "-" {
			continue
		}

		// Handle embedded structs
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			for k, v := range getFieldInfo(f.Type) {
				finfo[k] = append([]int{i}, v...)
			}
			continue
		}

		// Use field name for untagged fields
		if tag == "" {
			tag = f.Name
		}
		tag = NameMapper(tag)

		finfo[tag] = []int{i}
	}

	finfoLock.Lock()
	finfos[typ] = finfo
	finfoLock.Unlock()

	return finfo
}

// Scan scans the next row from rows in to a struct pointed to by dest. The struct type
// should have exported fields tagged with the "sql" tag. Columns from row which are not
// mapped to any struct fields are ignored. Struct fields which have no matching column
// in the result set are left unchanged.
func Scan(dest interface{}, rows Rows) error {
	return doScan(dest, rows, "")
}

// ScanAliased works like scan, except that it expects the results in the query to be
// prefixed by the given alias.
//
// For example, if scanning to a field named "name" with an alias of "user" it will
// expect to find the result in a column named "user_name".
//
// See ColumnAliased for a convenient way to generate these queries.
func ScanAliased(dest interface{}, rows Rows, alias string) error {
	return doScan(dest, rows, alias)
}

// Columns returns a string containing a sorted, comma-separated list of column names as
// defined by the type s. s must be a struct that has exported fields tagged with the "sql" tag.
func Columns(s interface{}) string {
	return strings.Join(cols(s), ", ")
}

// ColumnsAliased works like Columns except it prefixes the resulting column name with the
// given alias.
//
// For each field in the given struct it will generate a statement like:
//    alias.field AS alias_field
//
// It is intended to be used in conjunction with the ScanAliased function.
func ColumnsAliased(s interface{}, alias string) string {
	names := cols(s)
	aliased := make([]string, 0, len(names))
	for _, n := range names {
		aliased = append(aliased, alias+"."+n+" AS "+alias+"_"+n)
	}
	return strings.Join(aliased, ", ")
}

func cols(s interface{}) []string {
	v := reflect.ValueOf(s)
	fields := getFieldInfo(v.Type())

	names := make([]string, 0, len(fields))
	for f := range fields {
		names = append(names, f)
	}

	sort.Strings(names)
	return names
}

func doScan(dest interface{}, rows Rows, alias string) error {
	destv := reflect.ValueOf(dest)
	typ := destv.Type()

	if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct {
		panic(fmt.Errorf("dest must be pointer to struct; got %T", destv))
	}
	fieldInfo := getFieldInfo(typ.Elem())

	elem := destv.Elem()
	var values []interface{}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	for _, name := range cols {
		if len(alias) > 0 {
			name = strings.Replace(name, alias+"_", "", 1)
		}
		idx, ok := fieldInfo[strings.ToLower(name)]
		var v interface{}
		if !ok {
			// There is no field mapped to this column so we discard it
			v = &sql.RawBytes{}
		} else {
			v = elem.FieldByIndex(idx).Addr().Interface()
		}
		values = append(values, v)
	}

	return rows.Scan(values...)
}

// ToSnakeCase converts a string to snake case, words separated with underscores.
// It's intended to be used with NameMapper to map struct field names to snake case database fields.
func ToSnakeCase(src string) string {
	thisUpper := false
	prevUpper := false

	buf := bytes.NewBufferString("")
	for i, v := range src {
		if v >= 'A' && v <= 'Z' {
			thisUpper = true
		} else {
			thisUpper = false
		}
		if i > 0 && thisUpper && !prevUpper {
			buf.WriteRune('_')
		}
		prevUpper = thisUpper
		buf.WriteRune(v)
	}
	return strings.ToLower(buf.String())
}
<commit_msg>fix codeblock on documentation<commit_after>// Copyright 2012 Kamil Kisiel. All rights reserved.
// Use of this source code is governed by the MIT
// license which can be found in the LICENSE file.

/*
Package sqlstruct provides some convenience functions for using structs with
the Go standard library's database/sql package.

The package matches struct field names to SQL query column names. A field can
also specify a matching column with "sql" tag, if it's different from field
name.  Unexported fields or fields marked with `sql:"-"` are ignored, just like
with "encoding/json" package.

For example:

    type T struct {
        F1 string
        F2 string `sql:"field2"`
        F3 string `sql:"-"`
    }

    rows, err := db.Query(fmt.Sprintf("SELECT %s FROM tablename", sqlstruct.Columns(T{})))
    ...

    for rows.Next() {
    	var t T
        err = sqlstruct.Scan(&t, rows)
        ...
    }

    err = rows.Err() // get any errors encountered during iteration

Aliased tables in a SQL statement may be scanned into a specific structure identified
by the same alias, using the ColumnsAliased and ScanAliased functions:

    type User struct {
        Id int `sql:"id"`
        Username string `sql:"username"`
        Email string `sql:"address"`
        Name string `sql:"name"`
        HomeAddress *Address `sql:"-"`
    }

    type Address struct {
        Id int `sql:"id"`
        City string `sql:"city"`
        Street string `sql:"address"`
    }

    ...

    var user User
    var address Address
    sql := `
	SELECT %s, %s FROM users AS u
	INNER JOIN address AS a ON a.id = u.address_id
	WHERE u.username = ?
	`
    sql = fmt.Sprintf(sql, sqlstruct.ColumnsAliased(*user, "u"), sqlstruct.ColumnsAliased(*address, "a"))
    rows, err := db.Query(sql, "gedi")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    if rows.Next() {
        err = sqlstruct.ScanAliased(&user, rows, "u")
        if err != nil {
            log.Fatal(err)
        }
        err = sqlstruct.ScanAliased(&address, rows, "a")
        if err != nil {
            log.Fatal(err)
        }
        user.HomeAddress = address
    }
    fmt.Printf("%+v", *user)
    // output: "{Id:1 Username:gedi Email:gediminas.morkevicius@gmail.com Name:Gedas HomeAddress:0xc21001f570}"
    fmt.Printf("%+v", *user.HomeAddress)
    // output: "{Id:2 City:Vilnius Street:Plento 34}"

*/
package sqlstruct

import (
	"bytes"
	"database/sql"
	"fmt"
	"reflect"
	"sort"
	"strings"
	"sync"
)

// NameMapper is the function used to convert struct fields which do not have sql tags
// into database column names.
//
// The default mapper converts field names to lower case. If instead you would prefer
// field names converted to snake case, simply assign sqlstruct.ToSnakeCase to the variable:
//
//		sqlstruct.NameMapper = sqlstruct.ToSnakeCase
//
// Alternatively for a custom mapping, any func(string) string can be used instead.
var NameMapper func(string) string = strings.ToLower

// A cache of fieldInfos to save reflecting every time. Inspried by encoding/xml
var finfos map[reflect.Type]fieldInfo
var finfoLock sync.RWMutex

// TagName is the name of the tag to use on struct fields
var TagName = "sql"

// fieldInfo is a mapping of field tag values to their indices
type fieldInfo map[string][]int

func init() {
	finfos = make(map[reflect.Type]fieldInfo)
}

// Rows defines the interface of types that are scannable with the Scan function.
// It is implemented by the sql.Rows type from the standard library
type Rows interface {
	Scan(...interface{}) error
	Columns() ([]string, error)
}

// getFieldInfo creates a fieldInfo for the provided type. Fields that are not tagged
// with the "sql" tag and unexported fields are not included.
func getFieldInfo(typ reflect.Type) fieldInfo {
	finfoLock.RLock()
	finfo, ok := finfos[typ]
	finfoLock.RUnlock()
	if ok {
		return finfo
	}

	finfo = make(fieldInfo)

	n := typ.NumField()
	for i := 0; i < n; i++ {
		f := typ.Field(i)
		tag := f.Tag.Get(TagName)

		// Skip unexported fields or fields marked with "-"
		if f.PkgPath != "" || tag == "-" {
			continue
		}

		// Handle embedded structs
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			for k, v := range getFieldInfo(f.Type) {
				finfo[k] = append([]int{i}, v...)
			}
			continue
		}

		// Use field name for untagged fields
		if tag == "" {
			tag = f.Name
		}
		tag = NameMapper(tag)

		finfo[tag] = []int{i}
	}

	finfoLock.Lock()
	finfos[typ] = finfo
	finfoLock.Unlock()

	return finfo
}

// Scan scans the next row from rows in to a struct pointed to by dest. The struct type
// should have exported fields tagged with the "sql" tag. Columns from row which are not
// mapped to any struct fields are ignored. Struct fields which have no matching column
// in the result set are left unchanged.
func Scan(dest interface{}, rows Rows) error {
	return doScan(dest, rows, "")
}

// ScanAliased works like scan, except that it expects the results in the query to be
// prefixed by the given alias.
//
// For example, if scanning to a field named "name" with an alias of "user" it will
// expect to find the result in a column named "user_name".
//
// See ColumnAliased for a convenient way to generate these queries.
func ScanAliased(dest interface{}, rows Rows, alias string) error {
	return doScan(dest, rows, alias)
}

// Columns returns a string containing a sorted, comma-separated list of column names as
// defined by the type s. s must be a struct that has exported fields tagged with the "sql" tag.
func Columns(s interface{}) string {
	return strings.Join(cols(s), ", ")
}

// ColumnsAliased works like Columns except it prefixes the resulting column name with the
// given alias.
//
// For each field in the given struct it will generate a statement like:
//    alias.field AS alias_field
//
// It is intended to be used in conjunction with the ScanAliased function.
func ColumnsAliased(s interface{}, alias string) string {
	names := cols(s)
	aliased := make([]string, 0, len(names))
	for _, n := range names {
		aliased = append(aliased, alias+"."+n+" AS "+alias+"_"+n)
	}
	return strings.Join(aliased, ", ")
}

func cols(s interface{}) []string {
	v := reflect.ValueOf(s)
	fields := getFieldInfo(v.Type())

	names := make([]string, 0, len(fields))
	for f := range fields {
		names = append(names, f)
	}

	sort.Strings(names)
	return names
}

func doScan(dest interface{}, rows Rows, alias string) error {
	destv := reflect.ValueOf(dest)
	typ := destv.Type()

	if typ.Kind() != reflect.Ptr || typ.Elem().Kind() != reflect.Struct {
		panic(fmt.Errorf("dest must be pointer to struct; got %T", destv))
	}
	fieldInfo := getFieldInfo(typ.Elem())

	elem := destv.Elem()
	var values []interface{}

	cols, err := rows.Columns()
	if err != nil {
		return err
	}

	for _, name := range cols {
		if len(alias) > 0 {
			name = strings.Replace(name, alias+"_", "", 1)
		}
		idx, ok := fieldInfo[strings.ToLower(name)]
		var v interface{}
		if !ok {
			// There is no field mapped to this column so we discard it
			v = &sql.RawBytes{}
		} else {
			v = elem.FieldByIndex(idx).Addr().Interface()
		}
		values = append(values, v)
	}

	return rows.Scan(values...)
}

// ToSnakeCase converts a string to snake case, words separated with underscores.
// It's intended to be used with NameMapper to map struct field names to snake case database fields.
func ToSnakeCase(src string) string {
	thisUpper := false
	prevUpper := false

	buf := bytes.NewBufferString("")
	for i, v := range src {
		if v >= 'A' && v <= 'Z' {
			thisUpper = true
		} else {
			thisUpper = false
		}
		if i > 0 && thisUpper && !prevUpper {
			buf.WriteRune('_')
		}
		prevUpper = thisUpper
		buf.WriteRune(v)
	}
	return strings.ToLower(buf.String())
}
<|endoftext|>


<commit_before>package service

import (
	"os"
	"os/signal"
)

// Start is a convenience method equivalent to `service.Load(m).Run()` and starting the
// app with `./<myapp> start`. Prefer using `Run()` as it is more flexible.
func (s *Service) Start() error {
	return s.RunCommand("start")
}

// StartForTest starts the app with the environment set to test.
// Returns stop function as a convenience.
func (s *Service) StartForTest() func() {
	s.Env = EnvTest
	err := s.setup()
	if err != nil {
		panic(err)
	}
	go s.start()
	s.started.Wait()
	return s.Stop
}

// start calls Start on each module, in goroutines. Assumes that
// setup() has already been called. Start command must not block.
func (s *Service) start() {
	for _, m := range s.modules {
		n := getModuleName(m)
		c := s.configs[n]
		BootPrintln("[service] starting", n)
		if c.Start != nil {
			c.Start()
		}
	}
	// mark as started
	s.started.Done()

	// mark process as running
	s.running.Add(1)

	// wait for a stop signal to be received
	// note: that c might crash without this parent goroutine knowing.
	s.wait()

	// mark process as done
	s.running.Done()
}

// wait blocks until a signal is received, or the stopper channel is closed
func (s *Service) wait() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	select {
	case sig := <-c:
		BootPrintln("[service] got signal:", sig)
	case <-s.stopper:
		BootPrintln("[service] app stop")
	}
	s.stop()
}
<commit_msg>bugfix: handle SIGTERM correctly.<commit_after>package service

import (
	"os"
	"os/signal"
	"syscall"
)

// Start is a convenience method equivalent to `service.Load(m).Run()` and starting the
// app with `./<myapp> start`. Prefer using `Run()` as it is more flexible.
func (s *Service) Start() error {
	return s.RunCommand("start")
}

// StartForTest starts the app with the environment set to test.
// Returns stop function as a convenience.
func (s *Service) StartForTest() func() {
	s.Env = EnvTest
	err := s.setup()
	if err != nil {
		panic(err)
	}
	go s.start()
	s.started.Wait()
	return s.Stop
}

// start calls Start on each module, in goroutines. Assumes that
// setup() has already been called. Start command must not block.
func (s *Service) start() {
	for _, m := range s.modules {
		n := getModuleName(m)
		c := s.configs[n]
		BootPrintln("[service] starting", n)
		if c.Start != nil {
			c.Start()
		}
	}
	// mark as started
	s.started.Done()

	// mark process as running
	s.running.Add(1)

	// wait for a stop signal to be received
	// note: that c might crash without this parent goroutine knowing.
	s.wait()

	// mark process as done
	s.running.Done()
}

// wait blocks until a signal is received, or the stopper channel is closed
func (s *Service) wait() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, syscall.SIGTERM, os.Kill)
	select {
	case sig := <-c:
		BootPrintln("[service] got signal:", sig)
	case <-s.stopper:
		BootPrintln("[service] app stop")
	}
	s.stop()
}
<|endoftext|>


<commit_before>// @llr REQ-0-DDLN-SWL-018
package phabricator

import (
	"errors"
	"fmt"
	"strings"

	"github.com/arbovm/levenshtein"
	"github.com/danieldanciu/gonduit"
	"github.com/danieldanciu/gonduit/core"
	"github.com/danieldanciu/gonduit/entities"
	"github.com/danieldanciu/gonduit/requests"

	"github.com/daedaleanai/reqtraq/linepipes"
)

var cachedApiToken string

// getApiToken returns the Phabricator API token that allows us to make authenticated API operations.
func getApiToken() (string, error) {
	if cachedApiToken != "" {
		return cachedApiToken, nil
	}

	// The Phabricator API token comes from https://p.daedalean.ai/settings/user/git/page/apitokens/ (the already
	// generated Standard Api Token is good to use
	//
	// set it on the git server repository like this:
	// $ ssh git.daedalean.ai
	// $ cd /var/git/exp.git
	// $ sudo -u git sh -c "git config --local --replace-all daedalean.phabricator-api-token <TOKEN>"
	apiToken, err := linepipes.Single(linepipes.Run("git", "config", "--get", "daedalean.phabricator-api-token"))
	if err != nil {
		msg := `No Phabricator API token set. Please go to
	https://p.daedalean.ai/settings/user/<YOUR_USERNAME_HERE>/page/apitokens/
click on <Generate API Token>, and then paste the token into this command
	git config --local --replace-all daedalean.phabricator-api-token <PASTE_TOKEN_HERE>`
		return "", fmt.Errorf(msg)
	}
	cachedApiToken = apiToken
	return apiToken, nil
}

// getApiClient returns a client connection to the Phabricator server
func getApiClient() (*gonduit.Conn, error) {
	apiToken, err := getApiToken()
	if err != nil {
		return nil, err
	}
	return gonduit.Dial("https://p.daedalean.ai", &core.ClientOptions{APIToken: apiToken})
}

// GetRevision returns the Differential revision with the given ID or an error if the revision is not found
func GetRevision(revisionID uint64) (*entities.DifferentialRevision, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.DifferentialQuery(requests.DifferentialQueryRequest{IDs: []uint64{revisionID}})
	if err != nil {
		return nil, err
	}
	if len(*res) == 0 {
		return nil, errors.New("Cannot be found")
	}
	return (*res)[0], nil
}

// GetProject returns the PHID of the Phabricator project with the given name or nil if the project doesn't exist.
// For example, when called with "Reqtraq" the method will return "PHID-PROJ-3e2qnmcuzxzl3iko7xdl".
// The method calls https://p.daedalean.ai/api/project.query with the request
//	{
//		"names": ["Reqtraq"]
//	}
func GetProject(name string) (*entities.Project, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ProjectQuery(requests.ProjectQueryRequest{Names: []string{name}})
	if err != nil {
		return nil, err
	}
	if len(res.Data) == 0 {
		return nil, nil
	}
	if len(res.Data) > 1 {
		return nil, fmt.Errorf("Ambiguous project name: %s. Multiple projects match the name", name)
	}
	for _, v := range res.Data {
		return &v, nil
	}
	return nil, nil
}

// CreateProject creates a Phabricator project with the given name and parent and returns it.
func CreateProject(name, parentPHID string) (*entities.Project, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "name", Value: name},
	}
	if parentPHID != "" {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentPHID})
	}
	project, err := client.ProjectEdit(requests.EditEndpointRequest{
		Transactions: transactions})
	if err != nil {
		return nil, err
	}

	return project, nil
}

func GetOrCreateProject(name, parentPHID string) (*entities.Project, error) {
	project, err := GetProject(name)
	if err != nil {
		return nil, err
	}
	if project != nil {
		return project, nil
	}
	return CreateProject(name, parentPHID)
}

// FindTaskByPHID returns the Phabricator task with the given PHID string
func FindTaskByPHID(phid string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}

	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{PHIDs: []string{phid}})
	if err != nil {
		return nil, err
	}

	for _, v := range *res {
		return v, nil
	}
	return nil, fmt.Errorf("No task with phid %s found.", phid)
}

// FindTaskByTitle by title returns the Maniphest task with the given title, nil if the task is not found, or an error if
// there was an error finding the task. In case there are multiple tasks with the given title, FindTaskByTitle
// returns an error.
func FindTaskByTitle(taskTitle, projectPHID string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{FullText: taskTitle, ProjectPHIDs: []string{projectPHID}})
	if err != nil {
		return nil, err
	}

	var tasks []*entities.ManiphestTask
	for _, task := range *res {
		if task.Title == taskTitle {
			tasks = append(tasks, task)
		}
	}
	if len(tasks) == 0 {
		return nil, nil
	}
	if len(tasks) == 1 {
		return tasks[0], nil
	}
	return nil, fmt.Errorf("Multiple tasks found with title '%s'", taskTitle)
}

// FindTask returns the Maniphest task corresponding to the given Requirement ID, nil if the task was not found or an error if
// there was an error finding the task. In case there are multiple tasks with the given ID in the title, FindTask
// deterministically selects the task with the title that matches as closely as possible the given title
func FindTask(requirementID, requirementTitle, projectPHID string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{FullText: requirementID, ProjectPHIDs: []string{projectPHID}})
	if err != nil {
		return nil, err
	}

	var tasks []*entities.ManiphestTask
	for _, task := range *res {
		if strings.Contains(task.Title, requirementID) {
			tasks = append(tasks, task)
		}
	}
	if len(tasks) == 0 {
		return nil, nil
	}
	if len(tasks) == 1 {
		return tasks[0], nil
	}
	bestTask := tasks[0]
	bestDist := levenshtein.Distance(bestTask.Title, requirementTitle)
	for _, task := range tasks {
		if currentDist := levenshtein.Distance(task.Title, requirementTitle); currentDist < bestDist {
			bestDist = currentDist
			bestTask = task
		}
	}
	return bestTask, nil
}

// UpdateTask updates the Maniphest task with the given ID with the data from the given parameters
func UpdateTask(taskID, title, taskBody, projectPHID string, attributes map[string]string, parentTaskIDs []string) error {
	client, err := getApiClient()
	if err != nil {
		return err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "description", Value: taskBody},
		requests.Transaction{TransactionType: "projects.add", Value: []string{projectPHID}},
	}
	if len(parentTaskIDs) > 0 {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentTaskIDs[0]})
	}
	_, err = client.ManiphestEditTask(requests.EditEndpointRequest{
		ObjectIdentifier: taskID,
		Transactions:     transactions})
	return err

}

// DeleteTask closes the Maniphest task with the given ID as INVALID
func DeleteTask(taskID, title, projectPHID string) error {
	client, err := getApiClient()
	if err != nil {
		return err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "projects.add", Value: []string{projectPHID}},
		requests.Transaction{TransactionType: "status", Value: "invalid"},
	}
	_, err = client.ManiphestEditTask(requests.EditEndpointRequest{
		ObjectIdentifier: taskID,
		Transactions:     transactions})
	return err

}

// UpdateTask updates the Maniphest task with the given ID with the data from the given map
func CreateTask(title, taskBody, projectPHID string, attributes map[string]string, parentTaskIDs []string) (string, error) {
	client, err := getApiClient()
	if err != nil {
		return "", err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "description", Value: taskBody},
		requests.Transaction{TransactionType: "status", Value: "open"},
		requests.Transaction{TransactionType: "projects.set", Value: []string{projectPHID}},
	}
	if len(parentTaskIDs) > 0 {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentTaskIDs[0]})
	}
	res, err := client.ManiphestEditTask(requests.EditEndpointRequest{
		Transactions: transactions})
	if err != nil {
		return "", err
	}
	return res.Object.PHID, err

}
<commit_msg>Mark the phabricator api as build-specific<commit_after>// This file is very daedalean specific and is marked so with the Phabricator build tag. If you want to use another task
// management system instead of Phabricator, simply copy this file, change the tag below to e.g. Bugzilla or JIRA and
// re-implement the public methods to

// +build phabricator

// @llr REQ-0-DDLN-SWL-018
package phabricator

import (
	"errors"
	"fmt"
	"strings"

	"github.com/arbovm/levenshtein"
	"github.com/danieldanciu/gonduit"
	"github.com/danieldanciu/gonduit/core"
	"github.com/danieldanciu/gonduit/entities"
	"github.com/danieldanciu/gonduit/requests"

	"github.com/daedaleanai/reqtraq/linepipes"
)

var cachedApiToken string

// getApiToken returns the Phabricator API token that allows us to make authenticated API operations.
func getApiToken() (string, error) {
	if cachedApiToken != "" {
		return cachedApiToken, nil
	}

	// The Phabricator API token comes from https://p.daedalean.ai/settings/user/git/page/apitokens/ (the already
	// generated Standard Api Token is good to use
	//
	// set it on the git server repository like this:
	// $ ssh git.daedalean.ai
	// $ cd /var/git/exp.git
	// $ sudo -u git sh -c "git config --local --replace-all daedalean.phabricator-api-token <TOKEN>"
	apiToken, err := linepipes.Single(linepipes.Run("git", "config", "--get", "daedalean.phabricator-api-token"))
	if err != nil {
		msg := `No Phabricator API token set. Please go to
	https://p.daedalean.ai/settings/user/<YOUR_USERNAME_HERE>/page/apitokens/
click on <Generate API Token>, and then paste the token into this command
	git config --local --replace-all daedalean.phabricator-api-token <PASTE_TOKEN_HERE>`
		return "", fmt.Errorf(msg)
	}
	cachedApiToken = apiToken
	return apiToken, nil
}

// getApiClient returns a client connection to the Phabricator server
func getApiClient() (*gonduit.Conn, error) {
	apiToken, err := getApiToken()
	if err != nil {
		return nil, err
	}
	return gonduit.Dial("https://p.daedalean.ai", &core.ClientOptions{APIToken: apiToken})
}

// GetRevision returns the Differential revision with the given ID or an error if the revision is not found
func GetRevision(revisionID uint64) (*entities.DifferentialRevision, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.DifferentialQuery(requests.DifferentialQueryRequest{IDs: []uint64{revisionID}})
	if err != nil {
		return nil, err
	}
	if len(*res) == 0 {
		return nil, errors.New("Cannot be found")
	}
	return (*res)[0], nil
}

// GetProject returns the PHID of the Phabricator project with the given name or nil if the project doesn't exist.
// For example, when called with "Reqtraq" the method will return "PHID-PROJ-3e2qnmcuzxzl3iko7xdl".
// The method calls https://p.daedalean.ai/api/project.query with the request
//	{
//		"names": ["Reqtraq"]
//	}
func GetProject(name string) (*entities.Project, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ProjectQuery(requests.ProjectQueryRequest{Names: []string{name}})
	if err != nil {
		return nil, err
	}
	if len(res.Data) == 0 {
		return nil, nil
	}
	if len(res.Data) > 1 {
		return nil, fmt.Errorf("Ambiguous project name: %s. Multiple projects match the name", name)
	}
	for _, v := range res.Data {
		return &v, nil
	}
	return nil, nil
}

// CreateProject creates a Phabricator project with the given name and parent and returns it.
func CreateProject(name, parentPHID string) (*entities.Project, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "name", Value: name},
	}
	if parentPHID != "" {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentPHID})
	}
	project, err := client.ProjectEdit(requests.EditEndpointRequest{
		Transactions: transactions})
	if err != nil {
		return nil, err
	}

	return project, nil
}

func GetOrCreateProject(name, parentPHID string) (*entities.Project, error) {
	project, err := GetProject(name)
	if err != nil {
		return nil, err
	}
	if project != nil {
		return project, nil
	}
	return CreateProject(name, parentPHID)
}

// FindTaskByPHID returns the Phabricator task with the given PHID string
func FindTaskByPHID(phid string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}

	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{PHIDs: []string{phid}})
	if err != nil {
		return nil, err
	}

	for _, v := range *res {
		return v, nil
	}
	return nil, fmt.Errorf("No task with phid %s found.", phid)
}

// FindTaskByTitle by title returns the Maniphest task with the given title, nil if the task is not found, or an error if
// there was an error finding the task. In case there are multiple tasks with the given title, FindTaskByTitle
// returns an error.
func FindTaskByTitle(taskTitle, projectPHID string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{FullText: taskTitle, ProjectPHIDs: []string{projectPHID}})
	if err != nil {
		return nil, err
	}

	var tasks []*entities.ManiphestTask
	for _, task := range *res {
		if task.Title == taskTitle {
			tasks = append(tasks, task)
		}
	}
	if len(tasks) == 0 {
		return nil, nil
	}
	if len(tasks) == 1 {
		return tasks[0], nil
	}
	return nil, fmt.Errorf("Multiple tasks found with title '%s'", taskTitle)
}

// FindTask returns the Maniphest task corresponding to the given Requirement ID, nil if the task was not found or an error if
// there was an error finding the task. In case there are multiple tasks with the given ID in the title, FindTask
// deterministically selects the task with the title that matches as closely as possible the given title
func FindTask(requirementID, requirementTitle, projectPHID string) (*entities.ManiphestTask, error) {
	client, err := getApiClient()
	if err != nil {
		return nil, err
	}
	res, err := client.ManiphestQuery(requests.ManiphestQueryRequest{FullText: requirementID, ProjectPHIDs: []string{projectPHID}})
	if err != nil {
		return nil, err
	}

	var tasks []*entities.ManiphestTask
	for _, task := range *res {
		if strings.Contains(task.Title, requirementID) {
			tasks = append(tasks, task)
		}
	}
	if len(tasks) == 0 {
		return nil, nil
	}
	if len(tasks) == 1 {
		return tasks[0], nil
	}
	bestTask := tasks[0]
	bestDist := levenshtein.Distance(bestTask.Title, requirementTitle)
	for _, task := range tasks {
		if currentDist := levenshtein.Distance(task.Title, requirementTitle); currentDist < bestDist {
			bestDist = currentDist
			bestTask = task
		}
	}
	return bestTask, nil
}

// UpdateTask updates the Maniphest task with the given ID with the data from the given parameters
func UpdateTask(taskID, title, taskBody, projectPHID string, attributes map[string]string, parentTaskIDs []string) error {
	client, err := getApiClient()
	if err != nil {
		return err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "description", Value: taskBody},
		requests.Transaction{TransactionType: "projects.add", Value: []string{projectPHID}},
	}
	if len(parentTaskIDs) > 0 {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentTaskIDs[0]})
	}
	_, err = client.ManiphestEditTask(requests.EditEndpointRequest{
		ObjectIdentifier: taskID,
		Transactions:     transactions})
	return err

}

// DeleteTask closes the Maniphest task with the given ID as INVALID
func DeleteTask(taskID, title, projectPHID string) error {
	client, err := getApiClient()
	if err != nil {
		return err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "projects.add", Value: []string{projectPHID}},
		requests.Transaction{TransactionType: "status", Value: "invalid"},
	}
	_, err = client.ManiphestEditTask(requests.EditEndpointRequest{
		ObjectIdentifier: taskID,
		Transactions:     transactions})
	return err

}

// UpdateTask updates the Maniphest task with the given ID with the data from the given map
func CreateTask(title, taskBody, projectPHID string, attributes map[string]string, parentTaskIDs []string) (string, error) {
	client, err := getApiClient()
	if err != nil {
		return "", err
	}
	transactions := []requests.Transaction{
		requests.Transaction{TransactionType: "title", Value: title},
		requests.Transaction{TransactionType: "description", Value: taskBody},
		requests.Transaction{TransactionType: "status", Value: "open"},
		requests.Transaction{TransactionType: "projects.set", Value: []string{projectPHID}},
	}
	if len(parentTaskIDs) > 0 {
		transactions = append(transactions, requests.Transaction{TransactionType: "parent", Value: parentTaskIDs[0]})
	}
	res, err := client.ManiphestEditTask(requests.EditEndpointRequest{
		Transactions: transactions})
	if err != nil {
		return "", err
	}
	return res.Object.PHID, err

}
<|endoftext|>


<commit_before>package sftest

import (
	"encoding/json"
	"errors"
	"fmt"
	"testing"

	"github.com/json-iterator/go/assert"
	structform "github.com/urso/go-structform"
)

type Recording []Record

type Record interface {
	Replay(v structform.ExtVisitor) error
}

type NilRec struct{}
type BoolRec struct{ Value bool }
type StringRec struct{ Value string }
type IntRec struct{ Value int }
type Int8Rec struct{ Value int8 }
type Int16Rec struct{ Value int16 }
type Int32Rec struct{ Value int32 }
type Int64Rec struct{ Value int64 }
type UintRec struct{ Value uint }
type ByteRec struct{ Value byte }
type Uint8Rec struct{ Value uint8 }
type Uint16Rec struct{ Value uint16 }
type Uint32Rec struct{ Value uint32 }
type Uint64Rec struct{ Value uint64 }
type Float32Rec struct{ Value float32 }
type Float64Rec struct{ Value float64 }

// extended (yet) non-recordible records
type Int8ArrRec struct{ Value []int8 }
type StringArrRec struct{ Value []string }
type StringObjRec struct{ Value map[string]string }
type UintObjRec struct{ Value map[string]uint }

type ObjectStartRec struct {
	Len int
	T   structform.BaseType
}
type ObjectFinishRec struct{}
type ObjectKeyRec struct{ Value string }

type ArrayStartRec struct {
	Len int
	T   structform.BaseType
}
type ArrayFinishRec struct{}

func (NilRec) Replay(vs structform.ExtVisitor) error            { return vs.OnNil() }
func (r BoolRec) Replay(vs structform.ExtVisitor) error         { return vs.OnBool(r.Value) }
func (r StringRec) Replay(vs structform.ExtVisitor) error       { return vs.OnString(r.Value) }
func (r IntRec) Replay(vs structform.ExtVisitor) error          { return vs.OnInt(r.Value) }
func (r Int8Rec) Replay(vs structform.ExtVisitor) error         { return vs.OnInt8(r.Value) }
func (r Int16Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt16(r.Value) }
func (r Int32Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt32(r.Value) }
func (r Int64Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt64(r.Value) }
func (r UintRec) Replay(vs structform.ExtVisitor) error         { return vs.OnUint(r.Value) }
func (r ByteRec) Replay(vs structform.ExtVisitor) error         { return vs.OnByte(r.Value) }
func (r Uint8Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnUint8(r.Value) }
func (r Uint16Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint16(r.Value) }
func (r Uint32Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint32(r.Value) }
func (r Uint64Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint64(r.Value) }
func (r Float32Rec) Replay(vs structform.ExtVisitor) error      { return vs.OnFloat32(r.Value) }
func (r Float64Rec) Replay(vs structform.ExtVisitor) error      { return vs.OnFloat64(r.Value) }
func (r ObjectStartRec) Replay(vs structform.ExtVisitor) error  { return vs.OnObjectStart(r.Len, r.T) }
func (r ObjectFinishRec) Replay(vs structform.ExtVisitor) error { return vs.OnObjectFinished() }
func (r ObjectKeyRec) Replay(vs structform.ExtVisitor) error    { return vs.OnKey(r.Value) }
func (r ArrayStartRec) Replay(vs structform.ExtVisitor) error   { return vs.OnArrayStart(r.Len, r.T) }
func (r ArrayFinishRec) Replay(vs structform.ExtVisitor) error  { return vs.OnArrayFinished() }

func (r Int8ArrRec) Replay(vs structform.ExtVisitor) error   { return vs.OnInt8Array(r.Value) }
func (r StringArrRec) Replay(vs structform.ExtVisitor) error { return vs.OnStringArray(r.Value) }
func (r UintObjRec) Replay(vs structform.ExtVisitor) error   { return vs.OnUintObject(r.Value) }
func (r StringObjRec) Replay(vs structform.ExtVisitor) error { return vs.OnStringObject(r.Value) }

func (rec *Recording) Replay(vs structform.Visitor) error {
	evs := structform.EnsureExtVisitor(vs)
	for _, r := range *rec {
		if err := r.Replay(evs); err != nil {
			return err
		}
	}
	return nil
}

func (r *Recording) add(v Record) error {
	*r = append(*r, v)
	return nil
}

func (r *Recording) OnNil() error              { return r.add(NilRec{}) }
func (r *Recording) OnBool(b bool) error       { return r.add(BoolRec{b}) }
func (r *Recording) OnString(s string) error   { return r.add(StringRec{s}) }
func (r *Recording) OnInt8(i int8) error       { return r.add(Int8Rec{i}) }
func (r *Recording) OnInt16(i int16) error     { return r.add(Int16Rec{i}) }
func (r *Recording) OnInt32(i int32) error     { return r.add(Int32Rec{i}) }
func (r *Recording) OnInt64(i int64) error     { return r.add(Int64Rec{i}) }
func (r *Recording) OnInt(i int) error         { return r.add(IntRec{i}) }
func (r *Recording) OnUint8(i uint8) error     { return r.add(Uint8Rec{i}) }
func (r *Recording) OnByte(i byte) error       { return r.add(ByteRec{i}) }
func (r *Recording) OnUint16(i uint16) error   { return r.add(Uint16Rec{i}) }
func (r *Recording) OnUint32(i uint32) error   { return r.add(Uint32Rec{i}) }
func (r *Recording) OnUint64(i uint64) error   { return r.add(Uint64Rec{i}) }
func (r *Recording) OnUint(i uint) error       { return r.add(UintRec{i}) }
func (r *Recording) OnFloat32(i float32) error { return r.add(Float32Rec{i}) }
func (r *Recording) OnFloat64(i float64) error { return r.add(Float64Rec{i}) }

func (r *Recording) OnArrayStart(len int, baseType structform.BaseType) error {
	return r.add(ArrayStartRec{len, baseType})
}
func (r *Recording) OnArrayFinished() error {
	return r.add(ArrayFinishRec{})
}

func (r *Recording) OnObjectStart(len int, baseType structform.BaseType) error {
	return r.add(ObjectStartRec{len, baseType})
}
func (r *Recording) OnObjectFinished() error {
	return r.add(ObjectFinishRec{})
}
func (r *Recording) OnKey(s string) error {
	return r.add(ObjectKeyRec{s})
}

func (r *Recording) expand() Recording {
	var to Recording
	r.Replay(&to)
	return to
}

func (r Recording) Assert(t *testing.T, expected Recording) {
	exp, err := expected.ToJSON()
	if err != nil {
		t.Error("Assert (expected): ", err)
		t.Logf("  recording: %#v", exp)
		return
	}

	act, err := r.ToJSON()
	if err != nil {
		t.Error("Assert (actual): ", err)
		t.Logf("  recording: %#v", r)
		return
	}

	assert.Equal(t, exp, act)
}

func (r Recording) ToJSON() (string, error) {
	v, _, err := buildValue(r.expand())
	if err != nil {
		return "", err
	}

	b, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		return "", err
	}

	return string(b), nil
}

type builder struct {
	stack []interface{}
	value interface{}
}

func buildValue(rec Recording) (interface{}, Recording, error) {
	if len(rec) == 0 {
		return nil, nil, errors.New("empty recording")
	}

	switch v := rec[0].(type) {
	case NilRec:
		return nil, rec[1:], nil
	case BoolRec:
		return v.Value, rec[1:], nil
	case StringRec:
		return v.Value, rec[1:], nil
	case IntRec:
		return v.Value, rec[1:], nil
	case Int8Rec:
		return v.Value, rec[1:], nil
	case Int16Rec:
		return v.Value, rec[1:], nil
	case Int32Rec:
		return v.Value, rec[1:], nil
	case Int64Rec:
		return v.Value, rec[1:], nil
	case UintRec:
		return v.Value, rec[1:], nil
	case ByteRec:
		return v.Value, rec[1:], nil
	case Uint8Rec:
		return v.Value, rec[1:], nil
	case Uint16Rec:
		return v.Value, rec[1:], nil
	case Uint32Rec:
		return v.Value, rec[1:], nil
	case Uint64Rec:
		return v.Value, rec[1:], nil
	case Float32Rec:
		return v.Value, rec[1:], nil
	case Float64Rec:
		return v.Value, rec[1:], nil
	case ArrayStartRec:
		return buildArray(rec[1:])
	case ObjectStartRec:
		return buildObject(rec[1:])

	default:
		return nil, nil, fmt.Errorf("Invalid record entry: %v", v)
	}
}

func buildArray(rec Recording) (interface{}, Recording, error) {
	a := []interface{}{}

	for len(rec) > 0 {
		var (
			v   interface{}
			err error
		)

		if _, end := rec[0].(ArrayFinishRec); end {
			return a, rec[1:], nil
		}

		v, rec, err = buildValue(rec)
		if err != nil {
			return nil, nil, err
		}

		a = append(a, v)
	}

	return nil, nil, errors.New("missing array finish record")
}

func buildObject(rec Recording) (interface{}, Recording, error) {
	obj := map[string]interface{}{}

	for len(rec) > 0 {
		var (
			key string
			v   interface{}
			err error
		)

		switch v := rec[0].(type) {
		case ObjectFinishRec:
			return obj, rec[1:], nil
		case ObjectKeyRec:
			key = v.Value
		}

		v, rec, err = buildValue(rec[1:])
		if err != nil {
			return nil, nil, err
		}

		obj[key] = v
	}

	return nil, nil, errors.New("missing object finish record")
}

func TestEncodeParseConsistent(
	t *testing.T,
	samples []Recording,
	constr func() (structform.Visitor, func(structform.Visitor) error),
) {
	for i, sample := range samples {
		expected, err := sample.ToJSON()
		if err != nil {
			panic(err)
		}

		t.Logf("test %v: %#v => %v", i, sample, expected)

		enc, dec := constr()

		err = sample.Replay(enc)
		if err != nil {
			t.Errorf("Failed to encode %#v with %v", sample, err)
			return
		}

		var target Recording
		err = dec(&target)
		if err != nil {
			t.Errorf("Failed to decode %#v with %v", target, err)
			t.Logf("  recording: %#v", target)
		}

		target.Assert(t, sample)
	}
}

func concatSamples(recs ...[]Recording) []Recording {
	var out []Recording
	for _, r := range recs {
		out = append(out, r...)
	}
	return out
}
<commit_msg>fix import in sftest.go<commit_after>package sftest

import (
	"encoding/json"
	"errors"
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	structform "github.com/urso/go-structform"
)

type Recording []Record

type Record interface {
	Replay(v structform.ExtVisitor) error
}

type NilRec struct{}
type BoolRec struct{ Value bool }
type StringRec struct{ Value string }
type IntRec struct{ Value int }
type Int8Rec struct{ Value int8 }
type Int16Rec struct{ Value int16 }
type Int32Rec struct{ Value int32 }
type Int64Rec struct{ Value int64 }
type UintRec struct{ Value uint }
type ByteRec struct{ Value byte }
type Uint8Rec struct{ Value uint8 }
type Uint16Rec struct{ Value uint16 }
type Uint32Rec struct{ Value uint32 }
type Uint64Rec struct{ Value uint64 }
type Float32Rec struct{ Value float32 }
type Float64Rec struct{ Value float64 }

// extended (yet) non-recordible records
type Int8ArrRec struct{ Value []int8 }
type StringArrRec struct{ Value []string }
type StringObjRec struct{ Value map[string]string }
type UintObjRec struct{ Value map[string]uint }

type ObjectStartRec struct {
	Len int
	T   structform.BaseType
}
type ObjectFinishRec struct{}
type ObjectKeyRec struct{ Value string }

type ArrayStartRec struct {
	Len int
	T   structform.BaseType
}
type ArrayFinishRec struct{}

func (NilRec) Replay(vs structform.ExtVisitor) error            { return vs.OnNil() }
func (r BoolRec) Replay(vs structform.ExtVisitor) error         { return vs.OnBool(r.Value) }
func (r StringRec) Replay(vs structform.ExtVisitor) error       { return vs.OnString(r.Value) }
func (r IntRec) Replay(vs structform.ExtVisitor) error          { return vs.OnInt(r.Value) }
func (r Int8Rec) Replay(vs structform.ExtVisitor) error         { return vs.OnInt8(r.Value) }
func (r Int16Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt16(r.Value) }
func (r Int32Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt32(r.Value) }
func (r Int64Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnInt64(r.Value) }
func (r UintRec) Replay(vs structform.ExtVisitor) error         { return vs.OnUint(r.Value) }
func (r ByteRec) Replay(vs structform.ExtVisitor) error         { return vs.OnByte(r.Value) }
func (r Uint8Rec) Replay(vs structform.ExtVisitor) error        { return vs.OnUint8(r.Value) }
func (r Uint16Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint16(r.Value) }
func (r Uint32Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint32(r.Value) }
func (r Uint64Rec) Replay(vs structform.ExtVisitor) error       { return vs.OnUint64(r.Value) }
func (r Float32Rec) Replay(vs structform.ExtVisitor) error      { return vs.OnFloat32(r.Value) }
func (r Float64Rec) Replay(vs structform.ExtVisitor) error      { return vs.OnFloat64(r.Value) }
func (r ObjectStartRec) Replay(vs structform.ExtVisitor) error  { return vs.OnObjectStart(r.Len, r.T) }
func (r ObjectFinishRec) Replay(vs structform.ExtVisitor) error { return vs.OnObjectFinished() }
func (r ObjectKeyRec) Replay(vs structform.ExtVisitor) error    { return vs.OnKey(r.Value) }
func (r ArrayStartRec) Replay(vs structform.ExtVisitor) error   { return vs.OnArrayStart(r.Len, r.T) }
func (r ArrayFinishRec) Replay(vs structform.ExtVisitor) error  { return vs.OnArrayFinished() }

func (r Int8ArrRec) Replay(vs structform.ExtVisitor) error   { return vs.OnInt8Array(r.Value) }
func (r StringArrRec) Replay(vs structform.ExtVisitor) error { return vs.OnStringArray(r.Value) }
func (r UintObjRec) Replay(vs structform.ExtVisitor) error   { return vs.OnUintObject(r.Value) }
func (r StringObjRec) Replay(vs structform.ExtVisitor) error { return vs.OnStringObject(r.Value) }

func (rec *Recording) Replay(vs structform.Visitor) error {
	evs := structform.EnsureExtVisitor(vs)
	for _, r := range *rec {
		if err := r.Replay(evs); err != nil {
			return err
		}
	}
	return nil
}

func (r *Recording) add(v Record) error {
	*r = append(*r, v)
	return nil
}

func (r *Recording) OnNil() error              { return r.add(NilRec{}) }
func (r *Recording) OnBool(b bool) error       { return r.add(BoolRec{b}) }
func (r *Recording) OnString(s string) error   { return r.add(StringRec{s}) }
func (r *Recording) OnInt8(i int8) error       { return r.add(Int8Rec{i}) }
func (r *Recording) OnInt16(i int16) error     { return r.add(Int16Rec{i}) }
func (r *Recording) OnInt32(i int32) error     { return r.add(Int32Rec{i}) }
func (r *Recording) OnInt64(i int64) error     { return r.add(Int64Rec{i}) }
func (r *Recording) OnInt(i int) error         { return r.add(IntRec{i}) }
func (r *Recording) OnUint8(i uint8) error     { return r.add(Uint8Rec{i}) }
func (r *Recording) OnByte(i byte) error       { return r.add(ByteRec{i}) }
func (r *Recording) OnUint16(i uint16) error   { return r.add(Uint16Rec{i}) }
func (r *Recording) OnUint32(i uint32) error   { return r.add(Uint32Rec{i}) }
func (r *Recording) OnUint64(i uint64) error   { return r.add(Uint64Rec{i}) }
func (r *Recording) OnUint(i uint) error       { return r.add(UintRec{i}) }
func (r *Recording) OnFloat32(i float32) error { return r.add(Float32Rec{i}) }
func (r *Recording) OnFloat64(i float64) error { return r.add(Float64Rec{i}) }

func (r *Recording) OnArrayStart(len int, baseType structform.BaseType) error {
	return r.add(ArrayStartRec{len, baseType})
}
func (r *Recording) OnArrayFinished() error {
	return r.add(ArrayFinishRec{})
}

func (r *Recording) OnObjectStart(len int, baseType structform.BaseType) error {
	return r.add(ObjectStartRec{len, baseType})
}
func (r *Recording) OnObjectFinished() error {
	return r.add(ObjectFinishRec{})
}
func (r *Recording) OnKey(s string) error {
	return r.add(ObjectKeyRec{s})
}

func (r *Recording) expand() Recording {
	var to Recording
	r.Replay(&to)
	return to
}

func (r Recording) Assert(t *testing.T, expected Recording) {
	exp, err := expected.ToJSON()
	if err != nil {
		t.Error("Assert (expected): ", err)
		t.Logf("  recording: %#v", exp)
		return
	}

	act, err := r.ToJSON()
	if err != nil {
		t.Error("Assert (actual): ", err)
		t.Logf("  recording: %#v", r)
		return
	}

	assert.Equal(t, exp, act)
}

func (r Recording) ToJSON() (string, error) {
	v, _, err := buildValue(r.expand())
	if err != nil {
		return "", err
	}

	b, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		return "", err
	}

	return string(b), nil
}

type builder struct {
	stack []interface{}
	value interface{}
}

func buildValue(rec Recording) (interface{}, Recording, error) {
	if len(rec) == 0 {
		return nil, nil, errors.New("empty recording")
	}

	switch v := rec[0].(type) {
	case NilRec:
		return nil, rec[1:], nil
	case BoolRec:
		return v.Value, rec[1:], nil
	case StringRec:
		return v.Value, rec[1:], nil
	case IntRec:
		return v.Value, rec[1:], nil
	case Int8Rec:
		return v.Value, rec[1:], nil
	case Int16Rec:
		return v.Value, rec[1:], nil
	case Int32Rec:
		return v.Value, rec[1:], nil
	case Int64Rec:
		return v.Value, rec[1:], nil
	case UintRec:
		return v.Value, rec[1:], nil
	case ByteRec:
		return v.Value, rec[1:], nil
	case Uint8Rec:
		return v.Value, rec[1:], nil
	case Uint16Rec:
		return v.Value, rec[1:], nil
	case Uint32Rec:
		return v.Value, rec[1:], nil
	case Uint64Rec:
		return v.Value, rec[1:], nil
	case Float32Rec:
		return v.Value, rec[1:], nil
	case Float64Rec:
		return v.Value, rec[1:], nil
	case ArrayStartRec:
		return buildArray(rec[1:])
	case ObjectStartRec:
		return buildObject(rec[1:])

	default:
		return nil, nil, fmt.Errorf("Invalid record entry: %v", v)
	}
}

func buildArray(rec Recording) (interface{}, Recording, error) {
	a := []interface{}{}

	for len(rec) > 0 {
		var (
			v   interface{}
			err error
		)

		if _, end := rec[0].(ArrayFinishRec); end {
			return a, rec[1:], nil
		}

		v, rec, err = buildValue(rec)
		if err != nil {
			return nil, nil, err
		}

		a = append(a, v)
	}

	return nil, nil, errors.New("missing array finish record")
}

func buildObject(rec Recording) (interface{}, Recording, error) {
	obj := map[string]interface{}{}

	for len(rec) > 0 {
		var (
			key string
			v   interface{}
			err error
		)

		switch v := rec[0].(type) {
		case ObjectFinishRec:
			return obj, rec[1:], nil
		case ObjectKeyRec:
			key = v.Value
		}

		v, rec, err = buildValue(rec[1:])
		if err != nil {
			return nil, nil, err
		}

		obj[key] = v
	}

	return nil, nil, errors.New("missing object finish record")
}

func TestEncodeParseConsistent(
	t *testing.T,
	samples []Recording,
	constr func() (structform.Visitor, func(structform.Visitor) error),
) {
	for i, sample := range samples {
		expected, err := sample.ToJSON()
		if err != nil {
			panic(err)
		}

		t.Logf("test %v: %#v => %v", i, sample, expected)

		enc, dec := constr()

		err = sample.Replay(enc)
		if err != nil {
			t.Errorf("Failed to encode %#v with %v", sample, err)
			return
		}

		var target Recording
		err = dec(&target)
		if err != nil {
			t.Errorf("Failed to decode %#v with %v", target, err)
			t.Logf("  recording: %#v", target)
		}

		target.Assert(t, sample)
	}
}

func concatSamples(recs ...[]Recording) []Recording {
	var out []Recording
	for _, r := range recs {
		out = append(out, r...)
	}
	return out
}
<|endoftext|>


<commit_before>package autoscaling

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// Attach attaches instances or load balancers from autoscaling group.
func Attach(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return errors.New("AUTO_SCALING_GROUP_NAME is required.")
	}
	asgName := args[0]

	if viper.GetString("autoscaling.attach.instance-ids") != "" {
		if err := attachInstances(asgName); err != nil {
			return err
		}
	}

	if viper.GetString("autoscaling.attach.load-balancer-names") != "" {
		if err := attachLoadBalancers(asgName); err != nil {
			return err
		}
	}

	return nil
}

func attachInstances(asgName string) error {
	client := newAutoScalingClient()

	instanceIds := aws.StringSlice(viper.GetStringSlice("autoscaling.attach.instance-ids"))
	params := &autoscaling.AttachInstancesInput{
		AutoScalingGroupName: &asgName,
		InstanceIds:          instanceIds,
	}

	if _, err := client.AttachInstances(params); err != nil {
		return errors.Wrap(err, "AttachInstances failed:")
	}

	return nil
}

func attachLoadBalancers(asgName string) error {
	client := newAutoScalingClient()

	loadBalancerNames := aws.StringSlice(viper.GetStringSlice("autoscaling.attach.load-balancer-names"))
	params := &autoscaling.AttachLoadBalancersInput{
		AutoScalingGroupName: &asgName,
		LoadBalancerNames:    loadBalancerNames,
	}

	if _, err := client.AttachLoadBalancers(params); err != nil {
		return errors.Wrap(err, "AttachLoadBalancers failed:")
	}

	return nil
}
<commit_msg>Remove period from error message<commit_after>package autoscaling

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/autoscaling"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// Attach attaches instances or load balancers from autoscaling group.
func Attach(cmd *cobra.Command, args []string) error {
	if len(args) == 0 {
		return errors.New("AUTO_SCALING_GROUP_NAME is required")
	}
	asgName := args[0]

	if viper.GetString("autoscaling.attach.instance-ids") != "" {
		if err := attachInstances(asgName); err != nil {
			return err
		}
	}

	if viper.GetString("autoscaling.attach.load-balancer-names") != "" {
		if err := attachLoadBalancers(asgName); err != nil {
			return err
		}
	}

	return nil
}

func attachInstances(asgName string) error {
	client := newAutoScalingClient()

	instanceIds := aws.StringSlice(viper.GetStringSlice("autoscaling.attach.instance-ids"))
	params := &autoscaling.AttachInstancesInput{
		AutoScalingGroupName: &asgName,
		InstanceIds:          instanceIds,
	}

	if _, err := client.AttachInstances(params); err != nil {
		return errors.Wrap(err, "AttachInstances failed:")
	}

	return nil
}

func attachLoadBalancers(asgName string) error {
	client := newAutoScalingClient()

	loadBalancerNames := aws.StringSlice(viper.GetStringSlice("autoscaling.attach.load-balancer-names"))
	params := &autoscaling.AttachLoadBalancersInput{
		AutoScalingGroupName: &asgName,
		LoadBalancerNames:    loadBalancerNames,
	}

	if _, err := client.AttachLoadBalancers(params); err != nil {
		return errors.Wrap(err, "AttachLoadBalancers failed:")
	}

	return nil
}
<|endoftext|>


<commit_before>package kite

// MethodHandling defines how to handle chaining of kite.Handler middlewares.
// An error braks the chain regardless of what handling is used. Note that all
// Pre and Post handlers are executed regardless the handling logic, only the
// return paramater is defined by.
type MethodHandling int

const (
	// ReturnMethod returns main method reston. This is the standard default.
	ReturnMethod MethodHandling = iota

	// ReturnFirst returns with first non-nil response
	ReturnFirst

	// ReturnLatest executes all handlers in order and return the latest
	// handlers return value
	ReturnLatest
)

// Objects implementing the Handler interface can be registered to a method.
// The returned result must be marshalable with json package.
type Handler interface {
	ServeKite(*Request) (result interface{}, err error)
}

// HandlerFunc is a type adapter to allow the use of ordinary functions as
// Kite handlers. If h is a function with the appropriate signature,
// HandlerFunc(h) is a Handler object that calls h.
type HandlerFunc func(*Request) (result interface{}, err error)

// ServeKite calls h(r)
func (h HandlerFunc) ServeKite(r *Request) (interface{}, error) {
	return h(r)
}

// Method defines a method and the Handler it is bind to. By default
// "ExitOnMethod" handling is used.
type Method struct {
	// name is the method name. Unnamed methods can exist
	name string

	// handler contains the related Handler for the given method
	handler      Handler   // handler is the base handler, the response of it is returned as the final
	preHandlers  []Handler // a list of handlers that are executed before the main handler
	postHandlers []Handler // a list of handlers that are executed after the main handler

	// authenticate defines if a given authenticator function is enabled for
	// the given auth type in the request.
	authenticate bool

	// handling defines how to handle chaining of kite.Handler middlewares.
	handling MethodHandling
}

// addHandle is an internal method to add a handler
func (k *Kite) addHandle(method string, handler Handler) *Method {
	authenticate := true
	if k.Config.DisableAuthentication {
		authenticate = false
	}

	m := &Method{
		name:         method,
		handler:      handler,
		preHandlers:  k.preHandlers,
		postHandlers: k.postHandlers,
		authenticate: authenticate,
		handling:     k.MethodHandling,
	}

	k.handlers[method] = m
	return m
}

// DisableAuthentication disables authentication check for this method.
func (m *Method) DisableAuthentication() *Method {
	m.authenticate = false
	return m
}

// PreHandler adds a new kite handler which is executed before the method.
func (m *Method) PreHandle(handler Handler) *Method {
	m.preHandlers = append(m.preHandlers, handler)
	return m
}

// PreHandlerFunc adds a new kite handlerfunc which is executed before the
// method.
func (m *Method) PreHandleFunc(handler HandlerFunc) *Method {
	return m.PreHandle(handler)
}

// PostHandle adds a new kite handler which is executed after the method.
func (m *Method) PostHandle(handler Handler) *Method {
	m.postHandlers = append(m.postHandlers, handler)
	return m
}

// PostHandlerFunc adds a new kite handlerfunc which is executed before the
// method.
func (m *Method) PostHandleFunc(handler HandlerFunc) *Method {
	return m.PostHandle(handler)
}

// Handle registers the handler for the given method. The handler is called
// when a method call is received from a Kite.
func (k *Kite) Handle(method string, handler Handler) *Method {
	return k.addHandle(method, handler)
}

// HandleFunc registers a handler to run when a method call is received from a
// Kite. It returns a *Method option to further modify certain options on a
// method call
func (k *Kite) HandleFunc(method string, handler HandlerFunc) *Method {
	return k.addHandle(method, handler)
}

// PreHandle registers an handler which is executed before a kite.Handler
// method is executed. Calling PreHandle multiple times registers multiple
// handlers. A non-error return triggers the execution of the next handler. The
// execution order is FIFO.
func (k *Kite) PreHandle(handler Handler) {
	k.preHandlers = append(k.preHandlers, handler)
}

// PreHandleFunc is the same as PreHandle. It accepts a HandlerFunc.
func (k *Kite) PreHandleFunc(handler HandlerFunc) {
	k.PreHandle(handler)
}

// PostHandle registers an handler which is executed after a kite.Handler
// method is executed. Calling PostHandler multiple times registers multiple
// handlers. A non-error return triggers the execution of the next handler. The
// execution order is FIFO.
func (k *Kite) PostHandle(handler Handler) {
	k.postHandlers = append(k.postHandlers, handler)
}

// PostHandleFunc is the same as PostHandle. It accepts a HandlerFunc.
func (k *Kite) PostHandleFunc(handler HandlerFunc) {
	k.PostHandle(handler)
}

func (m *Method) ServeKite(r *Request) (interface{}, error) {
	var firstResp interface{}
	var resp interface{}
	var err error

	// first execute preHandlers
	for _, handler := range m.preHandlers {
		resp, err = handler.ServeKite(r)
		if err != nil {
			return nil, err
		}

		if m.handling == ReturnFirst && resp != nil {
			firstResp = resp
		}
	}

	// now call our base handler
	resp, err = m.handler.ServeKite(r)
	if err != nil {
		return nil, err
	}

	// also save it dependent on the handling mechanism
	methodResp := resp

	if m.handling == ReturnFirst && resp != nil {
		firstResp = resp
	}

	// and finally return our postHandlers
	for _, handler := range m.preHandlers {
		resp, err = handler.ServeKite(r)
		if err != nil {
			return nil, err
		}

		if m.handling == ReturnFirst && resp != nil {
			firstResp = resp
		}
	}

	switch m.handling {
	case ReturnMethod:
		return methodResp, nil
	case ReturnFirst:
		return firstResp, nil
	case ReturnLatest:
		return resp, nil
	}

	return resp, nil
}
<commit_msg>method: fix typos<commit_after>package kite

// MethodHandling defines how to handle chaining of kite.Handler middlewares.
// An error braks the chain regardless of what handling is used. Note that all
// Pre and Post handlers are executed regardless the handling logic, only the
// return paramater is defined by the handling mode.
type MethodHandling int

const (
	// ReturnMethod returns main method's response. This is the standard default.
	ReturnMethod MethodHandling = iota

	// ReturnFirst returns the first non-nil response.
	ReturnFirst

	// ReturnLatest returns the latest response (waterfall behaviour)
	ReturnLatest
)

// Objects implementing the Handler interface can be registered to a method.
// The returned result must be marshalable with json package.
type Handler interface {
	ServeKite(*Request) (result interface{}, err error)
}

// HandlerFunc is a type adapter to allow the use of ordinary functions as
// Kite handlers. If h is a function with the appropriate signature,
// HandlerFunc(h) is a Handler object that calls h.
type HandlerFunc func(*Request) (result interface{}, err error)

// ServeKite calls h(r)
func (h HandlerFunc) ServeKite(r *Request) (interface{}, error) {
	return h(r)
}

// Method defines a method and the Handler it is bind to. By default
// "ReturnMethod" handling is used.
type Method struct {
	// name is the method name. Unnamed methods can exist
	name string

	// handler contains the related Handler for the given method
	handler      Handler   // handler is the base handler, the response of it is returned as the final
	preHandlers  []Handler // a list of handlers that are executed before the main handler
	postHandlers []Handler // a list of handlers that are executed after the main handler

	// authenticate defines if a given authenticator function is enabled for
	// the given auth type in the request.
	authenticate bool

	// handling defines how to handle chaining of kite.Handler middlewares.
	handling MethodHandling
}

// addHandle is an internal method to add a handler
func (k *Kite) addHandle(method string, handler Handler) *Method {
	authenticate := true
	if k.Config.DisableAuthentication {
		authenticate = false
	}

	m := &Method{
		name:         method,
		handler:      handler,
		preHandlers:  k.preHandlers,
		postHandlers: k.postHandlers,
		authenticate: authenticate,
		handling:     k.MethodHandling,
	}

	k.handlers[method] = m
	return m
}

// DisableAuthentication disables authentication check for this method.
func (m *Method) DisableAuthentication() *Method {
	m.authenticate = false
	return m
}

// PreHandler adds a new kite handler which is executed before the method.
func (m *Method) PreHandle(handler Handler) *Method {
	m.preHandlers = append(m.preHandlers, handler)
	return m
}

// PreHandlerFunc adds a new kite handlerfunc which is executed before the
// method.
func (m *Method) PreHandleFunc(handler HandlerFunc) *Method {
	return m.PreHandle(handler)
}

// PostHandle adds a new kite handler which is executed after the method.
func (m *Method) PostHandle(handler Handler) *Method {
	m.postHandlers = append(m.postHandlers, handler)
	return m
}

// PostHandlerFunc adds a new kite handlerfunc which is executed before the
// method.
func (m *Method) PostHandleFunc(handler HandlerFunc) *Method {
	return m.PostHandle(handler)
}

// Handle registers the handler for the given method. The handler is called
// when a method call is received from a Kite.
func (k *Kite) Handle(method string, handler Handler) *Method {
	return k.addHandle(method, handler)
}

// HandleFunc registers a handler to run when a method call is received from a
// Kite. It returns a *Method option to further modify certain options on a
// method call
func (k *Kite) HandleFunc(method string, handler HandlerFunc) *Method {
	return k.addHandle(method, handler)
}

// PreHandle registers an handler which is executed before a kite.Handler
// method is executed. Calling PreHandle multiple times registers multiple
// handlers. A non-error return triggers the execution of the next handler. The
// execution order is FIFO.
func (k *Kite) PreHandle(handler Handler) {
	k.preHandlers = append(k.preHandlers, handler)
}

// PreHandleFunc is the same as PreHandle. It accepts a HandlerFunc.
func (k *Kite) PreHandleFunc(handler HandlerFunc) {
	k.PreHandle(handler)
}

// PostHandle registers an handler which is executed after a kite.Handler
// method is executed. Calling PostHandler multiple times registers multiple
// handlers. A non-error return triggers the execution of the next handler. The
// execution order is FIFO.
func (k *Kite) PostHandle(handler Handler) {
	k.postHandlers = append(k.postHandlers, handler)
}

// PostHandleFunc is the same as PostHandle. It accepts a HandlerFunc.
func (k *Kite) PostHandleFunc(handler HandlerFunc) {
	k.PostHandle(handler)
}

func (m *Method) ServeKite(r *Request) (interface{}, error) {
	var firstResp interface{}
	var resp interface{}
	var err error

	// first execute preHandlers
	for _, handler := range m.preHandlers {
		resp, err = handler.ServeKite(r)
		if err != nil {
			return nil, err
		}

		if m.handling == ReturnFirst && resp != nil {
			firstResp = resp
		}
	}

	// now call our base handler
	resp, err = m.handler.ServeKite(r)
	if err != nil {
		return nil, err
	}

	// also save it dependent on the handling mechanism
	methodResp := resp

	if m.handling == ReturnFirst && resp != nil {
		firstResp = resp
	}

	// and finally return our postHandlers
	for _, handler := range m.preHandlers {
		resp, err = handler.ServeKite(r)
		if err != nil {
			return nil, err
		}

		if m.handling == ReturnFirst && resp != nil {
			firstResp = resp
		}
	}

	switch m.handling {
	case ReturnMethod:
		return methodResp, nil
	case ReturnFirst:
		return firstResp, nil
	case ReturnLatest:
		return resp, nil
	}

	return resp, nil
}
<|endoftext|>