<commit_before>package main

import (
	"bufio"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/raff/godet"

	"github.com/njasm/marionette_client"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("browser_ip")
	viper.BindEnv("browser_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("browser_ip") || !viper.IsSet("browser_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both BROWSER_IP and BROWSER_PORT must be set via either config or environment.")
		os.Exit(1)
	}
	mode := viper.Get("BROWSER_CONTROL_MODE")
	ipStr := viper.Get("BROWSER_IP")
	if mode == 1 {
		log.Println("Using MODE1 (aka. FF Remote Control plugin) -- [DEPRECATED in newer versio of Firefox]")
	}
	if mode == 2 {
		log.Printf("Using MODE2:  Firefox Marionette protocol.  ")
		log.Printf("  IP is %s, but localhost will be used instead.\n", ipStr)
	}
	if mode == 3 {
		log.Printf("Using MODE3:  Chrome Debugging protocol.  ")
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		log.Printf("Content will change immediately.\n\n")

	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	var c = 0
	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			log.Println("Program rejected.  Invalid duration.")
		}

		list = append(list, p)
		c++
	}
	log.Printf("Loaded %d programs from %s", c, filename)
	return list
}

func runProgram(program Program) {

	timer_code := fmt.Sprintf(`

function addStyleString(str) {
    var node = document.createElement('style');
    node.innerHTML = str;
    document.body.appendChild(node);
}

var block_to_insert ;
var container_block ;
const duration = %v;
block_to_insert = document.createElement( 'div' );
block_to_insert.className = "gotator-overlay";
block_to_insert.innerHTML = '<progress value="0" max=%v id="progressBar"></progress>';

addStyleString('.gotator-overlay{ position: fixed; top: 0; left: 0; height: 0px; width: 100%%; z-index: 10000 ; background:white}');
addStyleString('#progressBar{-webkit-appearance: none; appearance: none; height: 5px; width: 100%%');

document.body.appendChild(block_to_insert);

var timeleft = duration;
var downloadTimer = setInterval(function(){
  document.getElementById("progressBar").value = duration - --timeleft;

  if(timeleft <= 0)
    clearInterval(downloadTimer);
},1000);
                `, program.Duration.Seconds(), program.Duration.Seconds())

	ip := viper.Get("BROWSER_IP")
	port := viper.GetInt("BROWSER_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	log.Printf("Running program for %s", program.Duration)
	log.Printf("  URL %s", program.URL)

	mode := viper.Get("BROWSER_CONTROL_MODE")
	if mode == 1 {
		// Connect to FF Remote Control
		conn, err := net.Dial("tcp", constr)
		if err != nil {
			log.Printf("  Error making network connection to: %s\n", constr)
			log.Println("  It is possible Firefox needs to be started or restarted.")
			log.Println("  It is possible FF Remote Control plugin is not installed.")
			log.Println("  Pausing for 30s")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}

		// Actual control of browser starts here
		fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
		status, err := bufio.NewReader(conn).ReadString('\n')
		if err != nil {
			log.Println("ERROR - URL didn't load as desired.")
		}

		var statusParsed interface{}
		err = json.Unmarshal([]byte(status), &statusParsed)

		m := statusParsed.(map[string]interface{})

		if m["result"] == program.URL {
			log.Println("RESULT: OK")
		} else {
			log.Println("RESULT: ERROR - URL didn't load as desired.")
		}
	}
	if mode == 2 {
		// Connect using Marionette
		client := marionette_client.NewClient()

		err := client.Connect("", 0) // this are the default marionette values for hostname, and port
		if err != nil {
			log.Println("Can't connect to firefox.  Sorry.")
			log.Println("It is possible Firefox needs to be started or restarted.")
			log.Println("Pausing for 30s")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}
		client.NewSession("", nil) // let marionette generate the Session ID with it's default Capabilities
		client.Navigate(program.URL)

		if viper.IsSet("timeroverlay") && viper.Get("timeroverlay") == true {
			// Inject count down progress bar into page
			args := []interface{}{}
			client.ExecuteScript(timer_code, args, 1000, false)
		}
	}
	if mode == 3 {

		remote, err := godet.Connect("localhost:9222", false)
		if err != nil {
			log.Println("Can not connect to Chrome instance:")
			log.Println(err)
			log.Println("Sleeping for 30 seconds")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}
		// disconnect when done
		defer remote.Close()

		remote.Navigate(program.URL)
		done := make(chan bool)
		remote.CallbackEvent("Page.frameStoppedLoading", func(params godet.Params) {
			log.Println("page loaded")
			done <- true
		})

		remote.PageEvents(true)

		_ = <-done

		if viper.IsSet("timeroverlay") && viper.Get("timeroverlay") == true {
			// Inject count down progress bar into page
			_, _ = remote.EvaluateWrap(timer_code)

		}

	}

	select {
	case <-time.After(program.Duration):
		return
	case <-skip:
		log.Println("Current program skipped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
	log.Println("Paused")
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
	log.Println("Unpaused")
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")

		for IsPaused() {
			fmt.Printf(".")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Printf("X")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		log.Println("Looping back to play program list from beginning")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	log.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	log.Printf("Duration: %s\n", d)

	// CAREFUL: There may be bugs here...
	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Stop normal rotation
	Pause()

	runProgram(p)
	w.Write([]byte("Program accepted\n"))
	Unpause()
}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Paused from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skipping from web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		log.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.2.0"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			log.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	log.Println("Starting gotator: version", version)

	InitializeConfig()

	go LoadAndRunLoop()

	if viper.IsSet("interactive") && viper.Get("interactive") == true {
		go readKeyboardLoop()
	}

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		log.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		if viper.IsSet("tlsenabled") && viper.Get("tlsenabled") == true {
			log.Printf("TLS is enabled.  Be sure to access API with https as protocol.")
			log.Fatal(http.ListenAndServeTLS(listen_port, "server.crt", "server.key", r))
		} else {
			log.Fatal(http.ListenAndServe(listen_port, r))
		}

	} else {
		log.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<commit_msg>Made duration optional for /play API endpoint.<commit_after>package main

import (
	"bufio"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/raff/godet"

	"github.com/njasm/marionette_client"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	viper.SetConfigName("config")

	viper.AddConfigPath("$HOME/.gotator")
	viper.AddConfigPath(".")

	err := viper.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("browser_ip")
	viper.BindEnv("browser_port")
	viper.BindEnv("gotator_port")

	if !viper.IsSet("browser_ip") || !viper.IsSet("browser_port") {
		fmt.Fprintln(os.Stderr, "Configuration error.  Both BROWSER_IP and BROWSER_PORT must be set via either config or environment.")
		os.Exit(1)
	}
	mode := viper.Get("BROWSER_CONTROL_MODE")
	ipStr := viper.Get("BROWSER_IP")
	if mode == 1 {
		log.Println("Using MODE1 (aka. FF Remote Control plugin) -- [DEPRECATED in newer versio of Firefox]")
	}
	if mode == 2 {
		log.Printf("Using MODE2:  Firefox Marionette protocol.  ")
		log.Printf("  IP is %s, but localhost will be used instead.\n", ipStr)
	}
	if mode == 3 {
		log.Printf("Using MODE3:  Chrome Debugging protocol.  ")
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Println("\nConfig file changed:", e.Name)
		skip <- struct{}{}
		log.Printf("Content will change immediately.\n\n")

	})

}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))
	r.LazyQuotes = true

	var c = 0
	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Printf("Error reading line from program file: %s.  Abandoning attempt to read programs.\n", filename)
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		if err != nil {
			log.Println("Program rejected.  Invalid duration.")
		}

		list = append(list, p)
		c++
	}
	log.Printf("Loaded %d programs from %s", c, filename)
	return list
}

func runProgram(program Program) {

	timer_code := fmt.Sprintf(`

function addStyleString(str) {
    var node = document.createElement('style');
    node.innerHTML = str;
    document.body.appendChild(node);
}

var block_to_insert ;
var container_block ;
const duration = %v;
block_to_insert = document.createElement( 'div' );
block_to_insert.className = "gotator-overlay";
block_to_insert.innerHTML = '<progress value="0" max=%v id="progressBar"></progress>';

addStyleString('.gotator-overlay{ position: fixed; top: 0; left: 0; height: 0px; width: 100%%; z-index: 10000 ; background:white}');
addStyleString('#progressBar{-webkit-appearance: none; appearance: none; height: 5px; width: 100%%');

document.body.appendChild(block_to_insert);

var timeleft = duration;
var downloadTimer = setInterval(function(){
  document.getElementById("progressBar").value = duration - --timeleft;

  if(timeleft <= 0)
    clearInterval(downloadTimer);
},1000);
                `, program.Duration.Seconds(), program.Duration.Seconds())

	ip := viper.Get("BROWSER_IP")
	port := viper.GetInt("BROWSER_PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	log.Printf("Running program for %s", program.Duration)
	log.Printf("  URL %s", program.URL)

	mode := viper.Get("BROWSER_CONTROL_MODE")
	if mode == 1 {
		// Connect to FF Remote Control
		conn, err := net.Dial("tcp", constr)
		if err != nil {
			log.Printf("  Error making network connection to: %s\n", constr)
			log.Println("  It is possible Firefox needs to be started or restarted.")
			log.Println("  It is possible FF Remote Control plugin is not installed.")
			log.Println("  Pausing for 30s")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}

		// Actual control of browser starts here
		fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
		status, err := bufio.NewReader(conn).ReadString('\n')
		if err != nil {
			log.Println("ERROR - URL didn't load as desired.")
		}

		var statusParsed interface{}
		err = json.Unmarshal([]byte(status), &statusParsed)

		m := statusParsed.(map[string]interface{})

		if m["result"] == program.URL {
			log.Println("RESULT: OK")
		} else {
			log.Println("RESULT: ERROR - URL didn't load as desired.")
		}
	}
	if mode == 2 {
		// Connect using Marionette
		client := marionette_client.NewClient()

		err := client.Connect("", 0) // this are the default marionette values for hostname, and port
		if err != nil {
			log.Println("Can't connect to firefox.  Sorry.")
			log.Println("It is possible Firefox needs to be started or restarted.")
			log.Println("Pausing for 30s")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}
		client.NewSession("", nil) // let marionette generate the Session ID with it's default Capabilities
		client.Navigate(program.URL)

		if viper.IsSet("timeroverlay") && viper.Get("timeroverlay") == true {
			// Inject count down progress bar into page
			args := []interface{}{}
			client.ExecuteScript(timer_code, args, 1000, false)
		}
	}
	if mode == 3 {

		remote, err := godet.Connect("localhost:9222", false)
		if err != nil {
			log.Println("Can not connect to Chrome instance:")
			log.Println(err)
			log.Println("Sleeping for 30 seconds")
			time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
			return
		}
		// disconnect when done
		defer remote.Close()

		remote.Navigate(program.URL)
		done := make(chan bool)
		remote.CallbackEvent("Page.frameStoppedLoading", func(params godet.Params) {
			log.Println("page loaded")
			done <- true
		})

		remote.PageEvents(true)

		_ = <-done

		if viper.IsSet("timeroverlay") && viper.Get("timeroverlay") == true {
			// Inject count down progress bar into page
			_, _ = remote.EvaluateWrap(timer_code)

		}

	}

	select {
	case <-time.After(program.Duration):
		return
	case <-skip:
		log.Println("Current program skipped")
		return
	}
}

func Pause() {
	mu.Lock()
	pause = true
	mu.Unlock()
	log.Println("Paused")
}

func Unpause() {
	mu.Lock()
	pause = false
	mu.Unlock()
	log.Println("Unpaused")
}

func IsPaused() bool {
	mu.Lock()
	defer mu.Unlock()

	return pause == true
}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")

		for IsPaused() {
			fmt.Printf(".")
			time.Sleep(1 * time.Second)
		}

		pl := loadProgramList(filename)

		for _, p := range pl {
			for IsPaused() {
				fmt.Printf("X")
				time.Sleep(1 * time.Second)
			}
			runProgram(p)
		}

		log.Println("Looping back to play program list from beginning")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	log.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	log.Printf("Duration: %s\n", d)

	dur_text := r.Form.Get("duration")
	if dur_text == "" {
		dur_text = "30s"
	}

	var err error
	p.Duration, err = time.ParseDuration(dur_text)
	if err != nil {
		w.Write([]byte("Program rejected.  Invalid duration.\n"))
		return
	}

	// Stop normal rotation
	Pause()

	runProgram(p)
	w.Write([]byte("Program accepted\n"))
	Unpause()
}

func PauseHandler(w http.ResponseWriter, r *http.Request) {
	Pause()
	log.Println("Paused from web request")
	w.Write([]byte("Ok, paused.\n"))
}

func ResumeHandler(w http.ResponseWriter, r *http.Request) {
	Unpause()
	log.Println("Unpausing from web request")
	w.Write([]byte("Ok, unpaused.\n"))
}
func SkipHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Skipping from web request")
	Unpause()
	skip <- struct{}{}

	w.Write([]byte("Skipping current programming and resume program list runner from web request.\n"))
}

func readKeyboardLoop() {
	for {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		log.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		Unpause()
		skip <- struct{}{}
	}
}

// Control channel to stop running programs immediately (yes, global)

var skip = make(chan struct{})
var exitprogram = make(chan struct{})
var pause bool
var mu = &sync.Mutex{}
var version = "0.2.0"

func main() {

	if len(os.Args) > 1 {
		if os.Args[1] == "version" {
			log.Println("Gotator version:", version)
			os.Exit(0)
		}
	}
	log.Println("Starting gotator: version", version)

	InitializeConfig()

	go LoadAndRunLoop()

	if viper.IsSet("interactive") && viper.Get("interactive") == true {
		go readKeyboardLoop()
	}

	if viper.IsSet("apienabled") && viper.Get("apienabled") == true {
		listen_port := ":8080"
		if viper.IsSet("gotator_port") {
			listen_port = ":" + viper.GetString("gotator_port")
		}

		log.Printf("Starting API server on port %s.  Notice:  This allows UNAUTHENTICATED remote control of Firefox. set 'apienabled: false' in config.yaml to disable.\n",
			listen_port)

		r := mux.NewRouter()
		r.HandleFunc("/play", PlayHandler)
		r.HandleFunc("/pause", PauseHandler)
		r.HandleFunc("/resume", ResumeHandler)
		r.HandleFunc("/skip", SkipHandler)

		if viper.IsSet("tlsenabled") && viper.Get("tlsenabled") == true {
			log.Printf("TLS is enabled.  Be sure to access API with https as protocol.")
			log.Fatal(http.ListenAndServeTLS(listen_port, "server.crt", "server.key", r))
		} else {
			log.Fatal(http.ListenAndServe(listen_port, r))
		}

	} else {
		log.Println("notice: rest API not enabled in configuration and will be unavailable.  set 'apienabled: true' in config.yaml if you want to use it.\n")
		// If we aren't doing http.ListenAndServe() we need to block here or else gotator would exit immediately
		<-exitprogram
	}

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os/user"
	"path/filepath"
	"sync"

	"github.com/zrob/boshler/archiver"
	"github.com/zrob/boshler/bosh_cli"
	"github.com/zrob/boshler/bosh_file"
	"github.com/zrob/boshler/boshio"
)

func main() {
	boshfile, err := bosh_file.ParseFile("BOSHFILE")
	if err != nil {
		panic(err.Error())
	}

	target, err := bosh_cli.GetTarget()
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(target)

	usr, err := user.Current()
	if err != nil {
		panic(err.Error())
	}
	archiveDir := filepath.Join(usr.HomeDir, ".boshler", "releases")

	var wg sync.WaitGroup
	wg.Add(len(boshfile.Releases))

	for _, release := range boshfile.Releases {
		go func(release bosh_file.Release) {
			fetcher := boshio.NewMetadataFetcher()
			archiver := archiver.NewArchiver(archiveDir)

			metadata, err := fetcher.Fetch(release)
			if err != nil {
				panic(err.Error())
			}

			var releaseVersion boshio.ReleaseVersion
			if release.Version == "" {
				releaseVersion = metadata.Latest()
			} else {
				releaseVersion, err = metadata.Version(release.Version)
				if err != nil {
					panic(err.Error())
				}
			}

			path, err := archiver.Store(releaseVersion)
			if err != nil {
				panic(err.Error())
			}

			err = bosh_cli.UploadRelease(path)
			if err != nil {
				println(err.Error())
				panic(err.Error())
			}

			wg.Done()
		}(release)
	}

	wg.Wait()
}
<commit_msg>extract helper methods in main<commit_after>package main

import (
	"fmt"
	"os/user"
	"path/filepath"
	"sync"

	"github.com/zrob/boshler/archiver"
	"github.com/zrob/boshler/bosh_cli"
	"github.com/zrob/boshler/bosh_file"
	"github.com/zrob/boshler/boshio"
)

func main() {
	boshfile := parseBoshFile()
	displayCurrentTarget()
	archiveDir := getArchiveDir()

	var wg sync.WaitGroup
	wg.Add(len(boshfile.Releases))

	for _, release := range boshfile.Releases {
		go func(release bosh_file.Release) {
			defer wg.Done()
			cacheAndUploadRelease(release, archiveDir)
		}(release)
	}

	wg.Wait()
}

func cacheAndUploadRelease(release bosh_file.Release, archiveDir string) {
	fetcher := boshio.NewMetadataFetcher()
	archiver := archiver.NewArchiver(archiveDir)

	metadata, err := fetcher.Fetch(release)
	if err != nil {
		panic(err.Error())
	}

	var releaseVersion boshio.ReleaseVersion
	if release.Version == "" {
		releaseVersion = metadata.Latest()
	} else {
		releaseVersion, err = metadata.Version(release.Version)
		if err != nil {
			panic(err.Error())
		}
	}

	path, err := archiver.Store(releaseVersion)
	if err != nil {
		panic(err.Error())
	}

	err = bosh_cli.UploadRelease(path)
	if err != nil {
		println(err.Error())
		panic(err.Error())
	}
}

func displayCurrentTarget() {
	target, err := bosh_cli.GetTarget()
	if err != nil {
		panic(err.Error())
	}
	fmt.Println(target)
}

func parseBoshFile() bosh_file.BoshFile {
	boshfile, err := bosh_file.ParseFile("BOSHFILE")
	if err != nil {
		panic(err.Error())
	}
	return boshfile
}

func getArchiveDir() string {
	usr, err := user.Current()
	if err != nil {
		panic(err.Error())
	}
	return filepath.Join(usr.HomeDir, ".boshler", "releases")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"

	"github.com/gophergala2016/togepi/meta"
	"github.com/gophergala2016/togepi/redis"
	"github.com/gophergala2016/togepi/server"
	"github.com/gophergala2016/togepi/tcp"
	"github.com/gophergala2016/togepi/util"
)

var (
	serverMode        = flag.Bool("server", false, "run in server mode")
	httpServerAddress = flag.String("http-host", "http://127.0.0.1:8011", "togepi server's host")
	tcpServerAddress  = flag.String("tcp-host", "127.0.0.1:8012", "togepi server's host")
	httpPort          = flag.Int("http-port", 8011, "HTTP server's port")
	tcpPort           = flag.Int("tcp-port", 8012, "TCP server's port")
	redisHost         = flag.String("redis-host", "127.0.0.1:6379", "Redis host address")
	redisDB           = flag.Int("redis-db", 0, "Redis DB")
)

var (
	srv *server.Server
	r   *redis.Redis
	md  *meta.Data
	l   *tcp.Listener
	cl  *tcp.Client
)

func init() {
	flag.Parse()
}

func shutdown() {
	log.Println("Shutting down gracefully..")

	if srv != nil {
		srv.Stop()
	}

	if r != nil {
		r.Close()
	}

	if l != nil {
		l.Stop()
	}

	if cl != nil {
		cl.Close()
	}

	log.Println("terminating process")
	os.Exit(0)
}

func startServer() {
	log.Println("starting server")
	var redisErr error
	r, redisErr = redis.NewClient(*redisHost, *redisDB)
	util.CheckError(redisErr, shutdown)

	sExists, sErr := r.KeyExists("secret")
	util.CheckError(sErr, shutdown)

	if !sExists {
		log.Println("running server for the first time")
		setErr := r.GenerateGlobalSecret()
		util.CheckError(setErr, shutdown)
	}

	getErr := r.RetrieveGlobalSecret()
	util.CheckError(getErr, shutdown)

	srv = server.New("/register", "/validate", *httpPort, r)
	startErr := srv.Start()
	util.CheckError(startErr, shutdown)

	var lErr error
	l, lErr = tcp.NewListener(*tcpPort)
	util.CheckError(lErr, shutdown)

	l.Start()
}

func startDaemon() {
	log.Println("starting daemon")

	configPath := os.Getenv("HOME") + "/.togepi/data"
	configStat, configStatErr := os.Stat(configPath)
	switch {
	case os.IsNotExist(configStatErr):
		log.Println("first start, generating configuration")

		resp, respErr := http.Get(*httpServerAddress + "/register")
		util.CheckError(respErr, shutdown)
		body, bodyErr := ioutil.ReadAll(resp.Body)
		util.CheckError(bodyErr, shutdown)
		resp.Body.Close()

		var respStruct server.RegResp
		jsonRespErr := json.Unmarshal(body, &respStruct)
		util.CheckError(jsonRespErr, shutdown)

		md.SetUserData(respStruct.UserID, respStruct.UserKey)
		dataErr := md.CreateDataFile(configPath)
		util.CheckError(dataErr, shutdown)
	case configStat.IsDir():
		log.Fatal(configPath + " is a directory")
	default:
		readDataErr := md.ReadDataFile(configPath)
		util.CheckError(readDataErr, shutdown)

		resp, respErr := http.Get(*httpServerAddress + "/validate?uid=" + md.UserID + "&ukey=" + md.UserKey)
		util.CheckError(respErr, shutdown)

		if resp.StatusCode != http.StatusOK {
			util.CheckError(errors.New("invalid user"), shutdown)
		}

		var clErr error
		cl, clErr = tcp.NewClient(md.UserID, *tcpServerAddress)
		util.CheckError(clErr, shutdown)
	}
}

func shareFile() {

}

func main() {
	md = meta.NewData()
	if *serverMode {
		startServer()
	} else {
		if len(os.Args) > 1 && os.Args[1] == "start" {
			startDaemon()
		} else {
			shareFile()
		}
	}

	// Shutting down on SIGINT.
	go func() {
		intChan := make(chan os.Signal)
		signal.Notify(intChan, os.Interrupt)

		<-intChan
		go shutdown()

		fmt.Println("\nsend SIGINT again to kill")
		<-intChan

		os.Exit(1)
	}()

	select {}
}
<commit_msg>shutting down on error<commit_after>package main

import (
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"

	"github.com/gophergala2016/togepi/meta"
	"github.com/gophergala2016/togepi/redis"
	"github.com/gophergala2016/togepi/server"
	"github.com/gophergala2016/togepi/tcp"
	"github.com/gophergala2016/togepi/util"
)

var (
	serverMode        = flag.Bool("server", false, "run in server mode")
	httpServerAddress = flag.String("http-host", "http://127.0.0.1:8011", "togepi server's host")
	tcpServerAddress  = flag.String("tcp-host", "127.0.0.1:8012", "togepi server's host")
	httpPort          = flag.Int("http-port", 8011, "HTTP server's port")
	tcpPort           = flag.Int("tcp-port", 8012, "TCP server's port")
	redisHost         = flag.String("redis-host", "127.0.0.1:6379", "Redis host address")
	redisDB           = flag.Int("redis-db", 0, "Redis DB")
)

var (
	srv *server.Server
	r   *redis.Redis
	md  *meta.Data
	l   *tcp.Listener
	cl  *tcp.Client
)

func init() {
	flag.Parse()
}

func shutdown() {
	log.Println("Shutting down gracefully..")

	if srv != nil {
		srv.Stop()
	}

	if r != nil {
		r.Close()
	}

	if l != nil {
		l.Stop()
	}

	if cl != nil {
		cl.Close()
	}

	log.Println("terminating process")
	os.Exit(0)
}

func startServer() {
	log.Println("starting server")
	var redisErr error
	r, redisErr = redis.NewClient(*redisHost, *redisDB)
	util.CheckError(redisErr, shutdown)

	sExists, sErr := r.KeyExists("secret")
	util.CheckError(sErr, shutdown)

	if !sExists {
		log.Println("running server for the first time")
		setErr := r.GenerateGlobalSecret()
		util.CheckError(setErr, shutdown)
	}

	getErr := r.RetrieveGlobalSecret()
	util.CheckError(getErr, shutdown)

	srv = server.New("/register", "/validate", *httpPort, r)
	startErr := srv.Start()
	util.CheckError(startErr, shutdown)

	var lErr error
	l, lErr = tcp.NewListener(*tcpPort)
	util.CheckError(lErr, shutdown)

	l.Start()
}

func startDaemon() {
	log.Println("starting daemon")

	configPath := os.Getenv("HOME") + "/.togepi/data"
	configStat, configStatErr := os.Stat(configPath)
	switch {
	case os.IsNotExist(configStatErr):
		log.Println("first start, generating configuration")

		resp, respErr := http.Get(*httpServerAddress + "/register")
		util.CheckError(respErr, shutdown)
		body, bodyErr := ioutil.ReadAll(resp.Body)
		util.CheckError(bodyErr, shutdown)
		resp.Body.Close()

		var respStruct server.RegResp
		jsonRespErr := json.Unmarshal(body, &respStruct)
		util.CheckError(jsonRespErr, shutdown)

		md.SetUserData(respStruct.UserID, respStruct.UserKey)
		dataErr := md.CreateDataFile(configPath)
		util.CheckError(dataErr, shutdown)
	case configStat.IsDir():
		util.CheckError(errors.New(configPath+" is a directory"), shutdown)
	default:
		readDataErr := md.ReadDataFile(configPath)
		util.CheckError(readDataErr, shutdown)

		resp, respErr := http.Get(*httpServerAddress + "/validate?uid=" + md.UserID + "&ukey=" + md.UserKey)
		util.CheckError(respErr, shutdown)

		if resp.StatusCode != http.StatusOK {
			util.CheckError(errors.New("invalid user"), shutdown)
		}

		var clErr error
		cl, clErr = tcp.NewClient(md.UserID, *tcpServerAddress)
		util.CheckError(clErr, shutdown)
	}
}

func shareFile() {

}

func main() {
	md = meta.NewData()
	if *serverMode {
		startServer()
	} else {
		if len(os.Args) > 1 && os.Args[1] == "start" {
			startDaemon()
		} else {
			shareFile()
		}
	}

	// Shutting down on SIGINT.
	go func() {
		intChan := make(chan os.Signal)
		signal.Notify(intChan, os.Interrupt)

		<-intChan
		go shutdown()

		fmt.Println("\nsend SIGINT again to kill")
		<-intChan

		os.Exit(1)
	}()

	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Lukasa/trustdeck/certs"
	"log"
	"net/http"
	"runtime"
)

const CERT_URL = "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt"

var certificates certs.CertMap = nil

func updateCertificates() {
	// Now, grab the certificates.
	resp, err := http.Get(CERT_URL)
	if err != nil {
		log.Fatalf("Unable to get cert file: %s", err)
	}

	_, _, objects := certs.ParseInput(resp.Body)
	resp.Body.Close()

	certificates = certs.OutputTrustedCerts(objects)
}

func serveCertificates(w http.ResponseWriter, r *http.Request) {
	exceptions := make(map[string]interface{})
	certs.WriteCerts(w, certificates, false, exceptions)
}

func main() {
	// Before we do anything, TURN ON THE CPUS.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// At start of day, populate the certificates.
	updateCertificates()

	// Start the HTTP server.
	http.HandleFunc("/", serveCertificates)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<commit_msg>Begin to define blacklist API.<commit_after>package main

import (
	"github.com/Lukasa/trustdeck/certs"
	"log"
	"net/http"
	"runtime"
	"strings"
)

const CERT_URL = "https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt"

var certificates certs.CertMap = nil

func updateCertificates() {
	// Now, grab the certificates.
	resp, err := http.Get(CERT_URL)
	if err != nil {
		log.Fatalf("Unable to get cert file: %s", err)
	}

	_, _, objects := certs.ParseInput(resp.Body)
	resp.Body.Close()

	certificates = certs.OutputTrustedCerts(objects)
}

// Parses the exceptions from the path.
func getExceptions(path string, prefix string) map[string]interface{} {
	// Remove the prefix.
	query := string(path[len(prefix):])

	// Split the query on each '+' character.
	components := strings.Split(query, "+")

	exceptions := make(map[string]interface{})
	for _, component := range components {
		exceptions[component] = nil
	}

	return exceptions
}

// serveBlacklistCertificates serves certificates using a blacklist. The
// expected form of the URL is: /generate/name1+name2+name3, where name1 and
// friends are the labels to exclude from the list.
func serveBlacklistCertificates(w http.ResponseWriter, r *http.Request) {
	exceptions := getExceptions(r.URL.Path, "/generate/")
	certs.WriteCerts(w, certificates, false, exceptions)
}

func main() {
	// Before we do anything, TURN ON THE CPUS.
	runtime.GOMAXPROCS(runtime.NumCPU())

	// At start of day, populate the certificates.
	updateCertificates()

	// Start the HTTP server.
	http.HandleFunc("/generate/", serveBlacklistCertificates)
	log.Fatal(http.ListenAndServe(":8080", nil))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"regexp"

	"github.com/Chiliec/golos-go/client"
	"gopkg.in/telegram-bot-api.v4"

	"github.com/Chiliec/golos-vote-bot/db"
	"github.com/Chiliec/golos-vote-bot/models"
)

var (
	postingKey string
	database   *sql.DB
	logins     map[int]string
)

const (
	rpc   = "wss://ws.golos.io"
	chain = "golos"

	keyButtonText   = "🔑 Ключница"
	aboutButtonText = "🐞 О боте"
)

var alreadyVotedError = errors.New("Уже проголосовали!")

func init() {
	flag.StringVar(&postingKey, "postingKey", "", "posting key")
	flag.Parse()

	database = db.InitDB("./db/database.db")
	logins = map[int]string{}
}

func main() {
	token := os.Getenv("TELEGRAM_TOKEN")
	if token == "" {
		log.Panic(errors.New("Нет токена"))
	}
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = true

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}
	for update := range updates {
		err := processMessage(bot, update)
		if err != nil {
			log.Println(err)
		}
	}
}

func processMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update) error {
	log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
	if update.Message != nil {
		regexp, err := regexp.Compile("https://golos.io/([-a-zA-Z0-9@:%_+.~#?&//=]{2,256})/@([-a-zA-Z0-9]{2,256})/([-a-zA-Z0-9@:%_+.~#?&=]{2,256})")
		if err != nil {
			return err
		}
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
		if update.Message.IsCommand() {
			switch update.Message.Command() {
			case "start":
				keyButton := tgbotapi.NewKeyboardButton(keyButtonText)
				aboutButton := tgbotapi.NewKeyboardButton(aboutButtonText)
				buttons := []tgbotapi.KeyboardButton{keyButton, aboutButton}
				keyboard := tgbotapi.NewReplyKeyboard(buttons)
				msg.ReplyMarkup = keyboard
			}
		} else if update.Message.Text == keyButtonText {
			msg.Text = "Введите логин на Голосе"
			setWaitLogin(update.Message.From.ID)
		} else if update.Message.Text == aboutButtonText {
			msg.Text = "Бот для блого-социальной сети на блокчейне \"Голос\"\n" +
				"Нет времени голосовать, но хочется зарабатывать? Добавьте приватный постинг ключ и мы распорядимся вашей Силой голоса наилучшим образом!\n" +
				"Автор: @babin"
		} else if regexp.MatchString(update.Message.Text) {
			matched := regexp.FindStringSubmatch(update.Message.Text)
			log.Println(matched)
			author, permalink := matched[2], matched[3]
			voter := "chiliec"
			percent := 65
			voteModel := models.Vote{
				UserID:    update.Message.From.ID,
				Voter:     voter,
				Author:    author,
				Permalink: permalink,
				Percent:   percent,
			}
			msg.ReplyToMessageID = update.Message.MessageID
			err := vote(voteModel)
			if err != nil {
				if err == alreadyVotedError {
					msg.Text = "Уже голосовал за этот пост!"
				} else {
					msg.Text = "Не смог прогосовать, попробуйте ещё раз"
				}
			} else {
				msg.Text = fmt.Sprintf("Проголосовал с силой %d%%", percent)
			}
		} else if wait, login := isWaitingKey(update.Message.From.ID); wait {
			if login == "" {
				msg.Text = "Введите приватный ключ"
				setWaitKey(update.Message.From.ID, update.Message.Text)
			} else {
				log.Println("Сейчас нужно сохранить логин и приватный ключ!")
				credential := models.Credential{
					UserID:     update.Message.From.ID,
					UserName:   login,
					PostingKey: update.Message.Text,
				}
				result, err := credential.Save(database)
				if err != nil {
					log.Println(err.Error())
				}
				msg.ReplyToMessageID = update.Message.MessageID
				if result {
					msg.Text = "Логин и приватный ключ успешно сохранён!"
				} else {
					msg.Text = "Не смог сохранить логин и приватный ключ :("
				}
				forgetLogin(update.Message.From.ID)
			}
		} else {
			msg.Text = "Команда не распознана"
		}
		bot.Send(msg)
	}
	return nil
}

func forgetLogin(userID int) {
	delete(logins, userID)
}

func setWaitLogin(userID int) {
	logins[userID] = ""
}

func setWaitKey(userID int, login string) {
	logins[userID] = login
}

func isWaitingKey(userID int) (bool, string) {
	for id, login := range logins {
		if userID == id {
			return true, login
		}
	}
	return false, ""
}

func vote(model models.Vote) error {
	exists := model.Exists(database)
	if exists {
		return alreadyVotedError
	}
	weight := model.Percent * 100
	client.Key_List = map[string]client.Keys{model.Voter: client.Keys{postingKey, "", "", ""}}
	api := client.NewApi(rpc, chain)
	err := api.Vote(model.Voter, model.Author, model.Permalink, weight)
	if err != nil {
		return err
	}
	_, err = model.Save(database)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Keys list using refactoring<commit_after>package main

import (
	"database/sql"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"regexp"

	"github.com/Chiliec/golos-go/client"
	"gopkg.in/telegram-bot-api.v4"

	"github.com/Chiliec/golos-vote-bot/db"
	"github.com/Chiliec/golos-vote-bot/models"
)

var (
	postingKey string
	database   *sql.DB
	logins     map[int]string
)

const (
	rpc   = "wss://ws.golos.io"
	chain = "golos"

	keyButtonText   = "🔑 Ключница"
	aboutButtonText = "🐞 О боте"
)

var golos = client.NewApi(rpc, chain)

var alreadyVotedError = errors.New("Уже проголосовали!")

func init() {
	flag.StringVar(&postingKey, "postingKey", "", "posting key")
	flag.Parse()

	database = db.InitDB("./db/database.db")
	logins = map[int]string{}
}

func main() {
	token := os.Getenv("TELEGRAM_TOKEN")
	if token == "" {
		log.Panic(errors.New("Нет токена"))
	}
	bot, err := tgbotapi.NewBotAPI(token)
	if err != nil {
		log.Panic(err)
	}

	bot.Debug = true

	log.Printf("Authorized on account %s", bot.Self.UserName)

	u := tgbotapi.NewUpdate(0)
	u.Timeout = 60

	updates, err := bot.GetUpdatesChan(u)
	if err != nil {
		log.Panic(err)
	}
	for update := range updates {
		err := processMessage(bot, update)
		if err != nil {
			log.Println(err)
		}
	}
}

func processMessage(bot *tgbotapi.BotAPI, update tgbotapi.Update) error {
	log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text)
	if update.Message != nil {
		regexp, err := regexp.Compile("https://golos.io/([-a-zA-Z0-9@:%_+.~#?&//=]{2,256})/@([-a-zA-Z0-9]{2,256})/([-a-zA-Z0-9@:%_+.~#?&=]{2,256})")
		if err != nil {
			return err
		}
		msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
		if update.Message.IsCommand() {
			switch update.Message.Command() {
			case "start":
				keyButton := tgbotapi.NewKeyboardButton(keyButtonText)
				aboutButton := tgbotapi.NewKeyboardButton(aboutButtonText)
				buttons := []tgbotapi.KeyboardButton{keyButton, aboutButton}
				keyboard := tgbotapi.NewReplyKeyboard(buttons)
				msg.ReplyMarkup = keyboard
			}
		} else if update.Message.Text == keyButtonText {
			msg.Text = "Введите логин на Голосе"
			setWaitLogin(update.Message.From.ID)
		} else if update.Message.Text == aboutButtonText {
			msg.Text = "Бот для блого-социальной сети на блокчейне \"Голос\"\n" +
				"Нет времени голосовать, но хочется зарабатывать? Добавьте приватный постинг ключ и мы распорядимся вашей Силой голоса наилучшим образом!\n" +
				"Автор: @babin"
		} else if regexp.MatchString(update.Message.Text) {
			matched := regexp.FindStringSubmatch(update.Message.Text)
			log.Println(matched)
			author, permalink := matched[2], matched[3]
			voter := "chiliec"
			percent := 65
			voteModel := models.Vote{
				UserID:    update.Message.From.ID,
				Voter:     voter,
				Author:    author,
				Permalink: permalink,
				Percent:   percent,
			}
			msg.ReplyToMessageID = update.Message.MessageID
			err := vote(voteModel)
			if err != nil {
				if err == alreadyVotedError {
					msg.Text = "Уже голосовал за этот пост!"
				} else {
					msg.Text = "Не смог прогосовать, попробуйте ещё раз"
				}
			} else {
				msg.Text = fmt.Sprintf("Проголосовал с силой %d%%", percent)
			}
		} else if wait, login := isWaitingKey(update.Message.From.ID); wait {
			if login == "" {
				msg.Text = "Введите приватный ключ"
				setWaitKey(update.Message.From.ID, update.Message.Text)
			} else {
				log.Println("Сейчас нужно сохранить логин и приватный ключ!")
				credential := models.Credential{
					UserID:     update.Message.From.ID,
					UserName:   login,
					PostingKey: update.Message.Text,
				}
				result, err := credential.Save(database)
				if err != nil {
					log.Println(err.Error())
				}
				msg.ReplyToMessageID = update.Message.MessageID
				if result {
					msg.Text = "Логин и приватный ключ успешно сохранён!"
				} else {
					msg.Text = "Не смог сохранить логин и приватный ключ :("
				}
				forgetLogin(update.Message.From.ID)
			}
		} else {
			msg.Text = "Команда не распознана"
		}
		bot.Send(msg)
	}
	return nil
}

func forgetLogin(userID int) {
	delete(logins, userID)
}

func setWaitLogin(userID int) {
	logins[userID] = ""
}

func setWaitKey(userID int, login string) {
	logins[userID] = login
}

func isWaitingKey(userID int) (bool, string) {
	for id, login := range logins {
		if userID == id {
			return true, login
		}
	}
	return false, ""
}

func vote(model models.Vote) error {
	exists := model.Exists(database)
	if exists {
		return alreadyVotedError
	}
	weight := model.Percent * 100
	client.Key_List[model.Voter] = client.Keys{PKey: postingKey}
	err := golos.Vote(model.Voter, model.Author, model.Permalink, weight)
	if err != nil {
		return err
	}
	_, err = model.Save(database)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	_ "net/http/pprof"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"

	"github.com/bosun-monitor/bosun/_third_party/github.com/bosun-monitor/collect"
	"github.com/bosun-monitor/bosun/_third_party/gopkg.in/fsnotify.v1"
	"github.com/bosun-monitor/bosun/conf"
	"github.com/bosun-monitor/bosun/sched"
	"github.com/bosun-monitor/bosun/web"
)

// These constants should remain in source control as their zero values.
const (
	// VersionDate should be set at build time as a date: 20140721184001.
	VersionDate uint64 = 0
	// VersionID should be set at build time as the most recent commit hash.
	VersionID string = ""
)

var (
	flagConf     = flag.String("c", "dev.conf", "config file location")
	flagTest     = flag.Bool("t", false, "test for valid config; exits with 0 on success, else 1")
	flagWatch    = flag.Bool("w", false, "watch .go files below current directory and exit; also build typescript files on change")
	flagReadonly = flag.Bool("r", false, "readonly-mode: don't write or relay any OpenTSDB metrics")
	flagQuiet    = flag.Bool("q", false, "quiet-mode: don't send any notifications except from the rule test page")
	flagDev      = flag.Bool("dev", false, "enable dev mode: use local resources")
	flagVersion  = flag.Bool("version", false, "Prints the version and exits.")
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Printf("bosun version %v (%v)\n", VersionDate, VersionID)
		os.Exit(0)
	}
	runtime.GOMAXPROCS(runtime.NumCPU())
	c, err := conf.ParseFile(*flagConf)
	if err != nil {
		log.Fatal(err)
	}
	if *flagTest {
		os.Exit(0)
	}
	httpListen := &url.URL{
		Scheme: "http",
		Host:   c.HttpListen,
	}
	if strings.HasPrefix(httpListen.Host, ":") {
		httpListen.Host = "localhost" + httpListen.Host
	}
	if err := collect.Init(httpListen, "bosun"); err != nil {
		log.Fatal(err)
	}
	sched.Load(c)
	if c.RelayListen != "" {
		go func() {
			mux := http.NewServeMux()
			mux.Handle("/api/", httputil.NewSingleHostReverseProxy(httpListen))
			s := &http.Server{
				Addr:    c.RelayListen,
				Handler: mux,
			}
			log.Fatal(s.ListenAndServe())
		}()
	}
	tsdbHost := &url.URL{
		Scheme: "http",
		Host:   c.TsdbHost,
	}
	if *flagReadonly {
		rp := httputil.NewSingleHostReverseProxy(tsdbHost)
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path == "/api/put" {
				w.WriteHeader(204)
				return
			}
			rp.ServeHTTP(w, r)
		}))
		log.Println("readonly relay at", ts.URL, "to", tsdbHost)
		tsdbHost, _ = url.Parse(ts.URL)
		c.TsdbHost = tsdbHost.Host
	}
	if *flagQuiet {
		c.Quiet = true
	}
	go func() { log.Fatal(web.Listen(c.HttpListen, *flagDev, tsdbHost)) }()
	go func() { log.Fatal(sched.Run()) }()
	if *flagWatch {
		watch(".", "*.go", quit)
		watch(filepath.Join("web", "static", "templates"), "*.html", quit)
		base := filepath.Join("web", "static", "js")
		args := []string{
			"--out", filepath.Join(base, "bosun.js"),
		}
		matches, _ := filepath.Glob(filepath.Join(base, "*.ts"))
		sort.Strings(matches)
		args = append(args, matches...)
		tsc := run("tsc", args...)
		watch(base, "*.ts", tsc)
		tsc()
	}
	select {}
}

func quit() {
	os.Exit(0)
}

func run(name string, arg ...string) func() {
	return func() {
		log.Println("running", name)
		c := exec.Command(name, arg...)
		stdout, err := c.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		stderr, err := c.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := c.Start(); err != nil {
			log.Fatal(err)
		}
		go func() { io.Copy(os.Stdout, stdout) }()
		go func() { io.Copy(os.Stderr, stderr) }()
		if err := c.Wait(); err != nil {
			log.Printf("run error: %v: %v", name, err)
		}
		log.Println("run complete:", name)
	}
}

func watch(root, pattern string, f func()) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if matched, err := filepath.Match(pattern, info.Name()); err != nil {
			log.Fatal(err)
		} else if !matched {
			return nil
		}
		err = watcher.Add(path)
		if err != nil {
			log.Fatal(err)
		}
		return nil
	})
	log.Println("watching", pattern, "in", root)
	wait := time.Now()
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if wait.After(time.Now()) {
					continue
				}
				if event.Op&fsnotify.Write == fsnotify.Write {
					f()
					wait = time.Now().Add(time.Second * 2)
				}
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()
}
<commit_msg>Don't wait for typescript<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	_ "net/http/pprof"
	"net/url"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"

	"github.com/bosun-monitor/bosun/_third_party/github.com/bosun-monitor/collect"
	"github.com/bosun-monitor/bosun/_third_party/gopkg.in/fsnotify.v1"
	"github.com/bosun-monitor/bosun/conf"
	"github.com/bosun-monitor/bosun/sched"
	"github.com/bosun-monitor/bosun/web"
)

// These constants should remain in source control as their zero values.
const (
	// VersionDate should be set at build time as a date: 20140721184001.
	VersionDate uint64 = 0
	// VersionID should be set at build time as the most recent commit hash.
	VersionID string = ""
)

var (
	flagConf     = flag.String("c", "dev.conf", "config file location")
	flagTest     = flag.Bool("t", false, "test for valid config; exits with 0 on success, else 1")
	flagWatch    = flag.Bool("w", false, "watch .go files below current directory and exit; also build typescript files on change")
	flagReadonly = flag.Bool("r", false, "readonly-mode: don't write or relay any OpenTSDB metrics")
	flagQuiet    = flag.Bool("q", false, "quiet-mode: don't send any notifications except from the rule test page")
	flagDev      = flag.Bool("dev", false, "enable dev mode: use local resources")
	flagVersion  = flag.Bool("version", false, "Prints the version and exits.")
)

func main() {
	flag.Parse()
	if *flagVersion {
		fmt.Printf("bosun version %v (%v)\n", VersionDate, VersionID)
		os.Exit(0)
	}
	runtime.GOMAXPROCS(runtime.NumCPU())
	c, err := conf.ParseFile(*flagConf)
	if err != nil {
		log.Fatal(err)
	}
	if *flagTest {
		os.Exit(0)
	}
	httpListen := &url.URL{
		Scheme: "http",
		Host:   c.HttpListen,
	}
	if strings.HasPrefix(httpListen.Host, ":") {
		httpListen.Host = "localhost" + httpListen.Host
	}
	if err := collect.Init(httpListen, "bosun"); err != nil {
		log.Fatal(err)
	}
	sched.Load(c)
	if c.RelayListen != "" {
		go func() {
			mux := http.NewServeMux()
			mux.Handle("/api/", httputil.NewSingleHostReverseProxy(httpListen))
			s := &http.Server{
				Addr:    c.RelayListen,
				Handler: mux,
			}
			log.Fatal(s.ListenAndServe())
		}()
	}
	tsdbHost := &url.URL{
		Scheme: "http",
		Host:   c.TsdbHost,
	}
	if *flagReadonly {
		rp := httputil.NewSingleHostReverseProxy(tsdbHost)
		ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path == "/api/put" {
				w.WriteHeader(204)
				return
			}
			rp.ServeHTTP(w, r)
		}))
		log.Println("readonly relay at", ts.URL, "to", tsdbHost)
		tsdbHost, _ = url.Parse(ts.URL)
		c.TsdbHost = tsdbHost.Host
	}
	if *flagQuiet {
		c.Quiet = true
	}
	go func() { log.Fatal(web.Listen(c.HttpListen, *flagDev, tsdbHost)) }()
	go func() { log.Fatal(sched.Run()) }()
	if *flagWatch {
		watch(".", "*.go", quit)
		watch(filepath.Join("web", "static", "templates"), "*.html", quit)
		base := filepath.Join("web", "static", "js")
		args := []string{
			"--out", filepath.Join(base, "bosun.js"),
		}
		matches, _ := filepath.Glob(filepath.Join(base, "*.ts"))
		sort.Strings(matches)
		args = append(args, matches...)
		tsc := run("tsc", args...)
		watch(base, "*.ts", tsc)
		go tsc()
	}
	select {}
}

func quit() {
	os.Exit(0)
}

func run(name string, arg ...string) func() {
	return func() {
		log.Println("running", name)
		c := exec.Command(name, arg...)
		stdout, err := c.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		stderr, err := c.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		if err := c.Start(); err != nil {
			log.Fatal(err)
		}
		go func() { io.Copy(os.Stdout, stdout) }()
		go func() { io.Copy(os.Stderr, stderr) }()
		if err := c.Wait(); err != nil {
			log.Printf("run error: %v: %v", name, err)
		}
		log.Println("run complete:", name)
	}
}

func watch(root, pattern string, f func()) {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
		if matched, err := filepath.Match(pattern, info.Name()); err != nil {
			log.Fatal(err)
		} else if !matched {
			return nil
		}
		err = watcher.Add(path)
		if err != nil {
			log.Fatal(err)
		}
		return nil
	})
	log.Println("watching", pattern, "in", root)
	wait := time.Now()
	go func() {
		for {
			select {
			case event := <-watcher.Events:
				if wait.After(time.Now()) {
					continue
				}
				if event.Op&fsnotify.Write == fsnotify.Write {
					f()
					wait = time.Now().Add(time.Second * 2)
				}
			case err := <-watcher.Errors:
				log.Println("error:", err)
			}
		}
	}()
}
<|endoftext|>


<commit_before>package main

import(
	"io/ioutil"
	"encoding/json"
	"net/http"
	"os"
	"io"
	"text/template"
	"fmt"
	"strconv"
	"flag"
)

// Account Model
type AccountEntry struct {
	Username string
	Password string
	SuccessRate string `json:"success_rate"`
	Upvotes string
	Posted string
}

// Account Collection
type AccountBook struct {
	Accounts []*AccountEntry
}

func main(){

	// adding usage
	flag.Usage = usage
	flag.Parse()

	args:=flag.Args()

	if len(args) != 1 {
		usage()
	}

	query := args[0]

	accountBook,_ := bmn(query)
	if len(accountBook.Accounts) > 0 {
		printMessage(os.Stdout,strconv.Itoa(len(accountBook.Accounts))+" accounts for "+query)
	} else {
		printMessage(os.Stdout,"No accounts for this domain.")
	}

	for _,account := range accountBook.Accounts {
		printAccount(os.Stdout,account)
	}
}

// Usage

const usageTmpl = `BMN is a command-line utility to find logins/passwords for websites that force you to register.
Usage:
  bmn [website]
`

func usage() {
	printUsage(os.Stderr)
	os.Exit(2)
}

func printUsage(w io.Writer) {
	tmpl(w, usageTmpl, nil)
}

// Result

const accountTmpl = `
	Username: {{.Username}}
	Password: {{.Password}}
	SuccessRate: {{.SuccessRate}}
	Upvotes: {{.Upvotes}}
	Posted: {{.Posted}}

`

func printAccount(w io.Writer,a *AccountEntry){
	tmpl(w,accountTmpl,a)
}

// Helper Functions

// Messages

const messageTmpl = `
	{{.Message}}
`
// printing message on command line
func printMessage(w io.Writer,msg string) {
	tmpl(w,messageTmpl,struct {Message string}{msg})
}

// logging error
func printErr(err error) {
	fmt.Fprintln(os.Stderr, err.Error())
	os.Exit(2)
}

const BASE_URL = "http://bugmenotapi.herokuapp.com/"

// Fetching data from bmn webservice
func bmn(website string)(*AccountBook,error) {

	res, err := http.Get(BASE_URL+website)
	if err != nil {
		return nil,err
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil,err
	}
	var accountBook AccountBook
	json.Unmarshal(body,&accountBook)

	return &accountBook,nil
}

// Output template
func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	template.Must(t.Parse(text))
	if err := t.Execute(w, data); err != nil {
		panic(err)
	}
}
<commit_msg>update comments<commit_after>package main

import(
	"io/ioutil"
	"encoding/json"
	"net/http"
	"os"
	"io"
	"text/template"
	"fmt"
	"strconv"
	"flag"
)

// Account Model
type AccountEntry struct {
	Username string
	Password string
	SuccessRate string `json:"success_rate"`
	Upvotes string
	Posted string
}

// Account Collection
type AccountBook struct {
	Accounts []*AccountEntry
}

func main(){

	// adding usage
	flag.Usage = usage
	flag.Parse()

	args:=flag.Args()

	if len(args) != 1 {
		usage()
	}

	// fetching first argument
	query := args[0]

	accountBook,_ := bmn(query)
	if len(accountBook.Accounts) > 0 {
		printMessage(os.Stdout,strconv.Itoa(len(accountBook.Accounts))+" accounts for "+query)
	} else {
		printMessage(os.Stdout,"No accounts for this domain.")
	}

	for _,account := range accountBook.Accounts {
		printAccount(os.Stdout,account)
	}
}

// Usage

const usageTmpl = `BMN is a command-line utility to find logins/passwords for websites that force you to register.
Usage:
  bmn [website]
`

func usage() {
	printUsage(os.Stderr)
	os.Exit(2)
}

func printUsage(w io.Writer) {
	tmpl(w, usageTmpl, nil)
}

// Result

const accountTmpl = `
	Username: {{.Username}}
	Password: {{.Password}}
	SuccessRate: {{.SuccessRate}}
	Upvotes: {{.Upvotes}}
	Posted: {{.Posted}}

`

func printAccount(w io.Writer,a *AccountEntry){
	tmpl(w,accountTmpl,a)
}

// Helper Functions

// Messages

const messageTmpl = `
	{{.Message}}
`
// printing message on command line
func printMessage(w io.Writer,msg string) {
	tmpl(w,messageTmpl,struct {Message string}{msg})
}

// logging error
func printErr(err error) {
	fmt.Fprintln(os.Stderr, err.Error())
	os.Exit(2)
}

const BASE_URL = "http://bugmenotapi.herokuapp.com/"

// Fetching data from bmn webservice
func bmn(website string)(*AccountBook,error) {

	res, err := http.Get(BASE_URL+website)
	if err != nil {
		return nil,err
	}
	body, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		return nil,err
	}
	var accountBook AccountBook
	json.Unmarshal(body,&accountBook)

	return &accountBook,nil
}

// Output template
func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	template.Must(t.Parse(text))
	if err := t.Execute(w, data); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/paypal/gatt"
	"log"
	"encoding/json"
)

type WifiNetwork struct {
	SSID string `json:"name"`
}

type WifiCredentials struct {
	SSID string `json:"ssid"`
	Key string `json:"key"`
}

func main() {
	// start by registering the RPC functions that will be accessible
	// once the client has authenticated
	rpc_router := JSONRPCRouter{}
	rpc_router.Init()
	rpc_router.AddHandler("sphere.setup.ping", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pong := JSONRPCResponse{"2.0", request.Id, 1234, nil}
		resp <- pong

		return resp
	})
	rpc_router.AddHandler("sphere.setup.get_visible_wifi_networks", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		wifi_networks := []WifiNetwork{
			{"SuperNinja"},
			{"MagicNet"},
		}

		pong := JSONRPCResponse{"2.0", request.Id, wifi_networks, nil}
		resp <- pong

		return resp
	})
	rpc_router.AddHandler("sphere.setup.connect_wifi_network", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		wifi_creds := new(WifiCredentials)
		b, _ := json.Marshal(request.Params[0])
		json.Unmarshal(b, wifi_creds)

		log.Println("Got wifi credentials", wifi_creds)

		pong := JSONRPCResponse{"2.0", request.Id, 1, nil}
		resp <- pong

		return resp
	})

	srv := &gatt.Server{Name: "ninjasphere"}

	auth_handler := new(OneTimeAuthHandler)
	auth_handler.Init("spheramid")

	RegisterSecuredRPCService(srv, rpc_router, auth_handler)

	// Start the server
	log.Println("Starting setup assistant...");
	log.Fatal(srv.AdvertiseAndServe())
}<commit_msg>Setup wifi and return the serial for activation.<commit_after>package main

import (
	"github.com/paypal/gatt"
	"log"
	"encoding/json"
	"github.com/theojulienne/go-wireless/iwlib"
	"os"
	"os/exec"
	"io"
	"strings"
)

type WifiNetwork struct {
	SSID string `json:"name"`
}

type WifiCredentials struct {
	SSID string `json:"ssid"`
	Key string `json:"key"`
}

const WPASupplicantTemplate = `
ctrl_interface=/var/run/wpa_supplicant
update_config=1
p2p_disabled=1

network={
	ssid="{{ssid}}"
	scan_ssid=1
	psk="{{key}}"
	key_mgmt=WPA-PSK
}
`

const WLANInterfaceTemplate = `
auto wlan0
iface wlan0 inet dhcp
	pre-up /usr/local/sbin/wpa_supplicant -B -D nl80211 -i wlan0 -c /etc/wpa_supplicant.conf
	post-down /usr/bin/killall -q wpa_supplicant
`

func WriteToFile(filename string, contents string) error {
	f, err := os.Create(filename)
	if err != nil {
		return err
	}

	defer f.Close()

	_, err = io.WriteString(f, contents)
	if err != nil {
		return err
	}

	return nil
}

func main() {
	// start by registering the RPC functions that will be accessible
	// once the client has authenticated
	rpc_router := JSONRPCRouter{}
	rpc_router.Init()
	rpc_router.AddHandler("sphere.setup.ping", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		pong := JSONRPCResponse{"2.0", request.Id, 1234, nil}
		resp <- pong

		return resp
	})
	rpc_router.AddHandler("sphere.setup.get_visible_wifi_networks", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		networks, err := iwlib.GetWirelessNetworks("wlan0")
		if err == nil {
			wifi_networks := make([]WifiNetwork, len(networks))
			for i, network := range networks {
				wifi_networks[i].SSID = network.SSID
			}

			resp <- JSONRPCResponse{"2.0", request.Id, wifi_networks, nil}
		} else {
			resp <- JSONRPCResponse{"2.0", request.Id, nil, &JSONRPCError{500, "Could not retrieve WiFi networks", nil}}
		}

		return resp
	})
	rpc_router.AddHandler("sphere.setup.connect_wifi_network", func (request JSONRPCRequest) chan JSONRPCResponse {
		resp := make(chan JSONRPCResponse, 1)

		wifi_creds := new(WifiCredentials)
		b, _ := json.Marshal(request.Params[0])
		json.Unmarshal(b, wifi_creds)

		log.Println("Got wifi credentials", wifi_creds)

		s := strings.Replace(WPASupplicantTemplate,"{{ssid}}",wifi_creds.SSID,-1)
		s = strings.Replace(s,"{{key}}",wifi_creds.Key,-1)

		go func() {
			WriteToFile("/etc/wpa_supplicant.conf", s)
			WriteToFile("/etc/network/interfaces.d/wlan0", WLANInterfaceTemplate)

			cmd := exec.Command("ifup", "wlan0")
			cmd.Start()
			cmd.Wait() // shit will break badly if this fails :/

			serial_number, err := exec.Command("/opt/ninjablocks/bin/sphere-serial").Output()
			if err != nil {
				// ow ow ow
			}

			pong := JSONRPCResponse{"2.0", request.Id, serial_number, nil}
			resp <- pong
		}()

		return resp
	})

	srv := &gatt.Server{Name: "ninjasphere"}

	auth_handler := new(OneTimeAuthHandler)
	auth_handler.Init("spheramid")

	RegisterSecuredRPCService(srv, rpc_router, auth_handler)

	// Start the server
	log.Println("Starting setup assistant...");
	log.Fatal(srv.AdvertiseAndServe())
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"time"

	"bitbucket.org/harfangapps/regis-companion/server"
	"bitbucket.org/harfangapps/regis-companion/sshconfig"
)

var (
	versionFlag           = flag.Bool("version", false, "Print the version.")
	addrFlag              = flag.String("addr", "127.0.0.1", "Server `address` to bind to.")
	portFlag              = flag.Int("port", 7070, "Port `number` to listen on.")
	tunnelIdleTimeoutFlag = flag.Duration("tunnel-idle-timeout", 30*time.Minute, "Idle `timeout` for inactive SSH tunnels.")
	writeTimeoutFlag      = flag.Duration("write-timeout", 30*time.Second, "Write `timeout`.")
	sshDialTimeoutFlag    = flag.Duration("ssh-dial-timeout", 30*time.Second, "SSH dial `timeout`.")
	knownHostsFileFlag    = flag.String("known-hosts-file", "${HOME}/.ssh/known_hosts", "Known hosts `file`.")
)

func main() {
	flag.Parse()

	if *versionFlag {
		fmt.Printf("%s (git:%s go:%s)\n", server.Version, server.GitHash, runtime.Version())
		return
	}

	ip := net.ParseIP(*addrFlag)
	if ip == nil {
		log.Fatalf("invalid address: %v", *addrFlag)
	}

	// handle SIGINT
	ctx, cancel := context.WithCancel(context.Background())
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		<-ch
		fmt.Println("received interrupt signal, stopping...")
		cancel()
	}()

	// configure and start the server
	meta := &sshconfig.MetaConfig{
		KnownHostsFile: *knownHostsFileFlag,
		SSHDialTimeout: *sshDialTimeoutFlag,
	}

	srv := &server.Server{
		Addr:              &net.TCPAddr{IP: ip, Port: *portFlag},
		MetaConfig:        meta,
		TunnelIdleTimeout: *tunnelIdleTimeoutFlag,
		WriteTimeout:      *writeTimeoutFlag,
	}
	if err := srv.ListenAndServe(ctx); err != nil {
		log.Fatalf("exit with error %v", err)
	}
}
<commit_msg>main: expand the known hosts file flag<commit_after>package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"runtime"
	"time"

	"bitbucket.org/harfangapps/regis-companion/server"
	"bitbucket.org/harfangapps/regis-companion/sshconfig"
)

var (
	versionFlag           = flag.Bool("version", false, "Print the version.")
	addrFlag              = flag.String("addr", "127.0.0.1", "Server `address` to bind to.")
	portFlag              = flag.Int("port", 7070, "Port `number` to listen on.")
	tunnelIdleTimeoutFlag = flag.Duration("tunnel-idle-timeout", 30*time.Minute, "Idle `timeout` for inactive SSH tunnels.")
	writeTimeoutFlag      = flag.Duration("write-timeout", 30*time.Second, "Write `timeout`.")
	sshDialTimeoutFlag    = flag.Duration("ssh-dial-timeout", 30*time.Second, "SSH dial `timeout`.")
	knownHostsFileFlag    = flag.String("known-hosts-file", "${HOME}/.ssh/known_hosts", "Known hosts `file`.")
)

func main() {
	flag.Parse()

	if *versionFlag {
		fmt.Printf("%s (git:%s go:%s)\n", server.Version, server.GitHash, runtime.Version())
		return
	}

	ip := net.ParseIP(*addrFlag)
	if ip == nil {
		log.Fatalf("invalid address: %v", *addrFlag)
	}

	// handle SIGINT
	ctx, cancel := context.WithCancel(context.Background())
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	go func() {
		<-ch
		fmt.Println("received interrupt signal, stopping...")
		cancel()
	}()

	// configure and start the server
	meta := &sshconfig.MetaConfig{
		KnownHostsFile: os.ExpandEnv(*knownHostsFileFlag),
		SSHDialTimeout: *sshDialTimeoutFlag,
	}

	srv := &server.Server{
		Addr:              &net.TCPAddr{IP: ip, Port: *portFlag},
		MetaConfig:        meta,
		TunnelIdleTimeout: *tunnelIdleTimeoutFlag,
		WriteTimeout:      *writeTimeoutFlag,
	}
	if err := srv.ListenAndServe(ctx); err != nil {
		log.Fatalf("exit with error %v", err)
	}
}
<|endoftext|>


<commit_before>package main

/*
   TODO:
   o oop
   o log
   o chunk i/o
   o keep alive
*/

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"strings"
)

type config struct {
	Bind    string
	Port    string
	Cmd     string
	CmdArgs []string
}

type option struct {
	Addr string
	Cmd  string
}

var deb bool
var opt option

func init() {
	const (
		verbUsage  = "Enable verbose"
		verbDefVal = false
	)

	flag.BoolVar(&deb, "v", verbDefVal, verbUsage)
	flag.BoolVar(&deb, "verbose", verbDefVal, verbUsage)

	flag.StringVar(&opt.Addr, "addr", "127.0.0.1:3131", "Ip address to bind")
	flag.StringVar(&opt.Cmd, "cmd", "", "Command to run")
}

func main() {
	flag.Parse()
	debug("%s", opt)

	conf := getConf()
	listener := getListener(conf)
	run(conf, listener)
}

func getConf() config {
	conf := config{
		Bind:    "127.0.0.1",
		Port:    "3000",
		Cmd:     "tee",
		CmdArgs: []string{},
	}

	if len(opt.Addr) > 0 {
		conf.Bind, conf.Port = parseOptAddr(opt.Addr)
	}

	if len(opt.Cmd) > 0 {
		conf.Cmd, conf.CmdArgs = parseOptCmd(opt.Cmd)
	}

	debug("Config: %s", conf)
	return conf
}

func parseOptAddr(addr string) (string, string) {
	addrs := strings.Split(addr, ":")
	if len(addrs) != 2 {
		printUsage()
		log.Fatal("Unable to parse addr")
	}
	return addrs[0], addrs[1]
}

func parseOptCmd(cmd string) (string, []string) {
	cmds := strings.Split(cmd, " ")
	if len(cmds[0]) == 0 || len(cmds) < 1 {
		printUsage()
		log.Fatal("Unable to parse cmd. cmd is required!")
	}

	args := make([]string, 0)
	for _, arg := range cmds[1:] {
		if arg == "" || arg == " " {
			continue
		}
		args = append(args, arg)
	}

	return cmds[0], args
}

func printUsage() {
	fmt.Println("Usage: tcpserver [--addr 0.0.0.0:3000] --cmd 'tr a-z A-Z'")
	flag.PrintDefaults()
	fmt.Println()
}

func getListener(conf config) net.Listener {
	addr := conf.Bind + ":" + conf.Port
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(fmt.Sprintf("Unable to listen to address: [%v] ERROR: %v", addr, err))
	}
	debug("Listenning to: %v", ln.Addr())
	return ln
}

func run(conf config, listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			errr("Something went wrong while connecting! ERROR: %v", err)
		} else {
			go handleConn(conn, conf)
		}
	}
}

func getCmd(conf config) *exec.Cmd {
	cmd := exec.Command(conf.Cmd)
	for _, arg := range conf.CmdArgs {
		cmd.Args = append(cmd.Args, arg)
	}
	debug("cmd: %s", cmd.Args)
	return cmd
}

func handleConn(conn net.Conn, conf config) {
	defer conn.Close()

	cmd := getCmd(conf)
	remote := conn.RemoteAddr()
	from := fmt.Sprintf("%s ", remote)
	debug("Accepted connection from: %v", remote)

	cnt := 0
	var prev string
	var str string
	sc := bufio.NewScanner(conn)
	for sc.Scan() {
		curr := sc.Text()
		debug("%s-> data: [%s]", from, curr)
		if cnt > 0 &&
			strings.Compare(prev, "") == 0 &&
			strings.Compare(curr, prev) == 0 {
			runCmd(cmd, conn, str)
			return
		}
		str += fmt.Sprintf("%s\n", curr)
		prev = curr
		cnt++
	}
	if err := sc.Err(); err != nil {
		errr("reading err [%v]", err)
	}

	debug(from + "XX ... connection closed")
}

func runCmd(cmd *exec.Cmd, conn net.Conn, str string) {
	from := fmt.Sprintf("%s ", conn.RemoteAddr())
	debug("echo '%s' | %s", str, opt.Cmd)

	cmd.Stdin = strings.NewReader(str)
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	if err != nil {
		errr("%s!! Failed to exec! ERROR: %s\n", from, err)
		errstr := strings.NewReader(fmt.Sprintf("err: %s\n", err))
		io.Copy(conn, errstr)
		return
	}

	debug(from + "!! ... Ran cmd")
	debug("%s", cmd.ProcessState)
}

func debug(pattern string, args ...interface{}) {
	if !deb {
		return
	}
	pattern = "[debug] " + pattern
	log.Printf(pattern, args...)
}

func errr(pattern string, args ...interface{}) {
	pattern = "[error] " + pattern
	log.Printf(pattern, args...)
}
<commit_msg>Some logging stuff<commit_after>package main

/*
   TODO:
   o oop
   o keep alive
*/

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os/exec"
	"strings"
)

type config struct {
	Bind    string
	Port    string
	Cmd     string
	CmdArgs []string
}

type option struct {
	Addr string
	Cmd  string
}

var deb bool
var opt option

func init() {
	const (
		verbUsage  = "Enable verbose"
		verbDefVal = false
	)

	flag.BoolVar(&deb, "v", verbDefVal, verbUsage)
	flag.BoolVar(&deb, "verbose", verbDefVal, verbUsage)

	flag.StringVar(&opt.Addr, "addr", "127.0.0.1:3131", "Ip address to bind")
	flag.StringVar(&opt.Cmd, "cmd", "", "Command to run")
}

func main() {
	flag.Parse()
	debug("%s", opt)

	conf := getConf()
	listener := getListener(conf)
	run(conf, listener)
}

func getConf() config {
	conf := config{
		Bind:    "127.0.0.1",
		Port:    "3000",
		Cmd:     "tee",
		CmdArgs: []string{},
	}

	if len(opt.Addr) > 0 {
		conf.Bind, conf.Port = parseOptAddr(opt.Addr)
	}

	if len(opt.Cmd) > 0 {
		conf.Cmd, conf.CmdArgs = parseOptCmd(opt.Cmd)
	}

	debug("Config: %s", conf)
	return conf
}

func parseOptAddr(addr string) (string, string) {
	addrs := strings.Split(addr, ":")
	if len(addrs) != 2 {
		printUsage()
		log.Fatal("Unable to parse addr")
	}
	return addrs[0], addrs[1]
}

func parseOptCmd(cmd string) (string, []string) {
	cmds := strings.Split(cmd, " ")
	if len(cmds[0]) == 0 || len(cmds) < 1 {
		printUsage()
		log.Fatal("Unable to parse cmd. cmd is required!")
	}

	args := make([]string, 0)
	for _, arg := range cmds[1:] {
		if arg == "" || arg == " " {
			continue
		}
		args = append(args, arg)
	}

	return cmds[0], args
}

func printUsage() {
	fmt.Println("Usage: tcpserver [--addr 0.0.0.0:3000] --cmd 'tr a-z A-Z'")
	flag.PrintDefaults()
	fmt.Println()
}

func getListener(conf config) net.Listener {
	addr := conf.Bind + ":" + conf.Port
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal(fmt.Sprintf("Unable to listen to address: [%v] ERROR: %v", addr, err))
	}
	debug("Listenning to: %v", ln.Addr())
	return ln
}

func run(conf config, listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			errr("Something went wrong while connecting! ERROR: %v", err)
		} else {
			go handleConn(conn, conf)
		}
	}
}

func getCmd(conf config) *exec.Cmd {
	cmd := exec.Command(conf.Cmd)
	for _, arg := range conf.CmdArgs {
		cmd.Args = append(cmd.Args, arg)
	}
	debug("cmd: %s", cmd.Args)
	return cmd
}

func handleConn(conn net.Conn, conf config) {
	defer conn.Close()

	cmd := getCmd(conf)
	remote := conn.RemoteAddr()
	from := fmt.Sprintf("%s ", remote)
	debug("Accepted connection from: %v", remote)

	cnt := 0
	var prev string
	var str string
	sc := bufio.NewScanner(conn)
	for sc.Scan() {
		curr := sc.Text()
		debug("%s-> data: [%s]", from, curr)
		if cnt > 0 &&
			strings.Compare(prev, "") == 0 &&
			strings.Compare(curr, prev) == 0 {
			runCmd(cmd, conn, str)
			return
		}
		str += fmt.Sprintf("%s\n", curr)
		prev = curr
		cnt++
	}
	if err := sc.Err(); err != nil {
		errr("reading err [%v]", err)
	}

	debug(from + "XX ... connection closed")
}

func runCmd(cmd *exec.Cmd, conn net.Conn, str string) {
	from := fmt.Sprintf("%s", conn.RemoteAddr())
	debug("echo '%s' | %s", str, opt.Cmd)

	cmd.Stdin = strings.NewReader(str)
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	if err != nil {
		errr("%s !! Failed to exec! ERROR: %s\n", from, err)
		errstr := strings.NewReader(fmt.Sprintf("err: %s\n", err))
		io.Copy(conn, errstr)
		return
	}

	debug("%s <- ... Ran cmd", from)
	debug("!! ... %s", cmd.ProcessState)
}

func debug(pattern string, args ...interface{}) {
	if !deb {
		return
	}
	pattern = "[debug] " + pattern
	log.Printf(pattern, args...)
}

func errr(pattern string, args ...interface{}) {
	pattern = "[error] " + pattern
	log.Printf(pattern, args...)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"

	"github.com/golang/protobuf/proto"
	clientmodel "github.com/prometheus/client_golang/model"
	"github.com/prometheus/log"

	"github.com/prometheus/migrate/v0x13"
	"github.com/prometheus/migrate/v0x14"
)

var outName = flag.String("out", "-", "Target for writing the output")

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [args ...] [<config_file>]", flag.Arg(0))

	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	flag.Parse()

	var (
		err error
		in  io.Reader = os.Stdin
		out io.Writer = os.Stdout
	)

	if flag.NArg() > 0 {
		filename := flag.Args()[0]
		in, err = os.Open(filename)
		if err != nil {
			log.Fatalf("Error opening input file: %s", err)
		}
		log.Infof("Translating file %s", filename)
	}

	if err := translate(in, out); err != nil {
		log.Fatal(err)
	}
}

func translate(in io.Reader, out io.Writer) error {
	b, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}
	var oldConf v0x13.Config
	err = proto.UnmarshalText(string(b), &oldConf.PrometheusConfig)
	if err != nil {
		return fmt.Errorf("Error parsing old config file: %s", err)
	}

	var newGlobConf v0x14.GlobalConfig

	newGlobConf.ScrapeInterval = v0x14.Duration(oldConf.ScrapeInterval())
	// The global scrape timeout is new and will be set to the global scrape interval.
	newGlobConf.ScrapeTimeout = newGlobConf.ScrapeInterval
	newGlobConf.EvaluationInterval = v0x14.Duration(oldConf.EvaluationInterval())

	var newConf v0x14.Config

	newConf.GlobalConfig = &newGlobConf
	if oldConf.Global != nil {
		newConf.RuleFiles = oldConf.Global.GetRuleFile()
	}

	var scrapeConfs []*v0x14.ScrapeConfig
	for _, oldJob := range oldConf.Jobs() {
		scfg := &v0x14.ScrapeConfig{}

		scfg.JobName = oldJob.GetName()

		var firstScheme string
		var firstPath string
		for _, oldTG := range oldJob.TargetGroup {
			newTG := &v0x14.TargetGroup{
				Labels: clientmodel.LabelSet{},
			}

			for _, t := range oldTG.Target {
				u, err := url.Parse(t)
				if err != nil {
					return err
				}
				fmt.Println(u, u.Host)

				if firstScheme == "" {
					firstScheme = u.Scheme
				} else if u.Scheme != firstScheme {
					return fmt.Errorf("Multiple URL schemes in Job not allowed.")
				}
				if firstPath == "" {
					firstPath = u.Path
				} else if u.Path != firstPath {
					return fmt.Errorf("Multiple paths in Job not allowed")
				}

				newTG.Targets = append(newTG.Targets, clientmodel.LabelSet{
					clientmodel.AddressLabel: clientmodel.LabelValue(u.Host),
				})

			}

			for _, lp := range oldTG.GetLabels().GetLabel() {
				ln := clientmodel.LabelName(lp.GetName())
				lv := clientmodel.LabelValue(lp.GetValue())
				newTG.Labels[ln] = lv
			}
			scfg.TargetGroups = append(scfg.TargetGroups, newTG)
		}
		scfg.Scheme = firstScheme

		scrapeConfs = append(scrapeConfs, scfg)
	}

	newConf.ScrapeConfigs = scrapeConfs

	return nil
}
<commit_msg>Do basic translation to YAML<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/url"
	"os"

	"github.com/golang/protobuf/proto"
	clientmodel "github.com/prometheus/client_golang/model"
	"github.com/prometheus/log"
	"gopkg.in/yaml.v2"

	"github.com/prometheus/migrate/v0x13"
	"github.com/prometheus/migrate/v0x14"
)

var outName = flag.String("out", "-", "Target for writing the output")

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [args ...] [<config_file>]", flag.Arg(0))

	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	flag.Parse()

	var (
		err error
		in  io.Reader = os.Stdin
		out io.Writer = os.Stdout
	)

	if flag.NArg() > 0 {
		filename := flag.Args()[0]
		in, err = os.Open(filename)
		if err != nil {
			log.Fatalf("Error opening input file: %s", err)
		}
		log.Infof("Translating file %s", filename)
	}

	if err := translate(in, out); err != nil {
		log.Fatal(err)
	}
}

func translate(in io.Reader, out io.Writer) error {
	b, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}
	var oldConf v0x13.Config
	err = proto.UnmarshalText(string(b), &oldConf.PrometheusConfig)
	if err != nil {
		return fmt.Errorf("Error parsing old config file: %s", err)
	}

	var newGlobConf v0x14.GlobalConfig

	newGlobConf.ScrapeInterval = v0x14.Duration(oldConf.ScrapeInterval())
	// The global scrape timeout is new and will be set to the global scrape interval.
	newGlobConf.ScrapeTimeout = newGlobConf.ScrapeInterval
	newGlobConf.EvaluationInterval = v0x14.Duration(oldConf.EvaluationInterval())

	var newConf v0x14.Config

	newConf.GlobalConfig = &newGlobConf
	if oldConf.Global != nil {
		newConf.RuleFiles = oldConf.Global.GetRuleFile()
	}

	var scrapeConfs []*v0x14.ScrapeConfig
	for _, oldJob := range oldConf.Jobs() {
		scfg := &v0x14.ScrapeConfig{}

		scfg.JobName = oldJob.GetName()

		var firstScheme string
		var firstPath string
		for _, oldTG := range oldJob.TargetGroup {
			newTG := &v0x14.TargetGroup{
				Labels: clientmodel.LabelSet{},
			}

			for _, t := range oldTG.Target {
				u, err := url.Parse(t)
				if err != nil {
					return err
				}

				if firstScheme == "" {
					firstScheme = u.Scheme
				} else if u.Scheme != firstScheme {
					return fmt.Errorf("Multiple URL schemes in Job not allowed.")
				}
				if firstPath == "" {
					firstPath = u.Path
				} else if u.Path != firstPath {
					return fmt.Errorf("Multiple paths in Job not allowed")
				}

				newTG.Targets = append(newTG.Targets, clientmodel.LabelSet{
					clientmodel.AddressLabel: clientmodel.LabelValue(u.Host),
				})
			}

			for _, lp := range oldTG.GetLabels().GetLabel() {
				ln := clientmodel.LabelName(lp.GetName())
				lv := clientmodel.LabelValue(lp.GetValue())
				newTG.Labels[ln] = lv
			}
			scfg.TargetGroups = append(scfg.TargetGroups, newTG)
		}
		scfg.Scheme = firstScheme

		scrapeConfs = append(scrapeConfs, scfg)
	}

	newConf.ScrapeConfigs = scrapeConfs

	res, err := yaml.Marshal(newConf)
	if err != nil {
		return err
	}

	if _, err := out.Write(res); err != nil {
		return err
	}
	return nil
}
<|endoftext|>