<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"
)

const (
	idstring = "http://golang.org/pkg/http/#ListenAndServe"
)

var (
	dlDir  = flag.String("dldir", "", "where to write the downloads. defaults to /tmp/nodashtube.")
	help   = flag.Bool("h", false, "show this help.")
	host   = flag.String("host", "0.0.0.0:8080", "listening port and hostname.")
	prefix = flag.String("prefix", "", "URL prefix for which the server runs (as in http://foo:8080/prefix).")
)

func usage() {
	fmt.Fprintf(os.Stderr, "\t nodashtube \n")
	flag.PrintDefaults()
	os.Exit(2)
}

var (
	urlInputName  = "youtubeURL"
	killInputName = "toKill"

	prefixes = map[string]string{
		"main":    "/",
		"youtube": "/youtube",
		"kill":    "/kill",
		"stored":  "/stored/",
	}

	tempDir string

	inProgressMu sync.RWMutex
	inProgress   = make(map[string]*dlInfo)

	storedMu sync.RWMutex
	stored   []string
	lastMod  time.Time

	tpl *template.Template
)

func main() {
	flag.Usage = usage
	flag.Parse()
	if *help {
		usage()
	}

	nargs := flag.NArg()
	if nargs > 0 {
		usage()
	}

	// these have to be redefined now because of *prefix flag
	// that is set after glob vars have been initialized.
	for k, v := range prefixes {
		prefixes[k] = path.Join(*prefix, v)
	}
	// TODO(mpl): sucks
	prefixes["stored"] = prefixes["stored"] + "/"

	tpl = template.Must(template.New("main").Parse(mainHTML()))
	tempDir = func() string {
		if *dlDir == "" {
			return filepath.Join(os.TempDir(), "nodashtube")
		}
		return *dlDir
	}()

	if err := os.MkdirAll(tempDir, 0755); err != nil {
		log.Fatalf("Could not create temp dir %v: %v", tempDir, err)
	}
	refreshStored(time.Time{})

	http.HandleFunc(prefixes["youtube"], youtubeHandler)
	http.HandleFunc(prefixes["kill"], killHandler)
	http.HandleFunc(prefixes["stored"], storedHandler)
	http.HandleFunc(prefixes["main"], mainHandler)
	if err := http.ListenAndServe(*host, nil); err != nil {
		log.Fatalf("Could not start http server: %v", err)
	}
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
	// TODO(mpl): remove that check?
	if r.URL.Path != prefixes["main"] {
		println(r.URL.Path + " != " + prefixes["main"])
		http.NotFound(w, r)
		return
	}
	refresh(w, r)
}

func youtubeHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Want POST", http.StatusMethodNotAllowed)
		return
	}
	// TODO(mpl): is there a lighter way to do that? I just want
	// the url bar path to be changed to "/".
	defer http.Redirect(w, r, prefixes["main"], http.StatusSeeOther)
	youtubeURL := r.PostFormValue(urlInputName)
	if youtubeURL == "" {
		mainHandler(w, r)
		return
	}
	inProgressMu.Lock()
	defer inProgressMu.Unlock()
	if _, ok := inProgress[youtubeURL]; ok {
		log.Printf("Not starting %v because it is already in progress", youtubeURL)
		return
	}

	cmd := exec.Command("youtube-dl", youtubeURL)
	out := progressWriter{}
	cmd.Stdout = &out
	//	cmd := exec.Command("wget", youtubeURL)
	cmd.Dir = tempDir
	if err := cmd.Start(); err != nil {
		log.Printf("Could not start youtube-dl with %v: %v", youtubeURL, err)
		return
	}
	log.Printf("Starting download of %v", youtubeURL)
	go func() {
		if err := cmd.Wait(); err != nil {
			log.Printf("youtube-dl %v didn't finish successfully: %v", youtubeURL, err)
			return
		}
		inProgressMu.Lock()
		delete(inProgress, youtubeURL)
		inProgressMu.Unlock()
		log.Printf("%v done.", youtubeURL)
	}()
	inProgress[youtubeURL] = &dlInfo{
		URL:      youtubeURL,
		Progress: &out,
		proc:     cmd.Process,
	}
}

func killHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Want POST", http.StatusMethodNotAllowed)
		return
	}
	defer http.Redirect(w, r, prefixes["main"], http.StatusSeeOther)
	toKill := r.PostFormValue(killInputName)
	if toKill == "" {
		return
	}
	inProgressMu.Lock()
	defer inProgressMu.Unlock()
	dl, ok := inProgress[toKill]
	if !ok {
		log.Printf("Could not cancel %v, because not in progress.", toKill)
		return
	}
	if err := dl.proc.Kill(); err != nil {
		log.Printf("Could not kill %v: %v", toKill, err)
		return
	}
	delete(inProgress, toKill)
}

func storedHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Want GET", http.StatusMethodNotAllowed)
		return
	}
	name := strings.TrimPrefix(r.URL.Path, prefixes["stored"])
	storedMu.RLock()
	defer storedMu.RUnlock()
	if !isStored(name) {
		http.NotFound(w, r)
		return
	}
	http.ServeFile(w, r, filepath.Join(tempDir, name))
}

func refresh(w http.ResponseWriter, r *http.Request) {
	ifMod, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since"))
	if err != nil {
		ifMod = time.Time{}
	}

	storedMu.Lock()
	defer storedMu.Unlock()
	refreshed := refreshStored(ifMod)
	inProgressMu.RLock()
	defer inProgressMu.RUnlock()
	if len(inProgress) == 0 && !refreshed {
		w.WriteHeader(http.StatusNotModified)
		return
	}
	w.Header().Set("Last-Modified", lastMod.UTC().Format(http.TimeFormat))
	dat := struct {
		InProgress map[string]*dlInfo
		Stored     []string
	}{
		InProgress: inProgress,
		Stored:     stored,
	}
	if err := tpl.Execute(w, &dat); err != nil {
		log.Printf("Could not execute template: %v", err)
	}
}

func refreshStored(since time.Time) bool {
	f, err := os.Open(tempDir)
	if err != nil {
		log.Fatalf("Could not open temp dir %v: %v", tempDir, err)
	}
	defer f.Close()

	d, err := f.Stat()
	if err != nil {
		log.Fatalf("Could not stat temp dir %v: %v", tempDir, err)
	}

	if !d.IsDir() {
		log.Fatalf("%v not a dir", tempDir)
	}

	if d.ModTime().After(since) {
		stored, err = sortedStored(f)
		if err != nil {
			log.Fatal(err)
		}
		lastMod = d.ModTime()
		return true
	}
	return false
}

func sortedStored(f *os.File) ([]string, error) {
	names, err := f.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	onlyFull := []string{}
	for _, v := range names {
		if !strings.HasSuffix(v, ".part") {
			onlyFull = append(onlyFull, v)
		}
	}
	sort.Strings(onlyFull)
	return onlyFull, nil
}

type dlInfo struct {
	URL      string
	Progress *progressWriter // get it with a chan from the proc output. or something.
	proc     *os.Process     // so we can kill it
}

// TODO(mpl): this means reads will block youtube-dl if it blocks on writes. We'll see.
type progressWriter struct {
	sync.RWMutex
	lastLine string
	buf      bytes.Buffer
}

func (prw *progressWriter) Write(p []byte) (n int, err error) {
	prw.Lock()
	defer prw.Unlock()
	n, err = prw.buf.Write(p)
	if err != nil {
		return n, err
	}
	contents := prw.buf.String()
	if len(contents) > 0 {
		cleanEnd := strings.LastIndex(contents, "\r")
		if cleanEnd == -1 {
			return n, err
		}
		cleanStart := strings.LastIndex(contents[:cleanEnd], "\n")
		if cleanStart == -1 {
			cleanStart = 0
		}
		prw.lastLine = contents[cleanStart:cleanEnd]
		prw.buf.Read(make([]byte, cleanEnd+1))
	}
	return n, err
}

func (prw *progressWriter) String() string {
	prw.RLock()
	defer prw.RUnlock()
	return prw.lastLine
}

func isStored(name string) bool {
	for _, v := range stored {
		if v == name {
			return true
		}
	}
	return false
}

func mainHTML() string {
	return `<!DOCTYPE HTML>

		<title>NoDashTube</title>

 Enter a youtube URL

	<form action="` + prefixes["youtube"] + `" method="POST" id="youtubeform">
	<input type="url" id="youtubeurl" name="` + urlInputName + `">
	<input type="submit" id="urlsubmit" value="Download">
	</form>
	{{if .InProgress}}

 In progress

	{{range $dl := .InProgress}}

		{{$dl.URL}}

{{$dl.Progress}}

			<form action="` + prefixes["kill"] + `" method="POST" id="killform">
			<input type="hidden" id="killurl" name="` + killInputName + `" value="{{$dl.URL}}">
			<input type="submit" id="killsubmit" value="Cancel">
			</form>

	{{end}}

	{{end}}
	{{if .Stored}}

 Stored

	{{range $st := .Stored}}

		<a href="` + prefixes["stored"] + `{{$st}}">{{$st}}

	{{end}}

	{{end}}

`
}
<commit_msg>wip notifications<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

const (
	idstring = "http://golang.org/pkg/http/#ListenAndServe"
)

var (
	dlDir = flag.String("dldir", "", "where to write the downloads. defaults to /tmp/nodashtube.")
	help  = flag.Bool("h", false, "show this help.")
	host  = flag.String("host", "0.0.0.0:8080", "listening port and hostname.")
	prefix = flag.String("prefix", "", "URL prefix for which the server runs (as in http://foo:8080/prefix).")
)

func usage() {
	fmt.Fprintf(os.Stderr, "\t nodashtube \n")
	flag.PrintDefaults()
	os.Exit(2)
}

var (
	urlInputName  = "youtubeURL"
	killInputName = "toKill"

	prefixes = map[string]string {
		"main": "/",
		"youtube": "/youtube",
		"kill": "/kill",
		"stored": "/stored/",
		"progress": "/progress",
		"notify": "/notify.js",
	}

	tempDir string

	inProgressMu sync.RWMutex
	inProgress   = make(map[string]*dlInfo)

	storedMu sync.RWMutex
	stored   []string
	lastMod  time.Time

	tpl *template.Template
)

func main() {
	flag.Usage = usage
	flag.Parse()
	if *help {
		usage()
	}

	nargs := flag.NArg()
	if nargs > 0 {
		usage()
	}

	// these have to be redefined now because of *prefix flag
	// that is set after glob vars have been initialized.
	for k, v := range prefixes{
		prefixes[k] = path.Join(*prefix, v)
	}
	// TODO(mpl): sucks
	prefixes["stored"] = prefixes["stored"] + "/"

	tpl = template.Must(template.New("main").Parse(mainHTML()))
	tempDir = func() string {
		if *dlDir == "" {
			return filepath.Join(os.TempDir(), "nodashtube")
		}
		return *dlDir
	}()

	if err := os.MkdirAll(tempDir, 0755); err != nil {
		log.Fatalf("Could not create temp dir %v: %v", tempDir, err)
	}
	refreshStored(time.Time{})

	// TODO(mpl): favicon.ico
	http.HandleFunc(prefixes["youtube"], youtubeHandler)
	http.HandleFunc(prefixes["kill"], killHandler)
	http.HandleFunc(prefixes["stored"], storedHandler)
	http.HandleFunc(prefixes["progress"], progressHandler)
	// TODO(mpl): embed instead
	http.HandleFunc(prefixes["notify"], func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, "/home/mpl/gocode/src/github.com/mpl/nodashtube/notify.js")
	})
	http.HandleFunc(prefixes["main"], mainHandler)
	if err := http.ListenAndServe(*host, nil); err != nil {
		log.Fatalf("Could not start http server: %v", err)
	}
}

func mainHandler(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != prefixes["main"] {
		println(r.URL.Path + " != " + prefixes["main"])
		http.NotFound(w, r)
		return
	}
	refresh(w, r)
}

func youtubeHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Want POST", http.StatusMethodNotAllowed)
		return
	}
	// TODO(mpl): is there a lighter way to do that? I just want
	// the url bar path to be changed to "/".
	defer http.Redirect(w, r, prefixes["main"], http.StatusSeeOther)
	youtubeURL := r.PostFormValue(urlInputName)
	if youtubeURL == "" {
		mainHandler(w, r)
		return
	}
	inProgressMu.Lock()
	defer inProgressMu.Unlock()
	if _, ok := inProgress[youtubeURL]; ok {
		log.Printf("Not starting %v because it is already in progress", youtubeURL)
		return
	}

	cmd := exec.Command("youtube-dl", youtubeURL)
	out := progressWriter{}
	cmd.Stdout = &out
	//	cmd := exec.Command("wget", youtubeURL)
	cmd.Dir = tempDir
	if err := cmd.Start(); err != nil {
		log.Printf("Could not start youtube-dl with %v: %v", youtubeURL, err)
		return
	}
	log.Printf("Starting download of %v", youtubeURL)
	go func() {
		if err := cmd.Wait(); err != nil {
			log.Printf("youtube-dl %v didn't finish successfully: %v", youtubeURL, err)
			return
		}
		inProgressMu.Lock()
		delete(inProgress, youtubeURL)
		inProgressMu.Unlock()
		log.Printf("%v done.", youtubeURL)
	}()
	inProgress[youtubeURL] = &dlInfo{
		URL:      youtubeURL,
		Progress: &out,
		proc:     cmd.Process,
	}
}

func killHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		http.Error(w, "Want POST", http.StatusMethodNotAllowed)
		return
	}
	defer http.Redirect(w, r, prefixes["main"], http.StatusSeeOther)
	toKill := r.PostFormValue(killInputName)
	if toKill == "" {
		return
	}
	inProgressMu.Lock()
	defer inProgressMu.Unlock()
	dl, ok := inProgress[toKill]
	if !ok {
		log.Printf("Could not cancel %v, because not in progress.", toKill)
		return
	}
	if err := dl.proc.Kill(); err != nil {
		log.Printf("Could not kill %v: %v", toKill, err)
		return
	}
	delete(inProgress, toKill)
}

func storedHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Want GET", http.StatusMethodNotAllowed)
		return
	}
	name := strings.TrimPrefix(r.URL.Path, prefixes["stored"])
	storedMu.RLock()
	defer storedMu.RUnlock()
	if !isStored(name) {
		http.NotFound(w, r)
		return
	}
	http.ServeFile(w, r, filepath.Join(tempDir, name))
}

func progressHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Want GET", http.StatusMethodNotAllowed)
		return
	}
	inProgressMu.RLock()
	defer inProgressMu.RUnlock()
	progressJSON, err := json.Marshal(inProgress)
	if err != nil {
		// TODO(mpl): json error
		http.Error(w, "Error encoding progress", http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "text/javascript")
	w.WriteHeader(http.StatusOK)
	w.Header().Set("Content-Length", strconv.Itoa(len(progressJSON)+1))
	w.Write(progressJSON)
	w.Write([]byte("\n"))
}

func refresh(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Server", idstring)
	ifMod, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since"))
	if err != nil {
		ifMod = time.Time{}
	}

	storedMu.Lock()
	defer storedMu.Unlock()
	refreshed := refreshStored(ifMod)
	inProgressMu.RLock()
	defer inProgressMu.RUnlock()
	if len(inProgress) == 0 && !refreshed {
		w.WriteHeader(http.StatusNotModified)
		return
	}
	w.Header().Set("Last-Modified", lastMod.UTC().Format(http.TimeFormat))
	dat := struct {
		InProgress map[string]*dlInfo
		Stored     []string
	}{
		InProgress: inProgress,
		Stored:     stored,
	}
	if err := tpl.Execute(w, &dat); err != nil {
		log.Printf("Could not execute template: %v", err)
	}
}

func refreshStored(since time.Time) bool {
	f, err := os.Open(tempDir)
	if err != nil {
		log.Fatalf("Could not open temp dir %v: %v", tempDir, err)
	}
	defer f.Close()

	d, err := f.Stat()
	if err != nil {
		log.Fatalf("Could not stat temp dir %v: %v", tempDir, err)
	}

	if !d.IsDir() {
		log.Fatalf("%v not a dir", tempDir)
	}

	if d.ModTime().After(since) {
		stored, err = sortedStored(f)
		if err != nil {
			log.Fatal(err)
		}
		lastMod = d.ModTime()
		return true
	}
	return false
}

func sortedStored(f *os.File) ([]string, error) {
	names, err := f.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	onlyFull := []string{}
	for _, v := range names {
		if !strings.HasSuffix(v, ".part") {
			onlyFull = append(onlyFull, v)
		}
	}
	sort.Strings(onlyFull)
	return onlyFull, nil
}

// TODO(mpl): this works well for the template, but not for the js because it doesn't
// give progress. I don't actually need the progress for the js notifications though.
// still it'd be nice to have a data struct which works directly for both without any
// massageing needed.
type dlInfo struct {
	URL      string
	Progress *progressWriter
	proc     *os.Process // so we can kill it
}

// TODO(mpl): this means reads will block youtube-dl if it blocks on writes. We'll see.
type progressWriter struct {
	sync.RWMutex
	lastLine string
	buf bytes.Buffer
}

func (prw *progressWriter) Write(p []byte) (n int, err error) {
	prw.Lock()
	defer prw.Unlock()
	n, err = prw.buf.Write(p)
	if err != nil {
		return n, err
	}
	contents := prw.buf.String()
	if len(contents) > 0 {
		cleanEnd := strings.LastIndex(contents, "\r")
		if cleanEnd == -1 {
			return n, err
		}
		cleanStart := strings.LastIndex(contents[:cleanEnd], "\n")
		if cleanStart == -1 {
			cleanStart = 0
		}
		prw.lastLine = contents[cleanStart:cleanEnd]
		prw.buf.Read(make([]byte, cleanEnd+1))
	}
	return n, err
}

func (prw *progressWriter) String() string {
	prw.RLock()
	defer prw.RUnlock()
	return prw.lastLine
}

func isStored(name string) bool {
	for _, v := range stored {
		if v == name {
			return true
		}
	}
	return false
}

// TODO(mpl): button to show .part
func mainHTML() string {
	return `<!DOCTYPE HTML>

		<title>NoDashTube</title>

 Enter a youtube URL

	<form action="` + prefixes["youtube"] + `" method="POST" id="youtubeform">
	<input type="url" id="youtubeurl" name="` + urlInputName + `">
	<input type="submit" id="urlsubmit" value="Download">
	</form>
	{{if .InProgress}}

 In progress

	{{range $dl := .InProgress}}

		{{$dl.URL}}

{{$dl.Progress}}

			<form action="` + prefixes["kill"] + `" method="POST" id="killform">
			<input type="hidden" id="killurl" name="` + killInputName + `" value="{{$dl.URL}}">
			<input type="submit" id="killsubmit" value="Cancel">
			</form>

	{{end}}

	{{end}}
	{{if .Stored}}

 Stored

	{{range $st := .Stored}}

		<a href="` + prefixes["stored"] + `{{$st}}">{{$st}}

	{{end}}

	{{end}}

`
}

/*
function notify() {
  var havePermission = window.webkitNotifications.checkPermission();
  if (havePermission == 0) {
    // 0 is PERMISSION_ALLOWED
    var notification = window.webkitNotifications.createNotification(
      'http://i.stack.imgur.com/dmHl0.png',
      'Chrome notification!',
      'Here is the notification text'
    );

    notification.onclick = function () {
      window.open("http://stackoverflow.com/a/13328397/1269037");
      notification.close();
    }
    notification.show();
  } else {
      window.webkitNotifications.requestPermission();
  }
}

function getProgressList(URL) {
	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("GET",URL,false);
	xmlhttp.send();
	console.log(xmlhttp.responseText);
	var newListJSON = xmlhttp.response;
	var newList = Object.keys(JSON.parse(newListJSON));
	console.log(newList.length);
	console.log(newList);
	if (currentList.length == 0) {
		currentList = newList;
		return;
	}
	for (var URL in currentList) {
		if (!(URL in newList)) {
			console.log(URL + " is done.")
		}
	}
	currentList = newList;
}

var currentList = [];
var progressHost = "http://localhost:8080/progress";
setInterval(function(){getProgressList(progressHost)},5000);

*/
<|endoftext|>


<commit_before>package main

import (
  "bufio"
  "encoding/json"
  "flag"
  "fmt"
  "os"
  "strings"
  bs_ast "bitbucket.org/yyuu/bs/ast"
  bs_compiler "bitbucket.org/yyuu/bs/compiler"
  bs_core "bitbucket.org/yyuu/bs/core"
  bs_ir "bitbucket.org/yyuu/bs/ir"
  bs_parser "bitbucket.org/yyuu/bs/parser"
  bs_sysdep "bitbucket.org/yyuu/bs/sysdep"
  bs_typesys "bitbucket.org/yyuu/bs/typesys"
)

var flagSet = flag.NewFlagSet(os.Args[0], 1)
var dump = flagSet.Int("d", 0, "dump mode")
var verbose = flagSet.Int("v", 0, "verbose mode")
var errorHandler = bs_core.NewErrorHandler(bs_core.LOG_DEBUG)

const (
  DUMP_AST = 1<<iota
  DUMP_SEMANT
  DUMP_IR
  DUMP_ASM
)

func main() {
  flagSet.Parse(os.Args[1:])
  bs_parser.Verbose = *verbose
  bs_compiler.Verbose = *verbose

  files := flagSet.Args()
  if 0 < len(files) {
    for i := range files {
      ep(bs_parser.ParseFile(files[i]))
    }
  } else {
    repl()
  }
}

func repl() {
  defer func() {
    if s := recover(); s != nil {
      fmt.Fprintf(os.Stderr, "recovered: %s\n", s)
      repl()
    }
  }()
  in  := bufio.NewReader(os.Stdin)
  out := bufio.NewWriter(os.Stdout)
  for {
    s := r(in, out)
    if s != "" {
      ep(bs_parser.ParseExpr(s))
    }
  }
}

func r(in *bufio.Reader, out *bufio.Writer) string {
  out.WriteString("> ")
  out.Flush()
  s, err := in.ReadString('\n')
  if err != nil {
    os.Exit(1)
  }
  return strings.TrimSpace(s)
}

func ep(ast *bs_ast.AST, err error) {
  if err != nil {
    panic(err)
  }
  if (*dump & DUMP_AST) != 0 {
    dumpAST(ast)
  }
  types := bs_typesys.NewTypeTableFor("x86-linux")
  sem := semanticAnalyze(ast, types)
  if (*dump & DUMP_SEMANT) != 0 {
    dumpSemant(sem)
  }
  ir := bs_compiler.NewIRGenerator(errorHandler, types).Generate(sem)
  if (*dump & DUMP_IR) != 0 {
    dumpIR(ir)
  }
  asm := generateAssembly(ir)
  if (*dump & DUMP_ASM) != 0 {
    dumpAsm(asm)
  }

  // TODO: remove this
  fmt.Fprintln(os.Stdout, ast)
}

func semanticAnalyze(ast *bs_ast.AST, types *bs_typesys.TypeTable) *bs_ast.AST {
  bs_compiler.NewLocalResolver(errorHandler).Resolve(ast)
  bs_compiler.NewTypeResolver(errorHandler, types).Resolve(ast)
  types.SemanticCheck(errorHandler)
  bs_compiler.NewDereferenceChecker(errorHandler, types).Check(ast)
  bs_compiler.NewTypeChecker(errorHandler, types).Check(ast)
  return ast
}

func generateAssembly(ir *bs_ir.IR) *bs_sysdep.AssemblyCode {
  return bs_sysdep.NewCodeGeneratorFor(errorHandler, "x86-linux").Generate(ir)
}

func dumpAST(ast *bs_ast.AST) {
  cs, err := json.MarshalIndent(ast, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Fprintln(os.Stderr, "// AST")
  fmt.Fprintln(os.Stderr, string(cs))
}

func dumpSemant(ast *bs_ast.AST) {
  cs, err := json.MarshalIndent(ast, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Fprintln(os.Stderr, "// Semantics")
  fmt.Fprintln(os.Stderr, string(cs))
}

func dumpIR(ir *bs_ir.IR) {
  cs, err := json.MarshalIndent(ir, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Fprintln(os.Stderr, "// IR")
  fmt.Fprintln(os.Stderr, string(cs))
}

func dumpAsm(asm *bs_sysdep.AssemblyCode) {
  cs, err := json.MarshalIndent(asm, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Fprintln(os.Stderr, "// Asm")
  fmt.Fprintln(os.Stderr, string(cs))
}
<commit_msg>Show dumped nodes on STDOUT<commit_after>package main

import (
  "bufio"
  "encoding/json"
  "flag"
  "fmt"
  "os"
  "strings"
  bs_ast "bitbucket.org/yyuu/bs/ast"
  bs_compiler "bitbucket.org/yyuu/bs/compiler"
  bs_core "bitbucket.org/yyuu/bs/core"
  bs_ir "bitbucket.org/yyuu/bs/ir"
  bs_parser "bitbucket.org/yyuu/bs/parser"
  bs_sysdep "bitbucket.org/yyuu/bs/sysdep"
  bs_typesys "bitbucket.org/yyuu/bs/typesys"
)

var flagSet = flag.NewFlagSet(os.Args[0], 1)
var dump = flagSet.Int("d", 0, "dump mode")
var verbose = flagSet.Int("v", 0, "verbose mode")
var errorHandler = bs_core.NewErrorHandler(bs_core.LOG_DEBUG)

const (
  DUMP_AST = 1<<iota
  DUMP_SEMANT
  DUMP_IR
  DUMP_ASM
)

func main() {
  flagSet.Parse(os.Args[1:])
  bs_parser.Verbose = *verbose
  bs_compiler.Verbose = *verbose

  files := flagSet.Args()
  if 0 < len(files) {
    for i := range files {
      ep(bs_parser.ParseFile(files[i]))
    }
  } else {
    repl()
  }
}

func repl() {
  defer func() {
    if s := recover(); s != nil {
      fmt.Fprintf(os.Stderr, "recovered: %s\n", s)
      repl()
    }
  }()
  in  := bufio.NewReader(os.Stdin)
  out := bufio.NewWriter(os.Stdout)
  for {
    s := r(in, out)
    if s != "" {
      ep(bs_parser.ParseExpr(s))
    }
  }
}

func r(in *bufio.Reader, out *bufio.Writer) string {
  out.WriteString("> ")
  out.Flush()
  s, err := in.ReadString('\n')
  if err != nil {
    os.Exit(1)
  }
  return strings.TrimSpace(s)
}

func ep(ast *bs_ast.AST, err error) {
  if err != nil {
    panic(err)
  }
  if (*dump & DUMP_AST) != 0 {
    dumpAST(ast)
  }
  types := bs_typesys.NewTypeTableFor("x86-linux")
  sem := semanticAnalyze(ast, types)
  if (*dump & DUMP_SEMANT) != 0 {
    dumpSemant(sem)
  }
  ir := bs_compiler.NewIRGenerator(errorHandler, types).Generate(sem)
  if (*dump & DUMP_IR) != 0 {
    dumpIR(ir)
  }
  asm := generateAssembly(ir)
  if (*dump & DUMP_ASM) != 0 {
    dumpAsm(asm)
  }
}

func semanticAnalyze(ast *bs_ast.AST, types *bs_typesys.TypeTable) *bs_ast.AST {
  bs_compiler.NewLocalResolver(errorHandler).Resolve(ast)
  bs_compiler.NewTypeResolver(errorHandler, types).Resolve(ast)
  types.SemanticCheck(errorHandler)
  bs_compiler.NewDereferenceChecker(errorHandler, types).Check(ast)
  bs_compiler.NewTypeChecker(errorHandler, types).Check(ast)
  return ast
}

func generateAssembly(ir *bs_ir.IR) *bs_sysdep.AssemblyCode {
  return bs_sysdep.NewCodeGeneratorFor(errorHandler, "x86-linux").Generate(ir)
}

func dumpAST(ast *bs_ast.AST) {
  cs, err := json.MarshalIndent(ast, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Println("// AST")
  fmt.Println(string(cs))
}

func dumpSemant(ast *bs_ast.AST) {
  cs, err := json.MarshalIndent(ast, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Println("// Semantics")
  fmt.Println(string(cs))
}

func dumpIR(ir *bs_ir.IR) {
  cs, err := json.MarshalIndent(ir, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Println("// IR")
  fmt.Println(string(cs))
}

func dumpAsm(asm *bs_sysdep.AssemblyCode) {
  cs, err := json.MarshalIndent(asm, "", "  ")
  if err != nil {
    panic(err)
  }
  fmt.Println("// Asm")
  fmt.Println(string(cs))
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
)

const (
	defaultPort = ":8000"
)

// GoProxy is our reverseproxy object
type GoProxy struct {
	target *url.URL
	proxy  *httputil.ReverseProxy
	debug  bool
}

// New creates a GoProxy instance
func New(backend string, debug bool) *GoProxy {
	url, err := url.Parse(backend)
	if err != nil {
		return nil
	}

	return &GoProxy{
		target: url,
		proxy:  httputil.NewSingleHostReverseProxy(url),
		debug:  debug,
	}
}

func (p *GoProxy) handle(w http.ResponseWriter, r *http.Request) {
	if p.debug {
		fmt.Println("--- New request ---")
		req, _ := httputil.DumpRequest(r, true)
		fmt.Println(string(req))
	}

	w.Header().Set("X-GoProxy", "GoProxy-by-cizixs")
	p.proxy.ServeHTTP(w, r)
}

func main() {
	port := flag.String("port", defaultPort, "Port for goproxy to run on.")
	backend := flag.String("backend", "", "Backend url address goproxy will forward packets to.")
	debug := flag.Bool("debug", true, "If enable debug mode. If so, application will print each request detail to stdout.")
	flag.Parse()

	if *backend == "" {
		fmt.Println("Must provide target url.\nUse --help to check usage.")
		return
	}

	proxy := New(*backend, *debug)
	if proxy == nil {
		fmt.Println("Can not setup proxy. Exit...")
		return
	}

	http.HandleFunc("/", proxy.handle)
	fmt.Printf("Start Serving at %s\n", *port)
	fmt.Printf("Packets will forward to %s\n\n", *backend)
	http.ListenAndServe(*port, nil)
}
<commit_msg>Enable multiple backends<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
)

const (
	defaultPort = ":8000"
)

// GoProxy is our reverseproxy object
type GoProxy struct {
	targets []*url.URL
	proxy   *httputil.ReverseProxy
	debug   bool
}

// New creates a GoProxy instance
func New(backends []string, debug bool) *GoProxy {
	var targets []*url.URL
	for _, backend := range backends {
		url, err := url.Parse(backend)
		if err != nil {
			return nil
		}
		targets = append(targets, url)
	}

	director := func(req *http.Request) {
		target := targets[rand.Int()%len(targets)]
		fmt.Printf("Target %s choosed\n", target.Host)
		req.URL.Scheme = target.Scheme
		req.URL.Host = target.Host
		req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
		if target.RawQuery == "" || req.URL.RawQuery == "" {
			req.URL.RawQuery = target.RawQuery + req.URL.RawQuery
		} else {
			req.URL.RawQuery = target.RawQuery + "&" + req.URL.RawQuery
		}
		fmt.Printf("Target path: %s\n", req.URL.Path)
	}

	return &GoProxy{
		targets: targets,
		proxy:   &httputil.ReverseProxy{Director: director},
		debug:   debug,
	}
}

func (p *GoProxy) handle(w http.ResponseWriter, r *http.Request) {
	if p.debug {
		fmt.Println("\n\n--- New request ---")
		req, _ := httputil.DumpRequest(r, true)
		fmt.Println(string(req))
	}

	w.Header().Set("X-GoProxy", "GoProxy-by-cizixs")
	p.proxy.ServeHTTP(w, r)
}

func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

func main() {
	port := flag.String("port", defaultPort, "Port for goproxy to run on.")
	backendStr := flag.String("backend", "", "Backend url address goproxy will forward packets to.")
	debug := flag.Bool("debug", true, "If enable debug mode. If so, application will print each request detail to stdout.")
	flag.Parse()

	if *backendStr == "" {
		fmt.Println("Must provide target url.\nUse --help to check usage.")
		return
	}

	backends := strings.Split(*backendStr, ",")
	proxy := New(backends, *debug)
	if proxy == nil {
		fmt.Println("Can not setup proxy. Exit...")
		return
	}

	http.HandleFunc("/", proxy.handle)
	fmt.Printf("Start Serving at %s\n", *port)
	fmt.Printf("Packets will forward to %s\n\n", backends)
	http.ListenAndServe(*port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"path/filepath"
	"regexp"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	src string
	dst string
}

func NewPackage(uri, filetype string) (*Package, error) {
	return &Package{}, nil
}
<commit_msg>Implement constructor<commit_after>package main

import (
	"path/filepath"
	"regexp"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	src string
	dst string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"

	"github.com/hoffie/larasync/server"
)

// main is our service dispatcher.
func main() {
	if len(os.Args) <= 1 {
		log.Fatal("no action specified")
		os.Exit(1)
	}
	action := os.Args[1]
	switch action {
	case "server":
		s := server.New([]byte("FIXME-broken-hardcoded-secret")) //FIXME: config!
		log.Printf("Listening on :%d", server.DefaultPort)
		log.Fatal(s.ListenAndServe())
		return
	default:
		log.Fatal("unsupported action; possible actions: server")
		os.Exit(1)
	}
}
<commit_msg>main: fixing api import path<commit_after>package main

import (
	"log"
	"os"

	"github.com/hoffie/larasync/api"
)

// main is our service dispatcher.
func main() {
	if len(os.Args) <= 1 {
		log.Fatal("no action specified")
		os.Exit(1)
	}
	action := os.Args[1]
	switch action {
	case "server":
		s := api.New([]byte("FIXME-broken-hardcoded-secret")) //FIXME: config!
		log.Printf("Listening on :%d", api.DefaultPort)
		log.Fatal(s.ListenAndServe())
		return
	default:
		log.Fatal("unsupported action; possible actions: server")
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/docker/docker/pkg/reexec"
	"github.com/ehazlett/simplelog"
	"github.com/rancher/norman/pkg/dump"
	"github.com/rancher/norman/pkg/kwrapper/k8s"
	"github.com/rancher/norman/signal"
	"github.com/rancher/rancher/app"
	"github.com/rancher/rancher/pkg/logserver"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var (
	VERSION = "dev"
)

func main() {
	app.RegisterPasswordResetCommand()
	app.RegisterEnsureDefaultAdminCommand()
	if reexec.Init() {
		return
	}

	os.Unsetenv("SSH_AUTH_SOCK")
	os.Unsetenv("SSH_AGENT_PID")
	os.Setenv("DISABLE_HTTP2", "true")

	if dir, err := os.Getwd(); err == nil {
		dmPath := filepath.Join(dir, "management-state", "bin")
		os.MkdirAll(dmPath, 0700)
		newPath := fmt.Sprintf("%s%s%s", dmPath, string(os.PathListSeparator), os.Getenv("PATH"))

		os.Setenv("PATH", newPath)
	}

	var config app.Config

	app := cli.NewApp()
	app.Version = VERSION
	app.Usage = "Complete container management platform"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "kubeconfig",
			Usage:       "Kube config for accessing k8s cluster",
			EnvVar:      "KUBECONFIG",
			Destination: &config.KubeConfig,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Enable debug logs",
			Destination: &config.Debug,
		},
		cli.StringFlag{
			Name:        "add-local",
			Usage:       "Add local cluster (true, false, auto)",
			Value:       "auto",
			Destination: &config.AddLocal,
		},
		cli.IntFlag{
			Name:        "http-listen-port",
			Usage:       "HTTP listen port",
			Value:       8080,
			Destination: &config.HTTPListenPort,
		},
		cli.IntFlag{
			Name:        "https-listen-port",
			Usage:       "HTTPS listen port",
			Value:       8443,
			Destination: &config.HTTPSListenPort,
		},
		cli.StringFlag{
			Name:        "k8s-mode",
			Usage:       "Mode to run or access k8s API server for management API (embedded, external, auto)",
			Value:       "auto",
			Destination: &config.K8sMode,
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "Log formatter used (json, text, simple)",
			Value: "simple",
		},
		cli.StringSliceFlag{
			Name:  "acme-domain",
			Usage: "Domain to register with LetsEncrypt",
		},
		cli.BoolFlag{
			Name:  "no-cacerts",
			Usage: "Skip CA certs population in settings when set to true",
		},
		cli.StringFlag{
			Name:   "audit-log-path",
			EnvVar: "AUDIT_LOG_PATH",
			Value:  "/var/log/auditlog/rancher-api-audit.log",
			Usage:  "Log path for Rancher Server API. Default path is /var/log/auditlog/rancher-api-audit.log",
		},
		cli.IntFlag{
			Name:   "audit-log-maxage",
			Value:  10,
			EnvVar: "AUDIT_LOG_MAXAGE",
			Usage:  "Defined the maximum number of days to retain old audit log files",
		},
		cli.IntFlag{
			Name:   "audit-log-maxbackup",
			Value:  10,
			EnvVar: "AUDIT_LOG_MAXBACKUP",
			Usage:  "Defines the maximum number of audit log files to retain",
		},
		cli.IntFlag{
			Name:   "audit-log-maxsize",
			Value:  100,
			EnvVar: "AUDIT_LOG_MAXSIZE",
			Usage:  "Defines the maximum size in megabytes of the audit log file before it gets rotated, default size is 100M",
		},
		cli.IntFlag{
			Name:   "audit-level",
			Value:  0,
			EnvVar: "AUDIT_LEVEL",
			Usage:  "Audit log level: 0 - disable audit log, 1 - log event metadata, 2 - log event metadata and request body, 3 - log event metadata, request body and response body",
		},
	}

	app.Action = func(c *cli.Context) error {
		// enable profiler
		go func() {
			log.Println(http.ListenAndServe("localhost:6060", nil))
		}()

		config.ACMEDomains = c.GlobalStringSlice("acme-domain")
		config.NoCACerts = c.Bool("no-cacerts")

		config.AuditLevel = c.Int("audit-level")
		config.AuditLogPath = c.String("audit-log-path")
		config.AuditLogMaxage = c.Int("audit-log-maxage")
		config.AuditLogMaxbackup = c.Int("audit-log-maxbackup")
		config.AuditLogMaxsize = c.Int("audit-log-maxsize")
		initLogs(c, config)
		return run(config)
	}

	app.ExitErrHandler = func(c *cli.Context, err error) {
		logrus.Fatal(err)
	}

	app.Run(os.Args)
}

func initLogs(c *cli.Context, cfg app.Config) {
	if cfg.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	switch c.String("log-format") {
	case "simple":
		logrus.SetFormatter(&simplelog.StandardFormatter{})
	case "text":
		logrus.SetFormatter(&logrus.TextFormatter{})
	case "json":
		logrus.SetFormatter(&logrus.JSONFormatter{})
	}
	logrus.SetOutput(os.Stdout)
	logserver.StartServerWithDefaults()
}

func run(cfg app.Config) error {
	logrus.Infof("Rancher version %s is starting", VERSION)
	logrus.Infof("Rancher arguments %+v", cfg)
	dump.GoroutineDumpOn(syscall.SIGUSR1, syscall.SIGILL)
	ctx := signal.SigTermCancelContext(context.Background())

	embedded, ctx, kubeConfig, err := k8s.GetConfig(ctx, cfg.K8sMode, cfg.KubeConfig)
	if err != nil {
		return err
	}
	cfg.Embedded = embedded

	os.Unsetenv("KUBECONFIG")
	kubeConfig.Timeout = 30 * time.Second
	return app.Run(ctx, *kubeConfig, &cfg)
}
<commit_msg>Fix upgrade from 2.1<commit_after>package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/docker/docker/pkg/reexec"
	"github.com/ehazlett/simplelog"
	"github.com/rancher/norman/pkg/dump"
	"github.com/rancher/norman/pkg/kwrapper/k8s"
	"github.com/rancher/norman/signal"
	"github.com/rancher/rancher/app"
	"github.com/rancher/rancher/pkg/logserver"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var (
	VERSION = "dev"
)

func main() {
	app.RegisterPasswordResetCommand()
	app.RegisterEnsureDefaultAdminCommand()
	if reexec.Init() {
		return
	}

	os.Unsetenv("SSH_AUTH_SOCK")
	os.Unsetenv("SSH_AGENT_PID")
	os.Setenv("DISABLE_HTTP2", "true")

	if dir, err := os.Getwd(); err == nil {
		dmPath := filepath.Join(dir, "management-state", "bin")
		os.MkdirAll(dmPath, 0700)
		newPath := fmt.Sprintf("%s%s%s", dmPath, string(os.PathListSeparator), os.Getenv("PATH"))

		os.Setenv("PATH", newPath)
	}

	var config app.Config

	app := cli.NewApp()
	app.Version = VERSION
	app.Usage = "Complete container management platform"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:        "kubeconfig",
			Usage:       "Kube config for accessing k8s cluster",
			EnvVar:      "KUBECONFIG",
			Destination: &config.KubeConfig,
		},
		cli.BoolFlag{
			Name:        "debug",
			Usage:       "Enable debug logs",
			Destination: &config.Debug,
		},
		cli.StringFlag{
			Name:        "add-local",
			Usage:       "Add local cluster (true, false, auto)",
			Value:       "auto",
			Destination: &config.AddLocal,
		},
		cli.IntFlag{
			Name:        "http-listen-port",
			Usage:       "HTTP listen port",
			Value:       8080,
			Destination: &config.HTTPListenPort,
		},
		cli.IntFlag{
			Name:        "https-listen-port",
			Usage:       "HTTPS listen port",
			Value:       8443,
			Destination: &config.HTTPSListenPort,
		},
		cli.StringFlag{
			Name:        "k8s-mode",
			Usage:       "Mode to run or access k8s API server for management API (embedded, external, auto)",
			Value:       "auto",
			Destination: &config.K8sMode,
		},
		cli.StringFlag{
			Name:  "log-format",
			Usage: "Log formatter used (json, text, simple)",
			Value: "simple",
		},
		cli.StringSliceFlag{
			Name:  "acme-domain",
			Usage: "Domain to register with LetsEncrypt",
		},
		cli.BoolFlag{
			Name:  "no-cacerts",
			Usage: "Skip CA certs population in settings when set to true",
		},
		cli.StringFlag{
			Name:   "audit-log-path",
			EnvVar: "AUDIT_LOG_PATH",
			Value:  "/var/log/auditlog/rancher-api-audit.log",
			Usage:  "Log path for Rancher Server API. Default path is /var/log/auditlog/rancher-api-audit.log",
		},
		cli.IntFlag{
			Name:   "audit-log-maxage",
			Value:  10,
			EnvVar: "AUDIT_LOG_MAXAGE",
			Usage:  "Defined the maximum number of days to retain old audit log files",
		},
		cli.IntFlag{
			Name:   "audit-log-maxbackup",
			Value:  10,
			EnvVar: "AUDIT_LOG_MAXBACKUP",
			Usage:  "Defines the maximum number of audit log files to retain",
		},
		cli.IntFlag{
			Name:   "audit-log-maxsize",
			Value:  100,
			EnvVar: "AUDIT_LOG_MAXSIZE",
			Usage:  "Defines the maximum size in megabytes of the audit log file before it gets rotated, default size is 100M",
		},
		cli.IntFlag{
			Name:   "audit-level",
			Value:  0,
			EnvVar: "AUDIT_LEVEL",
			Usage:  "Audit log level: 0 - disable audit log, 1 - log event metadata, 2 - log event metadata and request body, 3 - log event metadata, request body and response body",
		},
	}

	app.Action = func(c *cli.Context) error {
		// enable profiler
		go func() {
			log.Println(http.ListenAndServe("localhost:6060", nil))
		}()

		config.ACMEDomains = c.GlobalStringSlice("acme-domain")
		config.NoCACerts = c.Bool("no-cacerts")

		config.AuditLevel = c.Int("audit-level")
		config.AuditLogPath = c.String("audit-log-path")
		config.AuditLogMaxage = c.Int("audit-log-maxage")
		config.AuditLogMaxbackup = c.Int("audit-log-maxbackup")
		config.AuditLogMaxsize = c.Int("audit-log-maxsize")
		initLogs(c, config)
		return run(config)
	}

	app.ExitErrHandler = func(c *cli.Context, err error) {
		logrus.Fatal(err)
	}

	app.Run(os.Args)
}

func initLogs(c *cli.Context, cfg app.Config) {
	if cfg.Debug {
		logrus.SetLevel(logrus.DebugLevel)
	}

	switch c.String("log-format") {
	case "simple":
		logrus.SetFormatter(&simplelog.StandardFormatter{})
	case "text":
		logrus.SetFormatter(&logrus.TextFormatter{})
	case "json":
		logrus.SetFormatter(&logrus.JSONFormatter{})
	}
	logrus.SetOutput(os.Stdout)
	logserver.StartServerWithDefaults()
}

func migrateETCDlocal() {
	if _, err := os.Stat("etcd"); err != nil {
		return
	}

	// Purposely ignoring errors
	os.Mkdir("management-state", 0700)
	os.Symlink("../etcd", "management-state/etcd")
}

func run(cfg app.Config) error {
	logrus.Infof("Rancher version %s is starting", VERSION)
	logrus.Infof("Rancher arguments %+v", cfg)
	dump.GoroutineDumpOn(syscall.SIGUSR1, syscall.SIGILL)
	ctx := signal.SigTermCancelContext(context.Background())

	migrateETCDlocal()

	embedded, ctx, kubeConfig, err := k8s.GetConfig(ctx, cfg.K8sMode, cfg.KubeConfig)
	if err != nil {
		return err
	}
	cfg.Embedded = embedded

	os.Unsetenv("KUBECONFIG")
	kubeConfig.Timeout = 30 * time.Second
	return app.Run(ctx, *kubeConfig, &cfg)
}
<|endoftext|>


<commit_before>package main

import (
    "database/sql"
    "log"

    _ "github.com/mattn/go-sqlite3"
)

var createUsers = `
CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name VARCHAR
);
`

var insertUser = `INSERT INTO users (id, name) VALUES (?, ?)`

var selectUser = `SELECT id, name FROM users`

func main() {

    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    if _, err := db.Exec(createUsers); err != nil {
        panic(err)
    }

    if _, err := db.Exec(insertUser, 23, "skidoo"); err != nil {
        panic(err)
    }

    var id int64
    var name string
    row := db.QueryRow(selectUser)

    if err = row.Scan(&id, &name); err != nil {
        panic(err)
    }

    log.Println(id, name)

}<commit_msg>INSERT a NULL value and SELECT it back out<commit_after>package main

import (
	"database/sql"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

var createUsers = `
CREATE TABLE users (
    id INTEGER,
    name VARCHAR
);
`

var insertUser = `INSERT INTO users (id, name) VALUES (?, ?)`

var selectUser = `SELECT id, name FROM users`

type User struct {
	ID   int64
	Name sql.NullString
}

func (u User) String() string {
	if u.Name.Valid {
		return u.Name.String
	}
	return "No name"
}

func main() {
	// Connect to an in-memory sqlite3 instance
	db, err := sql.Open("sqlite3", ":memory:")
	if err != nil {
		panic(err)
	}
	defer db.Close()

	// Create the table
	if _, err := db.Exec(createUsers); err != nil {
		panic(err)
	}

	// Insert a user without a name
	if _, err := db.Exec(insertUser, 1, nil); err != nil {
		panic(err)
	}

	// Select a user
	var user User
	row := db.QueryRow(selectUser)
	if err = row.Scan(&user.ID, &user.Name); err != nil {
		panic(err)
	}
	log.Println(user)
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type method struct {
	args []interface{}
}

var parsed map[string]map[string]method

var suggested = [...]string{
	"io.Closer",
	"io.ReadCloser",
	"io.ReadWriter",
	"io.Reader",
	"io.Seeker",
	"io.WriteCloser",
	"io.Writer",
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]method, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		parsed[ifname] = make(map[string]method, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			m := method{}
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			params := sign.Params()
			for i := 0; i < params.Len(); i++ {
				p := params.At(i)
				m.args = append(m.args, p.Type())
			}
			parsed[ifname][fname] = m
		}
	}
}

func init() {
	typesInit()
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	default:
		return false
	}
}

func argsMatch(args1, args2 []interface{}) bool {
	if len(args1) != len(args2) {
		return false
	}
	for i, a1 := range args1 {
		a2 := args2[i]
		t1 := a1.(types.Type)
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(methods map[string]method) string {
	matchesIface := func(decls map[string]method) bool {
		if len(methods) > len(decls) {
			return false
		}
		for n, d := range decls {
			m, e := methods[n]
			if !e {
				return false
			}
			if !argsMatch(d.args, m.args) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	args map[string]types.Type
	used map[string]map[string]method
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		name := x.Name.Name
		scope := v.scopes[len(v.scopes)-1]
		f := scope.Lookup(name).(*types.Func)

		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		params := sign.Params()

		v.args = make(map[string]types.Type, params.Len())
		for i := 0; i < params.Len(); i++ {
			p := params.At(i)
			v.args[p.Name()] = p.Type()
		}
		v.used = make(map[string]map[string]method, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.args[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.args = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := method{}
	for _, a := range c.Args {
		m.args = append(m.args, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]method)
	}
	v.used[vname][fname] = m
}
<commit_msg>Separate flatten code into helper funcs<commit_after>/* Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc> */
/* See LICENSE for licensing information */

package main

import (
	"fmt"
	"go/ast"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io"
	"log"
	"os"
)

type method struct {
	args []interface{}
}

var parsed map[string]map[string]method

var suggested = [...]string{
	"io.Closer",
	"io.ReadCloser",
	"io.ReadWriter",
	"io.Reader",
	"io.Seeker",
	"io.WriteCloser",
	"io.Writer",
}

func typeList(t *types.Tuple) []interface{} {
	var l []interface{}
	for i := 0; i < t.Len(); i++ {
		v := t.At(i)
		l = append(l, v.Type())
	}
	return l
}

func typeMap(t *types.Tuple) map[string]types.Type {
	m := make(map[string]types.Type, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p.Name()] = p.Type()
	}
	return m
}

func typesInit() {
	fset := token.NewFileSet()
	// Simple program that imports and uses all needed packages
	const typesProgram = `
	package types
	import "io"
	func foo(r io.Reader) {
	}
	`
	f, err := parser.ParseFile(fset, "foo.go", typesProgram, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}
	pos := pkg.Scope().Lookup("foo").Pos()

	parsed = make(map[string]map[string]method, len(suggested))
	for _, v := range suggested {
		tv, err := types.Eval(fset, pkg, pos, v)
		if err != nil {
			log.Fatal(err)
		}
		t := tv.Type
		if !types.IsInterface(t) {
			log.Fatalf("%s is not an interface", v)
		}
		named := t.(*types.Named)
		ifname := named.String()
		iface := named.Underlying().(*types.Interface)
		parsed[ifname] = make(map[string]method, iface.NumMethods())
		for i := 0; i < iface.NumMethods(); i++ {
			f := iface.Method(i)
			fname := f.Name()
			sign := f.Type().(*types.Signature)
			parsed[ifname][fname] = method{
				args: typeList(sign.Params()),
			}
		}
	}
}

func init() {
	typesInit()
}

var toToken = map[string]token.Token{
	"int":   token.INT,
	"int32": token.INT,
	"int64": token.INT,
}

func argEqual(t1 types.Type, a2 interface{}) bool {
	switch x := a2.(type) {
	case string:
		return t1.String() == x
	case token.Token:
		return toToken[t1.String()] == x
	default:
		return false
	}
}

func argsMatch(args1, args2 []interface{}) bool {
	if len(args1) != len(args2) {
		return false
	}
	for i, a1 := range args1 {
		a2 := args2[i]
		t1 := a1.(types.Type)
		if !argEqual(t1, a2) {
			return false
		}
	}
	return true
}

func interfaceMatching(methods map[string]method) string {
	matchesIface := func(decls map[string]method) bool {
		if len(methods) > len(decls) {
			return false
		}
		for n, d := range decls {
			m, e := methods[n]
			if !e {
				return false
			}
			if !argsMatch(d.args, m.args) {
				return false
			}
		}
		return true
	}
	for name, decls := range parsed {
		if matchesIface(decls) {
			return name
		}
	}
	return ""
}

func main() {
	parseFile("stdin.go", os.Stdin, os.Stdout)
}

func parseFile(name string, r io.Reader, w io.Writer) {
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, name, r, 0)
	if err != nil {
		log.Fatal(err)
	}

	conf := types.Config{Importer: importer.Default()}
	pkg, err := conf.Check("", fset, []*ast.File{f}, nil)
	if err != nil {
		log.Fatal(err)
	}

	v := &Visitor{
		w:      w,
		fset:   fset,
		scopes: []*types.Scope{pkg.Scope()},
	}
	ast.Walk(v, f)
}

type Visitor struct {
	w      io.Writer
	fset   *token.FileSet
	scopes []*types.Scope

	nodes []ast.Node

	args map[string]types.Type
	used map[string]map[string]method
}

func (v *Visitor) Visit(node ast.Node) ast.Visitor {
	switch x := node.(type) {
	case *ast.File:
	case *ast.FuncDecl:
		name := x.Name.Name
		scope := v.scopes[len(v.scopes)-1]
		f := scope.Lookup(name).(*types.Func)

		v.scopes = append(v.scopes, f.Scope())
		sign := f.Type().(*types.Signature)
		v.args = typeMap(sign.Params())
		v.used = make(map[string]map[string]method, 0)
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.nodes[len(v.nodes)-1]
		v.nodes = v.nodes[:len(v.nodes)-1]
		if _, ok := top.(*ast.FuncDecl); !ok {
			return nil
		}
		v.scopes = v.scopes[:len(v.scopes)-1]
		for name, methods := range v.used {
			iface := interfaceMatching(methods)
			if iface == "" {
				continue
			}
			if iface == v.args[name].String() {
				continue
			}
			pos := v.fset.Position(top.Pos())
			fmt.Fprintf(v.w, "%s:%d: %s can be %s\n",
				pos.Filename, pos.Line, name, iface)
		}
		v.args = nil
		v.used = nil
	default:
		return nil
	}
	if node != nil {
		v.nodes = append(v.nodes, node)
	}
	return v
}

func getType(scope *types.Scope, name string) interface{} {
	if scope == nil {
		return nil
	}
	obj := scope.Lookup(name)
	if obj == nil {
		return getType(scope.Parent(), name)
	}
	switch x := obj.(type) {
	case *types.Var:
		return x.Type().String()
	default:
		return nil
	}
}

func (v *Visitor) descType(e ast.Expr) interface{} {
	switch x := e.(type) {
	case *ast.Ident:
		scope := v.scopes[len(v.scopes)-1]
		return getType(scope, x.Name)
	case *ast.BasicLit:
		return x.Kind
	default:
		return nil
	}
}

func (v *Visitor) onCall(c *ast.CallExpr) {
	sel, ok := c.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	right := sel.Sel
	vname := left.Name
	fname := right.Name
	m := method{}
	for _, a := range c.Args {
		m.args = append(m.args, v.descType(a))
	}
	if _, e := v.used[vname]; !e {
		v.used[vname] = make(map[string]method)
	}
	v.used[vname][fname] = m
}
<|endoftext|>


<commit_before>/*
Quick and simple monitoring system

Usage:
 jsonmon config.yml
 jsonmon -v # Prints version to stdout and exits

Environment:
 HOST: the JSON API network interface, defaults to localhost
 PORT: the JSON API port, defaults to 3000

More docs: https://github.com/chillum/jsonmon/wiki
*/
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

// Version is the application version.
const Version = "3.0.1"

// This one is for internal use.
type ver struct {
	App  string `json:"jsonmon"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

var version ver

// Check details.
type Check struct {
	Name   string `json:"name,omitempty" yaml:"name"`
	Web    string `json:"web,omitempty" yaml:"web"`
	Shell  string `json:"shell,omitempty" yaml:"shell"`
	Match  string `json:"-" yaml:"match"`
	Return int    `json:"-" yaml:"return"`
	Notify string `json:"-" yaml:"notify"`
	Alert  string `json:"-" yaml:"alert"`
	Tries  int    `json:"-" yaml:"tries"`
	Repeat int    `json:"-" yaml:"repeat"`
	Sleep  int    `json:"-" yaml:"sleep"`
	Failed bool   `json:"failed" yaml:"-"`
	Since  string `json:"since,omitempty" yaml:"-"`
}

// Global checks list. Need to share it with workers and Web UI.
var checks []Check

// Global started and last modified date for HTTP caching.
var modified string
var started string

var mutex *sync.RWMutex

// Construct the last modified string.
func etag(ts time.Time) string {
	return "W/\"" + strconv.FormatInt(ts.UnixNano(), 10) + "\""
}

// The main loop.
func main() {
	// Parse CLI args.
	usage := "Usage: " + path.Base(os.Args[0]) + " config.yml\n" +
		"Docs:  https://github.com/chillum/jsonmon/wiki"
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(1)
	}
	// -v for version.
	version.App = Version
	version.Go = runtime.Version()
	version.Os = runtime.GOOS
	version.Arch = runtime.GOARCH
	switch os.Args[1] {
	case "-h":
		fallthrough
	case "-help":
		fallthrough
	case "--help":
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(0)
	case "-v":
		fallthrough
	case "-version":
		fallthrough
	case "--version":
		json, _ := json.Marshal(&version)
		fmt.Println(string(json))
		os.Exit(0)
	}
	// Read config file or exit with error.
	config, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", err, "\n")
		os.Exit(3)
	}
	err = yaml.Unmarshal(config, &checks)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", "invalid config at ", os.Args[1], "\n", err, "\n")
		os.Exit(3)
	}
	// Exit with return code 0 on kill.
	done := make(chan os.Signal, 1)
	signal.Notify(done, syscall.SIGTERM)
	go func() {
		<-done
		os.Exit(0)
	}()
	// Run checks.
	started = etag(time.Now())
	modified = started
	mutex = &sync.RWMutex{}
	for i := range checks {
		go worker(&checks[i])
	}
	// Launch the JSON API.
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "3000"
	}
	http.HandleFunc("/status", getChecks)
	http.HandleFunc("/version", getVersion)
	http.HandleFunc("/", notFound)
	err = http.ListenAndServe(host+":"+port, nil)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", err, "\n")
	}
	os.Exit(4)
}

// Background worker.
func worker(check *Check) {
	if check.Shell == "" && check.Web == "" {
		fmt.Fprintln(os.Stderr, "<4>Ignoring entry with no either Web or shell check")
		mutex.Lock()
		check.Failed = true
		mutex.Unlock()
		return
	}
	if check.Shell != "" && check.Web != "" {
		fmt.Fprint(os.Stderr,
			"<3>Web and shell checks in one block are not allowed\n",
			"<3>Disabled: ", check.Shell, "\n",
			"<3>Disabled: ", check.Web, "\n")
		mutex.Lock()
		check.Failed = true
		mutex.Unlock()
		return
	}
	mutex.Lock()
	if check.Repeat == 0 { // Set default timeout.
		check.Repeat = 30
	}
	if check.Tries == 0 { // Default to 1 attempt.
		check.Tries = 1
	}
	mutex.Unlock()
	repeat := time.Second * time.Duration(check.Repeat)
	sleep := time.Second * time.Duration(check.Sleep)
	var name string
	if check.Web != "" {
		if check.Name != "" { // Set check's display name.
			name = check.Name
		} else {
			name = check.Web
		}
		if check.Return == 0 { // Successful HTTP return code is 200.
			mutex.Lock()
			check.Return = 200
			mutex.Unlock()
		}
		for {
			web(check, &name, &sleep)
			time.Sleep(repeat)
		}
	} else {
		if check.Name != "" { // Set check's display name.
			name = check.Name
		} else {
			name = check.Shell
		}
		for {
			shell(check, &name, &sleep)
			time.Sleep(repeat)
		}
	}
}

// Shell worker.
func shell(check *Check, name *string, sleep *time.Duration) {
	// Execute with shell in N attemps.
	var out []byte
	var err error
	for i := 0; i < check.Tries; {
		out, err = exec.Command("/bin/sh", "-c", check.Shell).CombinedOutput()
		if err == nil {
			if check.Match != "" { // Match regexp.
				var regex *regexp.Regexp
				regex, err = regexp.Compile(check.Match)
				if err == nil && !regex.Match(out) {
					err = errors.New("Expected:\n" + check.Match + "\n\nGot:\n" + string(out))
				}
			}
			break
		}
		i++
		if i < check.Tries {
			time.Sleep(*sleep)
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = false
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			subject := "Fixed: " + *name
			log(&subject, nil)
			if check.Notify != "" {
				notify(check, &subject, nil)
			}
			if check.Alert != "" {
				alert(check, name, nil, false)
			}
		}
	} else {
		if !check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = true
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			msg := string(out) + err.Error()
			subject := "Failed: " + *name
			log(&subject, &msg)
			if check.Notify != "" {
				notify(check, &subject, &msg)
			}
			if check.Alert != "" {
				alert(check, name, &msg, true)
			}
		}
	}
}

// Web worker.
func web(check *Check, name *string, sleep *time.Duration) {
	// Get the URL in N attempts.
	var err error
	for i := 0; i < check.Tries; {
		err = fetch(check.Web, check.Match, check.Return)
		if err == nil {
			break
		}
		i++
		if i < check.Tries {
			time.Sleep(*sleep)
		}
	}
	if err == nil {
		if check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = false
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			subject := "Fixed: " + *name
			log(&subject, nil)
			if check.Notify != "" {
				notify(check, &subject, nil)
			}
			if check.Alert != "" {
				alert(check, name, nil, false)
			}
		}
	} else {
		if !check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = true
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			msg := err.Error()
			subject := "Failed: " + *name
			log(&subject, &msg)
			if check.Notify != "" {
				notify(check, &subject, &msg)
			}
			if check.Alert != "" {
				alert(check, name, &msg, true)
			}
		}
	}
}

// Check HTTP redirects.
func redirect(req *http.Request, via []*http.Request) error {
	// When redirects number > 10 probably there's a problem.
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	// Redirects don't get User-Agent.
	req.Header.Set("User-Agent", "jsonmon")
	return nil
}

// The actual HTTP GET.
func fetch(url string, match string, code int) error {
	var err error
	var resp *http.Response
	var req *http.Request
	client := &http.Client{}
	client.CheckRedirect = redirect
	req, err = http.NewRequest("GET", url, nil)
	if err == nil {
		req.Header.Set("User-Agent", "jsonmon")
		resp, err = client.Do(req)
		if err == nil {
			if resp.StatusCode != code { // Check status code.
				err = errors.New(url + " returned " + strconv.Itoa(resp.StatusCode))
			} else { // Match regexp.
				if resp != nil && match != "" {
					var regex *regexp.Regexp
					regex, err = regexp.Compile(match)
					if err == nil {
						var body []byte
						body, _ = ioutil.ReadAll(resp.Body)
						if !regex.Match(body) {
							err = errors.New("Expected:\n" + match + "\n\nGot:\n" + string(body))
						}
					}
				}
			}
		}
	}
	if resp != nil {
		resp.Body.Close()
	}
	return err
}

// Logs status changes to stdout.
func log(subject *string, message *string) {
	// Log the alerts.
	if message == nil {
		fmt.Print("<5>", *subject, "\n")
	} else {
		fmt.Print("<5>", *subject, "\n", *message, "\n")
	}
}

// Mail notifications.
func notify(check *Check, subject *string, message *string) {
	// Make the message.
	var msg bytes.Buffer
	msg.WriteString("To: ")
	msg.WriteString(check.Notify)
	msg.WriteString("\nSubject: ")
	msg.WriteString(*subject)
	msg.WriteString("\nX-Mailer: jsonmon\n\n")
	if message != nil {
		msg.WriteString(*message)
	}
	msg.WriteString("\n.\n")
	// And send it.
	sendmail := exec.Command("/usr/sbin/sendmail", "-t")
	stdin, _ := sendmail.StdinPipe()
	err := sendmail.Start()
	if err != nil {
		fmt.Fprint(os.Stderr, "<3>", err, "\n")
	}
	io.WriteString(stdin, msg.String())
	sendmail.Wait()
}

// Executes callback. Passes args: true/false, check's name, message.
func alert(check *Check, name *string, msg *string, failed bool) {
	var out []byte
	var err error
	if msg != nil {
		out, err = exec.Command(check.Alert, strconv.FormatBool(failed), *name, *msg).CombinedOutput()
	} else {
		out, err = exec.Command(check.Alert, strconv.FormatBool(failed), *name).CombinedOutput()
	}
	if err != nil {
		fmt.Fprint(os.Stderr, "<3>", check.Alert, " failed\n", string(out), err.Error(), "\n")
	}
}

// 404 error.
func notFound(w http.ResponseWriter, r *http.Request) {
	h := w.Header()
	h.Set("Server", "jsonmon")
	http.NotFound(w, r)
}

// Display checks' details.
func getChecks(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &checks, &modified, true)
}

// Display application version.
func getVersion(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &version, &started, false)
}

// Output JSON.
func displayJSON(w http.ResponseWriter, r *http.Request, data interface{}, cache *string, lock bool) {
	var cached bool
	var result []byte
	h := w.Header()
	h.Set("Server", "jsonmon")
	if lock {
		mutex.RLock()
	}
	if r.Header.Get("If-None-Match") == *cache {
		cached = true
	} else {
		h.Set("ETag", *cache)
		result, _ = json.Marshal(&data)
	}
	if lock {
		mutex.RUnlock()
	}
	if cached {
		w.WriteHeader(http.StatusNotModified)
	} else {
		h.Set("Cache-Control", "no-cache")
		h.Set("Access-Control-Allow-Origin", "*")
		h.Set("X-Content-Type-Options", "nosniff")
		h.Set("Content-Type", "application/json; charset=utf-8")
		w.Write(result)
	}
}
<commit_msg>revert comment back<commit_after>/*
Quick and simple monitoring system

Usage:
 jsonmon config.yml
 jsonmon -v # Prints version to stdout and exits

Environment:
 HOST: the JSON API network interface, defaults to localhost
 PORT: the JSON API port, defaults to 3000

More docs: https://github.com/chillum/jsonmon/wiki
*/
package main

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gopkg.in/yaml.v2"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"regexp"
	"runtime"
	"strconv"
	"sync"
	"syscall"
	"time"
)

// Version is the application version.
const Version = "3.0.1"

// This one is for internal use.
type ver struct {
	App  string `json:"jsonmon"`
	Go   string `json:"runtime"`
	Os   string `json:"os"`
	Arch string `json:"arch"`
}

var version ver

// Check details.
type Check struct {
	Name   string `json:"name,omitempty" yaml:"name"`
	Web    string `json:"web,omitempty" yaml:"web"`
	Shell  string `json:"shell,omitempty" yaml:"shell"`
	Match  string `json:"-" yaml:"match"`
	Return int    `json:"-" yaml:"return"`
	Notify string `json:"-" yaml:"notify"`
	Alert  string `json:"-" yaml:"alert"`
	Tries  int    `json:"-" yaml:"tries"`
	Repeat int    `json:"-" yaml:"repeat"`
	Sleep  int    `json:"-" yaml:"sleep"`
	Failed bool   `json:"failed" yaml:"-"`
	Since  string `json:"since,omitempty" yaml:"-"`
}

// Global checks list. Need to share it with workers and Web UI.
var checks []Check

// Global started and last modified date for HTTP caching.
var modified string
var started string

var mutex *sync.RWMutex

// Construct the last modified string.
func etag(ts time.Time) string {
	return "W/\"" + strconv.FormatInt(ts.UnixNano(), 10) + "\""
}

// The main loop.
func main() {
	// Parse CLI args.
	usage := "Usage: " + path.Base(os.Args[0]) + " config.yml\n" +
		"Docs:  https://github.com/chillum/jsonmon/wiki"
	if len(os.Args) != 2 {
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(1)
	}
	// -v for version.
	version.App = Version
	version.Go = runtime.Version()
	version.Os = runtime.GOOS
	version.Arch = runtime.GOARCH
	switch os.Args[1] {
	case "-h":
		fallthrough
	case "-help":
		fallthrough
	case "--help":
		fmt.Fprintln(os.Stderr, usage)
		os.Exit(0)
	case "-v":
		fallthrough
	case "-version":
		fallthrough
	case "--version":
		json, _ := json.Marshal(&version)
		fmt.Println(string(json))
		os.Exit(0)
	}
	// Read config file or exit with error.
	config, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", err, "\n")
		os.Exit(3)
	}
	err = yaml.Unmarshal(config, &checks)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", "invalid config at ", os.Args[1], "\n", err, "\n")
		os.Exit(3)
	}
	// Exit with return code 0 on kill.
	done := make(chan os.Signal, 1)
	signal.Notify(done, syscall.SIGTERM)
	go func() {
		<-done
		os.Exit(0)
	}()
	// Run checks.
	started = etag(time.Now())
	modified = started
	mutex = &sync.RWMutex{}
	for i := range checks {
		go worker(&checks[i])
	}
	// Launch the JSON API.
	host := os.Getenv("HOST")
	port := os.Getenv("PORT")
	if host == "" {
		host = "localhost"
	}
	if port == "" {
		port = "3000"
	}
	http.HandleFunc("/status", getChecks)
	http.HandleFunc("/version", getVersion)
	http.HandleFunc("/", notFound)
	err = http.ListenAndServe(host+":"+port, nil)
	if err != nil {
		fmt.Fprint(os.Stderr, "<2>", err, "\n")
	}
	os.Exit(4)
}

// Background worker.
func worker(check *Check) {
	if check.Shell == "" && check.Web == "" {
		fmt.Fprintln(os.Stderr, "<4>Ignoring entry with no either Web or shell check")
		mutex.Lock()
		check.Failed = true
		mutex.Unlock()
		return
	}
	if check.Shell != "" && check.Web != "" {
		fmt.Fprint(os.Stderr,
			"<3>Web and shell checks in one block are not allowed\n",
			"<3>Disabled: ", check.Shell, "\n",
			"<3>Disabled: ", check.Web, "\n")
		mutex.Lock()
		check.Failed = true
		mutex.Unlock()
		return
	}
	mutex.Lock()
	if check.Repeat == 0 { // Set default timeout.
		check.Repeat = 30
	}
	if check.Tries == 0 { // Default to 1 attempt.
		check.Tries = 1
	}
	mutex.Unlock()
	repeat := time.Second * time.Duration(check.Repeat)
	sleep := time.Second * time.Duration(check.Sleep)
	var name string
	if check.Web != "" {
		if check.Name != "" { // Set check's display name.
			name = check.Name
		} else {
			name = check.Web
		}
		if check.Return == 0 { // Successful HTTP return code is 200.
			mutex.Lock()
			check.Return = 200
			mutex.Unlock()
		}
		for {
			web(check, &name, &sleep)
			time.Sleep(repeat)
		}
	} else {
		if check.Name != "" { // Set check's display name.
			name = check.Name
		} else {
			name = check.Shell
		}
		for {
			shell(check, &name, &sleep)
			time.Sleep(repeat)
		}
	}
}

// Shell worker.
func shell(check *Check, name *string, sleep *time.Duration) {
	// Execute with shell in N attemps.
	var out []byte
	var err error
	for i := 0; i < check.Tries; {
		out, err = exec.Command("/bin/sh", "-c", check.Shell).CombinedOutput()
		if err == nil {
			if check.Match != "" { // Match regexp.
				var regex *regexp.Regexp
				regex, err = regexp.Compile(check.Match)
				if err == nil && !regex.Match(out) {
					err = errors.New("Expected:\n" + check.Match + "\n\nGot:\n" + string(out))
				}
			}
			break
		}
		i++
		if i < check.Tries {
			time.Sleep(*sleep)
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = false
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			subject := "Fixed: " + *name
			log(&subject, nil)
			if check.Notify != "" {
				notify(check, &subject, nil)
			}
			if check.Alert != "" {
				alert(check, name, nil, false)
			}
		}
	} else {
		if !check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = true
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			msg := string(out) + err.Error()
			subject := "Failed: " + *name
			log(&subject, &msg)
			if check.Notify != "" {
				notify(check, &subject, &msg)
			}
			if check.Alert != "" {
				alert(check, name, &msg, true)
			}
		}
	}
}

// Web worker.
func web(check *Check, name *string, sleep *time.Duration) {
	// Get the URL in N attempts.
	var err error
	for i := 0; i < check.Tries; {
		err = fetch(check.Web, check.Match, check.Return)
		if err == nil {
			break
		}
		i++
		if i < check.Tries {
			time.Sleep(*sleep)
		}
	}
	// Process results.
	if err == nil {
		if check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = false
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			subject := "Fixed: " + *name
			log(&subject, nil)
			if check.Notify != "" {
				notify(check, &subject, nil)
			}
			if check.Alert != "" {
				alert(check, name, nil, false)
			}
		}
	} else {
		if !check.Failed {
			ts := time.Now()
			mutex.Lock()
			check.Failed = true
			check.Since = ts.Format(time.RFC3339)
			modified = etag(ts)
			mutex.Unlock()
			msg := err.Error()
			subject := "Failed: " + *name
			log(&subject, &msg)
			if check.Notify != "" {
				notify(check, &subject, &msg)
			}
			if check.Alert != "" {
				alert(check, name, &msg, true)
			}
		}
	}
}

// Check HTTP redirects.
func redirect(req *http.Request, via []*http.Request) error {
	// When redirects number > 10 probably there's a problem.
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	// Redirects don't get User-Agent.
	req.Header.Set("User-Agent", "jsonmon")
	return nil
}

// The actual HTTP GET.
func fetch(url string, match string, code int) error {
	var err error
	var resp *http.Response
	var req *http.Request
	client := &http.Client{}
	client.CheckRedirect = redirect
	req, err = http.NewRequest("GET", url, nil)
	if err == nil {
		req.Header.Set("User-Agent", "jsonmon")
		resp, err = client.Do(req)
		if err == nil {
			if resp.StatusCode != code { // Check status code.
				err = errors.New(url + " returned " + strconv.Itoa(resp.StatusCode))
			} else { // Match regexp.
				if resp != nil && match != "" {
					var regex *regexp.Regexp
					regex, err = regexp.Compile(match)
					if err == nil {
						var body []byte
						body, _ = ioutil.ReadAll(resp.Body)
						if !regex.Match(body) {
							err = errors.New("Expected:\n" + match + "\n\nGot:\n" + string(body))
						}
					}
				}
			}
		}
	}
	if resp != nil {
		resp.Body.Close()
	}
	return err
}

// Logs status changes to stdout.
func log(subject *string, message *string) {
	// Log the alerts.
	if message == nil {
		fmt.Print("<5>", *subject, "\n")
	} else {
		fmt.Print("<5>", *subject, "\n", *message, "\n")
	}
}

// Mail notifications.
func notify(check *Check, subject *string, message *string) {
	// Make the message.
	var msg bytes.Buffer
	msg.WriteString("To: ")
	msg.WriteString(check.Notify)
	msg.WriteString("\nSubject: ")
	msg.WriteString(*subject)
	msg.WriteString("\nX-Mailer: jsonmon\n\n")
	if message != nil {
		msg.WriteString(*message)
	}
	msg.WriteString("\n.\n")
	// And send it.
	sendmail := exec.Command("/usr/sbin/sendmail", "-t")
	stdin, _ := sendmail.StdinPipe()
	err := sendmail.Start()
	if err != nil {
		fmt.Fprint(os.Stderr, "<3>", err, "\n")
	}
	io.WriteString(stdin, msg.String())
	sendmail.Wait()
}

// Executes callback. Passes args: true/false, check's name, message.
func alert(check *Check, name *string, msg *string, failed bool) {
	var out []byte
	var err error
	if msg != nil {
		out, err = exec.Command(check.Alert, strconv.FormatBool(failed), *name, *msg).CombinedOutput()
	} else {
		out, err = exec.Command(check.Alert, strconv.FormatBool(failed), *name).CombinedOutput()
	}
	if err != nil {
		fmt.Fprint(os.Stderr, "<3>", check.Alert, " failed\n", string(out), err.Error(), "\n")
	}
}

// 404 error.
func notFound(w http.ResponseWriter, r *http.Request) {
	h := w.Header()
	h.Set("Server", "jsonmon")
	http.NotFound(w, r)
}

// Display checks' details.
func getChecks(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &checks, &modified, true)
}

// Display application version.
func getVersion(w http.ResponseWriter, r *http.Request) {
	displayJSON(w, r, &version, &started, false)
}

// Output JSON.
func displayJSON(w http.ResponseWriter, r *http.Request, data interface{}, cache *string, lock bool) {
	var cached bool
	var result []byte
	h := w.Header()
	h.Set("Server", "jsonmon")
	if lock {
		mutex.RLock()
	}
	if r.Header.Get("If-None-Match") == *cache {
		cached = true
	} else {
		h.Set("ETag", *cache)
		result, _ = json.Marshal(&data)
	}
	if lock {
		mutex.RUnlock()
	}
	if cached {
		w.WriteHeader(http.StatusNotModified)
	} else {
		h.Set("Cache-Control", "no-cache")
		h.Set("Access-Control-Allow-Origin", "*")
		h.Set("X-Content-Type-Options", "nosniff")
		h.Set("Content-Type", "application/json; charset=utf-8")
		w.Write(result)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/jmreicha/stalker/util"
)

func main() {

	//util.PrintStarredRepos()
	//util.PrintFromConfig()

	util.UpdateStarredRepos()
	util.IterateStarredRepos()
	/* Testing functions
	GetToken()							// Helper function to list api token
	RecentTags()						// Function to list paged results of recent tags
	GetStarredRepos("jmreicha")			// List starred repo for a given user
	LatestTag("rancher", "rancher")		// Get the latest github tag for a project
	LatestRelease("rancher", "rancher")	// Get the latest github release for a project
	TestLatestTag("lukasz-madon", "awesome-remote-job")  //Case where there is no tag
	*/

}
<commit_msg>Set correct default<commit_after>package main

import (
	"github.com/jmreicha/stalker/util"
)

func main() {

	util.PrintStarredRepos()
	//util.PrintFromConfig()

	//util.UpdateStarredRepos()
	//util.IterateStarredRepos()
	/* Testing functions
	GetToken()							// Helper function to list api token
	RecentTags()						// Function to list paged results of recent tags
	GetStarredRepos("jmreicha")			// List starred repo for a given user
	LatestTag("rancher", "rancher")		// Get the latest github tag for a project
	LatestRelease("rancher", "rancher")	// Get the latest github release for a project
	TestLatestTag("lukasz-madon", "awesome-remote-job")  //Case where there is no tag
	*/

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/Ray-GuanhuiLiang/GoGuidGenerator/guid"
	"github.com/Ray-GuanhuiLiang/GoGuidGenerator/net"
	"fmt"
)

func main() {
	g, err := guid.NewGuid()
	if err != nil {
		fmt.Println(err)
		return
	}
	s := server.NewTcpServer(*g)
	s.Start()
	s.Wait()
	fmt.Println("server end")
}
<commit_msg>修复一个指针bug<commit_after>package main

import (
	"github.com/Ray-GuanhuiLiang/GoGuidGenerator/guid"
	"github.com/Ray-GuanhuiLiang/GoGuidGenerator/net"
	"fmt"
)

func main() {
	g, err := guid.NewGuid()
	if err != nil {
		fmt.Println(err)
		return
	}
	s := server.NewTcpServer(g)
	s.Start()
	s.Wait()
	fmt.Println("server end")
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"fmt"
	"log"
	"net/url"
	"psychic-rat/mdl/item"
	"psychic-rat/mdl/user"
	"psychic-rat/ctr"
	"psychic-rat/mdl/company"
)

type MethodHandler func(http.ResponseWriter, *http.Request)

type HandlerMap struct {
	PathExpr string
	Method   string
	Handler  MethodHandler
}

func main() {
	http.HandleFunc("/api/v1/pledge", pledgeHandler)
	http.HandleFunc("/api/v1/item", itemHandler)
	http.ListenAndServe("localhost:8080", nil)
}

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

	handlerMaps := map[string]MethodHandler{
		http.MethodPost: handlePledgePost,
		http.MethodGet:  handleGet,
	}

	fmt.Printf("%v", request)
	v, ok := handlerMaps[request.Method]
	if ! ok {
		unsupportedMethod(writer)
		return
	}
	v(writer, request)
}

func unsupportedMethod(writer http.ResponseWriter) {
	fmt.Fprintf(writer, "unsupported method")
}

func handlePledgePost(writer http.ResponseWriter, request *http.Request) {
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}
	itemId, userId, err := parsePledgePost(request.Form)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
		return
	}

	err = ctr.GetController().Pledge().AddPledge(itemId, userId)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
	}
}

func unableToParseForm(err error, writer http.ResponseWriter) {
	fmt.Fprintf(writer, "error in form data")
	log.Print(err)
}

func parsePledgePost(values url.Values) (itemId item.Id, userId user.Id, err error) {
	const (
		Item = "item"
	)

	params, ok := extractFormParams(values, Item)
	if ! ok {
		return itemId, userId, fmt.Errorf("missing values, only got %v", params)
	}

	return item.Id(params[Item]), user.Id(0), nil
}

func extractFormParams(values url.Values, params ...string) (results map[string]string, gotAllParams bool) {
	gotAllParams = true
	for _, p := range (params) {
		v, ok := values[p]
		if ! ok {
			gotAllParams = false
			continue
		}
		results[p] = v[0]
	}
	return results, gotAllParams
}

func handleGet(writer http.ResponseWriter, request *http.Request) {
	const message = "Welcome"
	fmt.Fprintf(writer, message)
}

func itemHandler(writer http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet {
		handleItemGet(writer, request)
		return
	}
	if request.Method != http.MethodPost {
		unsupportedMethod(writer)
		return
	}
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}

	const (
		Make    = "make"
		Model   = "model"
		Company = "company"
	)
	params, ok := extractFormParams(request.Form, Make, Model, Company)
	if ! ok {
		fmt.Fprintf(writer, "form parameters missing: got %v", params)
	}

	err := ctr.GetController().Item().AddItem(params[Make], params[Model], company.Id(params[Company]))
	if err != nil {
		errorResponse(writer, err)
	}

}

func errorResponse(writer http.ResponseWriter, err error) {
	fmt.Fprintf(writer, "error: %v", err)
}

func handleItemGet(writer http.ResponseWriter, request *http.Request) {
	items := ctr.GetController().Item().ListItems()
	fmt.Fprintf(writer, "items: %v", items)
}
<commit_msg>init map<commit_after>package main

import (
	"net/http"
	"fmt"
	"log"
	"net/url"
	"psychic-rat/mdl/item"
	"psychic-rat/mdl/user"
	"psychic-rat/ctr"
	"psychic-rat/mdl/company"
)

type MethodHandler func(http.ResponseWriter, *http.Request)

type HandlerMap struct {
	PathExpr string
	Method   string
	Handler  MethodHandler
}

func main() {
	http.HandleFunc("/api/v1/pledge", pledgeHandler)
	http.HandleFunc("/api/v1/item", itemHandler)
	http.ListenAndServe("localhost:8080", nil)
}

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

	handlerMaps := map[string]MethodHandler{
		http.MethodPost: handlePledgePost,
		http.MethodGet:  handleGet,
	}

	fmt.Printf("%v", request)
	v, ok := handlerMaps[request.Method]
	if ! ok {
		unsupportedMethod(writer)
		return
	}
	v(writer, request)
}

func unsupportedMethod(writer http.ResponseWriter) {
	fmt.Fprintf(writer, "unsupported method")
}

func handlePledgePost(writer http.ResponseWriter, request *http.Request) {
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}
	itemId, userId, err := parsePledgePost(request.Form)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
		return
	}

	err = ctr.GetController().Pledge().AddPledge(itemId, userId)
	if err != nil {
		fmt.Fprintf(writer, "error: %v", err)
	}
}

func unableToParseForm(err error, writer http.ResponseWriter) {
	fmt.Fprintf(writer, "error in form data")
	log.Print(err)
}

func parsePledgePost(values url.Values) (itemId item.Id, userId user.Id, err error) {
	const (
		Item = "item"
	)

	params, ok := extractFormParams(values, Item)
	if ! ok {
		return itemId, userId, fmt.Errorf("missing values, only got %v", params)
	}

	return item.Id(params[Item]), user.Id(0), nil
}

func extractFormParams(values url.Values, params ...string) (results map[string]string, gotAllParams bool) {
	results = make(map[string]string)
	gotAllParams = true
	for _, p := range (params) {
		v, ok := values[p]
		if ! ok {
			gotAllParams = false
			continue
		}
		results[p] = v[0]
	}
	return results, gotAllParams
}

func handleGet(writer http.ResponseWriter, request *http.Request) {
	const message = "Welcome"
	fmt.Fprintf(writer, message)
}

func itemHandler(writer http.ResponseWriter, request *http.Request) {
	if request.Method == http.MethodGet {
		handleItemGet(writer, request)
		return
	}
	if request.Method != http.MethodPost {
		unsupportedMethod(writer)
		return
	}
	if err := request.ParseForm(); err != nil {
		unableToParseForm(err, writer)
		return
	}

	const (
		Make    = "make"
		Model   = "model"
		Company = "company"
	)
	params, ok := extractFormParams(request.Form, Make, Model, Company)
	if ! ok {
		fmt.Fprintf(writer, "form parameters missing: got %v", params)
	}

	err := ctr.GetController().Item().AddItem(params[Make], params[Model], company.Id(params[Company]))
	if err != nil {
		errorResponse(writer, err)
	}

}

func errorResponse(writer http.ResponseWriter, err error) {
	fmt.Fprintf(writer, "error: %v", err)
}

func handleItemGet(writer http.ResponseWriter, request *http.Request) {
	items := ctr.GetController().Item().ListItems()
	fmt.Fprintf(writer, "items: %v", items)
}
<|endoftext|>