<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/bazelbuild/rules_typescript/devserver/concatjs"
	"github.com/bazelbuild/rules_typescript/devserver/devserver"
	"github.com/bazelbuild/rules_typescript/devserver/runfiles"
)

var (
	port            = flag.Int("port", 5432, "server port to listen on")
	// The "base" CLI flag is only kept because within Google3 because removing would be a breaking change due to
	// ConcatJS and "devserver/devserver.go" still respecting the specified base flag.
	base            = flag.String("base", "", "server base (required, runfiles of the binary)")
	pkgs            = flag.String("packages", "", "root package(s) to serve, comma-separated")
	manifest        = flag.String("manifest", "", "sources manifest (.MF)")
	scriptsManifest = flag.String("scripts_manifest", "", "preScripts manifest (.MF)")
	servingPath     = flag.String("serving_path", "/_/ts_scripts.js", "path to serve the combined sources at")
	entryModule     = flag.String("entry_module", "", "entry module name")
)

func main() {
	flag.Parse()

	if len(*pkgs) == 0 || (*manifest == "") || (*scriptsManifest == "") {
		fmt.Fprintf(os.Stderr, "Required argument not set\n")
		os.Exit(1)
	}

	manifestPath, err := runfiles.Runfile(*base, *scriptsManifest)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to find scripts_manifest in runfiles: %v\n", err)
		os.Exit(1)
	}

	scriptFiles, err := manifestFiles(manifestPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to read scripts_manifest: %v\n", err)
		os.Exit(1)
	}

	if !strings.HasPrefix(*servingPath, "/") {
		fmt.Fprintf(os.Stderr, "The specified serving_path does not start with a slash. "+
			"This causes the serving path to not have any effect.\n")
		os.Exit(1)
	}

	preScripts := make([]string, 0, 100)
	postScripts := make([]string, 0, 1)

	// Include the livereload script if IBAZEL_LIVERELOAD_URL is set.
	livereloadUrl := os.Getenv("IBAZEL_LIVERELOAD_URL")
	if livereloadUrl != "" {
		fmt.Printf("Serving livereload script from %s\n", livereloadUrl)
		livereloadLoaderSnippet := fmt.Sprintf(`(function(){
	const script = document.createElement('script');
	script.src = "%s";
	document.head.appendChild(script);
})();`, livereloadUrl)
		preScripts = append(preScripts, livereloadLoaderSnippet)
	}

	// Include the profiler script if IBAZEL_PROFILER_URL is set.
	profilerScriptURL := os.Getenv("IBAZEL_PROFILER_URL")
	if profilerScriptURL != "" {
		fmt.Printf("Serving profiler script from %s\n", profilerScriptURL)
		profilerLoaderSnippet := fmt.Sprintf(`(function(){
	const script = document.createElement('script');
	script.src = "%s";
	document.head.appendChild(script);
})();`, profilerScriptURL)
		preScripts = append(preScripts, profilerLoaderSnippet)
	}

	// Include all user scripts in preScripts. This should always include
	// the requirejs script which is added to scriptFiles by the devserver
	// skylark rule.
	for _, v := range scriptFiles {
		runfile, err := runfiles.Runfile(*base, v)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not find runfile %s, got error %s", v, err)
		}

		js, err := loadScript(runfile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to read script %s: %v\n", v, err)
		} else {
			preScripts = append(preScripts, js)
		}
	}

	// If the entryModule is set then add a snippet to load
	// the application to postScripts to be outputted after the sources
	if *entryModule != "" {
		postScripts = append(postScripts, fmt.Sprintf("require([\"%s\"]);", *entryModule))
	}

	http.Handle(*servingPath, concatjs.ServeConcatenatedJS(*manifest, *base, preScripts, postScripts,
		&RunfileFileSystem{}))
	pkgList := strings.Split(*pkgs, ",")
	http.HandleFunc("/", devserver.CreateFileHandler(*servingPath, *manifest, pkgList, *base))

	h, err := os.Hostname()
	if err != nil {
		h = "localhost"
	}

	fmt.Printf("Server listening on http://%s:%d/\n", h, *port)
	fmt.Fprintln(os.Stderr, http.ListenAndServe(fmt.Sprintf(":%d", *port), nil).Error())
	os.Exit(1)
}

func loadScript(path string) (string, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(buf), nil
}

// manifestFiles parses a manifest, returning a list of the files in the manifest.
func manifestFiles(manifest string) ([]string, error) {
	f, err := os.Open(manifest)
	if err != nil {
		return nil, fmt.Errorf("could not read manifest %s: %s", manifest, err)
	}
	defer f.Close()
	return manifestFilesFromReader(f)
}

// manifestFilesFromReader is a helper for manifestFiles, split out for testing.
func manifestFilesFromReader(r io.Reader) ([]string, error) {
	var lines []string
	s := bufio.NewScanner(r)
	for s.Scan() {
		path := s.Text()
		if path == "" {
			continue
		}
		lines = append(lines, path)
	}
	if err := s.Err(); err != nil {
		return nil, err
	}

	return lines, nil
}
<commit_msg>Print a working hostname when running ts_devserver on crostini<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/bazelbuild/rules_typescript/devserver/concatjs"
	"github.com/bazelbuild/rules_typescript/devserver/devserver"
	"github.com/bazelbuild/rules_typescript/devserver/runfiles"
)

var (
	port = flag.Int("port", 5432, "server port to listen on")
	// The "base" CLI flag is only kept because within Google3 because removing would be a breaking change due to
	// ConcatJS and "devserver/devserver.go" still respecting the specified base flag.
	base            = flag.String("base", "", "server base (required, runfiles of the binary)")
	pkgs            = flag.String("packages", "", "root package(s) to serve, comma-separated")
	manifest        = flag.String("manifest", "", "sources manifest (.MF)")
	scriptsManifest = flag.String("scripts_manifest", "", "preScripts manifest (.MF)")
	servingPath     = flag.String("serving_path", "/_/ts_scripts.js", "path to serve the combined sources at")
	entryModule     = flag.String("entry_module", "", "entry module name")
)

func main() {
	flag.Parse()

	if len(*pkgs) == 0 || (*manifest == "") || (*scriptsManifest == "") {
		fmt.Fprintf(os.Stderr, "Required argument not set\n")
		os.Exit(1)
	}

	manifestPath, err := runfiles.Runfile(*base, *scriptsManifest)

	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to find scripts_manifest in runfiles: %v\n", err)
		os.Exit(1)
	}

	scriptFiles, err := manifestFiles(manifestPath)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to read scripts_manifest: %v\n", err)
		os.Exit(1)
	}

	if !strings.HasPrefix(*servingPath, "/") {
		fmt.Fprintf(os.Stderr, "The specified serving_path does not start with a slash. "+
			"This causes the serving path to not have any effect.\n")
		os.Exit(1)
	}

	preScripts := make([]string, 0, 100)
	postScripts := make([]string, 0, 1)

	// Include the livereload script if IBAZEL_LIVERELOAD_URL is set.
	livereloadUrl := os.Getenv("IBAZEL_LIVERELOAD_URL")
	if livereloadUrl != "" {
		fmt.Printf("Serving livereload script from %s\n", livereloadUrl)
		livereloadLoaderSnippet := fmt.Sprintf(`(function(){
	const script = document.createElement('script');
	script.src = "%s";
	document.head.appendChild(script);
})();`, livereloadUrl)
		preScripts = append(preScripts, livereloadLoaderSnippet)
	}

	// Include the profiler script if IBAZEL_PROFILER_URL is set.
	profilerScriptURL := os.Getenv("IBAZEL_PROFILER_URL")
	if profilerScriptURL != "" {
		fmt.Printf("Serving profiler script from %s\n", profilerScriptURL)
		profilerLoaderSnippet := fmt.Sprintf(`(function(){
	const script = document.createElement('script');
	script.src = "%s";
	document.head.appendChild(script);
})();`, profilerScriptURL)
		preScripts = append(preScripts, profilerLoaderSnippet)
	}

	// Include all user scripts in preScripts. This should always include
	// the requirejs script which is added to scriptFiles by the devserver
	// skylark rule.
	for _, v := range scriptFiles {
		runfile, err := runfiles.Runfile(*base, v)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Could not find runfile %s, got error %s", v, err)
		}

		js, err := loadScript(runfile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to read script %s: %v\n", v, err)
		} else {
			preScripts = append(preScripts, js)
		}
	}

	// If the entryModule is set then add a snippet to load
	// the application to postScripts to be outputted after the sources
	if *entryModule != "" {
		postScripts = append(postScripts, fmt.Sprintf("require([\"%s\"]);", *entryModule))
	}

	http.Handle(*servingPath, concatjs.ServeConcatenatedJS(*manifest, *base, preScripts, postScripts,
		&RunfileFileSystem{}))
	pkgList := strings.Split(*pkgs, ",")
	http.HandleFunc("/", devserver.CreateFileHandler(*servingPath, *manifest, pkgList, *base))

	h, err := os.Hostname()
	if err != nil {
		h = "localhost"
	}
	// Detect if we are running in a linux container inside ChromeOS
	// If so, we assume you want to use the native browser (outside the container)
	// so you'll need to modify the hostname to access the server
	if _, err := os.Stat("/etc/apt/sources.list.d/cros.list"); err == nil {
		h = h + ".linux.test"
	}

	fmt.Printf("Server listening on http://%s:%d/\n", h, *port)
	fmt.Fprintln(os.Stderr, http.ListenAndServe(fmt.Sprintf(":%d", *port), nil).Error())
	os.Exit(1)
}

func loadScript(path string) (string, error) {
	buf, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	return string(buf), nil
}

// manifestFiles parses a manifest, returning a list of the files in the manifest.
func manifestFiles(manifest string) ([]string, error) {
	f, err := os.Open(manifest)
	if err != nil {
		return nil, fmt.Errorf("could not read manifest %s: %s", manifest, err)
	}
	defer f.Close()
	return manifestFilesFromReader(f)
}

// manifestFilesFromReader is a helper for manifestFiles, split out for testing.
func manifestFilesFromReader(r io.Reader) ([]string, error) {
	var lines []string
	s := bufio.NewScanner(r)
	for s.Scan() {
		path := s.Text()
		if path == "" {
			continue
		}
		lines = append(lines, path)
	}
	if err := s.Err(); err != nil {
		return nil, err
	}

	return lines, nil
}
<|endoftext|>


<commit_before>// Package camo provides an HTTP proxy server with content type
// restrictions as well as regex host allow list support.
package camo

import (
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/cactus/go-camo/camo/encoding"
	"github.com/cactus/gologit"
	"github.com/gorilla/mux"
	httpclient "github.com/mreiferson/go-httpclient"
)

// Config holds configuration data used when creating a Proxy with New.
type Config struct {
	// HMACKey is a byte slice to be used as the hmac key
	HMACKey []byte
	// AllowList is a list of string represenstations of regex (not compiled
	// regex) that are used as a whitelist filter. If an AllowList is present,
	// then anything not matching is dropped. If no AllowList is present,
	// no Allow filtering is done.
	AllowList []string
	// MaxSize is the maximum valid image size response (in bytes).
	MaxSize int64
	// MaxRedirects is the maximum number of redirects to follow.
	MaxRedirects int
	// Request timeout is a timeout for fetching upstream data.
	RequestTimeout time.Duration
	// Server name used in Headers and Via checks
	ServerName string
	// Default headers to add to each response
	AddHeaders map[string]string
}

// ProxyMetrics interface for Proxy to use for stats/metrics.
// This must be goroutine safe, as AddBytes and AddServed will be called from
// many goroutines.
type ProxyMetrics interface {
	AddBytes(bc int64)
	AddServed()
}

// A Proxy is a Camo like HTTP proxy, that provides content type
// restrictions as well as regex host allow list support.
type Proxy struct {
	client *http.Client
	config *Config
	// compiled allow list regex
	allowList []*regexp.Regexp
	metrics   ProxyMetrics
}

// NotFound handles client requests that did not match a valid
// mux route.
func (p *Proxy) NotFoundHandler() http.Handler {
	handler := func(w http.ResponseWriter, req *http.Request) {
		h := w.Header()
		for k, v := range p.config.AddHeaders {
			h.Set(k, v)
		}
		h.Set("Server", p.config.ServerName)
		h.Set("Date", formattedDate.String())
		http.Error(w, "404 Not Found", 404)
	}
	return http.HandlerFunc(handler)
}

// ServerHTTP handles the client request, validates the request is validly
// HMAC signed, filters based on the Allow list, and then proxies
// valid requests to the desired endpoint. Responses are filtered for
// proper image content types.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	gologit.Debugln("Request:", req.URL)
	if p.metrics != nil {
		go p.metrics.AddServed()
	}

	// add default headers
	wh := w.Header()
	for k, v := range p.config.AddHeaders {
		wh.Set(k, v)
	}
	wh.Set("Server", p.config.ServerName)
	wh.Set("Date", formattedDate.String())

	if req.Header.Get("Via") == p.config.ServerName {
		http.Error(w, "Request loop failure", http.StatusNotFound)
		return
	}

	vars := mux.Vars(req)
	sURL, ok := encoding.DecodeURL(p.config.HMACKey, vars["sigHash"], vars["encodedURL"])
	if !ok {
		http.Error(w, "Bad Signature", http.StatusForbidden)
		return
	}
	gologit.Debugln("URL:", sURL)
	gologit.Debugln("Client request:", req)

	u, err := url.Parse(sURL)
	if err != nil {
		gologit.Debugln(err)
		http.Error(w, "Bad url", http.StatusBadRequest)
		return
	}

	u.Host = strings.ToLower(u.Host)
	if u.Host == "" || localhostRegex.MatchString(u.Host) {
		http.Error(w, "Bad url", http.StatusNotFound)
		return
	}

	// if allowList is set, require match
	matchFound := true
	if len(p.allowList) > 0 {
		matchFound = false
		for _, rgx := range p.allowList {
			if rgx.MatchString(u.Host) {
				matchFound = true
			}
		}
	}
	if !matchFound {
		http.Error(w, "Allowlist host failure", http.StatusNotFound)
		return
	}

	// filter out rfc1918 hosts
	ip := net.ParseIP(u.Host)
	if ip != nil {
		if addr1918PrefixRegex.MatchString(ip.String()) {
			http.Error(w, "Denylist host failure", http.StatusNotFound)
			return
		}
	}

	nreq, err := http.NewRequest(req.Method, sURL, nil)
	if err != nil {
		gologit.Debugln("Could not create NewRequest", err)
		http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		return
	}

	// filter headers
	p.copyHeader(&nreq.Header, &req.Header, &ValidReqHeaders)
	if req.Header.Get("X-Forwarded-For") == "" {
		host, _, err := net.SplitHostPort(req.RemoteAddr)
		if err == nil && !addr1918PrefixRegex.MatchString(host) {
			nreq.Header.Add("X-Forwarded-For", host)
		}
	}

	// add an accept header if the client didn't send one
	if nreq.Header.Get("Accept") == "" {
		nreq.Header.Add("Accept", "image/*")
	}

	nreq.Header.Add("user-agent", p.config.ServerName)
	nreq.Header.Add("via", p.config.ServerName)

	gologit.Debugln("Built outgoing request:", nreq)

	resp, err := p.client.Do(nreq)
	if err != nil {
		gologit.Debugln("Could not connect to endpoint", err)
		if strings.Contains(err.Error(), "timeout") {
			http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		} else {
			http.Error(w, "Error Fetching Resource", http.StatusNotFound)
		}
		return
	}
	defer resp.Body.Close()
	gologit.Debugln("Response from upstream:", resp)

	// check for too large a response
	if resp.ContentLength > p.config.MaxSize {
		gologit.Debugln("Content length exceeded", sURL)
		http.Error(w, "Content length exceeded", http.StatusNotFound)
		return
	}

	switch resp.StatusCode {
	case 200:
		// check content type
		if !strings.HasPrefix(resp.Header.Get("Content-Type"), "image/") {
			gologit.Debugln("Non-Image content-type returned", u)
			http.Error(w, "Non-Image content-type returned",
				http.StatusBadRequest)
			return
		}
	case 300:
		gologit.Debugln("Multiple choices not supported")
		http.Error(w, "Multiple choices not supported", http.StatusNotFound)
		return
	case 301, 302, 303, 307:
		// if we get a redirect here, we either disabled following,
		// or followed until max depth and still got one (redirect loop)
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	case 304:
		h := w.Header()
		p.copyHeader(&h, &resp.Header, &ValidRespHeaders)
		w.WriteHeader(304)
		return
	case 404:
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	case 500, 502, 503, 504:
		// upstream errors should probably just 502. client can try later.
		http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		return
	default:
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}

	h := w.Header()
	p.copyHeader(&h, &resp.Header, &ValidRespHeaders)
	w.WriteHeader(resp.StatusCode)

	// since this uses io.Copy from the respBody, it is streaming
	// from the request to the response. This means it will nearly
	// always end up with a chunked response.
	bW, err := io.Copy(w, resp.Body)
	if err != nil {
		opErr, ok := err.(*net.OpError)
		if !ok {
			switch opErr.Err {
			case syscall.EPIPE:
				// broken pipe - endpoint terminated the conn
				// log as debug only.
				gologit.Debugln("Error writing response:", err)
			case syscall.ECONNRESET:
				// connection reset by peer - endpoint terminated the conn
				// log as debug only.
				gologit.Debugln("Error writing response:", err)
			default:
				// log anything else normally
				gologit.Println("Error writing response:", err)
			}
		}
		return
	}

	if p.metrics != nil {
		go p.metrics.AddBytes(bW)
	}
	gologit.Debugln("Response to client:", w)
}

// copy headers from src into dst
// empty filter map will result in no filtering being done
func (p *Proxy) copyHeader(dst, src *http.Header, filter *map[string]bool) {
	f := *filter
	filtering := false
	if len(f) > 0 {
		filtering = true
	}

	for k, vv := range *src {
		if x, ok := f[k]; filtering && (!ok || !x) {
			continue
		}
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

// SetMetricsCollector sets a proxy metrics (ProxyMetrics interface) for
// the proxy
func (p *Proxy) SetMetricsCollector(pm ProxyMetrics) {
	p.metrics = pm
}

// New returns a new Proxy. An error is returned if there was a failure
// to parse the regex from the passed Config.
func New(pc Config) (*Proxy, error) {
	tr := &httpclient.Transport{
		MaxIdleConnsPerHost: 8,
		ConnectTimeout:      2 * time.Second,
		RequestTimeout:      pc.RequestTimeout}

	// spawn an idle conn trimmer
	go func() {
		// prunes every 5 minutes. this is just a guess at an
		// initial value. very busy severs may want to lower this...
		for {
			time.Sleep(5 * time.Minute)
			tr.CloseIdleConnections()
		}
	}()

	client := &http.Client{Transport: tr}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if len(via) >= pc.MaxRedirects {
			return errors.New("Too many redirects")
		}
		return nil
	}

	var allow []*regexp.Regexp
	var c *regexp.Regexp
	var err error
	// compile allow list
	for _, v := range pc.AllowList {
		c, err = regexp.Compile(strings.TrimSpace(v))
		if err != nil {
			return nil, err
		}
		allow = append(allow, c)
	}

	return &Proxy{
		client:    client,
		config:    &pc,
		allowList: allow}, nil
}
<commit_msg>make debug log more distinct<commit_after>// Package camo provides an HTTP proxy server with content type
// restrictions as well as regex host allow list support.
package camo

import (
	"errors"
	"io"
	"net"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/cactus/go-camo/camo/encoding"
	"github.com/cactus/gologit"
	"github.com/gorilla/mux"
	httpclient "github.com/mreiferson/go-httpclient"
)

// Config holds configuration data used when creating a Proxy with New.
type Config struct {
	// HMACKey is a byte slice to be used as the hmac key
	HMACKey []byte
	// AllowList is a list of string represenstations of regex (not compiled
	// regex) that are used as a whitelist filter. If an AllowList is present,
	// then anything not matching is dropped. If no AllowList is present,
	// no Allow filtering is done.
	AllowList []string
	// MaxSize is the maximum valid image size response (in bytes).
	MaxSize int64
	// MaxRedirects is the maximum number of redirects to follow.
	MaxRedirects int
	// Request timeout is a timeout for fetching upstream data.
	RequestTimeout time.Duration
	// Server name used in Headers and Via checks
	ServerName string
	// Default headers to add to each response
	AddHeaders map[string]string
}

// ProxyMetrics interface for Proxy to use for stats/metrics.
// This must be goroutine safe, as AddBytes and AddServed will be called from
// many goroutines.
type ProxyMetrics interface {
	AddBytes(bc int64)
	AddServed()
}

// A Proxy is a Camo like HTTP proxy, that provides content type
// restrictions as well as regex host allow list support.
type Proxy struct {
	client *http.Client
	config *Config
	// compiled allow list regex
	allowList []*regexp.Regexp
	metrics   ProxyMetrics
}

// NotFound handles client requests that did not match a valid
// mux route.
func (p *Proxy) NotFoundHandler() http.Handler {
	handler := func(w http.ResponseWriter, req *http.Request) {
		h := w.Header()
		for k, v := range p.config.AddHeaders {
			h.Set(k, v)
		}
		h.Set("Server", p.config.ServerName)
		h.Set("Date", formattedDate.String())
		http.Error(w, "404 Not Found", 404)
	}
	return http.HandlerFunc(handler)
}

// ServerHTTP handles the client request, validates the request is validly
// HMAC signed, filters based on the Allow list, and then proxies
// valid requests to the desired endpoint. Responses are filtered for
// proper image content types.
func (p *Proxy) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	gologit.Debugln("Request:", req.URL)
	if p.metrics != nil {
		go p.metrics.AddServed()
	}

	// add default headers
	wh := w.Header()
	for k, v := range p.config.AddHeaders {
		wh.Set(k, v)
	}
	wh.Set("Server", p.config.ServerName)
	wh.Set("Date", formattedDate.String())

	if req.Header.Get("Via") == p.config.ServerName {
		http.Error(w, "Request loop failure", http.StatusNotFound)
		return
	}

	vars := mux.Vars(req)
	sURL, ok := encoding.DecodeURL(p.config.HMACKey, vars["sigHash"], vars["encodedURL"])
	if !ok {
		http.Error(w, "Bad Signature", http.StatusForbidden)
		return
	}
	gologit.Debugln("URL:", sURL)
	gologit.Debugln("Client request:", req)

	u, err := url.Parse(sURL)
	if err != nil {
		gologit.Debugln("url parse error:", err)
		http.Error(w, "Bad url", http.StatusBadRequest)
		return
	}

	u.Host = strings.ToLower(u.Host)
	if u.Host == "" || localhostRegex.MatchString(u.Host) {
		http.Error(w, "Bad url", http.StatusNotFound)
		return
	}

	// if allowList is set, require match
	matchFound := true
	if len(p.allowList) > 0 {
		matchFound = false
		for _, rgx := range p.allowList {
			if rgx.MatchString(u.Host) {
				matchFound = true
			}
		}
	}
	if !matchFound {
		http.Error(w, "Allowlist host failure", http.StatusNotFound)
		return
	}

	// filter out rfc1918 hosts
	ip := net.ParseIP(u.Host)
	if ip != nil {
		if addr1918PrefixRegex.MatchString(ip.String()) {
			http.Error(w, "Denylist host failure", http.StatusNotFound)
			return
		}
	}

	nreq, err := http.NewRequest(req.Method, sURL, nil)
	if err != nil {
		gologit.Debugln("Could not create NewRequest", err)
		http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		return
	}

	// filter headers
	p.copyHeader(&nreq.Header, &req.Header, &ValidReqHeaders)
	if req.Header.Get("X-Forwarded-For") == "" {
		host, _, err := net.SplitHostPort(req.RemoteAddr)
		if err == nil && !addr1918PrefixRegex.MatchString(host) {
			nreq.Header.Add("X-Forwarded-For", host)
		}
	}

	// add an accept header if the client didn't send one
	if nreq.Header.Get("Accept") == "" {
		nreq.Header.Add("Accept", "image/*")
	}

	nreq.Header.Add("user-agent", p.config.ServerName)
	nreq.Header.Add("via", p.config.ServerName)

	gologit.Debugln("Built outgoing request:", nreq)

	resp, err := p.client.Do(nreq)
	if err != nil {
		gologit.Debugln("Could not connect to endpoint", err)
		if strings.Contains(err.Error(), "timeout") {
			http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		} else {
			http.Error(w, "Error Fetching Resource", http.StatusNotFound)
		}
		return
	}
	defer resp.Body.Close()
	gologit.Debugln("Response from upstream:", resp)

	// check for too large a response
	if resp.ContentLength > p.config.MaxSize {
		gologit.Debugln("Content length exceeded", sURL)
		http.Error(w, "Content length exceeded", http.StatusNotFound)
		return
	}

	switch resp.StatusCode {
	case 200:
		// check content type
		if !strings.HasPrefix(resp.Header.Get("Content-Type"), "image/") {
			gologit.Debugln("Non-Image content-type returned", u)
			http.Error(w, "Non-Image content-type returned",
				http.StatusBadRequest)
			return
		}
	case 300:
		gologit.Debugln("Multiple choices not supported")
		http.Error(w, "Multiple choices not supported", http.StatusNotFound)
		return
	case 301, 302, 303, 307:
		// if we get a redirect here, we either disabled following,
		// or followed until max depth and still got one (redirect loop)
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	case 304:
		h := w.Header()
		p.copyHeader(&h, &resp.Header, &ValidRespHeaders)
		w.WriteHeader(304)
		return
	case 404:
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	case 500, 502, 503, 504:
		// upstream errors should probably just 502. client can try later.
		http.Error(w, "Error Fetching Resource", http.StatusBadGateway)
		return
	default:
		http.Error(w, "Not Found", http.StatusNotFound)
		return
	}

	h := w.Header()
	p.copyHeader(&h, &resp.Header, &ValidRespHeaders)
	w.WriteHeader(resp.StatusCode)

	// since this uses io.Copy from the respBody, it is streaming
	// from the request to the response. This means it will nearly
	// always end up with a chunked response.
	bW, err := io.Copy(w, resp.Body)
	if err != nil {
		opErr, ok := err.(*net.OpError)
		if !ok {
			switch opErr.Err {
			case syscall.EPIPE:
				// broken pipe - endpoint terminated the conn
				// log as debug only.
				gologit.Debugln("Error writing response:", err)
			case syscall.ECONNRESET:
				// connection reset by peer - endpoint terminated the conn
				// log as debug only.
				gologit.Debugln("Error writing response:", err)
			default:
				// log anything else normally
				gologit.Println("Error writing response:", err)
			}
		}
		return
	}

	if p.metrics != nil {
		go p.metrics.AddBytes(bW)
	}
	gologit.Debugln("Response to client:", w)
}

// copy headers from src into dst
// empty filter map will result in no filtering being done
func (p *Proxy) copyHeader(dst, src *http.Header, filter *map[string]bool) {
	f := *filter
	filtering := false
	if len(f) > 0 {
		filtering = true
	}

	for k, vv := range *src {
		if x, ok := f[k]; filtering && (!ok || !x) {
			continue
		}
		for _, v := range vv {
			dst.Add(k, v)
		}
	}
}

// SetMetricsCollector sets a proxy metrics (ProxyMetrics interface) for
// the proxy
func (p *Proxy) SetMetricsCollector(pm ProxyMetrics) {
	p.metrics = pm
}

// New returns a new Proxy. An error is returned if there was a failure
// to parse the regex from the passed Config.
func New(pc Config) (*Proxy, error) {
	tr := &httpclient.Transport{
		MaxIdleConnsPerHost: 8,
		ConnectTimeout:      2 * time.Second,
		RequestTimeout:      pc.RequestTimeout}

	// spawn an idle conn trimmer
	go func() {
		// prunes every 5 minutes. this is just a guess at an
		// initial value. very busy severs may want to lower this...
		for {
			time.Sleep(5 * time.Minute)
			tr.CloseIdleConnections()
		}
	}()

	client := &http.Client{Transport: tr}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		if len(via) >= pc.MaxRedirects {
			return errors.New("Too many redirects")
		}
		return nil
	}

	var allow []*regexp.Regexp
	var c *regexp.Regexp
	var err error
	// compile allow list
	for _, v := range pc.AllowList {
		c, err = regexp.Compile(strings.TrimSpace(v))
		if err != nil {
			return nil, err
		}
		allow = append(allow, c)
	}

	return &Proxy{
		client:    client,
		config:    &pc,
		allowList: allow}, nil
}
<|endoftext|>


<commit_before>package v1

import (
	"fmt"
	"strings"

	"gopkg.in/thehowl/go-osuapi.v1"
	"zxq.co/ripple/rippleapi/common"
	"zxq.co/x/getrank"
)

type userScore struct {
	Score
	Beatmap beatmap `json:"beatmap"`
}

type userScoresResponse struct {
	common.ResponseBase
	Scores []userScore `json:"scores"`
}

const userScoreSelectBase = `
SELECT
	scores.id, scores.beatmap_md5, scores.score,
	scores.max_combo, scores.full_combo, scores.mods,
	scores.300_count, scores.100_count, scores.50_count,
	scores.gekis_count, scores.katus_count, scores.misses_count,
	scores.time, scores.play_mode, scores.accuracy, scores.pp,
	scores.completed,

	beatmaps.beatmap_id, beatmaps.beatmapset_id, beatmaps.beatmap_md5,
	beatmaps.song_name, beatmaps.ar, beatmaps.od, beatmaps.difficulty_std,
	beatmaps.difficulty_taiko, beatmaps.difficulty_ctb, beatmaps.difficulty_mania,
	beatmaps.max_combo, beatmaps.hit_length, beatmaps.ranked,
	beatmaps.ranked_status_freezed, beatmaps.latest_update
FROM scores
INNER JOIN beatmaps ON beatmaps.beatmap_md5 = scores.beatmap_md5
INNER JOIN users ON users.id = scores.userid
`

// UserScoresBestGET retrieves the best scores of an user, sorted by PP if
// mode is standard and sorted by ranked score otherwise.
func UserScoresBestGET(md common.MethodData) common.CodeMessager {
	cm, wc, param := whereClauseUser(md, "users")
	if cm != nil {
		return *cm
	}
	mc := genModeClause(md)
	// For all modes that have PP, we leave out 0 PP scores.
	if getMode(md.Query("mode")) != "ctb" {
		mc += " AND scores.pp > 0"
	}
	return scoresPuts(md, fmt.Sprintf(
		`WHERE
			scores.completed = '3'
			AND %s
			%s
			AND `+md.User.OnlyUserPublic(true)+`
		ORDER BY scores.pp DESC, scores.score DESC %s`,
		wc, mc, common.Paginate(md.Query("p"), md.Query("l"), 100),
	), param)
}

// UserScoresRecentGET retrieves an user's latest scores.
func UserScoresRecentGET(md common.MethodData) common.CodeMessager {
	cm, wc, param := whereClauseUser(md, "users")
	if cm != nil {
		return *cm
	}
	return scoresPuts(md, fmt.Sprintf(
		`WHERE
			%s
			%s
			AND `+md.User.OnlyUserPublic(true)+`
		ORDER BY scores.id DESC %s`,
		wc, genModeClause(md), common.Paginate(md.Query("p"), md.Query("l"), 100),
	), param)
}

func scoresPuts(md common.MethodData, whereClause string, params ...interface{}) common.CodeMessager {
	rows, err := md.DB.Query(userScoreSelectBase+whereClause, params...)
	if err != nil {
		md.Err(err)
		return Err500
	}
	var scores []userScore
	for rows.Next() {
		var (
			us userScore
			b  beatmap
		)
		err = rows.Scan(
			&us.ID, &us.BeatmapMD5, &us.Score.Score,
			&us.MaxCombo, &us.FullCombo, &us.Mods,
			&us.Count300, &us.Count100, &us.Count50,
			&us.CountGeki, &us.CountKatu, &us.CountMiss,
			&us.Time, &us.PlayMode, &us.Accuracy, &us.PP,
			&us.Completed,

			&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
			&b.SongName, &b.AR, &b.OD, &b.Diff2.STD,
			&b.Diff2.Taiko, &b.Diff2.CTB, &b.Diff2.Mania,
			&b.MaxCombo, &b.HitLength, &b.Ranked,
			&b.RankedStatusFrozen, &b.LatestUpdate,
		)
		if err != nil {
			md.Err(err)
			return Err500
		}
		b.Difficulty = b.Diff2.STD
		us.Beatmap = b
		us.Rank = strings.ToUpper(getrank.GetRank(
			osuapi.Mode(us.PlayMode),
			osuapi.Mods(us.Mods),
			us.Accuracy,
			us.Count300,
			us.Count100,
			us.Count50,
			us.CountMiss,
		))
		scores = append(scores, us)
	}
	r := userScoresResponse{}
	r.Code = 200
	r.Scores = scores
	return r
}
<commit_msg>Fix wrong condition on ctb user scores<commit_after>package v1

import (
	"fmt"
	"strings"

	"gopkg.in/thehowl/go-osuapi.v1"
	"zxq.co/ripple/rippleapi/common"
	"zxq.co/x/getrank"
)

type userScore struct {
	Score
	Beatmap beatmap `json:"beatmap"`
}

type userScoresResponse struct {
	common.ResponseBase
	Scores []userScore `json:"scores"`
}

const userScoreSelectBase = `
SELECT
	scores.id, scores.beatmap_md5, scores.score,
	scores.max_combo, scores.full_combo, scores.mods,
	scores.300_count, scores.100_count, scores.50_count,
	scores.gekis_count, scores.katus_count, scores.misses_count,
	scores.time, scores.play_mode, scores.accuracy, scores.pp,
	scores.completed,

	beatmaps.beatmap_id, beatmaps.beatmapset_id, beatmaps.beatmap_md5,
	beatmaps.song_name, beatmaps.ar, beatmaps.od, beatmaps.difficulty_std,
	beatmaps.difficulty_taiko, beatmaps.difficulty_ctb, beatmaps.difficulty_mania,
	beatmaps.max_combo, beatmaps.hit_length, beatmaps.ranked,
	beatmaps.ranked_status_freezed, beatmaps.latest_update
FROM scores
INNER JOIN beatmaps ON beatmaps.beatmap_md5 = scores.beatmap_md5
INNER JOIN users ON users.id = scores.userid
`

// UserScoresBestGET retrieves the best scores of an user, sorted by PP if
// mode is standard and sorted by ranked score otherwise.
func UserScoresBestGET(md common.MethodData) common.CodeMessager {
	cm, wc, param := whereClauseUser(md, "users")
	if cm != nil {
		return *cm
	}
	mc := genModeClause(md)
	// We leave out 0 PP scores.
	mc += " AND scores.pp > 0"
	return scoresPuts(md, fmt.Sprintf(
		`WHERE
			scores.completed = '3'
			AND %s
			%s
			AND `+md.User.OnlyUserPublic(true)+`
		ORDER BY scores.pp DESC, scores.score DESC %s`,
		wc, mc, common.Paginate(md.Query("p"), md.Query("l"), 100),
	), param)
}

// UserScoresRecentGET retrieves an user's latest scores.
func UserScoresRecentGET(md common.MethodData) common.CodeMessager {
	cm, wc, param := whereClauseUser(md, "users")
	if cm != nil {
		return *cm
	}
	return scoresPuts(md, fmt.Sprintf(
		`WHERE
			%s
			%s
			AND `+md.User.OnlyUserPublic(true)+`
		ORDER BY scores.id DESC %s`,
		wc, genModeClause(md), common.Paginate(md.Query("p"), md.Query("l"), 100),
	), param)
}

func scoresPuts(md common.MethodData, whereClause string, params ...interface{}) common.CodeMessager {
	rows, err := md.DB.Query(userScoreSelectBase+whereClause, params...)
	if err != nil {
		md.Err(err)
		return Err500
	}
	var scores []userScore
	for rows.Next() {
		var (
			us userScore
			b  beatmap
		)
		err = rows.Scan(
			&us.ID, &us.BeatmapMD5, &us.Score.Score,
			&us.MaxCombo, &us.FullCombo, &us.Mods,
			&us.Count300, &us.Count100, &us.Count50,
			&us.CountGeki, &us.CountKatu, &us.CountMiss,
			&us.Time, &us.PlayMode, &us.Accuracy, &us.PP,
			&us.Completed,

			&b.BeatmapID, &b.BeatmapsetID, &b.BeatmapMD5,
			&b.SongName, &b.AR, &b.OD, &b.Diff2.STD,
			&b.Diff2.Taiko, &b.Diff2.CTB, &b.Diff2.Mania,
			&b.MaxCombo, &b.HitLength, &b.Ranked,
			&b.RankedStatusFrozen, &b.LatestUpdate,
		)
		if err != nil {
			md.Err(err)
			return Err500
		}
		b.Difficulty = b.Diff2.STD
		us.Beatmap = b
		us.Rank = strings.ToUpper(getrank.GetRank(
			osuapi.Mode(us.PlayMode),
			osuapi.Mods(us.Mods),
			us.Accuracy,
			us.Count300,
			us.Count100,
			us.Count50,
			us.CountMiss,
		))
		scores = append(scores, us)
	}
	r := userScoresResponse{}
	r.Code = 200
	r.Scores = scores
	return r
}
<|endoftext|>


<commit_before>package ecs

import (
	"github.com/denverdino/aliyungo/common"
	"os"
)

// Interval for checking status in WaitForXXX method
const DefaultWaitForInterval = 5

// Default timeout value for WaitForXXX method
const DefaultTimeout = 60

type Client struct {
	common.Client
}

const (
	// ECSDefaultEndpoint is the default API endpoint of ECS services
	ECSDefaultEndpoint = "https://ecs.aliyuncs.com"
	ECSAPIVersion      = "2014-05-26"
)

// NewClient creates a new instance of ECS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
	endpoint := os.Getenv("ECS_ENDPOINT")
	if endpoint == "" {
		endpoint = ECSDefaultEndpoint
	}
	return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}

func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
	client := &Client{}
	client.Init(endpoint, ECSAPIVersion, accessKeyId, accessKeySecret)
	return client
}
<commit_msg>update ecsendpoint<commit_after>package ecs

import (
	"github.com/denverdino/aliyungo/common"
	"os"
)

// Interval for checking status in WaitForXXX method
const DefaultWaitForInterval = 5

// Default timeout value for WaitForXXX method
const DefaultTimeout = 60

type Client struct {
	common.Client
}

const (
	// ECSDefaultEndpoint is the default API endpoint of ECS services
	ECSDefaultEndpoint = "https://ecs-cn-hangzhou.aliyuncs.com"
	ECSAPIVersion      = "2014-05-26"
)

// NewClient creates a new instance of ECS client
func NewClient(accessKeyId, accessKeySecret string) *Client {
	endpoint := os.Getenv("ECS_ENDPOINT")
	if endpoint == "" {
		endpoint = ECSDefaultEndpoint
	}
	return NewClientWithEndpoint(endpoint, accessKeyId, accessKeySecret)
}

func NewClientWithEndpoint(endpoint string, accessKeyId, accessKeySecret string) *Client {
	client := &Client{}
	client.Init(endpoint, ECSAPIVersion, accessKeyId, accessKeySecret)
	return client
}
<|endoftext|>


<commit_before>package main

import (
	// "encoding/hex"
	"fmt"
	"os/exec"
	"bytes"
	// "time"
	// "math/big"
	// "github.com/PointCoin/btcutil"
	// "github.com/PointCoin/btcwire"
	// "github.com/PointCoin/btcrpcclient"
	// "github.com/PointCoin/btcjson"
	"strconv"
	"strings"
	"encoding/json"
	// "regexp"
	// "math/rand"
	"log"
)

func main() {
	print := fmt.Println
	s := "\"Hello\""
	fmt.Println(s)

	o,_ := strconv.Unquote(s)
	fmt.Println(o)
	// address: Prxy397nCyskwHwmiv3TaFG6ZgZ88Cbnju
	// command = pointctl getrawtransaction c1de1be883834d733d096b3e14674978459f111f90d9dfbc5a82c9fa20db60a7

	txid := "c1de1be883834d733d096b3e14674978459f111f90d9dfbc5a82c9fa20db60a7"
	txdetails := getTransactionDetails(txid)
	m := getTransactionJson(txdetails)

	txidreturned  := m["txid"]
	print("\n\ngot txid", txidreturned)

	vinList := getVinList(m)
	voutList := getVoutList(m)

	_ , _ = vinList,voutList

	// Start with transaction

	// See input addresses of transaction as well as amounts
	// For each vin, going to have to
	fmt.Println("Outputs")
	for i, x := range vinList {
		tx := getTransactionDetails(x.txid)
		txjs := getTransactionJson(tx)
		txvouts := getVoutList(txjs)
		for _, y := range txvouts {

			if y.n == x.vout {
				fmt.Println("\t[",i,"]",y.addresses[0],y.value)
				break
			}
		}
	}
		// 1) Get tx,
		// 2) Get 'n'th output
		// 3) Get address and amount of that output

	// See output addresses as well as amounts
	// For each vout
		// 1)Print address and amount

}

type vin struct {
    txid string
    vout  int
}

type vout struct {
	value float64
	n int
	addresses []string
}

func getVinList(m map[string]interface{}) ([]vin) {
	vinList := make([]vin,0)
	vinJsonList := m["vin"]

	switch vv := vinJsonList.(type) {
	case []interface{}:
		for _, u := range vv {
			j := u.(map[string]interface{})
			vinTxid := j["txid"].(string)
			vinVout := int(j["vout"].(float64))
			newVin := vin{txid: vinTxid, vout: vinVout}
			vinList = append(vinList, newVin)
            // fmt.Println(i, u)
        }
		// print("yes matches")
	default:
		print("nope getVinList didn't work")
	}

	fmt.Println("vins:")
	for _,x := range vinList {
		fmt.Println(x)
	}
	return vinList

}

func getVoutList(m map[string] interface{}) ([]vout) {
	voutList := make([]vout,0)
	voutJsonList := m["vout"]

	switch oo := voutJsonList.(type) {
	case []interface{}:
		for _,u := range oo {
			j := u.(map[string]interface{})
			voutVal := j["value"].(float64)
			voutN := int(j["n"].(float64))

			vScriptPubKey := j["scriptPubKey"].(map[string]interface{})
			vAddresses := vScriptPubKey["addresses"].([]interface{})
			vAddressesStrings := make([]string, 0)
			for _,u := range vAddresses {
				addr := u.(string)
				vAddressesStrings = append(vAddressesStrings, addr)
			}

			newVout := vout{value: voutVal, n: voutN, addresses: vAddressesStrings}
			voutList = append(voutList, newVout)
		}
	}

	fmt.Println("vouts:")
	for _,x := range voutList {
		fmt.Println(x)
	}
	return voutList
}

func getTransactionJson(txdetails string) (map[string]interface{}){
	txdetailsbytes := []byte(txdetails)

	var f interface{}
	_ = json.Unmarshal(txdetailsbytes, &f)
	m := f.(map[string]interface{})
	return m
}

func getTransactionDetails(txhash string) (string){
	// command = pointctl getrawtransaction d2011b19dea6e98ec8bf78bd224856e76b6a9c460bbb347e49adb3dcf457e548
	cmd := exec.Command("pointctl", "getrawtransaction", txhash)

	var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
    	log.Fatal(err)
    }
    // fmt.Printf("result: %s\n", out)
    // fmt.Println(out.String())

	cmd2 := exec.Command("xargs", "pointctl", "decoderawtransaction")
	cmd2.Stdin = strings.NewReader(out.String())
	var out2 bytes.Buffer
    cmd2.Stdout = &out2
    err2 := cmd2.Run()
    if err2 != nil {
    	log.Fatal(err2)
    }

    return out2.String()
    // fmt.Println(out2.String())
}

<commit_msg>trying again<commit_after>package main

import (
	// "encoding/hex"
	"fmt"
	"os/exec"
	"bytes"
	// "time"
	// "math/big"
	// "github.com/PointCoin/btcutil"
	// "github.com/PointCoin/btcwire"
	// "github.com/PointCoin/btcrpcclient"
	// "github.com/PointCoin/btcjson"
	"strconv"
	"strings"
	"encoding/json"
	// "regexp"
	// "math/rand"
	"log"
)

func main() {
	print := fmt.Println
	s := "\"Hello\""
	fmt.Println(s)

	o,_ := strconv.Unquote(s)
	fmt.Println(o)
	// address: Prxy397nCyskwHwmiv3TaFG6ZgZ88Cbnju
	// command = pointctl getrawtransaction c1de1be883834d733d096b3e14674978459f111f90d9dfbc5a82c9fa20db60a7

	txid := "c1de1be883834d733d096b3e14674978459f111f90d9dfbc5a82c9fa20db60a7"
	txdetails := getTransactionDetails(txid)
	// m := getTransactionJson(txdetails)
	txdetailsbytes := []byte(txdetails)

	var f interface{}
	_ = json.Unmarshal(txdetailsbytes, &f)
	m := f.(map[string]interface{})
	txidreturned  := m["txid"]
	print("\n\ngot txid", txidreturned)

	vinList := getVinList(m)
	voutList := getVoutList(m)

	_ , _ = vinList,voutList

	// Start with transaction

	// See input addresses of transaction as well as amounts
	// For each vin, going to have to
	fmt.Println("Outputs")
	for i, x := range vinList {
		tx := getTransactionDetails(x.txid)
		txjs := getTransactionJson(tx)
		txvouts := getVoutList(txjs)
		for _, y := range txvouts {

			if y.n == x.vout {
				fmt.Println("\t[",i,"]",y.addresses[0],y.value)
				break
			}
		}
	}
		// 1) Get tx,
		// 2) Get 'n'th output
		// 3) Get address and amount of that output

	// See output addresses as well as amounts
	// For each vout
		// 1)Print address and amount

}

type vin struct {
    txid string
    vout  int
}

type vout struct {
	value float64
	n int
	addresses []string
}

func getVinList(m map[string]interface{}) ([]vin) {
	vinList := make([]vin,0)
	vinJsonList := m["vin"]

	switch vv := vinJsonList.(type) {
	case []interface{}:
		for _, u := range vv {
			j := u.(map[string]interface{})
			vinTxid := j["txid"].(string)
			vinVout := int(j["vout"].(float64))
			newVin := vin{txid: vinTxid, vout: vinVout}
			vinList = append(vinList, newVin)
            // fmt.Println(i, u)
        }
		// print("yes matches")
	default:
		print("nope getVinList didn't work")
	}

	fmt.Println("vins:")
	for _,x := range vinList {
		fmt.Println(x)
	}
	return vinList

}

func getVoutList(m map[string] interface{}) ([]vout) {
	voutList := make([]vout,0)
	voutJsonList := m["vout"]

	switch oo := voutJsonList.(type) {
	case []interface{}:
		for _,u := range oo {
			j := u.(map[string]interface{})
			voutVal := j["value"].(float64)
			voutN := int(j["n"].(float64))

			vScriptPubKey := j["scriptPubKey"].(map[string]interface{})
			vAddresses := vScriptPubKey["addresses"].([]interface{})
			vAddressesStrings := make([]string, 0)
			for _,u := range vAddresses {
				addr := u.(string)
				vAddressesStrings = append(vAddressesStrings, addr)
			}

			newVout := vout{value: voutVal, n: voutN, addresses: vAddressesStrings}
			voutList = append(voutList, newVout)
		}
	}

	fmt.Println("vouts:")
	for _,x := range voutList {
		fmt.Println(x)
	}
	return voutList
}

func getTransactionJson(txdetails string) (map[string]interface{}){
	txdetailsbytes := []byte(txdetails)

	var f interface{}
	_ = json.Unmarshal(txdetailsbytes, &f)
	m := f.(map[string]interface{})
	return m
}

func getTransactionDetails(txhash string) (string){
	// command = pointctl getrawtransaction d2011b19dea6e98ec8bf78bd224856e76b6a9c460bbb347e49adb3dcf457e548
	cmd := exec.Command("pointctl", "getrawtransaction", txhash)

	var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
    	log.Fatal(err)
    }
    // fmt.Printf("result: %s\n", out)
    // fmt.Println(out.String())

	cmd2 := exec.Command("xargs", "pointctl", "decoderawtransaction")
	cmd2.Stdin = strings.NewReader(out.String())
	var out2 bytes.Buffer
    cmd2.Stdout = &out2
    err2 := cmd2.Run()
    if err2 != nil {
    	log.Fatal(err2)
    }

    return out2.String()
    // fmt.Println(out2.String())
}

<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/bigroom/vision/models"
	"github.com/bigroom/zombies"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/websocket"
	log "github.com/sirupsen/logrus"
)

func messageLoop() {
	for {
		log.Info("Waiting for message...")

		m := <-messages

		log.WithFields(log.Fields{
			"message":     m.Content,
			"channel_key": m.Key(),
		}).Info("Dispatching message to user")

		for _, client := range clients[m.Key()] {
			err := client.c.WriteJSON(response{
				Name:     "MESSAGE",
				Contents: m,
			})

			if err != nil {
				sentry.CaptureError(err, nil)

				log.WithFields(log.Fields{
					"error": err,
				}).Info("Couldnt send error")
			}
		}
	}
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

func dispatchHandler(w http.ResponseWriter, r *http.Request, t *jwt.Token) {
	u, err := models.FetchUser("id", t.Claims["id"])
	if err != nil {
		log.WithFields(log.Fields{
			"id": t.Claims["id"],
		}).Info("Could not get user with ID")
		return
	}

	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		sentry.CaptureError(err, nil)
		return
	}

	defer c.Close()

	server := r.FormValue("server")
	if server == "" {
		server = "chat.freenode.net:6667"
	}

	resp, err := pool.Tell("exists", u.ID)
	if err != nil {
		sentry.CaptureError(err, nil)
		return
	}

	if !resp.MustBool() {
		log.Info("Creating zombie")
		add := zombies.Add{
			ID:     u.ID,
			Nick:   u.Username,
			Server: server,
		}

		_, err := pool.Tell("add", add)
		if err != nil {
			log.Error("error creating:", err)
			sentry.CaptureError(err, nil)
			return
		}
	}

	for {
		var a action
		err := c.ReadJSON(&a)
		if err != nil {
			log.Warn("Closing connection. Error reading:", err)
			return
		}

		if a.Name == "SET" {
			err = handleJoin(a, u, c)
		} else if a.Name == "SEND" {
			err = handleSend(a, u, c)
		} else if a.Name == "CHANNELS" {
			err = handleChannels(a, u, c)
		}

		if err != nil {
			sentry.CaptureError(err, nil)
		}
	}
}

func handleJoin(a action, u models.User, c *websocket.Conn) error {
	log.WithFields(log.Fields{
		"channel_key": a.Message,
	}).Info("Adding user to chanel")

	_, err := pool.Tell("join", zombies.Join{
		ID:      u.ID,
		Channel: a.Message,
	})

	if err != nil {
		log.Warn("Closing connection. Error joining chanel:", err)
		return err
	}

	clients[a.Message] = append(clients[a.Message], &conn{
		c:  c,
		id: u.ID,
	})

	return nil
}

func handleSend(a action, u models.User, c *websocket.Conn) error {
	log.WithFields(log.Fields{
		"message":     a.Message,
		"channel_key": a.Channel,
	}).Info("Going to send message to IRC")

	_, err := pool.Tell("send", zombies.Send{
		ID:      u.ID,
		Channel: a.Channel,
		Message: a.Message,
	})

	if err != nil {
		log.Info("Closing connection. Error sending message:", err)
		return err
	}

	log.WithFields(log.Fields{
		"channel_key": a.Channel,
		"message":     a.Message,
	}).Info("Sent message")

	return nil
}

func handleChannels(a action, u models.User, c *websocket.Conn) error {
	log.Info("Sending channels to user")
	resp, err := pool.Tell("channels", u.ID)
	if err != nil {
		log.Warn("Closing connection. Could not connect to kite: ", err)
		return err
	}

	var channels zombies.Channels
	resp.MustUnmarshal(&channels)

	for _, channel := range channels.Channels {
		key := a.Message + "/" + channel
		log.Info("Joining channel", key)
		clients[key] = append(clients[key], &conn{
			c:  c,
			id: u.ID,
		})
	}

	err = c.WriteJSON(response{
		Contents: channels.Channels,
		Name:     "CHANNELS",
	})

	if err != nil {
		log.Warn("Could not write JSON", err)
		return err
	}

	return nil
}

type action struct {
	Name    string `json:"name"`
	Message string `json:"message"`
	Channel string `json:"channel"`
}

type conn struct {
	id int64
	c  *websocket.Conn
}

type response struct {
	Name     string      `json:"name"`
	Contents interface{} `json:"contents"`
}
<commit_msg>Fix duplicate message sending<commit_after>package main

import (
	"net/http"

	"github.com/bigroom/vision/models"
	"github.com/bigroom/zombies"
	"github.com/dgrijalva/jwt-go"
	"github.com/gorilla/websocket"
	log "github.com/sirupsen/logrus"
)

func messageLoop() {
	for {
		log.Info("Waiting for message...")

		m := <-messages

		log.WithFields(log.Fields{
			"message":     m.Content,
			"channel_key": m.Key(),
		}).Info("Dispatching message to user")

		for _, client := range clients[m.Key()] {
			err := client.c.WriteJSON(response{
				Name:     "MESSAGE",
				Contents: m,
			})

			if err != nil {
				sentry.CaptureError(err, nil)

				log.WithFields(log.Fields{
					"error": err,
				}).Info("Couldnt send error")
			}
		}
	}
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool { return true },
}

func dispatchHandler(w http.ResponseWriter, r *http.Request, t *jwt.Token) {
	u, err := models.FetchUser("id", t.Claims["id"])
	if err != nil {
		log.WithFields(log.Fields{
			"id": t.Claims["id"],
		}).Info("Could not get user with ID")
		return
	}

	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		sentry.CaptureError(err, nil)
		return
	}

	defer c.Close()

	server := r.FormValue("server")
	if server == "" {
		server = "chat.freenode.net:6667"
	}

	resp, err := pool.Tell("exists", u.ID)
	if err != nil {
		sentry.CaptureError(err, nil)
		return
	}

	if !resp.MustBool() {
		log.Info("Creating zombie")
		add := zombies.Add{
			ID:     u.ID,
			Nick:   u.Username,
			Server: server,
		}

		_, err := pool.Tell("add", add)
		if err != nil {
			log.Error("error creating:", err)
			sentry.CaptureError(err, nil)
			return
		}
	}

	for {
		var a action
		err := c.ReadJSON(&a)
		if err != nil {
			log.Warn("Closing connection. Error reading:", err)
			return
		}

		if a.Name == "SET" {
			err = handleJoin(a, u, c)
		} else if a.Name == "SEND" {
			err = handleSend(a, u, c)
		} else if a.Name == "CHANNELS" {
			err = handleChannels(a, u, c)
		}

		if err != nil {
			sentry.CaptureError(err, nil)
		}
	}
}

func handleJoin(a action, u models.User, c *websocket.Conn) error {
	log.WithFields(log.Fields{
		"channel_key": a.Message,
	}).Info("Adding user to chanel")

	_, err := pool.Tell("join", zombies.Join{
		ID:      u.ID,
		Channel: a.Message,
	})

	if err != nil {
		log.Warn("Closing connection. Error joining chanel:", err)
		return err
	}

	clients[a.Message] = append(clients[a.Message], &conn{
		c:  c,
		id: u.ID,
	})

	return nil
}

func handleSend(a action, u models.User, c *websocket.Conn) error {
	log.WithFields(log.Fields{
		"message":     a.Message,
		"channel_key": a.Channel,
	}).Info("Going to send message to IRC")

	_, err := pool.Tell("send", zombies.Send{
		ID:      u.ID,
		Channel: a.Channel,
		Message: a.Message,
	})

	if err != nil {
		log.Info("Closing connection. Error sending message:", err)
		return err
	}

	log.WithFields(log.Fields{
		"channel_key": a.Channel,
		"message":     a.Message,
	}).Info("Sent message")

	return nil
}

func handleChannels(a action, u models.User, c *websocket.Conn) error {
	log.Info("Sending channels to user")
	resp, err := pool.Tell("channels", u.ID)
	if err != nil {
		log.Warn("Closing connection. Could not connect to kite: ", err)
		return err
	}

	var channels zombies.Channels
	resp.MustUnmarshal(&channels)

	for _, channel := range channels.Channels {
		key := a.Message + "/" + channel
		log.Info("Joining channel", key)

		add := true
		for _, client := range clients[key] {
			if client.c == c {
				add = false
				break
			}
		}

		if add {
			clients[key] = append(clients[key], &conn{
				c:  c,
				id: u.ID,
			})
		}
	}

	err = c.WriteJSON(response{
		Contents: channels.Channels,
		Name:     "CHANNELS",
	})

	if err != nil {
		log.Warn("Could not write JSON", err)
		return err
	}

	return nil
}

type action struct {
	Name    string `json:"name"`
	Message string `json:"message"`
	Channel string `json:"channel"`
}

type conn struct {
	id int64
	c  *websocket.Conn
}

type response struct {
	Name     string      `json:"name"`
	Contents interface{} `json:"contents"`
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package run

import (
	"errors"
	"fmt"
	"io"
	"sort"

	"github.com/tsavola/wag/sections"
	"github.com/tsavola/wag/types"
)

type callSite struct {
	index       uint64
	stackOffset int
}

func findCaller(funcMap []byte, retAddr uint32) (num int, initial, ok bool) {
	count := len(funcMap) / 4
	if count == 0 {
		return
	}

	firstFuncAddr := endian.Uint32(funcMap[:4])
	if retAddr > 0 && retAddr < firstFuncAddr {
		initial = true
		ok = true
		return
	}

	num = sort.Search(count, func(i int) bool {
		i++
		if i == count {
			return true
		} else {
			return retAddr <= endian.Uint32(funcMap[i*4:(i+1)*4])
		}
	})

	if num < count {
		ok = true
	}
	return
}

func getCallSites(callMap []byte) (callSites map[int]callSite) {
	callSites = make(map[int]callSite)

	for i := 0; len(callMap) > 0; i++ {
		entry := endian.Uint64(callMap[:8])
		callMap = callMap[8:]

		addr := int(uint32(entry))
		stackOffset := int(entry >> 32)

		callSites[addr] = callSite{uint64(i), stackOffset}
	}

	return
}

func writeStacktraceTo(w io.Writer, textAddr uint64, stack, funcMap, callMap []byte, funcSigs []types.Function, ns *sections.NameSection,
) (err error) {
	stack = stack[signalStackReserve:]

	unused := endian.Uint64(stack)
	if unused == 0 {
		err = errors.New("no stack")
		return
	}
	if unused > uint64(len(stack)) || (unused&7) != 0 {
		err = errors.New("corrupted stack")
		return
	}
	stack = stack[unused:]

	callSites := getCallSites(callMap)

	depth := 1

	for ; len(stack) > 0; depth++ {
		absoluteRetAddr := endian.Uint64(stack[:8])

		retAddr := absoluteRetAddr - textAddr
		if retAddr > 0x7ffffffe {
			fmt.Fprintf(w, "#%d  <absolute return address 0x%x is not in text section>\n", depth, absoluteRetAddr)
			return
		}

		funcNum, start, ok := findCaller(funcMap, uint32(retAddr))
		if !ok {
			fmt.Fprintf(w, "#%d  <function not found for return address 0x%x>\n", depth, retAddr)
			return
		}

		site, found := callSites[int(retAddr)]
		if !found {
			fmt.Fprintf(w, "#%d  <unknown return address 0x%x>\n", depth, retAddr)
			return
		}

		if start {
			if site.stackOffset != 0 {
				fmt.Fprintf(w, "#%d  <start function call site stack offset is not zero>\n", depth)
			}
			if len(stack) != 8 {
				fmt.Fprintf(w, "#%d  <start function return address is not stored at start of stack>\n", depth)
			}
			return
		}

		if site.stackOffset < 8 || (site.stackOffset&7) != 0 {
			fmt.Fprintf(w, "#%d  <invalid stack offset %d>\n", depth, site.stackOffset)
			return
		}

		stack = stack[site.stackOffset:]

		var name string
		var localNames []string

		if ns != nil && funcNum < len(ns.FunctionNames) {
			name = ns.FunctionNames[funcNum].FunName
			localNames = ns.FunctionNames[funcNum].LocalNames
		} else {
			name = fmt.Sprintf("func-%d", funcNum)
		}

		var sigStr string

		if funcNum < len(funcSigs) {
			sigStr = funcSigs[funcNum].StringWithNames(localNames)
		}

		fmt.Fprintf(w, "#%d  %s%s\n", depth, name, sigStr)
	}

	if len(stack) != 0 {
		fmt.Fprintf(w, "#%d  <%d bytes of untraced stack>\n", depth, len(stack))
	}
	return
}
<commit_msg>run: demangle C++ symbols in stacktrace<commit_after>// Copyright (c) 2016 Timo Savola. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package run

import (
	"errors"
	"fmt"
	"io"
	"sort"

	"github.com/ianlancetaylor/demangle"
	"github.com/tsavola/wag/sections"
	"github.com/tsavola/wag/types"
)

type callSite struct {
	index       uint64
	stackOffset int
}

func findCaller(funcMap []byte, retAddr uint32) (num int, initial, ok bool) {
	count := len(funcMap) / 4
	if count == 0 {
		return
	}

	firstFuncAddr := endian.Uint32(funcMap[:4])
	if retAddr > 0 && retAddr < firstFuncAddr {
		initial = true
		ok = true
		return
	}

	num = sort.Search(count, func(i int) bool {
		i++
		if i == count {
			return true
		} else {
			return retAddr <= endian.Uint32(funcMap[i*4:(i+1)*4])
		}
	})

	if num < count {
		ok = true
	}
	return
}

func getCallSites(callMap []byte) (callSites map[int]callSite) {
	callSites = make(map[int]callSite)

	for i := 0; len(callMap) > 0; i++ {
		entry := endian.Uint64(callMap[:8])
		callMap = callMap[8:]

		addr := int(uint32(entry))
		stackOffset := int(entry >> 32)

		callSites[addr] = callSite{uint64(i), stackOffset}
	}

	return
}

func writeStacktraceTo(w io.Writer, textAddr uint64, stack, funcMap, callMap []byte, funcSigs []types.Function, ns *sections.NameSection,
) (err error) {
	stack = stack[signalStackReserve:]

	unused := endian.Uint64(stack)
	if unused == 0 {
		err = errors.New("no stack")
		return
	}
	if unused > uint64(len(stack)) || (unused&7) != 0 {
		err = errors.New("corrupted stack")
		return
	}
	stack = stack[unused:]

	callSites := getCallSites(callMap)

	depth := 1

	for ; len(stack) > 0; depth++ {
		absoluteRetAddr := endian.Uint64(stack[:8])

		retAddr := absoluteRetAddr - textAddr
		if retAddr > 0x7ffffffe {
			fmt.Fprintf(w, "#%d  <absolute return address 0x%x is not in text section>\n", depth, absoluteRetAddr)
			return
		}

		funcNum, start, ok := findCaller(funcMap, uint32(retAddr))
		if !ok {
			fmt.Fprintf(w, "#%d  <function not found for return address 0x%x>\n", depth, retAddr)
			return
		}

		site, found := callSites[int(retAddr)]
		if !found {
			fmt.Fprintf(w, "#%d  <unknown return address 0x%x>\n", depth, retAddr)
			return
		}

		if start {
			if site.stackOffset != 0 {
				fmt.Fprintf(w, "#%d  <start function call site stack offset is not zero>\n", depth)
			}
			if len(stack) != 8 {
				fmt.Fprintf(w, "#%d  <start function return address is not stored at start of stack>\n", depth)
			}
			return
		}

		if site.stackOffset < 8 || (site.stackOffset&7) != 0 {
			fmt.Fprintf(w, "#%d  <invalid stack offset %d>\n", depth, site.stackOffset)
			return
		}

		stack = stack[site.stackOffset:]

		var name string
		var localNames []string

		if ns != nil && funcNum < len(ns.FunctionNames) {
			name = ns.FunctionNames[funcNum].FunName
			localNames = ns.FunctionNames[funcNum].LocalNames
		} else {
			name = fmt.Sprintf("func-%d", funcNum)
		}

		var sigStr string

		if funcNum < len(funcSigs) {
			sigStr = funcSigs[funcNum].StringWithNames(localNames)
		}

		prettyName, err := demangle.ToString(name)
		if err != nil {
			prettyName = name
		}

		fmt.Fprintf(w, "#%d  %s%s\n", depth, prettyName, sigStr)
	}

	if len(stack) != 0 {
		fmt.Fprintf(w, "#%d  <%d bytes of untraced stack>\n", depth, len(stack))
	}
	return
}
<|endoftext|>


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

package commands

import (
	"strings"

	"fmt"

	"github.com/amalgam8/amalgam8/cli/common"
	"github.com/amalgam8/amalgam8/cli/terminal"
	"github.com/amalgam8/amalgam8/cli/utils"
	ctrl "github.com/amalgam8/amalgam8/controller/client"
	"github.com/amalgam8/amalgam8/pkg/api"
	reg "github.com/amalgam8/amalgam8/registry/client"
	"github.com/urfave/cli"
)

// TrafficStartCommand is used for the route-list command.
type TrafficStartCommand struct {
	ctx        *cli.Context
	registry   *reg.Client
	controller *ctrl.Client
	term       terminal.UI
}

// NewTrafficStartCommand constructs a new TrafficStart.
func NewTrafficStartCommand(term terminal.UI) (cmd *TrafficStartCommand) {
	return &TrafficStartCommand{
		term: term,
	}
}

// GetMetadata returns the metadata.
func (cmd *TrafficStartCommand) GetMetadata() cli.Command {
	T := utils.Language(common.DefaultLanguage)
	return cli.Command{
		Name:        "traffic-start",
		Description: T("traffic_start_description"),
		Usage:       T("traffic_start_usage"),
		// TODO: Complete UsageText
		UsageText: T("traffic_start_usage"),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "service, s",
				Usage: T("traffic_start_service_usage"),
				Value: "",
			},
			cli.StringFlag{
				Name:  "version, v",
				Usage: T("traffic_start_version_usage"),
				Value: "",
			},
			cli.IntFlag{
				Name:  "amount, a",
				Usage: T("traffic_start_amount_usage"),
			},
		},
		Before:       cmd.Before,
		OnUsageError: cmd.OnUsageError,
		Action:       cmd.Action,
	}
}

// Before runs before the Action
// https://godoc.org/github.com/urfave/cli#BeforeFunc
func (cmd *TrafficStartCommand) Before(ctx *cli.Context) error {
	// Update the context
	cmd.ctx = ctx
	return nil
}

// OnUsageError is executed if an usage error occurs.
func (cmd *TrafficStartCommand) OnUsageError(ctx *cli.Context, err error, isSubcommand bool) error {
	cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
	return nil
}

// Action runs when no subcommands are specified
// https://godoc.org/github.com/urfave/cli#ActionFunc
func (cmd *TrafficStartCommand) Action(ctx *cli.Context) error {
	registry, err := NewRegistry(ctx)
	if err != nil {
		// Exit if the registry returned an error
		return nil
	}
	// Update the registry
	cmd.registry = registry

	controller, err := NewController(ctx)
	if err != nil {
		// Exit if the controller returned an error
		return nil
	}
	// Update the controller
	cmd.controller = controller

	if ctx.IsSet("service") && ctx.IsSet("version") {
		if ctx.Int("amount") < 0 || ctx.Int("amount") > 100 {
			fmt.Fprintf(ctx.App.Writer, "%s\n\n", common.ErrIncorrectAmountRange.Error())
			return nil
		}

		return cmd.StartTraffic(ctx.String("service"), ctx.String("version"), ctx.Int("amount"))

	}

	if ctx.NArg() > 0 {
		cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
		return nil
	}

	return cmd.DefaultAction(ctx)
}

// StartTraffic .
func (cmd *TrafficStartCommand) StartTraffic(serviceName string, version string, amount int) error {

	filter := &api.RuleFilter{
		Destinations: []string{serviceName},
	}
	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	routingRules := routes.Services[serviceName]
	if len(routingRules) == 0 {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: %q\n\n", common.ErrNotRulesFoundForService.Error(), serviceName)
		return nil
	}

	for _, rule := range routingRules {
		if len(rule.Route.Backends) > 1 {
			fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q traffic is already being split\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
			return nil
		}
	}

	rule := routingRules[0]
	for _, backend := range rule.Route.Backends {
		if backend.Weight != 0 {
			fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q traffic is already being split\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
			return nil
		}
	}

	defaultVersion := strings.Join(rule.Route.Backends[0].Tags, ", ")

	instances, err := cmd.registry.ListServiceInstances(serviceName)
	if err != nil {
		return err
	}

	if !cmd.IsServiceActive(serviceName, defaultVersion, instances) {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q is not currently receiving traffic\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
		return nil
	}

	if !cmd.IsServiceActive(serviceName, version, instances) {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q does not have active instances of version %q\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName, version)
		return nil
	}

	if amount == 100 {
		rule.Route.Backends[0].Tags = []string{version}
	} else {
		if amount == 0 {
			amount += 10
		}

		rule.Route.Backends = append([]api.Backend{api.Backend{
			Tags:   []string{version},
			Weight: float64(amount) / 100,
		}}, rule.Route.Backends...)
	}

	rulesSet := &api.RulesSet{
		Rules: []api.Rule{
			rule,
		},
	}

	_, err = cmd.controller.UpdateRules(rulesSet)
	if err != nil {
		return err
	}

	if amount == 100 {
		fmt.Fprintf(cmd.ctx.App.Writer, "Transfer complete for %q: sending %d%% of traffic to %q\n\n", serviceName, amount, version)
		return nil
	}

	fmt.Fprintf(cmd.ctx.App.Writer, "Transfer starting for %q: diverting %d%% of traffic from %q to %q\n\n", serviceName, amount, defaultVersion, version)
	return nil
}

// IsServiceActive .
func (cmd *TrafficStartCommand) IsServiceActive(serviceName, version string, instances []*api.ServiceInstance) bool {
	for _, instance := range instances {
		if version == strings.Join(instance.Tags, ", ") {
			return true
		}
	}
	return false
}

// DefaultAction runs the default action.
func (cmd *TrafficStartCommand) DefaultAction(ctx *cli.Context) error {
	return cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
}
<commit_msg>bug fix: subset matching for tags if instances has more than one<commit_after>// Copyright 2016 IBM Corporation
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package commands

import (
	"strings"

	"fmt"

	"github.com/amalgam8/amalgam8/cli/common"
	"github.com/amalgam8/amalgam8/cli/terminal"
	"github.com/amalgam8/amalgam8/cli/utils"
	ctrl "github.com/amalgam8/amalgam8/controller/client"
	"github.com/amalgam8/amalgam8/pkg/api"
	reg "github.com/amalgam8/amalgam8/registry/client"
	"github.com/urfave/cli"
)

// TrafficStartCommand is used for the route-list command.
type TrafficStartCommand struct {
	ctx        *cli.Context
	registry   *reg.Client
	controller *ctrl.Client
	term       terminal.UI
}

// NewTrafficStartCommand constructs a new TrafficStart.
func NewTrafficStartCommand(term terminal.UI) (cmd *TrafficStartCommand) {
	return &TrafficStartCommand{
		term: term,
	}
}

// GetMetadata returns the metadata.
func (cmd *TrafficStartCommand) GetMetadata() cli.Command {
	T := utils.Language(common.DefaultLanguage)
	return cli.Command{
		Name:        "traffic-start",
		Description: T("traffic_start_description"),
		Usage:       T("traffic_start_usage"),
		// TODO: Complete UsageText
		UsageText: T("traffic_start_usage"),
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "service, s",
				Usage: T("traffic_start_service_usage"),
				Value: "",
			},
			cli.StringFlag{
				Name:  "version, v",
				Usage: T("traffic_start_version_usage"),
				Value: "",
			},
			cli.IntFlag{
				Name:  "amount, a",
				Usage: T("traffic_start_amount_usage"),
			},
		},
		Before:       cmd.Before,
		OnUsageError: cmd.OnUsageError,
		Action:       cmd.Action,
	}
}

// Before runs before the Action
// https://godoc.org/github.com/urfave/cli#BeforeFunc
func (cmd *TrafficStartCommand) Before(ctx *cli.Context) error {
	// Update the context
	cmd.ctx = ctx
	return nil
}

// OnUsageError is executed if an usage error occurs.
func (cmd *TrafficStartCommand) OnUsageError(ctx *cli.Context, err error, isSubcommand bool) error {
	cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
	return nil
}

// Action runs when no subcommands are specified
// https://godoc.org/github.com/urfave/cli#ActionFunc
func (cmd *TrafficStartCommand) Action(ctx *cli.Context) error {
	registry, err := NewRegistry(ctx)
	if err != nil {
		// Exit if the registry returned an error
		return nil
	}
	// Update the registry
	cmd.registry = registry

	controller, err := NewController(ctx)
	if err != nil {
		// Exit if the controller returned an error
		return nil
	}
	// Update the controller
	cmd.controller = controller

	if ctx.IsSet("service") && ctx.IsSet("version") {
		if ctx.Int("amount") < 0 || ctx.Int("amount") > 100 {
			fmt.Fprintf(ctx.App.Writer, "%s\n\n", common.ErrIncorrectAmountRange.Error())
			return nil
		}

		return cmd.StartTraffic(ctx.String("service"), ctx.String("version"), ctx.Int("amount"))

	}

	if ctx.NArg() > 0 {
		cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
		return nil
	}

	return cmd.DefaultAction(ctx)
}

// StartTraffic .
func (cmd *TrafficStartCommand) StartTraffic(serviceName string, version string, amount int) error {

	filter := &api.RuleFilter{
		Destinations: []string{serviceName},
	}
	routes, err := cmd.controller.ListRoutes(filter)
	if err != nil {
		return err
	}

	routingRules := routes.Services[serviceName]
	if len(routingRules) == 0 {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: %q\n\n", common.ErrNotRulesFoundForService.Error(), serviceName)
		return nil
	}

	for _, rule := range routingRules {
		if len(rule.Route.Backends) > 1 {
			fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q traffic is already being split\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
			return nil
		}
	}

	rule := routingRules[0]
	for _, backend := range rule.Route.Backends {
		if backend.Weight != 0 {
			fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q traffic is already being split\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
			return nil
		}
	}

	defaultVersion := strings.Join(rule.Route.Backends[0].Tags, ", ")

	instances, err := cmd.registry.ListServiceInstances(serviceName)
	if err != nil {
		return err
	}

	if !cmd.IsServiceActive(serviceName, defaultVersion, instances) {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q is not currently receiving traffic\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName)
		return nil
	}

	if !cmd.IsServiceActive(serviceName, version, instances) {
		fmt.Fprintf(cmd.ctx.App.Writer, "%s: service %q does not have active instances of version %q\n\n", common.ErrInvalidStateForTrafficStart.Error(), serviceName, version)
		return nil
	}

	if amount == 100 {
		rule.Route.Backends[0].Tags = []string{version}
	} else {
		if amount == 0 {
			amount += 10
		}

		rule.Route.Backends = append([]api.Backend{api.Backend{
			Tags:   []string{version},
			Weight: float64(amount) / 100,
		}}, rule.Route.Backends...)
	}

	rulesSet := &api.RulesSet{
		Rules: []api.Rule{
			rule,
		},
	}

	_, err = cmd.controller.UpdateRules(rulesSet)
	if err != nil {
		return err
	}

	if amount == 100 {
		fmt.Fprintf(cmd.ctx.App.Writer, "Transfer complete for %q: sending %d%% of traffic to %q\n\n", serviceName, amount, version)
		return nil
	}

	fmt.Fprintf(cmd.ctx.App.Writer, "Transfer starting for %q: diverting %d%% of traffic from %q to %q\n\n", serviceName, amount, defaultVersion, version)
	return nil
}

// IsServiceActive .
func (cmd *TrafficStartCommand) IsServiceActive(serviceName, version string, instances []*api.ServiceInstance) bool {
	for _, instance := range instances {
		for _, tag := range instance.Tags {
			if version == tag {
				return true
			}
		}
	}
	return false
}

// DefaultAction runs the default action.
func (cmd *TrafficStartCommand) DefaultAction(ctx *cli.Context) error {
	return cli.ShowCommandHelp(ctx, cmd.GetMetadata().FullName())
}
<|endoftext|>


<commit_before>package beat

import (
	"bytes"
	"github.com/christiangalsterer/execbeat/config"
	"github.com/elastic/beats/libbeat/logp"
	"github.com/robfig/cron"
	"os/exec"
	"strings"
	"time"
)

type Executor struct {
	execbeat *Execbeat
	config   config.ExecConfig
	schedule string
	documentType string
}

func NewExecutor(execbeat *Execbeat, config config.ExecConfig) *Executor {
	executor := &Executor{
		execbeat: execbeat,
		config:   config,
	}

	return executor
}

func (e *Executor) Run() {

	// setup default config
	e.documentType = config.DefaultDocumentType
	e.schedule = config.DefaultSchedule

	// setup DocumentType
	if e.config.DocumentType != "" {
		e.documentType = e.config.DocumentType
	}

	// setup cron schedule
	if e.config.Schedule != "" {
		logp.Debug("Execbeat", "Use schedule: [%w]", e.config.Schedule)
		e.schedule = e.config.Schedule
	}

	cron := cron.New()
	cron.AddFunc(e.schedule, func() { e.runOneTime() })
	cron.Start()
}

func (e *Executor) runOneTime() error {
	var cmd *exec.Cmd
	var err error
	var stdout bytes.Buffer
	var stderr bytes.Buffer

	cmdName := strings.TrimSpace(e.config.Command)
	cmdArgs := strings.TrimSpace(e.config.Args)

	// execute command
	logp.Debug("Execbeat", "Executing command: [%v] with args [%w]", cmdName, cmdArgs)
	now := time.Now()

	if len(cmdArgs) > 0 {
		cmd = exec.Command(cmdName, cmdArgs)
	} else {
		cmd = exec.Command(cmdName)
	}
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err = cmd.Start()
	if err != nil {
		logp.Err("An error occured while executing command: %v", err)
	}

	err = cmd.Wait()
	if err != nil {
		logp.Err("An error occured while executing command: %v", err)
	}

	commandEvent := Exec{
		Command: cmdName,
		StdOut:  stdout.String(),
		StdErr:  stderr.String(),
	}

	event := ExecEvent{
		ReadTime:     now,
		DocumentType: e.documentType,
		Fields:       e.config.Fields,
		Exec:         commandEvent,
	}

	e.execbeat.client.PublishEvent(event.ToMapStr())

	return nil
}

func (e *Executor) Stop() {
}
<commit_msg>- Refactoring for default configuration<commit_after>package beat

import (
	"bytes"
	"github.com/christiangalsterer/execbeat/config"
	"github.com/elastic/beats/libbeat/logp"
	"github.com/robfig/cron"
	"os/exec"
	"strings"
	"time"
)

type Executor struct {
	execbeat     *Execbeat
	config       config.ExecConfig
	schedule     string
	documentType string
}

func NewExecutor(execbeat *Execbeat, config config.ExecConfig) *Executor {
	executor := &Executor{
		execbeat: execbeat,
		config:   config,
	}

	return executor
}

func (e *Executor) Run() {

	// setup default config
	e.documentType = config.DefaultDocumentType
	e.schedule = config.DefaultSchedule

	// setup document type
	if e.config.DocumentType != "" {
		e.documentType = e.config.DocumentType
	}

	// setup cron schedule
	if e.config.Schedule != "" {
		logp.Debug("Execbeat", "Use schedule: [%w]", e.config.Schedule)
		e.schedule = e.config.Schedule
	}

	cron := cron.New()
	cron.AddFunc(e.schedule, func() { e.runOneTime() })
	cron.Start()
}

func (e *Executor) runOneTime() error {
	var cmd *exec.Cmd
	var err error
	var stdout bytes.Buffer
	var stderr bytes.Buffer

	cmdName := strings.TrimSpace(e.config.Command)
	cmdArgs := strings.TrimSpace(e.config.Args)

	// execute command
	logp.Debug("Execbeat", "Executing command: [%v] with args [%w]", cmdName, cmdArgs)
	now := time.Now()

	if len(cmdArgs) > 0 {
		cmd = exec.Command(cmdName, cmdArgs)
	} else {
		cmd = exec.Command(cmdName)
	}
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr

	err = cmd.Start()
	if err != nil {
		logp.Err("An error occured while executing command: %v", err)
	}

	err = cmd.Wait()
	if err != nil {
		logp.Err("An error occured while executing command: %v", err)
	}

	commandEvent := Exec{
		Command: cmdName,
		StdOut:  stdout.String(),
		StdErr:  stderr.String(),
	}

	event := ExecEvent{
		ReadTime:     now,
		DocumentType: e.documentType,
		Fields:       e.config.Fields,
		Exec:         commandEvent,
	}

	e.execbeat.client.PublishEvent(event.ToMapStr())

	return nil
}

func (e *Executor) Stop() {
}
<|endoftext|>


<commit_before>package assert

type AnyTypeAssert interface {
	IsEqualTo(expected interface{}) AnyTypeAssert
}
<commit_msg>some ideas for any type assertions<commit_after>package assert

type AnyTypeAssert interface {
	IsEqualTo(expected interface{}) AnyTypeAssert
	// TODO
	// IsNotEqualTo(unexpected interface{}) AnyTypeAssert
	// IsNil() AnyTypeAssert
	// IsNotNil() AnyTypeAssert
	// AsInt() IntAssert // new assert that treats actual value as int, reports failure if cannot convert
	// AsString() StringAssert
}
<|endoftext|>