<commit_before>/*
Config loads and understand the tegola config format.
*/
package config

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
)

type ErrMapNotFound struct {
	MapName string
}

func (e ErrMapNotFound) Error() string {
	return fmt.Sprintf("config: map (%v) not found", e.MapName)
}

type ErrInvalidProviderLayerName struct {
	ProviderLayerName string
}

func (e ErrInvalidProviderLayerName) Error() string {
	return fmt.Sprintf("config: invalid provider layer name (%v)", e.ProviderLayerName)
}

type ErrLayerCollision struct {
	ProviderLayer1 string
	ProviderLayer2 string
}

func (e ErrLayerCollision) Error() string {
	return fmt.Sprintf("config: layer collision (%v) and (%v)", e.ProviderLayer1, e.ProviderLayer2)
}

// A Config represents the a Tegola Config file.
type Config struct {
	// LocationName is the file name or http server that the config was read from. If this is "", it means that the location was unknown. This is the case if the Prase() function is used
	// directly.
	LocationName string
	Webserver    Webserver `webserver`
	// Map of providers.
	Providers []map[string]interface{}
	Maps      []Map
}

type Webserver struct {
	Port      string `toml:"port"`
	LogFile   string `toml:"log_file"`
	LogFormat string `toml:"log_format"`
}

// A Map represents a map in the Tegola Config file.
type Map struct {
	Name        string     `toml:"name"`
	Attribution string     `toml:"attribution"`
	Bounds      []float64  `toml:"bounds"`
	Center      [3]float64 `toml:"center"`
	Layers      []MapLayer `toml:"layers"`
}

type MapLayer struct {
	ProviderLayer string      `toml:"provider_layer"`
	MinZoom       int         `toml:"min_zoom"`
	MaxZoom       int         `toml:"max_zoom"`
	DefaultTags   interface{} `toml:"default_tags"`
}

//	checks the config for issues
func (c *Config) Validate() error {

	//	check for map layer name / zoom collisions
	//	map of layers to providers
	layerNames := map[string]MapLayer{}
	for _, m := range c.Maps {
		for _, l := range m.Layers {
			//	split the provider layer (syntax is provider.layer)
			plParts := strings.Split(l.ProviderLayer, ".")
			if len(plParts) != 2 {
				return ErrInvalidProviderLayerName{
					ProviderLayerName: l.ProviderLayer,
				}
			}

			//	check if already have this layer
			val, ok := layerNames[plParts[1]]
			if ok {
				//	we have a hit
				//	check for zoom range overlap
				if val.MinZoom <= l.MaxZoom && l.MinZoom <= val.MaxZoom {
					return ErrLayerCollision{
						ProviderLayer1: val.ProviderLayer,
						ProviderLayer2: l.ProviderLayer,
					}
				}
			} else {
				//	add the MapLayer to our map
				layerNames[plParts[1]] = l
			}
		}
	}

	return nil
}

// Parse will parse the Tegola config file provided by the io.Reader.
func Parse(reader io.Reader, location string) (conf Config, err error) {
	//	decode conf file, don't care about the meta data.
	_, err = toml.DecodeReader(reader, &conf)
	conf.LocationName = location

	return conf, err
}

// Load will load and parse the config file from the given location.
func Load(location string) (conf Config, err error) {
	var reader io.Reader

	//	check for http prefix
	if strings.HasPrefix(location, "http") {
		log.Printf("Loading remote config (%v)", location)

		//	setup http client with a timeout
		var httpClient = &http.Client{
			Timeout: time.Second * 10,
		}

		//	make the http request
		res, err := httpClient.Get(location)
		if err != nil {
			return conf, fmt.Errorf("error fetching remote config file (%v): %v ", location, err)
		}

		//	set the reader to the response body
		reader = res.Body
	} else {
		log.Printf("Loading local config (%v)", location)

		//	check the conf file exists
		if _, err := os.Stat(location); os.IsNotExist(err) {
			return conf, fmt.Errorf("config file at location (%v) not found!", location)
		}
		//	open the confi file
		reader, err = os.Open(location)
		if err != nil {
			return conf, fmt.Errorf("error opening local config file (%v): %v ", location, err)
		}
	}

	return Parse(reader, location)
}

// FindMap will find the map with the provided name. If "" is used for the name, it will return the first
// Map in the config, if one is defined.
// If a map with the name is not found it will return ErrMapNotFound error.
func (cfg *Config) FindMap(name string) (Map, error) {
	if name == "" && len(cfg.Maps) > 0 {
		return cfg.Maps[0], nil
	}

	for _, m := range cfg.Maps {
		if m.Name == name {
			return m, nil
		}
	}

	return Map{}, ErrMapNotFound{
		MapName: name,
	}
}
<commit_msg>fixed toml struct tags for config. cleaned up layer checking logic. closes #81<commit_after>/*
Config loads and understand the tegola config format.
*/
package config

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
)

type ErrMapNotFound struct {
	MapName string
}

func (e ErrMapNotFound) Error() string {
	return fmt.Sprintf("config: map (%v) not found", e.MapName)
}

type ErrInvalidProviderLayerName struct {
	ProviderLayerName string
}

func (e ErrInvalidProviderLayerName) Error() string {
	return fmt.Sprintf("config: invalid provider layer name (%v)", e.ProviderLayerName)
}

type ErrLayerCollision struct {
	ProviderLayer1 string
	ProviderLayer2 string
}

func (e ErrLayerCollision) Error() string {
	return fmt.Sprintf("config: layer collision (%v) and (%v)", e.ProviderLayer1, e.ProviderLayer2)
}

// A Config represents the a Tegola Config file.
type Config struct {
	// LocationName is the file name or http server that the config was read from. If this is "", it means that the location was unknown. This is the case if the Prase() function is used
	// directly.
	LocationName string
	Webserver    Webserver `toml:"webserver"`
	// Map of providers.
	Providers []map[string]interface{}
	Maps      []Map
}

type Webserver struct {
	Port      string `toml:"port"`
	LogFile   string `toml:"log_file"`
	LogFormat string `toml:"log_format"`
}

// A Map represents a map in the Tegola Config file.
type Map struct {
	Name        string     `toml:"name"`
	Attribution string     `toml:"attribution"`
	Bounds      []float64  `toml:"bounds"`
	Center      [3]float64 `toml:"center"`
	Layers      []MapLayer `toml:"layers"`
}

type MapLayer struct {
	ProviderLayer string      `toml:"provider_layer"`
	MinZoom       int         `toml:"min_zoom"`
	MaxZoom       int         `toml:"max_zoom"`
	DefaultTags   interface{} `toml:"default_tags"`
}

//	checks the config for issues
func (c *Config) Validate() error {

	//	check for map layer name / zoom collisions
	//	map of layers to providers
	layerNames := map[string]MapLayer{}
	for _, m := range c.Maps {
		for _, l := range m.Layers {
			//	split the provider layer (syntax is provider.layer)
			plParts := strings.Split(l.ProviderLayer, ".")
			if len(plParts) != 2 {
				return ErrInvalidProviderLayerName{
					ProviderLayerName: l.ProviderLayer,
				}
			}

			//	check if already have this layer
			if val, ok := layerNames[plParts[1]]; ok {
				//	we have a hit
				//	check for zoom range overlap
				if val.MinZoom <= l.MaxZoom && l.MinZoom <= val.MaxZoom {
					return ErrLayerCollision{
						ProviderLayer1: val.ProviderLayer,
						ProviderLayer2: l.ProviderLayer,
					}
				}
				continue
			}

			//	add the MapLayer to our map
			layerNames[plParts[1]] = l
		}
	}

	return nil
}

// Parse will parse the Tegola config file provided by the io.Reader.
func Parse(reader io.Reader, location string) (conf Config, err error) {
	//	decode conf file, don't care about the meta data.
	_, err = toml.DecodeReader(reader, &conf)
	conf.LocationName = location

	return conf, err
}

// Load will load and parse the config file from the given location.
func Load(location string) (conf Config, err error) {
	var reader io.Reader

	//	check for http prefix
	if strings.HasPrefix(location, "http") {
		log.Printf("Loading remote config (%v)", location)

		//	setup http client with a timeout
		var httpClient = &http.Client{
			Timeout: time.Second * 10,
		}

		//	make the http request
		res, err := httpClient.Get(location)
		if err != nil {
			return conf, fmt.Errorf("error fetching remote config file (%v): %v ", location, err)
		}

		//	set the reader to the response body
		reader = res.Body
	} else {
		log.Printf("Loading local config (%v)", location)

		//	check the conf file exists
		if _, err := os.Stat(location); os.IsNotExist(err) {
			return conf, fmt.Errorf("config file at location (%v) not found!", location)
		}
		//	open the confi file
		reader, err = os.Open(location)
		if err != nil {
			return conf, fmt.Errorf("error opening local config file (%v): %v ", location, err)
		}
	}

	return Parse(reader, location)
}

// FindMap will find the map with the provided name. If "" is used for the name, it will return the first
// Map in the config, if one is defined.
// If a map with the name is not found it will return ErrMapNotFound error.
func (cfg *Config) FindMap(name string) (Map, error) {
	if name == "" && len(cfg.Maps) > 0 {
		return cfg.Maps[0], nil
	}

	for _, m := range cfg.Maps {
		if m.Name == name {
			return m, nil
		}
	}

	return Map{}, ErrMapNotFound{
		MapName: name,
	}
}
<|endoftext|>


<commit_before>package main

import (
  "github.com/simon-engledew/gocmdpev/gopev"
  "io/ioutil"
  "github.com/fatih/color"
  "log"
  "os"
)

func main() {
  buffer, err := ioutil.ReadAll(os.Stdin)

  if err != nil {
    log.Fatalf("%v", err)
  }

  // fmt.Println(string(buffer))

  err = gopev.Visualize(color.Output, buffer)

  if err != nil {
    log.Fatalf("%v", err)
  }
}
<commit_msg>Use kingpin to add a -v/-h to use as Homebrew's test method<commit_after>package main

import (
  "github.com/simon-engledew/gocmdpev/gopev"
  "gopkg.in/alecthomas/kingpin.v2"
  "io/ioutil"
  "github.com/fatih/color"
  "log"
  "os"
)

func main() {
  kingpin.CommandLine.HelpFlag.Short('h')
  kingpin.CommandLine.Version("1.0.0")
  kingpin.CommandLine.VersionFlag.Short('v')
  kingpin.Parse()

  buffer, err := ioutil.ReadAll(os.Stdin)

  if err != nil {
    log.Fatalf("%v", err)
  }

  // fmt.Println(string(buffer))

  err = gopev.Visualize(color.Output, buffer)

  if err != nil {
    log.Fatalf("%v", err)
  }
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/BurntSushi/toml"
	"golang.org/x/tools/go/analysis"
)

var Analyzer = &analysis.Analyzer{
	Name: "config",
	Doc:  "loads configuration for the current package tree",
	Run: func(pass *analysis.Pass) (interface{}, error) {
		if len(pass.Files) == 0 {
			cfg := DefaultConfig
			return &cfg, nil
		}
		cache, err := os.UserCacheDir()
		if err != nil {
			cache = ""
		}
		var path string
		for _, f := range pass.Files {
			p := pass.Fset.PositionFor(f.Pos(), true).Filename
			// FIXME(dh): using strings.HasPrefix isn't technically
			// correct, but it should be good enough for now.
			if cache != "" && strings.HasPrefix(p, cache) {
				// File in the build cache of the standard Go build system
				continue
			}
			path = p
			break
		}

		if path == "" {
			// The package only consists of generated files.
			cfg := DefaultConfig
			return &cfg, nil
		}

		dir := filepath.Dir(path)
		cfg, err := Load(dir)
		if err != nil {
			return nil, fmt.Errorf("error loading staticcheck.conf: %s", err)
		}
		return &cfg, nil
	},
	RunDespiteErrors: true,
	ResultType:       reflect.TypeOf((*Config)(nil)),
}

func For(pass *analysis.Pass) *Config {
	return pass.ResultOf[Analyzer].(*Config)
}

func mergeLists(a, b []string) []string {
	out := make([]string, 0, len(a)+len(b))
	for _, el := range b {
		if el == "inherit" {
			out = append(out, a...)
		} else {
			out = append(out, el)
		}
	}

	return out
}

func normalizeList(list []string) []string {
	if len(list) > 1 {
		nlist := make([]string, 0, len(list))
		nlist = append(nlist, list[0])
		for i, el := range list[1:] {
			if el != list[i] {
				nlist = append(nlist, el)
			}
		}
		list = nlist
	}

	for _, el := range list {
		if el == "inherit" {
			// This should never happen, because the default config
			// should not use "inherit"
			panic(`unresolved "inherit"`)
		}
	}

	return list
}

func (cfg Config) Merge(ocfg Config) Config {
	if ocfg.Checks != nil {
		cfg.Checks = mergeLists(cfg.Checks, ocfg.Checks)
	}
	if ocfg.Initialisms != nil {
		cfg.Initialisms = mergeLists(cfg.Initialisms, ocfg.Initialisms)
	}
	if ocfg.DotImportWhitelist != nil {
		cfg.DotImportWhitelist = mergeLists(cfg.DotImportWhitelist, ocfg.DotImportWhitelist)
	}
	if ocfg.HTTPStatusCodeWhitelist != nil {
		cfg.HTTPStatusCodeWhitelist = mergeLists(cfg.HTTPStatusCodeWhitelist, ocfg.HTTPStatusCodeWhitelist)
	}
	return cfg
}

type Config struct {
	// TODO(dh): this implementation makes it impossible for external
	// clients to add their own checkers with configuration. At the
	// moment, we don't really care about that; we don't encourage
	// that people use this package. In the future, we may. The
	// obvious solution would be using map[string]interface{}, but
	// that's obviously subpar.

	Checks                  []string `toml:"checks"`
	Initialisms             []string `toml:"initialisms"`
	DotImportWhitelist      []string `toml:"dot_import_whitelist"`
	HTTPStatusCodeWhitelist []string `toml:"http_status_code_whitelist"`
}

var DefaultConfig = Config{
	Checks: []string{"all", "-ST1000", "-ST1003", "-ST1016"},
	Initialisms: []string{
		"ACL", "API", "ASCII", "CPU", "CSS", "DNS",
		"EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID",
		"IP", "JSON", "QPS", "RAM", "RPC", "SLA",
		"SMTP", "SQL", "SSH", "TCP", "TLS", "TTL",
		"UDP", "UI", "GID", "UID", "UUID", "URI",
		"URL", "UTF8", "VM", "XML", "XMPP", "XSRF",
		"XSS", "SIP", "RTP",
	},
	DotImportWhitelist:      []string{},
	HTTPStatusCodeWhitelist: []string{"200", "400", "404", "500"},
}

const configName = "staticcheck.conf"

func parseConfigs(dir string) ([]Config, error) {
	var out []Config

	// TODO(dh): consider stopping at the GOPATH/module boundary
	for dir != "" {
		f, err := os.Open(filepath.Join(dir, configName))
		if os.IsNotExist(err) {
			ndir := filepath.Dir(dir)
			if ndir == dir {
				break
			}
			dir = ndir
			continue
		}
		if err != nil {
			return nil, err
		}
		var cfg Config
		_, err = toml.DecodeReader(f, &cfg)
		f.Close()
		if err != nil {
			return nil, err
		}
		out = append(out, cfg)
		ndir := filepath.Dir(dir)
		if ndir == dir {
			break
		}
		dir = ndir
	}
	out = append(out, DefaultConfig)
	if len(out) < 2 {
		return out, nil
	}
	for i := 0; i < len(out)/2; i++ {
		out[i], out[len(out)-1-i] = out[len(out)-1-i], out[i]
	}
	return out, nil
}

func mergeConfigs(confs []Config) Config {
	if len(confs) == 0 {
		// This shouldn't happen because we always have at least a
		// default config.
		panic("trying to merge zero configs")
	}
	if len(confs) == 1 {
		return confs[0]
	}
	conf := confs[0]
	for _, oconf := range confs[1:] {
		conf = conf.Merge(oconf)
	}
	return conf
}

func Load(dir string) (Config, error) {
	confs, err := parseConfigs(dir)
	if err != nil {
		return Config{}, err
	}
	conf := mergeConfigs(confs)

	conf.Checks = normalizeList(conf.Checks)
	conf.Initialisms = normalizeList(conf.Initialisms)
	conf.DotImportWhitelist = normalizeList(conf.DotImportWhitelist)
	conf.HTTPStatusCodeWhitelist = normalizeList(conf.HTTPStatusCodeWhitelist)

	return conf, nil
}
<commit_msg>config: add more default initialisms<commit_after>package config

import (
	"fmt"
	"os"
	"path/filepath"
	"reflect"
	"strings"

	"github.com/BurntSushi/toml"
	"golang.org/x/tools/go/analysis"
)

var Analyzer = &analysis.Analyzer{
	Name: "config",
	Doc:  "loads configuration for the current package tree",
	Run: func(pass *analysis.Pass) (interface{}, error) {
		if len(pass.Files) == 0 {
			cfg := DefaultConfig
			return &cfg, nil
		}
		cache, err := os.UserCacheDir()
		if err != nil {
			cache = ""
		}
		var path string
		for _, f := range pass.Files {
			p := pass.Fset.PositionFor(f.Pos(), true).Filename
			// FIXME(dh): using strings.HasPrefix isn't technically
			// correct, but it should be good enough for now.
			if cache != "" && strings.HasPrefix(p, cache) {
				// File in the build cache of the standard Go build system
				continue
			}
			path = p
			break
		}

		if path == "" {
			// The package only consists of generated files.
			cfg := DefaultConfig
			return &cfg, nil
		}

		dir := filepath.Dir(path)
		cfg, err := Load(dir)
		if err != nil {
			return nil, fmt.Errorf("error loading staticcheck.conf: %s", err)
		}
		return &cfg, nil
	},
	RunDespiteErrors: true,
	ResultType:       reflect.TypeOf((*Config)(nil)),
}

func For(pass *analysis.Pass) *Config {
	return pass.ResultOf[Analyzer].(*Config)
}

func mergeLists(a, b []string) []string {
	out := make([]string, 0, len(a)+len(b))
	for _, el := range b {
		if el == "inherit" {
			out = append(out, a...)
		} else {
			out = append(out, el)
		}
	}

	return out
}

func normalizeList(list []string) []string {
	if len(list) > 1 {
		nlist := make([]string, 0, len(list))
		nlist = append(nlist, list[0])
		for i, el := range list[1:] {
			if el != list[i] {
				nlist = append(nlist, el)
			}
		}
		list = nlist
	}

	for _, el := range list {
		if el == "inherit" {
			// This should never happen, because the default config
			// should not use "inherit"
			panic(`unresolved "inherit"`)
		}
	}

	return list
}

func (cfg Config) Merge(ocfg Config) Config {
	if ocfg.Checks != nil {
		cfg.Checks = mergeLists(cfg.Checks, ocfg.Checks)
	}
	if ocfg.Initialisms != nil {
		cfg.Initialisms = mergeLists(cfg.Initialisms, ocfg.Initialisms)
	}
	if ocfg.DotImportWhitelist != nil {
		cfg.DotImportWhitelist = mergeLists(cfg.DotImportWhitelist, ocfg.DotImportWhitelist)
	}
	if ocfg.HTTPStatusCodeWhitelist != nil {
		cfg.HTTPStatusCodeWhitelist = mergeLists(cfg.HTTPStatusCodeWhitelist, ocfg.HTTPStatusCodeWhitelist)
	}
	return cfg
}

type Config struct {
	// TODO(dh): this implementation makes it impossible for external
	// clients to add their own checkers with configuration. At the
	// moment, we don't really care about that; we don't encourage
	// that people use this package. In the future, we may. The
	// obvious solution would be using map[string]interface{}, but
	// that's obviously subpar.

	Checks                  []string `toml:"checks"`
	Initialisms             []string `toml:"initialisms"`
	DotImportWhitelist      []string `toml:"dot_import_whitelist"`
	HTTPStatusCodeWhitelist []string `toml:"http_status_code_whitelist"`
}

var DefaultConfig = Config{
	Checks: []string{"all", "-ST1000", "-ST1003", "-ST1016"},
	Initialisms: []string{
		"ACL", "API", "ASCII", "CPU", "CSS", "DNS",
		"EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID",
		"IP", "JSON", "QPS", "RAM", "RPC", "SLA",
		"SMTP", "SQL", "SSH", "TCP", "TLS", "TTL",
		"UDP", "UI", "GID", "UID", "UUID", "URI",
		"URL", "UTF8", "VM", "XML", "XMPP", "XSRF",
		"XSS", "SIP", "RTP", "AMQP", "DB", "TS",
	},
	DotImportWhitelist:      []string{},
	HTTPStatusCodeWhitelist: []string{"200", "400", "404", "500"},
}

const configName = "staticcheck.conf"

func parseConfigs(dir string) ([]Config, error) {
	var out []Config

	// TODO(dh): consider stopping at the GOPATH/module boundary
	for dir != "" {
		f, err := os.Open(filepath.Join(dir, configName))
		if os.IsNotExist(err) {
			ndir := filepath.Dir(dir)
			if ndir == dir {
				break
			}
			dir = ndir
			continue
		}
		if err != nil {
			return nil, err
		}
		var cfg Config
		_, err = toml.DecodeReader(f, &cfg)
		f.Close()
		if err != nil {
			return nil, err
		}
		out = append(out, cfg)
		ndir := filepath.Dir(dir)
		if ndir == dir {
			break
		}
		dir = ndir
	}
	out = append(out, DefaultConfig)
	if len(out) < 2 {
		return out, nil
	}
	for i := 0; i < len(out)/2; i++ {
		out[i], out[len(out)-1-i] = out[len(out)-1-i], out[i]
	}
	return out, nil
}

func mergeConfigs(confs []Config) Config {
	if len(confs) == 0 {
		// This shouldn't happen because we always have at least a
		// default config.
		panic("trying to merge zero configs")
	}
	if len(confs) == 1 {
		return confs[0]
	}
	conf := confs[0]
	for _, oconf := range confs[1:] {
		conf = conf.Merge(oconf)
	}
	return conf
}

func Load(dir string) (Config, error) {
	confs, err := parseConfigs(dir)
	if err != nil {
		return Config{}, err
	}
	conf := mergeConfigs(confs)

	conf.Checks = normalizeList(conf.Checks)
	conf.Initialisms = normalizeList(conf.Initialisms)
	conf.DotImportWhitelist = normalizeList(conf.DotImportWhitelist)
	conf.HTTPStatusCodeWhitelist = normalizeList(conf.HTTPStatusCodeWhitelist)

	return conf, nil
}
<|endoftext|>


<commit_before>package main

import(
	"fmt"
	"log"
	"net/http"
	"os"
	"gofire/web"
	"gofire/socket"
	"code.google.com/p/go.net/websocket"
)

const StandardPort = "8080"

const StandardAddress = "localhost"

func main(){

	addr := os.Getenv("ADRESS")

	if addr == ""{
		addr = StandardAddress
	}

	port := os.Getenv("PORT")

	if port == ""{
		port = StandardPort
	}

	http.HandleFunc("/", web.IndexHandler)
	log.Println("IndexHandler registered")

	http.HandleFunc("/login", web.LoginHandler)
	log.Println("LoginHandler registered")

	http.HandleFunc("/logout", web.LogoutHandler)
	log.Println("LogoutHandler registered")

	http.HandleFunc("/chat", web.ChatHandler)
	log.Println("ChatHandler registered")

	socket.Start()
	log.Println("Fireserver is running")

	http.Handle("/ws",websocket.Handler(socket.SocketHandler))

	log.Printf("Server started on : %s:%s",addr, port)
	err := http.ListenAndServe(fmt.Sprintf("%s:%s",addr,port),nil)
	panic(err)
}
<commit_msg>add serve for /img and /css<commit_after>package main

import(
	"fmt"
	"log"
	"net/http"
	"os"
	"gofire/web"
	"gofire/socket"
	"code.google.com/p/go.net/websocket"
)

const StandardPort = "8080"

const StandardAddress = "localhost"

func main(){

	addr := os.Getenv("ADRESS")

	if addr == ""{
		addr = StandardAddress
	}

	port := os.Getenv("PORT")

	if port == ""{
		port = StandardPort
	}

	http.HandleFunc("/", web.IndexHandler)
	log.Println("IndexHandler registered")

    http.HandleFunc("/css/", web.StaticHandler)
    http.HandleFunc("/img/", web.StaticHandler)

	http.HandleFunc("/login", web.LoginHandler)
	log.Println("LoginHandler registered")

	http.HandleFunc("/logout", web.LogoutHandler)
	log.Println("LogoutHandler registered")

	http.HandleFunc("/chat", web.ChatHandler)
	log.Println("ChatHandler registered")

	socket.Start()
	log.Println("Fireserver is running")

	http.Handle("/ws",websocket.Handler(socket.SocketHandler))

	log.Printf("Server started on : %s:%s",addr, port)
	err := http.ListenAndServe(fmt.Sprintf("%s:%s",addr,port),nil)
	panic(err)
}
<|endoftext|>


<commit_before>// Copyright 2016 The fer Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package config implements command-line flag parsing and fer devices
// configuration from JSON files.
package config

import (
	"encoding/json"
	"flag"
	"os"
)

// Parse parses the command-line flags from os.Args[1:]. Must be called after
// all flags are defined and before flags are accessed by the program.
func Parse() (Config, error) {
	var (
		id      = flag.String("id", "", "device ID")
		trans   = flag.String("transport", "zeromq", "transport mechanism to use (zeromq, nanomsg, go-chan, ...")
		mq      = flag.String("mq-config", "", "path to JSON file holding device configuration")
		control = flag.String("control", "interactive", "starts device in interactive/static mode")
	)

	flag.Parse()

	cfg := Config{
		ID:        *id,
		Transport: *trans,
		Control:   *control,
	}

	f, err := os.Open(*mq)
	if err != nil {
		return cfg, err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&cfg)
	if err != nil {
		return cfg, err
	}

	return cfg, err
}

// Config holds the configuration of a Fer program.
type Config struct {
	Options   Options `json:"fairMQOptions"`
	ID        string  `json:"fer_id,omitempty"`
	Transport string  `json:"fer_transport,omitempty"` // zeromq, nanomsg, chan
	Control   string  `json:"fer_control,omitempty"`
}

// Options holds the configuration of a Fer MQ program.
type Options struct {
	Devices []Device `json:"devices"`
}

// Device returns the configuration of a device by name.
func (opts Options) Device(name string) (Device, bool) {
	for _, dev := range opts.Devices {
		if dev.Name() == name {
			return dev, true
		}
	}
	return Device{}, false
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (opts *Options) UnmarshalJSON(data []byte) error {
	var raw struct {
		Device  Device   `json:"device"`
		Devices []Device `json:"devices"`
	}
	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	opts.Devices = opts.Devices[:0]
	if !raw.Device.isZero() {
		opts.Devices = append(opts.Devices, raw.Device)
	}
	opts.Devices = append(opts.Devices, raw.Devices...)
	return nil
}

// Device holds the configuration of a device.
type Device struct {
	Doc      string    `json:"_______COMMENT:,omitempty"`
	ID       string    `json:"id,omitempty"`
	Key      string    `json:"key,omitempty"`
	Channels []Channel `json:"channels"`
}

// Name returns the name of a device (either its key or its id).
func (dev Device) Name() string {
	if dev.Key != "" {
		return dev.Key
	}
	return dev.ID
}

func (dev Device) isZero() bool {
	return dev.ID == "" && len(dev.Channels) == 0
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (dev *Device) UnmarshalJSON(data []byte) error {
	var raw struct {
		Doc      string    `json:"_______COMMENT:,omitempty"`
		ID       string    `json:"id"`
		Key      string    `json:"key"`
		Channel  Channel   `json:"channel"`
		Channels []Channel `json:"channels"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	dev.Doc = raw.Doc
	dev.ID = raw.ID
	dev.Key = raw.Key
	dev.Channels = dev.Channels[:0]
	if !raw.Channel.isZero() {
		dev.Channels = append(dev.Channels, raw.Channel)
	}
	dev.Channels = append(dev.Channels, raw.Channels...)
	return nil
}

// Channel holds the configuration of a channel.
type Channel struct {
	Name    string   `json:"name"`
	Sockets []Socket `json:"sockets,omitempty"`

	Type        string `json:"type,omitempty"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
	Method      string `json:"method,omitempty"`  // Method to operate the socket (connect/bind)
	Address     string `json:"address,omitempty"` // Address is the socket end-point
	SendBufSize int    `json:"sndBufSize,omitempty"`
	RecvBufSize int    `json:"rcvBufSize,omitempty"`
	RateLogging int    `json:"rateLogging,omitempty"`
}

func (ch Channel) isZero() bool {
	return ch.Name == "" && len(ch.Sockets) == 0
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (ch *Channel) UnmarshalJSON(data []byte) error {
	var raw struct {
		Name    string   `json:"name"`
		Socket  Socket   `json:"socket"`
		Sockets []Socket `json:"sockets"`

		Type        string `json:"type,omitempty"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
		Method      string `json:"method,omitempty"`  // Method to operate the socket (connect/bind)
		Address     string `json:"address,omitempty"` // Address is the socket end-point
		SendBufSize int    `json:"sndBufSize,omitempty"`
		RecvBufSize int    `json:"rcvBufSize,omitempty"`
		RateLogging int    `json:"rateLogging,omitempty"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	ch.Name = raw.Name
	ch.Sockets = ch.Sockets[:0]
	if (raw.Socket != Socket{}) {
		ch.Sockets = append(ch.Sockets, raw.Socket)
	}
	ch.Sockets = append(ch.Sockets, raw.Sockets...)

	ch.Type = raw.Type
	ch.Method = raw.Method
	ch.Address = raw.Address
	ch.SendBufSize = raw.SendBufSize
	ch.RecvBufSize = raw.RecvBufSize
	ch.RateLogging = raw.RateLogging
	return nil
}

// Socket holds the configuration of a socket.
type Socket struct {
	Type        string `json:"type"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
	Method      string `json:"method"`  // Method to operate the socket (connect/bind)
	Address     string `json:"address"` // Address is the socket end-point
	SendBufSize int    `json:"sndBufSize"`
	RecvBufSize int    `json:"rcvBufSize"`
	RateLogging int    `json:"rateLogging"`
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (sck *Socket) UnmarshalJSON(data []byte) error {
	var raw struct {
		Type        string `json:"type"`
		Method      string `json:"method"`
		Address     string `json:"address"`
		SendBufSize int    `json:"sndBufSize"`
		RecvBufSize int    `json:"rcvBufSize"`
		RateLogging int    `json:"rateLogging"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	sck.Type = raw.Type
	sck.Method = raw.Method
	sck.Address = raw.Address
	sck.SendBufSize = raw.SendBufSize
	sck.RecvBufSize = raw.RecvBufSize
	sck.RateLogging = raw.RateLogging

	if sck.SendBufSize == 0 {
		sck.SendBufSize = 1000
	}

	if sck.RecvBufSize == 0 {
		sck.RecvBufSize = 1000
	}

	return nil
}
<commit_msg>config: fix cli help<commit_after>// Copyright 2016 The fer Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package config implements command-line flag parsing and fer devices
// configuration from JSON files.
package config

import (
	"encoding/json"
	"flag"
	"os"
)

// Parse parses the command-line flags from os.Args[1:]. Must be called after
// all flags are defined and before flags are accessed by the program.
func Parse() (Config, error) {
	var (
		id      = flag.String("id", "", "device ID")
		trans   = flag.String("transport", "zeromq", "transport mechanism to use (zeromq, nanomsg, go-chan, ...)")
		mq      = flag.String("mq-config", "", "path to JSON file holding device configuration")
		control = flag.String("control", "interactive", "starts device in interactive/static mode")
	)

	flag.Parse()

	cfg := Config{
		ID:        *id,
		Transport: *trans,
		Control:   *control,
	}

	f, err := os.Open(*mq)
	if err != nil {
		return cfg, err
	}
	defer f.Close()

	err = json.NewDecoder(f).Decode(&cfg)
	if err != nil {
		return cfg, err
	}

	return cfg, err
}

// Config holds the configuration of a Fer program.
type Config struct {
	Options   Options `json:"fairMQOptions"`
	ID        string  `json:"fer_id,omitempty"`
	Transport string  `json:"fer_transport,omitempty"` // zeromq, nanomsg, chan
	Control   string  `json:"fer_control,omitempty"`
}

// Options holds the configuration of a Fer MQ program.
type Options struct {
	Devices []Device `json:"devices"`
}

// Device returns the configuration of a device by name.
func (opts Options) Device(name string) (Device, bool) {
	for _, dev := range opts.Devices {
		if dev.Name() == name {
			return dev, true
		}
	}
	return Device{}, false
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (opts *Options) UnmarshalJSON(data []byte) error {
	var raw struct {
		Device  Device   `json:"device"`
		Devices []Device `json:"devices"`
	}
	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	opts.Devices = opts.Devices[:0]
	if !raw.Device.isZero() {
		opts.Devices = append(opts.Devices, raw.Device)
	}
	opts.Devices = append(opts.Devices, raw.Devices...)
	return nil
}

// Device holds the configuration of a device.
type Device struct {
	Doc      string    `json:"_______COMMENT:,omitempty"`
	ID       string    `json:"id,omitempty"`
	Key      string    `json:"key,omitempty"`
	Channels []Channel `json:"channels"`
}

// Name returns the name of a device (either its key or its id).
func (dev Device) Name() string {
	if dev.Key != "" {
		return dev.Key
	}
	return dev.ID
}

func (dev Device) isZero() bool {
	return dev.ID == "" && len(dev.Channels) == 0
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (dev *Device) UnmarshalJSON(data []byte) error {
	var raw struct {
		Doc      string    `json:"_______COMMENT:,omitempty"`
		ID       string    `json:"id"`
		Key      string    `json:"key"`
		Channel  Channel   `json:"channel"`
		Channels []Channel `json:"channels"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	dev.Doc = raw.Doc
	dev.ID = raw.ID
	dev.Key = raw.Key
	dev.Channels = dev.Channels[:0]
	if !raw.Channel.isZero() {
		dev.Channels = append(dev.Channels, raw.Channel)
	}
	dev.Channels = append(dev.Channels, raw.Channels...)
	return nil
}

// Channel holds the configuration of a channel.
type Channel struct {
	Name    string   `json:"name"`
	Sockets []Socket `json:"sockets,omitempty"`

	Type        string `json:"type,omitempty"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
	Method      string `json:"method,omitempty"`  // Method to operate the socket (connect/bind)
	Address     string `json:"address,omitempty"` // Address is the socket end-point
	SendBufSize int    `json:"sndBufSize,omitempty"`
	RecvBufSize int    `json:"rcvBufSize,omitempty"`
	RateLogging int    `json:"rateLogging,omitempty"`
}

func (ch Channel) isZero() bool {
	return ch.Name == "" && len(ch.Sockets) == 0
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (ch *Channel) UnmarshalJSON(data []byte) error {
	var raw struct {
		Name    string   `json:"name"`
		Socket  Socket   `json:"socket"`
		Sockets []Socket `json:"sockets"`

		Type        string `json:"type,omitempty"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
		Method      string `json:"method,omitempty"`  // Method to operate the socket (connect/bind)
		Address     string `json:"address,omitempty"` // Address is the socket end-point
		SendBufSize int    `json:"sndBufSize,omitempty"`
		RecvBufSize int    `json:"rcvBufSize,omitempty"`
		RateLogging int    `json:"rateLogging,omitempty"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}
	ch.Name = raw.Name
	ch.Sockets = ch.Sockets[:0]
	if (raw.Socket != Socket{}) {
		ch.Sockets = append(ch.Sockets, raw.Socket)
	}
	ch.Sockets = append(ch.Sockets, raw.Sockets...)

	ch.Type = raw.Type
	ch.Method = raw.Method
	ch.Address = raw.Address
	ch.SendBufSize = raw.SendBufSize
	ch.RecvBufSize = raw.RecvBufSize
	ch.RateLogging = raw.RateLogging
	return nil
}

// Socket holds the configuration of a socket.
type Socket struct {
	Type        string `json:"type"`    // Type is the type of a Socket (PUB/SUB/PUSH/PULL/...)
	Method      string `json:"method"`  // Method to operate the socket (connect/bind)
	Address     string `json:"address"` // Address is the socket end-point
	SendBufSize int    `json:"sndBufSize"`
	RecvBufSize int    `json:"rcvBufSize"`
	RateLogging int    `json:"rateLogging"`
}

// UnmarshalJSON implements the json.Unmarshaler interface.
func (sck *Socket) UnmarshalJSON(data []byte) error {
	var raw struct {
		Type        string `json:"type"`
		Method      string `json:"method"`
		Address     string `json:"address"`
		SendBufSize int    `json:"sndBufSize"`
		RecvBufSize int    `json:"rcvBufSize"`
		RateLogging int    `json:"rateLogging"`
	}

	err := json.Unmarshal(data, &raw)
	if err != nil {
		return err
	}

	sck.Type = raw.Type
	sck.Method = raw.Method
	sck.Address = raw.Address
	sck.SendBufSize = raw.SendBufSize
	sck.RecvBufSize = raw.RecvBufSize
	sck.RateLogging = raw.RateLogging

	if sck.SendBufSize == 0 {
		sck.SendBufSize = 1000
	}

	if sck.RecvBufSize == 0 {
		sck.RecvBufSize = 1000
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
)

// urlsInProgress is a wait group, for concurrency
var urlsInProgress sync.WaitGroup

// Responses is a channel to store the concurrent responses from the target
var responses chan *http.Response

// RedirectError is a custom error type for following redirects, and can be safely ignored
type RedirectError struct {
	RedirectRequest *http.Request
}

// Error method returns a string of the error
func (err *RedirectError) Error() string {
	return fmt.Sprintf("Redirect not followed to: %v", err.RedirectRequest.URL.String())
}

// Request body content
var body string

// Target URL value
var targetURL *url.URL

// Cookie jar value
var jar *cookiejar.Jar

// Number of requests
var numRequests int

// Request type
var requestMethod string

// Follow redirects
var followRedirects bool

// Verbose logging enabled
var verbose bool

// Command-line flags
var flagTargetURL = flag.String("url", "", "URL to send the request to.")
var flagBodyFile = flag.String("body", "", "The location (relative or absolute path) of a file containing the body of the request.")
var flagCookiesFile = flag.String("cookies", "", "The location (relative or absolute path) of a file containing newline-separate cookie values being sent along with the request. Cookie names and values are separated by a comma. For example: cookiename,cookieval")
var flagNumRequests = flag.Int("requests", 100, "The number of requests to send to the destination URL.")
var flagRequestMethod = flag.String("method", "POST", "The request type. Can be either `POST, GET, HEAD, PUT`.")
var flagFollowRedirects = flag.Bool("redirects", false, "Follow redirects (3xx status code in responses)")
var flagVerbose = flag.Bool("v", false, "Enable verbose logging.")

func main() {
	// Change output location of logs
	log.SetOutput(os.Stdout)

	// Check the flags
	err := checkFlags()
	if err != nil {
		log.Println(err.Error())
		flag.Usage()
		os.Exit(1)
	}

	// Send the requests concurrently
	log.Println("Requests begin.")
	errChan := sendRequests()
	if len(errChan) != 0 {
		for err := range errChan {
			log.Printf("[ERROR] %s\n", err.Error())
		}
	}

	// Compare the responses for uniqueness
	uniqueResponses, errChan := compareResponses()
	if len(errChan) != 0 {
		for err := range errChan {
			log.Printf("[ERROR] %s\n", err.Error())
		}
	}

	// Output the responses
	outputResponses(uniqueResponses)

	// Echo completion
	log.Println("Complete.")
}

// Function checkFlags checks that all necessary flags are entered, and parses them for contents.
// Returns a custom error if something went wrong.
func checkFlags() error {
	// Parse the flags
	flag.Parse()

	// Set verbose logging explicitely
	verbose = *flagVerbose

	// Determine whether to follow redirects
	followRedirects = *flagFollowRedirects

	// Set the request type
	switch strings.ToUpper(*flagRequestMethod) {
	case "POST":
		requestMethod = "POST"
	case "GET":
		requestMethod = "GET"
	case "PUT":
		requestMethod = "PUT"
	case "HEAD":
		requestMethod = "HEAD"
	default:
		// Invalid request type specified
		return fmt.Errorf("Invalid request type specified.")
	}

	// Ensure that the destination URL is present
	if *flagTargetURL == "" {
		return fmt.Errorf("Destination URL required.")
	}

	// Parse the URL
	var err error
	targetURL, err = url.Parse(*flagTargetURL)
	if err != nil {
		return fmt.Errorf("Invalid URL provided: %s", *flagTargetURL)
	}

	// Get the request body content
	if *flagBodyFile != "" {
		buf, err := ioutil.ReadFile(*flagBodyFile)
		if err != nil {
			// Error opening the file
			return fmt.Errorf("Unable to open the file: %s\n", *flagBodyFile)
		}
		body = string(buf)
	} else {
		// Body file flag not present, exit.
		return fmt.Errorf("Request body contents required.")
	}

	// Check the number of requests used for testing
	numRequests = *flagNumRequests

	// Initialize the cookie jar
	jar, _ = cookiejar.New(nil)
	var cookies []*http.Cookie
	// Get the cookies to pass to the request
	if *flagCookiesFile != "" {
		file, err := os.Open(*flagCookiesFile)
		if err != nil {
			// Error opening the file
			return fmt.Errorf("Unable to open the file: %s", *flagCookiesFile)
		}

		// Ensure the file is closed
		defer file.Close()

		// Initialize the file scanner
		scanner := bufio.NewScanner(file)

		// Iterate through the file to get the cookies
		for scanner.Scan() {
			// Parse the line to separate the cookie names and values
			nextLine := scanner.Text()
			vals := strings.Split(nextLine, ",")
			cookieName := strings.TrimSpace(vals[0])
			cookieValue := strings.TrimSpace(vals[1])

			// Create the cookie
			cookie := &http.Cookie{
				Name:  cookieName,
				Value: cookieValue,
			}

			// Add the cookie to the existing slice of cookies
			cookies = append(cookies, cookie)
		}

		// Set the cookies to the appropriate URL
		jar.SetCookies(targetURL, cookies)

	}

	// Made it through with no errors, return
	return nil
}

// Function sendRequests takes care of sending the requests to the target concurrently.
// Errors are passed back in a channel of errors. If the length is zero, there were no errors.
func sendRequests() chan error {
	// Initialize the concurrency objects
	responses = make(chan *http.Response, numRequests)
	errorChannel := make(chan error, numRequests)
	urlsInProgress.Add(numRequests)

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Sending %d %s requests to %s\n", numRequests, requestMethod, targetURL.String())
		if body != "" {
			log.Printf("[VERBOSE] Request body: %s", body)
		}
	}
	for i := 0; i < numRequests; i++ {
		go func(index int) {
			// Ensure that the waitgroup element is returned
			defer urlsInProgress.Done()

			// Convert the request body to an io.Reader interface, to pass to the request.
			// This must be done in the loop, because any call to client.Do() will
			// read the body contents on the first time, but not any subsequent requests.
			requestBody := strings.NewReader(body)

			// Declare HTTP request method and URL
			req, err := http.NewRequest(requestMethod, targetURL.String(), requestBody)
			if err != nil {
				errorChannel <- fmt.Errorf("Error in forming request: %v", err.Error())
				return
			}

			// Create the HTTP client
			// Using Cookie jar
			// Ignoring TLS errors
			// Ignoring redirects (more accurate output), depending on user flag
			// Implementing a connection timeouts, for slow clients & servers (especially important with race conditions on the server)
			var client http.Client
			if followRedirects {
				client = http.Client{
					Jar: jar,
					Transport: &http.Transport{
						TLSClientConfig: &tls.Config{
							InsecureSkipVerify: true,
						},
					},
					Timeout: 20 * time.Second,
				}
			} else {
				client = http.Client{
					Jar: jar,
					Transport: &http.Transport{
						TLSClientConfig: &tls.Config{
							InsecureSkipVerify: true,
						},
					},
					CheckRedirect: func(req *http.Request, via []*http.Request) error {
						// Craft the custom error
						redirectError := RedirectError{req}
						return &redirectError
					},
					Timeout: 20 * time.Second,
				}
			}

			// Make the request
			resp, err := client.Do(req)
			// Check the error type from the request
			if err != nil {
				if uErr, ok := err.(*url.Error); ok {
					if rErr, ok2 := uErr.Err.(*RedirectError); ok2 {
						// Redirect error
						// VERBOSE
						if verbose {
							log.Printf("[VERBOSE] %v\n", rErr)
						}
						// Add the response to the responses channel, because it is still valid
						responses <- resp
					} else {
						// URL Error, but not a redirect error
						errorChannel <- fmt.Errorf("Error in request #%v: %v\n", index, err)
					}
				} else {
					// Other type of error
					errorChannel <- fmt.Errorf("Error in request #%v: %v\n", index, err)
				}
			} else {
				// Add the response to the responses channel
				responses <- resp
			}
		}(i)
	}

	// Wait for the URLs to finish sending
	urlsInProgress.Wait()

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Requests complete.")
	}

	// Close the response and error chanels, so they don't block on the range read
	close(responses)
	close(errorChannel)

	return errorChannel
}

// Function compareResponses compares the responses returned from the requests,
// and adds them to a map, where the key is an *http.Response, and the value is
// the number of similar responses observed.
func compareResponses() (uniqueResponses map[*http.Response]int, errorChannel chan error) {
	// Initialize the unique responses map
	uniqueResponses = make(map[*http.Response]int)

	// Initialize the error channel
	errorChannel = make(chan error, len(responses))

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Unique response comparison begin.\n")
	}

	// Compare the responses, one at a time
	for resp := range responses {
		// Read the response body
		defer resp.Body.Close()
		respBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			errorChannel <- fmt.Errorf("Error reading response body: %s", err.Error())

			// Exit this loop
			continue
		}

		// Add an entry, if the unique responses map is empty
		if len(uniqueResponses) == 0 {
			uniqueResponses[resp] = 0
		} else {
			// Add to the unique responses map, if no similar ones exist
			for uResp := range uniqueResponses {
				// Read the unique response body
				defer uResp.Body.Close()
				uRespBody, err := ioutil.ReadAll(uResp.Body)
				if err != nil {
					errorChannel <- fmt.Errorf("Error reading unique response body: %s", err.Error())

					// Exit the inner loop
					continue
				}

				// Compare the response bodies
				respBodyMatch := false
				if string(respBody) == string(uRespBody) {
					respBodyMatch = true
				}

				// Compare response status code, body content, and content length
				if resp.StatusCode == uResp.StatusCode && resp.ContentLength == uResp.ContentLength && respBodyMatch {
					// Similar, increase count
					uniqueResponses[uResp]++
					// Exit inner loop
					continue
				} else {
					// Unique, add to unique responses
					uniqueResponses[resp] = 0
					// Exit inner loop
					continue
				}
			}
		}
	}

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Unique response comparision complete.\n")
	}

	// Close the error channel
	close(errorChannel)

	return
}

func outputResponses(uniqueResponses map[*http.Response]int) {
	// Display the responses
	log.Printf("Responses:\n")
	for resp, count := range uniqueResponses {
		fmt.Printf("Response:\n")
		fmt.Printf("[Status Code] %v\n", resp.StatusCode)
		fmt.Printf("[Protocol] %v\n", resp.Proto)
		if len(resp.Header) != 0 {
			fmt.Println("[Headers]")
			for header, value := range resp.Header {
				fmt.Printf("\t%v: %v\n", header, value)
			}
		}
		location, err := resp.Location()
		if err != http.ErrNoLocation {
			fmt.Printf("[Location] %v\n", location.String())
		}
		respBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Println("[Body] ")
		} else {
			fmt.Printf("[Body]\n%s\n", respBody)
			// Close the response body
			resp.Body.Close()
		}
		fmt.Printf("Similar: %v\n\n", count)
	}
}

// BUG: Not reading some response bodies. Might be a timeout issue?
<commit_msg>Fixed bug where response bodies were not being read properly.<commit_after>package main

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"sync"
	"time"
)

// urlsInProgress is a wait group, for concurrency
var urlsInProgress sync.WaitGroup

// Responses is a channel to store the concurrent responses from the target
var responses chan *http.Response

// UniqueResponses is a map to store all compared responses, and the number of similar responses found
var uniqueResponses map[*http.Response]int

// RedirectError is a custom error type for following redirects, and can be safely ignored
type RedirectError struct {
	RedirectRequest *http.Request
}

// Error method returns a string of the error
func (err *RedirectError) Error() string {
	return fmt.Sprintf("Redirect not followed to: %v", err.RedirectRequest.URL.String())
}

// Request body content
var body string

// Target URL value
var targetURL *url.URL

// Cookie jar value
var jar *cookiejar.Jar

// Number of requests
var numRequests int

// Request type
var requestMethod string

// Follow redirects
var followRedirects bool

// Verbose logging enabled
var verbose bool

// Command-line flags
var flagTargetURL = flag.String("url", "", "URL to send the request to.")
var flagBodyFile = flag.String("body", "", "The location (relative or absolute path) of a file containing the body of the request.")
var flagCookiesFile = flag.String("cookies", "", "The location (relative or absolute path) of a file containing newline-separate cookie values being sent along with the request. Cookie names and values are separated by a comma. For example: cookiename,cookieval")
var flagNumRequests = flag.Int("requests", 100, "The number of requests to send to the destination URL.")
var flagRequestMethod = flag.String("method", "POST", "The request type. Can be either `POST, GET, HEAD, PUT`.")
var flagFollowRedirects = flag.Bool("redirects", false, "Follow redirects (3xx status code in responses)")
var flagVerbose = flag.Bool("v", false, "Enable verbose logging.")

func main() {
	// Change output location of logs
	log.SetOutput(os.Stdout)

	// Check the flags
	err := checkFlags()
	if err != nil {
		log.Println(err.Error())
		flag.Usage()
		os.Exit(1)
	}

	// Make sure all response bodies are closed- memory leaks otherwise
	defer func() {
		for resp := range responses {
			resp.Body.Close()
		}
		for resp := range uniqueResponses {
			resp.Body.Close()
		}
	}()

	// Initialize an error channel
	var errChan chan error

	// Send the requests concurrently
	log.Println("Requests begin.")
	errChan = sendRequests()
	if len(errChan) != 0 {
		for err := range errChan {
			log.Printf("[ERROR] %s\n", err.Error())
		}
	}

	// Compare the responses for uniqueness
	uniqueResponses, errChan = compareResponses()
	if len(errChan) != 0 {
		for err := range errChan {
			log.Printf("[ERROR] %s\n", err.Error())
		}
	}

	// Output the responses
	outputResponses(uniqueResponses)

	// Echo completion
	log.Println("Complete.")
}

// Function checkFlags checks that all necessary flags are entered, and parses them for contents.
// Returns a custom error if something went wrong.
func checkFlags() error {
	// Parse the flags
	flag.Parse()

	// Set verbose logging explicitely
	verbose = *flagVerbose

	// Determine whether to follow redirects
	followRedirects = *flagFollowRedirects

	// Set the request type
	switch strings.ToUpper(*flagRequestMethod) {
	case "POST":
		requestMethod = "POST"
	case "GET":
		requestMethod = "GET"
	case "PUT":
		requestMethod = "PUT"
	case "HEAD":
		requestMethod = "HEAD"
	default:
		// Invalid request type specified
		return fmt.Errorf("Invalid request type specified.")
	}

	// Ensure that the destination URL is present
	if *flagTargetURL == "" {
		return fmt.Errorf("Destination URL required.")
	}

	// Parse the URL
	var err error
	targetURL, err = url.Parse(*flagTargetURL)
	if err != nil {
		return fmt.Errorf("Invalid URL provided: %s", *flagTargetURL)
	}

	// Get the request body content
	if *flagBodyFile != "" {
		buf, err := ioutil.ReadFile(*flagBodyFile)
		if err != nil {
			// Error opening the file
			return fmt.Errorf("Unable to open the file: %s\n", *flagBodyFile)
		}
		body = string(buf)
	} else {
		// Body file flag not present, exit.
		return fmt.Errorf("Request body contents required.")
	}

	// Check the number of requests used for testing
	numRequests = *flagNumRequests

	// Initialize the cookie jar
	jar, _ = cookiejar.New(nil)
	var cookies []*http.Cookie
	// Get the cookies to pass to the request
	if *flagCookiesFile != "" {
		file, err := os.Open(*flagCookiesFile)
		if err != nil {
			// Error opening the file
			return fmt.Errorf("Unable to open the file: %s", *flagCookiesFile)
		}

		// Ensure the file is closed
		defer file.Close()

		// Initialize the file scanner
		scanner := bufio.NewScanner(file)

		// Iterate through the file to get the cookies
		for scanner.Scan() {
			// Parse the line to separate the cookie names and values
			nextLine := scanner.Text()
			vals := strings.Split(nextLine, ",")
			cookieName := strings.TrimSpace(vals[0])
			cookieValue := strings.TrimSpace(vals[1])

			// Create the cookie
			cookie := &http.Cookie{
				Name:  cookieName,
				Value: cookieValue,
			}

			// Add the cookie to the existing slice of cookies
			cookies = append(cookies, cookie)
		}

		// Set the cookies to the appropriate URL
		jar.SetCookies(targetURL, cookies)

	}

	// Made it through with no errors, return
	return nil
}

// Function sendRequests takes care of sending the requests to the target concurrently.
// Errors are passed back in a channel of errors. If the length is zero, there were no errors.
func sendRequests() chan error {
	// Initialize the concurrency objects
	responses = make(chan *http.Response, numRequests)
	errorChannel := make(chan error, numRequests)
	urlsInProgress.Add(numRequests)

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Sending %d %s requests to %s\n", numRequests, requestMethod, targetURL.String())
		if body != "" {
			log.Printf("[VERBOSE] Request body: %s", body)
		}
	}
	for i := 0; i < numRequests; i++ {
		go func(index int) {
			// Ensure that the waitgroup element is returned
			defer urlsInProgress.Done()

			// Convert the request body to an io.Reader interface, to pass to the request.
			// This must be done in the loop, because any call to client.Do() will
			// read the body contents on the first time, but not any subsequent requests.
			requestBody := strings.NewReader(body)

			// Declare HTTP request method and URL
			req, err := http.NewRequest(requestMethod, targetURL.String(), requestBody)
			if err != nil {
				errorChannel <- fmt.Errorf("Error in forming request: %v", err.Error())
				return
			}

			// Create the HTTP client
			// Using Cookie jar
			// Ignoring TLS errors
			// Ignoring redirects (more accurate output), depending on user flag
			// Implementing a connection timeouts, for slow clients & servers (especially important with race conditions on the server)
			var client http.Client
			if followRedirects {
				client = http.Client{
					Jar: jar,
					Transport: &http.Transport{
						TLSClientConfig: &tls.Config{
							InsecureSkipVerify: true,
						},
					},
					Timeout: 20 * time.Second,
				}
			} else {
				client = http.Client{
					Jar: jar,
					Transport: &http.Transport{
						TLSClientConfig: &tls.Config{
							InsecureSkipVerify: true,
						},
					},
					CheckRedirect: func(req *http.Request, via []*http.Request) error {
						// Craft the custom error
						redirectError := RedirectError{req}
						return &redirectError
					},
					Timeout: 20 * time.Second,
				}
			}

			// Make the request
			resp, err := client.Do(req)
			// Check the error type from the request
			if err != nil {
				if uErr, ok := err.(*url.Error); ok {
					if rErr, ok2 := uErr.Err.(*RedirectError); ok2 {
						// Redirect error
						// VERBOSE
						if verbose {
							log.Printf("[VERBOSE] %v\n", rErr)
						}
						// Add the response to the responses channel, because it is still valid
						responses <- resp
					} else {
						// URL Error, but not a redirect error
						errorChannel <- fmt.Errorf("Error in request #%v: %v\n", index, err)
					}
				} else {
					// Other type of error
					errorChannel <- fmt.Errorf("Error in request #%v: %v\n", index, err)
				}
			} else {
				// Add the response to the responses channel
				responses <- resp
			}
		}(i)
	}

	// Wait for the URLs to finish sending
	urlsInProgress.Wait()

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Requests complete.")
	}

	// Close the response and error chanels, so they don't block on the range read
	close(responses)
	close(errorChannel)

	return errorChannel
}

// Function compareResponses compares the responses returned from the requests,
// and adds them to a map, where the key is an *http.Response, and the value is
// the number of similar responses observed.
func compareResponses() (newResponses map[*http.Response]int, errorChannel chan error) {
	// Initialize the unique responses map
	newResponses = make(map[*http.Response]int)

	// Initialize the error channel
	errorChannel = make(chan error, len(responses))

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Unique response comparison begin.\n")
	}

	// Compare the responses, one at a time
	for resp := range responses {
		// Read the response body
		respBody, err := readResponseBody(resp)
		if err != nil {
			errorChannel <- fmt.Errorf("Error reading response body: %s", err.Error())

			// Exit this loop
			continue
		}

		// Add an entry, if the unique responses map is empty
		if len(newResponses) == 0 {
			newResponses[resp] = 0
		} else {
			// Add to the unique responses map, if no similar ones exist
			for uResp := range newResponses {
				// Read the unique response body
				uRespBody, err := readResponseBody(uResp)
				if err != nil {
					errorChannel <- fmt.Errorf("Error reading unique response body: %s", err.Error())

					// Exit the inner loop
					continue
				}

				// Compare the response bodies
				respBodyMatch := false
				if string(respBody) == string(uRespBody) {
					respBodyMatch = true
				}

				// Compare response status code, body content, and content length
				if resp.StatusCode == uResp.StatusCode && resp.ContentLength == uResp.ContentLength && respBodyMatch {
					// Similar, increase count
					newResponses[uResp]++
					// Exit inner loop
					continue
				} else {
					// Unique, add to unique responses
					newResponses[resp] = 0
					// Exit inner loop
					continue
				}
			}
		}
	}

	// VERBOSE
	if verbose {
		log.Printf("[VERBOSE] Unique response comparision complete.\n")
	}

	// Close the error channel
	close(errorChannel)

	return
}

func outputResponses(uniqueResponses map[*http.Response]int) {
	// Display the responses
	log.Printf("Responses:\n")
	for resp, count := range uniqueResponses {
		fmt.Printf("Response:\n")
		fmt.Printf("[Status Code] %v\n", resp.StatusCode)
		fmt.Printf("[Protocol] %v\n", resp.Proto)
		if len(resp.Header) != 0 {
			fmt.Println("[Headers]")
			for header, value := range resp.Header {
				fmt.Printf("\t%v: %v\n", header, value)
			}
		}
		location, err := resp.Location()
		if err != http.ErrNoLocation {
			fmt.Printf("[Location] %v\n", location.String())
		}
		respBody, err := readResponseBody(resp)
		if err != nil {
			fmt.Println("[Body] ")
			fmt.Printf("[ERROR] Error reading body: %v.", err)
		} else {
			fmt.Printf("[Body]\n%s\n", respBody)
			// Close the response body
			resp.Body.Close()
		}
		fmt.Printf("Similar: %v\n\n", count)
	}
}

// Function readResponseBody is a helper function to read the content form a response's body,
// and refill the body with another io.ReadCloser, so that it can be read again.
func readResponseBody(resp *http.Response) (content []byte, err error) {
	// Get the content
	content, err = ioutil.ReadAll(resp.Body)

	// Reset the response body
	rCloser := ioutil.NopCloser(bytes.NewBuffer(content))
	resp.Body = rCloser

	return
}

// TODO: Optimize speed (more concurrency)
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

// Exit statuses.
const (
	_ = iota
	exitNoTorrentProvided
	exitErrorInClient
)

func main() {
	// Parse flags.
	var port, torrentPort int
	var seed, tcp *bool
	var player *string
	var maxConnections int

	player = flag.String("player", "", "Open the stream with a video player ("+joinPlayerNames()+")")
	flag.IntVar(&port, "port", 8080, "Port to stream the video on")
	flag.IntVar(&torrentPort, "torrent-port", 6882, "Port to listen for incoming torrent connections")
	seed = flag.Bool("seed", false, "Seed after finished downloading")
	flag.IntVar(&maxConnections, "conn", 200, "Maximum number of connections")
	tcp = flag.Bool("tcp", true, "Allow connections via TCP")
	flag.Parse()
	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(exitNoTorrentProvided)
	}

	// Start up the torrent client.
	client, err := NewClient(flag.Arg(0), port, torrentPort, *seed, *tcp, maxConnections)
	if err != nil {
		log.Fatalf(err.Error())
		os.Exit(exitErrorInClient)
	}

	// Http handler.
	go func() {
		http.HandleFunc("/", client.GetFile)
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(port), nil))
	}()

	// Open selected video player
	if *player != "" {
		go func() {
			for !client.ReadyForPlayback() {
				time.Sleep(time.Second)
			}
			openPlayer(*player, port)
		}()
	}

	// Handle exit signals.
	interruptChannel := make(chan os.Signal, 1)
	signal.Notify(interruptChannel,
		os.Interrupt,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)
	go func(interruptChannel chan os.Signal) {
		for range interruptChannel {
			log.Println("Exiting...")
			client.Close()
			os.Exit(0)
		}
	}(interruptChannel)

	// Cli render loop.
	for {
		client.Render()
		time.Sleep(time.Second)
	}
}
<commit_msg>Use default upstream listening port<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

// Exit statuses.
const (
	_ = iota
	exitNoTorrentProvided
	exitErrorInClient
)

func main() {
	// Parse flags.
	var port, torrentPort int
	var seed, tcp *bool
	var player *string
	var maxConnections int

	player = flag.String("player", "", "Open the stream with a video player ("+joinPlayerNames()+")")
	flag.IntVar(&port, "port", 8080, "Port to stream the video on")
	flag.IntVar(&torrentPort, "torrent-port", 50007, "Port to listen for incoming torrent connections")
	seed = flag.Bool("seed", false, "Seed after finished downloading")
	flag.IntVar(&maxConnections, "conn", 200, "Maximum number of connections")
	tcp = flag.Bool("tcp", true, "Allow connections via TCP")
	flag.Parse()
	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(exitNoTorrentProvided)
	}

	// Start up the torrent client.
	client, err := NewClient(flag.Arg(0), port, torrentPort, *seed, *tcp, maxConnections)
	if err != nil {
		log.Fatalf(err.Error())
		os.Exit(exitErrorInClient)
	}

	// Http handler.
	go func() {
		http.HandleFunc("/", client.GetFile)
		log.Fatal(http.ListenAndServe(":"+strconv.Itoa(port), nil))
	}()

	// Open selected video player
	if *player != "" {
		go func() {
			for !client.ReadyForPlayback() {
				time.Sleep(time.Second)
			}
			openPlayer(*player, port)
		}()
	}

	// Handle exit signals.
	interruptChannel := make(chan os.Signal, 1)
	signal.Notify(interruptChannel,
		os.Interrupt,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)
	go func(interruptChannel chan os.Signal) {
		for range interruptChannel {
			log.Println("Exiting...")
			client.Close()
			os.Exit(0)
		}
	}(interruptChannel)

	// Cli render loop.
	for {
		client.Render()
		time.Sleep(time.Second)
	}
}
<|endoftext|>


<commit_before>package conio

import (
	"bytes"
	"fmt"
	"strings"
	"unicode"

	"github.com/atotto/clipboard"
)

func KeyFuncPass(this *Buffer) Result {
	return CONTINUE
}

func KeyFuncEnter(this *Buffer) Result { // Ctrl-M
	return ENTER
}

func KeyFuncIntr(this *Buffer) Result { // Ctrl-C
	this.Length = 0
	this.Cursor = 0
	this.Buffer = []rune{}
	return ENTER
}

func KeyFuncHead(this *Buffer) Result { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *Buffer) Result { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(GetCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *Buffer) Result { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	} else {
		PutRune('\a')
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := GetCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + GetCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *Buffer) Result { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRune(this.Buffer[this.Cursor])
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if GetCharWidth(this.Buffer[this.Cursor]) > GetCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *Buffer) Result { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *Buffer) Result { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *Buffer) Result { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *Buffer) Result {
	ch := this.Unicode
	if ch < 0x20 {
		return CONTINUE
	}
	this.Insert(this.Cursor, []rune{ch})

	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := GetCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if GetCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *Buffer) Result {
	this.InsertAndRepaint(fmt.Sprintf("[%X]", this.Unicode))
	return CONTINUE
}

func KeyFuncClearAfter(this *Buffer) Result {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0

	var killbuf bytes.Buffer
	for j := this.Cursor; j < this.Length; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())

	for i < this.Length && w < this.ViewWidth {
		w1 := GetCharWidth(this.Buffer[i])
		PutRunes(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *Buffer) Result {
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRunes(' ', this.ViewWidth)
	Backspace(this.ViewWidth)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncWordRubout(this *Buffer) Result {
	org_cursor := this.Cursor
	for this.Cursor > 0 && unicode.IsSpace(this.Buffer[this.Cursor-1]) {
		this.Cursor--
	}
	i := this.CurrentWordTop()
	var killbuf bytes.Buffer
	for j := i; j < org_cursor; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())
	keta := this.Delete(i, org_cursor-i)
	if i >= this.ViewStart {
		Backspace(keta)
	} else {
		Backspace(this.GetWidthBetween(this.ViewStart, org_cursor))
	}
	this.Cursor = i
	this.Repaint(i, keta)
	return CONTINUE
}

func KeyFuncClearBefore(this *Buffer) Result {
	keta := this.GetWidthBetween(this.ViewStart, this.Cursor)
	var killbuf bytes.Buffer
	for i := 0; i < this.Cursor; i++ {
		killbuf.WriteRune(this.Buffer[i])
	}
	clipboard.WriteAll(killbuf.String())
	this.Delete(0, this.Cursor)
	Backspace(keta)
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, keta)
	return CONTINUE
}

func KeyFuncCLS(this *Buffer) Result {
	Cls()
	this.RepaintAll()
	return CONTINUE
}

func KeyFuncPaste(this *Buffer) Result {
	text, err := clipboard.ReadAll()
	if err == nil {
		this.InsertAndRepaint(
			strings.Replace(
				strings.Replace(
					strings.Replace(text, "\n", " ", -1),
					"\r", "", -1),
				"\t", " ", -1))
	}
	return CONTINUE
}

func maxInt(a, b int) int {
	if a < b {
		return b
	} else {
		return a
	}
}

func KeyFuncSwapChar(this *Buffer) Result {
	if this.Length == this.Cursor {
		if this.Cursor < 2 {
			return CONTINUE
		}
		this.Buffer[this.Cursor-2], this.Buffer[this.Cursor-1] = this.Buffer[this.Cursor-1], this.Buffer[this.Cursor-2]

		redrawStart := maxInt(this.Cursor-2, this.ViewStart)
		Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
		for i := redrawStart; i < this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
	} else {
		if this.Cursor < 1 {
			return CONTINUE
		}

		w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
		this.Buffer[this.Cursor-1], this.Buffer[this.Cursor] = this.Buffer[this.Cursor], this.Buffer[this.Cursor-1]
		if w >= this.ViewWidth {
			// cursor move right and scroll
			w_1 := w - GetCharWidth(this.Buffer[this.Cursor])
			Backspace(w_1)
			this.ViewStart++
			for i := this.ViewStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		} else {
			// no neccesary to scroll
			redrawStart := maxInt(this.Cursor-1, this.ViewStart)
			Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
			for i := redrawStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		}
		this.Cursor++
	}
	return CONTINUE
}
<commit_msg>Fix: hanged at call "INTR" in function bound to key #118<commit_after>package conio

import (
	"bytes"
	"fmt"
	"strings"
	"unicode"

	"github.com/atotto/clipboard"
)

func KeyFuncPass(this *Buffer) Result {
	return CONTINUE
}

func KeyFuncEnter(this *Buffer) Result { // Ctrl-M
	return ENTER
}

func KeyFuncIntr(this *Buffer) Result { // Ctrl-C
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return ENTER
}

func KeyFuncHead(this *Buffer) Result { // Ctrl-A
	Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, 1)
	return CONTINUE
}

func KeyFuncBackword(this *Buffer) Result { // Ctrl-B
	if this.Cursor <= 0 {
		return CONTINUE
	}
	this.Cursor--
	if this.Cursor < this.ViewStart {
		this.ViewStart--
		this.Repaint(this.Cursor, 1)
	} else {
		Backspace(GetCharWidth(this.Buffer[this.Cursor]))
	}
	return CONTINUE
}

func KeyFuncTail(this *Buffer) Result { // Ctrl-E
	allength := this.GetWidthBetween(this.ViewStart, this.Length)
	if allength < this.ViewWidth {
		for ; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	} else {
		PutRune('\a')
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		this.ViewStart = this.Length - 1
		w := GetCharWidth(this.Buffer[this.ViewStart])
		for {
			if this.ViewStart <= 0 {
				break
			}
			w_ := w + GetCharWidth(this.Buffer[this.ViewStart-1])
			if w_ >= this.ViewWidth {
				break
			}
			w = w_
			this.ViewStart--
		}
		for this.Cursor = this.ViewStart; this.Cursor < this.Length; this.Cursor++ {
			PutRune(this.Buffer[this.Cursor])
		}
	}
	return CONTINUE
}

func KeyFuncForward(this *Buffer) Result { // Ctrl-F
	if this.Cursor >= this.Length {
		return CONTINUE
	}
	w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
	if w < this.ViewWidth {
		// No Scroll
		PutRune(this.Buffer[this.Cursor])
	} else {
		// Right Scroll
		Backspace(this.GetWidthBetween(this.ViewStart, this.Cursor))
		if GetCharWidth(this.Buffer[this.Cursor]) > GetCharWidth(this.Buffer[this.ViewStart]) {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncBackSpace(this *Buffer) Result { // Backspace
	if this.Cursor > 0 {
		this.Cursor--
		delw := this.Delete(this.Cursor, 1)
		if this.Cursor >= this.ViewStart {
			Backspace(delw)
		} else {
			this.ViewStart = this.Cursor
		}
		this.Repaint(this.Cursor, delw)
	}
	return CONTINUE
}

func KeyFuncDelete(this *Buffer) Result { // Del
	delw := this.Delete(this.Cursor, 1)
	this.Repaint(this.Cursor, delw)
	return CONTINUE
}

func KeyFuncDeleteOrAbort(this *Buffer) Result { // Ctrl-D
	if this.Length > 0 {
		return KeyFuncDelete(this)
	} else {
		return ABORT
	}
}

func KeyFuncInsertSelf(this *Buffer) Result {
	ch := this.Unicode
	if ch < 0x20 {
		return CONTINUE
	}
	this.Insert(this.Cursor, []rune{ch})

	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	w1 := GetCharWidth(ch)
	if w+w1 >= this.ViewWidth {
		// scroll left
		Backspace(w)
		if GetCharWidth(this.Buffer[this.ViewStart]) < w1 {
			this.ViewStart++
		}
		this.ViewStart++
		for i := this.ViewStart; i <= this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
		PutRune(' ')
		Backspace(1)
	} else {
		this.Repaint(this.Cursor, -w1)
	}
	this.Cursor++
	return CONTINUE
}

func KeyFuncInsertReport(this *Buffer) Result {
	this.InsertAndRepaint(fmt.Sprintf("[%X]", this.Unicode))
	return CONTINUE
}

func KeyFuncClearAfter(this *Buffer) Result {
	w := this.GetWidthBetween(this.ViewStart, this.Cursor)
	i := this.Cursor
	bs := 0

	var killbuf bytes.Buffer
	for j := this.Cursor; j < this.Length; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())

	for i < this.Length && w < this.ViewWidth {
		w1 := GetCharWidth(this.Buffer[i])
		PutRunes(' ', w1)
		i++
		w += w1
		bs += w1
	}
	Backspace(bs)
	this.Length = this.Cursor
	return CONTINUE
}

func KeyFuncClear(this *Buffer) Result {
	width := this.GetWidthBetween(this.ViewStart, this.Cursor)
	Backspace(width)
	PutRunes(' ', this.ViewWidth)
	Backspace(this.ViewWidth)
	this.Length = 0
	this.Cursor = 0
	this.ViewStart = 0
	return CONTINUE
}

func KeyFuncWordRubout(this *Buffer) Result {
	org_cursor := this.Cursor
	for this.Cursor > 0 && unicode.IsSpace(this.Buffer[this.Cursor-1]) {
		this.Cursor--
	}
	i := this.CurrentWordTop()
	var killbuf bytes.Buffer
	for j := i; j < org_cursor; j++ {
		killbuf.WriteRune(this.Buffer[j])
	}
	clipboard.WriteAll(killbuf.String())
	keta := this.Delete(i, org_cursor-i)
	if i >= this.ViewStart {
		Backspace(keta)
	} else {
		Backspace(this.GetWidthBetween(this.ViewStart, org_cursor))
	}
	this.Cursor = i
	this.Repaint(i, keta)
	return CONTINUE
}

func KeyFuncClearBefore(this *Buffer) Result {
	keta := this.GetWidthBetween(this.ViewStart, this.Cursor)
	var killbuf bytes.Buffer
	for i := 0; i < this.Cursor; i++ {
		killbuf.WriteRune(this.Buffer[i])
	}
	clipboard.WriteAll(killbuf.String())
	this.Delete(0, this.Cursor)
	Backspace(keta)
	this.Cursor = 0
	this.ViewStart = 0
	this.Repaint(0, keta)
	return CONTINUE
}

func KeyFuncCLS(this *Buffer) Result {
	Cls()
	this.RepaintAll()
	return CONTINUE
}

func KeyFuncPaste(this *Buffer) Result {
	text, err := clipboard.ReadAll()
	if err == nil {
		this.InsertAndRepaint(
			strings.Replace(
				strings.Replace(
					strings.Replace(text, "\n", " ", -1),
					"\r", "", -1),
				"\t", " ", -1))
	}
	return CONTINUE
}

func maxInt(a, b int) int {
	if a < b {
		return b
	} else {
		return a
	}
}

func KeyFuncSwapChar(this *Buffer) Result {
	if this.Length == this.Cursor {
		if this.Cursor < 2 {
			return CONTINUE
		}
		this.Buffer[this.Cursor-2], this.Buffer[this.Cursor-1] = this.Buffer[this.Cursor-1], this.Buffer[this.Cursor-2]

		redrawStart := maxInt(this.Cursor-2, this.ViewStart)
		Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
		for i := redrawStart; i < this.Cursor; i++ {
			PutRune(this.Buffer[i])
		}
	} else {
		if this.Cursor < 1 {
			return CONTINUE
		}

		w := this.GetWidthBetween(this.ViewStart, this.Cursor+1)
		this.Buffer[this.Cursor-1], this.Buffer[this.Cursor] = this.Buffer[this.Cursor], this.Buffer[this.Cursor-1]
		if w >= this.ViewWidth {
			// cursor move right and scroll
			w_1 := w - GetCharWidth(this.Buffer[this.Cursor])
			Backspace(w_1)
			this.ViewStart++
			for i := this.ViewStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		} else {
			// no neccesary to scroll
			redrawStart := maxInt(this.Cursor-1, this.ViewStart)
			Backspace(this.GetWidthBetween(redrawStart, this.Cursor))
			for i := redrawStart; i <= this.Cursor; i++ {
				PutRune(this.Buffer[i])
			}
		}
		this.Cursor++
	}
	return CONTINUE
}
<|endoftext|>


<commit_before>package main

import (
	types "./types"
	"flag"
	"fmt"
	"github.com/nsf/termbox-go"
	"os"
	"sync"
	"time"
)

var cassandraHost string
var cassandraPort string

// var messageChannel = make(chan types.LogMessage, 10)
var metricsChannel = make(chan types.CFMetric, 100)
var messageChannel = make(chan types.LogMessage, 100)
var stats = make(map[string]types.CFStats)
var statsMutex sync.Mutex
var dataDisplayed = "Metrics"
var dataSortedBy = "Reads"
var termWidth = 80
var termHeight = 25
var refreshTime = 1 * time.Second

var hostName, _ = os.Hostname()
var portNumber = "8081"

const (
	defaultForeGroundColour = termbox.ColorWhite
	defaultBackGroundColour = termbox.ColorBlack
	messageForeGroundColour = termbox.ColorMagenta
)

func init() {
	// Default to localhost (MX4J needs to be configured to listen to this address in cassandra-env.sh though):
	flag.StringVar(&cassandraHost, "host", hostName, "IP address of the Cassandra host to run against")
	flag.StringVar(&cassandraPort, "port", portNumber, "TCP port of the Cassandra host")
}

// Do all the things:
func main() {

	// Set the vars from the command-line args:
	flag.Parse()

	// Check our connection to MX4J:
	if checkConnection(cassandraHost, cassandraPort) != nil {
		fmt.Printf("Can't connect to stats-provider (%s)! Trying localhost before bailing...\n", cassandraHost)
		if checkConnection("localhost", cassandraPort) != nil {
			fmt.Println("Can't even connect to localhost! Check your destination host and port and try again.")
			os.Exit(2)
		} else {
			fmt.Println("Proceeding with localhost..")
			cassandraHost = "localhost"
		}
	}

	// Initialise "termbox" (console interface):
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	// Get the initial window-size:
	termWidth, termHeight = termbox.Size()

	// Get the display running in the right mode:
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	// Render the initial "UI":
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	drawBorder(termWidth, termHeight)
	termbox.Flush()

	// Run the metrics-collector:
	go MetricsCollector(cassandraHost)
	go handleMetrics()
	go refreshScreen()

loop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		// Key pressed:
		case termbox.EventKey:

			// Handle keypresses:
			if ev.Ch == 113 {
				// "q" (quit):
				printfTb(2, 1, messageForeGroundColour, termbox.ColorBlack, "Goodbye!: %s", ev.Ch)
				break loop
			} else if ev.Ch == 0 { // "Space-bar (refresh)"
				showStats()
			} else if ev.Ch == 109 { // "M"
				dataDisplayed = "Metrics"
				showStats()
			} else if ev.Ch == 108 { // "L"
				dataDisplayed = "Logs"
			} else if ev.Ch == 49 { // "1"
				dataSortedBy = "Reads"
			} else if ev.Ch == 50 { // "2"
				dataSortedBy = "Writes"
			} else if ev.Ch == 51 { // "3"
				dataSortedBy = "Space"
			} else if ev.Ch == 52 { // "4"
				dataSortedBy = "ReadLatency"
			} else if ev.Ch == 53 { // "5"
				dataSortedBy = "WriteLatency"
			} else {
				// Anything else:
				handleKeypress(&ev)
			}

			// Redraw the display:
			drawBorder(termWidth, termHeight)
			termbox.Flush()

		// Window is re-sized:
		case termbox.EventResize:
			// Remember the new sizes:
			termWidth = ev.Width
			termHeight = ev.Height

			// Redraw the screen:
			drawBorder(termWidth, termHeight)
			termbox.Flush()

		// Error:
		case termbox.EventError:
			panic(ev.Err)

		default:
		}
	}
}
<commit_msg>Use more accurate name for port parameter<commit_after>package main

import (
	types "./types"
	"flag"
	"fmt"
	"github.com/nsf/termbox-go"
	"os"
	"sync"
	"time"
)

var cassandraHost string
var cassandraPort string

// var messageChannel = make(chan types.LogMessage, 10)
var metricsChannel = make(chan types.CFMetric, 100)
var messageChannel = make(chan types.LogMessage, 100)
var stats = make(map[string]types.CFStats)
var statsMutex sync.Mutex
var dataDisplayed = "Metrics"
var dataSortedBy = "Reads"
var termWidth = 80
var termHeight = 25
var refreshTime = 1 * time.Second

var hostName, _ = os.Hostname()
var portNumber = "8081"

const (
	defaultForeGroundColour = termbox.ColorWhite
	defaultBackGroundColour = termbox.ColorBlack
	messageForeGroundColour = termbox.ColorMagenta
)

func init() {
	// Default to localhost (MX4J needs to be configured to listen to this address in cassandra-env.sh though):
	flag.StringVar(&cassandraHost, "host", hostName, "IP address of the Cassandra host to run against")
	flag.StringVar(&cassandraPort, "mx4j-port", portNumber, "TCP port of the Cassandra host")
}

// Do all the things:
func main() {

	// Set the vars from the command-line args:
	flag.Parse()

	// Check our connection to MX4J:
	if checkConnection(cassandraHost, cassandraPort) != nil {
		fmt.Printf("Can't connect to stats-provider (%s)! Trying localhost before bailing...\n", cassandraHost)
		if checkConnection("localhost", cassandraPort) != nil {
			fmt.Println("Can't even connect to localhost! Check your destination host and port and try again.")
			os.Exit(2)
		} else {
			fmt.Println("Proceeding with localhost..")
			cassandraHost = "localhost"
		}
	}

	// Initialise "termbox" (console interface):
	err := termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	// Get the initial window-size:
	termWidth, termHeight = termbox.Size()

	// Get the display running in the right mode:
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	// Render the initial "UI":
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	drawBorder(termWidth, termHeight)
	termbox.Flush()

	// Run the metrics-collector:
	go MetricsCollector(cassandraHost)
	go handleMetrics()
	go refreshScreen()

loop:
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		// Key pressed:
		case termbox.EventKey:

			// Handle keypresses:
			if ev.Ch == 113 {
				// "q" (quit):
				printfTb(2, 1, messageForeGroundColour, termbox.ColorBlack, "Goodbye!: %s", ev.Ch)
				break loop
			} else if ev.Ch == 0 { // "Space-bar (refresh)"
				showStats()
			} else if ev.Ch == 109 { // "M"
				dataDisplayed = "Metrics"
				showStats()
			} else if ev.Ch == 108 { // "L"
				dataDisplayed = "Logs"
			} else if ev.Ch == 49 { // "1"
				dataSortedBy = "Reads"
			} else if ev.Ch == 50 { // "2"
				dataSortedBy = "Writes"
			} else if ev.Ch == 51 { // "3"
				dataSortedBy = "Space"
			} else if ev.Ch == 52 { // "4"
				dataSortedBy = "ReadLatency"
			} else if ev.Ch == 53 { // "5"
				dataSortedBy = "WriteLatency"
			} else {
				// Anything else:
				handleKeypress(&ev)
			}

			// Redraw the display:
			drawBorder(termWidth, termHeight)
			termbox.Flush()

		// Window is re-sized:
		case termbox.EventResize:
			// Remember the new sizes:
			termWidth = ev.Width
			termHeight = ev.Height

			// Redraw the screen:
			drawBorder(termWidth, termHeight)
			termbox.Flush()

		// Error:
		case termbox.EventError:
			panic(ev.Err)

		default:
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
)

var dryRun = flag.Bool("dry-run", false, "Print the commands that would be run.")

var noRemoveSrcDir = flag.Bool("no-remove-src", false, "Do not remove the source dir after building.")

// We expect 5 arguments on the command line
const NumArgs = 5

func main() {
	flag.Parse()

	if len(flag.Args()) != NumArgs {
		// TODO: need to make the usage describe the args
		flag.Usage()
		os.Exit(1)
	}

	srcDir := flag.Arg(0)
	configFile := flag.Arg(1)
	rootDir := flag.Arg(2)
	project := flag.Arg(3)
	tag := flag.Arg(4)

	buildId := BuildIdAtNow(rootDir, project, tag)

	log.SetOutput(os.Stderr)
	if *dryRun {
		log.Printf("Dry run, will print actions but not take them.")
	}

	createBuildRecord(buildId)

	logFile := configureLogging(buildId)
	defer logFile.Close()

	logStart(buildId)

	config, err := ParseConfigFile(configFile)
	if err != nil {
		logAndDie(fmt.Sprintf("Error parsing config file: %s", err), buildId)
	}

	runBuild(srcDir, config, buildId)
	createTarball(srcDir, buildId)
	removeSrcDir(srcDir)

	// TODO clean up old builds unless told not to

	// TODO update the html
}

func logAndDie(msg string, buildId BuildId) {
	if err := MarkBuildFailed(buildId); err != nil {
		log.Printf("Could not mark build failed in db: %s", err)
	}
	log.Fatalf(msg)
}

func createBuildRecord(buildId BuildId) {
	log.Printf("Creating db record for build.")

	if !*dryRun {
		if err := CreateBuildRecord(buildId); err != nil {
			log.Fatalf("Could not create build record: %s", err)
		}
	}
}

func removeSrcDir(srcDir string) {
	if *noRemoveSrcDir {
		log.Printf("Not removing source dir due to --no-remove-src.")
	} else {
		log.Printf("Removing source dir %s", srcDir)
		if !*dryRun {
			os.RemoveAll(srcDir)
		}
	}
}

func createTarball(srcDir string, buildId BuildId) {
	log.Printf("Tarballing %s into %s", srcDir, FmtTarballPath(buildId))

	if !*dryRun {
		if err := CreateTarball(srcDir, buildId); err != nil {
			logAndDie(fmt.Sprintf("Error creating tarball: %s", err), buildId)
		}
	}
}

func runBuild(srcDir string, config *Config, buildId BuildId) {
	log.Printf("Running build in dir %s with script %s and args %s", srcDir, config.BuildScript, config.BuildScriptArgs)

	if !*dryRun {
		buildOutput, err := RunBuildScript(srcDir, config.BuildScript, config.BuildScriptArgs, config.TimeoutInSecs, buildId)

		if err != nil {
			log.Printf("Completed build with error: %s", err)
			MarkBuildFailed(buildId)
		} else {
			log.Printf("Completed build successfully.")
			MarkBuildSucceeded(buildId)
		}

		log.Printf("Build script stdout in: %s", buildOutput.StdoutPath)
		log.Printf("Build scrip stderr in: %s", buildOutput.StderrPath)
	}
}

func configureLogging(buildId BuildId) *os.File {
	logsDir := FmtLogsDir(buildId)

	log.Printf("Creating logs dir %s with perms 0700", logsDir)

	if !*dryRun {
		// TODO: reconsider permissions
		os.MkdirAll(logsDir, 0700)
	}

	logPath := FmtKerouacLogPath(buildId)

	log.Printf("Creating log at %s", logPath)

	var logFile *os.File
	var err error

	if !*dryRun {
		logFile, err = os.Create(logPath)
		if err != nil {
			log.Fatalf("Logging ironic error, could not configure logging: %s", err)
		}
	}

	log.Printf("Teeing log output to %s and stderr", logPath)

	if !*dryRun {
		writer := io.MultiWriter(os.Stderr, logFile)
		log.SetOutput(writer)
	}

	return logFile
}

func logStart(buildId BuildId) {
	log.Printf("Starting build of %s with tag %s at %s", buildId.Project, buildId.Tag, buildId.DateTime.Format("2006-01-02 15:04:05 (MST)"))
	log.Printf("Build dir is %s", FmtBuildDir(buildId))
}
<commit_msg>Exit with non-0 error code when the build fails.<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
)

var dryRun = flag.Bool("dry-run", false, "Print the commands that would be run.")

var noRemoveSrcDir = flag.Bool("no-remove-src", false, "Do not remove the source dir after building.")

// We expect 5 arguments on the command line
const NumArgs = 5

func main() {
	flag.Parse()

	if len(flag.Args()) != NumArgs {
		// TODO: need to make the usage describe the args
		flag.Usage()
		os.Exit(1)
	}

	srcDir := flag.Arg(0)
	configFile := flag.Arg(1)
	rootDir := flag.Arg(2)
	project := flag.Arg(3)
	tag := flag.Arg(4)

	buildId := BuildIdAtNow(rootDir, project, tag)

	log.SetOutput(os.Stderr)
	if *dryRun {
		log.Printf("Dry run, will print actions but not take them.")
	}

	createBuildRecord(buildId)

	logFile := configureLogging(buildId)
	defer logFile.Close()

	logStart(buildId)

	config, err := ParseConfigFile(configFile)
	if err != nil {
		logAndDie(fmt.Sprintf("Error parsing config file: %s", err), buildId)
	}

	buildSuceeded := runBuild(srcDir, config, buildId)
	createTarball(srcDir, buildId)
	removeSrcDir(srcDir)

	// TODO clean up old builds unless told not to

	// TODO update the html

	if buildSuceeded {
		os.Exit(0)
	} else {
		os.Exit(1)
	}
}

func logAndDie(msg string, buildId BuildId) {
	if err := MarkBuildFailed(buildId); err != nil {
		log.Printf("Could not mark build failed in db: %s", err)
	}
	log.Fatalf(msg)
}

func createBuildRecord(buildId BuildId) {
	log.Printf("Creating db record for build.")

	if !*dryRun {
		if err := CreateBuildRecord(buildId); err != nil {
			log.Fatalf("Could not create build record: %s", err)
		}
	}
}

func removeSrcDir(srcDir string) {
	if *noRemoveSrcDir {
		log.Printf("Not removing source dir due to --no-remove-src.")
	} else {
		log.Printf("Removing source dir %s", srcDir)
		if !*dryRun {
			os.RemoveAll(srcDir)
		}
	}
}

func createTarball(srcDir string, buildId BuildId) {
	log.Printf("Tarballing %s into %s", srcDir, FmtTarballPath(buildId))

	if !*dryRun {
		if err := CreateTarball(srcDir, buildId); err != nil {
			logAndDie(fmt.Sprintf("Error creating tarball: %s", err), buildId)
		}
	}
}

func runBuild(srcDir string, config *Config, buildId BuildId) bool {
	log.Printf("Running build in dir %s with script %s and args %s", srcDir, config.BuildScript, config.BuildScriptArgs)

	succeeded := false

	if !*dryRun {
		buildOutput, err := RunBuildScript(srcDir, config.BuildScript, config.BuildScriptArgs, config.TimeoutInSecs, buildId)

		if err != nil {
			log.Printf("Completed build with error: %s", err)
			MarkBuildFailed(buildId)
		} else {
			log.Printf("Completed build successfully.")
			MarkBuildSucceeded(buildId)
			succeeded = true
		}

		log.Printf("Build script stdout in: %s", buildOutput.StdoutPath)
		log.Printf("Build scrip stderr in: %s", buildOutput.StderrPath)
	}

	return succeeded
}

func configureLogging(buildId BuildId) *os.File {
	logsDir := FmtLogsDir(buildId)

	log.Printf("Creating logs dir %s with perms 0700", logsDir)

	if !*dryRun {
		// TODO: reconsider permissions
		os.MkdirAll(logsDir, 0700)
	}

	logPath := FmtKerouacLogPath(buildId)

	log.Printf("Creating log at %s", logPath)

	var logFile *os.File
	var err error

	if !*dryRun {
		logFile, err = os.Create(logPath)
		if err != nil {
			log.Fatalf("Logging ironic error, could not configure logging: %s", err)
		}
	}

	log.Printf("Teeing log output to %s and stderr", logPath)

	if !*dryRun {
		writer := io.MultiWriter(os.Stderr, logFile)
		log.SetOutput(writer)
	}

	return logFile
}

func logStart(buildId BuildId) {
	log.Printf("Starting build of %s with tag %s at %s", buildId.Project, buildId.Tag, buildId.DateTime.Format("2006-01-02 15:04:05 (MST)"))
	log.Printf("Build dir is %s", FmtBuildDir(buildId))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"github.com/CotaPreco/Horus/command"
	"github.com/CotaPreco/Horus/receiver/udp"
	"github.com/CotaPreco/Horus/util"
	"github.com/CotaPreco/Horus/ws"
	wsc "github.com/CotaPreco/Horus/ws/command"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		// @link https://godoc.org/github.com/gorilla/websocket#hdr-Origin_Considerations
		return true
	},
}

const (
	VERSION = "0.1.0-beta"
)

func main() {
	flag.Usage = func() {
		flag.CommandLine.SetOutput(os.Stdout)

		fmt.Fprintf(os.Stdout, "Horus v.%s\nUsage: horus [...OPTIONS] :-)\n\n", VERSION)
		flag.PrintDefaults()

		os.Exit(0)
	}

	// --
	udpHost := flag.String(
		"receiver-udp-host",
		util.EnvOrDefault("UDP_RECEIVER_HOST", "0.0.0.0"),
		"Defines the host IP for `UdpReceiver`",
	)

	udpReceiverPort, _ := strconv.Atoi(util.EnvOrDefault("UDP_RECEIVER_PORT", "7600"))

	udpPort := flag.Int(
		"receiver-udp-port",
		udpReceiverPort,
		"Defines which port `UdpReceiver` will be listening",
	)

	wsHost := flag.String(
		"ws-host",
		util.EnvOrDefault("WS_HOST", "0.0.0.0"),
		"Where websocket will be available?",
	)

	wsDefaultPort, _ := strconv.Atoi(util.EnvOrDefault("WS_PORT", "8000"))

	wsPort := flag.Int(
		"ws-port",
		wsDefaultPort,
		"And in which port people will connect?",
	)

	flag.Parse()
	// --

	bus := command.NewGenericCommandBus()
	hub := ws.NewTaggedConnectionHub()

	bus.PushHandler(hub)
	bus.PushHandler(wsc.NewARTagCommandRedispatcher(bus))

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)

		if err != nil {
			if _, ok := err.(websocket.HandshakeError); !ok {
				util.Invariant(
					err == nil,
					"...`%s` on attempt to upgrade/handshake connection",
					err,
				)
			}
		}

		defer conn.Close()

		hub.Subscribe(conn)

		for {
			messageType, message, err := conn.ReadMessage()

			if err != nil {
				hub.Unsubscribe(conn)
				return
			}

			// util.Invariant(
			// 	err == nil,
			// 	"... `%s` on `ReadMessage`",
			// 	err,
			// )

			if messageType == websocket.TextMessage {
				bus.Dispatch(wsc.NewSimpleTextCommand(string(message), conn))
			}
		}
	})

	// ---
	receiver := udp.NewUdpReceiver(*udpHost, *udpPort, new(udp.NullByteReceiveStrategy))
	receiver.Attach(hub)

	go receiver.Receive()
	// ---

	err := http.ListenAndServe(
		fmt.Sprintf("%s:%d", *wsHost, *wsPort),
		nil,
	)

	util.Invariant(
		err == nil,
		"...unexpected `%s` (ListenAndServe)",
		err,
	)
}
<commit_msg>Adding `TODO:...` about encapsulating configuration<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"github.com/CotaPreco/Horus/command"
	"github.com/CotaPreco/Horus/receiver/udp"
	"github.com/CotaPreco/Horus/util"
	"github.com/CotaPreco/Horus/ws"
	wsc "github.com/CotaPreco/Horus/ws/command"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		// @link https://godoc.org/github.com/gorilla/websocket#hdr-Origin_Considerations
		return true
	},
}

const (
	VERSION = "0.1.0-beta"
)

func main() {
	flag.Usage = func() {
		flag.CommandLine.SetOutput(os.Stdout)

		fmt.Fprintf(os.Stdout, "Horus v.%s\nUsage: horus [...OPTIONS] :-)\n\n", VERSION)
		flag.PrintDefaults()

		os.Exit(0)
	}

	// --
	// TODO: ...remove setup from main, encapsulate it
	udpHost := flag.String(
		"receiver-udp-host",
		util.EnvOrDefault("UDP_RECEIVER_HOST", "0.0.0.0"),
		"Defines the host IP for `UdpReceiver`",
	)

	udpReceiverPort, _ := strconv.Atoi(util.EnvOrDefault("UDP_RECEIVER_PORT", "7600"))

	udpPort := flag.Int(
		"receiver-udp-port",
		udpReceiverPort,
		"Defines which port `UdpReceiver` will be listening",
	)

	wsHost := flag.String(
		"ws-host",
		util.EnvOrDefault("WS_HOST", "0.0.0.0"),
		"Where websocket will be available?",
	)

	wsDefaultPort, _ := strconv.Atoi(util.EnvOrDefault("WS_PORT", "8000"))

	wsPort := flag.Int(
		"ws-port",
		wsDefaultPort,
		"And in which port people will connect?",
	)

	flag.Parse()
	// --

	bus := command.NewGenericCommandBus()
	hub := ws.NewTaggedConnectionHub()

	bus.PushHandler(hub)
	bus.PushHandler(wsc.NewARTagCommandRedispatcher(bus))

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		conn, err := upgrader.Upgrade(w, r, nil)

		if err != nil {
			if _, ok := err.(websocket.HandshakeError); !ok {
				util.Invariant(
					err == nil,
					"...`%s` on attempt to upgrade/handshake connection",
					err,
				)
			}
		}

		defer conn.Close()

		hub.Subscribe(conn)

		for {
			messageType, message, err := conn.ReadMessage()

			if err != nil {
				hub.Unsubscribe(conn)
				return
			}

			// util.Invariant(
			// 	err == nil,
			// 	"... `%s` on `ReadMessage`",
			// 	err,
			// )

			if messageType == websocket.TextMessage {
				bus.Dispatch(wsc.NewSimpleTextCommand(string(message), conn))
			}
		}
	})

	// ---
	receiver := udp.NewUdpReceiver(*udpHost, *udpPort, new(udp.NullByteReceiveStrategy))
	receiver.Attach(hub)

	go receiver.Receive()
	// ---

	err := http.ListenAndServe(
		fmt.Sprintf("%s:%d", *wsHost, *wsPort),
		nil,
	)

	util.Invariant(
		err == nil,
		"...unexpected `%s` (ListenAndServe)",
		err,
	)
}
<|endoftext|>