<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const VERSION = "v0.0.1"

func main() {
	var i string
	flag.StringVar(&i, "i", "1s", "Interval to wait between executions in seconds")
	flag.StringVar(&i, "interval", "1s", "Interval to wait between executions in seconds")

	var interrupt bool
	flag.BoolVar(&interrupt, "x", false, "Exit and elevate status code if the command fails")
	flag.BoolVar(&interrupt, "exit", false, "Exit and elevate status code if the command fails")

	var version bool
	flag.BoolVar(&version, "v", false, "Print out version")
	flag.BoolVar(&version, "version", false, "Print out version")

	var usage bool
	flag.BoolVar(&usage, "h", false, "Print out version")
	flag.BoolVar(&usage, "help", false, "Print out version")

	flag.Parse()

	if version {
		die(0, VERSION)
	}

	command := flag.Args()

	if usage || len(command) == 0 {
		help()
		die(0, "")
	}

	if !commandExists(command) {
		die(0, "Executable not found in PATH")
	}

	interval := parseInterval(i)

	loop(intervalToTime(interval), func() {
		reset()
		status := run(command)
		if interrupt && status != 0 {
			die(status, "")
		}
	})
}

func intervalSuffixes() []string {
	return []string{"ms", "s", "MS", "S"}
}

func unitToFactor(s string) float64 {
	if s == "ms" || s == "MS" {
		return 1.0
	}
	if s == "s" || s == "S" {
		return 1000.0
	}
	return 1000.0
}

func suffixToInterval(s string, i string) (float64, bool) {
	is_unit := strings.HasSuffix(i, s)
	if is_unit {
		n, err := strconv.ParseFloat(i[:len(i)-len(s)], 64)
		dieIf(err, -1, "Invalid interval")
		return n * unitToFactor(s), true
	}
	return 0, false
}

func parseInterval(i string) float64 {
	suffixes := intervalSuffixes()
	for j := 0; j < len(suffixes); j++ {
		if val, is := suffixToInterval(suffixes[j], i); is {
			return val
		}
	}
	return 0
}

func help() {
	s := `
   Usage: watch [options] <cmd>

   Sample: watch -i=100ms make

   Options:

     -i, --interval             interval in seconds or ms, defaulting to 1s
     -x, --exit                 exit on failure
     -v, --version              print out version
     -h, --help                 this help page

`
	fmt.Print(s)
}

func dieIf(err error, status int, message string) {
	if err != nil {
		die(status, message)
	}
}

func die(status int, message string) {
	if len(message) > 0 {
		fmt.Println(message)
	}
	os.Exit(status)
}

func intervalToTime(i float64) time.Duration {
	return time.Duration(i) * time.Millisecond
}

func reset() {
	run([]string{"clear"})
}

func makeCmd(bin string, args []string) *exec.Cmd {
	cmd := exec.Command(bin, args...)
	cmd.Env = os.Environ()
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd
}

func getExitStatus(cmd *exec.Cmd) int {
	status, _ := cmd.ProcessState.Sys().(syscall.WaitStatus)
	return status.ExitStatus()
}

func commandExists(command []string) bool {
	_, result := exec.LookPath(command[0])
	return result == nil
}

func run(command []string) int {
	path, _ := exec.LookPath(command[0])
	cmd := makeCmd(path, command[1:])
	cmd.Run()
	return getExitStatus(cmd)
}

func loop(d time.Duration, fn func()) {
	fn()
	for range time.Tick(d) {
		fn()
	}
}
<commit_msg>Clear duplicated, unused descriptions<commit_after>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"syscall"
	"time"
)

const VERSION = "v0.0.1"

func main() {
	var i string
	flag.StringVar(&i, "i", "1s", "")
	flag.StringVar(&i, "interval", "1s", "")

	var interrupt bool
	flag.BoolVar(&interrupt, "x", false, "")
	flag.BoolVar(&interrupt, "exit", false, "")

	var version bool
	flag.BoolVar(&version, "v", false, "")
	flag.BoolVar(&version, "version", false, "")

	var usage bool
	flag.BoolVar(&usage, "h", false, "")
	flag.BoolVar(&usage, "help", false, "")

	flag.Parse()

	if version {
		die(0, VERSION)
	}

	command := flag.Args()

	if usage || len(command) == 0 {
		help()
		die(0, "")
	}

	if !commandExists(command) {
		die(0, "Executable not found in PATH")
	}

	interval := parseInterval(i)

	loop(intervalToTime(interval), func() {
		reset()
		status := run(command)
		if interrupt && status != 0 {
			die(status, "")
		}
	})
}

func intervalSuffixes() []string {
	return []string{"ms", "s", "MS", "S"}
}

func unitToFactor(s string) float64 {
	if s == "ms" || s == "MS" {
		return 1.0
	}
	if s == "s" || s == "S" {
		return 1000.0
	}
	return 1000.0
}

func suffixToInterval(s string, i string) (float64, bool) {
	is_unit := strings.HasSuffix(i, s)
	if is_unit {
		n, err := strconv.ParseFloat(i[:len(i)-len(s)], 64)
		dieIf(err, -1, "Invalid interval")
		return n * unitToFactor(s), true
	}
	return 0, false
}

func parseInterval(i string) float64 {
	suffixes := intervalSuffixes()
	for j := 0; j < len(suffixes); j++ {
		if val, is := suffixToInterval(suffixes[j], i); is {
			return val
		}
	}
	return 0
}

func help() {
	s := `
   Usage: watch [options] <cmd>

   Sample: watch -i=100ms make

   Options:

     -i, --interval             interval in seconds or ms, defaulting to 1s
     -x, --exit                 exit on failure
     -v, --version              print out version
     -h, --help                 this help page

`
	fmt.Print(s)
}

func dieIf(err error, status int, message string) {
	if err != nil {
		die(status, message)
	}
}

func die(status int, message string) {
	if len(message) > 0 {
		fmt.Println(message)
	}
	os.Exit(status)
}

func intervalToTime(i float64) time.Duration {
	return time.Duration(i) * time.Millisecond
}

func reset() {
	run([]string{"clear"})
}

func makeCmd(bin string, args []string) *exec.Cmd {
	cmd := exec.Command(bin, args...)
	cmd.Env = os.Environ()
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd
}

func getExitStatus(cmd *exec.Cmd) int {
	status, _ := cmd.ProcessState.Sys().(syscall.WaitStatus)
	return status.ExitStatus()
}

func commandExists(command []string) bool {
	_, result := exec.LookPath(command[0])
	return result == nil
}

func run(command []string) int {
	path, _ := exec.LookPath(command[0])
	cmd := makeCmd(path, command[1:])
	cmd.Run()
	return getExitStatus(cmd)
}

func loop(d time.Duration, fn func()) {
	fn()
	for range time.Tick(d) {
		fn()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"

	"github.com/google/gops/agent"
	"github.com/julienschmidt/httprouter"
	log "github.com/meifamily/logrus"
	"github.com/robfig/cron"

	ctrlr "github.com/meifamily/ptt-alertor/controllers"
	"github.com/meifamily/ptt-alertor/jobs"
	"github.com/meifamily/ptt-alertor/line"
	"github.com/meifamily/ptt-alertor/messenger"
	"github.com/meifamily/ptt-alertor/myutil"
	"github.com/meifamily/ptt-alertor/telegram"
)

var auth map[string]string

type myRouter struct {
	httprouter.Router
}

func (mr myRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.WithFields(log.Fields{
		"IP":  r.RemoteAddr,
		"URI": r.URL.Path,
	}).Info("visit")
	mr.Router.ServeHTTP(w, r)
}

func newRouter() *myRouter {
	return &myRouter{
		Router: *httprouter.New(),
	}
}

func basicAuth(handle httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
		user, password, hasAuth := r.BasicAuth()
		if hasAuth && user == auth["user"] && password == auth["password"] {
			handle(w, r, params)
		} else {
			w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func main() {
	log.Info("Start Jobs")
	startJobs()
	// Web Server
	log.Info("Web Server Start on Port 9090")

	router := newRouter()
	router.NotFound = http.FileServer(http.Dir("public"))
	m := messenger.New()

	router.GET("/", ctrlr.Index)
	router.GET("/messenger", ctrlr.MessengerIndex)
	router.GET("/line", ctrlr.LineIndex)
	router.GET("/telegram", ctrlr.TelegramIndex)
	router.GET("/redirect/:sha1", ctrlr.Redirect)
	router.GET("/top", ctrlr.Top)
	router.GET("/docs", ctrlr.Docs)

	router.POST("/broadcast", basicAuth(ctrlr.Broadcast))

	// boards apis
	router.GET("/boards/:boardName/articles/:code", ctrlr.BoardArticle)
	router.GET("/boards/:boardName/articles", ctrlr.BoardArticleIndex)
	router.GET("/boards", ctrlr.BoardIndex)

	// keyword apis
	router.GET("/keyword/boards", ctrlr.KeywordBoards)

	// author apis
	router.GET("/author/boards", ctrlr.AuthorBoards)

	// pushsum apis
	router.GET("/pushsum/boards", ctrlr.PushSumBoards)

	// articles apis
	router.GET("/articles", ctrlr.ArticleIndex)

	// users apis
	router.GET("/users/:account", basicAuth(ctrlr.UserFind))
	router.GET("/users", basicAuth(ctrlr.UserAll))
	router.POST("/users", basicAuth(ctrlr.UserCreate))
	router.PUT("/users/:account", basicAuth(ctrlr.UserModify))

	// line
	router.POST("/line/callback", line.HandleRequest)
	router.POST("/line/notify/callback", line.CatchCallback)

	// facebook messenger
	router.GET("/messenger/webhook", m.Verify)
	router.POST("/messenger/webhook", m.Received)

	// telegram
	router.POST("/telegram/"+telegram.Token, telegram.HandleRequest)

	// gops agent
	if err := agent.Listen(&agent.Options{Addr: "127.0.0.1:9090", NoShutdownCleanup: false}); err != nil {
		log.Fatal(err)
	}

	err := http.ListenAndServe(":9090", router)
	if err != nil {
		log.Fatal("ListenAndServer ", err)
	}

}

func startJobs() {
	go jobs.NewChecker().Run()
	go jobs.NewPushListChecker().Run()
	go jobs.NewPushSumChecker().Run()
	c := cron.New()
	c.AddJob("@hourly", jobs.NewTop())
	c.AddJob("@every 3d", jobs.NewPushSumKeyReplacer())
	c.Start()
}

func init() {
	auth = myutil.Config("auth")
	jobs.NewTop().Run()
	// for initial app
	// jobs.NewCacheCleaner().Run()
	// jobs.NewGenerator().Run()
	// jobs.NewFetcher().Run()
}
<commit_msg>add request method in log<commit_after>package main

import (
	"net/http"

	"github.com/google/gops/agent"
	"github.com/julienschmidt/httprouter"
	log "github.com/meifamily/logrus"
	"github.com/robfig/cron"

	ctrlr "github.com/meifamily/ptt-alertor/controllers"
	"github.com/meifamily/ptt-alertor/jobs"
	"github.com/meifamily/ptt-alertor/line"
	"github.com/meifamily/ptt-alertor/messenger"
	"github.com/meifamily/ptt-alertor/myutil"
	"github.com/meifamily/ptt-alertor/telegram"
)

var auth map[string]string

type myRouter struct {
	httprouter.Router
}

func (mr myRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.WithFields(log.Fields{
		"method": r.Method,
		"IP":     r.RemoteAddr,
		"URI":    r.URL.Path,
	}).Info("visit")
	mr.Router.ServeHTTP(w, r)
}

func newRouter() *myRouter {
	return &myRouter{
		Router: *httprouter.New(),
	}
}

func basicAuth(handle httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
		user, password, hasAuth := r.BasicAuth()
		if hasAuth && user == auth["user"] && password == auth["password"] {
			handle(w, r, params)
		} else {
			w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
			http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
		}
	}
}

func main() {
	log.Info("Start Jobs")
	startJobs()
	// Web Server
	log.Info("Web Server Start on Port 9090")

	router := newRouter()
	router.NotFound = http.FileServer(http.Dir("public"))
	m := messenger.New()

	router.GET("/", ctrlr.Index)
	router.GET("/messenger", ctrlr.MessengerIndex)
	router.GET("/line", ctrlr.LineIndex)
	router.GET("/telegram", ctrlr.TelegramIndex)
	router.GET("/redirect/:sha1", ctrlr.Redirect)
	router.GET("/top", ctrlr.Top)
	router.GET("/docs", ctrlr.Docs)

	router.POST("/broadcast", basicAuth(ctrlr.Broadcast))

	// boards apis
	router.GET("/boards/:boardName/articles/:code", ctrlr.BoardArticle)
	router.GET("/boards/:boardName/articles", ctrlr.BoardArticleIndex)
	router.GET("/boards", ctrlr.BoardIndex)

	// keyword apis
	router.GET("/keyword/boards", ctrlr.KeywordBoards)

	// author apis
	router.GET("/author/boards", ctrlr.AuthorBoards)

	// pushsum apis
	router.GET("/pushsum/boards", ctrlr.PushSumBoards)

	// articles apis
	router.GET("/articles", ctrlr.ArticleIndex)

	// users apis
	router.GET("/users/:account", basicAuth(ctrlr.UserFind))
	router.GET("/users", basicAuth(ctrlr.UserAll))
	router.POST("/users", basicAuth(ctrlr.UserCreate))
	router.PUT("/users/:account", basicAuth(ctrlr.UserModify))

	// line
	router.POST("/line/callback", line.HandleRequest)
	router.POST("/line/notify/callback", line.CatchCallback)

	// facebook messenger
	router.GET("/messenger/webhook", m.Verify)
	router.POST("/messenger/webhook", m.Received)

	// telegram
	router.POST("/telegram/"+telegram.Token, telegram.HandleRequest)

	// gops agent
	if err := agent.Listen(&agent.Options{Addr: "127.0.0.1:9090", NoShutdownCleanup: false}); err != nil {
		log.Fatal(err)
	}

	err := http.ListenAndServe(":9090", router)
	if err != nil {
		log.Fatal("ListenAndServer ", err)
	}

}

func startJobs() {
	go jobs.NewChecker().Run()
	go jobs.NewPushListChecker().Run()
	go jobs.NewPushSumChecker().Run()
	c := cron.New()
	c.AddJob("@hourly", jobs.NewTop())
	c.AddJob("@every 3d", jobs.NewPushSumKeyReplacer())
	c.Start()
}

func init() {
	auth = myutil.Config("auth")
	jobs.NewTop().Run()
	// for initial app
	// jobs.NewCacheCleaner().Run()
	// jobs.NewGenerator().Run()
	// jobs.NewFetcher().Run()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"net/http"
	"strings"
)

func main() {
	http.HandleFunc("/hello", hello)

	http.HandleFunc("/weather/", func(w http.ResponseWriter, r *http.Request) {
		city := strings.SplitN(r.URL.Path, "/", 3)[2]

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

		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		json.NewEncoder(w).Encode(data)
	})

	http.ListenAndServe(":8080", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello!\n"))
}

func query(city string) (weatherData, error) {
	resp, err := http.Get("http://api.openweathermap.org/data/2.5/weather?q=" + city)
	if err != nil {
		return weatherData{}, err
	}

	defer resp.Body.Close()

	var d weatherData

	if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
		return weatherData{}, err
	}

	return d, nil
}

type weatherData struct {
	Name string `json:"name"`
	Main struct {
		Kelvin float64 `json:"temp"`
	} `json:"main"`
}
<commit_msg>starting over<commit_after><|endoftext|>


<commit_before>package main

import (
  "log"
  "fmt"
  "net/http"
  "sync"
  "strconv"
  "runtime"

  "github.com/ant0ine/go-json-rest/rest"
  "github.com/PuerkitoBio/goquery"
  //"github.com/k0kubun/pp"
)

type PostData struct {
  Url string
}

type List struct {
  Url []string
  User []User
}

type User struct {
  Name string
  Image string
  CancelCount int
  JoinCount int
}

func main() {
  api := rest.NewApi()
  api.Use(rest.DefaultDevStack...)
  router, err := rest.MakeRouter(
    rest.Post("/", PostCancel),
  )

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

  port := os.Getenv("PORT")

  api.SetApp(router)
  log.Fatal(http.ListenAndServe(port, api.MakeHandler()))
}

func PostCancel(w rest.ResponseWriter, r *rest.Request) {
  cpus := runtime.NumCPU()
  runtime.GOMAXPROCS(cpus)

  post_data := PostData{}
  err := r.DecodeJsonPayload(&post_data)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  if post_data.Url == "" {
    rest.Error(w, "url required", 400)
  }

  list := List{}
  fmt.Println(post_data.Url)
  GetPageToConnpass(post_data.Url, &list)

  wg := new(sync.WaitGroup)
  for _, url := range list.Url {
    wg.Add(1)
    go GetUserPageToConnpass(&list, url, wg)
  }
  wg.Wait()

  w.WriteJson(list.User)
  // pp.Println(list.User)
}

func GetPageToConnpass(url string, list *List) {
  doc, _ := goquery.NewDocument(url + "participation/#participants")
  doc.Find(".user").Each(func(_ int, s *goquery.Selection) {
    s.Find(".image_link").Each(func(_ int, s *goquery.Selection) {
      url, _ := s.Attr("href")
      list.Url = append(list.Url, url)
    })
  })
}

func GetUserPageToConnpass(list *List, url string, wg *sync.WaitGroup) {
  // 退会ユーザーなどはURLが取れないため無視
  if url != "" {
    user := User{"", "", 0, 0}

    doc, _ := goquery.NewDocument(url)
    image_elm := doc.Find("#side_area > div.mb_20.text_center img")
    user.Name, _ = image_elm.Attr("title")
    user.Image, _ = image_elm.Attr("src")
    doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
      join_status := s.Find("p.label_status_tag").Text()
      if join_status == "キャンセル" {
        user.CancelCount++
      } else {
        user.JoinCount++
      }
    })

    // ページ数が１以上ある場合
    if (doc.Find("#main > div.paging_area > ul > li").Length() - 1) > 1 {
      total_page := doc.Find("#main > div.paging_area > ul > li").Length() - 1

      for i := 2; i <= total_page; i++ {
        doc, _ := goquery.NewDocument(url + "?page=" + strconv.Itoa(i))
        doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
          join_status := s.Find("p.label_status_tag").Text()
          if join_status == "キャンセル" {
            user.CancelCount++
          } else {
            user.JoinCount++
          }
        })
      }
    }

    list.User = append(list.User, user)
  }
  wg.Done()
}
<commit_msg>commit<commit_after>package main

import (
  "os"
  "log"
  "fmt"
  "net/http"
  "sync"
  "strconv"
  "runtime"

  "github.com/ant0ine/go-json-rest/rest"
  "github.com/PuerkitoBio/goquery"
  //"github.com/k0kubun/pp"
)

type PostData struct {
  Url string
}

type List struct {
  Url []string
  User []User
}

type User struct {
  Name string
  Image string
  CancelCount int
  JoinCount int
}

func main() {
  api := rest.NewApi()
  api.Use(rest.DefaultDevStack...)
  router, err := rest.MakeRouter(
    rest.Post("/", PostCancel),
  )

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

  port := os.Getenv("PORT")

  api.SetApp(router)
  log.Fatal(http.ListenAndServe(port, api.MakeHandler()))
}

func PostCancel(w rest.ResponseWriter, r *rest.Request) {
  cpus := runtime.NumCPU()
  runtime.GOMAXPROCS(cpus)

  post_data := PostData{}
  err := r.DecodeJsonPayload(&post_data)
  if err != nil {
    rest.Error(w, err.Error(), http.StatusInternalServerError)
    return
  }
  if post_data.Url == "" {
    rest.Error(w, "url required", 400)
  }

  list := List{}
  fmt.Println(post_data.Url)
  GetPageToConnpass(post_data.Url, &list)

  wg := new(sync.WaitGroup)
  for _, url := range list.Url {
    wg.Add(1)
    go GetUserPageToConnpass(&list, url, wg)
  }
  wg.Wait()

  w.WriteJson(list.User)
  // pp.Println(list.User)
}

func GetPageToConnpass(url string, list *List) {
  doc, _ := goquery.NewDocument(url + "participation/#participants")
  doc.Find(".user").Each(func(_ int, s *goquery.Selection) {
    s.Find(".image_link").Each(func(_ int, s *goquery.Selection) {
      url, _ := s.Attr("href")
      list.Url = append(list.Url, url)
    })
  })
}

func GetUserPageToConnpass(list *List, url string, wg *sync.WaitGroup) {
  // 退会ユーザーなどはURLが取れないため無視
  if url != "" {
    user := User{"", "", 0, 0}

    doc, _ := goquery.NewDocument(url)
    image_elm := doc.Find("#side_area > div.mb_20.text_center img")
    user.Name, _ = image_elm.Attr("title")
    user.Image, _ = image_elm.Attr("src")
    doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
      join_status := s.Find("p.label_status_tag").Text()
      if join_status == "キャンセル" {
        user.CancelCount++
      } else {
        user.JoinCount++
      }
    })

    // ページ数が１以上ある場合
    if (doc.Find("#main > div.paging_area > ul > li").Length() - 1) > 1 {
      total_page := doc.Find("#main > div.paging_area > ul > li").Length() - 1

      for i := 2; i <= total_page; i++ {
        doc, _ := goquery.NewDocument(url + "?page=" + strconv.Itoa(i))
        doc.Find("#main > div.event_area.mb_10 > div.event_list.vevent").Each(func(_ int, s *goquery.Selection) {
          join_status := s.Find("p.label_status_tag").Text()
          if join_status == "キャンセル" {
            user.CancelCount++
          } else {
            user.JoinCount++
          }
        })
      }
    }

    list.User = append(list.User, user)
  }
  wg.Done()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"log"
	"net/url"
	"os"
	"io"
	"strconv"
	"strings"
)

type InputLine struct {
	ChannelId int
	URL       *url.URL
	Method    string
}

const (
	NEW_STOREID = iota
	NO_CHANGE
)

type OutputLine struct {
	ChannelId int
	result    uint
	store_id  string
}

func main() {
	readerLoop(os.Stdin)
}

func readerLoop(input io.Reader) {
	rd := bufio.NewReader(input)
	for {
		line, err := rd.ReadString('\n')
		if err != nil {
			break
		}
		fields := strings.Fields(line)
		if ln := len(fields); ln == 0 {
			log.Println("Normal exit from squid")
			return
		} else if ln != 4 && ln != 5 {
			log.Println("Linha com erro:", line)
			continue
		}

		il := new(InputLine)
		log.Println("Fields are:", fields)
		il.Parse(fields)
		log.Println("Parsed:", il, il.URL.Host)
		handleInput(il)
	}
}

func handleInput(il *InputLine) {
	fn := func () {
		log.Println("Handling...")

		ol := new(OutputLine)
		ol.ChannelId = il.ChannelId
		ol.result = NO_CHANGE

		printOutput(ol)

		log.Println("Exiting handling...")
	}
	if il.ChannelId == -1 { // Sequential
		fn()
	} else {
		go fn()
	}
}

func printOutput(ol *OutputLine) {
	if(ol.ChannelId != -1) {
		fmt.Printf("%v ", ol.ChannelId)
	}
	switch ol.result {
	case NO_CHANGE:
		fmt.Println("ERR") // Squid misleading return code
	case NEW_STOREID:
		fmt.Printf("OK store-id=%v", ol.store_id)
	}
}

func (il *InputLine) Parse(s []string) {
	start := 1
	if ChannelId, err := strconv.ParseUint(s[0], 10, 0); err != nil {
		il.ChannelId = -1
		start = 0
	} else {
		il.ChannelId = int(ChannelId)
	}

	if URL, err := url.Parse(s[start]); err != nil {
		log.Println("Error!")
		return
	} else {
		il.URL = URL
	}

	log.Println("start:", start)

	il.Method = s[start+3]

}
<commit_msg>Minor correction<commit_after>package main

import (
	"bufio"
	"fmt"
	"log"
	"net/url"
	"os"
	"io"
	"strconv"
	"strings"
)

type InputLine struct {
	ChannelId int
	URL       *url.URL
	Method    string
}

const (
	NEW_STOREID = iota
	NO_CHANGE
)

type OutputLine struct {
	ChannelId int
	result    uint
	store_id  string
}

func main() {
	readerLoop(os.Stdin)
}

func readerLoop(input io.Reader) {
	rd := bufio.NewReader(input)
	for {
		line, err := rd.ReadString('\n')
		if err != nil {
			break
		}
		fields := strings.Fields(line)
		if ln := len(fields); ln == 0 {
			log.Println("Normal exit from squid")
			return
		} else if ln != 4 && ln != 5 {
			log.Println("Linha com erro:", line)
			continue
		}

		il := new(InputLine)
		log.Println("Fields are:", fields)
		il.Parse(fields)
		log.Println("Parsed:", il, il.URL.Host)
		handleInput(il)
	}
}

func handleInput(il *InputLine) {
	fn := func () {
		log.Println("Handling...")

		ol := new(OutputLine)
		ol.ChannelId = il.ChannelId
		ol.result = NEW_STOREID
		ol.store_id = "http://ObamaPreto.com/"

		printOutput(ol)

		log.Println("Exiting handling...")
	}
	if il.ChannelId == -1 { // Sequential
		fn()
	} else {
		go fn()
	}
}

func printOutput(ol *OutputLine) {
	if(ol.ChannelId != -1) {
		fmt.Printf("%v ", ol.ChannelId)
	}
	switch ol.result {
	case NO_CHANGE:
		fmt.Println("ERR") // Squid misleading return code
	case NEW_STOREID:
		fmt.Printf("OK store-id=%v\n", ol.store_id)
	}
}

func (il *InputLine) Parse(s []string) {
	start := 1
	if ChannelId, err := strconv.ParseUint(s[0], 10, 0); err != nil {
		il.ChannelId = -1
		start = 0
	} else {
		il.ChannelId = int(ChannelId)
	}

	if URL, err := url.Parse(s[start]); err != nil {
		log.Println("Error!")
		return
	} else {
		il.URL = URL
	}

	log.Println("start:", start)

	il.Method = s[start+3]

}
<|endoftext|>


<commit_before>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"flag"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"strconv"
	"text/template"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/carlescere/scheduler"
	"github.com/gin-gonic/gin"
	"github.com/itsjamie/gin-cors"
	"github.com/kardianos/osext"
	"github.com/vharitonsky/iniflags"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
)

var (
	version              = "x.x.x-dev" //don't modify it, Jenkins will take care
	git_revision         = "xxxxxxxx"  //don't modify it, Jenkins will take care
	embedded_autoupdate  = true
	embedded_autoextract = false
	hibernate            = flag.Bool("hibernate", false, "start hibernated")
	verbose              = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")
	configIni    = flag.String("configFile", "config.ini", "config file path")
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")
	gcType       = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")
	logDump      = flag.String("log", "off", "off = (default)")
	// hostname. allow user to override, otherwise we look it up
	hostname       = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")
	updateUrl      = flag.String("updateUrl", "", "")
	appName        = flag.String("appName", "", "")
	globalToolsMap = make(map[string]string)
	tempToolsPath  = createToolsDir()
	port           string
	portSSL        string
	origins        = flag.String("origins", "", "Allowed origin list for CORS")
)

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

type logWriter struct{}

func (u *logWriter) Write(p []byte) (n int, err error) {
	h.broadcastSys <- p
	return len(p), nil
}

var logger_ws logWriter

func createToolsDir() string {
	usr, _ := user.Current()
	return usr.HomeDir + "/.arduino-create"
}

func homeHandler(c *gin.Context) {
	homeTemplate.Execute(c.Writer, c.Request.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 2 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 2 secs. Now launching...")
}

func main() {

	flag.Parse()

	if *hibernate == false {

		go func() {

			// autoextract self
			src, _ := osext.Executable()
			dest := filepath.Dir(src)

			os.Mkdir(tempToolsPath, 0777)
			hideFile(tempToolsPath)

			if embedded_autoextract {
				// save the config.ini (if it exists)
				if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
					log.Println("First run, unzipping self")
					err := Unzip(src, dest)
					log.Println("Self extraction, err:", err)
				}

				if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
					flag.Parse()
					log.Println("No config.ini at", *configIni)
				} else {
					flag.Parse()
					flag.Set("config", dest+"/"+*configIni)
					iniflags.Parse()
				}
			} else {
				flag.Set("config", dest+"/"+*configIni)
				iniflags.Parse()
			}

			// move CORS to config file compatibility, Vagrant version
			if *origins == "" {
				log.Println("Patching config.ini for compatibility")
				f, err := os.OpenFile(dest+"/"+*configIni, os.O_APPEND|os.O_WRONLY, 0666)
				if err != nil {
					panic(err)
				}
				_, err = f.WriteString("\norigins = http://webide.arduino.cc:8080\n")
				if err != nil {
					panic(err)
				}
				f.Close()
				restart("")
			}
			//log.SetFormatter(&log.JSONFormatter{})

			log.SetLevel(log.InfoLevel)

			log.SetOutput(os.Stderr)

			// see if we are supposed to wait 5 seconds
			if *isLaunchSelf {
				launchSelfLater()
			}

			if embedded_autoupdate {

				var updater = &Updater{
					CurrentVersion: version,
					ApiURL:         *updateUrl,
					BinURL:         *updateUrl,
					DiffURL:        "",
					Dir:            "update/",
					CmdName:        *appName,
				}

				if updater != nil {
					updater_job := func() {
						go updater.BackgroundRun()
					}
					scheduler.Every(5).Minutes().Run(updater_job)
				}
			}

			log.Println("Version:" + version)

			// hostname
			hn, _ := os.Hostname()
			if *hostname == "unknown-hostname" {
				*hostname = hn
			}
			log.Println("Hostname:", *hostname)

			// turn off garbage collection
			// this is dangerous, as u could overflow memory
			//if *isGC {
			if *gcType == "std" {
				log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
			} else if *gcType == "max" {
				log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
			} else {
				log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
				debug.SetGCPercent(-1)
			}

			// see if they provided a regex filter
			if len(*regExpFilter) > 0 {
				log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
			}

			// list serial ports
			portList, _ := GetList(false)
			log.Println("Your serial ports:")
			if len(portList) == 0 {
				log.Println("\tThere are no serial ports to list.")
			}
			for _, element := range portList {
				log.Printf("\t%v\n", element)

			}

			if !*verbose {
				log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
				log.SetOutput(new(NullWriter)) //route all logging to nullwriter
			}

			// launch the hub routine which is the singleton for the websocket server
			go h.run()
			// launch our serial port routine
			go sh.run()
			// launch our dummy data routine
			//go d.run()

			go discoverLoop()

			r := gin.New()

			socketHandler := wsHandler().ServeHTTP

			extraOriginStr := "https://create.arduino.cc, http://create.arduino.cc, https://create-dev.arduino.cc, http://create-dev.arduino.cc, http://create-staging.arduino.cc, https://create-staging.arduino.cc"

			for i := 8990; i < 9001; i++ {
				extraOriginStr = extraOriginStr + ", http://localhost:" + strconv.Itoa(i) + ", https://localhost:" + strconv.Itoa(i)
			}

			r.Use(cors.Middleware(cors.Config{
				Origins:         *origins + "," + extraOriginStr,
				Methods:         "GET, PUT, POST, DELETE",
				RequestHeaders:  "Origin, Authorization, Content-Type",
				ExposedHeaders:  "",
				MaxAge:          50 * time.Second,
				Credentials:     true,
				ValidateHeaders: false,
			}))

			r.GET("/", homeHandler)
			r.POST("/upload", uploadHandler)
			r.GET("/socket.io/", socketHandler)
			r.POST("/socket.io/", socketHandler)
			r.Handle("WS", "/socket.io/", socketHandler)
			r.Handle("WSS", "/socket.io/", socketHandler)
			r.GET("/info", infoHandler)
			go func() {
				start := 8990
				end := 9000
				i := start
				for i < end {
					i = i + 1
					portSSL = ":" + strconv.Itoa(i)
					if err := r.RunTLS(portSSL, filepath.Join(dest, "cert.pem"), filepath.Join(dest, "key.pem")); err != nil {
						log.Printf("Error trying to bind to port: %v, so exiting...", err)
						continue
					} else {
						ip := "0.0.0.0"
						log.Print("Starting server and websocket (SSL) on " + ip + "" + port)
						break
					}
				}
			}()

			go func() {
				start := 8990
				end := 9000
				i := start
				for i < end {
					i = i + 1
					port = ":" + strconv.Itoa(i)
					if err := r.Run(port); err != nil {
						log.Printf("Error trying to bind to port: %v, so exiting...", err)
						continue
					} else {
						ip := "0.0.0.0"
						log.Print("Starting server and websocket on " + ip + "" + port)
						break
					}
				}
			}()

		}()
	}
	setupSysTray()
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
    <input name="pause" type="checkbox" value="pause" id="myCheck"/> Pause

</form>

`
<commit_msg>Be sure we have a comma + space separated list<commit_after>// Version 1.82
// Supports Windows, Linux, Mac, and Raspberry Pi, Beagle Bone Black

package main

import (
	"flag"
	"os"
	"os/user"
	"path/filepath"
	"runtime/debug"
	"strconv"
	"text/template"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/carlescere/scheduler"
	"github.com/gin-gonic/gin"
	"github.com/itsjamie/gin-cors"
	"github.com/kardianos/osext"
	"github.com/vharitonsky/iniflags"
	//"github.com/sanbornm/go-selfupdate/selfupdate" #included in update.go to change heavily
)

var (
	version              = "x.x.x-dev" //don't modify it, Jenkins will take care
	git_revision         = "xxxxxxxx"  //don't modify it, Jenkins will take care
	embedded_autoupdate  = true
	embedded_autoextract = false
	hibernate            = flag.Bool("hibernate", false, "start hibernated")
	verbose              = flag.Bool("v", true, "show debug logging")
	//verbose = flag.Bool("v", false, "show debug logging")
	isLaunchSelf = flag.Bool("ls", false, "launch self 5 seconds later")
	configIni    = flag.String("configFile", "config.ini", "config file path")
	regExpFilter = flag.String("regex", "usb|acm|com", "Regular expression to filter serial port list")
	gcType       = flag.String("gc", "std", "Type of garbage collection. std = Normal garbage collection allowing system to decide (this has been known to cause a stop the world in the middle of a CNC job which can cause lost responses from the CNC controller and thus stalled jobs. use max instead to solve.), off = let memory grow unbounded (you have to send in the gc command manually to garbage collect or you will run out of RAM eventually), max = Force garbage collection on each recv or send on a serial port (this minimizes stop the world events and thus lost serial responses, but increases CPU usage)")
	logDump      = flag.String("log", "off", "off = (default)")
	// hostname. allow user to override, otherwise we look it up
	hostname       = flag.String("hostname", "unknown-hostname", "Override the hostname we get from the OS")
	updateUrl      = flag.String("updateUrl", "", "")
	appName        = flag.String("appName", "", "")
	globalToolsMap = make(map[string]string)
	tempToolsPath  = createToolsDir()
	port           string
	portSSL        string
	origins        = flag.String("origins", "", "Allowed origin list for CORS")
)

type NullWriter int

func (NullWriter) Write([]byte) (int, error) { return 0, nil }

type logWriter struct{}

func (u *logWriter) Write(p []byte) (n int, err error) {
	h.broadcastSys <- p
	return len(p), nil
}

var logger_ws logWriter

func createToolsDir() string {
	usr, _ := user.Current()
	return usr.HomeDir + "/.arduino-create"
}

func homeHandler(c *gin.Context) {
	homeTemplate.Execute(c.Writer, c.Request.Host)
}

func launchSelfLater() {
	log.Println("Going to launch myself 2 seconds later.")
	time.Sleep(2 * 1000 * time.Millisecond)
	log.Println("Done waiting 2 secs. Now launching...")
}

func main() {

	flag.Parse()

	if *hibernate == false {

		go func() {

			// autoextract self
			src, _ := osext.Executable()
			dest := filepath.Dir(src)

			os.Mkdir(tempToolsPath, 0777)
			hideFile(tempToolsPath)

			if embedded_autoextract {
				// save the config.ini (if it exists)
				if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
					log.Println("First run, unzipping self")
					err := Unzip(src, dest)
					log.Println("Self extraction, err:", err)
				}

				if _, err := os.Stat(dest + "/" + *configIni); os.IsNotExist(err) {
					flag.Parse()
					log.Println("No config.ini at", *configIni)
				} else {
					flag.Parse()
					flag.Set("config", dest+"/"+*configIni)
					iniflags.Parse()
				}
			} else {
				flag.Set("config", dest+"/"+*configIni)
				iniflags.Parse()
			}

			// move CORS to config file compatibility, Vagrant version
			if *origins == "" {
				log.Println("Patching config.ini for compatibility")
				f, err := os.OpenFile(dest+"/"+*configIni, os.O_APPEND|os.O_WRONLY, 0666)
				if err != nil {
					panic(err)
				}
				_, err = f.WriteString("\norigins = http://webide.arduino.cc:8080\n")
				if err != nil {
					panic(err)
				}
				f.Close()
				restart("")
			}
			//log.SetFormatter(&log.JSONFormatter{})

			log.SetLevel(log.InfoLevel)

			log.SetOutput(os.Stderr)

			// see if we are supposed to wait 5 seconds
			if *isLaunchSelf {
				launchSelfLater()
			}

			if embedded_autoupdate {

				var updater = &Updater{
					CurrentVersion: version,
					ApiURL:         *updateUrl,
					BinURL:         *updateUrl,
					DiffURL:        "",
					Dir:            "update/",
					CmdName:        *appName,
				}

				if updater != nil {
					updater_job := func() {
						go updater.BackgroundRun()
					}
					scheduler.Every(5).Minutes().Run(updater_job)
				}
			}

			log.Println("Version:" + version)

			// hostname
			hn, _ := os.Hostname()
			if *hostname == "unknown-hostname" {
				*hostname = hn
			}
			log.Println("Hostname:", *hostname)

			// turn off garbage collection
			// this is dangerous, as u could overflow memory
			//if *isGC {
			if *gcType == "std" {
				log.Println("Garbage collection is on using Standard mode, meaning we just let Golang determine when to garbage collect.")
			} else if *gcType == "max" {
				log.Println("Garbage collection is on for MAXIMUM real-time collecting on each send/recv from serial port. Higher CPU, but less stopping of the world to garbage collect since it is being done on a constant basis.")
			} else {
				log.Println("Garbage collection is off. Memory use will grow unbounded. You WILL RUN OUT OF RAM unless you send in the gc command to manually force garbage collection. Lower CPU, but progressive memory footprint.")
				debug.SetGCPercent(-1)
			}

			// see if they provided a regex filter
			if len(*regExpFilter) > 0 {
				log.Printf("You specified a serial port regular expression filter: %v\n", *regExpFilter)
			}

			// list serial ports
			portList, _ := GetList(false)
			log.Println("Your serial ports:")
			if len(portList) == 0 {
				log.Println("\tThere are no serial ports to list.")
			}
			for _, element := range portList {
				log.Printf("\t%v\n", element)

			}

			if !*verbose {
				log.Println("You can enter verbose mode to see all logging by starting with the -v command line switch.")
				log.SetOutput(new(NullWriter)) //route all logging to nullwriter
			}

			// launch the hub routine which is the singleton for the websocket server
			go h.run()
			// launch our serial port routine
			go sh.run()
			// launch our dummy data routine
			//go d.run()

			go discoverLoop()

			r := gin.New()

			socketHandler := wsHandler().ServeHTTP

			extraOriginStr := "https://create.arduino.cc, http://create.arduino.cc, https://create-dev.arduino.cc, http://create-dev.arduino.cc, http://create-staging.arduino.cc, https://create-staging.arduino.cc"

			for i := 8990; i < 9001; i++ {
				extraOriginStr = extraOriginStr + ", http://localhost:" + strconv.Itoa(i) + ", https://localhost:" + strconv.Itoa(i)
			}

			r.Use(cors.Middleware(cors.Config{
				Origins:         *origins + ", " + extraOriginStr,
				Methods:         "GET, PUT, POST, DELETE",
				RequestHeaders:  "Origin, Authorization, Content-Type",
				ExposedHeaders:  "",
				MaxAge:          50 * time.Second,
				Credentials:     true,
				ValidateHeaders: false,
			}))

			r.GET("/", homeHandler)
			r.POST("/upload", uploadHandler)
			r.GET("/socket.io/", socketHandler)
			r.POST("/socket.io/", socketHandler)
			r.Handle("WS", "/socket.io/", socketHandler)
			r.Handle("WSS", "/socket.io/", socketHandler)
			r.GET("/info", infoHandler)
			go func() {
				start := 8990
				end := 9000
				i := start
				for i < end {
					i = i + 1
					portSSL = ":" + strconv.Itoa(i)
					if err := r.RunTLS(portSSL, filepath.Join(dest, "cert.pem"), filepath.Join(dest, "key.pem")); err != nil {
						log.Printf("Error trying to bind to port: %v, so exiting...", err)
						continue
					} else {
						ip := "0.0.0.0"
						log.Print("Starting server and websocket (SSL) on " + ip + "" + port)
						break
					}
				}
			}()

			go func() {
				start := 8990
				end := 9000
				i := start
				for i < end {
					i = i + 1
					port = ":" + strconv.Itoa(i)
					if err := r.Run(port); err != nil {
						log.Printf("Error trying to bind to port: %v, so exiting...", err)
						continue
					} else {
						ip := "0.0.0.0"
						log.Print("Starting server and websocket on " + ip + "" + port)
						break
					}
				}
			}()

		}()
	}
	setupSysTray()
}

var homeTemplate = template.Must(template.New("home").Parse(homeTemplateHtml))

// If you navigate to this server's homepage, you'll get this HTML
// so you can directly interact with the serial port server
const homeTemplateHtml = `<!DOCTYPE html>

<title>Serial Port Example</title>

<form id="form">
    <input type="submit" value="Send" />
    <input type="text" id="msg" size="64"/>
    <input name="pause" type="checkbox" value="pause" id="myCheck"/> Pause

</form>

`
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	term "github.com/nsf/termbox-go"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	err := term.Init()
	check(err)
	defer term.Close()

	pwd, err := os.Getwd()
	check(err)
	var st state
	st.setPath(pwd)
	st.render()
	for st.input() {
		st.render()
	}

	f, err := os.Create("/tmp/nav-path")
	check(err)
	defer f.Close()
	f.WriteString(st.getPath(false))
}

type state struct {
	path   []component
	buffer []rune
}

type component struct {
	entries   []entry
	matches   []int
	selection int
	width     int
	err       error
}

type entry struct {
	name      []rune
	isMatched bool
}

func (c *component) next() {
	c.selection++
	if c.selection >= len(c.matches) {
		c.selection = 0
	}
}

func (c *component) prev() {
	c.selection--
	if c.selection < 0 {
		c.selection = len(c.matches) - 1
	}
}

func (c component) isValid() bool {
	return c.selection >= 0 && c.selection < len(c.matches)
}

func (c component) getSelected() *entry {
	if c.selection < 0 {
		return nil
	}
	return &c.entries[c.matches[c.selection]]
}

func (c *component) list(path string) {
	c.entries = nil
	infos, err := ioutil.ReadDir(path)
	if err != nil {
		c.err = err
		c.width = len([]rune(err.Error()))
		return
	}
	for _, info := range infos {
		e := entry{
			name: []rune(info.Name()),
		}
		c.entries = append(c.entries, e)
	}
	c.selection = -1
	if len(c.matches) > 0 {
		c.selection = 0
	}
	// determine display width
	WIDTH_MIN := 8
	WIDTH_MAX := 25
	c.width = WIDTH_MIN
	for i := range c.entries {
		w := len(c.entries[i].name)
		if w <= WIDTH_MAX && w > c.width {
			c.width = w
		}
	}
}

func (c *component) filter(pattern []rune) {
	oldSelection := -1
	if c.selection < 0 {
	}
	if len(c.matches) > 0 {
		if c.selection < 0 {
			c.selection = 0
		}
		oldSelection = c.matches[c.selection]
	}
	c.matches = nil
	newSelection := -1
	for i := range c.entries {
		entry := &c.entries[i]
		entry.isMatched = strings.HasPrefix(string(entry.name), string(pattern))
		if entry.isMatched {
			if newSelection == -1 && oldSelection <= i {
				newSelection = len(c.matches)
			}
			c.matches = append(c.matches, i)
		}
	}
	if len(c.matches) > 0 && newSelection == -1 {
		newSelection = len(c.matches) - 1
	}
	c.selection = newSelection
}

func (c *component) commonPrefix() []rune {
	var cp []rune
	if len(c.matches) > 0 {
		cpLen := len(c.entries[c.matches[0]].name)
		for _, idx := range c.matches {
			name := c.entries[idx].name
			if len(name) > cpLen {
				cpLen = len(name)
			}
		}
		for i := 0; i < cpLen; i++ {
			ch := c.entries[c.matches[0]].name[i]
			for _, idx := range c.matches {
				name := c.entries[idx].name
				if ch != name[i] {
					return cp
				}
			}
			cp = append(cp, ch)
		}
	}
	return cp
}

func (st state) getPath(appendBuffer bool) string {
	if len(st.path) == 0 {
		return "/"
	}
	var buffer bytes.Buffer
	for _, component := range st.path[0 : len(st.path)-1] {
		// TODO: turn absolute path into one relative to the current dir
		// needed for better behavior w.r.t. access rights
		buffer.WriteRune('/')
		buffer.WriteString(string(component.getSelected().name))
	}
	if appendBuffer {
		buffer.WriteRune('/')
		buffer.WriteString(string(st.buffer))
	}
	return buffer.String()
}

func (st *state) setPath(path string) {
	absPath, err := filepath.Abs(path)
	check(err)
	parts := strings.Split(absPath, "/")
	cursor := "/"
	st.path = nil
	for i, part := range parts {
		if i > 0 {
			for j, entry := range st.path[i-1].entries {
				if string(entry.name) == part {
					st.path[i-1].selection = j
					break
				}
			}
		}
		cursor = filepath.Join(cursor, part)
		var c component
		c.list(cursor)
		c.filter(nil)
		st.path = append(st.path, c)
	}
}

func (st state) getCurrent() *component {
	return &st.path[len(st.path)-1]
}

func (st *state) push() {
	if st.getCurrent().isValid() {
		st.buffer = nil
		st.getCurrent().filter(nil)
		st.path = append(st.path, component{})
		st.getCurrent().list(st.getPath(false))
		st.getCurrent().filter(nil)
	}
}

func (st *state) pop() {
	if len(st.path) > 1 {
		st.path = st.path[0 : len(st.path)-1]
		st.buffer = nil
		st.getCurrent().filter(nil)
	}
}

func (st *state) insertChar(ch rune) {
	st.buffer = append(st.buffer, ch)
	st.getCurrent().filter(st.buffer)
}

func (st *state) deleteChar() {
	st.buffer = st.buffer[0 : len(st.buffer)-1]
	st.getCurrent().filter(st.buffer)
}

func (st *state) input() bool {
	event := term.PollEvent()
	switch event.Type {
	case term.EventKey:
		switch event.Ch {
		case 0:
			switch event.Key {
			case term.KeyEsc:
				return false
			case term.KeyArrowLeft:
				st.pop()
			case term.KeyArrowDown:
				if st.getCurrent().isValid() {
					st.getCurrent().next()
				}
			case term.KeyArrowUp:
				if st.getCurrent().isValid() {
					st.getCurrent().prev()
				}
			case term.KeyBackspace, term.KeyBackspace2, term.KeyDelete:
				if len(st.buffer) > 0 {
					st.deleteChar()
				} else {
					st.pop()
				}
			case term.KeyArrowRight:
				st.push()
			case term.KeyTab:
				if len(st.getCurrent().matches) == 1 {
					st.push()
				} else {
					st.buffer = st.getCurrent().commonPrefix()
					st.getCurrent().filter(st.buffer)
				}
			}
		default:
			st.insertChar(event.Ch)
		}
	case term.EventResize:
	case term.EventMouse:
	case term.EventError:
	}
	return true
}

func (st state) render() {
	term.Clear(term.ColorDefault, term.ColorDefault)
	// columns
	_, height := term.Size()
	baseX := 0
	for i, comp := range st.path {
		if comp.err != nil {
			fg, bg := term.ColorWhite, term.ColorRed
			msg := []rune(comp.err.Error())
			for y := 0; y < height-1; y++ {
				for x := 0; x < comp.width; x++ {
					ch := msg[x]
					term.SetCell(baseX+x, 1+y, ch, fg, bg)
				}
			}
		} else {
			for y := 0; y < height-1; y++ {
				var line []rune
				fg, bg := term.ColorBlack, term.ColorBlue
				if y < len(comp.entries) {
					line = comp.entries[y].name
					if !comp.entries[y].isMatched {
						fg = term.ColorMagenta
					}
				}
				if i&1 == 0 {
					bg = term.ColorGreen
				}
				if comp.selection >= 0 && y == comp.matches[comp.selection] {
					bg = term.ColorWhite
				}
				for x := 0; x < comp.width; x++ {
					ch := ' '
					if x < len(line) {
						ch = line[x]
					}
					term.SetCell(baseX+x, 1+y, ch, fg, bg)
				}
			}
		}
		baseX += comp.width
	}
	// path
	path := st.getPath(true)
	var x int
	for _, ch := range path {
		term.SetCell(x, 0, ch, term.ColorDefault, term.ColorDefault)
		x++
	}
	term.SetCursor(x, 0)
	term.Flush()
}
<commit_msg>refactor: better names, push -> descend, pop -> ascend<commit_after>package main

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	term "github.com/nsf/termbox-go"
)

func check(err error) {
	if err != nil {
		panic(err)
	}
}

func main() {
	err := term.Init()
	check(err)
	defer term.Close()

	pwd, err := os.Getwd()
	check(err)
	var st state
	st.setPath(pwd)
	st.render()
	for st.input() {
		st.render()
	}

	f, err := os.Create("/tmp/nav-path")
	check(err)
	defer f.Close()
	f.WriteString(st.getPath(false))
}

type state struct {
	path   []component
	buffer []rune
}

type component struct {
	entries   []entry
	matches   []int
	selection int
	width     int
	err       error
}

type entry struct {
	name      []rune
	isMatched bool
}

func (c *component) next() {
	c.selection++
	if c.selection >= len(c.matches) {
		c.selection = 0
	}
}

func (c *component) prev() {
	c.selection--
	if c.selection < 0 {
		c.selection = len(c.matches) - 1
	}
}

func (c component) isValid() bool {
	return c.selection >= 0 && c.selection < len(c.matches)
}

func (c component) getSelected() *entry {
	if c.selection < 0 {
		return nil
	}
	return &c.entries[c.matches[c.selection]]
}

func (c *component) list(path string) {
	c.entries = nil
	infos, err := ioutil.ReadDir(path)
	if err != nil {
		c.err = err
		c.width = len([]rune(err.Error()))
		return
	}
	for _, info := range infos {
		e := entry{
			name: []rune(info.Name()),
		}
		c.entries = append(c.entries, e)
	}
	c.selection = -1
	if len(c.matches) > 0 {
		c.selection = 0
	}
	// determine display width
	WIDTH_MIN := 8
	WIDTH_MAX := 25
	c.width = WIDTH_MIN
	for i := range c.entries {
		w := len(c.entries[i].name)
		if w <= WIDTH_MAX && w > c.width {
			c.width = w
		}
	}
}

func (c *component) filter(pattern []rune) {
	oldSelection := -1
	if c.selection < 0 {
	}
	if len(c.matches) > 0 {
		if c.selection < 0 {
			c.selection = 0
		}
		oldSelection = c.matches[c.selection]
	}
	c.matches = nil
	newSelection := -1
	for i := range c.entries {
		entry := &c.entries[i]
		entry.isMatched = strings.HasPrefix(string(entry.name), string(pattern))
		if entry.isMatched {
			if newSelection == -1 && oldSelection <= i {
				newSelection = len(c.matches)
			}
			c.matches = append(c.matches, i)
		}
	}
	if len(c.matches) > 0 && newSelection == -1 {
		newSelection = len(c.matches) - 1
	}
	c.selection = newSelection
}

func (c *component) commonPrefix() []rune {
	var cp []rune
	if len(c.matches) > 0 {
		cpLen := len(c.entries[c.matches[0]].name)
		for _, idx := range c.matches {
			name := c.entries[idx].name
			if len(name) > cpLen {
				cpLen = len(name)
			}
		}
		for i := 0; i < cpLen; i++ {
			ch := c.entries[c.matches[0]].name[i]
			for _, idx := range c.matches {
				name := c.entries[idx].name
				if ch != name[i] {
					return cp
				}
			}
			cp = append(cp, ch)
		}
	}
	return cp
}

func (st state) getPath(appendBuffer bool) string {
	if len(st.path) == 0 {
		return "/"
	}
	var buffer bytes.Buffer
	for _, component := range st.path[0 : len(st.path)-1] {
		// TODO: turn absolute path into one relative to the current dir
		// needed for better behavior w.r.t. access rights
		buffer.WriteRune('/')
		buffer.WriteString(string(component.getSelected().name))
	}
	if appendBuffer {
		buffer.WriteRune('/')
		buffer.WriteString(string(st.buffer))
	}
	return buffer.String()
}

func (st *state) setPath(path string) {
	absPath, err := filepath.Abs(path)
	check(err)
	parts := strings.Split(absPath, "/")
	cursor := "/"
	st.path = nil
	for i, part := range parts {
		if i > 0 {
			for j, entry := range st.path[i-1].entries {
				if string(entry.name) == part {
					st.path[i-1].selection = j
					break
				}
			}
		}
		cursor = filepath.Join(cursor, part)
		var c component
		c.list(cursor)
		c.filter(nil)
		st.path = append(st.path, c)
	}
}

func (st state) getCurrent() *component {
	return &st.path[len(st.path)-1]
}

func (st *state) descend() {
	if st.getCurrent().isValid() {
		st.buffer = nil
		st.getCurrent().filter(nil)
		st.path = append(st.path, component{})
		st.getCurrent().list(st.getPath(false))
		st.getCurrent().filter(nil)
	}
}

func (st *state) ascend() {
	if len(st.path) > 1 {
		st.path = st.path[0 : len(st.path)-1]
		st.buffer = nil
		st.getCurrent().filter(nil)
	}
}

func (st *state) insertChar(ch rune) {
	st.buffer = append(st.buffer, ch)
	st.getCurrent().filter(st.buffer)
}

func (st *state) deleteChar() {
	st.buffer = st.buffer[0 : len(st.buffer)-1]
	st.getCurrent().filter(st.buffer)
}

func (st *state) input() bool {
	event := term.PollEvent()
	switch event.Type {
	case term.EventKey:
		switch event.Ch {
		case 0:
			switch event.Key {
			case term.KeyEsc:
				return false
			case term.KeyArrowLeft:
				st.ascend()
			case term.KeyArrowDown:
				if st.getCurrent().isValid() {
					st.getCurrent().next()
				}
			case term.KeyArrowUp:
				if st.getCurrent().isValid() {
					st.getCurrent().prev()
				}
			case term.KeyBackspace, term.KeyBackspace2, term.KeyDelete:
				if len(st.buffer) > 0 {
					st.deleteChar()
				} else {
					st.ascend()
				}
			case term.KeyArrowRight:
				st.descend()
			case term.KeyTab:
				if len(st.getCurrent().matches) == 1 {
					st.descend()
				} else {
					st.buffer = st.getCurrent().commonPrefix()
					st.getCurrent().filter(st.buffer)
				}
			}
		default:
			st.insertChar(event.Ch)
		}
	case term.EventResize:
	case term.EventMouse:
	case term.EventError:
	}
	return true
}

func (st state) render() {
	term.Clear(term.ColorDefault, term.ColorDefault)
	// columns
	_, height := term.Size()
	baseX := 0
	for i, comp := range st.path {
		if comp.err != nil {
			fg, bg := term.ColorWhite, term.ColorRed
			msg := []rune(comp.err.Error())
			for y := 0; y < height-1; y++ {
				for x := 0; x < comp.width; x++ {
					ch := msg[x]
					term.SetCell(baseX+x, 1+y, ch, fg, bg)
				}
			}
		} else {
			for y := 0; y < height-1; y++ {
				var line []rune
				fg, bg := term.ColorBlack, term.ColorBlue
				if y < len(comp.entries) {
					line = comp.entries[y].name
					if !comp.entries[y].isMatched {
						fg = term.ColorMagenta
					}
				}
				if i&1 == 0 {
					bg = term.ColorGreen
				}
				if comp.selection >= 0 && y == comp.matches[comp.selection] {
					bg = term.ColorWhite
				}
				for x := 0; x < comp.width; x++ {
					ch := ' '
					if x < len(line) {
						ch = line[x]
					}
					term.SetCell(baseX+x, 1+y, ch, fg, bg)
				}
			}
		}
		baseX += comp.width
	}
	// path
	path := st.getPath(true)
	var x int
	for _, ch := range path {
		term.SetCell(x, 0, ch, term.ColorDefault, term.ColorDefault)
		x++
	}
	term.SetCursor(x, 0)
	term.Flush()
}
<|endoftext|>


<commit_before>// Package main is the main package
package main

import (
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/fekle/simplewebwatcher/config"

	"time"

	"github.com/everdev/mack"
	"github.com/skratchdot/open-golang/open"
)

func main() {

	// set max procs to cpu count
	runtime.GOMAXPROCS(runtime.NumCPU())

	// determine home directory
	var userHome string
	if runtime.GOOS == "windows" {
		userHome = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if userHome == "" {
			userHome = os.Getenv("USERPROFILE")
		}
	} else {
		userHome = os.Getenv("HOME")
	}

	// create paths
	homePath := filepath.Join(userHome, ".simplewebwatcher")
	configPath := filepath.Join(homePath, "config")

	// create application home directory, if not exists
	handleFatalError(os.MkdirAll(homePath, 0700))

	// chdir to the application home path
	handleFatalError(os.Chdir(homePath))

	// check if Working Directory is valid
	{
		cwd, err := os.Getwd()
		handleFatalError(err)
		if cwd != homePath {
			handleFatalError(errors.New("wrong pwd"))
		}
	}

	// check if config exists
	{
		if _, err := os.Stat(configPath); os.IsNotExist(err) {
			// no config found - crete new default config and exit

			log.Println("config not found, creating new default config at", configPath)

			configFile, err := os.Create(configPath)
			defer configFile.Close()

			handleFatalError(err)

			handleFatalError(config.WriteConfig(config.NewDefaultConfig(), configFile))

			log.Println("default config created - please edit")

			return
		}
	}

	// variable for config
	var safeConfig *config.ThreadSafeConfigWrapper

	// read config
	{
		log.Println("reading config from", configPath)
		configFile, err := os.Open(configPath)
		defer configFile.Close()
		handleFatalError(err)

		configBytes, err := ioutil.ReadAll(configFile)

		handleFatalError(err)

		tmpConfig, err := config.ReadConfig(string(configBytes))

		handleFatalError(err)

		// create and initialize new threadsafeconfig
		safeConfig = new(config.ThreadSafeConfigWrapper)
		safeConfig.Set(*tmpConfig)
	}

	// create sync waitgroup
	waitGroup := new(sync.WaitGroup)

	// iterate through configured sites and spawn a gouroutine for each one
	for i := range safeConfig.Get().Site {
		waitGroup.Add(1)
		go doCheck(safeConfig, i, waitGroup, homePath)
	}

	// wait for all checks to finish
	waitGroup.Wait()

	// write new configuration
	{

		configFile, err := os.OpenFile(configPath, os.O_RDWR, 0700)
		defer configFile.Close()
		handleFatalError(err)

		newConf := safeConfig.Get()

		log.Println("updating config file")

		handleFatalError(config.WriteConfig(&newConf, configFile))

	}

}

func doCheck(safeConfig *config.ThreadSafeConfigWrapper, pos int, wg *sync.WaitGroup, dir string) {
	defer wg.Done()

	// copy site config
	siteConfig := safeConfig.Get().Site[pos]

	// create new http client
	webClient := &http.Client{}

	// configure request
	req, err := http.NewRequest("GET", siteConfig.URL, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// if set, configure http basic auth
	if siteConfig.Password != "" && len(siteConfig.Password) > 0 && siteConfig.Username != "" && len(siteConfig.Username) > 0 {
		req.SetBasicAuth(siteConfig.Username, siteConfig.Password)
	}

	// execute request
	resp, err := webClient.Do(req)
	defer resp.Body.Close()
	if err != nil {
		log.Println(err)
		return
	}

	// read body and determine size
	body, err := ioutil.ReadAll(resp.Body)
	size := binary.Size(body)

	// determine sha1 hash
	var hash string
	{
		hasher := sha1.New()
		_, err := hasher.Write(body)

		if err != nil {
			log.Println(err)
			return
		}

		hash = hex.EncodeToString(hasher.Sum(nil))
	}

	// compare size and hash to stored data
	if size != siteConfig.LastBytes || hash != siteConfig.LastHash {
		// announce match
		log.Println(siteConfig.Description, " | ", siteConfig.LastBytes, "->", size, " | ", siteConfig.LastHash, "->", hash, " | ", "change detected")

		// set options for alert, and execute it - OSX ONLY
		moptions := mack.AlertOptions{
			Title:         "CIS Notifier",
			Message:       "Change detected for " + siteConfig.Description,
			Style:         "informational",
			Buttons:       "Open",
			DefaultButton: "Open",
			Duration:      0,
		}
		if _, err = mack.AlertBox(moptions); err != nil {
			log.Println(err)
			return
		}

		// open site in browser
		open.Run(siteConfig.URL)

		// update current site config
		siteConfig.LastBytes = size
		siteConfig.LastHash = hash
		siteConfig.LastCheck = time.Now()

		// write new site config to safe config
		safeConfig.SetSite(pos, siteConfig)

	} else {
		// announce mismatch
		log.Println(siteConfig.Description, " | ", siteConfig.LastBytes, "->", size, " | ", siteConfig.LastHash, "->", hash, " | ", "no change detected")
	}
}

func handleFatalError(err error) {
	if err != nil {
		log.Fatalln("FATAL ERROR:", err)
	}
}
<commit_msg>add logging<commit_after>// Package main is the main package
package main

import (
	"crypto/sha1"
	"encoding/binary"
	"encoding/hex"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"sync"

	"github.com/fekle/simplewebwatcher/config"

	"time"

	"io"

	"github.com/everdev/mack"
	"github.com/skratchdot/open-golang/open"
)

func main() {

	// set max procs to cpu count
	runtime.GOMAXPROCS(runtime.NumCPU())

	// determine home directory
	var userHome string
	if runtime.GOOS == "windows" {
		userHome = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
		if userHome == "" {
			userHome = os.Getenv("USERPROFILE")
		}
	} else {
		userHome = os.Getenv("HOME")
	}

	// create paths
	homePath := filepath.Join(userHome, ".simplewebwatcher")
	configPath := filepath.Join(homePath, "config")
	logPath := filepath.Join(homePath, "log")

	// create application home directory, if not exists
	handleFatalError(os.MkdirAll(homePath, 0700))

	// chdir to the application home path
	handleFatalError(os.Chdir(homePath))

	{
		logFile, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0700)
		if err != nil {
			log.Fatal("error opening file:", err)
		}
		defer logFile.Close()

		log.SetOutput(io.MultiWriter(logFile, os.Stdout))
	}

	// check if Working Directory is valid
	{
		cwd, err := os.Getwd()
		handleFatalError(err)
		if cwd != homePath {
			handleFatalError(errors.New("wrong pwd"))
		}
	}

	// check if config exists
	{
		if _, err := os.Stat(configPath); os.IsNotExist(err) {
			// no config found - crete new default config and exit

			log.Println("config not found, creating new default config at", configPath)

			configFile, err := os.Create(configPath)
			handleFatalError(err)
			defer configFile.Close()

			handleFatalError(config.WriteConfig(config.NewDefaultConfig(), configFile))

			log.Println("default config created - please edit")

			return
		}
	}

	// variable for config
	var safeConfig *config.ThreadSafeConfigWrapper

	// read config
	{
		log.Println("reading config from", configPath)
		configFile, err := os.Open(configPath)
		handleFatalError(err)
		defer configFile.Close()

		configBytes, err := ioutil.ReadAll(configFile)

		handleFatalError(err)

		tmpConfig, err := config.ReadConfig(string(configBytes))

		handleFatalError(err)

		// create and initialize new threadsafeconfig
		safeConfig = new(config.ThreadSafeConfigWrapper)
		safeConfig.Set(*tmpConfig)
	}

	// create sync waitgroup
	waitGroup := new(sync.WaitGroup)

	// iterate through configured sites and spawn a gouroutine for each one
	for i := range safeConfig.Get().Site {
		waitGroup.Add(1)
		go doCheck(safeConfig, i, waitGroup, homePath)
	}

	// wait for all checks to finish
	waitGroup.Wait()

	// write new configuration
	{

		configFile, err := os.OpenFile(configPath, os.O_RDWR, 0700)
		defer configFile.Close()
		handleFatalError(err)

		newConf := safeConfig.Get()

		log.Println("updating config file")

		handleFatalError(config.WriteConfig(&newConf, configFile))

	}

}

func doCheck(safeConfig *config.ThreadSafeConfigWrapper, pos int, wg *sync.WaitGroup, dir string) {
	defer wg.Done()

	// copy site config
	siteConfig := safeConfig.Get().Site[pos]

	// create new http client
	webClient := &http.Client{}

	// configure request
	req, err := http.NewRequest("GET", siteConfig.URL, nil)
	if err != nil {
		log.Println(err)
		return
	}

	// if set, configure http basic auth
	if siteConfig.Password != "" && len(siteConfig.Password) > 0 && siteConfig.Username != "" && len(siteConfig.Username) > 0 {
		req.SetBasicAuth(siteConfig.Username, siteConfig.Password)
	}

	// execute request
	resp, err := webClient.Do(req)
	if err != nil {
		log.Println(err)

		moptions := mack.AlertOptions{
			Title:         "CIS Notifier",
			Message:       "Site Error for " + siteConfig.Description + ": " + err.Error(),
			Style:         "informational",
			Buttons:       "Open",
			DefaultButton: "Open",
			Duration:      0,
		}
		if _, err = mack.AlertBox(moptions); err != nil {
			log.Println(err)
			return
		}

		return
	}
	defer resp.Body.Close()

	// read body and determine size
	body, err := ioutil.ReadAll(resp.Body)
	size := binary.Size(body)

	// determine sha1 hash
	var hash string
	{
		hasher := sha1.New()
		_, err := hasher.Write(body)

		if err != nil {
			log.Println(err)
			return
		}

		hash = hex.EncodeToString(hasher.Sum(nil))
	}

	// compare size and hash to stored data
	if size != siteConfig.LastBytes || hash != siteConfig.LastHash {
		// announce match
		log.Println(siteConfig.Description, " | ", siteConfig.LastBytes, "->", size, " | ", siteConfig.LastHash, "->", hash, " | ", "change detected")

		// set options for alert, and execute it - OSX ONLY
		moptions := mack.AlertOptions{
			Title:         "CIS Notifier",
			Message:       "Change detected for " + siteConfig.Description,
			Style:         "informational",
			Buttons:       "Open",
			DefaultButton: "Open",
			Duration:      0,
		}
		if _, err = mack.AlertBox(moptions); err != nil {
			log.Println(err)
			return
		}

		// open site in browser
		open.Run(siteConfig.URL)

		// update current site config
		siteConfig.LastBytes = size
		siteConfig.LastHash = hash
		siteConfig.LastCheck = time.Now()

		// write new site config to safe config
		safeConfig.SetSite(pos, siteConfig)

	} else {
		// announce mismatch
		log.Println(siteConfig.Description, " | ", siteConfig.LastBytes, "->", size, " | ", siteConfig.LastHash, "->", hash, " | ", "no change detected")
	}
}

func handleFatalError(err error) {
	if err != nil {
		log.Fatalln("FATAL ERROR:", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
)

const namespace = "aurora"

var (
	addr       = flag.String("web.listen-address", ":9113", "Address to listen on for web interface and telemetry.")
	auroraURL  = flag.String("exporter.aurora-url", "http://127.0.0.1:8081", "URL to an Aurora scheduler")
	metricPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
)

var noLables = []string{}

var httpClient = http.Client{
	Transport: &http.Transport{
		MaxIdleConnsPerHost:   2,
		ResponseHeaderTimeout: 10 * time.Second,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 10 * time.Second,
		}).Dial,
	},
}

type exporter struct {
	sync.Mutex
	f        finder
	errors   prometheus.Counter
	duration prometheus.Gauge
}

func newAuroraExporter(f finder) *exporter {
	return &exporter{
		f: f,
		errors: prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "exporter_scrape_errors_total",
				Help:      "Total scrape errors",
			}),
		duration: prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "exporter_last_scrape_duration_seconds",
				Help:      "The last scrape duration",
			}),
	}
}

func (e *exporter) Describe(ch chan<- *prometheus.Desc) {
	ch <- e.duration.Desc()
	ch <- e.errors.Desc()
}

func (e *exporter) Collect(ch chan<- prometheus.Metric) {
	e.Lock()
	defer e.Unlock()

	metricsChan := make(chan prometheus.Metric)
	go e.scrape(metricsChan)

	for metric := range metricsChan {
		ch <- metric
	}

	ch <- e.errors
	ch <- e.duration
}

func (e *exporter) scrape(ch chan<- prometheus.Metric) {
	defer close(ch)

	recordErr := func(err error) {
		glog.Warning(err)
		e.errors.Inc()
	}

	url, err := e.f.leaderURL()
	if err != nil {
		recordErr(err)
		return
	}

	varsURL := fmt.Sprintf("%s/vars.json", url)
	resp, err := httpClient.Get(varsURL)
	if err != nil {
		recordErr(err)
		return
	}
	defer resp.Body.Close()

	var vars map[string]interface{}

	if err = json.NewDecoder(resp.Body).Decode(&vars); err != nil {
		recordErr(err)
		return
	}

	for name, v := range vars {

		if desc, ok := counterMap[name]; ok {
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.CounterValue,
				v.(float64), noLables...,
			)
		}

		if desc, ok := gaugeMap[name]; ok {
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.GaugeValue,
				v.(float64), noLables...,
			)
		}

		if desc, ok := taskStateMap[name]; ok {
			label := strings.Split(name, "task_store_")[1]
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.GaugeValue,
				v.(float64), label,
			)
		}

		variableVars(ch, name, v)
	}
}

func main() {
	flag.Parse()

	finder, err := newFinder(*auroraURL)
	if err != nil {
		log.Fatal(err)
	}

	exporter := newAuroraExporter(finder)
	prometheus.MustRegister(exporter)

	http.Handle(*metricPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, *metricPath, http.StatusMovedPermanently)
	})

	glog.Info("starting aurora_exporter on ", *addr)

	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Track scrape durations<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/golang/glog"
	"github.com/prometheus/client_golang/prometheus"
)

const namespace = "aurora"

var (
	addr       = flag.String("web.listen-address", ":9113", "Address to listen on for web interface and telemetry.")
	auroraURL  = flag.String("exporter.aurora-url", "http://127.0.0.1:8081", "URL to an Aurora scheduler")
	metricPath = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
)

var noLables = []string{}

var httpClient = http.Client{
	Transport: &http.Transport{
		MaxIdleConnsPerHost:   2,
		ResponseHeaderTimeout: 10 * time.Second,
		Dial: (&net.Dialer{
			Timeout:   10 * time.Second,
			KeepAlive: 10 * time.Second,
		}).Dial,
	},
}

type exporter struct {
	sync.Mutex
	f        finder
	errors   prometheus.Counter
	duration prometheus.Gauge
}

func newAuroraExporter(f finder) *exporter {
	return &exporter{
		f: f,
		errors: prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "exporter_scrape_errors_total",
				Help:      "Total scrape errors",
			}),
		duration: prometheus.NewGauge(
			prometheus.GaugeOpts{
				Namespace: namespace,
				Name:      "exporter_last_scrape_duration_seconds",
				Help:      "The last scrape duration",
			}),
	}
}

func (e *exporter) Describe(ch chan<- *prometheus.Desc) {
	ch <- e.duration.Desc()
	ch <- e.errors.Desc()
}

func (e *exporter) Collect(ch chan<- prometheus.Metric) {
	e.Lock()
	defer e.Unlock()

	metricsChan := make(chan prometheus.Metric)
	go e.scrape(metricsChan)

	for metric := range metricsChan {
		ch <- metric
	}

	ch <- e.errors
	ch <- e.duration
}

func (e *exporter) scrape(ch chan<- prometheus.Metric) {
	defer close(ch)

	now := time.Now().UnixNano()
	defer func() {
		e.duration.Set(float64(time.Now().UnixNano()-now) / 1000000000)
	}()

	recordErr := func(err error) {
		glog.Warning(err)
		e.errors.Inc()
	}

	url, err := e.f.leaderURL()
	if err != nil {
		recordErr(err)
		return
	}

	varsURL := fmt.Sprintf("%s/vars.json", url)
	resp, err := httpClient.Get(varsURL)
	if err != nil {
		recordErr(err)
		return
	}
	defer resp.Body.Close()

	var vars map[string]interface{}

	if err = json.NewDecoder(resp.Body).Decode(&vars); err != nil {
		recordErr(err)
		return
	}

	for name, v := range vars {

		if desc, ok := counterMap[name]; ok {
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.CounterValue,
				v.(float64), noLables...,
			)
		}

		if desc, ok := gaugeMap[name]; ok {
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.GaugeValue,
				v.(float64), noLables...,
			)
		}

		if desc, ok := taskStateMap[name]; ok {
			label := strings.Split(name, "task_store_")[1]
			ch <- prometheus.MustNewConstMetric(
				desc,
				prometheus.GaugeValue,
				v.(float64), label,
			)
		}

		variableVars(ch, name, v)
	}
}

func main() {
	flag.Parse()

	finder, err := newFinder(*auroraURL)
	if err != nil {
		log.Fatal(err)
	}

	exporter := newAuroraExporter(finder)
	prometheus.MustRegister(exporter)

	http.Handle(*metricPath, prometheus.Handler())
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, *metricPath, http.StatusMovedPermanently)
	})

	glog.Info("starting aurora_exporter on ", *addr)

	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"

	. "github.com/candid82/joker/core"
	_ "github.com/candid82/joker/std/base64"
	_ "github.com/candid82/joker/std/json"
	_ "github.com/candid82/joker/std/os"
	_ "github.com/candid82/joker/std/string"
	"gopkg.in/readline.v1"
)

type (
	ReplContext struct {
		first  *Var
		second *Var
		third  *Var
		exc    *Var
	}
)

const VERSION = "v0.8.0"

func NewReplContext(env *Env) *ReplContext {
	first, _ := env.Resolve(MakeSymbol("joker.core/*1"))
	second, _ := env.Resolve(MakeSymbol("joker.core/*2"))
	third, _ := env.Resolve(MakeSymbol("joker.core/*3"))
	exc, _ := env.Resolve(MakeSymbol("joker.core/*e"))
	first.Value = NIL
	second.Value = NIL
	third.Value = NIL
	exc.Value = NIL
	return &ReplContext{
		first:  first,
		second: second,
		third:  third,
		exc:    exc,
	}
}

func (ctx *ReplContext) PushValue(obj Object) {
	ctx.third.Value = ctx.second.Value
	ctx.second.Value = ctx.first.Value
	ctx.first.Value = obj
}

func (ctx *ReplContext) PushException(exc Object) {
	ctx.exc.Value = exc
}

func processFile(filename string, phase Phase) error {
	var reader *Reader
	if filename == "--" {
		reader = NewReader(bufio.NewReader(os.Stdin), "<stdin>")
		filename = ""
	} else {
		f, err := os.Open(filename)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error: ", err)
			return err
		}
		reader = NewReader(bufio.NewReader(f), filename)
	}
	return ProcessReader(reader, filename, phase)
}

func skipRestOfLine(reader *Reader) {
	for {
		switch reader.Get() {
		case EOF, '\n':
			return
		}
	}
}

func processReplCommand(reader *Reader, phase Phase, parseContext *ParseContext, replContext *ReplContext) (exit bool) {

	defer func() {
		if r := recover(); r != nil {
			switch r := r.(type) {
			case *ParseError:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			case *EvalError:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			case Error:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			// case *runtime.TypeAssertionError:
			// 	fmt.Fprintln(os.Stderr, r)
			default:
				panic(r)
			}
		}
	}()

	obj, err := TryRead(reader)
	if err == io.EOF {
		return true
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		skipRestOfLine(reader)
		return
	}

	if phase == READ {
		fmt.Println(obj.ToString(true))
		return false
	}

	expr := Parse(obj, parseContext)
	if phase == PARSE {
		fmt.Println(expr)
		return false
	}

	res := Eval(expr, nil)
	replContext.PushValue(res)
	fmt.Println(res.ToString(true))
	return false
}

func repl(phase Phase) {
	fmt.Printf("Welcome to joker %s. Use ctrl-c to exit.\n", VERSION)
	parseContext := &ParseContext{GlobalEnv: GLOBAL_ENV}
	replContext := NewReplContext(parseContext.GlobalEnv)

	rl, err := readline.New("")
	if err != nil {
		fmt.Println("Error: " + err.Error())
	}
	defer rl.Close()

	reader := NewReader(NewLineRuneReader(rl), "<repl>")

	for {
		rl.SetPrompt(GLOBAL_ENV.CurrentNamespace().Name.ToString(false) + "=> ")
		if processReplCommand(reader, phase, parseContext, replContext) {
			return
		}
	}
}

func makeDialectKeyword(dialect Dialect) Keyword {
	switch dialect {
	case EDN:
		return MakeKeyword("clj")
	case CLJ:
		return MakeKeyword("clj")
	case CLJS:
		return MakeKeyword("cljs")
	default:
		return MakeKeyword("joker ")
	}
}

func configureLinterMode(dialect Dialect) {
	LINTER_MODE = true
	DIALECT = dialect
	lm, _ := GLOBAL_ENV.Resolve(MakeSymbol("joker.core/*linter-mode*"))
	lm.Value = Bool{B: true}
	GLOBAL_ENV.Features = GLOBAL_ENV.Features.Disjoin(MakeKeyword("joker")).Conj(makeDialectKeyword(dialect)).(Set)
	ProcessLinterData(dialect)
}

func detectDialect(filename string) Dialect {
	switch {
	case strings.HasSuffix(filename, ".edn"):
		return EDN
	case strings.HasSuffix(filename, ".cljs"):
		return CLJS
	case strings.HasSuffix(filename, ".joke"):
		return JOKER
	}
	return CLJ
}

func lintFile(filename string, dialect Dialect) {
	phase := PARSE
	if dialect == EDN {
		phase = READ
	}
	ReadConfig(filename)
	configureLinterMode(dialect)
	if processFile(filename, phase) == nil {
		WarnOnUnusedNamespaces()
		WarnOnUnusedVars()
	}
}

func main() {
	GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.CoreNamespace)
	if len(os.Args) == 1 {
		repl(EVAL)
		return
	}
	if len(os.Args) == 2 {
		if os.Args[1] == "-v" || os.Args[1] == "--version" {
			println(VERSION)
			return
		}
		processFile(os.Args[1], EVAL)
		return
	}
	switch os.Args[1] {
	case "--read":
		processFile(os.Args[2], READ)
	case "--parse":
		processFile(os.Args[2], PARSE)
	case "--lint":
		dialect := detectDialect(os.Args[2])
		lintFile(os.Args[2], dialect)
	case "--lintclj":
		lintFile(os.Args[2], CLJ)
	case "--lintcljs":
		lintFile(os.Args[2], CLJS)
	case "--lintjoker":
		lintFile(os.Args[2], JOKER)
	case "--lintedn":
		lintFile(os.Args[2], EDN)
	default:
		processFile(os.Args[1], EVAL)
	}
}
<commit_msg>v0.8.1<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"

	. "github.com/candid82/joker/core"
	_ "github.com/candid82/joker/std/base64"
	_ "github.com/candid82/joker/std/json"
	_ "github.com/candid82/joker/std/os"
	_ "github.com/candid82/joker/std/string"
	"gopkg.in/readline.v1"
)

type (
	ReplContext struct {
		first  *Var
		second *Var
		third  *Var
		exc    *Var
	}
)

const VERSION = "v0.8.1"

func NewReplContext(env *Env) *ReplContext {
	first, _ := env.Resolve(MakeSymbol("joker.core/*1"))
	second, _ := env.Resolve(MakeSymbol("joker.core/*2"))
	third, _ := env.Resolve(MakeSymbol("joker.core/*3"))
	exc, _ := env.Resolve(MakeSymbol("joker.core/*e"))
	first.Value = NIL
	second.Value = NIL
	third.Value = NIL
	exc.Value = NIL
	return &ReplContext{
		first:  first,
		second: second,
		third:  third,
		exc:    exc,
	}
}

func (ctx *ReplContext) PushValue(obj Object) {
	ctx.third.Value = ctx.second.Value
	ctx.second.Value = ctx.first.Value
	ctx.first.Value = obj
}

func (ctx *ReplContext) PushException(exc Object) {
	ctx.exc.Value = exc
}

func processFile(filename string, phase Phase) error {
	var reader *Reader
	if filename == "--" {
		reader = NewReader(bufio.NewReader(os.Stdin), "<stdin>")
		filename = ""
	} else {
		f, err := os.Open(filename)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error: ", err)
			return err
		}
		reader = NewReader(bufio.NewReader(f), filename)
	}
	return ProcessReader(reader, filename, phase)
}

func skipRestOfLine(reader *Reader) {
	for {
		switch reader.Get() {
		case EOF, '\n':
			return
		}
	}
}

func processReplCommand(reader *Reader, phase Phase, parseContext *ParseContext, replContext *ReplContext) (exit bool) {

	defer func() {
		if r := recover(); r != nil {
			switch r := r.(type) {
			case *ParseError:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			case *EvalError:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			case Error:
				replContext.PushException(r)
				fmt.Fprintln(os.Stderr, r)
			// case *runtime.TypeAssertionError:
			// 	fmt.Fprintln(os.Stderr, r)
			default:
				panic(r)
			}
		}
	}()

	obj, err := TryRead(reader)
	if err == io.EOF {
		return true
	}
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		skipRestOfLine(reader)
		return
	}

	if phase == READ {
		fmt.Println(obj.ToString(true))
		return false
	}

	expr := Parse(obj, parseContext)
	if phase == PARSE {
		fmt.Println(expr)
		return false
	}

	res := Eval(expr, nil)
	replContext.PushValue(res)
	fmt.Println(res.ToString(true))
	return false
}

func repl(phase Phase) {
	fmt.Printf("Welcome to joker %s. Use ctrl-c to exit.\n", VERSION)
	parseContext := &ParseContext{GlobalEnv: GLOBAL_ENV}
	replContext := NewReplContext(parseContext.GlobalEnv)

	rl, err := readline.New("")
	if err != nil {
		fmt.Println("Error: " + err.Error())
	}
	defer rl.Close()

	reader := NewReader(NewLineRuneReader(rl), "<repl>")

	for {
		rl.SetPrompt(GLOBAL_ENV.CurrentNamespace().Name.ToString(false) + "=> ")
		if processReplCommand(reader, phase, parseContext, replContext) {
			return
		}
	}
}

func makeDialectKeyword(dialect Dialect) Keyword {
	switch dialect {
	case EDN:
		return MakeKeyword("clj")
	case CLJ:
		return MakeKeyword("clj")
	case CLJS:
		return MakeKeyword("cljs")
	default:
		return MakeKeyword("joker ")
	}
}

func configureLinterMode(dialect Dialect) {
	LINTER_MODE = true
	DIALECT = dialect
	lm, _ := GLOBAL_ENV.Resolve(MakeSymbol("joker.core/*linter-mode*"))
	lm.Value = Bool{B: true}
	GLOBAL_ENV.Features = GLOBAL_ENV.Features.Disjoin(MakeKeyword("joker")).Conj(makeDialectKeyword(dialect)).(Set)
	ProcessLinterData(dialect)
}

func detectDialect(filename string) Dialect {
	switch {
	case strings.HasSuffix(filename, ".edn"):
		return EDN
	case strings.HasSuffix(filename, ".cljs"):
		return CLJS
	case strings.HasSuffix(filename, ".joke"):
		return JOKER
	}
	return CLJ
}

func lintFile(filename string, dialect Dialect) {
	phase := PARSE
	if dialect == EDN {
		phase = READ
	}
	ReadConfig(filename)
	configureLinterMode(dialect)
	if processFile(filename, phase) == nil {
		WarnOnUnusedNamespaces()
		WarnOnUnusedVars()
	}
}

func main() {
	GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.CoreNamespace)
	if len(os.Args) == 1 {
		repl(EVAL)
		return
	}
	if len(os.Args) == 2 {
		if os.Args[1] == "-v" || os.Args[1] == "--version" {
			println(VERSION)
			return
		}
		processFile(os.Args[1], EVAL)
		return
	}
	switch os.Args[1] {
	case "--read":
		processFile(os.Args[2], READ)
	case "--parse":
		processFile(os.Args[2], PARSE)
	case "--lint":
		dialect := detectDialect(os.Args[2])
		lintFile(os.Args[2], dialect)
	case "--lintclj":
		lintFile(os.Args[2], CLJ)
	case "--lintcljs":
		lintFile(os.Args[2], CLJS)
	case "--lintjoker":
		lintFile(os.Args[2], JOKER)
	case "--lintedn":
		lintFile(os.Args[2], EDN)
	default:
		processFile(os.Args[1], EVAL)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
)

var (
	server string
	wallet string
)

const Version = 1002

func main() {
	cfg := ReadConfig().Main
	server = cfg.Server
	wallet = cfg.Wallet

	// command line flags overwirte conf file
	var (
		hflag = flag.Bool("h", false, "help")
		sflag = flag.String("s", "", "address of api server")
		wflag = flag.String("w", "", "wallet address")
	)
	flag.Parse()
	args := flag.Args()
	if *sflag != "" {
		server = *sflag
	}
	if *wflag != "" {
		wallet = *wflag
	}
	if *hflag {
		args = []string{"help"}
	}
	if len(args) == 0 {
		args = append(args, "help")
	}

	switch args[0] {

	case "get":
		get(args)
	case "help":
		help(args)
	case "mkchain":
		mkchain(args)
	case "put":
		put(args)
	// two commands for the same thing
	case "newaddress":
		generateaddress(args)
	case "generateaddress":
		generateaddress(args)
	// two commands for the same thing
	case "balances":
		getaddresses(args)
	case "getaddresses":
		getaddresses(args)
	case "transactions":
		gettransactions(args)
	case "balance":
		balance(args)
	case "newtransaction":
		fctnewtrans(args)
	case "deletetransaction":
		fctdeletetrans(args)
	case "addinput":
		fctaddinput(args)
	case "addoutput":
		fctaddoutput(args)
	case "addecoutput":
		fctaddecoutput(args)
	case "sign":
		fctsign(args)
	case "submit":
		fctsubmit(args)
	case "getfee":
		fctgetfee(args)
	case "addfee":
		fctaddfee(args)
	case "properties":
		fctproperties(args)
	case "list":
		getlist(args)
	case "listj":
		getlistj(args)
	default:
		fmt.Println("Command not found")
		man("default")
	}
}

func errorln(a ...interface{}) (n int, err error) {
	return fmt.Fprintln(os.Stderr, a...)
}
<commit_msg>bump version<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"fmt"
	"os"
)

var (
	server string
	wallet string
)

const Version = 1003

func main() {
	cfg := ReadConfig().Main
	server = cfg.Server
	wallet = cfg.Wallet

	// command line flags overwirte conf file
	var (
		hflag = flag.Bool("h", false, "help")
		sflag = flag.String("s", "", "address of api server")
		wflag = flag.String("w", "", "wallet address")
	)
	flag.Parse()
	args := flag.Args()
	if *sflag != "" {
		server = *sflag
	}
	if *wflag != "" {
		wallet = *wflag
	}
	if *hflag {
		args = []string{"help"}
	}
	if len(args) == 0 {
		args = append(args, "help")
	}

	switch args[0] {

	case "get":
		get(args)
	case "help":
		help(args)
	case "mkchain":
		mkchain(args)
	case "put":
		put(args)
	// two commands for the same thing
	case "newaddress":
		generateaddress(args)
	case "generateaddress":
		generateaddress(args)
	// two commands for the same thing
	case "balances":
		getaddresses(args)
	case "getaddresses":
		getaddresses(args)
	case "transactions":
		gettransactions(args)
	case "balance":
		balance(args)
	case "newtransaction":
		fctnewtrans(args)
	case "deletetransaction":
		fctdeletetrans(args)
	case "addinput":
		fctaddinput(args)
	case "addoutput":
		fctaddoutput(args)
	case "addecoutput":
		fctaddecoutput(args)
	case "sign":
		fctsign(args)
	case "submit":
		fctsubmit(args)
	case "getfee":
		fctgetfee(args)
	case "addfee":
		fctaddfee(args)
	case "properties":
		fctproperties(args)
	case "list":
		getlist(args)
	case "listj":
		getlistj(args)
	default:
		fmt.Println("Command not found")
		man("default")
	}
}

func errorln(a ...interface{}) (n int, err error) {
	return fmt.Fprintln(os.Stderr, a...)
}
<|endoftext|>


<commit_before>package main

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

  "./models"
  "./schema"
)

func graphqlHandler(w http.ResponseWriter, r *http.Request) {
  username, password, ok := r.BasicAuth()
  if !ok || !models.AuthenticateUser(username, password) {
    http.Error(w, "Unauthorized", http.StatusUnauthorized)
    return
  }
  if r.Method == "GET" {
    result := schema.ExecuteQuery(r.URL.Query()["query"][0])
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(result)
  } else if r.Method == "POST" {
    body := make([]byte, r.ContentLength)
    _, err := r.Body.Read(body)
    if err != nil {
      result := schema.ExecuteQuery(string(body[:]))
      w.Header().Set("Content-Type", "application/json")
      json.NewEncoder(w).Encode(result)
    } else {
      http.Error(w, "Bad Request", http.StatusBadRequest)
    }
  } else {
    http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
  }
}

func main() {
  err := models.InitDBConnection()
  if (err != nil) {
    fmt.Printf("Error establishing connection to database: %v\n", err)
    return
  }
  http.HandleFunc("/graphql", graphqlHandler)
  fmt.Printf("HTTP listening to port 8080\n")
  http.ListenAndServe(":8080", nil)
}
<commit_msg>Remove GET method<commit_after>package main

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

  "./models"
  "./schema"
)

func graphqlHandler(w http.ResponseWriter, r *http.Request) {
  username, password, ok := r.BasicAuth()
  if !ok || !models.AuthenticateUser(username, password) {
    http.Error(w, "Unauthorized", http.StatusUnauthorized)
    return
  }
  if r.Method == "POST" {
    body := make([]byte, r.ContentLength)
    _, err := r.Body.Read(body)
    if err != nil {
      result := schema.ExecuteQuery(string(body[:]))
      w.Header().Set("Content-Type", "application/json")
      json.NewEncoder(w).Encode(result)
    } else {
      http.Error(w, "Bad Request", http.StatusBadRequest)
    }
  } else {
    http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
  }
}

func main() {
  err := models.InitDBConnection()
  if (err != nil) {
    fmt.Printf("Error establishing connection to database: %v\n", err)
    return
  }
  http.HandleFunc("/graphql", graphqlHandler)
  fmt.Printf("HTTP listening to port 8080\n")
  http.ListenAndServe(":8080", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"github.com/heroku/docker-registry-client/registry"
	"log"
	"net/http"
)

type Config struct {
	Url      string
	Username string
	Password string
}

const CONTENT_TYPE  = "application/json"

func (config *Config) Auth() (*registry.Registry, error) {
	hub, err := registry.New(config.Url, config.Username, config.Password)
	if err != nil {
		panic(err.Error())
	}

	return hub, nil
}

func (config *Config) GetRepositories(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s request to %s\n", r.Method, r.RequestURI)

	hub, err := config.Auth()
	if err != nil {
		panic(err)
	}

	repositories, err := hub.Repositories()
	if err != nil {
		panic(err)
	}

	response, err := json.Marshal(repositories)

	w.Header().Set("Content-Type", CONTENT_TYPE)
	w.Write(response)
}

func main() {
	config := &Config{
		Url:      "",
		Username: "",
		Password: "",
	}

	http.HandleFunc("/catalog", config.GetRepositories)
	log.Fatal("ListenAndServe: ", http.ListenAndServe(":8080", nil))
}
<commit_msg>Adding tags entrypoint<commit_after>package main

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/heroku/docker-registry-client/registry"
	"log"
	"net/http"
	"sort"
)

type Config struct {
	Url      string
	Username string
	Password string
}

const CONTENT_TYPE = "application/json"

func (config *Config) Auth() (*registry.Registry, error) {
	hub, err := registry.New(config.Url, config.Username, config.Password)
	if err != nil {
		log.Panic(err)
	}

	return hub, nil
}

func (config *Config) GetRepositories(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s request to %s\n", r.Method, r.RequestURI)

	hub, err := config.Auth()
	if err != nil {
		log.Panic(err)
	}

	repositories, err := hub.Repositories()
	if err != nil {
		log.Panic(err)
	}

	response, err := json.Marshal(repositories)

	w.Header().Set("Content-Type", CONTENT_TYPE)
	w.Write(response)
}

func (config *Config) GetTags(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s request to %s \n", r.Method, r.RequestURI)

	vars := mux.Vars(r)
	name := vars["name"]

	hub, err := config.Auth()
	if err != nil {
		panic(err)
	}

	tags, err := hub.Tags(name)
	if err != nil {
		panic(err)
	}

	sort.Strings(tags)
	response, err := json.Marshal(tags)

	w.Header().Set("Content-Type", CONTENT_TYPE)
	w.Write(response)
}

func main() {
	config := &Config{
		Url:      "",
		Username: "",
		Password: "",
	}

	router := mux.NewRouter().StrictSlash(true)

	router.HandleFunc("/catalog", config.GetRepositories)
	router.HandleFunc("/tags/{name}", config.GetTags).Methods("GET")
	log.Fatal("ListenAndServe: ", http.ListenAndServe(":8080", router))
}
<|endoftext|>