<commit_before>package main

import (
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/alecthomas/kingpin"
	"github.com/jmoiron/sqlx"
	"github.com/sgt-kabukiman/kabukibot/bot"
	"github.com/sgt-kabukiman/kabukibot/plugin/acl"
	"github.com/sgt-kabukiman/kabukibot/plugin/banhammer_bot"
	"github.com/sgt-kabukiman/kabukibot/plugin/blacklist"
	"github.com/sgt-kabukiman/kabukibot/plugin/content"
	"github.com/sgt-kabukiman/kabukibot/plugin/custom_commands"
	"github.com/sgt-kabukiman/kabukibot/plugin/dictionary"
	"github.com/sgt-kabukiman/kabukibot/plugin/domain_ban"
	"github.com/sgt-kabukiman/kabukibot/plugin/echo"
	"github.com/sgt-kabukiman/kabukibot/plugin/emote_counter"
	"github.com/sgt-kabukiman/kabukibot/plugin/join"
	"github.com/sgt-kabukiman/kabukibot/plugin/log"
	"github.com/sgt-kabukiman/kabukibot/plugin/monitor"
	"github.com/sgt-kabukiman/kabukibot/plugin/ping"
	"github.com/sgt-kabukiman/kabukibot/plugin/plugin_control"
	"github.com/sgt-kabukiman/kabukibot/plugin/speedruncom"
	"github.com/sgt-kabukiman/kabukibot/plugin/subhype"
	"github.com/sgt-kabukiman/kabukibot/plugin/sysinfo"
	"github.com/sgt-kabukiman/kabukibot/plugin/troll"
	"github.com/sgt-kabukiman/kabukibot/twitch"
)

var (
	configFile   = kingpin.Flag("config", "Path to the config file to use").Required().String()
	channelsFile = kingpin.Flag("channels", "Path to a file of channels to join after connecting").String()
	debug        = kingpin.Flag("debug", "Enable debug output").Bool()
)

func main() {
	kingpin.Parse()

	// create logger
	level := bot.LogLevelInfo
	if *debug {
		level = bot.LogLevelDebug
	}

	logger := bot.NewLogger(level)

	// load configuration
	logger.Info("Loading configuration file @ " + *configFile + "...")
	config, err := bot.LoadConfiguration(*configFile)
	if err != nil {
		logger.Fatal(err.Error())
	}

	var channels []string

	if *channelsFile != "" {
		logger.Info("Reading initial channel list @ " + *channelsFile + "...")
		data, err := ioutil.ReadFile(*channelsFile)
		if err != nil {
			logger.Fatal(err.Error())
		}

		channels = strings.Split(string(data), "\n")
	}

	// connect to database
	logger.Info("Connecting to database @ %s...", config.Database.DSN)
	db, err := sqlx.Connect("mysql", config.Database.DSN)
	if err != nil {
		logger.Fatal(err.Error())
	}

	// setup our TwitchClient
	server := net.JoinHostPort(config.IRC.Host, strconv.Itoa(config.IRC.Port))
	twitch := twitch.NewTwitchClient(server, config.Account.Username, config.Account.Password, 2*time.Second)

	// build the bot
	kabukibot, err := bot.NewKabukibot(twitch, logger, db, config)
	if err != nil {
		logger.Fatal(err.Error())
	}

	// add plugins
	kabukibot.AddPlugin(blacklist.NewPlugin()) // load this as early as possible, because users will only be blacklisted for all following plugins
	kabukibot.AddPlugin(log.NewPlugin())
	kabukibot.AddPlugin(ping.NewPlugin())
	kabukibot.AddPlugin(join.NewPlugin())
	kabukibot.AddPlugin(acl.NewPlugin())
	kabukibot.AddPlugin(plugin_control.NewPlugin())
	kabukibot.AddPlugin(speedruncom.NewPlugin())
	kabukibot.AddPlugin(echo.NewPlugin())
	kabukibot.AddPlugin(sysinfo.NewPlugin())
	kabukibot.AddPlugin(dictionary.NewPlugin())
	kabukibot.AddPlugin(domain_ban.NewPlugin())
	kabukibot.AddPlugin(banhammer_bot.NewPlugin())
	kabukibot.AddPlugin(emote_counter.NewPlugin())
	kabukibot.AddPlugin(subhype.NewPlugin())
	kabukibot.AddPlugin(troll.NewPlugin())
	kabukibot.AddPlugin(monitor.NewPlugin())
	kabukibot.AddPlugin(custom_commands.NewPlugin())
	kabukibot.AddPlugin(content.NewGTAPlugin())
	kabukibot.AddPlugin(content.NewCrashPlugin())
	kabukibot.AddPlugin(content.NewChattyPlugin())
	kabukibot.AddPlugin(content.NewSDAPlugin())
	kabukibot.AddPlugin(content.NewESAPlugin())

	// here we go
	err = kabukibot.Connect()
	if err != nil {
		logger.Fatal(err.Error())
	}

	// do your thing, kabukibot
	logger.Info("Letting the magic happen...")
	go kabukibot.Work()

	for _, cn := range channels {
		<-kabukibot.Join(cn)
	}

	// wait for disconnect
	<-kabukibot.Alive()
}
<commit_msg>do not print the DSN, as it probably contains the password<commit_after>package main

import (
	"io/ioutil"
	"net"
	"strconv"
	"strings"
	"time"

	"github.com/alecthomas/kingpin"
	"github.com/jmoiron/sqlx"
	"github.com/sgt-kabukiman/kabukibot/bot"
	"github.com/sgt-kabukiman/kabukibot/plugin/acl"
	"github.com/sgt-kabukiman/kabukibot/plugin/banhammer_bot"
	"github.com/sgt-kabukiman/kabukibot/plugin/blacklist"
	"github.com/sgt-kabukiman/kabukibot/plugin/content"
	"github.com/sgt-kabukiman/kabukibot/plugin/custom_commands"
	"github.com/sgt-kabukiman/kabukibot/plugin/dictionary"
	"github.com/sgt-kabukiman/kabukibot/plugin/domain_ban"
	"github.com/sgt-kabukiman/kabukibot/plugin/echo"
	"github.com/sgt-kabukiman/kabukibot/plugin/emote_counter"
	"github.com/sgt-kabukiman/kabukibot/plugin/join"
	"github.com/sgt-kabukiman/kabukibot/plugin/log"
	"github.com/sgt-kabukiman/kabukibot/plugin/monitor"
	"github.com/sgt-kabukiman/kabukibot/plugin/ping"
	"github.com/sgt-kabukiman/kabukibot/plugin/plugin_control"
	"github.com/sgt-kabukiman/kabukibot/plugin/speedruncom"
	"github.com/sgt-kabukiman/kabukibot/plugin/subhype"
	"github.com/sgt-kabukiman/kabukibot/plugin/sysinfo"
	"github.com/sgt-kabukiman/kabukibot/plugin/troll"
	"github.com/sgt-kabukiman/kabukibot/twitch"
)

var (
	configFile   = kingpin.Flag("config", "Path to the config file to use").Required().String()
	channelsFile = kingpin.Flag("channels", "Path to a file of channels to join after connecting").String()
	debug        = kingpin.Flag("debug", "Enable debug output").Bool()
)

func main() {
	kingpin.Parse()

	// create logger
	level := bot.LogLevelInfo
	if *debug {
		level = bot.LogLevelDebug
	}

	logger := bot.NewLogger(level)

	// load configuration
	logger.Info("Loading configuration file @ " + *configFile + "...")
	config, err := bot.LoadConfiguration(*configFile)
	if err != nil {
		logger.Fatal(err.Error())
	}

	var channels []string

	if *channelsFile != "" {
		logger.Info("Reading initial channel list @ " + *channelsFile + "...")
		data, err := ioutil.ReadFile(*channelsFile)
		if err != nil {
			logger.Fatal(err.Error())
		}

		channels = strings.Split(string(data), "\n")
	}

	// connect to database
	logger.Info("Connecting to database...")
	db, err := sqlx.Connect("mysql", config.Database.DSN)
	if err != nil {
		logger.Fatal(err.Error())
	}

	// setup our TwitchClient
	server := net.JoinHostPort(config.IRC.Host, strconv.Itoa(config.IRC.Port))
	twitch := twitch.NewTwitchClient(server, config.Account.Username, config.Account.Password, 2*time.Second)

	// build the bot
	kabukibot, err := bot.NewKabukibot(twitch, logger, db, config)
	if err != nil {
		logger.Fatal(err.Error())
	}

	// add plugins
	kabukibot.AddPlugin(blacklist.NewPlugin()) // load this as early as possible, because users will only be blacklisted for all following plugins
	kabukibot.AddPlugin(log.NewPlugin())
	kabukibot.AddPlugin(ping.NewPlugin())
	kabukibot.AddPlugin(join.NewPlugin())
	kabukibot.AddPlugin(acl.NewPlugin())
	kabukibot.AddPlugin(plugin_control.NewPlugin())
	kabukibot.AddPlugin(speedruncom.NewPlugin())
	kabukibot.AddPlugin(echo.NewPlugin())
	kabukibot.AddPlugin(sysinfo.NewPlugin())
	kabukibot.AddPlugin(dictionary.NewPlugin())
	kabukibot.AddPlugin(domain_ban.NewPlugin())
	kabukibot.AddPlugin(banhammer_bot.NewPlugin())
	kabukibot.AddPlugin(emote_counter.NewPlugin())
	kabukibot.AddPlugin(subhype.NewPlugin())
	kabukibot.AddPlugin(troll.NewPlugin())
	kabukibot.AddPlugin(monitor.NewPlugin())
	kabukibot.AddPlugin(custom_commands.NewPlugin())
	kabukibot.AddPlugin(content.NewGTAPlugin())
	kabukibot.AddPlugin(content.NewCrashPlugin())
	kabukibot.AddPlugin(content.NewChattyPlugin())
	kabukibot.AddPlugin(content.NewSDAPlugin())
	kabukibot.AddPlugin(content.NewESAPlugin())

	// here we go
	err = kabukibot.Connect()
	if err != nil {
		logger.Fatal(err.Error())
	}

	// do your thing, kabukibot
	logger.Info("Letting the magic happen...")
	go kabukibot.Work()

	for _, cn := range channels {
		<-kabukibot.Join(cn)
	}

	// wait for disconnect
	<-kabukibot.Alive()
}
<|endoftext|>


<commit_before>package main

import(
  "github.com/TykTechnologies/tykcommon"

  "encoding/json"
  "fmt"
  "flag"
  "errors"
  "io/ioutil"
  "bytes"
  "archive/zip"
  "crypto/md5"
  "strings"
  "os"
  "io"
)

// tyk-cli <module> <submodule> <command> [--options] args...

var module, submodule, command string

var bundleOutput string

const(
  defaultBundleOutput = "bundle.zip"
)

func init() {
  if len(os.Args) == 1 {
    fmt.Println("No module specified!")
    os.Exit(1)
  }
  if len(os.Args) == 2 {
    fmt.Println("No command specified!")
    os.Exit(1)
  }

  module = os.Args[1]
  command = os.Args[2]

  os.Args = os.Args[2:]

  flag.StringVar(&bundleOutput, "output", "", "Bundle output")
  flag.Parse()
}

// main is the entrypoint.
func main() {
  fmt.Println("tyk-cli:", flag.CommandLine, os.Args)

  fmt.Println("module =", module)
  fmt.Println("command =", command)

  var err error

  switch module {
  case "bundle":
    fmt.Println("Using bundle module.")
    err = bundle(command)
  default:
    err = errors.New("Invalid module")
  }

  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(1)
  }
}

// bundle will handle the bundle command calls.
func bundle(command string) (err error) {
  switch command {
  case "build":
    var manifestPath = "./manifest.json"
    if _, err := os.Stat(manifestPath); err == nil {
      var manifestData []byte
      manifestData, err = ioutil.ReadFile(manifestPath)

      var manifest tykcommon.BundleManifest
      err = json.Unmarshal(manifestData, &manifest)

      if err != nil {
        fmt.Println("Couldn't parse manifest file!")
        break
      }

      err = bundleValidateManifest(&manifest)

      if err != nil {
        fmt.Println("Bundle validation error:")
        fmt.Println(err)
        break
      }

      // The manifest is valid, we should do the checksum and sign step at this point.
      bundleBuild(&manifest)

    } else {
      err = errors.New("Manifest file doesn't exist.")
    }
  default:
    err = errors.New("Invalid command.")
  }
  return err
}

// bundleValidateManifest will validate the manifest file before building a bundle.
func bundleValidateManifest(manifest *tykcommon.BundleManifest) (err error) {
  // Validate manifest file list:
  for _, file := range manifest.FileList {
    if _, statErr := os.Stat(file); statErr != nil {
      err = errors.New("Referencing a nonexistent file: " + file)
      break
    }
  }

  // The custom middleware block must specify at least one hook:
  var definedHooks int
  definedHooks = len(manifest.CustomMiddleware.Pre) + len(manifest.CustomMiddleware.Post) + len(manifest.CustomMiddleware.PostKeyAuth)

  if manifest.CustomMiddleware.AuthCheck.Name != "" {
    definedHooks++
  }

  if definedHooks == 0 {
    err = errors.New("No hooks defined!")
    return err
  }

  // The custom middleware block must specify a driver:
  if manifest.CustomMiddleware.Driver == "" {
    err = errors.New("No driver specified!")
    return err
  }

  return err
}

// bundleBuild will build and generate a bundle file.
func bundleBuild(manifest *tykcommon.BundleManifest) (err error) {
  if bundleOutput == "" {
    fmt.Println("No output specified, using bundle.zip")
    bundleOutput = defaultBundleOutput
  }

  var bundleChecksums []string
  for _, file := range manifest.FileList {
    var data []byte
    data, err = ioutil.ReadFile(file)
    if err != nil {
      return err
    }
    hash := fmt.Sprintf("%x", md5.Sum(data))
    bundleChecksums = append(bundleChecksums, hash)
  }

  mergedChecksums := strings.Join(bundleChecksums, "")
  manifest.Checksum = fmt.Sprintf("%x", md5.Sum([]byte(mergedChecksums)))

  var newManifestData []byte
  newManifestData, err = json.Marshal(&manifest)

  // Write the bundle file:
  buf := new(bytes.Buffer)
  bundleWriter := zip.NewWriter(buf)

  for _, file := range manifest.FileList {
    var outputFile io.Writer
    outputFile, err = bundleWriter.Create(file)
    if err != nil {
      return err
    }
    var data []byte
    data, err = ioutil.ReadFile(file)

    _, err = outputFile.Write(data)

    if err != nil {
      return err
    }
  }

  // Write manifest file:
  var newManifest io.Writer
  newManifest, err = bundleWriter.Create("manifest.json")
  _, err = newManifest.Write(newManifestData)

  err = bundleWriter.Close()
  err = ioutil.WriteFile(bundleOutput, buf.Bytes(), 0755)

  return err
}
<commit_msg>tyk-85: Bundle signing feature.<commit_after>package main

import(
  "github.com/TykTechnologies/tykcommon"
  "github.com/TykTechnologies/goverify"

  "encoding/base64"
  "encoding/json"
  "fmt"
  "flag"
  "errors"
  "io/ioutil"
  "bytes"
  "archive/zip"
  "crypto/md5"
  "strings"
  "os"
  "io"
)

// tyk-cli <module> <submodule> <command> [--options] args...

var module, submodule, command string

var bundleOutput, privKey string

const(
  defaultBundleOutput = "bundle.zip"
)

func init() {
  if len(os.Args) == 1 {
    fmt.Println("No module specified!")
    os.Exit(1)
  }
  if len(os.Args) == 2 {
    fmt.Println("No command specified!")
    os.Exit(1)
  }

  module = os.Args[1]
  command = os.Args[2]

  os.Args = os.Args[2:]

  flag.StringVar(&bundleOutput, "output", "", "Bundle output")
  flag.StringVar(&privKey, "key", "", "Key for bundle signature")

  flag.Parse()
}

// main is the entrypoint.
func main() {
  fmt.Println("tyk-cli:", flag.CommandLine, os.Args)

  fmt.Println("module =", module)
  fmt.Println("command =", command)

  var err error

  switch module {
  case "bundle":
    fmt.Println("Using bundle module.")
    err = bundle(command)
  default:
    err = errors.New("Invalid module")
  }

  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(1)
  }
}

// bundle will handle the bundle command calls.
func bundle(command string) (err error) {
  switch command {
  case "build":
    var manifestPath = "./manifest.json"
    if _, err := os.Stat(manifestPath); err == nil {
      var manifestData []byte
      manifestData, err = ioutil.ReadFile(manifestPath)

      var manifest tykcommon.BundleManifest
      err = json.Unmarshal(manifestData, &manifest)

      if err != nil {
        fmt.Println("Couldn't parse manifest file!")
        break
      }

      err = bundleValidateManifest(&manifest)

      if err != nil {
        fmt.Println("Bundle validation error:")
        fmt.Println(err)
        break
      }

      // The manifest is valid, we should do the checksum and sign step at this point.
      bundleBuild(&manifest)

    } else {
      err = errors.New("Manifest file doesn't exist.")
    }
  default:
    err = errors.New("Invalid command.")
  }
  return err
}

// bundleValidateManifest will validate the manifest file before building a bundle.
func bundleValidateManifest(manifest *tykcommon.BundleManifest) (err error) {
  // Validate manifest file list:
  for _, file := range manifest.FileList {
    if _, statErr := os.Stat(file); statErr != nil {
      err = errors.New("Referencing a nonexistent file: " + file)
      break
    }
  }

  // The custom middleware block must specify at least one hook:
  var definedHooks int
  definedHooks = len(manifest.CustomMiddleware.Pre) + len(manifest.CustomMiddleware.Post) + len(manifest.CustomMiddleware.PostKeyAuth)

  if manifest.CustomMiddleware.AuthCheck.Name != "" {
    definedHooks++
  }

  if definedHooks == 0 {
    err = errors.New("No hooks defined!")
    return err
  }

  // The custom middleware block must specify a driver:
  if manifest.CustomMiddleware.Driver == "" {
    err = errors.New("No driver specified!")
    return err
  }

  return err
}

// bundleBuild will build and generate a bundle file.
func bundleBuild(manifest *tykcommon.BundleManifest) (err error) {
  var useSignature bool

  if bundleOutput == "" {
    fmt.Println("No output specified, using bundle.zip")
    bundleOutput = defaultBundleOutput
  }

  if privKey == "" {
    // Warning?
    fmt.Println("The bundle won't be signed.")
  } else {
    fmt.Println("The bundle will be signed.")
    useSignature = true
  }

  var signer goverify.Signer

  if useSignature {
    signer, err = goverify.LoadPrivateKeyFromFile(privKey)
    if err != nil {
      return err
    }
  }

  // Checksum and signature:

  var bundleChecksums []string
  var bundleSignatures []string

  for _, file := range manifest.FileList {
    var data []byte
    data, err = ioutil.ReadFile(file)
    if err != nil {
      fmt.Println("*** Error: ", err)
      return err
    }
    hash := fmt.Sprintf("%x", md5.Sum(data))
    bundleChecksums = append(bundleChecksums, hash)

    if useSignature {
      var signed []byte
      signed, err = signer.Sign(data)

      sig := base64.StdEncoding.EncodeToString(signed)
      bundleSignatures = append(bundleSignatures, sig)
      fmt.Printf("Signature: %v %s\n", sig, file)
    }
  }

  mergedChecksums := strings.Join(bundleChecksums, "")
  mergedSignatures := strings.Join(bundleSignatures, "")

  // Update the manifest file:

  manifest.Checksum = fmt.Sprintf("%x", md5.Sum([]byte(mergedChecksums)))
  manifest.Signature = mergedSignatures

  var newManifestData []byte
  newManifestData, err = json.Marshal(&manifest)

  // Write the bundle file:
  buf := new(bytes.Buffer)
  bundleWriter := zip.NewWriter(buf)

  for _, file := range manifest.FileList {
    var outputFile io.Writer
    outputFile, err = bundleWriter.Create(file)
    if err != nil {
      return err
    }
    var data []byte
    data, err = ioutil.ReadFile(file)

    _, err = outputFile.Write(data)

    if err != nil {
      return err
    }
  }

  // Write manifest file:
  var newManifest io.Writer
  newManifest, err = bundleWriter.Create("manifest.json")
  _, err = newManifest.Write(newManifestData)

  err = bundleWriter.Close()
  err = ioutil.WriteFile(bundleOutput, buf.Bytes(), 0755)

  return err
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
)

func main() {

	http.HandleFunc("/events", handler)
	http.ListenAndServe(":5050", nil)
}

func handler(writer http.ResponseWriter, request *http.Request) {

	writer.WriteHeader(http.StatusOK)
}<commit_msg>watch branches; parse image tag; update deployments;<commit_after>package main

import (
	"net/http"
	"fmt"
	"strings"
	"errors"
	"os"

	log "github.com/Sirupsen/logrus"
)

var (
	kube KubeClient
	watchBranches Set
)

func main() {

	kube = NewKubeClient()
	watchBranches = getWatchRepositories()

	http.HandleFunc("/events", handler)
	http.ListenAndServe(":5050", nil)
}

func handler(writer http.ResponseWriter, request *http.Request) {

	if repositories, err := GetPushEventRepositories(request.Body); err != nil {
		log.Error(err)
		writer.WriteHeader(http.StatusBadRequest)
	} else {
		for _, currRepository := range repositories {
			branch, namespace, deployment, version, err := parseTag(currRepository.Tag)
			if err != nil {
				log.Error(err)
				continue
			}

			fmt.Println("branch: ", branch, " ur:", watchBranches)
			if watchBranches.Contains(branch) {
				image := fmt.Sprintf("%s:%s", currRepository.Name, version)
				if err := kube.UpdateDeployment(deployment, namespace, image); err != nil {
					log.Errorf("Failed to update deployment: %s, branch: %s, namespace: %s, image: %s",
						deployment, branch, namespace, image, err)
				}
			}
		}
		writer.WriteHeader(http.StatusOK)
	}
}

// example tag: master-default-ceribrouideplyment-7
func parseTag(tag string) (branch, namespace, deployment, version string, err error) {

	ret := strings.Split(tag, "-")
	if len(ret) != 4 || ret[0] == "" || ret[1] == "" || ret[2] == "" || ret[3] == "" {
		return "", "", "", "", errors.New(fmt.Sprintf(
			"Failed to parse docker image tag: %s. Format should be: <branch>-<kubernetes namespace>-<kubernetes deployment name>-<version>", tag))
	}

	return ret[0], ret[1], ret[2], ret[3], nil
}

func getWatchRepositories() Set {

	ret := NewSet()
	names := os.Getenv("WATCH_BRANCES")
	if len(names) > 0 {
		for _, currBranch := range strings.Split(names, ",") {
			ret.Add(currBranch)
		}
	} else {
		ret.Add("master")
	}
	log.Info("Watch branches:", watchBranches.ToArray())

	return ret
}<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/mjibson/mog/server"
	"gopkg.in/fsnotify.v1"

	// codecs
	_ "github.com/mjibson/mog/codec/flac"
	_ "github.com/mjibson/mog/codec/gme"
	_ "github.com/mjibson/mog/codec/mpa"
	_ "github.com/mjibson/mog/codec/nsf"
	_ "github.com/mjibson/mog/codec/rar"
	_ "github.com/mjibson/mog/codec/vorbis"
	_ "github.com/mjibson/mog/codec/wav"

	// protocols
	_ "github.com/mjibson/mog/protocol/bandcamp"
	"github.com/mjibson/mog/protocol/drive"
	"github.com/mjibson/mog/protocol/dropbox"
	_ "github.com/mjibson/mog/protocol/file"
	_ "github.com/mjibson/mog/protocol/gmusic"
	"github.com/mjibson/mog/protocol/soundcloud"
	_ "github.com/mjibson/mog/protocol/stream"
)

var (
	flagAddr       = flag.String("addr", ":6601", "listen address")
	flagWatch      = flag.Bool("w", false, "watch current directory and exit on changes; for use with an autorestarter")
	flagDrive      = flag.String("drive", "792434736327-0pup5skbua0gbfld4min3nfv2reairte.apps.googleusercontent.com:OsN_bydWG45resaU0PPiDmtK", "Google Drive API credentials of the form ClientID:ClientSecret")
	flagDropbox    = flag.String("dropbox", "rnhpqsbed2q2ezn:ldref688unj74ld", "Dropbox API credentials of the form ClientID:ClientSecret")
	flagSoundcloud = flag.String("soundcloud", "ec28c2226a0838d01edc6ed0014e462e:a115e94029d698f541960c8dc8560978", "SoundCloud API credentials of the form ClientID:ClientSecret")
	flagDev        = flag.Bool("dev", false, "enable dev mode")
	flagCentral = flag.String("central", "http://localhost:8080", "Central Mog data server")
	stateFile      = flag.String("state", "", "specify non-default statefile location")
)

func main() {
	flag.Parse()
	http.DefaultClient = &http.Client{
		Transport: &httpcontrol.Transport{
			ResponseHeaderTimeout: time.Second * 3,
			MaxTries:              3,
			RetryAfterTimeout:     true,
		},
	}
	if *flagWatch {
		watch(".", "*.go", quit)
		go browserify()
	}
	redir := *flagAddr
	if strings.HasPrefix(redir, ":") {
		redir = "localhost" + redir
	}
	redir = "http://" + redir + "/api/oauth/"
	if *flagDrive != "" {
		sp := strings.Split(*flagDrive, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagDrive)
		}
		drive.Init(sp[0], sp[1], redir)
	}
	if *flagDropbox != "" {
		sp := strings.Split(*flagDropbox, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagDropbox)
		}
		dropbox.Init(sp[0], sp[1], redir)
	}
	if *flagSoundcloud != "" {
		sp := strings.Split(*flagSoundcloud, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagSoundcloud)
		}
		soundcloud.Init(sp[0], sp[1], redir)
	}
	if *stateFile == "" {
		switch {
		case *flagDev:
			*stateFile = "mog.state"
		case runtime.GOOS == "windows":
			dir := filepath.Join(os.Getenv("APPDATA"), "mog")
			if err := os.MkdirAll(dir, 0600); err != nil {
				log.Fatal(err)
			}
			*stateFile = filepath.Join(dir, "mog.state")
		default:
			*stateFile = filepath.Join(os.Getenv("HOME"), ".mog.state")
		}
	}
	log.Fatal(server.ListenAndServe(*stateFile, *flagAddr, *flagCentral, *flagDev))
}

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

func browserify() {
	base := filepath.Join("server", "static")
	src := filepath.Join(base, "src")
	js := filepath.Join(base, "js")
	log.Println("starting watchify")
	c := exec.Command("watchify",
		"-t", "[", "reactify", "--es6", "]",
		filepath.Join(src, "nav.js"),
		"-o", filepath.Join(js, "mog.js"),
		"--verbose",
	)
	c.Stderr = os.Stderr
	c.Stdout = os.Stdout
	if err := c.Start(); err != nil {
		log.Fatal(err)
	}
	if err := c.Wait(); err != nil {
		log.Printf("browserify error: %v", err)
	}
}

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)
			}
		}
	}()
}

//go:generate browserify -t [ reactify --es6 ] server/static/src/nav.js -o server/static/js/mog.js
//go:generate esc -o server/static.go -pkg server -prefix server server/static/index.html server/static/css server/static/fonts server/static/js
<commit_msg>Set default central URL<commit_after>package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"github.com/facebookgo/httpcontrol"
	"github.com/mjibson/mog/server"
	"gopkg.in/fsnotify.v1"

	// codecs
	_ "github.com/mjibson/mog/codec/flac"
	_ "github.com/mjibson/mog/codec/gme"
	_ "github.com/mjibson/mog/codec/mpa"
	_ "github.com/mjibson/mog/codec/nsf"
	_ "github.com/mjibson/mog/codec/rar"
	_ "github.com/mjibson/mog/codec/vorbis"
	_ "github.com/mjibson/mog/codec/wav"

	// protocols
	_ "github.com/mjibson/mog/protocol/bandcamp"
	"github.com/mjibson/mog/protocol/drive"
	"github.com/mjibson/mog/protocol/dropbox"
	_ "github.com/mjibson/mog/protocol/file"
	_ "github.com/mjibson/mog/protocol/gmusic"
	"github.com/mjibson/mog/protocol/soundcloud"
	_ "github.com/mjibson/mog/protocol/stream"
)

var (
	flagAddr       = flag.String("addr", ":6601", "listen address")
	flagWatch      = flag.Bool("w", false, "watch current directory and exit on changes; for use with an autorestarter")
	flagDrive      = flag.String("drive", "792434736327-0pup5skbua0gbfld4min3nfv2reairte.apps.googleusercontent.com:OsN_bydWG45resaU0PPiDmtK", "Google Drive API credentials of the form ClientID:ClientSecret")
	flagDropbox    = flag.String("dropbox", "rnhpqsbed2q2ezn:ldref688unj74ld", "Dropbox API credentials of the form ClientID:ClientSecret")
	flagSoundcloud = flag.String("soundcloud", "ec28c2226a0838d01edc6ed0014e462e:a115e94029d698f541960c8dc8560978", "SoundCloud API credentials of the form ClientID:ClientSecret")
	flagDev        = flag.Bool("dev", false, "enable dev mode")
	flagCentral = flag.String("central", "https://mog-music-client.appspot.com", "Central Mog data server; empty to disable")
	stateFile      = flag.String("state", "", "specify non-default statefile location")
)

func main() {
	flag.Parse()
	http.DefaultClient = &http.Client{
		Transport: &httpcontrol.Transport{
			ResponseHeaderTimeout: time.Second * 3,
			MaxTries:              3,
			RetryAfterTimeout:     true,
		},
	}
	if *flagWatch {
		watch(".", "*.go", quit)
		go browserify()
	}
	redir := *flagAddr
	if strings.HasPrefix(redir, ":") {
		redir = "localhost" + redir
	}
	redir = "http://" + redir + "/api/oauth/"
	if *flagDrive != "" {
		sp := strings.Split(*flagDrive, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagDrive)
		}
		drive.Init(sp[0], sp[1], redir)
	}
	if *flagDropbox != "" {
		sp := strings.Split(*flagDropbox, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagDropbox)
		}
		dropbox.Init(sp[0], sp[1], redir)
	}
	if *flagSoundcloud != "" {
		sp := strings.Split(*flagSoundcloud, ":")
		if len(sp) != 2 {
			log.Fatal("bad drive string %s", *flagSoundcloud)
		}
		soundcloud.Init(sp[0], sp[1], redir)
	}
	if *stateFile == "" {
		switch {
		case *flagDev:
			*stateFile = "mog.state"
		case runtime.GOOS == "windows":
			dir := filepath.Join(os.Getenv("APPDATA"), "mog")
			if err := os.MkdirAll(dir, 0600); err != nil {
				log.Fatal(err)
			}
			*stateFile = filepath.Join(dir, "mog.state")
		default:
			*stateFile = filepath.Join(os.Getenv("HOME"), ".mog.state")
		}
	}
	log.Fatal(server.ListenAndServe(*stateFile, *flagAddr, *flagCentral, *flagDev))
}

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

func browserify() {
	base := filepath.Join("server", "static")
	src := filepath.Join(base, "src")
	js := filepath.Join(base, "js")
	log.Println("starting watchify")
	c := exec.Command("watchify",
		"-t", "[", "reactify", "--es6", "]",
		filepath.Join(src, "nav.js"),
		"-o", filepath.Join(js, "mog.js"),
		"--verbose",
	)
	c.Stderr = os.Stderr
	c.Stdout = os.Stdout
	if err := c.Start(); err != nil {
		log.Fatal(err)
	}
	if err := c.Wait(); err != nil {
		log.Printf("browserify error: %v", err)
	}
}

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)
			}
		}
	}()
}

//go:generate browserify -t [ reactify --es6 ] server/static/src/nav.js -o server/static/js/mog.js
//go:generate esc -o server/static.go -pkg server -prefix server server/static/index.html server/static/css server/static/fonts server/static/js
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"sort"
	"strings"
)

const VERSION = "0.0.1"

var fset *token.FileSet

func main() {
	if len(os.Args) != 2 {
		printUsage()
		os.Exit(1)
	}

	filename := os.Args[1]

	fset = token.NewFileSet()
	tags := make(sort.StringSlice, 0)

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		// TODO: fix error handling; it should still result in a valid ctags file
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// header
	tags = append(tags, "!_TAG_FILE_FORMAT\t2\t")
	tags = append(tags, "!_TAG_FILE_SORTED\t1\t")

	// package
	if f.Name != nil {
		tags = append(tags, createTag(f.Name.Name, f.Name.Pos(), "p").String())
	}

	// imports
	for _, im := range f.Imports {
		if im.Path != nil {
			name := strings.Trim(im.Path.Value, "\"")
			tags = append(tags, createTag(name, im.Path.Pos(), "i").String())
		}
	}

	// declarations
	for _, d := range f.Decls {
		switch decl := d.(type) {
		case *ast.FuncDecl:
			tags = append(tags, createFuncTag(decl))
		case *ast.GenDecl:
			for _, s := range decl.Specs {
				switch ts := s.(type) {
				case *ast.TypeSpec:
					tags = append(tags, createTag(ts.Name.Name, ts.Pos(), "t").String())
				case *ast.ValueSpec:
					if len(ts.Names) > 0 {
						tag := createTag(ts.Names[0].Name, ts.Pos(), "v")

						switch ts.Names[0].Obj.Kind {
						case ast.Var:
							tag.Type = "v"
						case ast.Con:
							tag.Type = "c"
						}

						tags = append(tags, tag.String())
					}
				}
			}
		}
	}

	// sort and print tags
	sort.Sort(tags)
	for _, tag := range tags {
		fmt.Println(tag)
	}
}

func printUsage() {
	fmt.Printf("gotags version %s\n\n", VERSION)
	fmt.Printf("Usage: %s file\n", os.Args[0])
}

func createTag(name string, pos token.Pos, tagtype string) *Tag {
	return NewTag(name, fset.File(pos).Name(), fset.Position(pos).Line, tagtype)
}

func createFuncTag(f *ast.FuncDecl) string {
	if f == nil || f.Name == nil {
		return ""
	}

	tag := createTag(f.Name.Name, f.Pos(), "f")

	// access
	if ast.IsExported(tag.Name) {
		tag.Fields["access"] = "public"
	} else {
		tag.Fields["access"] = "private"
	}

	// signature
	var sig bytes.Buffer
	sig.WriteByte('(')
	for i, param := range f.Type.Params.List {
		// parameter names
		for j, n := range param.Names {
			sig.WriteString(n.Name)
			if j < len(param.Names)-1 {
				sig.WriteString(", ")
			}
		}

		// parameter type
		sig.WriteByte(' ')
		sig.WriteString(getType(param.Type))

		if i < len(f.Type.Params.List)-1 {
			sig.WriteString(", ")
		}
	}
	sig.WriteByte(')')
	tag.Fields["signature"] = sig.String()

	// receiver
	if f.Recv != nil && len(f.Recv.List) > 0 {
		tag.Fields["type"] = getType(f.Recv.List[0].Type)
	}

	return tag.String()
}

func getType(node ast.Node) (paramType string) {
	switch t := node.(type) {
	case *ast.Ident:
		paramType = t.Name
	case *ast.StarExpr:
		paramType = "*" + getType(t.X)
	case *ast.SelectorExpr:
		paramType = getType(t.X) + "." + getType(t.Sel)
	}
	return
}
<commit_msg>Do not add star to receiver types<commit_after>package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"os"
	"sort"
	"strings"
)

const VERSION = "0.0.1"

var fset *token.FileSet

func main() {
	if len(os.Args) != 2 {
		printUsage()
		os.Exit(1)
	}

	filename := os.Args[1]

	fset = token.NewFileSet()
	tags := make(sort.StringSlice, 0)

	f, err := parser.ParseFile(fset, filename, nil, 0)
	if err != nil {
		// TODO: fix error handling; it should still result in a valid ctags file
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	// header
	tags = append(tags, "!_TAG_FILE_FORMAT\t2\t")
	tags = append(tags, "!_TAG_FILE_SORTED\t1\t")

	// package
	if f.Name != nil {
		tags = append(tags, createTag(f.Name.Name, f.Name.Pos(), "p").String())
	}

	// imports
	for _, im := range f.Imports {
		if im.Path != nil {
			name := strings.Trim(im.Path.Value, "\"")
			tags = append(tags, createTag(name, im.Path.Pos(), "i").String())
		}
	}

	// declarations
	for _, d := range f.Decls {
		switch decl := d.(type) {
		case *ast.FuncDecl:
			tags = append(tags, createFuncTag(decl))
		case *ast.GenDecl:
			for _, s := range decl.Specs {
				switch ts := s.(type) {
				case *ast.TypeSpec:
					tags = append(tags, createTag(ts.Name.Name, ts.Pos(), "t").String())
				case *ast.ValueSpec:
					if len(ts.Names) > 0 {
						tag := createTag(ts.Names[0].Name, ts.Pos(), "v")

						switch ts.Names[0].Obj.Kind {
						case ast.Var:
							tag.Type = "v"
						case ast.Con:
							tag.Type = "c"
						}

						tags = append(tags, tag.String())
					}
				}
			}
		}
	}

	// sort and print tags
	sort.Sort(tags)
	for _, tag := range tags {
		fmt.Println(tag)
	}
}

func printUsage() {
	fmt.Printf("gotags version %s\n\n", VERSION)
	fmt.Printf("Usage: %s file\n", os.Args[0])
}

func createTag(name string, pos token.Pos, tagtype string) *Tag {
	return NewTag(name, fset.File(pos).Name(), fset.Position(pos).Line, tagtype)
}

func createFuncTag(f *ast.FuncDecl) string {
	if f == nil || f.Name == nil {
		return ""
	}

	tag := createTag(f.Name.Name, f.Pos(), "f")

	// access
	if ast.IsExported(tag.Name) {
		tag.Fields["access"] = "public"
	} else {
		tag.Fields["access"] = "private"
	}

	// signature
	var sig bytes.Buffer
	sig.WriteByte('(')
	for i, param := range f.Type.Params.List {
		// parameter names
		for j, n := range param.Names {
			sig.WriteString(n.Name)
			if j < len(param.Names)-1 {
				sig.WriteString(", ")
			}
		}

		// parameter type
		sig.WriteByte(' ')
		sig.WriteString(getType(param.Type, true))

		if i < len(f.Type.Params.List)-1 {
			sig.WriteString(", ")
		}
	}
	sig.WriteByte(')')
	tag.Fields["signature"] = sig.String()

	// receiver
	if f.Recv != nil && len(f.Recv.List) > 0 {
		tag.Fields["type"] = getType(f.Recv.List[0].Type, false)
	}

	return tag.String()
}

func getType(node ast.Node, star bool) (paramType string) {
	switch t := node.(type) {
	case *ast.Ident:
		paramType = t.Name
	case *ast.StarExpr:
		if star {
			paramType = "*" + getType(t.X, star)
		} else {
			paramType = getType(t.X, star)
		}
	case *ast.SelectorExpr:
		paramType = getType(t.X, star) + "." + getType(t.Sel, star)
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"

	"github.com/doubledutch/quantum-basic/basic"
	"github.com/doubledutch/quantum-basic/remote"
	"github.com/doubledutch/quantum/agent"
)

const (
	defaultPort = ":8877"
)

func main() {
	config := agent.RegisterFlags(&agent.Config{
		Port: defaultPort,
	})
	flag.Parse()

	srv := agent.New(config)
	srv.Add(&basic.Job{})
	srv.Add(&remote.Job{})
	if err := srv.Start(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>uses new quantum config<commit_after>package main

import (
	"log"
	"os"

	"github.com/doubledutch/lager"
	"github.com/doubledutch/mux/gob"
	"github.com/doubledutch/quantum"
	"github.com/doubledutch/quantum-basic/basic"
	"github.com/doubledutch/quantum-basic/remote"
	"github.com/doubledutch/quantum/agent"
)

const (
	defaultPort      = ":8877"
	defaultLogLevels = "IE"
)

func main() {
	port := os.Getenv("BASIC_PORT")
	if port == "" {
		port = defaultPort
	}

	logLevels := os.Getenv("BASIC_LOG_LEVELS")
	if logLevels == "" {
		logLevels = defaultLogLevels
	}

	lgr := lager.NewLogLager(&lager.LogConfig{
		Levels: lager.LevelsFromString(logLevels),
		Output: os.Stdout,
	})

	cc := &quantum.ConnConfig{
		Config: &quantum.Config{
			Pool:  new(gob.Pool),
			Lager: lgr,
		},
	}

	config := &agent.Config{
		Port:       port,
		ConnConfig: cc,
	}

	srv := agent.New(config)
	srv.Add(&basic.Job{})
	srv.Add(&remote.Job{})
	if err := srv.Start(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"regexp"
	"time"

	"github.com/elazarl/goproxy"
)

var (
	cache       = make(map[string]bool)
	filters     []*regexp.Regexp
	flagRoot    string
	flagAddr    string
	flagVerbose bool
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options...] regexp regexp...\n\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&flagRoot, "r", "", "cache root directory")
	flag.StringVar(&flagAddr, "a", ":9999", "proxy bind address")
	flag.BoolVar(&flagVerbose, "v", false, "verbose output")
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(0)
	}

	if flagRoot == "" {
		fr, err := os.Getwd()
		if err != nil {
			log.Fatalln(err)
			os.Exit(1)
		}
		flagRoot = fr
	}

	for _, arg := range flag.Args() {
		filters = append(filters, regexp.MustCompile(arg))
	}

	proxy := goproxy.NewProxyHttpServer()
	if flagVerbose {
		proxy.Verbose = true
	}
	proxy.OnRequest().DoFunc(
		func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
			log.Println("Request", r.URL.Path)
			for _, re := range filters {
				if re.MatchString(r.URL.Path) {
					return r, nil
				}
			}
			for {
				if _, exist := cache[r.URL.Path]; !exist {
					break
				}
				time.Sleep(100 * time.Millisecond)
			}
			filePath := path.Join(flagRoot, r.URL.Path)
			file, err := os.Open(filePath)
			if err != nil {
				if os.IsNotExist(err) {
					r.Header.Add("X-PkgCache", "fetch")
					return r, nil
				} else {
					log.Println(err)
					return r, nil
				}
			}

			resp := &http.Response{}
			resp.Request = r
			resp.TransferEncoding = r.TransferEncoding
			resp.Header = make(http.Header)
			resp.Header.Add("Content-Type", "application/octet-stream")
			resp.StatusCode = 200
			resp.Body = file
			log.Println("Used", r.URL.Path)

			return r, resp
		})
	proxy.OnResponse().DoFunc(
		func(r *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
			if r.Request.Header.Get("X-PkgCache") != "fetch" {
				return r
			}
			if r.StatusCode == 200 {
				cache[r.Request.URL.Path] = true
				defer func(key string) {
					delete(cache, key)
				}(r.Request.URL.Path)

				filePath := path.Join(flagRoot, r.Request.URL.Path)
				if err := os.MkdirAll(path.Dir(filePath), 0777); err != nil {
					log.Println(err)
					return r
				}
				file, err := os.Create(filePath)
				if err != nil {
					log.Println(err)
					return r
				}
				if n, err := io.Copy(file, r.Body); err != nil {
					log.Println(err)
				} else {
					log.Printf("Saved %s (%d)\n", filePath, n)
				}
				if err := file.Sync(); err != nil {
					log.Println(err)
				}
				if _, err := file.Seek(0, 0); err != nil {
					log.Println(err)
				}
				r.Body.Close()
				r.Body = file
			}
			return r
		})
	http.ListenAndServe(flagAddr, proxy)
}
<commit_msg>Rewrite as dependency free<commit_after>package main

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

var (
	client      = &http.Client{}
	cache       = make(map[string]bool)
	filters     []*regexp.Regexp
	flagRoot    string
	flagAddr    string
	flagVerbose bool
)

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options...] regexp regexp...\n\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&flagRoot, "r", "", "cache root directory")
	flag.StringVar(&flagAddr, "a", ":9999", "proxy bind address")
	flag.BoolVar(&flagVerbose, "v", false, "verbose output")
}

func checkFile(path string) (*os.File, error) {
	file, err := os.Open(path)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		} else {
			return nil, err
		}
	}
	return file, nil
}

func handle(w http.ResponseWriter, req *http.Request) {
	log.Println("Request", req.URL.Path)
	filePath := path.Join(flagRoot, req.URL.Path)
	process := true
	download := false

	for _, re := range filters {
		if re.MatchString(req.URL.Path) {
			process = false
		}
	}

	if process {
		file, err := checkFile(filePath)
		if err != nil {
			log.Println(err)
		}
		if file == nil {
			download = true
		} else {
			defer file.Close()
			w.Header().Set("Content-Type", "application/octet-stream")
			w.WriteHeader(http.StatusOK)
			log.Println("Using", filePath)
			if _, err := io.Copy(w, file); err != nil {
				log.Println(err)
			}
			return
		}
	}

	r, err := http.NewRequest(req.Method, req.RequestURI, nil)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	res, err := client.Do(r)
	if err != nil {
		log.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer res.Body.Close()
	w.Header().Set("Content-Type", res.Header.Get("Content-Type"))
	w.WriteHeader(res.StatusCode)
	if res.StatusCode != 200 {
		if _, err := io.Copy(w, res.Body); err != nil {
			log.Println(err)
		}
		return
	}
	var target io.Writer
	target = w
	if download {
		if err := os.MkdirAll(path.Dir(filePath), 0777); err != nil {
			log.Println(err)
		} else {
			file, err := os.Create(filePath)
			if err != nil {
				log.Println(err)
			} else {
				log.Println("Saving", filePath)
				defer file.Close()
				target = io.MultiWriter(w, file)
			}
		}
	}
	if _, err := io.Copy(target, res.Body); err != nil {
		log.Println(err)
	}
	return
}

func main() {
	flag.Parse()

	if flag.NArg() < 1 {
		flag.Usage()
		os.Exit(0)
	}

	if flagRoot == "" {
		fr, err := os.Getwd()
		if err != nil {
			log.Fatalln(err)
			os.Exit(1)
		}
		flagRoot = fr
	}

	for _, arg := range flag.Args() {
		filters = append(filters, regexp.MustCompile(arg))
	}

	http.HandleFunc("/", handle)
	log.Fatalln(http.ListenAndServe(flagAddr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jessevdk/go-flags"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"log"
	"os"
	"reflect"
	"strings"
)

const (
	SQL_INFO         = "SELECT version(), user, current_database(), inet_client_addr(), inet_client_port(), inet_server_addr(), inet_server_port()"
	SQL_TABLES       = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;"
	SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';"
)

type Client struct {
	db *sqlx.DB
}

type Result struct {
	Columns []string        `json:"columns"`
	Rows    [][]interface{} `json:"rows"`
}

type Error struct {
	Message string `json:"error"`
}

var dbClient *Client
var history []string

var options struct {
	Url    string `long:"url" description:"Database connection string"`
	Host   string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"`
	Port   int    `short:"p" long:"port" description:"Server port" default:"5432"`
	User   string `short:"u" long:"user" description:"Database user" default:"postgres"`
	DbName string `short:"d" long:"db" description:"Database name" default:"postgres"`
	Ssl    string `long:"ssl" description:"SSL option" default:"disable"`
	Static string `short:"s" description:"Path to static assets" default:"./static"`
}

func formatResult(res *Result) []map[string]interface{} {
	var items []map[string]interface{}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		items = append(items, item)
	}

	return items
}

func getConnectionString() string {
	if options.Url != "" {
		return options.Url
	}

	return fmt.Sprintf(
		"host=%s port=%d user=%s dbname=%s sslmode=disable",
		options.Host, options.Port,
		options.User, options.DbName,
	)
}

func NewClient() (*Client, error) {
	db, err := sqlx.Open("postgres", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

func NewError(err error) Error {
	return Error{err.Error()}
}

func (client *Client) Tables() ([]string, error) {
	res, err := client.Query(SQL_TABLES)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func API_RunQuery(c *gin.Context) {
	query := strings.TrimSpace(c.Request.FormValue("query"))

	if query == "" {
		c.JSON(400, errors.New("Query parameter is missing"))
		return
	}

	history = append(history, query)
	API_HandleQuery(query, c)
}

func API_GetTables(c *gin.Context) {
	names, err := dbClient.Tables()

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, names)
}

func API_GetTable(c *gin.Context) {
	res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, c.Params.ByName("name")))

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, formatResult(res))
}

func API_History(c *gin.Context) {
	c.JSON(200, history)
}

func API_Info(c *gin.Context) {
	res, err := dbClient.Query(SQL_INFO)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, formatResult(res)[0])
}

func API_HandleQuery(query string, c *gin.Context) {
	result, err := dbClient.Query(query)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, result)
}

func initClient() {
	client, err := NewClient()

	if err != nil {
		log.Fatal(err)
	}

	_, err = client.Query(SQL_INFO)

	if err != nil {
		log.Fatal(err)
	}

	dbClient = client
}

func initOptions() {
	_, err := flags.ParseArgs(&options, os.Args)

	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	initOptions()
	initClient()
	defer dbClient.db.Close()

	router := gin.Default()

	router.GET("/info", API_Info)
	router.GET("/tables", API_GetTables)
	router.GET("/tables/:name", API_GetTable)
	router.GET("/select", API_RunQuery)
	router.POST("/select", API_RunQuery)
	router.GET("/history", API_History)

	router.Static("/app", options.Static)

	fmt.Println("Starting server at 0.0.0.0:8080")
	router.Run(":8080")
}
<commit_msg>Tweaks<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jessevdk/go-flags"
	"github.com/jmoiron/sqlx"
	_ "github.com/lib/pq"
	"log"
	"os"
	"reflect"
	"strings"
)

const (
	SQL_INFO         = "SELECT version(), user, current_database(), inet_client_addr(), inet_client_port(), inet_server_addr(), inet_server_port()"
	SQL_TABLES       = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;"
	SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';"
)

type Client struct {
	db *sqlx.DB
}

type Result struct {
	Columns []string        `json:"columns"`
	Rows    [][]interface{} `json:"rows"`
}

type Error struct {
	Message string `json:"error"`
}

var dbClient *Client
var history []string

var options struct {
	Url    string `long:"url" description:"Database connection string"`
	Host   string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"`
	Port   int    `short:"p" long:"port" description:"Server port" default:"5432"`
	User   string `short:"u" long:"user" description:"Database user" default:"postgres"`
	DbName string `short:"d" long:"db" description:"Database name" default:"postgres"`
	Ssl    string `long:"ssl" description:"SSL option" default:"disable"`
	Static string `short:"s" description:"Path to static assets" default:"./static"`
}

func (res *Result) Format() []map[string]interface{} {
	var items []map[string]interface{}

	for _, row := range res.Rows {
		item := make(map[string]interface{})

		for i, c := range res.Columns {
			item[c] = row[i]
		}

		items = append(items, item)
	}

	return items
}

func getConnectionString() string {
	if options.Url != "" {
		return options.Url
	}

	return fmt.Sprintf(
		"host=%s port=%d user=%s dbname=%s sslmode=disable",
		options.Host, options.Port,
		options.User, options.DbName,
	)
}

func NewClient() (*Client, error) {
	db, err := sqlx.Open("postgres", getConnectionString())

	if err != nil {
		return nil, err
	}

	return &Client{db: db}, nil
}

func NewError(err error) Error {
	return Error{err.Error()}
}

func (client *Client) Tables() ([]string, error) {
	res, err := client.Query(SQL_TABLES)

	if err != nil {
		return nil, err
	}

	var tables []string

	for _, row := range res.Rows {
		tables = append(tables, row[0].(string))
	}

	return tables, nil
}

func (client *Client) Query(query string) (*Result, error) {
	rows, err := client.db.Queryx(query)

	if err != nil {
		return nil, err
	}

	defer rows.Close()

	cols, err := rows.Columns()

	if err != nil {
		return nil, err
	}

	result := Result{
		Columns: cols,
	}

	for rows.Next() {
		obj, err := rows.SliceScan()

		for i, item := range obj {
			if item == nil {
				obj[i] = nil
			} else {
				t := reflect.TypeOf(item).Kind().String()

				if t == "slice" {
					obj[i] = string(item.([]byte))
				}
			}
		}

		if err == nil {
			result.Rows = append(result.Rows, obj)
		}
	}

	return &result, nil
}

func API_RunQuery(c *gin.Context) {
	query := strings.TrimSpace(c.Request.FormValue("query"))

	if query == "" {
		c.JSON(400, errors.New("Query parameter is missing"))
		return
	}

	history = append(history, query)
	API_HandleQuery(query, c)
}

func API_GetTables(c *gin.Context) {
	names, err := dbClient.Tables()

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, names)
}

func API_GetTable(c *gin.Context) {
	res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, c.Params.ByName("name")))

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, res.Format())
}

func API_History(c *gin.Context) {
	c.JSON(200, history)
}

func API_Info(c *gin.Context) {
	res, err := dbClient.Query(SQL_INFO)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, res.Format()[0])
}

func API_HandleQuery(query string, c *gin.Context) {
	result, err := dbClient.Query(query)

	if err != nil {
		c.JSON(400, NewError(err))
		return
	}

	c.JSON(200, result)
}

func initClient() {
	client, err := NewClient()

	if err != nil {
		log.Fatal(err)
	}

	_, err = client.Query(SQL_INFO)

	if err != nil {
		log.Fatal(err)
	}

	dbClient = client
}

func initOptions() {
	_, err := flags.ParseArgs(&options, os.Args)

	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	initOptions()
	initClient()
	defer dbClient.db.Close()

	router := gin.Default()

	router.GET("/info", API_Info)
	router.GET("/tables", API_GetTables)
	router.GET("/tables/:name", API_GetTable)
	router.GET("/select", API_RunQuery)
	router.POST("/select", API_RunQuery)
	router.GET("/history", API_History)

	router.Static("/app", options.Static)

	fmt.Println("Starting server at 0.0.0.0:8080")
	router.Run(":8080")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"
)

const usage string = `A simple CLI stopwatch.
Usage: 4d [DURATION]

4d		display elapsed time
4d 15m		countdown 15 minutes
4d 3h2m1s	countdown 3 hours, 2 minutes, 1 second

Return key exits.`

// printDuration prints a given duration as HH:MM:SS.
func printDuration(d time.Duration) {
	fmt.Printf("\r%02d:%02d:%02d ",
		int(d.Hours())%60,
		int(d.Minutes())%60,
		int(d.Seconds())%60,
	)
}

// Countdown prints time remaining relative to a given total.
func Countdown(ticker *time.Ticker, d time.Duration, start time.Time) {
	for range ticker.C {
		remaining := d - time.Since(start) + time.Second
		if remaining >= 0.0 {
			printDuration(remaining)
		} else {
			fmt.Println()
			os.Exit(0)
		}
	}
}

// Elapsed prints the duration since the function was called.
func Elapsed(ticker *time.Ticker, start time.Time) {
	for range ticker.C {
		printDuration(time.Since(start))
	}
}

func main() {
	var countdown time.Duration

	// parse duration if provided
	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "-h", "-help", "--help", "help":
			fmt.Println(usage)
			os.Exit(0)
		}

		d, err := time.ParseDuration(os.Args[1])
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		countdown = d
	}

	// - set tick lower than than the smallest unit of interest (1s) to
	//   mitigate output "skips" due to missed ticks
	// - related issue: https://github.com/golang/go/issues/3516
	ticker := time.NewTicker(time.Second / 2)

	if countdown >= time.Second {
		go Countdown(ticker, countdown, time.Now())
	} else {
		go Elapsed(ticker, time.Now())
	}

	fmt.Scanln()
}
<commit_msg>Remove start time as parameter for Countdown<commit_after>package main

import (
	"fmt"
	"os"
	"time"
)

const usage string = `A simple CLI stopwatch.
Usage: 4d [DURATION]

4d		display elapsed time
4d 15m		countdown 15 minutes
4d 3h2m1s	countdown 3 hours, 2 minutes, 1 second

Return key exits.`

// printDuration prints a given duration as HH:MM:SS.
func printDuration(d time.Duration) {
	fmt.Printf("\r%02d:%02d:%02d ",
		int(d.Hours())%60,
		int(d.Minutes())%60,
		int(d.Seconds())%60,
	)
}

// Countdown prints time remaining relative to a given total.
func Countdown(ticker *time.Ticker, d time.Duration) {
	start := time.Now()
	for range ticker.C {
		remaining := d - time.Since(start) + time.Second
		if remaining >= 0.0 {
			printDuration(remaining)
		} else {
			fmt.Println()
			os.Exit(0)
		}
	}
}

// Elapsed prints the duration since the provided start time.
func Elapsed(ticker *time.Ticker, start time.Time) {
	for range ticker.C {
		printDuration(time.Since(start))
	}
}

func main() {
	var countdown time.Duration

	// parse duration if provided
	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "-h", "-help", "--help", "help":
			fmt.Println(usage)
			os.Exit(0)
		}

		d, err := time.ParseDuration(os.Args[1])
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		countdown = d
	}

	// - set tick lower than than the smallest unit of interest (1s) to
	//   mitigate output "skips" due to missed ticks
	// - related issue: https://github.com/golang/go/issues/3516
	ticker := time.NewTicker(time.Second / 2)

	if countdown >= time.Second {
		go Countdown(ticker, countdown)
	} else {
		go Elapsed(ticker, time.Now())
	}

	fmt.Scanln()
}
<|endoftext|>


<commit_before>// 2015 - Mathieu Lonjaret

// The montorrent program serves the status of rtorrent. It uses
// github.com/mpl/rtorrentrpc to query rtorrent.
package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mpl/basicauth"
)

var (
	cache    = flag.Int("cache", 0, "cache the status for that many seconds. 0 means no caching")
	help     = flag.Bool("h", false, "show this help")
	host     = flag.String("host", "localhost:8080", "listening host:port")
	scgi     = flag.String("scgi", "localhost:5000", "host:port for rtorrent's scgi.")
	secure   = flag.Bool("tls", false, "for https. cert.pem and key.pem in current dir will be used.")
	userpass = flag.String("userpass", "", "optional username:password protection")
	verbose  = flag.Bool("v", false, "verbose")
)

const (
	numRetry   = 20
	retryDelay = 2 * time.Second
	idstring   = "http://golang.org/pkg/http/#ListenAndServe"
)

func usage() {
	flag.PrintDefaults()
	os.Exit(2)
}

func rpc(args ...string) ([]byte, error) {
	var answer []byte
	for i := 0; i < numRetry; i++ {
		cmd := exec.Command("rtorrentrpc", args...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			// TODO(mpl): diagnose better the error and return early if it's not the expected EOF one.
			if *verbose {
				log.Printf("ignoring error: %v", err)
			}
			continue
		}
		if len(output) > 0 {
			answer = output
			break
		}
		time.Sleep(retryDelay)
	}
	if len(answer) == 0 {
		return nil, fmt.Errorf("empty answer for %v", args)
	}
	return answer, nil
}

func scanAnswer(answer []byte, prefix, suffix string) ([]string, error) {
	var list []string
	scanner := bufio.NewScanner(bytes.NewReader(answer))
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, prefix) || !strings.HasSuffix(line, suffix) {
			continue
		}
		list = append(list, strings.TrimSuffix(strings.TrimPrefix(line, prefix), suffix))
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("could not scan answer: %v", err)
	}
	return list, nil
}

func downloadList() ([]string, error) {
	answer, err := rpc(*scgi, "download_list", "")
	if err != nil {
		return nil, err
	}
	return scanAnswer(answer, "<value><string>", "</string></value>")
}

func torrentName(torrentHash string) (string, error) {
	answer, err := rpc(*scgi, "d.name", torrentHash)
	if err != nil {
		return "", err
	}
	list, err := scanAnswer(answer, "<param><value><string>", "</string></value></param>")
	if err != nil {
		return "", err
	}
	if len(list) == 0 {
		return "", fmt.Errorf("%v: name not found", torrentHash)
	}
	return list[0], nil
}

func bytesDone(torrentHash string) (int, error) {
	var n int
	answer, err := rpc(*scgi, "d.get_bytes_done", torrentHash)
	if err != nil {
		return n, err
	}
	list, err := scanAnswer(answer, "<param><value><i8>", "</i8></value></param>")
	if err != nil {
		return n, err
	}
	if len(list) == 0 {
		return n, fmt.Errorf("%v: bytes_done not found", torrentHash)
	}
	n, err = strconv.Atoi(list[0])
	if err != nil {
		return n, fmt.Errorf("could not convert bytes_done to int: %v", err)
	}
	return n, nil
}

func bytesLeft(torrentHash string) (int, error) {
	var n int
	answer, err := rpc(*scgi, "d.get_left_bytes", torrentHash)
	if err != nil {
		return n, err
	}
	list, err := scanAnswer(answer, "<param><value><i8>", "</i8></value></param>")
	if err != nil {
		return n, err
	}
	if len(list) == 0 {
		return n, fmt.Errorf("%v: bytes_left not found", torrentHash)
	}
	n, err = strconv.Atoi(list[0])
	if err != nil {
		return n, fmt.Errorf("could not convert bytes_left to int: %v", err)
	}
	return n, nil
}

type torrentStatus struct {
	Name        string
	BytesDone   int
	BytesLeft   int
	BytesTotal  int
	PercentDone int
}

func getStatus(torrentHash string) (*torrentStatus, error) {
	name, err := torrentName(torrentHash)
	if err != nil {
		return nil, err
	}
	nDone, err := bytesDone(torrentHash)
	if err != nil {
		return nil, err
	}
	nLeft, err := bytesLeft(torrentHash)
	if err != nil {
		return nil, err
	}
	total := nDone + nLeft // yay, super precision!!
	percent := nDone * 100 / total
	return &torrentStatus{
		Name:        name,
		BytesDone:   nDone,
		BytesLeft:   nLeft,
		BytesTotal:  total,
		PercentDone: percent,
	}, nil
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if e, ok := recover().(error); ok {
				http.Error(w, e.Error(), http.StatusInternalServerError)
				return
			}
		}()
		w.Header().Set("Server", idstring)
		if up.IsAllowed(r) {
			fn(w, r)
		} else {
			basicauth.SendUnauthorized(w, r, "montorrent")
		}
	}
}

func serveJSON(w http.ResponseWriter, r *http.Request, data []byte) {
	w.Header().Set("Content-Type", "text/javascript")
	w.Header().Set("Content-Length", strconv.Itoa(len(data)+1))
	w.WriteHeader(200)
	w.Write(data)
	w.Write([]byte("\n"))
}

func serveStatus(w http.ResponseWriter, r *http.Request) {
	if *cache > 0 {
		lastUpdateMu.RLock()
		// TODO(mpl): maybe use a checkLastModified. pull it out of simpleHttpd as a lib?
		if time.Now().Before(lastUpdate.Add(time.Duration(*cache) * time.Second)) {
			defer lastUpdateMu.RUnlock()
			statusMu.RLock()
			defer statusMu.RUnlock()
			data, err := json.MarshalIndent(status, "", "	")
			if err != nil {
				if *verbose {
					log.Printf("could not get json encode: %v", err)
				}
				http.Error(w, "could not json encode", http.StatusInternalServerError)
				return
			}
			serveJSON(w, r, data)
			return
		}
		lastUpdateMu.RUnlock()
	}
	list, err := downloadList()
	if err != nil {
		if *verbose {
			log.Printf("could not get torrents list: %v", err)
		}
		http.Error(w, "could not get torrents list", http.StatusInternalServerError)
		return
	}
	allStatus := make(map[string]*torrentStatus)
	for _, v := range list {
		tStatus, err := getStatus(v)
		if err != nil {
			if *verbose {
				log.Printf("could not get torrent status: %v", err)
			}
			http.Error(w, "could not get torrent status", http.StatusInternalServerError)
			return
		}
		allStatus[v] = tStatus
	}
	lastUpdateMu.Lock()
	defer lastUpdateMu.Unlock()
	statusMu.Lock()
	defer statusMu.Unlock()
	data, err := json.MarshalIndent(allStatus, "", "	")
	if err != nil {
		if *verbose {
			log.Printf("could not get json encode: %v", err)
		}
		http.Error(w, "could not json encode", http.StatusInternalServerError)
		return
	}
	status = allStatus
	lastUpdate = time.Now()
	serveJSON(w, r, data)
}

var (
	up *basicauth.UserPass

	statusMu sync.RWMutex
	status   map[string]*torrentStatus

	lastUpdateMu sync.RWMutex
	lastUpdate   time.Time
)

func main() {
	flag.Usage = usage
	flag.Parse()

	var err error
	up, err = basicauth.New(*userpass)
	if err != nil {
		log.Fatal(err)
	}
	if *verbose {
		basicauth.Verbose = true
	}

	http.Handle("/", makeHandler(serveStatus))
	if *secure {
		log.Fatal(http.ListenAndServeTLS(*host, "cert.pem", "key.pem", nil))
	}
	http.ListenAndServe(*host, nil)
}
<commit_msg>Use lets encrypt<commit_after>// 2015 - Mathieu Lonjaret

// The montorrent program serves the status of rtorrent. It uses
// github.com/mpl/rtorrentrpc to query rtorrent.
package main

import (
	"bufio"
	"bytes"
	"crypto/rand"
	"crypto/tls"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/mpl/basicauth"
	"golang.org/x/crypto/acme/autocert"
)

var (
	cache   = flag.Int("cache", 0, "cache the status for that many seconds. 0 means no caching")
	help    = flag.Bool("h", false, "show this help")
	host    = flag.String("host", "localhost:8080", "listening host:port")
	scgi    = flag.String("scgi", "localhost:5000", "host:port for rtorrent's scgi.")
	flagTLS = flag.Bool("tls", false, `For https. If "key.pem" or "cert.pem" are not found in $HOME/keys/, in-memory self-signed are generated and used instead.`)

	flagAutocert = flag.Bool("autocert", false, `Get https certificate from Let's Encrypt. Implies -tls=true. Obviously -host must contain a full qualified domain name. The cached certificate(s) will be in $HOME/keys/letsencrypt.cache.`)
	userpass     = flag.String("userpass", "", "optional username:password protection")
	verbose      = flag.Bool("v", false, "verbose")
)

const (
	numRetry   = 20
	retryDelay = 2 * time.Second
	idstring   = "http://golang.org/pkg/http/#ListenAndServe"
)

func usage() {
	flag.PrintDefaults()
	os.Exit(2)
}

func rpc(args ...string) ([]byte, error) {
	var answer []byte
	for i := 0; i < numRetry; i++ {
		cmd := exec.Command("rtorrentrpc", args...)
		output, err := cmd.CombinedOutput()
		if err != nil {
			// TODO(mpl): diagnose better the error and return early if it's not the expected EOF one.
			if *verbose {
				log.Printf("ignoring error: %v", err)
			}
			continue
		}
		if len(output) > 0 {
			answer = output
			break
		}
		time.Sleep(retryDelay)
	}
	if len(answer) == 0 {
		return nil, fmt.Errorf("empty answer for %v", args)
	}
	return answer, nil
}

func scanAnswer(answer []byte, prefix, suffix string) ([]string, error) {
	var list []string
	scanner := bufio.NewScanner(bytes.NewReader(answer))
	for scanner.Scan() {
		line := scanner.Text()
		if !strings.HasPrefix(line, prefix) || !strings.HasSuffix(line, suffix) {
			continue
		}
		list = append(list, strings.TrimSuffix(strings.TrimPrefix(line, prefix), suffix))
	}
	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("could not scan answer: %v", err)
	}
	return list, nil
}

func downloadList() ([]string, error) {
	answer, err := rpc(*scgi, "download_list", "")
	if err != nil {
		return nil, err
	}
	return scanAnswer(answer, "<value><string>", "</string></value>")
}

func torrentName(torrentHash string) (string, error) {
	answer, err := rpc(*scgi, "d.name", torrentHash)
	if err != nil {
		return "", err
	}
	list, err := scanAnswer(answer, "<param><value><string>", "</string></value></param>")
	if err != nil {
		return "", err
	}
	if len(list) == 0 {
		return "", fmt.Errorf("%v: name not found", torrentHash)
	}
	return list[0], nil
}

func bytesDone(torrentHash string) (int, error) {
	var n int
	answer, err := rpc(*scgi, "d.get_bytes_done", torrentHash)
	if err != nil {
		return n, err
	}
	list, err := scanAnswer(answer, "<param><value><i8>", "</i8></value></param>")
	if err != nil {
		return n, err
	}
	if len(list) == 0 {
		return n, fmt.Errorf("%v: bytes_done not found", torrentHash)
	}
	n, err = strconv.Atoi(list[0])
	if err != nil {
		return n, fmt.Errorf("could not convert bytes_done to int: %v", err)
	}
	return n, nil
}

func bytesLeft(torrentHash string) (int, error) {
	var n int
	answer, err := rpc(*scgi, "d.get_left_bytes", torrentHash)
	if err != nil {
		return n, err
	}
	list, err := scanAnswer(answer, "<param><value><i8>", "</i8></value></param>")
	if err != nil {
		return n, err
	}
	if len(list) == 0 {
		return n, fmt.Errorf("%v: bytes_left not found", torrentHash)
	}
	n, err = strconv.Atoi(list[0])
	if err != nil {
		return n, fmt.Errorf("could not convert bytes_left to int: %v", err)
	}
	return n, nil
}

type torrentStatus struct {
	Name        string
	BytesDone   int
	BytesLeft   int
	BytesTotal  int
	PercentDone int
}

func getStatus(torrentHash string) (*torrentStatus, error) {
	name, err := torrentName(torrentHash)
	if err != nil {
		return nil, err
	}
	nDone, err := bytesDone(torrentHash)
	if err != nil {
		return nil, err
	}
	nLeft, err := bytesLeft(torrentHash)
	if err != nil {
		return nil, err
	}
	total := nDone + nLeft // yay, super precision!!
	percent := nDone * 100 / total
	return &torrentStatus{
		Name:        name,
		BytesDone:   nDone,
		BytesLeft:   nLeft,
		BytesTotal:  total,
		PercentDone: percent,
	}, nil
}

func makeHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if e, ok := recover().(error); ok {
				http.Error(w, e.Error(), http.StatusInternalServerError)
				return
			}
		}()
		w.Header().Set("Server", idstring)
		if up.IsAllowed(r) {
			fn(w, r)
		} else {
			basicauth.SendUnauthorized(w, r, "montorrent")
		}
	}
}

func serveJSON(w http.ResponseWriter, r *http.Request, data []byte) {
	w.Header().Set("Content-Type", "text/javascript")
	w.Header().Set("Content-Length", strconv.Itoa(len(data)+1))
	w.WriteHeader(200)
	w.Write(data)
	w.Write([]byte("\n"))
}

func serveStatus(w http.ResponseWriter, r *http.Request) {
	if *cache > 0 {
		lastUpdateMu.RLock()
		// TODO(mpl): maybe use a checkLastModified. pull it out of simpleHttpd as a lib?
		if time.Now().Before(lastUpdate.Add(time.Duration(*cache) * time.Second)) {
			defer lastUpdateMu.RUnlock()
			statusMu.RLock()
			defer statusMu.RUnlock()
			data, err := json.MarshalIndent(status, "", "	")
			if err != nil {
				if *verbose {
					log.Printf("could not get json encode: %v", err)
				}
				http.Error(w, "could not json encode", http.StatusInternalServerError)
				return
			}
			serveJSON(w, r, data)
			return
		}
		lastUpdateMu.RUnlock()
	}
	list, err := downloadList()
	if err != nil {
		if *verbose {
			log.Printf("could not get torrents list: %v", err)
		}
		http.Error(w, "could not get torrents list", http.StatusInternalServerError)
		return
	}
	allStatus := make(map[string]*torrentStatus)
	for _, v := range list {
		tStatus, err := getStatus(v)
		if err != nil {
			if *verbose {
				log.Printf("could not get torrent status: %v", err)
			}
			http.Error(w, "could not get torrent status", http.StatusInternalServerError)
			return
		}
		allStatus[v] = tStatus
	}
	lastUpdateMu.Lock()
	defer lastUpdateMu.Unlock()
	statusMu.Lock()
	defer statusMu.Unlock()
	data, err := json.MarshalIndent(allStatus, "", "	")
	if err != nil {
		if *verbose {
			log.Printf("could not get json encode: %v", err)
		}
		http.Error(w, "could not json encode", http.StatusInternalServerError)
		return
	}
	status = allStatus
	lastUpdate = time.Now()
	serveJSON(w, r, data)
}

func setupTLS() (*tls.Config, error) {
	hostname := *host
	if strings.Contains(hostname, ":") {
		h, _, err := net.SplitHostPort(hostname)
		if err != nil {
			return nil, err
		}
		hostname = h
	}
	if *flagAutocert {
		m := autocert.Manager{
			Prompt:     autocert.AcceptTOS,
			HostPolicy: autocert.HostWhitelist(hostname),
			Cache:      autocert.DirCache(certCache),
		}
		return &tls.Config{
			GetCertificate: m.GetCertificate,
		}, nil
	}
	cert, err := tls.LoadX509KeyPair(tlsCert, tlsKey)
	if err != nil {
		return nil, fmt.Errorf("Failed to load TLS cert: %v", err)
	}
	return &tls.Config{
		Rand:         rand.Reader,
		Time:         time.Now,
		NextProtos:   []string{"http/1.1"},
		Certificates: []tls.Certificate{cert},
	}, nil
}

var (
	up        *basicauth.UserPass
	tlsKey    = filepath.Join(os.Getenv("HOME"), "keys", "key.pem")
	tlsCert   = filepath.Join(os.Getenv("HOME"), "keys", "cert.pem")
	certCache = filepath.Join(os.Getenv("HOME"), "keys", "letsencrypt.cache")

	statusMu sync.RWMutex
	status   map[string]*torrentStatus

	lastUpdateMu sync.RWMutex
	lastUpdate   time.Time
)

func main() {
	flag.Usage = usage
	flag.Parse()

	var err error
	up, err = basicauth.New(*userpass)
	if err != nil {
		log.Fatal(err)
	}
	if *verbose {
		basicauth.Verbose = true
	}

	listener, err := net.Listen("tcp", *host)
	if err != nil {
		log.Fatalf("Failed to listen on %s: %v", *host, err)
	}

	if !*flagTLS && *flagAutocert {
		*flagTLS = true
	}

	if *flagTLS {
		config, err := setupTLS()
		if err != nil {
			log.Fatalf("could not configure TLS connection: %v", err)
		}
		listener = tls.NewListener(listener, config)
	}

	http.Handle("/", makeHandler(serveStatus))
	log.Fatal(http.Serve(listener, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"github.com/chzyer/readline"
	"github.com/codegangsta/cli"
	"github.com/madcitygg/rcon"
	"github.com/mitchellh/colorstring"
	"io"
	"os"
	"strconv"
	"strings"
)

// Server addresses

const (
	defaultPort = 27015
)

type Address struct {
	Host string
	Port int
}

func (a *Address) String() string {
	return fmt.Sprintf("%s:%d", a.Host, a.Port)
}

func ParseAddress(address string) (a *Address, err error) {
	var host string
	var port int

	parts := strings.Split(address, ":")
	if len(parts) > 2 {
		err = errors.New("address contains multiple colons")
	}

	if len(parts) == 1 {
		host = parts[0]
		port = defaultPort
	} else if len(parts) == 2 {
		host = parts[0]
		port, err = strconv.Atoi(parts[1])
		if err != nil {
			return
		}
	}

	a = &Address{host, port}
	return
}

// Main loop

func main() {
	// global vars
	password := ""
	authenticated := false

	// set up cli app
	app := cli.NewApp()
	app.Name = "rcc"
	app.Usage = "control a Source RCON server"
	app.UsageText = "rcc [global options] server"
	app.Version = "0.0.1"

	// add global command line flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "password, p",
			Usage:       "rcon password",
			Destination: &password,
		},
	}

	// default action
	app.Action = func(ctx *cli.Context) {
		if len(ctx.Args()) == 0 {
			// the user did not provide a server to connect to
			cli.ShowAppHelp(ctx)
			os.Exit(1)
		}

		// parse server address
		address, err := ParseAddress(ctx.Args()[0])
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}

		// dial the server
		colorstring.Printf("Connecting to %s\n", address)
		rc, err := rcon.Dial(address.String())
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}
		defer rc.Close()
		colorstring.Printf("[green]Connection successful![reset]\n")

		// create readline instance
		rl, err := readline.NewEx(&readline.Config{
			Prompt:          "> ",
			InterruptPrompt: "\nPress Ctrl+D to exit",
			EOFPrompt:       "exit",
		})
		if err != nil {
			panic(err)
		}
		defer rl.Close()

		passwordConfig := rl.GenPasswordConfig()
		passwordConfig.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
			rl.SetPrompt("Enter password: ")
			rl.Refresh()
			return nil, 0, false
		})

		// start inner console
		console := cli.NewApp()
		console.Commands = []cli.Command{
			{
				Name:  "login",
				Usage: "Log in to rcon server",
				Action: func(c *cli.Context) {
					askForPassword := func(destination *string) {
						for len(*destination) == 0 {
							// read a password from command line
							pw, err := rl.ReadPasswordWithConfig(passwordConfig)
							if err == io.EOF {
								os.Exit(1)
							}
							if err != nil {
								colorstring.Printf("Press Ctrl+D to exit\n")
							}
							// clean it up and check if it makes sense
							*destination = strings.TrimSpace(string(pw))
							if len(*destination) == 0 {
								colorstring.Printf("[red]Please enter a valid password[reset]")
							}
						}
					}

					// ask for a password until we authenticate successfully
					for !authenticated {
						askForPassword(&password)
						err := rc.Authenticate(password)
						if err != nil {
							colorstring.Printf("[red]Authentication failed. Incorrect password?[reset]")
							password = ""
							continue
						}

						authenticated = true
					}
				},
			},
			{
				Name: "clear",
				Action: func(c *cli.Context) {
					colorstring.Printf("[red]`clear` has not been implemented yet.[reset]\n")
				},
			},
			{
				Name:    "exit",
				Aliases: []string{"quit", "q"},
				Action: func(c *cli.Context) {
					os.Exit(1)
				},
			},
		}
		console.Action = func(c *cli.Context) {
			command := strings.Join(c.Args(), " ")
			response, err := rc.Execute(command)
			if err != nil {
				colorstring.Printf("[red]Error: %s[reset]\n", err)
			}

			fmt.Println(response.Body)
		}

		// perform login to authenticate with rcon server
		console.Run(strings.Fields("cmd login"))

		// set a nice prompt with server name and port
		prompt := "[white]%s[reset]:[blue]%d[reset]> "
		rl.SetPrompt(colorstring.Color(fmt.Sprintf(prompt, address.Host, address.Port)))

		// start readline loop
		for {
			line, err := rl.Readline()
			if err == io.EOF {
				break
			}
			if err != nil {
				continue
			}

			console.Run([]string{"cmd", line})
		}
	}

	app.Run(os.Args)
}
<commit_msg>Don't try and print an error response<commit_after>package main

import (
	"errors"
	"fmt"
	"github.com/chzyer/readline"
	"github.com/codegangsta/cli"
	"github.com/madcitygg/rcon"
	"github.com/mitchellh/colorstring"
	"io"
	"os"
	"strconv"
	"strings"
)

// Server addresses

const (
	defaultPort = 27015
)

type Address struct {
	Host string
	Port int
}

func (a *Address) String() string {
	return fmt.Sprintf("%s:%d", a.Host, a.Port)
}

func ParseAddress(address string) (a *Address, err error) {
	var host string
	var port int

	parts := strings.Split(address, ":")
	if len(parts) > 2 {
		err = errors.New("address contains multiple colons")
	}

	if len(parts) == 1 {
		host = parts[0]
		port = defaultPort
	} else if len(parts) == 2 {
		host = parts[0]
		port, err = strconv.Atoi(parts[1])
		if err != nil {
			return
		}
	}

	a = &Address{host, port}
	return
}

// Main loop

func main() {
	// global vars
	password := ""
	authenticated := false

	// set up cli app
	app := cli.NewApp()
	app.Name = "rcc"
	app.Usage = "control a Source RCON server"
	app.UsageText = "rcc [global options] server"
	app.Version = "0.0.1"

	// add global command line flags
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "password, p",
			Usage:       "rcon password",
			Destination: &password,
		},
	}

	// default action
	app.Action = func(ctx *cli.Context) {
		if len(ctx.Args()) == 0 {
			// the user did not provide a server to connect to
			cli.ShowAppHelp(ctx)
			os.Exit(1)
		}

		// parse server address
		address, err := ParseAddress(ctx.Args()[0])
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}

		// dial the server
		colorstring.Printf("Connecting to %s\n", address)
		rc, err := rcon.Dial(address.String())
		if err != nil {
			println(err.Error())
			os.Exit(1)
		}
		defer rc.Close()
		colorstring.Printf("[green]Connection successful![reset]\n")

		// create readline instance
		rl, err := readline.NewEx(&readline.Config{
			Prompt:          "> ",
			InterruptPrompt: "\nPress Ctrl+D to exit",
			EOFPrompt:       "exit",
		})
		if err != nil {
			panic(err)
		}
		defer rl.Close()

		passwordConfig := rl.GenPasswordConfig()
		passwordConfig.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
			rl.SetPrompt("Enter password: ")
			rl.Refresh()
			return nil, 0, false
		})

		// start inner console
		console := cli.NewApp()
		console.Commands = []cli.Command{
			{
				Name:  "login",
				Usage: "Log in to rcon server",
				Action: func(c *cli.Context) {
					askForPassword := func(destination *string) {
						for len(*destination) == 0 {
							// read a password from command line
							pw, err := rl.ReadPasswordWithConfig(passwordConfig)
							if err == io.EOF {
								os.Exit(1)
							}
							if err != nil {
								colorstring.Printf("Press Ctrl+D to exit\n")
							}
							// clean it up and check if it makes sense
							*destination = strings.TrimSpace(string(pw))
							if len(*destination) == 0 {
								colorstring.Printf("[red]Please enter a valid password[reset]")
							}
						}
					}

					// ask for a password until we authenticate successfully
					for !authenticated {
						askForPassword(&password)
						err := rc.Authenticate(password)
						if err != nil {
							colorstring.Printf("[red]Authentication failed. Incorrect password?[reset]")
							password = ""
							continue
						}

						authenticated = true
					}
				},
			},
			{
				Name: "clear",
				Action: func(c *cli.Context) {
					colorstring.Printf("[red]`clear` has not been implemented yet.[reset]\n")
				},
			},
			{
				Name:    "exit",
				Aliases: []string{"quit", "q"},
				Action: func(c *cli.Context) {
					os.Exit(1)
				},
			},
		}
		console.Action = func(c *cli.Context) {
			command := strings.Join(c.Args(), " ")
			response, err := rc.Execute(command)
			if err != nil {
				colorstring.Printf("[red]Error: %s[reset]\n", err)
				return
			}

			fmt.Println(response.Body)
		}

		// perform login to authenticate with rcon server
		console.Run(strings.Fields("cmd login"))

		// set a nice prompt with server name and port
		prompt := "[white]%s[reset]:[blue]%d[reset]> "
		rl.SetPrompt(colorstring.Color(fmt.Sprintf(prompt, address.Host, address.Port)))

		// start readline loop
		for {
			line, err := rl.Readline()
			if err == io.EOF {
				break
			}
			if err != nil {
				continue
			}

			console.Run([]string{"cmd", line})
		}
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	//	"github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1"
)

type ImageRender struct {
	BinaryPath *string
}

//render image with wkhtmltoimage with url
func (r *ImageRender) GetBytes(req *http.Request, format string) ([]byte, error) {
	err := req.ParseForm()
	if err != nil {
		return nil, err
	}
	url := req.Form.Get("url")

	var html string
	if len(url) == 0 {
		html = req.Form.Get("html")

		if len(html) == 0 {
			return nil, errors.New("url can't be null")
		} else {
			url = "-"
			log.Println("render for: ", html)
		}
	} else {
		html = ""
		log.Println("render for: ", url)
	}

	c := ImageOptions{BinaryPath: *r.BinaryPath,
		Input: url, Html: html, Format: format}

	return GenerateImage(&c)
}

//render image bytes to browser
func (r *ImageRender) RenderBytes(w http.ResponseWriter, req *http.Request, format string) {
	out, err := r.GetBytes(req, format)
	if err != nil {
		w.Write([]byte(fmt.Sprint(err)))
		return
	}
	w.Write(out)
}

func main() {
	binPath := flag.String("path", "/usr/local/bin/wkhtmltoimage", "wkhtmltoimage bin path")
	port := flag.String("web.port", "8080", "web server port")
	flag.Parse()
	render := ImageRender{}
	render.BinaryPath = binPath
	//	r := render.New()
	mux := http.NewServeMux()

	mux.HandleFunc("/render.png", func(w http.ResponseWriter, req *http.Request) {
		render.RenderBytes(w, req, "png")
	})
	mux.HandleFunc("/render.jpg", func(w http.ResponseWriter, req *http.Request) {
		render.RenderBytes(w, req, "jpg")
	})
	if len(*port) == 0 {
		*port = "8080"
	}
	http.ListenAndServe(":"+*port, mux)
}
<commit_msg>support for custom width, height and quality<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"strconv"
	//	"github.com/unrolled/render" // or "gopkg.in/unrolled/render.v1"
)

type ImageRender struct {
	BinaryPath *string
}

//render image with wkhtmltoimage with url
func (r *ImageRender) GetBytes(req *http.Request, format string) ([]byte, error) {
	err := req.ParseForm()
	if err != nil {
		return nil, err
	}
	url := req.Form.Get("url")

	var html string
	if len(url) == 0 {
		html = req.Form.Get("html")

		if len(html) == 0 {
			return nil, errors.New("url can't be null")
		} else {
			url = "-"
			log.Println("render for: ", html)
		}
	} else {
		html = ""
		log.Println("render for: ", url)
	}

	c := ImageOptions{BinaryPath: *r.BinaryPath,
		Input: url, Html: html, Format: format}

	width, err := strconv.Atoi(req.Form.Get("width"))
	if err == nil {
		c.Width = width
	}

	height, err := strconv.Atoi(req.Form.Get("height"))
	if err == nil {
		c.Height = height
	}

	quality, err := strconv.Atoi(req.Form.Get("quality"))
	if err == nil {
		c.Quality = quality
	}

	return GenerateImage(&c)
}

//render image bytes to browser
func (r *ImageRender) RenderBytes(w http.ResponseWriter, req *http.Request, format string) {
	out, err := r.GetBytes(req, format)
	if err != nil {
		w.Write([]byte(fmt.Sprint(err)))
		return
	}
	w.Write(out)
}

func main() {
	binPath := flag.String("path", "/usr/local/bin/wkhtmltoimage", "wkhtmltoimage bin path")
	port := flag.String("web.port", "8080", "web server port")
	flag.Parse()
	render := ImageRender{}
	render.BinaryPath = binPath
	//	r := render.New()
	mux := http.NewServeMux()

	mux.HandleFunc("/render.png", func(w http.ResponseWriter, req *http.Request) {
		render.RenderBytes(w, req, "png")
	})
	mux.HandleFunc("/render.jpg", func(w http.ResponseWriter, req *http.Request) {
		render.RenderBytes(w, req, "jpg")
	})
	if len(*port) == 0 {
		*port = "8080"
	}
	http.ListenAndServe(":"+*port, mux)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"path"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

func main() {
	config := GetConfig()
	fmt.Println(config)

	// set destination for all backups
	dst := "/tmp/"
	t := time.Now().UTC()
	datetime := fmt.Sprintf("%d-%02d-%02d_%02d-%02d-%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	dst += datetime + "/"
	err := os.Mkdir(dst, 0700)
	if err != nil {
		log.Fatalf("Could not create backup destination: %s", dst)
	}
	defer eraseFolder(dst)

	_, err = archiveVolumes(dst, config.Keep_failed_container)
	if err != nil {
		log.Panicf("Failed to archive volumes: %s", err.Error())
	}

	err = deliverToFTP(config, dst)
	if err != nil {
		fmt.Printf("Failed uploading to FTP: %s\n", err.Error())
		eraseFolder(dst)
		os.Exit(1)
	}
	log.Println("FTP upload successful")
}

func eraseFolder(destination string) error {
	err := os.RemoveAll(destination)
	if err != nil {
		log.Printf("Failed to remove archives at %s", destination)
		return err
	}
	log.Printf("Removed archives at %s", destination)
	return nil
}

func archiveVolumes(destination string, keepFailed bool) ([]string, error) {
	// Init the client
	client, err := docker.NewClient("unix:///var/run/docker.sock")
	if err != nil {
		return nil, err
	}

	toPause, err := getRunningContainers(client)
	if err != nil {
		return nil, err
	}

	err = pauseContainers(client, toPause)
	if err != nil {
		return nil, err
	}
	log.Printf("Paused %d cointainers.\n", len(toPause))

	defer func() {
		err = unpauseContainers(client, toPause)
		if err != nil {
			log.Panic(err.Error())
		}
		log.Printf("Unpaused %d cointainers.\n", len(toPause))
	}()

	volumes := getDataVolumes(client)
	log.Printf("%d data volumes to backup in %s .", len(volumes), destination)

	files := make([]string, 0)

	for _, vol := range volumes {
		file, err := backupVolume(client, destination, vol, keepFailed)
		if err != nil {
			return files, err
		}
		files = append(files, file)
		log.Printf(" * %s", path.Base(file))
	}

	return files, nil
}

func getRunningContainers(cli *docker.Client) ([]string, error) {
	containers, err := cli.ListContainers(docker.ListContainersOptions{
		All: true,
		Filters: map[string][]string{
			"status": []string{"running"},
		}})
	if err != nil {
		return nil, err
	}

	ids := make([]string, 0)
	for _, cont := range containers {
		ids = append(ids, cont.ID)
	}

	return ids, nil
}

func getDataVolumes(cli *docker.Client) []Volume {
	containers, err := cli.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		log.Fatal(err)
	}

	vols := make([]Volume, 0, 0)

	for _, cont := range containers {
		c := cont
		if isVolumeContainer(&c) {
			moreVols := getVolumes(cli, &c)
			vols = append(vols, moreVols...)
		}
	}

	return vols
}
<commit_msg>factor out tmp dir creation into a function<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"path"
	"time"

	docker "github.com/fsouza/go-dockerclient"
)

func main() {
	config := GetConfig()
	fmt.Println(config)

	// get destination for all backups
	dst, err := createArchiveDir()
	if err != nil {
		log.Fatalf("Could not create backup destination: %s", dst)
	}
	defer eraseFolder(dst)

	_, err = archiveVolumes(dst, config.Keep_failed_container)
	if err != nil {
		log.Panicf("Failed to archive volumes: %s", err.Error())
	}

	err = deliverToFTP(config, dst)
	if err != nil {
		fmt.Printf("Failed uploading to FTP: %s\n", err.Error())
		eraseFolder(dst)
		os.Exit(1)
	}
	log.Println("FTP upload successful")
}

func createArchiveDir() (string, error) {
	dst := "/tmp/"
	t := time.Now().UTC()
	datetime := fmt.Sprintf("%d-%02d-%02d_%02d-%02d-%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	dst += datetime + "/"
	err := os.Mkdir(dst, 0700)
	return dst, err
}

func eraseFolder(destination string) error {
	err := os.RemoveAll(destination)
	if err != nil {
		log.Printf("Failed to remove archives at %s", destination)
		return err
	}
	log.Printf("Removed archives at %s", destination)
	return nil
}

func archiveVolumes(destination string, keepFailed bool) ([]string, error) {
	// Init the client
	client, err := docker.NewClient("unix:///var/run/docker.sock")
	if err != nil {
		return nil, err
	}

	toPause, err := getRunningContainers(client)
	if err != nil {
		return nil, err
	}

	err = pauseContainers(client, toPause)
	if err != nil {
		return nil, err
	}
	log.Printf("Paused %d cointainers.\n", len(toPause))

	defer func() {
		err = unpauseContainers(client, toPause)
		if err != nil {
			log.Panic(err.Error())
		}
		log.Printf("Unpaused %d cointainers.\n", len(toPause))
	}()

	volumes := getDataVolumes(client)
	log.Printf("%d data volumes to backup in %s .", len(volumes), destination)

	files := make([]string, 0)

	for _, vol := range volumes {
		file, err := backupVolume(client, destination, vol, keepFailed)
		if err != nil {
			return files, err
		}
		files = append(files, file)
		log.Printf(" * %s", path.Base(file))
	}

	return files, nil
}

func getRunningContainers(cli *docker.Client) ([]string, error) {
	containers, err := cli.ListContainers(docker.ListContainersOptions{
		All: true,
		Filters: map[string][]string{
			"status": []string{"running"},
		}})
	if err != nil {
		return nil, err
	}

	ids := make([]string, 0)
	for _, cont := range containers {
		ids = append(ids, cont.ID)
	}

	return ids, nil
}

func getDataVolumes(cli *docker.Client) []Volume {
	containers, err := cli.ListContainers(docker.ListContainersOptions{All: true})
	if err != nil {
		log.Fatal(err)
	}

	vols := make([]Volume, 0, 0)

	for _, cont := range containers {
		c := cont
		if isVolumeContainer(&c) {
			moreVols := getVolumes(cli, &c)
			vols = append(vols, moreVols...)
		}
	}

	return vols
}
<|endoftext|>


<commit_before>// Package choose provides functions for making choices.
package choose

import (
	"math"
)

// UniformFloat64 returns the indices of n elements of a sequence such that the
// first and last elements are included, and the rest are chosen to have a more
// or less uniform distance between two successive elements.
func UniformFloat64(sequence []float64, n uint) []uint {
	m := uint(len(sequence))

	if m <= n {
		indices := make([]uint, m)
		for i := uint(0); i < m; i++ {
			indices[i] = i
		}
		return indices
	}

	switch n {
	case 0:
		return []uint{}
	case 1:
		return []uint{0}
	}

	indices := make([]uint, n)
	indices[0], indices[n-1] = 0, m-1

	pool := make(map[uint]bool)
	for i := uint(1); i+1 < m; i++ {
		pool[i] = true
	}

	min, max := float64(sequence[0]), float64(sequence[m-1])
	Δ := (max - min) / (float64(n) - 1)

	for i := uint(1); i+1 < n; i++ {
		k, x := ^uint(0), min+float64(i)*Δ
		for j := range pool {
			if k == ^uint(0) {
				k = j
				continue
			}
			Δ1 := math.Abs(x - sequence[j])
			Δ2 := math.Abs(x - sequence[k])
			if Δ1 < Δ2 || Δ1 == Δ2 && j < k {
				k = j
			}
		}
		indices[i] = k
		delete(pool, k)
	}

	return indices
}

// UniformUint is an analog of UniformFloat64 for uint.
func UniformUint(sequence []uint, n uint) []uint {
	clone := make([]float64, len(sequence))
	for i := range sequence {
		clone[i] = float64(sequence[i])
	}
	return UniformFloat64(clone, n)
}
<commit_msg>Refactor a bit<commit_after>// Package choose provides functions for making choices.
package choose

import (
	"math"
)

// UniformFloat64 returns the indices of n elements of a sequence such that the
// first and last elements are included, and the rest are chosen to have a more
// or less uniform distance between two successive elements.
func UniformFloat64(sequence []float64, n uint) []uint {
	m := uint(len(sequence))

	if m <= n {
		indices := make([]uint, m)
		for i := uint(0); i < m; i++ {
			indices[i] = i
		}
		return indices
	} else if n == 0 {
		return []uint{}
	} else if n == 1 {
		return []uint{0}
	}

	indices := make([]uint, n)
	indices[0], indices[n-1] = 0, m-1

	pool := make(map[uint]bool)
	for i := uint(1); i+1 < m; i++ {
		pool[i] = true
	}

	min, max := float64(sequence[0]), float64(sequence[m-1])
	Δ := (max - min) / (float64(n) - 1)

	for i := uint(1); i+1 < n; i++ {
		k, x := ^uint(0), min+float64(i)*Δ
		for j := range pool {
			if k == ^uint(0) {
				k = j
				continue
			}
			Δ1 := math.Abs(x - sequence[j])
			Δ2 := math.Abs(x - sequence[k])
			if Δ1 < Δ2 || Δ1 == Δ2 && j < k {
				k = j
			}
		}
		indices[i] = k
		delete(pool, k)
	}

	return indices
}

// UniformUint is an analog of UniformFloat64 for uint.
func UniformUint(sequence []uint, n uint) []uint {
	clone := make([]float64, len(sequence))
	for i := range sequence {
		clone[i] = float64(sequence[i])
	}
	return UniformFloat64(clone, n)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"

	"github.com/lnsp/dkvs/nodes/local"
)

var (
	role       = flag.String("role", "master", "Set the node role (master, slave, client)")
	replicas   = flag.Int("replicas", 0, "Set the number of replicas stored")
	remoteHost = flag.String("remote", "localhost:5000", "Set the remote address")
	localHost  = flag.String("local", "localhost:5000", "Set the local address")
)

func main() {
	flag.Parse()
	var instance local.Node
	switch *role {
	case "master":
		instance = local.NewMaster(*localHost, *remoteHost, *replicas)
	case "slave":
		instance = local.NewSlave(*localHost, *remoteHost)
	default:
		fmt.Println("Mode", *role, "not supported")
	}
	instance.Listen()
}
<commit_msg>add version flag<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/lnsp/dkvs/nodes/local"
)

const (
	versionText = "version:\n\tdkvs-0.0.1-indev"
)

func main() {
	role := flag.String("role", "master", "set node role to either master, slave or client")
	replicas := flag.Int("replicas", 0, "number of replicas in cluster")
	remoteHost := flag.String("remote", "localhost:5000", "set the remote address")
	localHost := flag.String("local", "localhost:5000", "set the local address")
	version := flag.Bool("v", false, "display version of dkvs")
	flag.Parse()

	if *version {
		fmt.Println(versionText)
		os.Exit(0)
	}

	var instance local.Node
	switch *role {
	case "master":
		instance = local.NewMaster(*localHost, *remoteHost, *replicas)
	case "slave":
		instance = local.NewSlave(*localHost, *remoteHost)
	default:
		fmt.Printf("usage:\n\t%s [-v] [--role [master | slave | client]] [--replicas [N]] [--local ...] [--remote ...]\n", os.Args[0])
		os.Exit(1)
	}
	instance.Listen()
}
<|endoftext|>