<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"strings"

	c "github.com/fatih/color"
	"github.com/fsnotify/fsnotify"
	"github.com/ianschenck/envflag"
	"github.com/urfave/cli"
	"gopkg.in/yaml.v2"
)

var success, notices, triggers, errors *c.Color

func init() {
	success = c.New(c.FgGreen)
	notices = c.New(c.FgBlue)
	triggers = c.New(c.FgYellow)
	errors = c.New(c.FgHiRed)
}

func main() {
	envflag.Parse()
	app := cli.NewApp()

	app.Name = "gotta watch"
	app.Usage = "Run command(s) when files in the folder change."
	app.Action = WatchIt
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "f, folder",
			Value:  ".",
			Usage:  "Folder to watch for changes",
			EnvVar: "GOTTAW_FOLDER",
		},
		cli.StringFlag{
			Name:  "c, config",
			Value: "./.gottaw.yml",
			Usage: "Config file to read",
		},
		cli.StringFlag{
			Name:  "d, delay",
			Value: "1500ms",
			Usage: "Delay of the pipeline action after event",
		},
	}

	app.Run(os.Args)
}

// WatchIt does the work
func WatchIt(c *cli.Context) error {
	var cfg *Config

	configFile := c.String("config")
	if parsed, err := parseConfig(configFile); err != nil {
		panic(err)
	} else if parsed == nil {
		panic(fmt.Errorf("🚨  parsed config is empty: '%s'", configFile))
	} else {
		cfg = parsed
	}
	delay, err := time.ParseDuration(c.String("delay"))
	if err != nil {
		panic(err)
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	watchlist := make(Watchlist)

	done := make(chan bool)
	go func() {
		var timer *time.Timer
		for {
			select {
			case ev := <-watcher.Events:
				if ev.Op&fsnotify.Chmod == fsnotify.Chmod {
					continue
				}
				if ignore, err := isIgnored(ev.Name, cfg); err != nil {
					panic(err)
				} else if ignore {
					continue
				}
				triggers.Printf("🔎  change detected: %s\n", ev.Name)
				if timer == nil {
					timer = time.AfterFunc(delay, createAction(ev, cfg.Pipeline, func() {
						timer = nil
					}))
				} else if timer != nil {
					timer.Reset(delay)
				}

			case err := <-watcher.Errors:
				errors.Printf("error: %v\n", err)
			}
		}

	}()

	if f, err := os.Stat(c.String("folder")); err != nil {
		panic(err)
	} else if err := watchDirRecursive(f.Name(), watcher, watchlist, cfg); err != nil {
		panic(err)
	}
	notices.Printf("watching %d folders.\n", len(watchlist))
	<-done

	return nil
}

func watchDirRecursive(dir string, watcher *fsnotify.Watcher, watchlist Watchlist, cfg *Config) error {
	var recorder filepath.WalkFunc = func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if ignored, err := isIgnored(path, cfg); err != nil {
				return err
			} else if !ignored {
				watchlist[path] = true
				if err := watcher.Add(path); err != nil {
					return err
				}
			}
		}
		return nil
	}
	err := filepath.Walk(dir, recorder)
	return err
}

func createAction(ev fsnotify.Event, pipeline []string, cleanup func()) func() {
	return func() {
		start := time.Now()
		for i, commandStr := range pipeline {
			elements := strings.Split(commandStr, " ")
			command, elements := elements[0], elements[1:]
			cmd := exec.Command(command, elements...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			err := cmd.Start()
			pid := cmd.Process.Pid
			if err != nil {
				errors.Printf("🚨  (%d@%d) ERROR starting '%s': %v", i, pid, commandStr, err)
				break
			}
			notices.Printf("♻  (%d@%d) started '%s'\n", i, pid, commandStr)
			if err := cmd.Wait(); err != nil {
				if exitErr, ok := err.(*exec.ExitError); ok {
					errors.Printf("🚨  (%d@%d) ERROR: %#v", i, pid, exitErr.ProcessState)
				} else {
					errors.Printf("🚨  (%d@%d) ERROR: %#v \n", i, pid, err)
				}
			}

			notices.Printf("♻  (%d@%d) done\n", i, pid)
		}
		dur := time.Since(start)
		success.Printf("✅  Pipeline done after %s\n", dur.String())
		cleanup()
	}
}

func isIgnored(f string, cfg *Config) (bool, error) {
	for _, exclude := range cfg.Excludes {
		if ignore, err := filepath.Match(exclude, f); err != nil {
			return false, err
		} else if ignore {
			//log.Printf("ignoring %s because of %s", f, exclude)
			return true, nil
		}
	}
	//log.Printf("not ignoring %s for %v", f, cfg.Excludes)
	return false, nil
}

func parseConfig(cfgFile string) (*Config, error) {
	var cfg Config
	source, err := ioutil.ReadFile(cfgFile)
	if err != nil {
		return nil, err
	}
	if err := yaml.Unmarshal(source, &cfg); err != nil {
		return nil, err
	}
	return &cfg, nil
}

// Config is the root config object
type Config struct {
	Excludes []string `yaml:"excludes"`
	Pipeline []string `yaml:"pipeline"`
}

type Watchlist map[string]bool
<commit_msg>removes envflag<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"strings"

	c "github.com/fatih/color"
	"github.com/fsnotify/fsnotify"
	"github.com/urfave/cli"
	"gopkg.in/yaml.v2"
)

var success, notices, triggers, errors *c.Color

func init() {
	success = c.New(c.FgGreen)
	notices = c.New(c.FgBlue)
	triggers = c.New(c.FgYellow)
	errors = c.New(c.FgHiRed)
}

func main() {
	app := cli.NewApp()

	app.Name = "gotta watch"
	app.Usage = "Run command(s) when files in the folder change."
	app.Action = WatchIt
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "f, folder",
			Value:  ".",
			Usage:  "Folder to watch for changes",
			EnvVar: "GOTTAW_FOLDER",
		},
		cli.StringFlag{
			Name:  "c, config",
			Value: "./.gottaw.yml",
			Usage: "Config file to read",
		},
		cli.StringFlag{
			Name:  "d, delay",
			Value: "1500ms",
			Usage: "Delay of the pipeline action after event",
		},
	}

	app.Run(os.Args)
}

// WatchIt does the work
func WatchIt(c *cli.Context) error {
	var cfg *Config

	configFile := c.String("config")
	if parsed, err := parseConfig(configFile); err != nil {
		panic(err)
	} else if parsed == nil {
		panic(fmt.Errorf("🚨  parsed config is empty: '%s'", configFile))
	} else {
		cfg = parsed
	}
	delay, err := time.ParseDuration(c.String("delay"))
	if err != nil {
		panic(err)
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		panic(err)
	}
	defer watcher.Close()

	watchlist := make(Watchlist)

	done := make(chan bool)
	go func() {
		var timer *time.Timer
		for {
			select {
			case ev := <-watcher.Events:
				if ev.Op&fsnotify.Chmod == fsnotify.Chmod {
					continue
				}
				if ignore, err := isIgnored(ev.Name, cfg); err != nil {
					panic(err)
				} else if ignore {
					continue
				}
				triggers.Printf("🔎  change detected: %s\n", ev.Name)
				if timer == nil {
					timer = time.AfterFunc(delay, createAction(ev, cfg.Pipeline, func() {
						timer = nil
					}))
				} else if timer != nil {
					timer.Reset(delay)
				}

			case err := <-watcher.Errors:
				errors.Printf("error: %v\n", err)
			}
		}

	}()

	if f, err := os.Stat(c.String("folder")); err != nil {
		panic(err)
	} else if err := watchDirRecursive(f.Name(), watcher, watchlist, cfg); err != nil {
		panic(err)
	}
	notices.Printf("watching %d folders.\n", len(watchlist))
	<-done

	return nil
}

func watchDirRecursive(dir string, watcher *fsnotify.Watcher, watchlist Watchlist, cfg *Config) error {
	var recorder filepath.WalkFunc = func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() {
			if ignored, err := isIgnored(path, cfg); err != nil {
				return err
			} else if !ignored {
				watchlist[path] = true
				if err := watcher.Add(path); err != nil {
					return err
				}
			}
		}
		return nil
	}
	err := filepath.Walk(dir, recorder)
	return err
}

func createAction(ev fsnotify.Event, pipeline []string, cleanup func()) func() {
	return func() {
		start := time.Now()
		for i, commandStr := range pipeline {
			elements := strings.Split(commandStr, " ")
			command, elements := elements[0], elements[1:]
			cmd := exec.Command(command, elements...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			err := cmd.Start()
			pid := cmd.Process.Pid
			if err != nil {
				errors.Printf("🚨  (%d@%d) ERROR starting '%s': %v", i, pid, commandStr, err)
				break
			}
			notices.Printf("♻  (%d@%d) started '%s'\n", i, pid, commandStr)
			if err := cmd.Wait(); err != nil {
				if exitErr, ok := err.(*exec.ExitError); ok {
					errors.Printf("🚨  (%d@%d) ERROR: %#v", i, pid, exitErr.ProcessState)
				} else {
					errors.Printf("🚨  (%d@%d) ERROR: %#v \n", i, pid, err)
				}
			}

			notices.Printf("♻  (%d@%d) done\n", i, pid)
		}
		dur := time.Since(start)
		success.Printf("✅  Pipeline done after %s\n", dur.String())
		cleanup()
	}
}

func isIgnored(f string, cfg *Config) (bool, error) {
	for _, exclude := range cfg.Excludes {
		if ignore, err := filepath.Match(exclude, f); err != nil {
			return false, err
		} else if ignore {
			//log.Printf("ignoring %s because of %s", f, exclude)
			return true, nil
		}
	}
	//log.Printf("not ignoring %s for %v", f, cfg.Excludes)
	return false, nil
}

func parseConfig(cfgFile string) (*Config, error) {
	var cfg Config
	source, err := ioutil.ReadFile(cfgFile)
	if err != nil {
		return nil, err
	}
	if err := yaml.Unmarshal(source, &cfg); err != nil {
		return nil, err
	}
	return &cfg, nil
}

// Config is the root config object
type Config struct {
	Excludes []string `yaml:"excludes"`
	Pipeline []string `yaml:"pipeline"`
}

type Watchlist map[string]bool
<|endoftext|>


<commit_before>/*
Bloggy is a fast and simple blogging environment.

Usage:
	bloggy [flags]

Available flags are:

	--reset
		Reset the blog folder and deletes all files.

	--blog="my-blog"
		Set the source folder for templates and posts.

	--repo="https://github.com/lnsp/example-blog"
		Change the git source repository for new blogs

	-i
		Enables the interactive command line interface.

	-c="certificate"
		Loads the certificate file and enables HTTPS.

	-k="key"
		Loads the private key file. Required if HTTPS is enabled.
*/
package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
)

// DefaultBlogRepository is the default example blog repository.
const DefaultBlogRepository = "https://github.com/lnsp/bloggy-blueprint"

var (
	// GlobalConfig is the global app configuration.
	GlobalConfig BlogConfig
	// BlogFolder is the source folder.
	BlogFolder string
	// Trace logger
	Trace *log.Logger
	// Info logger
	Info *log.Logger
	// Warning logger
	Warning *log.Logger
	// Error logger
	Error *log.Logger
	// Logging flags
	logFlags = log.Ltime | log.Lshortfile
	// Other flags
	resetFlag       = flag.Bool("reset", false, "Resets the blog data")
	folderFlag      = flag.String("blog", "my-blog", "Sets the data source folder")
	repositoryFlag  = flag.String("repo", DefaultBlogRepository, "Change the git source repository for resets")
	interactiveFlag = flag.Bool("i", false, "Runs an interactive CLI")
	certFlag        = flag.String("c", "", "Certificate file for HTTPS")
	keyFlag         = flag.String("k", "", "Private key file for HTTPS")
)

func runCLI() {
	for {
		fmt.Print("> ")
		var command, arg string
		fmt.Scanln(&command, &arg)

		switch command {
		case "reload":
			// Reload all templates and posts
			LoadTemplates()
			LoadPosts()
			Info.Println("Reloaded posts and templates")
		case "stop":
			// Stops the server
			Info.Println("Forcing shutdown")
			os.Exit(1)
		case "debug":
			switch arg {
			case "on":
				logFlags = log.Ldate | log.Ltime | log.Lshortfile
				initLogger(os.Stdout)
				Info.Println("Activated debug mode")
			case "off":
				logFlags = log.Ldate | log.Ltime
				initLogger(ioutil.Discard)
				Info.Println("Deactivated debug mode")
			}
		}
	}
}

func initLogger(traceOutput io.Writer) {
	Trace = log.New(traceOutput, "[Trace] ", log.Ltime|log.Lshortfile)
	Info = log.New(os.Stdout, "[Info] ", log.Ltime|log.Lshortfile)
	Warning = log.New(os.Stdout, "[Warning] ", log.Ltime|log.Lshortfile)
	Error = log.New(os.Stderr, "[Error] ", log.Ltime|log.Lshortfile)
}

// ResetBlog resets the blog, deletes all files and clones the source repo.
func ResetBlog(repository string) error {
	// delete existing folder
	remError := os.RemoveAll(BlogFolder)
	if remError != nil && !os.IsNotExist(remError) {
		return remError
	}

	cloneCmd := exec.Command("git", "clone", repository, BlogFolder)
	// run git
	cloneStartError := cloneCmd.Start()
	// failed to run git
	if cloneStartError != nil {
		return cloneStartError
	}
	// wait for git to finish
	cloneWaitError := cloneCmd.Wait()
	// git runtime error
	if cloneWaitError != nil {
		return cloneWaitError
	}

	return nil
}

func main() {
	initLogger(ioutil.Discard)

	// parse command line arguments
	flag.Parse()

	cwd, err := os.Getwd()
	if err != nil {
		Error.Println("Could not determine working directory")
		os.Exit(1)
	}
	BlogFolder = path.Join(cwd, *folderFlag)
	// check if reset
	if *resetFlag {
		Info.Println("Resetting blog folder:", BlogFolder)
		resetError := ResetBlog(*repositoryFlag)
		if resetError != nil {
			Error.Println("Failed to reset blog:", resetError)
			os.Exit(1)
		}
	}

	// load configuration file from disk
	loadError := LoadConfig()
	if loadError != nil {
		Error.Println("Failed to load configuration:", loadError)
		os.Exit(1)
	}
	// Load all posts and templates
	LoadTemplates()
	LoadPosts()

	// Start interactive command line interface
	if *interactiveFlag {
		go runCLI()
	}
	// Create handler
	router := http.Handler(LoadRoutes())
	if *certFlag != "" {
		// Enable HSTS header if HTTPS is enabled
		router = hstsHandler(router)
		Info.Println("Enabled TLS/SSL using certificates", *certFlag, "and", *keyFlag)
		go func() {
			Error.Println(http.ListenAndServeTLS(GlobalConfig.HostAddressTLS, *certFlag, *keyFlag, router))
		}()
	}
	Error.Println(http.ListenAndServe(GlobalConfig.HostAddress, router))
}
<commit_msg>Reduce declaration space<commit_after>/*
Bloggy is a fast and simple blogging environment.

Usage:
	bloggy [flags]

Available flags are:

	--reset
		Reset the blog folder and deletes all files.

	--blog="my-blog"
		Set the source folder for templates and posts.

	--repo="https://github.com/lnsp/example-blog"
		Change the git source repository for new blogs

	-i
		Enables the interactive command line interface.

	-c="certificate"
		Loads the certificate file and enables HTTPS.

	-k="key"
		Loads the private key file. Required if HTTPS is enabled.
*/
package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
)

// DefaultBlogRepository is the default example blog repository.
const DefaultBlogRepository = "https://github.com/lnsp/bloggy-blueprint"

var (
	// GlobalConfig is the global app configuration.
	GlobalConfig BlogConfig
	// BlogFolder is the source folder.
	BlogFolder string
	// Loggers
	Trace, Info, Warning, Error *log.Logger
	// Logging flags
	logFlags = log.Ltime | log.Lshortfile
	// Other flags
	resetFlag       = flag.Bool("reset", false, "Resets the blog data")
	folderFlag      = flag.String("blog", "my-blog", "Sets the data source folder")
	repositoryFlag  = flag.String("repo", DefaultBlogRepository, "Change the git source repository for resets")
	interactiveFlag = flag.Bool("i", false, "Runs an interactive CLI")
	certFlag        = flag.String("c", "", "Certificate file for HTTPS")
	keyFlag         = flag.String("k", "", "Private key file for HTTPS")
)

func runCLI() {
	for {
		fmt.Print("> ")
		var command, arg string
		fmt.Scanln(&command, &arg)

		switch command {
		case "reload":
			// Reload all templates and posts
			LoadTemplates()
			LoadPosts()
			Info.Println("Reloaded posts and templates")
		case "stop":
			// Stops the server
			Info.Println("Forcing shutdown")
			os.Exit(1)
		case "debug":
			switch arg {
			case "on":
				logFlags = log.Ldate | log.Ltime | log.Lshortfile
				initLogger(os.Stdout)
				Info.Println("Activated debug mode")
			case "off":
				logFlags = log.Ldate | log.Ltime
				initLogger(ioutil.Discard)
				Info.Println("Deactivated debug mode")
			}
		}
	}
}

func initLogger(traceOutput io.Writer) {
	Trace = log.New(traceOutput, "[Trace] ", log.Ltime|log.Lshortfile)
	Info = log.New(os.Stdout, "[Info] ", log.Ltime|log.Lshortfile)
	Warning = log.New(os.Stdout, "[Warning] ", log.Ltime|log.Lshortfile)
	Error = log.New(os.Stderr, "[Error] ", log.Ltime|log.Lshortfile)
}

// ResetBlog resets the blog, deletes all files and clones the source repo.
func ResetBlog(repository string) error {
	// delete existing folder
	remError := os.RemoveAll(BlogFolder)
	if remError != nil && !os.IsNotExist(remError) {
		return remError
	}

	cloneCmd := exec.Command("git", "clone", repository, BlogFolder)
	// run git
	cloneStartError := cloneCmd.Start()
	// failed to run git
	if cloneStartError != nil {
		return cloneStartError
	}
	// wait for git to finish
	cloneWaitError := cloneCmd.Wait()
	// git runtime error
	if cloneWaitError != nil {
		return cloneWaitError
	}

	return nil
}

func main() {
	initLogger(ioutil.Discard)

	// parse command line arguments
	flag.Parse()

	cwd, err := os.Getwd()
	if err != nil {
		Error.Println("Could not determine working directory")
		os.Exit(1)
	}
	BlogFolder = path.Join(cwd, *folderFlag)
	// check if reset
	if *resetFlag {
		Info.Println("Resetting blog folder:", BlogFolder)
		resetError := ResetBlog(*repositoryFlag)
		if resetError != nil {
			Error.Println("Failed to reset blog:", resetError)
			os.Exit(1)
		}
	}

	// load configuration file from disk
	loadError := LoadConfig()
	if loadError != nil {
		Error.Println("Failed to load configuration:", loadError)
		os.Exit(1)
	}
	// Load all posts and templates
	LoadTemplates()
	LoadPosts()

	// Start interactive command line interface
	if *interactiveFlag {
		go runCLI()
	}
	// Create handler
	router := http.Handler(LoadRoutes())
	if *certFlag != "" {
		// Enable HSTS header if HTTPS is enabled
		router = hstsHandler(router)
		Info.Println("Enabled TLS/SSL using certificates", *certFlag, "and", *keyFlag)
		go func() {
			Error.Println(http.ListenAndServeTLS(GlobalConfig.HostAddressTLS, *certFlag, *keyFlag, router))
		}()
	}
	Error.Println(http.ListenAndServe(GlobalConfig.HostAddress, router))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/boredomist/gob/parse"
	"os"
)

var (
	showVersion = flag.Bool("version", false, "Show version info")
	// TODO: other
)

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Println("Gob 0.0.0")
	}

	for _, name := range flag.Args() {
		file, err := os.Open(name)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		parser := parse.NewParser(name, file)

		node, err := parser.Parse()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(*node)
		}
	}

}
<commit_msg>Make version a const<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/boredomist/gob/parse"
	"os"
)

const GOB_VERSION = "0.0.0"

var (
	showVersion = flag.Bool("version", false, "Show version info")
	// TODO: other
)

func main() {
	flag.Parse()

	if *showVersion {
		fmt.Printf("Gob v%s\n", GOB_VERSION)
	}

	for _, name := range flag.Args() {
		file, err := os.Open(name)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		parser := parse.NewParser(name, file)

		node, err := parser.Parse()
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(*node)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"sync"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("Cannot get the user home dir.\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("Cannot open the file %s, due to error '%s'.\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	currentGroupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool {
		return configurationFileStructure.Groups[i].Name == configurationFileStructure.Local.Group
	})
	var newVisibleRepositories []string
	for _, visibleRepository := range configurationFileStructure.VisibleRepositories {
		newVisibleRepositories = append(newVisibleRepositories, visibleRepository.Name)
	}
	configurationFileStructure.Groups[currentGroupIndex].VisibleRepositories = newVisibleRepositories
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("Cannot save the current configurationFile structure!")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("Cannot access to your file to save the configurationFile structure!")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	// var addCmd = &cobra.Command{
	// 	Use:   "add",
	// 	Short: "Add the current path as a VISIBLE repository",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("There was a problem retrieving the current directory")
	// 		}
	// 		if !utils.IsGitRepository(currentDir) {
	// 			log.Fatalf("%s is not a git repository!\n", currentDir)
	// 		}
	// 		if err := configurationFileStructure.Extract(); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// If the path is/contains a .git directory, add this one as a VISIBLE repository
	// 		if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
	// 			traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
	// 		}
	// 	},
	// }

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("There was an error retrieving your git repositories: '%s'\n", err)
			}
			if err := configurationFileStructure.Extract(false); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*loadCmd permits to load visible repositories from the goyave configuration file
	 */
	// var loadCmd = &cobra.Command{
	// 	Use:   "load",
	// 	Short: "Load the configuration file to restore your previous work space",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		currentLocalhost := utils.GetLocalhost()
	// 		fmt.Printf("Current localhost is %s\n", currentLocalhost)
	// 		configGroups := configurationFileStructure.Groups
	// 		var visibleRepositories []string
	// 		for {
	// 			index := utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost })
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
	// 				fmt.Println("Please to choose one of those, to load the configuration file:")
	// 				for _, group := range configGroups {
	// 					fmt.Printf("\t%s\n", group.Name)
	// 				}
	// 				scanner := bufio.NewScanner(os.Stdin)
	// 				currentLocalhost = scanner.Text()
	// 				continue
	// 			} else {
	// 				visibleRepositories = configurationFileStructure.Groups[index].VisibleRepositories
	// 			}
	// 			break
	// 		}
	// 		traces.InfoTracer.Printf("Importing configuration from group %s\n", currentLocalhost)
	// 		for _, visibleRepository := range visibleRepositories {
	// 			traces.InfoTracer.Printf("* Importing %s...\n", visibleRepository)
	// 			index := utils.SliceIndex(len(configurationFileStructure.Repositories), func(i int) bool { return configurationFileStructure.Repositories[i].Name == visibleRepository })
	// 			// Check the local path, and the remote URL
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("\tThe repository \"%s\" does not exists in your configuration file.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// Check if the repository exists locally
	// 			pathRepository, URLRepository := configurationFileStructure.Repositories[index].Path, configurationFileStructure.Repositories[index].URL
	// 			if _, err := os.Stat(pathRepository); err == nil {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" already exists as a local git repository.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// If it does not exists, clone it
	// 			if err := gitManip.Clone(pathRepository, URLRepository); err != nil {
	// 				traces.ErrorTracer.Printf("\tThe repository \"%s\" can't be cloned: %s\n", visibleRepository, err)
	// 			} else {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" has been successfully cloned!\n", visibleRepository)
	// 			}
	// 		}
	// 	},
	// }

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	var pathCmd = &cobra.Command{
		Use:   "path",
		Short: "Get the path of a given repository, if this one exists",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				log.Fatalln("Needs a repository name!")
			}
			repo := args[0]
			if err := configurationFileStructure.Extract(true); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			repoPath := configurationFileStructure.GetPathFromRepository(repo)
			if repoPath != "" {
				fmt.Println(repoPath)
			} else {
				log.Fatalf("The repository %s does not exists!\n", repo)
			}
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			if err := configurationFileStructure.Extract(true); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			var gitStructs []configurationFile.GitRepository
			if len(args) == 0 {
				gitStructs = configurationFileStructure.VisibleRepositories
			} else {
				// Sort visible repositories by name
				sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
				repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
				// Looking for given repository names - if the looking one does not exists, let the function prints a warning message.
				for _, repositoryName := range args {
					repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
					if repositoryIndex != repositoriesListLength {
						gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
					}
				}
			}
			var wg sync.WaitGroup
			for _, gitStruct := range gitStructs {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init(gitStruct.Path)
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	// var switchCmd = &cobra.Command{
	// 	Use:   "switch",
	// 	Short: "Switch the visibility of the current git repository (given by the current path)",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("There was a problem retrieving the current directory")
	// 		}
	// 		if err := configurationFileStructure.Extract(); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.VisibleFlag); err == nil {
	// 			configurationFileStructure.AddRepository(currentDir, consts.HiddenFlag)
	// 			traces.InfoTracer.Printf("%s has been set to an hidden repository!", currentDir)
	// 			return
	// 		}
	// 		if err := configurationFileStructure.RemoveRepositoryFromSlice(currentDir, consts.HiddenFlag); err == nil {
	// 			configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
	// 			traces.InfoTracer.Printf("%s has been set to a visible repository!", currentDir)
	// 			return
	// 		}
	// 		log.Fatalf("The repository %s is not saved as a VISIBLE or HIDDEN repository! Please to add it before.\n", currentDir)
	// 	},
	// }

	rootCmd.AddCommand(crawlCmd, pathCmd, stateCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>Save previous state<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"sort"

	"sync"

	"github.com/BurntSushi/toml"
	"github.com/k0pernicus/goyave/configurationFile"
	"github.com/k0pernicus/goyave/consts"
	"github.com/k0pernicus/goyave/traces"
	"github.com/k0pernicus/goyave/utils"
	"github.com/k0pernicus/goyave/walk"
	"github.com/spf13/cobra"
)

var configurationFileStructure configurationFile.ConfigurationFile
var configurationFilePath string
var userHomeDir string

/*initialize get the configuration file existing in the system (or create it), and return
 *a pointer to his content.
 */
func initialize(configurationFileStructure *configurationFile.ConfigurationFile) {
	// Initialize all different traces structures
	traces.InitTraces(os.Stdout, os.Stderr, os.Stdout, os.Stdout)

	// Get the user home directory
	userHomeDir = utils.GetUserHomeDir()
	if len(userHomeDir) == 0 {
		log.Fatalf("cant get the user home dir\n")
	}
	// Set the configuration path file
	configurationFilePath = path.Join(userHomeDir, consts.ConfigurationFileName)
	filePointer, err := os.OpenFile(configurationFilePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		log.Fatalf("cant open the file %s, due to error '%s'\n", configurationFilePath, err)
	}
	defer filePointer.Close()
	var bytesArray []byte
	// Get the content of the goyave configuration file
	configurationFile.GetConfigurationFileContent(filePointer, &bytesArray)
	if _, err = toml.Decode(string(bytesArray[:]), configurationFileStructure); err != nil {
		log.Fatalln(err)
	}
}

/*kill saves the current state of the configuration structure in the configuration file
 */
func kill() {
	var outputBuffer bytes.Buffer
	currentGroupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool {
		return configurationFileStructure.Groups[i].Name == configurationFileStructure.Local.Group
	})
	var newVisibleRepositories []string
	for _, visibleRepository := range configurationFileStructure.VisibleRepositories {
		newVisibleRepositories = append(newVisibleRepositories, visibleRepository.Name)
	}
	configurationFileStructure.Groups[currentGroupIndex].VisibleRepositories = newVisibleRepositories
	if err := configurationFileStructure.Encode(&outputBuffer); err != nil {
		log.Fatalln("can't save the current configurationFile structure")
	}
	if err := ioutil.WriteFile(configurationFilePath, outputBuffer.Bytes(), 0777); err != nil {
		log.Fatalln("can't access to your file to save the configurationFile structure")
	}
}

func main() {

	/*rootCmd defines the global app, and some actions to run before and after the command running
	 */
	var rootCmd = &cobra.Command{
		Use:   "goyave",
		Short: "Goyave is a tool to take a look at your local git repositories",
		// Initialize the structure
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			initialize(&configurationFileStructure)
		},
		// Save the current configuration file structure, in the configuration file
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			kill()
		},
	}

	/*addCmd is a subcommand to add the current working directory as a VISIBLE one
	 */
	// var addCmd = &cobra.Command{
	// 	Use:   "add",
	// 	Short: "Add the current path as a VISIBLE repository",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("There was a problem retrieving the current directory")
	// 		}
	// 		if !utils.IsGitRepository(currentDir) {
	// 			log.Fatalf("%s is not a git repository!\n", currentDir)
	// 		}
	// 		if err := configurationFileStructure.Extract(); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// If the path is/contains a .git directory, add this one as a VISIBLE repository
	// 		if err := configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag); err != nil {
	// 			traces.WarningTracer.Printf("[%s] %s\n", currentDir, err)
	// 		}
	// 	},
	// }

	/*crawlCmd is a subcommand to crawl your hard drive in order to get and save new git repositories
	 */
	var crawlCmd = &cobra.Command{
		Use:   "crawl",
		Short: "Crawl the hard drive in order to find git repositories",
		Run: func(cmd *cobra.Command, args []string) {
			var wg sync.WaitGroup
			// Get all git paths, and display them
			gitPaths, err := walk.RetrieveGitRepositories(userHomeDir)
			if err != nil {
				log.Fatalf("there was an error retrieving your git repositories: '%s'\n", err)
			}
			if err := configurationFileStructure.Extract(false); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			// For each git repository, check if it exists, and if not add it to the default target visibility
			for _, gitPath := range gitPaths {
				wg.Add(1)
				go func(gitPath string) {
					defer wg.Done()
					if err := configurationFileStructure.AddRepository(gitPath, configurationFileStructure.Local.DefaultTarget); err != nil {
						traces.WarningTracer.Printf("[%s] %s\n", gitPath, err)
					}
				}(gitPath)
			}
			wg.Wait()
		},
	}

	/*loadCmd permits to load visible repositories from the goyave configuration file
	 */
	// var loadCmd = &cobra.Command{
	// 	Use:   "load",
	// 	Short: "Load the configuration file to restore your previous work space",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		currentLocalhost := utils.GetLocalhost()
	// 		fmt.Printf("Current localhost is %s\n", currentLocalhost)
	// 		configGroups := configurationFileStructure.Groups
	// 		var visibleRepositories []string
	// 		for {
	// 			index := utils.SliceIndex(len(configGroups), func(i int) bool { return configGroups[i].Name == currentLocalhost })
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("Your current local host (%s) has not been found!", currentLocalhost)
	// 				fmt.Println("Please to choose one of those, to load the configuration file:")
	// 				for _, group := range configGroups {
	// 					fmt.Printf("\t%s\n", group.Name)
	// 				}
	// 				scanner := bufio.NewScanner(os.Stdin)
	// 				currentLocalhost = scanner.Text()
	// 				continue
	// 			} else {
	// 				visibleRepositories = configurationFileStructure.Groups[index].VisibleRepositories
	// 			}
	// 			break
	// 		}
	// 		traces.InfoTracer.Printf("Importing configuration from group %s\n", currentLocalhost)
	// 		for _, visibleRepository := range visibleRepositories {
	// 			traces.InfoTracer.Printf("* Importing %s...\n", visibleRepository)
	// 			index := utils.SliceIndex(len(configurationFileStructure.Repositories), func(i int) bool { return configurationFileStructure.Repositories[i].Name == visibleRepository })
	// 			// Check the local path, and the remote URL
	// 			if index == -1 {
	// 				traces.WarningTracer.Printf("\tThe repository \"%s\" does not exists in your configuration file.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// Check if the repository exists locally
	// 			pathRepository, URLRepository := configurationFileStructure.Repositories[index].Path, configurationFileStructure.Repositories[index].URL
	// 			if _, err := os.Stat(pathRepository); err == nil {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" already exists as a local git repository.\n", visibleRepository)
	// 				continue
	// 			}
	// 			// If it does not exists, clone it
	// 			if err := gitManip.Clone(pathRepository, URLRepository); err != nil {
	// 				traces.ErrorTracer.Printf("\tThe repository \"%s\" can't be cloned: %s\n", visibleRepository, err)
	// 			} else {
	// 				traces.InfoTracer.Printf("\tThe repository \"%s\" has been successfully cloned!\n", visibleRepository)
	// 			}
	// 		}
	// 	},
	// }

	/*pathCmd is a subcommand to get the path of a given git repository.
	 *This subcommand is useful to change directory, like `cd $(goyave path mygitrepo)`
	 */
	var pathCmd = &cobra.Command{
		Use:   "path",
		Short: "Get the path of a given repository, if this one exists",
		Run: func(cmd *cobra.Command, args []string) {
			if len(args) == 0 {
				log.Fatalln("Needs a repository name!")
			}
			repo := args[0]
			if err := configurationFileStructure.Extract(true); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			repoPath := configurationFileStructure.GetPathFromRepository(repo)
			if repoPath != "" {
				fmt.Println(repoPath)
			} else {
				log.Fatalf("the repository %s does not exists\n", repo)
			}
		},
	}

	/*stateCmd is a subcommand to list the state of each local git repository.
	 */
	var stateCmd = &cobra.Command{
		Use:     "state",
		Example: "goyave state\ngoyave state myRepositoryName\ngoyave state myRepositoryName1 myRepositoryName2",
		Short:   "Get the state of each local visible git repository",
		Long:    "Check only visible git repositories.\nIf some repository names have been setted, goyave will only check those repositories, otherwise it checks all visible repositories of your system.",
		Run: func(cmd *cobra.Command, args []string) {
			if err := configurationFileStructure.Extract(true); err != nil {
				traces.ErrorTracer.Fatalln(err)
			}
			var gitStructs []configurationFile.GitRepository
			if len(args) == 0 {
				gitStructs = configurationFileStructure.VisibleRepositories
			} else {
				// Sort visible repositories by name
				sort.Sort(configurationFile.ByName(configurationFileStructure.VisibleRepositories))
				repositoriesListLength := len(configurationFileStructure.VisibleRepositories)
				// Looking for given repository names - if the looking one does not exists, let the function prints a warning message.
				for _, repositoryName := range args {
					repositoryIndex := sort.Search(repositoriesListLength, func(i int) bool { return configurationFileStructure.VisibleRepositories[i].Name >= repositoryName })
					if repositoryIndex != repositoriesListLength {
						gitStructs = append(gitStructs, configurationFileStructure.VisibleRepositories[repositoryIndex])
					} else {
						traces.WarningTracer.Printf("%s cannot be found in your visible repositories!\n", repositoryName)
					}
				}
			}
			var wg sync.WaitGroup
			for _, gitStruct := range gitStructs {
				wg.Add(1)
				go func(gitStruct configurationFile.GitRepository) {
					defer wg.Done()
					gitStruct.Init(gitStruct.Path)
					gitStruct.GitObject.Status()
				}(gitStruct)
			}
			wg.Wait()
		},
	}

	/*switchCmd is a subcommand to switch the visibility of the current git repository.
	 */
	// var switchCmd = &cobra.Command{
	// 	Use:   "switch",
	// 	Short: "Switch the visibility of the current git repository (given by the current path)",
	// 	Run: func(cmd *cobra.Command, args []string) {
	// 		// Get the path where the command has been executed
	// 		currentDir, err := os.Getwd()
	// 		if err != nil {
	// 			log.Fatalln("there was a problem retrieving the current directory")
	// 		}
	// 		if err := configurationFileStructure.Extract(true); err != nil {
	// 			traces.ErrorTracer.Fatalln(err)
	// 		}
	// 		// Recognizing the repository in the configuration file
	// 		repositoryName := filepath.Base(currentDir)
	// 		localRepositories := configurationFileStructure.Repositories
	// 		repositoryPathIndex := utils.SliceIndex(len(localRepositories), func(i int) bool { return localRepositories[i].Name == repositoryName })
	// 		if repositoryPathIndex == -1 {
	// 			log.Fatalf("the repository '%s' does not exists in the configuration file", filepath.Base(currentDir))
	// 			os.Exit(2)
	// 		}
	// 		repositoryGroupIndex := utils.SliceIndex(len(localRepositories[repositoryPathIndex].Paths), func(i int) bool { return localRepositories[repositoryPathIndex].Paths[i].Path == currentDir })
	// 		if repositoryGroupIndex == -1 {
	// 			log.Fatalf("the file path '%s' does not exists in the configuration file", currentDir)
	// 			os.Exit(2)
	// 		}
	// 		// The repository is now recognized
	// 		currentGroupName := utils.GetLocalhost()
	// 		groupIndex := utils.SliceIndex(len(configurationFileStructure.Groups), func(i int) bool { return configurationFileStructure.Groups[i].Name == currentGroupName })
	// 		if groupIndex == -1 {
	// 			log.Fatalln("your localhost is not recognized, please to crawl first")
	// 			os.Exit(2)
	// 		}
	// 		visibleRepositories := configurationFileStructure.VisibleRepositories
	// 		// visibleRepositories := configurationFileStructure.Groups[groupIndex].VisibleRepositories
	// 		repositoryIndex := utils.SliceIndex(len(visibleRepositories), func(i int) bool { return visibleRepositories[i].Name == repositoryName })
	// 		if repositoryIndex == -1 {
	// 			configurationFileStructure.AddRepository(currentDir, consts.VisibleFlag)
	// 			fmt.Printf("The repository %s has been added!\n", repositoryName)
	// 		} else {
	// 			configurationFileStructure.VisibleRepositories = append(visibleRepositories[:repositoryIndex], visibleRepositories[repositoryIndex+1:]...)
	// 			fmt.Printf("The repository %s has been removed!\n", repositoryName)
	// 		}
	// 		fmt.Println(configurationFileStructure.VisibleRepositories)
	// 	},
	// }

	rootCmd.AddCommand(crawlCmd, pathCmd, stateCmd)

	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

// lasso
// github.com/bnfinet/lasso

import (
	"net/http"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/bnfinet/lasso/handlers"
	"github.com/bnfinet/lasso/pkg/cfg"
	"github.com/bnfinet/lasso/pkg/timelog"
	tran "github.com/bnfinet/lasso/pkg/transciever"
)

func main() {
	log.Info("starting lasso")
	mux := http.NewServeMux()
	// router := mux.NewRouter()
	// router.HandleFunc("/", handlers.IndexHandler)

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	mux.HandleFunc("/validate", timelog.TimeLog(authH))
	// mux.HandleFunc("/validate", handlers.ValidateRequestHandler)

	loginH := http.HandlerFunc(handlers.LoginHandler)
	mux.HandleFunc("/login", timelog.TimeLog(loginH))

	gcallH := http.HandlerFunc(handlers.GCallbackHandler)
	mux.HandleFunc("/auth", timelog.TimeLog(gcallH))

	// router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	mux.Handle("/static", http.FileServer(http.Dir("./static")))

	mux.Handle("/ws", tran.WS)

	// socketio := tran.NewServer()
	// mux.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	log.Infof("running lasso on %s", listen)

	srv := &http.Server{
		Handler: mux,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())

}
<commit_msg>logout endpoint<commit_after>package main

// lasso
// github.com/bnfinet/lasso

import (
	"net/http"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/bnfinet/lasso/handlers"
	"github.com/bnfinet/lasso/pkg/cfg"
	"github.com/bnfinet/lasso/pkg/timelog"
	tran "github.com/bnfinet/lasso/pkg/transciever"
)

func main() {
	log.Info("starting lasso")
	mux := http.NewServeMux()
	// router := mux.NewRouter()
	// router.HandleFunc("/", handlers.IndexHandler)

	authH := http.HandlerFunc(handlers.ValidateRequestHandler)
	mux.HandleFunc("/validate", timelog.TimeLog(authH))
	// mux.HandleFunc("/validate", handlers.ValidateRequestHandler)

	loginH := http.HandlerFunc(handlers.LoginHandler)
	mux.HandleFunc("/login", timelog.TimeLog(loginH))

	logoutH := http.HandlerFunc(handlers.LogoutHandler)
	mux.HandleFunc("/logout", timelog.TimeLog(logoutH))

	callH := http.HandlerFunc(handlers.CallbackHandler)
	mux.HandleFunc("/auth", timelog.TimeLog(callH))

	// router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
	mux.Handle("/static", http.FileServer(http.Dir("./static")))

	mux.Handle("/ws", tran.WS)

	// socketio := tran.NewServer()
	// mux.Handle("/socket.io/", cors.AllowAll(socketio))
	// http.Handle("/socket.io/", tran.Server)

	var listen = cfg.Cfg.Listen + ":" + strconv.Itoa(cfg.Cfg.Port)
	log.Infof("running lasso on %s", listen)

	srv := &http.Server{
		Handler: mux,
		Addr:    listen,
		// Good practice: enforce timeouts for servers you create!
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	log.Fatal(srv.ListenAndServe())

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/codegangsta/martini"
	"github.com/donovanhide/eventsource"
	"github.com/monnand/goredis"
)

type Message struct {
	Idx           string
	Channel, Html string
}

func (c *Message) Id() string    { return c.Idx }
func (c *Message) Event() string { return c.Channel }
func (c *Message) Data() string {
	b, _ := json.Marshal(c)
	return string(b)
}

type IdGenerator struct {
	val int
}

func (idg *IdGenerator) Next() int {
	idg.val += 1
	return idg.val
}

var client goredis.Client

// Proxy all messages to `debug` Channel on the EventSource Server.
// TODO (yml): Delete this function when we are out of the POC
func proxyAllMessages(srv *eventsource.Server, messages <-chan goredis.Message) {
	idx := IdGenerator{}
	for {
		select {
		case msg := <-messages:
			message := &Message{
				Idx:     strconv.Itoa(idx.Next()),
				Channel: msg.Channel,
				Html:    string(msg.Message),
			}
			srv.Publish([]string{"debug"}, message)
		}
	}
}

func main() {
	srv := eventsource.NewServer()
	defer srv.Close()

	psub := make(chan string, 1)
	psub <- "channel_update:*"
	messages := make(chan goredis.Message, 0)

	fmt.Println("Start listening to redis Publication BUS for: `channel_update:*`")
	go client.Subscribe(nil, nil, psub, nil, messages)

	// Start a goroutine that proxy all messages from `channel_update:*` to debug eventsource Channel
	go proxyAllMessages(srv, messages)

	m := martini.Classic()
	// eventsource endpoints
	m.Get("/:channel/eventsource", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		srv.Handler(params["channel"])(w, req)
	})
	m.Run()

}
<commit_msg>Restricted the debug channel to small subset of public channel<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"

	"github.com/codegangsta/martini"
	"github.com/donovanhide/eventsource"
	"github.com/monnand/goredis"
)

type Message struct {
	Idx           string
	Channel, Html string
}

func (c *Message) Id() string    { return c.Idx }
func (c *Message) Event() string { return c.Channel }
func (c *Message) Data() string {
	b, _ := json.Marshal(c)
	return string(b)
}

type IdGenerator struct {
	val int
}

func (idg *IdGenerator) Next() int {
	idg.val += 1
	return idg.val
}

var client goredis.Client

// Proxy all messages to `debug` Channel on the EventSource Server.
// TODO (yml): Delete this function when we are out of the POC
func proxyAllMessages(srv *eventsource.Server, messages <-chan goredis.Message) {
	idx := IdGenerator{}
	for {
		select {
		case msg := <-messages:
			message := &Message{
				Idx:     strconv.Itoa(idx.Next()),
				Channel: msg.Channel,
				Html:    string(msg.Message),
			}
			srv.Publish([]string{"debug"}, message)
		}
	}
}

func main() {
	srv := eventsource.NewServer()
	defer srv.Close()

	psub := make(chan string, 0)
	messages := make(chan goredis.Message, 0)

	fmt.Println("Start listening to redis Publication BUS for: `channel_update:*`")
	go client.Subscribe(nil, nil, psub, nil, messages)

	// Listening to all channel updates
	// psub <- "channel_update:*"

	// TODO (yml) remove after debuging  only go-nuts, rust and docker for now
	psub <- "channel_update:5"  // go-nuts
	psub <- "channel_update:33" //rust
	psub <- "channel_update:31" //docker

	// Start a goroutine that proxy all messages from `channel_update:*` to debug eventsource Channel
	go proxyAllMessages(srv, messages)

	m := martini.Classic()
	// eventsource endpoints
	m.Get("/:channel/eventsource", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		//TODO
		srv.Handler(params["channel"])(w, req)
	})
	m.Run()

}
<|endoftext|>


<commit_before>/*
七牛本地上传客户端
$ qn_cli --help
*/
package main

import (
	"crypto/md5"
	"encoding/hex"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"golang.org/x/net/context"
	"qiniupkg.com/api.v7/kodo"
	"qiniupkg.com/api.v7/kodocli"
)

const Version string = "0.4.0"

var ignorePaths = []string{
	".git", ".hg", ".svn", ".module-cache", ".bin",
}

type stringSlice []string

func (s *stringSlice) String() string {
	return fmt.Sprintf("%s", *s)
}
func (s *stringSlice) Set(value string) error {
	*s = append(*s, value)
	return nil
}

// 生成上传 token
func genUpToken(a *args, c *kodo.Client, key string) string {
	policy := kodo.PutPolicy{
		Scope: a.bucketName,
		// ReturnBody: `{"bucket": $(bucket),"key": $(key)}`,
		DetectMime: 1,
	}
	if key != "" {
		policy.SaveKey = key
		if a.overwrite {
			policy.Scope = policy.Scope + ":" + key
			policy.InsertOnly = 0
		}
	}
	return c.MakeUptoken(&policy)
}

// 上传本地文件
func uploadFile(
	uploader kodocli.Uploader, ctx context.Context, localFile, key, uptoken string) (ret *kodocli.PutRet, err error) {
	ret = &kodocli.PutRet{}
	if key == "" {
		err = uploader.PutFileWithoutKey(ctx, ret, uptoken, localFile, nil)
	} else {
		err = uploader.PutFile(ctx, ret, uptoken, key, localFile, nil)
	}
	return
}

// 自动生成文件名
func autoFileName(p string) (string, string, string) {
	dirname, name := path.Split(p)
	ext := path.Ext(name)
	return dirname, name, ext
}

func autoMD5FileName(p string) string {
	dirname, oldName, ext := autoFileName(p)
	now := int(time.Now().Nanosecond())
	hash := md5.Sum([]byte(
		strconv.Itoa(now),
	))
	newName := dirname + oldName + "_" + hex.EncodeToString(hash[:]) + ext
	return newName
}

func walkFiles(files []string, ignorePaths []string) (fileSlice []string) {
	for _, file := range files {
		matches, err := filepath.Glob(file)
		if err == nil {

			for _, path := range matches {
				// 遍历目录
				err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
					if err != nil {
						log.Print(err)
						return nil
					}

					// ignore ignorePaths
					for _, i := range ignorePaths {
						p := filepath.Base(path)
						if m, _ := filepath.Match(i, p); m {
							if info.IsDir() {
								return filepath.SkipDir
							}
							return nil
						}
					}
					if info.IsDir() {
						return nil
					}

					fileSlice = append(fileSlice, path)
					return nil
				})
				if err != nil {
					log.Print(err)
				}
			}
		}
	}

	return
}

func finalURL(bucketURL, key string) (url string) {
	return bucketURL + key
}

type args struct {
	bucketName  string
	bucketURL   string
	fileSlice   []string
	key         string
	autoName    bool
	autoMD5Name bool
	overwrite   bool
	saveDir     string
	verbose     bool
	maxTasks    int
}

func parseArgs() *args {
	// 保存名称
	saveName := flag.String("n", "", "Save name")
	saveDir := flag.String("d", "", "Save dirname")
	autoName := flag.Bool("a", true, "Auto named saved files")
	autoMD5Name := flag.Bool("md5", false, "Auto named saved files use MD5 value")
	overwrite := flag.Bool("w", true, "Overwrite exists files")
	verbose := flag.Bool("v", false, "Verbose mode")
	version := flag.Bool("V", false, "Version info")
	maxTasks := flag.Int("max-tasks", 5, "Max upload tasks")
	var ignores stringSlice
	flag.Var(&ignores, "i", "ignores")

	flag.Parse()
	if *version {
		fmt.Println("qn_cli " + Version)
		os.Exit(0)
	}

	files := flag.Args()

	bucketName := os.Getenv("QINIU_BUCKET_NAME")
	bucketURL := os.Getenv("QINIU_BUCKET_URL")
	accessKey := os.Getenv("QINIU_ACCESS_KEY")
	secretKey := os.Getenv("QINIU_SECRET_KEY")
	if *verbose {
		fmt.Printf("bucketName: %s\n", bucketName)
		fmt.Printf("bucketURL: %s\n", bucketURL)
		fmt.Printf("accessKey: %s\n", accessKey)
		fmt.Printf("secretKey: %s\n", secretKey)
	}

	key := *saveName
	// 支持通配符
	fileSlice := walkFiles(files, ignorePaths)

	if len(fileSlice) == 0 {
		flag.PrintDefaults()
		fmt.Println("need files: qn_cli FILE [FILE ...]")
		os.Exit(1)
	}

	// 配置 accessKey, secretKey
	kodo.SetMac(accessKey, secretKey)
	if len(ignores) != 0 {
		ignorePaths = append(ignorePaths, ignores...)
	}

	return &args{
		bucketName:  bucketName,
		bucketURL:   bucketURL,
		fileSlice:   fileSlice,
		key:         key,
		autoName:    *autoName,
		autoMD5Name: *autoMD5Name,
		overwrite:   *overwrite,
		saveDir:     *saveDir,
		verbose:     *verbose,
		maxTasks:    *maxTasks,
	}
}

func main() {
	a := parseArgs()
	if a.verbose {
		fmt.Println(a)
	}

	// 定义任务组
	var wg sync.WaitGroup
	cts := 1

	// 上传文件
	for _, file := range a.fileSlice {
		// 正在上传的任务数超出了限制，等待上传完成
		if cts > a.maxTasks {
			wg.Wait()
		}

		// 增加一个任务
		wg.Add(1)
		cts++

		// 使用 goroutine 异步执行上传任务
		go func(file string) {
			defer wg.Done()          // 标记任务完成
			defer func() { cts-- }() // 正在进行的任务数减一

			key := a.key
			zone := 0
			c := kodo.New(zone, nil)
			uploader := kodocli.NewUploader(zone, nil)
			ctx := context.Background()

			if a.autoMD5Name && key == "" {
				key = autoMD5FileName(file)
			} else if a.autoName && key == "" {
				key = file
			}
			if a.saveDir != "" {
				key = path.Join(a.saveDir, key)
			}
			token := genUpToken(a, c, key)

			// 上传文件
			ret, err := uploadFile(uploader, ctx, file, key, token)
			if err != nil {
				if a.verbose {
					fmt.Printf("%s: %s ✕\n", file, err)
				} else {
					fmt.Printf("%s ✕\n", file)
				}
				log.Fatal(err)
			} else {
				url := finalURL(a.bucketURL, ret.Key)
				if a.verbose {
					fmt.Printf("%s: %s ✓\n", file, url)
				} else {
					fmt.Printf("%s\n", url)
				}
			}
		}(file)
	}

	// 等待所有任务完成
	wg.Wait()
}
<commit_msg>fixed #4<commit_after>/*
七牛本地上传客户端
$ qn_cli --help
*/
package main

import (
	"crypto/md5"
	"encoding/hex"
	"flag"
	"fmt"
	"log"
	url2 "net/url"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"sync"
	"time"

	"golang.org/x/net/context"
	"qiniupkg.com/api.v7/kodo"
	"qiniupkg.com/api.v7/kodocli"
)

const Version string = "0.4.0"

var ignorePaths = []string{
	".git", ".hg", ".svn", ".module-cache", ".bin",
}

type stringSlice []string

func (s *stringSlice) String() string {
	return fmt.Sprintf("%s", *s)
}
func (s *stringSlice) Set(value string) error {
	*s = append(*s, value)
	return nil
}

// 生成上传 token
func genUpToken(a *args, c *kodo.Client, key string) string {
	policy := kodo.PutPolicy{
		Scope: a.bucketName,
		// ReturnBody: `{"bucket": $(bucket),"key": $(key)}`,
		DetectMime: 1,
	}
	if key != "" {
		policy.SaveKey = key
		if a.overwrite {
			policy.Scope = policy.Scope + ":" + key
			policy.InsertOnly = 0
		}
	}
	return c.MakeUptoken(&policy)
}

// 上传本地文件
func uploadFile(
	uploader kodocli.Uploader, ctx context.Context, localFile, key, uptoken string) (ret *kodocli.PutRet, err error) {
	ret = &kodocli.PutRet{}
	if key == "" {
		err = uploader.PutFileWithoutKey(ctx, ret, uptoken, localFile, nil)
	} else {
		err = uploader.PutFile(ctx, ret, uptoken, key, localFile, nil)
	}
	return
}

// 自动生成文件名
func autoFileName(p string) (string, string, string) {
	dirname, name := path.Split(p)
	ext := path.Ext(name)
	return dirname, name, ext
}

func autoMD5FileName(p string) string {
	dirname, oldName, ext := autoFileName(p)
	now := int(time.Now().Nanosecond())
	hash := md5.Sum([]byte(
		strconv.Itoa(now),
	))
	newName := dirname + oldName + "_" + hex.EncodeToString(hash[:]) + ext
	return newName
}

func walkFiles(files []string, ignorePaths []string) (fileSlice []string) {
	for _, file := range files {
		matches, err := filepath.Glob(file)
		if err == nil {

			for _, path := range matches {
				// 遍历目录
				err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
					if err != nil {
						log.Print(err)
						return nil
					}

					// ignore ignorePaths
					for _, i := range ignorePaths {
						p := filepath.Base(path)
						if m, _ := filepath.Match(i, p); m {
							if info.IsDir() {
								return filepath.SkipDir
							}
							return nil
						}
					}
					if info.IsDir() {
						return nil
					}

					fileSlice = append(fileSlice, path)
					return nil
				})
				if err != nil {
					log.Print(err)
				}
			}
		}
	}

	return
}

func finalURL(bucketURL, key string) (url string) {
	u, _ := url2.Parse(bucketURL + key)
	url = u.String()
	return
}

type args struct {
	bucketName  string
	bucketURL   string
	fileSlice   []string
	key         string
	autoName    bool
	autoMD5Name bool
	overwrite   bool
	saveDir     string
	verbose     bool
	maxTasks    int
}

func parseArgs() *args {
	// 保存名称
	saveName := flag.String("n", "", "Save name")
	saveDir := flag.String("d", "", "Save dirname")
	autoName := flag.Bool("a", true, "Auto named saved files")
	autoMD5Name := flag.Bool("md5", false, "Auto named saved files use MD5 value")
	overwrite := flag.Bool("w", true, "Overwrite exists files")
	verbose := flag.Bool("v", false, "Verbose mode")
	version := flag.Bool("V", false, "Version info")
	maxTasks := flag.Int("max-tasks", 5, "Max upload tasks")
	var ignores stringSlice
	flag.Var(&ignores, "i", "ignores")

	flag.Parse()
	if *version {
		fmt.Println("qn_cli " + Version)
		os.Exit(0)
	}

	files := flag.Args()

	bucketName := os.Getenv("QINIU_BUCKET_NAME")
	bucketURL := os.Getenv("QINIU_BUCKET_URL")
	accessKey := os.Getenv("QINIU_ACCESS_KEY")
	secretKey := os.Getenv("QINIU_SECRET_KEY")
	if *verbose {
		fmt.Printf("bucketName: %s\n", bucketName)
		fmt.Printf("bucketURL: %s\n", bucketURL)
		fmt.Printf("accessKey: %s\n", accessKey)
		fmt.Printf("secretKey: %s\n", secretKey)
	}

	key := *saveName
	// 支持通配符
	fileSlice := walkFiles(files, ignorePaths)

	if len(fileSlice) == 0 {
		flag.PrintDefaults()
		fmt.Println("need files: qn_cli FILE [FILE ...]")
		os.Exit(1)
	}

	// 配置 accessKey, secretKey
	kodo.SetMac(accessKey, secretKey)
	if len(ignores) != 0 {
		ignorePaths = append(ignorePaths, ignores...)
	}

	return &args{
		bucketName:  bucketName,
		bucketURL:   bucketURL,
		fileSlice:   fileSlice,
		key:         key,
		autoName:    *autoName,
		autoMD5Name: *autoMD5Name,
		overwrite:   *overwrite,
		saveDir:     *saveDir,
		verbose:     *verbose,
		maxTasks:    *maxTasks,
	}
}

func main() {
	a := parseArgs()
	if a.verbose {
		fmt.Println(a)
	}

	// 定义任务组
	var wg sync.WaitGroup
	cts := 1

	// 上传文件
	for _, file := range a.fileSlice {
		// 正在上传的任务数超出了限制，等待上传完成
		if cts > a.maxTasks {
			wg.Wait()
		}

		// 增加一个任务
		wg.Add(1)
		cts++

		// 使用 goroutine 异步执行上传任务
		go func(file string) {
			defer wg.Done()          // 标记任务完成
			defer func() { cts-- }() // 正在进行的任务数减一

			key := a.key
			zone := 0
			c := kodo.New(zone, nil)
			uploader := kodocli.NewUploader(zone, nil)
			ctx := context.Background()

			if a.autoMD5Name && key == "" {
				key = autoMD5FileName(file)
			} else if a.autoName && key == "" {
				key = file
			}
			if a.saveDir != "" {
				key = path.Join(a.saveDir, key)
			}
			token := genUpToken(a, c, key)

			// 上传文件
			ret, err := uploadFile(uploader, ctx, file, key, token)
			if err != nil {
				if a.verbose {
					fmt.Printf("%s: %s ✕\n", file, err)
				} else {
					fmt.Printf("%s ✕\n", file)
				}
				log.Fatal(err)
			} else {
				url := finalURL(a.bucketURL, ret.Key)
				if a.verbose {
					fmt.Printf("%s: %s ✓\n", file, url)
				} else {
					fmt.Printf("%s\n", url)
				}
			}
		}(file)
	}

	// 等待所有任务完成
	wg.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2013 mongoapi 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 main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"log"
	"net/http"
)

const version = "0.1"

var printVersion bool

func init() {
	flag.BoolVar(&printVersion, "v", false, "Print version and exit")
	flag.Parse()
}

func buildMux() *pat.PatternServeMux {
	m := pat.New()
	m.Post("/resources", http.HandlerFunc(Add))
	m.Post("/resources/:name", Handler(Bind))
	m.Del("/resources/:name/hostname/:hostname", Handler(Unbind))
	m.Del("/resources/:name", Handler(Remove))
	m.Get("/resources/:name/status", Handler(Status))
	return m
}

func main() {
	if printVersion {
		fmt.Printf("mongoapi version %s", version)
		return
	}
	listen := coalesceEnv("0.0.0.0:3333", "MONGODB_API_LISTEN")
	log.Fatal(http.ListenAndServe(listen, buildMux()))
}
<commit_msg>main: change version scheme<commit_after>// Copyright 2013 mongoapi 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 main

import (
	"flag"
	"fmt"
	"github.com/bmizerany/pat"
	"log"
	"net/http"
)

const version = "0.1.0"

var printVersion bool

func init() {
	flag.BoolVar(&printVersion, "v", false, "Print version and exit")
	flag.Parse()
}

func buildMux() *pat.PatternServeMux {
	m := pat.New()
	m.Post("/resources", http.HandlerFunc(Add))
	m.Post("/resources/:name", Handler(Bind))
	m.Del("/resources/:name/hostname/:hostname", Handler(Unbind))
	m.Del("/resources/:name", Handler(Remove))
	m.Get("/resources/:name/status", Handler(Status))
	return m
}

func main() {
	if printVersion {
		fmt.Printf("mongoapi version %s", version)
		return
	}
	listen := coalesceEnv("0.0.0.0:3333", "MONGODB_API_LISTEN")
	log.Fatal(http.ListenAndServe(listen, buildMux()))
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/yudai/gotty/backend/localcommand"
	"github.com/yudai/gotty/pkg/homedir"
	"github.com/yudai/gotty/server"
	"github.com/yudai/gotty/utils"
)

func main() {
	app := cli.NewApp()
	app.Name = "gotty"
	app.Version = Version + "+" + CommitID
	app.Usage = "Share your terminal as a web application"
	app.HideHelp = true
	cli.AppHelpTemplate = helpTemplate

	appOptions := &server.Options{}
	if err := utils.ApplyDefaultValues(appOptions); err != nil {
		exit(err, 1)
	}
	backendOptions := &localcommand.Options{}
	if err := utils.ApplyDefaultValues(backendOptions); err != nil {
		exit(err, 1)
	}

	cliFlags, flagMappings, err := utils.GenerateFlags(appOptions, backendOptions)
	if err != nil {
		exit(err, 3)
	}

	app.Flags = append(
		cliFlags,
		cli.StringFlag{
			Name:   "config",
			Value:  "~/.gotty",
			Usage:  "Config file path",
			EnvVar: "GOTTY_CONFIG",
		},
	)

	app.Action = func(c *cli.Context) {
		if len(c.Args()) == 0 {
			msg := "Error: No command given."
			cli.ShowAppHelp(c)
			exit(fmt.Errorf(msg), 1)
		}

		configFile := c.String("config")
		_, err := os.Stat(homedir.Expand(configFile))
		if configFile != "~/.gotty" || !os.IsNotExist(err) {
			if err := utils.ApplyConfigFile(configFile, appOptions, backendOptions); err != nil {
				exit(err, 2)
			}
		}

		utils.ApplyFlags(cliFlags, flagMappings, c, appOptions, backendOptions)

		appOptions.EnableBasicAuth = c.IsSet("credential")
		appOptions.EnableTLSClientAuth = c.IsSet("tls-ca-crt")

		err = appOptions.Validate()
		if err != nil {
			exit(err, 6)
		}

		args := c.Args()
		factory, err := localcommand.NewFactory(args[0], args[1:], backendOptions)
		if err != nil {
			exit(err, 3)
		}

		hostname, _ := os.Hostname()
		appOptions.TitleVariables = map[string]interface{}{
			"command":  args[0],
			"argv":     args[1:],
			"hostname": hostname,
		}

		srv, err := server.New(factory, appOptions)
		if err != nil {
			exit(err, 3)
		}

		ctx, cancel := context.WithCancel(context.Background())
		gCtx, gCancel := context.WithCancel(context.Background())

		errs := make(chan error, 1)
		go func() {
			errs <- srv.Run(ctx, server.WithGracefullContext(gCtx))
		}()
		err = waitSignals(errs, cancel, gCancel)

		if err != nil && err != context.Canceled {
			fmt.Printf("Error: %s\n", err)
			exit(err, 8)
		}

	}
	app.Run(os.Args)
}

func exit(err error, code int) {
	if err != nil {
		fmt.Println(err)
	}
	os.Exit(code)
}

func waitSignals(errs chan error, cancel context.CancelFunc, gracefullCancel context.CancelFunc) error {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(
		sigChan,
		syscall.SIGINT,
		syscall.SIGTERM,
	)

	select {
	case err := <-errs:
		return err

	case s := <-sigChan:
		switch s {
		case syscall.SIGINT:
			gracefullCancel()
			fmt.Println("C-C to force close")
			select {
			case err := <-errs:
				return err
			case <-sigChan:
				cancel()
				return <-errs
			}
		default:
			cancel()
			return <-errs
		}
	}
}
<commit_msg>Log force closing<commit_after>package main

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"syscall"

	"github.com/codegangsta/cli"

	"github.com/yudai/gotty/backend/localcommand"
	"github.com/yudai/gotty/pkg/homedir"
	"github.com/yudai/gotty/server"
	"github.com/yudai/gotty/utils"
)

func main() {
	app := cli.NewApp()
	app.Name = "gotty"
	app.Version = Version + "+" + CommitID
	app.Usage = "Share your terminal as a web application"
	app.HideHelp = true
	cli.AppHelpTemplate = helpTemplate

	appOptions := &server.Options{}
	if err := utils.ApplyDefaultValues(appOptions); err != nil {
		exit(err, 1)
	}
	backendOptions := &localcommand.Options{}
	if err := utils.ApplyDefaultValues(backendOptions); err != nil {
		exit(err, 1)
	}

	cliFlags, flagMappings, err := utils.GenerateFlags(appOptions, backendOptions)
	if err != nil {
		exit(err, 3)
	}

	app.Flags = append(
		cliFlags,
		cli.StringFlag{
			Name:   "config",
			Value:  "~/.gotty",
			Usage:  "Config file path",
			EnvVar: "GOTTY_CONFIG",
		},
	)

	app.Action = func(c *cli.Context) {
		if len(c.Args()) == 0 {
			msg := "Error: No command given."
			cli.ShowAppHelp(c)
			exit(fmt.Errorf(msg), 1)
		}

		configFile := c.String("config")
		_, err := os.Stat(homedir.Expand(configFile))
		if configFile != "~/.gotty" || !os.IsNotExist(err) {
			if err := utils.ApplyConfigFile(configFile, appOptions, backendOptions); err != nil {
				exit(err, 2)
			}
		}

		utils.ApplyFlags(cliFlags, flagMappings, c, appOptions, backendOptions)

		appOptions.EnableBasicAuth = c.IsSet("credential")
		appOptions.EnableTLSClientAuth = c.IsSet("tls-ca-crt")

		err = appOptions.Validate()
		if err != nil {
			exit(err, 6)
		}

		args := c.Args()
		factory, err := localcommand.NewFactory(args[0], args[1:], backendOptions)
		if err != nil {
			exit(err, 3)
		}

		hostname, _ := os.Hostname()
		appOptions.TitleVariables = map[string]interface{}{
			"command":  args[0],
			"argv":     args[1:],
			"hostname": hostname,
		}

		srv, err := server.New(factory, appOptions)
		if err != nil {
			exit(err, 3)
		}

		ctx, cancel := context.WithCancel(context.Background())
		gCtx, gCancel := context.WithCancel(context.Background())

		errs := make(chan error, 1)
		go func() {
			errs <- srv.Run(ctx, server.WithGracefullContext(gCtx))
		}()
		err = waitSignals(errs, cancel, gCancel)

		if err != nil && err != context.Canceled {
			fmt.Printf("Error: %s\n", err)
			exit(err, 8)
		}

	}
	app.Run(os.Args)
}

func exit(err error, code int) {
	if err != nil {
		fmt.Println(err)
	}
	os.Exit(code)
}

func waitSignals(errs chan error, cancel context.CancelFunc, gracefullCancel context.CancelFunc) error {
	sigChan := make(chan os.Signal, 1)
	signal.Notify(
		sigChan,
		syscall.SIGINT,
		syscall.SIGTERM,
	)

	select {
	case err := <-errs:
		return err

	case s := <-sigChan:
		switch s {
		case syscall.SIGINT:
			gracefullCancel()
			fmt.Println("C-C to force close")
			select {
			case err := <-errs:
				return err
			case <-sigChan:
				fmt.Println("Force closing...")
				cancel()
				return <-errs
			}
		default:
			cancel()
			return <-errs
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/tomsteele/blacksheepwall/bsw"
	"log"
	"net"
	"os"
	"sort"
	"text/tabwriter"
)

var usage = `
  Usage: blacksheepwall [options] <ip address or CIDR>

  Options:
  -h, --help            Show Usage and exit.
  -version              Show version and exit.
  -debug                Enable debugging and show errors returned from tasks.
  -concurrency <int>    Max amount of concurrent tasks.    [default: 100]
  -server <string>      DNS server address.    [default: "8.8.8.8"]
  -input <string>       Line separated file of networks (CIDR) or
                        IP Addresses.
  -ipv6	                Look for additional AAAA records where applicable.
  -domain <string>      Target domain to use for certain tasks.
  -dictionary <string>  Attempt to retrieve the CNAME and A record for
                        each subdomain in the line separated file.
  -yandex <string>      Provided a Yandex search XML API url. Use the Yandex
                        search 'rhost:' operator to find subdomains of a
                        provided domain..
  -bing	<string>        Provided a base64 encoded API key. Use the Bing search
                        API's 'ip:' operator to lookup hostnames for each host.
  -headers              Perform HTTP(s) requests to each host and look for
                        hostnames in a possible Location header.
  -reverse              Retrieve the PTR for each host.
  -tls                  Attempt to retrieve names from TLS certificates
                        (CommonName and Subject Alternative Name).
  -viewdns              Lookup each host using viewdns.info's Reverse IP
                        Lookup function.
  -fcrdns               Verify results by attempting to retrieve the A or AAAA record for
                        each result previously identified hostname.
  -clean                Print results as unique hostnames for each host.
  -csv                  Print results in csv format.
  -json                 Print results as JSON.

`

// Returns all ip addresses from each CIDR range in a list.
func linesToIpList(lines []string) ([]string, error) {
	ipList := []string{}
	for _, line := range lines {
		if net.ParseIP(line) != nil {
			ipList = append(ipList, line)
		} else if ip, network, err := net.ParseCIDR(line); err == nil {
			for ip := ip.Mask(network.Mask); network.Contains(ip); increaseIp(ip) {
				ipList = append(ipList, ip.String())
			}
		} else {
			return ipList, errors.New("\"" + line + "\" is not an IP Address or CIDR Network")
		}
	}
	return ipList, nil
}

// Increases IP by a single address
func increaseIp(ip net.IP) {
	for j := len(ip) - 1; j >= 0; j-- {
		ip[j]++
		if ip[j] > 0 {
			break
		}
	}
}

// Reads lines from a file and returns as a slice.
func readFileLines(path string) ([]string, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	lines := []string{}
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

type task func() (bsw.Results, error)
type empty struct{}

func main() {
	// Command line options. For usage information see the
	// usage variable above.
	var (
		flVersion     = flag.Bool("version", false, "")
		flConcurrency = flag.Int("concurrency", 100, "")
		flDebug       = flag.Bool("debug", false, "")
		flipv6        = flag.Bool("ipv6", false, "")
		flServerAddr  = flag.String("server", "8.8.8.8", "")
		flIpFile      = flag.String("input", "", "")
		flReverse     = flag.Bool("reverse", false, "")
		flHeader      = flag.Bool("headers", false, "")
		flTLS         = flag.Bool("tls", false, "")
		flViewDnsInfo = flag.Bool("viewdns", false, "")
		flBing        = flag.String("bing", "", "")
		flYandex      = flag.String("yandex", "", "")
		flDomain      = flag.String("domain", "", "")
		flDictFile    = flag.String("dictionary", "", "")
		flFcrdns      = flag.Bool("fcrdns", false, "")
		flClean       = flag.Bool("clean", false, "")
		flCsv         = flag.Bool("csv", false, "")
		flJson        = flag.Bool("json", false, "")
	)
	flag.Usage = func() { fmt.Print(usage) }
	flag.Parse()

	if *flVersion {
		fmt.Println("blacksheepwall version ", bsw.VERSION)
		os.Exit(0)
	}

	// Holds all ip addresses for testing
	ipAddrList := []string{}

	// Used to hold a ip or CIDR range passed as fl.Arg(0)
	var flNetwork string

	// Verify that some sort of work load was given in commands
	if *flIpFile == "" && *flDomain == "" && len(flag.Args()) < 1 {
		log.Fatal("You didn't provide any work for me to do")
	}
	if *flYandex != "" && *flDomain == "" {
		log.Fatal("Yandex API requires domain set with -domain")
	}
	if *flDictFile != "" && *flDomain == "" {
		log.Fatal("Dictionary lookup requires domain set with -domain")
	}
	if *flDomain != "" && *flYandex == "" && *flDictFile == "" {
		log.Fatal("-domain provided but no methods provided that use it")
	}

	// Get first argument that is not an option and turn it into a list of ips
	if len(flag.Args()) > 0 {
		flNetwork = flag.Arg(0)
		list, err := linesToIpList([]string{flNetwork})
		if err != nil {
			log.Fatal(err.Error())
		}
		ipAddrList = append(ipAddrList, list...)
	}

	// If file given as -input, read lines and turn each possible ip or network into
	// a list of ips. Appends list to ipAddrList. Will fail fatally if line in file
	// is not a valid ip or CIDR range.
	if *flIpFile != "" {
		lines, err := readFileLines(*flIpFile)
		if err != nil {
			log.Fatal("Error reading " + *flIpFile + " " + err.Error())
		}
		list, err := linesToIpList(lines)
		if err != nil {
			log.Fatal(err.Error())
		}
		ipAddrList = append(ipAddrList, list...)
	}

	// tracker: Chanel uses an empty struct to track when all goroutines in the pool
	//          have completed as well as a single call from the gatherer.
	//
	// tasks:   Chanel used in the goroutine pool to manage incoming work. A task is
	//          a function wrapper that returns a slice of results and a possible error.
	//
	// res:     When each task is called in the pool, it will send valid results to
	//          the res channel.
	tracker := make(chan empty)
	tasks := make(chan task, *flConcurrency)
	res := make(chan bsw.Results, *flConcurrency)
	// Use a map that acts like a set to store only unique results
	resMap:= make(map[bsw.Result]bool)

	// Start up *flConcurrency amount of goroutines
	log.Printf("Spreading tasks across %d goroutines", *flConcurrency)
	for i := 0; i < *flConcurrency; i++ {
		go func() {
			var c = 0
			for def := range tasks {
				result, err := def()
				if m := c % 2; m == 0 {
					c = 3
					os.Stderr.WriteString("\rWorking \\")
				} else {
					c = 2
					os.Stderr.WriteString("\rWorking /")
				}
				if err != nil && *flDebug {
					log.Println(err.Error())
				}
				if err == nil {
					res <- result
				}
			}
			tracker <- empty{}
		}()
	}

	// Ingest incoming results
	go func() {
		for result := range res {
			if len(result) < 1 {
				continue
			}
			if *flFcrdns {
				for _, r := range result {
					ip, err := bsw.LookupName(r.Hostname, *flServerAddr)
					if err == nil && len(ip) > 0 {
						resMap[bsw.Result{Source: "fcrdns", IP: ip, Hostname: r.Hostname}] = true
					}
					ip, err = bsw.LookupName6(r.Hostname, *flServerAddr)
					if err == nil && len(ip) > 0 {
						resMap[bsw.Result{Source: "fcrdns", IP: ip, Hostname: r.Hostname}] = true
					}
				}
			} else {
				for _, r := range result {
					resMap[r] = true
				}
			}
		}
		tracker <- empty{}
	}()

	// Bing has two possible search paths. We need to find which one is valid.
	var bingPath string
	if *flBing != "" {
		p, err := bsw.FindBingSearchPath(*flBing)
		if err != nil {
			log.Fatal(err.Error())
		}
		bingPath = p
	}

	// ip based functionality should be added to the pool here
	for _, h := range ipAddrList {
		host := h
		if *flReverse {
			tasks <- func() (bsw.Results, error) { return bsw.Reverse(host, *flServerAddr) }
		}
		if *flTLS {
			tasks <- func() (bsw.Results, error) { return bsw.TLS(host) }
		}
		if *flViewDnsInfo {
			tasks <- func() (bsw.Results, error) { return bsw.ViewDnsInfo(host) }
		}
		if *flBing != "" && bingPath != "" {
			tasks <- func() (bsw.Results, error) { return bsw.BingAPI(host, *flBing, bingPath) }
		}
		if *flHeader {
			tasks <- func() (bsw.Results, error) { return bsw.Headers(host) }
		}

	}

	// Domain based functions will likely require separate blocks

	// Subdomain dictionary guessing
	if *flDictFile != "" && *flDomain != "" {
		nameList, err := readFileLines(*flDictFile)
		if err != nil {
			log.Fatal("Error reading " + *flDictFile + " " + err.Error())
		}
		// Get an ip for a possible wildcard domain and use it as a blacklist
		blacklist := bsw.GetWildCard(*flDomain, *flServerAddr)
		var blacklist6 string
		if *flipv6 {
			blacklist6 = bsw.GetWildCard6(*flDomain, *flServerAddr)
		}
		for _, n := range nameList {
			sub := n
			tasks <- func() (bsw.Results, error) { return bsw.Dictionary(*flDomain, sub, blacklist, *flServerAddr) }
			if *flipv6 {
				tasks <- func() (bsw.Results, error) { return bsw.Dictionary6(*flDomain, sub, blacklist6, *flServerAddr) }
			}
		}
	}

	if *flYandex != "" && *flDomain != "" {
		tasks <- func() (bsw.Results, error) { return bsw.YandexAPI(*flDomain, *flYandex, *flServerAddr) }
	}

	// Close the tasks channel after all jobs have completed and for each
	// goroutine in the pool receive an empty message from  tracker.
	close(tasks)
	for i := 0; i < *flConcurrency; i++ {
		<-tracker
	}
	close(res)
	// Receive and empty message from the result gatherer
	<-tracker
	os.Stderr.WriteString("\r")
	log.Println("All tasks completed\n")

	// Create a results slice from the unique set in resMap. Allows for sorting.
	results := bsw.Results{}
	for k, _ := range resMap {
		results = append(results, k)
	}
	sort.Sort(results)

	// Output options
	switch {
	case *flJson:
		j, _ := json.MarshalIndent(results, "", "    ")
		fmt.Println(string(j))
	case *flCsv:
		for _, r := range results {
			fmt.Printf("%s,%s,%s\n", r.Hostname, r.IP, r.Source)
		}
	case *flClean:
		cleanSet := make(map[string][]string)
		for _, r := range results {
			cleanSet[r.IP] = append(cleanSet[r.IP], r.Hostname)
		}
		for k, v := range cleanSet {
			fmt.Printf("%s:\n", k)
			for _, h := range v {
				fmt.Printf("\t%s\n", h)
			}
		}
	default:
		w := tabwriter.NewWriter(os.Stdout, 0, 8, 4, ' ', 0)
		fmt.Fprintln(w, "IP\tHostname\tSource")
		for _, r := range results {
			fmt.Fprintf(w, "%s\t%s\t%s\n", r.IP, r.Hostname, r.Source)
		}
		w.Flush()
	}
}
<commit_msg>Renamed to blacksheepwall.go<commit_after><|endoftext|>


<commit_before>package main

import (
	"github.com/ak1t0/flame/crawler"
	"github.com/ak1t0/flame/format"
	"github.com/ak1t0/flame/reader"
	"log"
)

func main() {
	parsed := reader.ReadJson("flame.json")
	r := crawler.Scan(format.NewOnionLogs(parsed))

	log.Println(r)
}
<commit_msg>add cli<commit_after>package main

import (
	"github.com/urfave/cli"
	"github.com/ak1t0/flame/crawler"
	"github.com/ak1t0/flame/format"
	"github.com/ak1t0/flame/reader"
	"log"
	"os"
)

var Version string = "0.0.1"

func main() {
	app := cli.NewApp()
	app.Name = "flame"
	app.Usage = "crawl onion services"
	app.Version = Version
	app.Author = "ak1t0"
	app.Email = "aktoo3097@gmail.com"
	app.Commands = Commands

	app.Run(os.Args)
}

var Commands = []cli.Command{
	commandScan,
}

var commandScan = cli.Command{
	Name: "scan",
	Usage: "Scan onion services",
	Aliases: []string{"s"},
	Action: doScan,
	Flags: []cli.Flag {
		cli.StringFlag{
			Name: "f",
			Usage: "Select log file",
		},
	},
}

func doScan(c *cli.Context) error {
	var target string
	if c.String("f") != "" {
		target = c.String("f")
	} else {
		target = "log.json"
	}

	parsed := reader.ReadJson(target)
	r := crawler.Scan(format.NewOnionLogs(parsed))

	log.Println(r)

	return nil
}

<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"time"

	"github.com/codahale/hdrhistogram"
)

type MeasuredResponse struct {
	sz      uint64
	code    int
	latency int64
	timeout bool
}

func sendRequest(client *http.Client, url *url.URL, host *string, received chan *MeasuredResponse) {
	if client == nil {
		client = &http.Client{}
	}
	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
	}
	req.Host = *host

	// FIX: find a way to measure latency with the http client.
	start := time.Now()
	response, err := client.Do(req)

	elapsed := time.Since(start)
	if err != nil {
		// FIX: handle errors more gracefully.
		fmt.Printf("%s\n", err)
		os.Exit(1)
	} else {
		sz, _ := io.Copy(ioutil.Discard, response.Body)
		response.Body.Close()
		received <- &MeasuredResponse{uint64(sz), response.StatusCode, elapsed.Nanoseconds(), false}
	}
}

func exUsage(msg string) {
	fmt.Fprintf(os.Stderr, "%s\n", msg)
	fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n", path.Base(os.Args[0]))
	flag.PrintDefaults()
	os.Exit(64)
}

func main() {
	qps := flag.Int("qps", 1, "QPS to send to backends per request thread")
	concurrency := flag.Uint("concurrency", 1, "Number of request threads")
	host := flag.String("host", "web", "value of Host header to set")
	urldest := flag.String("url", "http://localhost:4140/", "Destination url")
	interval := flag.Duration("interval", 10*time.Second, "reporting interval")
	reuse := flag.Bool("reuse", false, "reuse connections")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()

	if *qps < 1 {
		exUsage("qps must be at least 1")
	}

	if *concurrency < 1 {
		exUsage("concurrency must be at least 1")
	}

	dstURL, err := url.Parse(*urldest)
	if err != nil {
		exUsage(fmt.Sprintf("invalid URL: '%s': %s\n", urldest, err.Error()))
	}

	// Repsonse tracking metadata.
	count := uint64(0)
	size := uint64(0)
	good := uint64(0)
	bad := uint64(0)
	// from 0 to 1 minute in nanoseconds
	// FIX: verify that these buckets work correctly for our use case.
	hist := hdrhistogram.New(0, 60000000000, 5)
	received := make(chan *MeasuredResponse)
	timeout := time.After(*interval)

	timeToWait := time.Millisecond * time.Duration(1000 / *qps)

	tr := http.Transport{}
	if dstURL.Scheme == "https" {
		tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}
	var client *http.Client
	if *reuse {
		client = &http.Client{Transport: &tr}
	}

	for i := uint(0); i < *concurrency; i++ {
		ticker := time.NewTicker(timeToWait)
		go func() {
			for _ = range ticker.C {
				sendRequest(client, dstURL, host, received)
			}
		}()
	}

	for {
		select {
		case t := <-timeout:
			// Periodically print stats about the request load.
			fmt.Printf("%s %6d/%1d requests %6d kilobytes %s [%3d %3d %3d %4d ]\n",
				t.Format(time.RFC3339),
				good,
				bad,
				(size / 1024),
				interval,
				hist.ValueAtQuantile(50)/1000000,
				hist.ValueAtQuantile(95)/1000000,
				hist.ValueAtQuantile(99)/1000000,
				hist.ValueAtQuantile(999)/1000000)
			count = 0
			size = 0
			good = 0
			bad = 0
			hist = hdrhistogram.New(0, 60000000000, 5)
			timeout = time.After(*interval)
		case managedResp := <-received:
			count++
			size += managedResp.sz
			if managedResp.code >= 200 && managedResp.code < 500 {
				good++
			} else {
				bad++
			}
			hist.RecordValue(managedResp.latency)
		}
	}
}
<commit_msg>another newline for better error output<commit_after>package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"time"

	"github.com/codahale/hdrhistogram"
)

type MeasuredResponse struct {
	sz      uint64
	code    int
	latency int64
	timeout bool
}

func sendRequest(client *http.Client, url *url.URL, host *string, received chan *MeasuredResponse) {
	if client == nil {
		client = &http.Client{}
	}
	req, err := http.NewRequest("GET", url.String(), nil)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		fmt.Fprintln(os.Stderr, "\n")
	}
	req.Host = *host

	// FIX: find a way to measure latency with the http client.
	start := time.Now()
	response, err := client.Do(req)

	elapsed := time.Since(start)
	if err != nil {
		// FIX: handle errors more gracefully.
		fmt.Printf("%s\n", err)
		os.Exit(1)
	} else {
		sz, _ := io.Copy(ioutil.Discard, response.Body)
		response.Body.Close()
		received <- &MeasuredResponse{uint64(sz), response.StatusCode, elapsed.Nanoseconds(), false}
	}
}

func exUsage(msg string) {
	fmt.Fprintf(os.Stderr, "%s\n", msg)
	fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n", path.Base(os.Args[0]))
	flag.PrintDefaults()
	os.Exit(64)
}

func main() {
	qps := flag.Int("qps", 1, "QPS to send to backends per request thread")
	concurrency := flag.Uint("concurrency", 1, "Number of request threads")
	host := flag.String("host", "web", "value of Host header to set")
	urldest := flag.String("url", "http://localhost:4140/", "Destination url")
	interval := flag.Duration("interval", 10*time.Second, "reporting interval")
	reuse := flag.Bool("reuse", false, "reuse connections")

	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags]\n", path.Base(os.Args[0]))
		flag.PrintDefaults()
	}

	flag.Parse()

	if *qps < 1 {
		exUsage("qps must be at least 1")
	}

	if *concurrency < 1 {
		exUsage("concurrency must be at least 1")
	}

	dstURL, err := url.Parse(*urldest)
	if err != nil {
		exUsage(fmt.Sprintf("invalid URL: '%s': %s\n", urldest, err.Error()))
	}

	// Repsonse tracking metadata.
	count := uint64(0)
	size := uint64(0)
	good := uint64(0)
	bad := uint64(0)
	// from 0 to 1 minute in nanoseconds
	// FIX: verify that these buckets work correctly for our use case.
	hist := hdrhistogram.New(0, 60000000000, 5)
	received := make(chan *MeasuredResponse)
	timeout := time.After(*interval)

	timeToWait := time.Millisecond * time.Duration(1000 / *qps)

	tr := http.Transport{}
	if dstURL.Scheme == "https" {
		tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
	}
	var client *http.Client
	if *reuse {
		client = &http.Client{Transport: &tr}
	}

	for i := uint(0); i < *concurrency; i++ {
		ticker := time.NewTicker(timeToWait)
		go func() {
			for _ = range ticker.C {
				sendRequest(client, dstURL, host, received)
			}
		}()
	}

	for {
		select {
		case t := <-timeout:
			// Periodically print stats about the request load.
			fmt.Printf("%s %6d/%1d requests %6d kilobytes %s [%3d %3d %3d %4d ]\n",
				t.Format(time.RFC3339),
				good,
				bad,
				(size / 1024),
				interval,
				hist.ValueAtQuantile(50)/1000000,
				hist.ValueAtQuantile(95)/1000000,
				hist.ValueAtQuantile(99)/1000000,
				hist.ValueAtQuantile(999)/1000000)
			count = 0
			size = 0
			good = 0
			bad = 0
			hist = hdrhistogram.New(0, 60000000000, 5)
			timeout = time.After(*interval)
		case managedResp := <-received:
			count++
			size += managedResp.sz
			if managedResp.code >= 200 && managedResp.code < 500 {
				good++
			} else {
				bad++
			}
			hist.RecordValue(managedResp.latency)
		}
	}
}
<|endoftext|>