<commit_before>package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/meiraka/vv/internal/mpd"
	"github.com/meiraka/vv/internal/songs/cover"
)

const (
	defaultConfigDir = "/etc/xdg/vv"
)

var version = "v0.10.2+"

//go:generate go run internal/cmd/fix-assets/main.go
func main() {
	v2()
}

func configDirs() []string {
	dir, err := os.UserConfigDir()
	if err != nil {
		return []string{defaultConfigDir}
	}
	return []string{filepath.Join(dir, "vv"), defaultConfigDir}
}

func v2() {
	ctx := context.TODO()
	config, date, err := ParseConfig(configDirs(), "config.yaml")
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}
	dialer := mpd.Dialer{
		Timeout:              10 * time.Second,
		HealthCheckInterval:  time.Second,
		ReconnectionInterval: 5 * time.Second,
	}
	tree, err := json.Marshal(config.Playlist.Tree)
	if err != nil {
		log.Fatalf("failed to create playlist tree: %v", err)
	}
	treeOrder, err := json.Marshal(config.Playlist.TreeOrder)
	if err != nil {
		log.Fatalf("failed to create playlist tree order: %v", err)
	}
	cl, err := dialer.Dial(config.MPD.Network, config.MPD.Addr, "")
	if err != nil {
		log.Fatalf("failed to dial mpd: %v", err)
	}
	w, err := dialer.NewWatcher(config.MPD.Network, config.MPD.Addr, "")
	if err != nil {
		log.Fatalf("failed to dial mpd: %v", err)
	}
	commands, err := cl.Commands(ctx)
	if err != nil {
		log.Fatalf("failed to check mpd supported functions: %v", err)
	}
	// get music dir from local mpd connection
	if config.MPD.Network == "unix" && config.MPD.MusicDirectory == "" {
		if c, err := cl.Config(ctx); err == nil {
			if dir, ok := c["music_directory"]; ok {
				config.MPD.MusicDirectory = dir
				log.Printf("apply mpd.music_directory from mpd connection: %s", dir)
			}
		}
	}

	// get music dir from local mpd config
	mpdConf, _ := mpd.ParseConfig(config.MPD.Conf)
	if config.MPD.MusicDirectory == "" {
		if mpdConf != nil && len(config.MPD.Conf) != 0 {
			config.MPD.MusicDirectory = mpdConf.MusicDirectory
			log.Printf("apply mpd.music_directory from %s: %s", config.MPD.Conf, mpdConf.MusicDirectory)
		}
	}
	proxy := map[string]string{}
	if mpdConf != nil {
		host := "localhost"
		if config.MPD.Network == "tcp" {
			h := strings.Split(config.MPD.Addr, ":")[0]
			if len(h) != 0 {
				host = h
			}
		}
		for _, dev := range mpdConf.AudioOutputs {
			if len(dev.Port) != 0 {
				proxy[dev.Name] = "http://" + host + ":" + dev.Port
			}
		}
	}
	m := http.NewServeMux()
	covers := make([]cover.Cover, 0, 2)
	if config.Server.Cover.Local {
		if len(config.MPD.MusicDirectory) == 0 {
			log.Println("config.server.cover.local is disabled: mpd.music_directory is empty")
		} else if !strings.HasPrefix(config.MPD.MusicDirectory, "/") {
			log.Printf("config.server.cover.local is disabled: mpd.music_directory is not absolute local directory path: %v", config.MPD.MusicDirectory)
		} else {
			c, err := cover.NewLocal("/api/music/images/local/", config.MPD.MusicDirectory, []string{"cover.jpg", "cover.jpeg", "cover.png", "cover.gif", "cover.bmp"})
			if err != nil {
				log.Fatalf("failed to initialize coverart: %v", err)
			}
			m.Handle("/api/music/images/local/", c)
			covers = append(covers, c)

		}
	}
	if config.Server.Cover.Remote {
		if !contains(commands, "albumart") {
			log.Println("config.server.cover.remote is disabled: mpd does not support albumart command")
		} else {
			c, err := cover.NewRemote("/api/music/images/remote/", cl, filepath.Join(config.Server.CacheDirectory, "imgcache"))
			if err != nil {
				log.Fatalf("failed to initialize coverart: %v", err)
			}
			m.Handle("/api/music/images/remote/", c)
			covers = append(covers, c)
			defer c.Close()
		}
	}
	batch := cover.NewBatch(covers)
	assets := AssetsConfig{
		LocalAssets: config.debug,
		Extra: map[string]string{
			"AssetsAppCSSHash": string(AssetsAppCSSHash),
			"AssetsAppJSHash":  string(AssetsAppJSHash),
			"TREE":             string(tree),
			"TREE_ORDER":       string(treeOrder),
		},
		ExtraDate: date,
	}.NewAssetsHandler()
	api, stopAPI, err := APIConfig{
		AudioProxy: proxy,
	}.NewAPIHandler(ctx, cl, w, batch)
	if err != nil {
		log.Fatalf("failed to initialize api handler: %v", err)
	}
	m.Handle("/", assets)
	m.Handle("/api/", api)

	if err != nil {
		log.Fatalf("failed to initialize app: %v", err)
	}
	s := http.Server{
		Handler: m,
		Addr:    config.Server.Addr,
	}
	s.RegisterOnShutdown(stopAPI)
	errs := make(chan error, 1)
	go func() {
		errs <- s.ListenAndServe()
	}()
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGTERM, syscall.SIGINT)
	select {
	case <-sc:
	case err := <-errs:
		if err != http.ErrServerClosed {
			log.Fatalf("server stopped with error: %v", err)
		}
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := s.Shutdown(ctx); err != nil {
		log.Printf("failed to stop http server: %v", err)
	}
	if err := cl.Close(ctx); err != nil {
		log.Printf("failed to close mpd connection(main): %v", err)
	}
	if err := w.Close(ctx); err != nil {
		log.Printf("failed to close mpd connection(event): %v", err)
	}
	if err := batch.Shutdown(ctx); err != nil {
		log.Printf("failed to stop image api: %v", err)
	}
}

func contains(list []string, item string) bool {
	for _, n := range list {
		if item == n {
			return true
		}
	}
	return false
}
<commit_msg>allow manual configured relative music_directory path<commit_after>package main

import (
	"context"
	"encoding/json"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"github.com/meiraka/vv/internal/mpd"
	"github.com/meiraka/vv/internal/songs/cover"
)

const (
	defaultConfigDir = "/etc/xdg/vv"
)

var version = "v0.10.2+"

//go:generate go run internal/cmd/fix-assets/main.go
func main() {
	v2()
}

func configDirs() []string {
	dir, err := os.UserConfigDir()
	if err != nil {
		return []string{defaultConfigDir}
	}
	return []string{filepath.Join(dir, "vv"), defaultConfigDir}
}

func v2() {
	ctx := context.TODO()
	config, date, err := ParseConfig(configDirs(), "config.yaml")
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}
	dialer := mpd.Dialer{
		Timeout:              10 * time.Second,
		HealthCheckInterval:  time.Second,
		ReconnectionInterval: 5 * time.Second,
	}
	tree, err := json.Marshal(config.Playlist.Tree)
	if err != nil {
		log.Fatalf("failed to create playlist tree: %v", err)
	}
	treeOrder, err := json.Marshal(config.Playlist.TreeOrder)
	if err != nil {
		log.Fatalf("failed to create playlist tree order: %v", err)
	}
	cl, err := dialer.Dial(config.MPD.Network, config.MPD.Addr, "")
	if err != nil {
		log.Fatalf("failed to dial mpd: %v", err)
	}
	w, err := dialer.NewWatcher(config.MPD.Network, config.MPD.Addr, "")
	if err != nil {
		log.Fatalf("failed to dial mpd: %v", err)
	}
	commands, err := cl.Commands(ctx)
	if err != nil {
		log.Fatalf("failed to check mpd supported functions: %v", err)
	}
	// get music dir from local mpd connection
	if config.MPD.Network == "unix" && config.MPD.MusicDirectory == "" {
		if c, err := cl.Config(ctx); err == nil {
			if dir, ok := c["music_directory"]; ok && filepath.IsAbs(dir) {
				config.MPD.MusicDirectory = dir
				log.Printf("apply mpd.music_directory from mpd connection: %s", dir)
			}
		}
	}

	// get music dir from local mpd config
	mpdConf, _ := mpd.ParseConfig(config.MPD.Conf)
	if config.MPD.MusicDirectory == "" {
		if mpdConf != nil && filepath.IsAbs(config.MPD.Conf) {
			config.MPD.MusicDirectory = mpdConf.MusicDirectory
			log.Printf("apply mpd.music_directory from %s: %s", config.MPD.Conf, mpdConf.MusicDirectory)
		}
	}
	proxy := map[string]string{}
	if mpdConf != nil {
		host := "localhost"
		if config.MPD.Network == "tcp" {
			h := strings.Split(config.MPD.Addr, ":")[0]
			if len(h) != 0 {
				host = h
			}
		}
		for _, dev := range mpdConf.AudioOutputs {
			if len(dev.Port) != 0 {
				proxy[dev.Name] = "http://" + host + ":" + dev.Port
			}
		}
	}
	m := http.NewServeMux()
	covers := make([]cover.Cover, 0, 2)
	if config.Server.Cover.Local {
		if len(config.MPD.MusicDirectory) == 0 {
			log.Println("config.server.cover.local is disabled: mpd.music_directory is empty")
		} else {
			c, err := cover.NewLocal("/api/music/images/local/", config.MPD.MusicDirectory, []string{"cover.jpg", "cover.jpeg", "cover.png", "cover.gif", "cover.bmp"})
			if err != nil {
				log.Fatalf("failed to initialize coverart: %v", err)
			}
			m.Handle("/api/music/images/local/", c)
			covers = append(covers, c)

		}
	}
	if config.Server.Cover.Remote {
		if !contains(commands, "albumart") {
			log.Println("config.server.cover.remote is disabled: mpd does not support albumart command")
		} else {
			c, err := cover.NewRemote("/api/music/images/remote/", cl, filepath.Join(config.Server.CacheDirectory, "imgcache"))
			if err != nil {
				log.Fatalf("failed to initialize coverart: %v", err)
			}
			m.Handle("/api/music/images/remote/", c)
			covers = append(covers, c)
			defer c.Close()
		}
	}
	batch := cover.NewBatch(covers)
	assets := AssetsConfig{
		LocalAssets: config.debug,
		Extra: map[string]string{
			"AssetsAppCSSHash": string(AssetsAppCSSHash),
			"AssetsAppJSHash":  string(AssetsAppJSHash),
			"TREE":             string(tree),
			"TREE_ORDER":       string(treeOrder),
		},
		ExtraDate: date,
	}.NewAssetsHandler()
	api, stopAPI, err := APIConfig{
		AudioProxy: proxy,
	}.NewAPIHandler(ctx, cl, w, batch)
	if err != nil {
		log.Fatalf("failed to initialize api handler: %v", err)
	}
	m.Handle("/", assets)
	m.Handle("/api/", api)

	if err != nil {
		log.Fatalf("failed to initialize app: %v", err)
	}
	s := http.Server{
		Handler: m,
		Addr:    config.Server.Addr,
	}
	s.RegisterOnShutdown(stopAPI)
	errs := make(chan error, 1)
	go func() {
		errs <- s.ListenAndServe()
	}()
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGTERM, syscall.SIGINT)
	select {
	case <-sc:
	case err := <-errs:
		if err != http.ErrServerClosed {
			log.Fatalf("server stopped with error: %v", err)
		}
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := s.Shutdown(ctx); err != nil {
		log.Printf("failed to stop http server: %v", err)
	}
	if err := cl.Close(ctx); err != nil {
		log.Printf("failed to close mpd connection(main): %v", err)
	}
	if err := w.Close(ctx); err != nil {
		log.Printf("failed to close mpd connection(event): %v", err)
	}
	if err := batch.Shutdown(ctx); err != nil {
		log.Printf("failed to stop image api: %v", err)
	}
}

func contains(list []string, item string) bool {
	for _, n := range list {
		if item == n {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/djosephsen/hal"
	_ "github.com/djosephsen/hal/adapter/slack"
	"github.com/djosephsen/bothandlers"
	_ "github.com/djosephsen/hal/store/memory"
	"os"
)

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		bothandlers.Syn,
		bothandlers.Tableflip,
		bothandlers.IKR,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}

func main() {
	os.Exit(run())
}
<commit_msg>added listroom<commit_after>package main

import (
	"github.com/djosephsen/hal"
	_ "github.com/djosephsen/hal/adapter/slack"
	"github.com/djosephsen/bothandlers"
	_ "github.com/djosephsen/hal/store/memory"
	"os"
)

func run() int {
	robot, err := hal.NewRobot()
	if err != nil {
		hal.Logger.Error(err)
		return 1
	}

	robot.Handle(
		bothandlers.Syn,
		bothandlers.Tableflip,
		bothandlers.IKR,
		bothandlers.Listrooms,
	)

	if err := robot.Run(); err != nil {
		hal.Logger.Error(err)
		return 1
	}
	return 0
}

func main() {
	os.Exit(run())
}
<|endoftext|>


<commit_before>package main

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

	"github.com/AlexanderThaller/logger"
	"github.com/juju/errgo"
	"github.com/julienschmidt/httprouter"
	"github.com/spf13/viper"
)

const (
	// Name is the name of the application. Used in logging.
	Name = "wikgo"
)

var (
	BuildHash string
	BuildTime string
)

func init() {
	err := configure()
	if err != nil {
		panic(err)
	}

	loglevel, err := logger.ParsePriority(viper.GetString("LogLevel"))
	if err != nil {
		panic(err)
	}

	err = logger.SetLevel(".", loglevel)
	if err != nil {
		panic(err)
	}
}

func main() {
	l := logger.New(Name, "main")
	l.Info("Version: ", fmt.Sprintf("%v-b%v", BuildHash, BuildTime))

	pagesFolder := viper.GetString("PagesFolder")
	binding := viper.GetString("Binding")

	router := httprouter.New()
	router.GET("/", rootHandler)
	router.GET("/"+pagesFolder+"/*path", pagesHandler)

	l.Notice("Listening on ", binding)
	err := http.ListenAndServe(binding, router)
	if err != nil {
		l.Alert(errgo.Notef(err, "can not listen on binding"))
		os.Exit(1)
	}
}

func rootHandler(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	pagesFolder := viper.GetString("PagesFolder")
	http.Redirect(wr, re, "/"+pagesFolder+"/", 301)
}

func pagesHandler(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandler")
	timestart := time.Now()
	ip, _, _ := net.SplitHostPort(re.RemoteAddr)

	path := path.Clean("./" + re.URL.Path)
	l.Notice("Sending ", path, " to ", ip)

	stat, err := os.Stat(path)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not stat path"))
		return
	}

	if stat.Mode().IsDir() {
		l.Trace("Filetype: Directory")
		pagesHandlerDirectory(wr, re, ps)
	}

	if stat.Mode().IsRegular() {
		l.Trace("Filetype: File")
		pagesHandlerFile(wr, re, ps)
	}

	if !stat.Mode().IsDir() && !stat.Mode().IsRegular() {
		l.Error("Filetype is not a directory and not a regular file. Something is strange.")
	}

	l.Debug("Sent ", path, " (", time.Since(timestart), ")")
}

func pagesHandlerDirectory(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandlerDirectory")

	urlpath := "./" + re.URL.Path
	files, err := ioutil.ReadDir(urlpath)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not read from directory"))
		return
	}

	fmt.Fprintf(wr, `<!DOCTYPE html>

  <meta charset="utf-8">
  <title>title</title>

  `)
	for _, file := range files {
		filepath := path.Clean(re.URL.Path + "/" + file.Name())
		fmt.Fprintf(wr, ""+file.Name()+"")
		fmt.Fprintf(wr, "
\n")
	}
	fmt.Fprintf(wr, `
  `)
}

func pagesHandlerFile(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandlerDirectory")

	path := "./" + re.URL.Path
	file, err := os.Open(path)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not open file for reading"))
		return
	}
	defer file.Close()

	l.Trace("Filepath Extention: ", filepath.Ext(path))
	switch filepath.Ext(path) {
	case ".asciidoc":
		err = asciiDoctor(file, wr)
		if err != nil {
			printerr(l, wr, errgo.Notef(err, "can not format file with asciidoctor"))
			return
		}

	default:
		_, err = io.Copy(wr, file)
		if err != nil {
			printerr(l, wr, errgo.Notef(err, "can not copy file to response writer"))
			return
		}
	}
}

func printerr(l logger.Logger, wr http.ResponseWriter, err error) {
	l.Error(errgo.Details(err))
	fmt.Fprintf(wr, errgo.Details(err))

	return
}

func asciiDoctor(reader io.Reader, writer io.Writer) error {
	stderr := new(bytes.Buffer)

	command := exec.Command("asciidoctor", "-")
	command.Stdin = reader
	command.Stdout = writer
	command.Stderr = stderr

	err := command.Run()
	if err != nil {
		return errgo.Notef(errgo.Notef(err, "can not run asciidoctor"),
			stderr.String())
	}

	return nil
}
<commit_msg>Will now encode filenames in directory listing.<commit_after>package main

import (
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/http"
	"net/url"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"time"

	"github.com/AlexanderThaller/logger"
	"github.com/juju/errgo"
	"github.com/julienschmidt/httprouter"
	"github.com/spf13/viper"
)

const (
	// Name is the name of the application. Used in logging.
	Name = "wikgo"
)

var (
	BuildHash string
	BuildTime string
)

func init() {
	err := configure()
	if err != nil {
		panic(err)
	}

	loglevel, err := logger.ParsePriority(viper.GetString("LogLevel"))
	if err != nil {
		panic(err)
	}

	err = logger.SetLevel(".", loglevel)
	if err != nil {
		panic(err)
	}
}

func main() {
	l := logger.New(Name, "main")
	l.Info("Version: ", fmt.Sprintf("%v-b%v", BuildHash, BuildTime))

	pagesFolder := viper.GetString("PagesFolder")
	binding := viper.GetString("Binding")

	router := httprouter.New()
	router.GET("/", rootHandler)
	router.GET("/"+pagesFolder+"/*path", pagesHandler)

	l.Notice("Listening on ", binding)
	err := http.ListenAndServe(binding, router)
	if err != nil {
		l.Alert(errgo.Notef(err, "can not listen on binding"))
		os.Exit(1)
	}
}

func rootHandler(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	pagesFolder := viper.GetString("PagesFolder")
	http.Redirect(wr, re, "/"+pagesFolder+"/", 301)
}

func pagesHandler(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandler")
	timestart := time.Now()
	ip, _, _ := net.SplitHostPort(re.RemoteAddr)

	path := path.Clean("./" + re.URL.Path)
	l.Notice("Sending ", path, " to ", ip)

	stat, err := os.Stat(path)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not stat path"))
		return
	}

	if stat.Mode().IsDir() {
		l.Trace("Filetype: Directory")
		pagesHandlerDirectory(wr, re, ps)
	}

	if stat.Mode().IsRegular() {
		l.Trace("Filetype: File")
		pagesHandlerFile(wr, re, ps)
	}

	if !stat.Mode().IsDir() && !stat.Mode().IsRegular() {
		l.Error("Filetype is not a directory and not a regular file. Something is strange.")
	}

	l.Debug("Sent ", path, " (", time.Since(timestart), ")")
}

func pagesHandlerDirectory(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandlerDirectory")

	urlpath := "./" + re.URL.Path
	files, err := ioutil.ReadDir(urlpath)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not read from directory"))
		return
	}

	fmt.Fprintf(wr, `<!DOCTYPE html>

  <meta charset="utf-8">
  <title>title</title>

  `)
	for _, file := range files {
		url, err := url.Parse(path.Clean(re.URL.Path + "/" + file.Name()))
		if err != nil {
			l.Error(errgo.Notef(err, "can not escape url"))
		}

		fmt.Fprintf(wr, "%s", url.String(), file.Name())
		fmt.Fprint(wr, "
\n")
	}
	fmt.Fprintf(wr, `
  `)
}

func pagesHandlerFile(wr http.ResponseWriter, re *http.Request, ps httprouter.Params) {
	l := logger.New(Name, "pagesHandlerDirectory")

	path := "./" + re.URL.Path
	file, err := os.Open(path)
	if err != nil {
		printerr(l, wr, errgo.Notef(err, "can not open file for reading"))
		return
	}
	defer file.Close()

	l.Trace("Filepath Extention: ", filepath.Ext(path))
	switch filepath.Ext(path) {
	case ".asciidoc":
		err = asciiDoctor(file, wr)
		if err != nil {
			printerr(l, wr, errgo.Notef(err, "can not format file with asciidoctor"))
			return
		}

	default:
		_, err = io.Copy(wr, file)
		if err != nil {
			printerr(l, wr, errgo.Notef(err, "can not copy file to response writer"))
			return
		}
	}
}

func printerr(l logger.Logger, wr http.ResponseWriter, err error) {
	l.Error(errgo.Details(err))
	fmt.Fprintf(wr, errgo.Details(err))

	return
}

func asciiDoctor(reader io.Reader, writer io.Writer) error {
	stderr := new(bytes.Buffer)

	command := exec.Command("asciidoctor", "-")
	command.Stdin = reader
	command.Stdout = writer
	command.Stderr = stderr

	err := command.Run()
	if err != nil {
		return errgo.Notef(errgo.Notef(err, "can not run asciidoctor"),
			stderr.String())
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	//"gopkg.in/resty.v0"
	//    "github.com/aerth/anaconda"
)
var fast bool

func init() {
fast = false
}
func main() {

	log.Println("go-quitter v0.0.1")
	log.Println("Copyright 2016 aerth@sdf.org")

	/* OAuth coming soon.

		if os.Getenv("GNUSOCIALKEY") == "" {
				fmt.Println("Set environmental variable GNUSOCIALKEY before running go-quitter.")
				fmt.Println("GNUSOCIALKEY before running go-quitter.")
				os.Exit(1)
			}
		if os.Getenv("GNUSOCIALSECRET") == "" {
				fmt.Println("Set environmental variable GNUSOCIALSECRET before running go-quitter.")
				os.Exit(1)
		}

		if os.Getenv("GNUSOCIALACCESSTOKEN") == "" {
		 fmt.Println("Set environmental variable GNUSOCIALACCESSTOKEN before running go-quitter.")
		 os.Exit(1)
		}
		if os.Getenv("GNUSOCIALTOKENSECRET") == "" {
		 fmt.Println("Set environmental variable GNUSOCIALTOKENSECRET before running go-quitter.")
		 os.Exit(1)
	 }
	*/

	if len(os.Args) < 2 {
		log.Fatalln("Usage:\n\n\tgo-quitter read\t\t\tReads 20 new posts\n\tgo-quitter read fast\t\tReads 20 new posts (no delay)\n\nYou may set your GNUSOCIALNODE environmental variable to change nodes.\nFor example: `export GNUSOCIALNODE=gs.sdf.org` in your ~/.shrc or ~/.profile\n")
	}

	if os.Args[1] == "read" && len(os.Args) == 2 {
		readNew(false)
		os.Exit(0)
	}
		if os.Args[1] == "read" && os.Args[2] == "fast" {
			readNew(true)
			os.Exit(0)
		}

}
func readNew(fast bool) {

	type User struct {
		Name string `json:"name"`
	}
	type Tweet struct {
		Id                   int64  `json:"id"`
		IdStr                string `json:"id_str"`
		InReplyToScreenName  string `json:"in_reply_to_screen_name"`
		InReplyToStatusID    int64  `json:"in_reply_to_status_id"`
		InReplyToStatusIdStr string `json:"in_reply_to_status_id_str"`
		InReplyToUserID      int64  `json:"in_reply_to_user_id"`
		InReplyToUserIdStr   string `json:"in_reply_to_user_id_str"`
		Lang                 string `json:"lang"`
		Place                string `json:"place"`
		PossiblySensitive    bool   `json:"possibly_sensitive"`
		RetweetCount         int    `json:"retweet_count"`
		Retweeted            bool   `json:"retweeted"`
		RetweetedStatus      *Tweet `json:"retweeted_status"`
		Source               string `json:"source"`

		Text                string   `json:"text"`
		Truncated           bool     `json:"truncated"`
		User                User     `json:"user"`
		WithheldCopyright   bool     `json:"withheld_copyright"`
		WithheldInCountries []string `json:"withheld_in_countries"`
		WithheldScope       string   `json:"withheld_scope"`
	}

	var gnusocialnode string
	if os.Getenv("GNUSOCIALNODE") == "" {
		gnusocialnode = "gs.sdf.org"
	} else {
		gnusocialnode = os.Getenv("GNUSOCIALNODE")
	}

	res, err := http.Get("https://" + gnusocialnode + "/api/statuses/public_timeline.json")
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	defer res.Body.Close()
	var tweets []*Tweet
	err = json.Unmarshal(body, &tweets)

	if err != nil {
		fmt.Println("error:", err)
	}

	for i := range tweets {
		fmt.Printf("[" + tweets[i].User.Name + "] " + tweets[i].Text + "\n\n")
		if fast != true { time.Sleep(2000 * time.Millisecond) }
	}

}
<commit_msg>Add node name to output<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"time"

	//"gopkg.in/resty.v0"
	//    "github.com/aerth/anaconda"
)
var fast bool

func init() {
fast = false
}
func main() {

	log.Println("go-quitter v0.0.1")
	log.Println("Copyright 2016 aerth@sdf.org")

	/* OAuth coming soon.

		if os.Getenv("GNUSOCIALKEY") == "" {
				fmt.Println("Set environmental variable GNUSOCIALKEY before running go-quitter.")
				fmt.Println("GNUSOCIALKEY before running go-quitter.")
				os.Exit(1)
			}
		if os.Getenv("GNUSOCIALSECRET") == "" {
				fmt.Println("Set environmental variable GNUSOCIALSECRET before running go-quitter.")
				os.Exit(1)
		}

		if os.Getenv("GNUSOCIALACCESSTOKEN") == "" {
		 fmt.Println("Set environmental variable GNUSOCIALACCESSTOKEN before running go-quitter.")
		 os.Exit(1)
		}
		if os.Getenv("GNUSOCIALTOKENSECRET") == "" {
		 fmt.Println("Set environmental variable GNUSOCIALTOKENSECRET before running go-quitter.")
		 os.Exit(1)
	 }
	*/

	if len(os.Args) < 2 {
		log.Fatalln("Usage:\n\n\tgo-quitter read\t\t\tReads 20 new posts\n\tgo-quitter read fast\t\tReads 20 new posts (no delay)\n\nYou may set your GNUSOCIALNODE environmental variable to change nodes.\nFor example: `export GNUSOCIALNODE=gs.sdf.org` in your ~/.shrc or ~/.profile\n")
	}

	if os.Args[1] == "read" && len(os.Args) == 2 {
		readNew(false)
		os.Exit(0)
	}
		if os.Args[1] == "read" && os.Args[2] == "fast" {
			readNew(true)
			os.Exit(0)
		}

}
func readNew(fast bool) {

	type User struct {
		Name string `json:"name"`
	}
	type Tweet struct {
		Id                   int64  `json:"id"`
		IdStr                string `json:"id_str"`
		InReplyToScreenName  string `json:"in_reply_to_screen_name"`
		InReplyToStatusID    int64  `json:"in_reply_to_status_id"`
		InReplyToStatusIdStr string `json:"in_reply_to_status_id_str"`
		InReplyToUserID      int64  `json:"in_reply_to_user_id"`
		InReplyToUserIdStr   string `json:"in_reply_to_user_id_str"`
		Lang                 string `json:"lang"`
		Place                string `json:"place"`
		PossiblySensitive    bool   `json:"possibly_sensitive"`
		RetweetCount         int    `json:"retweet_count"`
		Retweeted            bool   `json:"retweeted"`
		RetweetedStatus      *Tweet `json:"retweeted_status"`
		Source               string `json:"source"`

		Text                string   `json:"text"`
		Truncated           bool     `json:"truncated"`
		User                User     `json:"user"`
		WithheldCopyright   bool     `json:"withheld_copyright"`
		WithheldInCountries []string `json:"withheld_in_countries"`
		WithheldScope       string   `json:"withheld_scope"`
	}

	var gnusocialnode string
	if os.Getenv("GNUSOCIALNODE") == "" {
		gnusocialnode = "gs.sdf.org"
	} else {
		gnusocialnode = os.Getenv("GNUSOCIALNODE")
	}
	log.Println("node: "+gnusocialnode)
	res, err := http.Get("https://" + gnusocialnode + "/api/statuses/public_timeline.json")
	if err != nil {
		log.Fatalln(err)
	}

	body, err := ioutil.ReadAll(res.Body)
	defer res.Body.Close()
	var tweets []*Tweet
	_ = json.Unmarshal(body, &tweets)

	for i := range tweets {
		fmt.Printf("[" + tweets[i].User.Name + "] " + tweets[i].Text + "\n\n")
		if fast != true { time.Sleep(2000 * time.Millisecond) }
	}

}
<|endoftext|>


<commit_before>// Package main generates web project.
package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/go-bootstrap/go-bootstrap/helpers"
)

func setupMySQLDatabase(fullpath string) {
	// go get github.com/mattes/migrate
	log.Print("Running go get github.com/mattes/migrate...")
	output, err := exec.Command("go", "get", "github.com/mattes/migrate").CombinedOutput()
	helpers.ExitOnError(err, string(output))

	// Bootstrap databases.
	cmd := exec.Command("bash", "scripts/db-bootstrap")
	cmd.Dir = fullpath
	output, _ = cmd.CombinedOutput()
	log.Print(string(output))
}

func setupPGDatabase(fullpath string) {
	// go get github.com/rnubel/pgmgr
	log.Print("Running go get github.com/rnubel/pgmgr...")
	output, err := exec.Command("go", "get", "github.com/rnubel/pgmgr").CombinedOutput()
	helpers.ExitOnError(err, string(output))

	// Bootstrap databases.
	cmd := exec.Command("bash", "scripts/db-bootstrap")
	cmd.Dir = fullpath
	output, _ = cmd.CombinedOutput()
	log.Print(string(output))
}

func main() {
	dirInput := flag.String("dir", "", "Project directory relative to $GOPATH/src/")
	gopathInput := flag.String("gopath", "", "Choose which $GOPATH to use")
	templateInput := flag.String("template", "postgresql", "Choose project template. Available options: postgresql, mysql and core")

	flag.Parse()

	if *dirInput == "" {
		log.Fatalln("dir option is missing.")
	}

	// There can be more than one path, separated by colon.
	gopaths := helpers.GoPaths()
	if len(gopaths) == 0 {
		log.Fatalln("GOPATH is not set.")
	}

	// By default, we choose the last GOPATH.
	gopath := gopaths[len(gopaths)-1]

	// But if user specified one, we choose that one.
	if *gopathInput != "" {
		abs, err := filepath.Abs(*gopathInput)
		if err == nil && helpers.IsValidGoPath(abs) {
			gopath = abs
		} else {
			log.Fatalln("Cannot find " + *gopathInput + " in $GOPATH")
		}
	}

	trimmedPath := strings.Trim(*dirInput, "/")
	fullpath := filepath.Join(gopath, "src", trimmedPath)
	dirChunks := strings.Split(trimmedPath, "/")

	if len(dirChunks) < 3 {
		log.Fatalln("Cannot extract repo name, repo user and project name, " +
			"-dir should have three parts, seperated by '/'.")
	}

	repoName := dirChunks[len(dirChunks)-3]
	repoUser := dirChunks[len(dirChunks)-2]
	projectName := dirChunks[len(dirChunks)-1]
	dbName := projectName
	testDbName := projectName + "-test"
	projectTemplateDir, err := helpers.GetProjectTemplateDir(*templateInput)
	helpers.ExitOnError(err, "")

	// 1. Create target directory
	log.Print("Creating " + fullpath + "...")
	err = os.MkdirAll(fullpath, 0755)
	helpers.ExitOnError(err, "")

	// 2. Copy everything under project template directory to target directory.
	log.Print("Copying project template directory to " + fullpath + "...")
	currDir, err := os.Getwd()
	helpers.ExitOnError(err, "Can't get current path!")

	err = os.Chdir(projectTemplateDir)
	helpers.ExitOnError(err, "")

	output, err := exec.Command("cp", "-rf", ".", fullpath).CombinedOutput()
	helpers.ExitOnError(err, string(output))

	err = os.Chdir(currDir)
	helpers.ExitOnError(err, "")

	// 3. Interpolate placeholder variables on the new project.
	log.Print("Replacing placeholder variables on " + repoUser + "/" + projectName + "...")

	replacers := make(map[string]string)
	replacers["$GO_BOOTSTRAP_REPO_NAME"] = repoName
	replacers["$GO_BOOTSTRAP_REPO_USER"] = repoUser
	replacers["$GO_BOOTSTRAP_PROJECT_NAME"] = projectName
	replacers["$GO_BOOTSTRAP_COOKIE_SECRET"] = helpers.RandString(16)
	replacers["$GO_BOOTSTRAP_CURRENT_USER"] = helpers.GetCurrentUser()
	replacers["$GO_BOOTSTRAP_PG_DSN"] = helpers.DefaultPGDSN(dbName)
	replacers["$GO_BOOTSTRAP_PG_TEST_DSN"] = helpers.DefaultPGDSN(testDbName)

	err = helpers.RecursiveSearchReplaceFiles(fullpath, replacers)
	helpers.ExitOnError(err, "")

	// 4. Setup and bootstrap databases.
	if *templateInput == "postgresql" {
		setupPGDatabase(fullpath)
	}
	if *templateInput == "mysql" {
		setupMySQLDatabase(fullpath)
	}

	// 5. Get all application dependencies for the first time.
	log.Print("Running go get ./...")
	cmd := exec.Command("go", "get", "./...")
	cmd.Dir = fullpath
	output, err = cmd.CombinedOutput()
	helpers.ExitOnError(err, string(output))

	repoIsGit := strings.HasPrefix(repoName, "git")
	repoIsHg := strings.HasPrefix(repoName, "bitbucket")

	// Generate Godeps directory.
	// Works only on git repo or bitbucket repo.
	if repoIsGit || repoIsHg {
		log.Print("Installing github.com/tools/godep...")
		output, err := exec.Command("go", "get", "github.com/tools/godep").CombinedOutput()
		helpers.ExitOnError(err, string(output))

		if repoIsGit {
			log.Print("Running git init...")
			cmd := exec.Command("git", "init")
			cmd.Dir = fullpath
			output, err = cmd.CombinedOutput()
			helpers.ExitOnError(err, string(output))
		}
		if repoIsHg {
			log.Print("Running hg init...")
			cmd := exec.Command("hg", "init")
			cmd.Dir = fullpath
			output, _ = cmd.CombinedOutput()
			log.Print(string(output))
		}

		// godep save ./...
		log.Print("Running godep save ./...")
		cmd = exec.Command("godep", "save", "./...")
		cmd.Dir = fullpath
		output, err = cmd.CombinedOutput()
		helpers.ExitOnError(err, string(output))

		// Run tests on newly generated app.
		log.Print("Running godep go test ./...")
		cmd = exec.Command("godep", "go", "test", "./...")
		cmd.Dir = fullpath
		output, _ = cmd.CombinedOutput()
		log.Print(string(output))

	} else {
		// Run tests on newly generated app.
		log.Print("Running go test ./...")
		cmd = exec.Command("go", "test", "./...")
		cmd.Dir = fullpath
		output, _ = cmd.CombinedOutput()
		log.Print(string(output))
	}
}
<commit_msg>Always update to the latest packages. See: https://github.com/go-bootstrap/go-bootstrap/issues/40<commit_after>// Package main generates web project.
package main

import (
	"flag"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/go-bootstrap/go-bootstrap/helpers"
)

func setupMySQLDatabase(fullpath string) {
	// go get github.com/mattes/migrate
	log.Print("Running go get -u github.com/mattes/migrate...")
	output, err := exec.Command("go", "get", "-u", "github.com/mattes/migrate").CombinedOutput()
	helpers.ExitOnError(err, string(output))

	// Bootstrap databases.
	cmd := exec.Command("bash", "scripts/db-bootstrap")
	cmd.Dir = fullpath
	output, _ = cmd.CombinedOutput()
	log.Print(string(output))
}

func setupPGDatabase(fullpath string) {
	// go get github.com/rnubel/pgmgr
	log.Print("Running go get -u github.com/rnubel/pgmgr...")
	output, err := exec.Command("go", "get", "-u", "github.com/rnubel/pgmgr").CombinedOutput()
	helpers.ExitOnError(err, string(output))

	// Bootstrap databases.
	cmd := exec.Command("bash", "scripts/db-bootstrap")
	cmd.Dir = fullpath
	output, _ = cmd.CombinedOutput()
	log.Print(string(output))
}

func main() {
	dirInput := flag.String("dir", "", "Project directory relative to $GOPATH/src/")
	gopathInput := flag.String("gopath", "", "Choose which $GOPATH to use")
	templateInput := flag.String("template", "postgresql", "Choose project template. Available options: postgresql, mysql and core")

	flag.Parse()

	if *dirInput == "" {
		log.Fatalln("dir option is missing.")
	}

	// There can be more than one path, separated by colon.
	gopaths := helpers.GoPaths()
	if len(gopaths) == 0 {
		log.Fatalln("GOPATH is not set.")
	}

	// By default, we choose the last GOPATH.
	gopath := gopaths[len(gopaths)-1]

	// But if user specified one, we choose that one.
	if *gopathInput != "" {
		abs, err := filepath.Abs(*gopathInput)
		if err == nil && helpers.IsValidGoPath(abs) {
			gopath = abs
		} else {
			log.Fatalln("Cannot find " + *gopathInput + " in $GOPATH")
		}
	}

	trimmedPath := strings.Trim(*dirInput, "/")
	fullpath := filepath.Join(gopath, "src", trimmedPath)
	dirChunks := strings.Split(trimmedPath, "/")

	if len(dirChunks) < 3 {
		log.Fatalln("Cannot extract repo name, repo user and project name, " +
			"-dir should have three parts, seperated by '/'.")
	}

	repoName := dirChunks[len(dirChunks)-3]
	repoUser := dirChunks[len(dirChunks)-2]
	projectName := dirChunks[len(dirChunks)-1]
	dbName := projectName
	testDbName := projectName + "-test"
	projectTemplateDir, err := helpers.GetProjectTemplateDir(*templateInput)
	helpers.ExitOnError(err, "")

	// 1. Create target directory
	log.Print("Creating " + fullpath + "...")
	err = os.MkdirAll(fullpath, 0755)
	helpers.ExitOnError(err, "")

	// 2. Copy everything under project template directory to target directory.
	log.Print("Copying project template directory to " + fullpath + "...")
	currDir, err := os.Getwd()
	helpers.ExitOnError(err, "Can't get current path!")

	err = os.Chdir(projectTemplateDir)
	helpers.ExitOnError(err, "")

	output, err := exec.Command("cp", "-rf", ".", fullpath).CombinedOutput()
	helpers.ExitOnError(err, string(output))

	err = os.Chdir(currDir)
	helpers.ExitOnError(err, "")

	// 3. Interpolate placeholder variables on the new project.
	log.Print("Replacing placeholder variables on " + repoUser + "/" + projectName + "...")

	replacers := make(map[string]string)
	replacers["$GO_BOOTSTRAP_REPO_NAME"] = repoName
	replacers["$GO_BOOTSTRAP_REPO_USER"] = repoUser
	replacers["$GO_BOOTSTRAP_PROJECT_NAME"] = projectName
	replacers["$GO_BOOTSTRAP_COOKIE_SECRET"] = helpers.RandString(16)
	replacers["$GO_BOOTSTRAP_CURRENT_USER"] = helpers.GetCurrentUser()
	replacers["$GO_BOOTSTRAP_PG_DSN"] = helpers.DefaultPGDSN(dbName)
	replacers["$GO_BOOTSTRAP_PG_TEST_DSN"] = helpers.DefaultPGDSN(testDbName)

	err = helpers.RecursiveSearchReplaceFiles(fullpath, replacers)
	helpers.ExitOnError(err, "")

	// 4. Setup and bootstrap databases.
	if *templateInput == "postgresql" {
		setupPGDatabase(fullpath)
	}
	if *templateInput == "mysql" {
		setupMySQLDatabase(fullpath)
	}

	// 5. Get all application dependencies for the first time.
	log.Print("Running go get -u ./...")
	cmd := exec.Command("go", "get", "-u", "./...")
	cmd.Dir = fullpath
	output, err = cmd.CombinedOutput()
	helpers.ExitOnError(err, string(output))

	repoIsGit := strings.HasPrefix(repoName, "git")
	repoIsHg := strings.HasPrefix(repoName, "bitbucket")

	// Generate Godeps directory.
	// Works only on git repo or bitbucket repo.
	if repoIsGit || repoIsHg {
		log.Print("Installing github.com/tools/godep...")
		output, err := exec.Command("go", "get", "-u", "github.com/tools/godep").CombinedOutput()
		helpers.ExitOnError(err, string(output))

		if repoIsGit {
			log.Print("Running git init...")
			cmd := exec.Command("git", "init")
			cmd.Dir = fullpath
			output, err = cmd.CombinedOutput()
			helpers.ExitOnError(err, string(output))
		}
		if repoIsHg {
			log.Print("Running hg init...")
			cmd := exec.Command("hg", "init")
			cmd.Dir = fullpath
			output, _ = cmd.CombinedOutput()
			log.Print(string(output))
		}

		// godep save ./...
		log.Print("Running godep save ./...")
		cmd = exec.Command("godep", "save", "./...")
		cmd.Dir = fullpath
		output, err = cmd.CombinedOutput()
		helpers.ExitOnError(err, string(output))

		// Run tests on newly generated app.
		log.Print("Running godep go test ./...")
		cmd = exec.Command("godep", "go", "test", "./...")
		cmd.Dir = fullpath
		output, _ = cmd.CombinedOutput()
		log.Print(string(output))

	} else {
		// Run tests on newly generated app.
		log.Print("Running go test ./...")
		cmd = exec.Command("go", "test", "./...")
		cmd.Dir = fullpath
		output, _ = cmd.CombinedOutput()
		log.Print(string(output))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	cli "github.com/codegangsta/cli"
	fs "github.com/kr/fs"
	gx "github.com/whyrusleeping/gx/gxutil"
)

func main() {
	app := cli.NewApp()
	app.Name = "gx-go-tool"
	app.Author = "whyrusleeping"
	app.Version = "0.2.0"

	var UpdateCommand = cli.Command{
		Name:      "update",
		Usage:     "update a packages imports to a new path",
		ArgsUsage: "[old import] [new import]",
		Action: func(c *cli.Context) {
			if len(c.Args()) < 2 {
				fmt.Println("must specify current and new import names")
				return
			}

			oldimp := c.Args()[0]
			newimp := c.Args()[1]

			curpath, err := os.Getwd()
			if err != nil {
				fmt.Println("error getting working dir: ", err)
				return
			}

			rw := func(in string) string {
				if in == oldimp {
					return newimp
				}
				return in
			}

			filter := func(in string) bool {
				return !strings.HasSuffix(in, ".go")
			}

			err = updateImports(curpath, rw, filter)
			if err != nil {
				fmt.Println(err)
				return
			}
		},
	}

	var ImportCommand = cli.Command{
		Name: "import",
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "rewrite",
				Usage: "rewrite import paths to use vendored packages",
			},
		},
		Action: func(c *cli.Context) {
			importer, err := NewImporter(c.Bool("rewrite"))
			if err != nil {
				fmt.Println(err)
				return
			}

			if !c.Args().Present() {
				fmt.Println("must specify a package name")
				return
			}

			pkg := c.Args().First()
			fmt.Printf("vendoring package %s\n", pkg)

			_, err = importer.GxPublishGoPackage(pkg)
			if err != nil {
				log.Println(err)
				return
			}
		},
	}

	app.Commands = []cli.Command{
		UpdateCommand,
		ImportCommand,
	}

	app.Run(os.Args)
}

func pathIsNotStdlib(path string) bool {
	first := strings.Split(path, "/")[0]

	if len(strings.Split(first, ".")) > 1 {
		return true
	}
	return false
}

type Importer struct {
	pkgs    map[string]*gx.Dependency
	gopath  string
	pm      *gx.PM
	rewrite bool
}

func NewImporter(rw bool) (*Importer, error) {
	gp, err := getGoPath()
	if err != nil {
		return nil, err
	}

	return &Importer{
		pkgs:    make(map[string]*gx.Dependency),
		gopath:  gp,
		pm:      gx.NewPM(),
		rewrite: rw,
	}, nil
}

func getGoPath() (string, error) {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return "", errors.New("gopath not set")
	}
	return gopath, nil
}

func (i *Importer) GxPublishGoPackage(imppath string) (*gx.Dependency, error) {
	if d, ok := i.pkgs[imppath]; ok {
		return d, nil
	}

	// make sure its local
	err := GoGet(imppath)
	if err != nil {
		return nil, err
	}

	pkgpath := path.Join(i.gopath, "src", imppath)
	pkgFilePath := path.Join(pkgpath, gx.PkgFileName)
	pkg, err := gx.LoadPackageFile(pkgFilePath)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}

		// init as gx package
		parts := strings.Split(imppath, "/")
		pkgname := parts[len(parts)-1]
		err = gx.InitPkg(pkgpath, pkgname, "go")
		if err != nil {
			return nil, err
		}

		pkg, err = gx.LoadPackageFile(pkgFilePath)
		if err != nil {
			return nil, err
		}
	}

	// recurse!
	gopkg, err := build.Import(imppath, "", 0)
	if err != nil {
		return nil, err
	}

	var depsToVendor []string

	for _, child := range gopkg.Imports {
		if pathIsNotStdlib(child) {
			depsToVendor = append(depsToVendor, child)
		}
	}

	for n, child := range depsToVendor {
		fmt.Printf("- processing dep %s for %s [%d / %d]\n", child, imppath, n+1, len(depsToVendor))
		childdep, err := i.GxPublishGoPackage(child)
		if err != nil {
			return nil, err
		}

		pkg.Dependencies = append(pkg.Dependencies, childdep)
	}

	err = gx.SavePackageFile(pkg, pkgFilePath)
	if err != nil {
		return nil, err
	}

	if i.rewrite {
		fullpkgpath, err := filepath.Abs(pkgpath)
		if err != nil {
			return nil, err
		}

		err = i.rewriteImports(fullpkgpath)
		if err != nil {
			return nil, err
		}
	}

	hash, err := i.pm.PublishPackage(pkgpath, pkg)
	if err != nil {
		return nil, err
	}

	fmt.Printf("published %s as %s\n", imppath, hash)

	dep := &gx.Dependency{
		Hash: hash,
		Name: pkg.Name,
	}
	i.pkgs[imppath] = dep
	return dep, nil
}

func (i *Importer) rewriteImports(pkgpath string) error {

	filter := func(p string) bool {
		return strings.HasPrefix(p, "vendor") ||
			strings.HasPrefix(p, ".git") ||
			!strings.HasSuffix(p, ".go")
	}

	rw := func(in string) string {
		dep, ok := i.pkgs[in]
		if !ok {
			return in
		}

		return dep.Hash + "/" + dep.Name
	}

	return updateImports(pkgpath, rw, filter)
}

func updateImports(path string, rw func(string) string, filter func(string) bool) error {
	w := fs.Walk(path)
	for w.Step() {
		rel := w.Path()[len(path):]
		if len(rel) == 0 {
			continue
		}
		rel = rel[1:]

		if filter(rel) {
			w.SkipDir()
			continue
		}

		err := rewriteImportsInFile(w.Path(), rw)
		if err != nil {
			fmt.Println("rewrite error: ", err)
			return err
		}
	}
	return nil
}

// inspired by godeps rewrite, rewrites import paths with gx vendored names
func rewriteImportsInFile(fi string, rw func(string) string) error {
	fmt.Println("REWRITE FI: ", fi)
	cfg := &printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, fi, nil, parser.ParseComments)
	if err != nil {
		return err
	}

	var changed bool
	for _, imp := range file.Imports {
		p, err := strconv.Unquote(imp.Path.Value)
		if err != nil {
			return err
		}

		np := rw(p)

		if np != p {
			changed = true
			imp.Path.Value = strconv.Quote(np)
		}
	}

	if !changed {
		return nil
	}

	var buffer bytes.Buffer
	if err = cfg.Fprint(&buffer, fset, file); err != nil {
		return err
	}
	fset = token.NewFileSet()
	file, err = parser.ParseFile(fset, fi, &buffer, parser.ParseComments)
	ast.SortImports(fset, file)
	wpath := fi + ".temp"
	w, err := os.Create(wpath)
	if err != nil {
		return err
	}
	if err = cfg.Fprint(w, fset, file); err != nil {
		return err
	}
	if err = w.Close(); err != nil {
		return err
	}

	return os.Rename(wpath, fi)
}

// TODO: take an option to grab packages from local GOPATH
func GoGet(path string) error {
	return exec.Command("go", "get", path).Run()
}
<commit_msg>update docs<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strconv"
	"strings"

	cli "github.com/codegangsta/cli"
	fs "github.com/kr/fs"
	gx "github.com/whyrusleeping/gx/gxutil"
)

func main() {
	app := cli.NewApp()
	app.Name = "gx-go-tool"
	app.Author = "whyrusleeping"
	app.Version = "0.2.0"

	var UpdateCommand = cli.Command{
		Name:      "update",
		Usage:     "update a packages imports to a new path",
		ArgsUsage: "[old import] [new import]",
		Action: func(c *cli.Context) {
			if len(c.Args()) < 2 {
				fmt.Println("must specify current and new import names")
				return
			}

			oldimp := c.Args()[0]
			newimp := c.Args()[1]

			curpath, err := os.Getwd()
			if err != nil {
				fmt.Println("error getting working dir: ", err)
				return
			}

			rw := func(in string) string {
				if in == oldimp {
					return newimp
				}
				return in
			}

			filter := func(in string) bool {
				return !strings.HasSuffix(in, ".go")
			}

			err = updateImports(curpath, rw, filter)
			if err != nil {
				fmt.Println(err)
				return
			}
		},
	}

	var ImportCommand = cli.Command{
		Name:  "import",
		Usage: "import a go package and all its depencies into gx",
		Flags: []cli.Flag{
			cli.BoolFlag{
				Name:  "rewrite",
				Usage: "rewrite import paths to use vendored packages",
			},
		},
		Action: func(c *cli.Context) {
			importer, err := NewImporter(c.Bool("rewrite"))
			if err != nil {
				fmt.Println(err)
				return
			}

			if !c.Args().Present() {
				fmt.Println("must specify a package name")
				return
			}

			pkg := c.Args().First()
			fmt.Printf("vendoring package %s\n", pkg)

			_, err = importer.GxPublishGoPackage(pkg)
			if err != nil {
				log.Println(err)
				return
			}
		},
	}

	app.Commands = []cli.Command{
		UpdateCommand,
		ImportCommand,
	}

	app.Run(os.Args)
}

func pathIsNotStdlib(path string) bool {
	first := strings.Split(path, "/")[0]

	if len(strings.Split(first, ".")) > 1 {
		return true
	}
	return false
}

type Importer struct {
	pkgs    map[string]*gx.Dependency
	gopath  string
	pm      *gx.PM
	rewrite bool
}

func NewImporter(rw bool) (*Importer, error) {
	gp, err := getGoPath()
	if err != nil {
		return nil, err
	}

	return &Importer{
		pkgs:    make(map[string]*gx.Dependency),
		gopath:  gp,
		pm:      gx.NewPM(),
		rewrite: rw,
	}, nil
}

func getGoPath() (string, error) {
	gopath := os.Getenv("GOPATH")
	if gopath == "" {
		return "", errors.New("gopath not set")
	}
	return gopath, nil
}

func (i *Importer) GxPublishGoPackage(imppath string) (*gx.Dependency, error) {
	if d, ok := i.pkgs[imppath]; ok {
		return d, nil
	}

	// make sure its local
	err := GoGet(imppath)
	if err != nil {
		return nil, err
	}

	pkgpath := path.Join(i.gopath, "src", imppath)
	pkgFilePath := path.Join(pkgpath, gx.PkgFileName)
	pkg, err := gx.LoadPackageFile(pkgFilePath)
	if err != nil {
		if !os.IsNotExist(err) {
			return nil, err
		}

		// init as gx package
		parts := strings.Split(imppath, "/")
		pkgname := parts[len(parts)-1]
		err = gx.InitPkg(pkgpath, pkgname, "go")
		if err != nil {
			return nil, err
		}

		pkg, err = gx.LoadPackageFile(pkgFilePath)
		if err != nil {
			return nil, err
		}
	}

	// recurse!
	gopkg, err := build.Import(imppath, "", 0)
	if err != nil {
		return nil, err
	}

	var depsToVendor []string

	for _, child := range gopkg.Imports {
		if pathIsNotStdlib(child) {
			depsToVendor = append(depsToVendor, child)
		}
	}

	for n, child := range depsToVendor {
		fmt.Printf("- processing dep %s for %s [%d / %d]\n", child, imppath, n+1, len(depsToVendor))
		childdep, err := i.GxPublishGoPackage(child)
		if err != nil {
			return nil, err
		}

		pkg.Dependencies = append(pkg.Dependencies, childdep)
	}

	err = gx.SavePackageFile(pkg, pkgFilePath)
	if err != nil {
		return nil, err
	}

	if i.rewrite {
		fullpkgpath, err := filepath.Abs(pkgpath)
		if err != nil {
			return nil, err
		}

		err = i.rewriteImports(fullpkgpath)
		if err != nil {
			return nil, err
		}
	}

	hash, err := i.pm.PublishPackage(pkgpath, pkg)
	if err != nil {
		return nil, err
	}

	fmt.Printf("published %s as %s\n", imppath, hash)

	dep := &gx.Dependency{
		Hash: hash,
		Name: pkg.Name,
	}
	i.pkgs[imppath] = dep
	return dep, nil
}

func (i *Importer) rewriteImports(pkgpath string) error {

	filter := func(p string) bool {
		return strings.HasPrefix(p, "vendor") ||
			strings.HasPrefix(p, ".git") ||
			!strings.HasSuffix(p, ".go")
	}

	rw := func(in string) string {
		dep, ok := i.pkgs[in]
		if !ok {
			return in
		}

		return dep.Hash + "/" + dep.Name
	}

	return updateImports(pkgpath, rw, filter)
}

func updateImports(path string, rw func(string) string, filter func(string) bool) error {
	w := fs.Walk(path)
	for w.Step() {
		rel := w.Path()[len(path):]
		if len(rel) == 0 {
			continue
		}
		rel = rel[1:]

		if filter(rel) {
			w.SkipDir()
			continue
		}

		err := rewriteImportsInFile(w.Path(), rw)
		if err != nil {
			fmt.Println("rewrite error: ", err)
			return err
		}
	}
	return nil
}

// inspired by godeps rewrite, rewrites import paths with gx vendored names
func rewriteImportsInFile(fi string, rw func(string) string) error {
	fmt.Println("REWRITE FI: ", fi)
	cfg := &printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
	fset := token.NewFileSet()
	file, err := parser.ParseFile(fset, fi, nil, parser.ParseComments)
	if err != nil {
		return err
	}

	var changed bool
	for _, imp := range file.Imports {
		p, err := strconv.Unquote(imp.Path.Value)
		if err != nil {
			return err
		}

		np := rw(p)

		if np != p {
			changed = true
			imp.Path.Value = strconv.Quote(np)
		}
	}

	if !changed {
		return nil
	}

	var buffer bytes.Buffer
	if err = cfg.Fprint(&buffer, fset, file); err != nil {
		return err
	}
	fset = token.NewFileSet()
	file, err = parser.ParseFile(fset, fi, &buffer, parser.ParseComments)
	ast.SortImports(fset, file)
	wpath := fi + ".temp"
	w, err := os.Create(wpath)
	if err != nil {
		return err
	}
	if err = cfg.Fprint(w, fset, file); err != nil {
		return err
	}
	if err = w.Close(); err != nil {
		return err
	}

	return os.Rename(wpath, fi)
}

// TODO: take an option to grab packages from local GOPATH
func GoGet(path string) error {
	return exec.Command("go", "get", path).Run()
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
	"html"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

var dbHandle *sql.DB
var templates = template.Must(template.ParseFiles("index.html"))
var debugLogger *log.Logger

type Record struct {
	Category         string    `json: "category"`
	Records          []Records `json: "records"`
	QueryRecordCount int       `json: "queryRecordCount"`
	TotalRecordCount int       `json: "totalRecordCount"`
}

type Records struct {
	Id     string `json: "id"`
	Name   string `json: "name"`
	Status int    `json: "status"`
	Hash   string `json: "hash"`
	Magnet string `json: "magnet"`
}

func getDBHandle() *sql.DB {
	db, err := sql.Open("sqlite3", "./nyaa.db")
	checkErr(err)
	return db
}

func checkErr(err error) {
	if err != nil {
		debugLogger.Println("   " + err.Error())
		os.Exit(1)
	}
}

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

	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
func singleapiHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	id := vars["id"]
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents where torrent_id = ? ORDER BY torrent_id DESC", html.EscapeString(id))
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 1
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	param1 := r.URL.Query().Get("q")
	cat := r.URL.Query().Get("c")
	param2 := strings.Split(cat, "_")[0]
	param3 := strings.Split(cat, "_")[1]
	b := Record{Category: cat, Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents "+
		"where torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ? "+
		"ORDER BY torrent_id DESC LIMIT 50 offset ?",
		"%"+html.EscapeString(param1)+"%", html.EscapeString(param2)+"%", html.EscapeString(param3)+"%", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	rows.Close()

	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Category: "_", Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + "&tr=udp://tracker.openbittorrent.com"
		res := Records{
			Id:     id,
			Name:   name,
			Status: status,
			Hash:   hash,
			Magnet: magnet}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

func main() {

	dbHandle = getDBHandle()
	router := mux.NewRouter()

	// Routes,
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/page/{page}", rootHandler)
	router.HandleFunc("/search", searchHandler)
	router.HandleFunc("/search/{page}", searchHandler)
	router.HandleFunc("/api/{page}", apiHandler).Methods("GET")
	router.HandleFunc("/api/torrent/{id}", singleapiHandler).Methods("GET")
	// Set up server,
	srv := &http.Server{
		Handler:      router,
		Addr:         "localhost:9999",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	err := srv.ListenAndServe()
	checkErr(err)
}
<commit_msg>status merged<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
	"html"
	"html/template"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

var dbHandle *sql.DB
var templates = template.Must(template.ParseFiles("index.html"))
var debugLogger *log.Logger
var trackers = "&tr=udp://zer0day.to:1337/announce&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://explodie.org:6969&tr=udp://tracker.opentrackr.org:1337&tr=udp://tracker.coppersurfer.tk:6969"

type Record struct {
	Category         string    `json: "category"`
	Records          []Records `json: "records"`
	QueryRecordCount int       `json: "queryRecordCount"`
	TotalRecordCount int       `json: "totalRecordCount"`
}

type Records struct {
	Id     string       `json: "id"`
	Name   string       `json: "name"`
	Status int          `json: "status"`
	Hash   string       `json: "hash"`
	Magnet template.URL `json: "magnet"`
}

func getDBHandle() *sql.DB {
	db, err := sql.Open("sqlite3", "./nyaa.db")
	checkErr(err)
	return db
}

func checkErr(err error) {
	if err != nil {
		debugLogger.Println("   " + err.Error())
	}
}

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

	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers
		res := Records{
			Id:     id,
			Name:   name,
      Status: status,
			Hash:   hash,
			Magnet: safe(magnet)}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}
func singleapiHandler(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	id := vars["id"]
	b := Record{Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents where torrent_id = ? ORDER BY torrent_id DESC", html.EscapeString(id))
	for rows.Next() {
		var id, name, hash, magnet string
		var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers
		res := Records{
			Id:     id,
			Name:   name,
      Status: status,
			Hash:   hash,
			Magnet: safe(magnet)}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 1
	b.TotalRecordCount = 1473098
	rows.Close()
	w.Header().Set("Content-Type", "application/json")
	err = json.NewEncoder(w).Encode(b)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	param1 := r.URL.Query().Get("q")
	cat := r.URL.Query().Get("c")
	param2 := strings.Split(cat, "_")[0]
	param3 := strings.Split(cat, "_")[1]
	b := Record{Category: cat, Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents "+
		"where torrent_name LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ? "+
		"ORDER BY torrent_id DESC LIMIT 50 offset ?",
		"%"+html.EscapeString(param1)+"%", html.EscapeString(param2)+"%", html.EscapeString(param3)+"%", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
    var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers
		res := Records{
			Id:     id,
			Name:   name,
      Status: status,
			Hash:   hash,
			Magnet: safe(magnet)}

		b.Records = append(b.Records, res)

	}
	rows.Close()

	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}
func safe(s string) template.URL {
	return template.URL(s)
}

func rootHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	page := vars["page"]
	pagenum, _ := strconv.Atoi(html.EscapeString(page))
	b := Record{Category: "_", Records: []Records{}}
	rows, err := dbHandle.Query("select torrent_id, torrent_name, status_id, torrent_hash from torrents ORDER BY torrent_id DESC LIMIT 50 offset ?", 50*pagenum-1)
	for rows.Next() {
		var id, name, hash, magnet string
    var status int
		rows.Scan(&id, &name, &status, &hash)
		magnet = "magnet:?xt=urn:btih:" + hash + "&dn=" + url.QueryEscape(name) + trackers
		res := Records{
			Id:     id,
			Name:   name,
      Status: status,
			Hash:   hash,
			Magnet: safe(magnet)}

		b.Records = append(b.Records, res)

	}
	b.QueryRecordCount = 50
	b.TotalRecordCount = 1473098
	rows.Close()
	err = templates.ExecuteTemplate(w, "index.html", &b)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}

}

func main() {

	dbHandle = getDBHandle()
	router := mux.NewRouter()

	// Routes,
	router.HandleFunc("/", rootHandler)
	router.HandleFunc("/page/{page}", rootHandler)
	router.HandleFunc("/search", searchHandler)
	router.HandleFunc("/search/{page}", searchHandler)
	router.HandleFunc("/api/{page}", apiHandler).Methods("GET")
	router.HandleFunc("/api/torrent/{id}", singleapiHandler).Methods("GET")
	// Set up server,
	srv := &http.Server{
		Handler:      router,
		Addr:         "localhost:9999",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	err := srv.ListenAndServe()
	checkErr(err)
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB
var es eventsource.EventSource

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	row.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	row.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM logs")
	data := []LogData{}
	for rows.Next() {
		log := LogData{}
		rows.Scan(&log.Id, &log.Log)
		data = append(data, log)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func Test(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	buf,_ := json.Marshal("test")
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"1; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	r.ParseForm()
	w.Write([]byte(r.Form.Encode()))
	/*mode := r.PostFormValue("mode")
	hellingsgraad := r.PostFormValue("hellingsgraad")
	if hellingsgraad == "" {
		hellingsgraad = "0"
	}
	snelheid := r.PostFormValue("snelheid")
	if snelheid == "" {
		snelheid = "0"
	}
	batterij := r.PostFormValue("batterij")
	if batterij == "" {
		batterij = "0"
	}
	balloncount := r.PostFormValue("ballonCount")
	if balloncount == "" {
		balloncount = "0"
	}
	_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		mode, hellingsgraad, snelheid, batterij, balloncount)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
	w.Write([]byte("successful"))*/
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO logs (log) VALUES ($1)",
		r.FormValue("log"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	es.SendEventMessage(r.FormValue("log"), "log", "")
	w.WriteHeader(201)
	w.Write([]byte(r.FormValue("log")))
}

func Head(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	SetHeaders(&w)
	w.WriteHeader(204)
}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()

	es = eventsource.New(
		&eventsource.Settings{
			Timeout: 5 * time.Second,
			CloseOnTimeout: false,
			IdleTimeout: 30 * time.Minute,
		},
		func(req *http.Request) [][]byte {
			return [][]byte{
				[]byte("X-Accel-Buffering: no"),
				[]byte("Access-Control-Allow-Origin: *"),
			}
		},
	)
	defer es.Close()

	router := httprouter.New()
	router.HEAD("/*path", Head)
	router.GET("/test", Test)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/log", GetLogs)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	router.POST("/log", PostLog)

	http.Handle("/subscribe", es)
	http.Handle("/", router)

	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}<commit_msg>postformvalue<commit_after>package main

import (
	"time"
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"net/http"
	"log"
	"os"
	//"io"
	"fmt"
	"database/sql"
	_ "github.com/lib/pq"
	"gopkg.in/antage/eventsource.v1"
)

var conn *sql.DB
var es eventsource.EventSource

func SetHeaders(w *http.ResponseWriter) {
	(*w).Header().Set("Access-Control-Allow-Origin", "*")
	(*w).Header().Set("Content-Type", "application/json")
}

func GetBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM blog")
	data := []BlogPost{}
	for rows.Next() {
		post := BlogPost{}
		rows.Scan(&post.Id, &post.Titel, &post.Text, &post.Auteur, &post.Img_url, &post.Ctime, &post.Image)
		data = append(data, post)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM blog WHERE id = $1 LIMIT 1", ps.ByName("id"))
	data := BlogPost{}
	row.Scan(&data.Id, &data.Titel, &data.Text, &data.Auteur, &data.Img_url, &data.Ctime, &data.Image)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata ORDER BY tijd DESC LIMIT 1")
	spin := SpinData{}
	rows.Next()
	rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
	buf,_ := json.Marshal(spin)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT batterij FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data int
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT mode FROM spindata ORDER BY tijd DESC LIMIT 1")
	var data string
	row.Scan(&data)
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM spindata")
	data := []SpinData{}
	for rows.Next() {
		spin := SpinData{}
		rows.Scan(&spin.Id, &spin.Tijd, &spin.Mode, &spin.Hellingsgraad, &spin.Snelheid, &spin.Batterij, &spin.BallonCount)
		data = append(data, spin)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinBatterij(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT batterij FROM spindata")
	data := make([]int, 0)
	var scanInt int
	for rows.Next() {
		rows.Scan(&scanInt)
		data = append(data, scanInt)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedSpinMode(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT mode FROM spindata")
	data := make([]string, 0)
	var scanStr string
	for rows.Next() {
		rows.Scan(&scanStr)
		data = append(data, scanStr)
	}
	buf,_ := json.Marshal(data)
	fmt.Printf(string(buf))
	SetHeaders(&w)
	w.Write(buf)
}

func GetLatestServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	row := conn.QueryRow("SELECT * FROM servodata ORDER BY tijd DESC LIMIT 1")
	servo := ServoData{}
	row.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
	buf,_ := json.Marshal(servo)
	SetHeaders(&w)
	w.Write(buf)
}

func GetArchivedServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM servodata")
	data := []ServoData{}
	for rows.Next() {
		servo := ServoData{}
		rows.Scan(&servo.Id, &servo.ServoId, &servo.Tijd, &servo.Voltage, &servo.Positie, &servo.Load, &servo.Temperatuur)
		data = append(data, servo)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func GetLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	rows,_ := conn.Query("SELECT * FROM logs")
	data := []LogData{}
	for rows.Next() {
		log := LogData{}
		rows.Scan(&log.Id, &log.Log)
		data = append(data, log)
	}
	buf,_ := json.Marshal(data)
	SetHeaders(&w)
	w.Write(buf)
}

func Test(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	buf,_ := json.Marshal("test")
	SetHeaders(&w)
	w.Write(buf)
}

func PostBlog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	//r.ParseMultipartForm(32 << 20)
	/*file, handler, err := r.FormFile("uploadfile")
	defer file.Close()
	if err == nil {
		fmt.Fprintf(w, "%v", handler.Header)
		f, err := os.OpenFile("./img/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
		if err != nil {
			w.WriteHeader(500)
			return
		}
		defer f.Close()
		io.Copy(f, file)
	}

	err = nil*/

	//_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime, image) VALUES ($1, $2, $3, $4, $5)", r.FormValue("titel"), r.FormValue("text"), r.FormValue("auteur"), time.Now(), "http://idp-api.herokuapp.com/img/"+handler.Filename)
	_,err := conn.Query("INSERT INTO blog (titel, text, auteur, ctime) VALUES ($1, $2, $3, $4)", r.FormValue("onderwerp"), r.FormValue("bericht"), r.FormValue("naam"), time.Now())
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(201)
	w.Write([]byte("<meta http-equiv=\"refresh\" content=\"1; url=http://knightspider.herokuapp.com/#/blog\">successful"))
}

func PostSpinData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	r.ParseForm()
	mode := r.PostFormValue("mode")
	hellingsgraad := r.PostFormValue("hellingsgraad")
	snelheid := r.PostFormValue("snelheid")
	batterij := r.PostFormValue("batterij")
	balloncount := r.PostFormValue("ballonCount")
	/*_,err := conn.Query("INSERT INTO spindata (tijd, mode, hellingsgraad, snelheid, batterij, balloncount) VALUES ($1, $2, $3, $4, $5, $6)", time.Now(),
		mode, hellingsgraad, snelheid, batterij, balloncount)
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
		w.Write([]byte(err.Error()))
		return
	}*/
	w.WriteHeader(201)
	w.Write([]byte(fmt.Sprintf("mode = %s, hellingsgraad = %s, batterij = %s, balloncount = %s", mode, hellingsgraad, batterij, balloncount)))
	//w.Write([]byte("successful"))
}

func PostServoData(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO servodata (servo_id, tijd, voltage, positie, load, temperatuur) VALUES ($1, $2, $3, $4, $5, $6)",
		r.FormValue("servo_id"), time.Now(), r.FormValue("voltage"), r.FormValue("positie"), r.FormValue("load"), r.FormValue("Temperatuur"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	w.WriteHeader(201)
	w.Write([]byte("successful"))
}

func PostLog(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	_,err := conn.Query("INSERT INTO logs (log) VALUES ($1)",
		r.FormValue("log"))
	if err != nil {
		w.WriteHeader(500)
		w.Write([]byte(err.Error()))
		return
	}
	es.SendEventMessage(r.FormValue("log"), "log", "")
	w.WriteHeader(201)
	w.Write([]byte(r.FormValue("log")))
}

func Head(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	SetHeaders(&w)
	w.WriteHeader(204)
}

func main() {
	conn,_ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
	defer conn.Close()

	es = eventsource.New(
		&eventsource.Settings{
			Timeout: 5 * time.Second,
			CloseOnTimeout: false,
			IdleTimeout: 30 * time.Minute,
		},
		func(req *http.Request) [][]byte {
			return [][]byte{
				[]byte("X-Accel-Buffering: no"),
				[]byte("Access-Control-Allow-Origin: *"),
			}
		},
	)
	defer es.Close()

	router := httprouter.New()
	router.HEAD("/*path", Head)
	router.GET("/test", Test)
	router.GET("/blog", GetBlog)
	router.GET("/blog/:id", GetPost)
	router.GET("/spin/latest", GetLatestSpinData)
	router.GET("/spin/latest/batterij", GetLatestSpinBatterij)
	router.GET("/spin/latest/mode", GetLatestSpinMode)
	router.GET("/spin/archive", GetArchivedSpinData)
	router.GET("/spin/archive/batterij", GetArchivedSpinBatterij)
	router.GET("/spin/archive/mode", GetArchivedSpinMode)
	router.GET("/servo/latest", GetLatestServoData)
	router.GET("/servo/archive", GetArchivedServoData)
	router.GET("/log", GetLogs)
	router.POST("/blog", PostBlog)
	router.POST("/spin", PostSpinData)
	router.POST("/servo", PostServoData)
	router.POST("/log", PostLog)

	http.Handle("/subscribe", es)
	http.Handle("/", router)

	port := os.Getenv("PORT")
	if port == "" {
		port = "3000"
	}
	fmt.Printf("Starting server at localhost:%s...", port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}<|endoftext|>


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

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"math"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"
	"github.com/prometheus/common/version"
	"github.com/prometheus/statsd_exporter/pkg/mapper"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	listenAddress   = kingpin.Flag("web.listen-address", "Address on which to expose metrics.").Default(":9108").String()
	metricsPath     = kingpin.Flag("web.telemetry-path", "Path under which to expose Prometheus metrics.").Default("/metrics").String()
	graphiteAddress = kingpin.Flag("graphite.listen-address", "TCP and UDP address on which to accept samples.").Default(":9109").String()
	mappingConfig   = kingpin.Flag("graphite.mapping-config", "Metric mapping configuration file name.").Default("").String()
	sampleExpiry    = kingpin.Flag("graphite.sample-expiry", "How long a sample is valid for.").Default("5m").Duration()
	strictMatch     = kingpin.Flag("graphite.mapping-strict-match", "Only store metrics that match the mapping configuration.").Bool()
	dumpFSMPath     = kingpin.Flag("debug.dump-fsm", "The path to dump internal FSM generated for glob matching as Dot file.").Default("").String()

	lastProcessed = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "graphite_last_processed_timestamp_seconds",
			Help: "Unix timestamp of the last processed graphite metric.",
		},
	)
	sampleExpiryMetric = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "graphite_sample_expiry_seconds",
			Help: "How long in seconds a metric sample is valid for.",
		},
	)
	invalidMetricChars = regexp.MustCompile("[^a-zA-Z0-9_:]")
)

type graphiteSample struct {
	OriginalName string
	Name         string
	Labels       map[string]string
	Help         string
	Value        float64
	Type         prometheus.ValueType
	Timestamp    time.Time
}

func (s graphiteSample) String() string {
	return fmt.Sprintf("%#v", s)
}

type metricMapper interface {
	GetMapping(string, mapper.MetricType) (*mapper.MetricMapping, prometheus.Labels, bool)
	InitFromFile(string) error
}

type graphiteCollector struct {
	samples     map[string]*graphiteSample
	mu          *sync.Mutex
	mapper      metricMapper
	sampleCh    chan *graphiteSample
	lineCh      chan string
	strictMatch bool
	logger      log.Logger
}

func newGraphiteCollector(logger log.Logger) *graphiteCollector {
	c := &graphiteCollector{
		sampleCh:    make(chan *graphiteSample),
		lineCh:      make(chan string),
		mu:          &sync.Mutex{},
		samples:     map[string]*graphiteSample{},
		strictMatch: *strictMatch,
		logger:      logger,
	}
	go c.processSamples()
	go c.processLines()
	return c
}

func (c *graphiteCollector) processReader(reader io.Reader) {
	lineScanner := bufio.NewScanner(reader)
	for {
		if ok := lineScanner.Scan(); !ok {
			break
		}
		c.lineCh <- lineScanner.Text()
	}
}

func (c *graphiteCollector) processLines() {
	for line := range c.lineCh {
		c.processLine(line)
	}
}

func (c *graphiteCollector) processLine(line string) {
	line = strings.TrimSpace(line)
	level.Debug(c.logger).Log("msg", "Incoming line", "line", line)
	parts := strings.Split(line, " ")
	if len(parts) != 3 {
		level.Info(c.logger).Log("msg", "Invalid part count", "length", len(parts), "parts", line)
		return
	}
	originalName := parts[0]
	var name string
	mapping, labels, present := c.mapper.GetMapping(originalName, mapper.MetricTypeGauge)

	if (present && mapping.Action == mapper.ActionTypeDrop) || (!present && c.strictMatch) {
		return
	}

	if present {
		name = invalidMetricChars.ReplaceAllString(mapping.Name, "_")
	} else {
		name = invalidMetricChars.ReplaceAllString(originalName, "_")
	}

	value, err := strconv.ParseFloat(parts[1], 64)
	if err != nil {
		level.Info(c.logger).Log("msg", "Invalid value", "line", line)
		return
	}
	timestamp, err := strconv.ParseFloat(parts[2], 64)
	if err != nil {
		level.Info(c.logger).Log("msg", "Invalid timestamp", "line", line)
		return
	}
	sample := graphiteSample{
		OriginalName: originalName,
		Name:         name,
		Value:        value,
		Labels:       labels,
		Type:         prometheus.GaugeValue,
		Help:         fmt.Sprintf("Graphite metric %s", name),
		Timestamp:    time.Unix(int64(timestamp), int64(math.Mod(timestamp, 1.0)*1e9)),
	}
	level.Debug(c.logger).Log("msg", "Processing sample", "sample", sample)
	lastProcessed.Set(float64(time.Now().UnixNano()) / 1e9)
	c.sampleCh <- &sample
}

func (c *graphiteCollector) processSamples() {
	ticker := time.NewTicker(time.Minute).C

	for {
		select {
		case sample, ok := <-c.sampleCh:
			if sample == nil || !ok {
				return
			}
			c.mu.Lock()
			c.samples[sample.OriginalName] = sample
			c.mu.Unlock()
		case <-ticker:
			// Garbage collect expired samples.
			ageLimit := time.Now().Add(-*sampleExpiry)
			c.mu.Lock()
			for k, sample := range c.samples {
				if ageLimit.After(sample.Timestamp) {
					delete(c.samples, k)
				}
			}
			c.mu.Unlock()
		}
	}
}

// Collect implements prometheus.Collector.
func (c graphiteCollector) Collect(ch chan<- prometheus.Metric) {
	ch <- lastProcessed

	c.mu.Lock()
	samples := make([]*graphiteSample, 0, len(c.samples))
	for _, sample := range c.samples {
		samples = append(samples, sample)
	}
	c.mu.Unlock()

	ageLimit := time.Now().Add(-*sampleExpiry)
	for _, sample := range samples {
		if ageLimit.After(sample.Timestamp) {
			continue
		}
		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(sample.Name, sample.Help, []string{}, sample.Labels),
			sample.Type,
			sample.Value,
		)
	}
}

// Describe implements prometheus.Collector.
func (c graphiteCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- lastProcessed.Desc()
}

func init() {
	prometheus.MustRegister(version.NewCollector("graphite_exporter"))
}

func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger log.Logger) error {
	f, err := os.Create(dumpFilename)
	if err != nil {
		return err
	}
	level.Info(logger).Log("msg", "Start dumping FSM", "to", dumpFilename)
	w := bufio.NewWriter(f)
	mapper.FSM.DumpFSM(w)
	w.Flush()
	f.Close()
	level.Info(logger).Log("msg", "Finish dumping FSM")
	return nil
}

func main() {
	promlogConfig := &promlog.Config{}
	flag.AddFlags(kingpin.CommandLine, promlogConfig)
	kingpin.Version(version.Print("graphite_exporter"))
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(promlogConfig)

	prometheus.MustRegister(sampleExpiryMetric)
	sampleExpiryMetric.Set(sampleExpiry.Seconds())

	level.Info(logger).Log("msg", "Starting graphite_exporter", "version_info", version.Info())
	level.Info(logger).Log("build_context", version.BuildContext())

	http.Handle(*metricsPath, promhttp.Handler())
	c := newGraphiteCollector(logger)
	prometheus.MustRegister(c)

	c.mapper = &mapper.MetricMapper{}
	if *mappingConfig != "" {
		err := c.mapper.InitFromFile(*mappingConfig)
		if err != nil {
			level.Error(logger).Log("msg", "Error loading metric mapping config", "err", err)
			os.Exit(1)
		}
	}

	if *dumpFSMPath != "" {
		err := dumpFSM(c.mapper.(*mapper.MetricMapper), *dumpFSMPath, logger)
		if err != nil {
			level.Error(logger).Log("msg", "Error dumping FSM", "err", err)
			os.Exit(1)
		}
	}

	tcpSock, err := net.Listen("tcp", *graphiteAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error binding to TCP socket", "err", err)
		os.Exit(1)
	}
	go func() {
		for {
			conn, err := tcpSock.Accept()
			if err != nil {
				level.Error(logger).Log("msg", "Error accepting TCP connection", "err", err)
				continue
			}
			go func() {
				defer conn.Close()
				c.processReader(conn)
			}()
		}
	}()

	udpAddress, err := net.ResolveUDPAddr("udp", *graphiteAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error resolving UDP address", "err", err)
		os.Exit(1)
	}
	udpSock, err := net.ListenUDP("udp", udpAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error listening to UDP address", "err", err)
		os.Exit(1)
	}
	go func() {
		defer udpSock.Close()
		for {
			buf := make([]byte, 65536)
			chars, srcAddress, err := udpSock.ReadFromUDP(buf)
			if err != nil {
				level.Error(logger).Log("msg", "Error reading UDP packet", "from", srcAddress, "err", err)
				continue
			}
			go c.processReader(bytes.NewReader(buf[0:chars]))
		}
	}()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}
		w.Write([]byte(`
      <title>Graphite Exporter</title>

Graphite Exporter

Accepting plaintext Graphite samples over TCP and UDP on ` + *graphiteAddress + `

<a href="` + *metricsPath + `">Metrics

      `))
	})

	level.Info(logger).Log("msg", "Listening on "+*listenAddress)
	level.Error(logger).Log("err", http.ListenAndServe(*listenAddress, nil))
	os.Exit(1)
}
<commit_msg>Update main.go<commit_after>// Copyright 2015 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"math"
	"net"
	"net/http"
	_ "net/http/pprof"
	"os"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/prometheus/common/promlog"
	"github.com/prometheus/common/promlog/flag"
	"github.com/prometheus/common/version"
	"github.com/prometheus/statsd_exporter/pkg/mapper"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	listenAddress   = kingpin.Flag("web.listen-address", "Address on which to expose metrics.").Default(":9108").String()
	metricsPath     = kingpin.Flag("web.telemetry-path", "Path under which to expose Prometheus metrics.").Default("/metrics").String()
	graphiteAddress = kingpin.Flag("graphite.listen-address", "TCP and UDP address on which to accept samples.").Default(":9109").String()
	mappingConfig   = kingpin.Flag("graphite.mapping-config", "Metric mapping configuration file name.").Default("").String()
	sampleExpiry    = kingpin.Flag("graphite.sample-expiry", "How long a sample is valid for.").Default("5m").Duration()
	strictMatch     = kingpin.Flag("graphite.mapping-strict-match", "Only store metrics that match the mapping configuration.").Bool()
	dumpFSMPath     = kingpin.Flag("debug.dump-fsm", "The path to dump internal FSM generated for glob matching as Dot file.").Default("").String()

	lastProcessed = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "graphite_last_processed_timestamp_seconds",
			Help: "Unix timestamp of the last processed graphite metric.",
		},
	)
	sampleExpiryMetric = prometheus.NewGauge(
		prometheus.GaugeOpts{
			Name: "graphite_sample_expiry_seconds",
			Help: "How long in seconds a metric sample is valid for.",
		},
	)
	invalidMetricChars = regexp.MustCompile("[^a-zA-Z0-9_:]")
)

type graphiteSample struct {
	OriginalName string
	Name         string
	Labels       map[string]string
	Help         string
	Value        float64
	Type         prometheus.ValueType
	Timestamp    time.Time
}

func (s graphiteSample) String() string {
	return fmt.Sprintf("%#v", s)
}

type metricMapper interface {
	GetMapping(string, mapper.MetricType) (*mapper.MetricMapping, prometheus.Labels, bool)
	InitFromFile(string) error
}

type graphiteCollector struct {
	samples     map[string]*graphiteSample
	mu          *sync.Mutex
	mapper      metricMapper
	sampleCh    chan *graphiteSample
	lineCh      chan string
	strictMatch bool
	logger      log.Logger
}

func newGraphiteCollector(logger log.Logger) *graphiteCollector {
	c := &graphiteCollector{
		sampleCh:    make(chan *graphiteSample),
		lineCh:      make(chan string),
		mu:          &sync.Mutex{},
		samples:     map[string]*graphiteSample{},
		strictMatch: *strictMatch,
		logger:      logger,
	}
	go c.processSamples()
	go c.processLines()
	return c
}

func (c *graphiteCollector) processReader(reader io.Reader) {
	lineScanner := bufio.NewScanner(reader)
	for {
		if ok := lineScanner.Scan(); !ok {
			break
		}
		c.lineCh <- lineScanner.Text()
	}
}

func (c *graphiteCollector) processLines() {
	for line := range c.lineCh {
		c.processLine(line)
	}
}

func (c *graphiteCollector) processLine(line string) {
	line = strings.TrimSpace(line)
	level.Debug(c.logger).Log("msg", "Incoming line", "line", line)
	parts := strings.Split(line, " ")
	if len(parts) != 3 {
		level.Info(c.logger).Log("msg", "Invalid part count", "parts", len(parts), "line", line)
		return
	}
	originalName := parts[0]
	var name string
	mapping, labels, present := c.mapper.GetMapping(originalName, mapper.MetricTypeGauge)

	if (present && mapping.Action == mapper.ActionTypeDrop) || (!present && c.strictMatch) {
		return
	}

	if present {
		name = invalidMetricChars.ReplaceAllString(mapping.Name, "_")
	} else {
		name = invalidMetricChars.ReplaceAllString(originalName, "_")
	}

	value, err := strconv.ParseFloat(parts[1], 64)
	if err != nil {
		level.Info(c.logger).Log("msg", "Invalid value", "line", line)
		return
	}
	timestamp, err := strconv.ParseFloat(parts[2], 64)
	if err != nil {
		level.Info(c.logger).Log("msg", "Invalid timestamp", "line", line)
		return
	}
	sample := graphiteSample{
		OriginalName: originalName,
		Name:         name,
		Value:        value,
		Labels:       labels,
		Type:         prometheus.GaugeValue,
		Help:         fmt.Sprintf("Graphite metric %s", name),
		Timestamp:    time.Unix(int64(timestamp), int64(math.Mod(timestamp, 1.0)*1e9)),
	}
	level.Debug(c.logger).Log("msg", "Processing sample", "sample", sample)
	lastProcessed.Set(float64(time.Now().UnixNano()) / 1e9)
	c.sampleCh <- &sample
}

func (c *graphiteCollector) processSamples() {
	ticker := time.NewTicker(time.Minute).C

	for {
		select {
		case sample, ok := <-c.sampleCh:
			if sample == nil || !ok {
				return
			}
			c.mu.Lock()
			c.samples[sample.OriginalName] = sample
			c.mu.Unlock()
		case <-ticker:
			// Garbage collect expired samples.
			ageLimit := time.Now().Add(-*sampleExpiry)
			c.mu.Lock()
			for k, sample := range c.samples {
				if ageLimit.After(sample.Timestamp) {
					delete(c.samples, k)
				}
			}
			c.mu.Unlock()
		}
	}
}

// Collect implements prometheus.Collector.
func (c graphiteCollector) Collect(ch chan<- prometheus.Metric) {
	ch <- lastProcessed

	c.mu.Lock()
	samples := make([]*graphiteSample, 0, len(c.samples))
	for _, sample := range c.samples {
		samples = append(samples, sample)
	}
	c.mu.Unlock()

	ageLimit := time.Now().Add(-*sampleExpiry)
	for _, sample := range samples {
		if ageLimit.After(sample.Timestamp) {
			continue
		}
		ch <- prometheus.MustNewConstMetric(
			prometheus.NewDesc(sample.Name, sample.Help, []string{}, sample.Labels),
			sample.Type,
			sample.Value,
		)
	}
}

// Describe implements prometheus.Collector.
func (c graphiteCollector) Describe(ch chan<- *prometheus.Desc) {
	ch <- lastProcessed.Desc()
}

func init() {
	prometheus.MustRegister(version.NewCollector("graphite_exporter"))
}

func dumpFSM(mapper *mapper.MetricMapper, dumpFilename string, logger log.Logger) error {
	f, err := os.Create(dumpFilename)
	if err != nil {
		return err
	}
	level.Info(logger).Log("msg", "Start dumping FSM", "to", dumpFilename)
	w := bufio.NewWriter(f)
	mapper.FSM.DumpFSM(w)
	w.Flush()
	f.Close()
	level.Info(logger).Log("msg", "Finish dumping FSM")
	return nil
}

func main() {
	promlogConfig := &promlog.Config{}
	flag.AddFlags(kingpin.CommandLine, promlogConfig)
	kingpin.Version(version.Print("graphite_exporter"))
	kingpin.HelpFlag.Short('h')
	kingpin.Parse()
	logger := promlog.New(promlogConfig)

	prometheus.MustRegister(sampleExpiryMetric)
	sampleExpiryMetric.Set(sampleExpiry.Seconds())

	level.Info(logger).Log("msg", "Starting graphite_exporter", "version_info", version.Info())
	level.Info(logger).Log("build_context", version.BuildContext())

	http.Handle(*metricsPath, promhttp.Handler())
	c := newGraphiteCollector(logger)
	prometheus.MustRegister(c)

	c.mapper = &mapper.MetricMapper{}
	if *mappingConfig != "" {
		err := c.mapper.InitFromFile(*mappingConfig)
		if err != nil {
			level.Error(logger).Log("msg", "Error loading metric mapping config", "err", err)
			os.Exit(1)
		}
	}

	if *dumpFSMPath != "" {
		err := dumpFSM(c.mapper.(*mapper.MetricMapper), *dumpFSMPath, logger)
		if err != nil {
			level.Error(logger).Log("msg", "Error dumping FSM", "err", err)
			os.Exit(1)
		}
	}

	tcpSock, err := net.Listen("tcp", *graphiteAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error binding to TCP socket", "err", err)
		os.Exit(1)
	}
	go func() {
		for {
			conn, err := tcpSock.Accept()
			if err != nil {
				level.Error(logger).Log("msg", "Error accepting TCP connection", "err", err)
				continue
			}
			go func() {
				defer conn.Close()
				c.processReader(conn)
			}()
		}
	}()

	udpAddress, err := net.ResolveUDPAddr("udp", *graphiteAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error resolving UDP address", "err", err)
		os.Exit(1)
	}
	udpSock, err := net.ListenUDP("udp", udpAddress)
	if err != nil {
		level.Error(logger).Log("msg", "Error listening to UDP address", "err", err)
		os.Exit(1)
	}
	go func() {
		defer udpSock.Close()
		for {
			buf := make([]byte, 65536)
			chars, srcAddress, err := udpSock.ReadFromUDP(buf)
			if err != nil {
				level.Error(logger).Log("msg", "Error reading UDP packet", "from", srcAddress, "err", err)
				continue
			}
			go c.processReader(bytes.NewReader(buf[0:chars]))
		}
	}()

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}
		w.Write([]byte(`
      <title>Graphite Exporter</title>

Graphite Exporter

Accepting plaintext Graphite samples over TCP and UDP on ` + *graphiteAddress + `

<a href="` + *metricsPath + `">Metrics

      `))
	})

	level.Info(logger).Log("msg", "Listening on "+*listenAddress)
	level.Error(logger).Log("err", http.ListenAndServe(*listenAddress, nil))
	os.Exit(1)
}
<|endoftext|>