<commit_before>// Copyright 2013 Christopher Swenson. All rights reserved.
// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"
)

type Slide struct {
	Contents string
	Notes    string
}

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
	slidesFile = flag.String("slides", "slides.go", "Slides file to read in")
	slides     []Slide
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	readSlides()

	http.HandleFunc("/", FrontPage)
	http.HandleFunc("/compile", Compile)
	fmt.Printf("Listening on %s\n", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

func readSlides() {
	slidesRaw, err := ioutil.ReadFile(*slidesFile)
	if err != nil {
		panic(err)
	}
	splitSlides := strings.Split(string(slidesRaw), "//!")
	slides = make([]Slide, 0, len(splitSlides))
	for _, slideString := range splitSlides {
		trimmed := strings.TrimSpace(slideString)
		if len(trimmed) == 0 {
			continue
		}
		s := strings.Split(trimmed, "/*--")
		notes := ""
		if len(s) == 2 {
			notes = strings.TrimSuffix(s[1], "*/")
		}
		slides = append(slides, Slide{s[0], notes})
	}
}

type PageData struct {
	Contents  string
	Notes     string
	PrevSlide int64
	NextSlide int64
}

// FrontPage is an HTTP handler that renders the goplay interface.
// If a filename is supplied in the path component of the URI,
// its contents will be put in the interface's text area.
// Otherwise, the default "hello, world" program is displayed.
func FrontPage(w http.ResponseWriter, req *http.Request) {
	data, err := ioutil.ReadFile(req.URL.Path[1:])
	notes := ""
	slide := int64(0)
	if s := req.URL.Query()["s"]; s != nil {
		slide, _ = strconv.ParseInt(s[0], 10, 16)
	}
	var cont string
	if err != nil {
		cont = slides[slide].Contents
		notes = slides[slide].Notes
	} else {
		cont = string(data)
	}
	prevSlide := slide - 1
	if prevSlide < 0 {
		prevSlide = 0
	}
	nextSlide := slide + 1
	if int(nextSlide) >= len(slides) {
		nextSlide = slide
	}
	params := PageData{cont, notes, prevSlide, nextSlide}
	frontPage.Execute(w, params)
}

// Compile is an HTTP handler that reads Go source code from the request,
// runs the program (returning any errors),
// and sends the program's output as the HTTP response.
func Compile(w http.ResponseWriter, req *http.Request) {
	out, err := compile(req)
	if err != nil {
		error_(w, out, err)
		return
	}

	// write the output of x as the http response
	if *htmlOutput {
		w.Write(out)
	} else {
		output.Execute(w, out)
	}
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	packageRe = regexp.MustCompile(`^package`)
	importRe  = regexp.MustCompile(`\nimport .*`)
	tmpdir    string
)

func init() {
	// find real temporary directory (for rewriting filename in output)
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

func compile(req *http.Request) (out []byte, err error) {
	// x is the base name for .go, .6, executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		if err != nil {
			// drop messages from the go tool like '# _/compile0'
			out = commentRe.ReplaceAll(out, nil)
		}
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := new(bytes.Buffer)
	if _, err = body.ReadFrom(req.Body); err != nil {
		return
	}

	originalBodyBytes := body.Bytes()
	var bodyBytes []byte

	// check to see if the body starts with a "package"
	if packageRe.Find(originalBodyBytes) == nil {
		newBody := new(bytes.Buffer)
		newBody.WriteString("package main\n")
		// move all import lines to the top
		for _, importLine := range importRe.FindAll(originalBodyBytes, -1) {
			newBody.Write(importLine)
			newBody.WriteRune(10)
		}
		newBody.WriteString("func main() {\n")
		newBody.Write(importRe.ReplaceAll(originalBodyBytes, make([]byte, 0)))
		newBody.WriteString("\n}\n")
		bodyBytes = newBody.Bytes()
	} else {
		bodyBytes = originalBodyBytes
	}

	defer os.Remove(src)
	if err = ioutil.WriteFile(src, bodyBytes, 0666); err != nil {
		return
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	out, err = run(dir, "go", "build", "-o", bin, file)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run("", bin)
}

// error writes compile, link, or runtime errors to the HTTP connection.
// The JavaScript interface uses the 404 status code to identify the error.
func error_(w http.ResponseWriter, out []byte, err error) {
	w.WriteHeader(404)
	if out != nil {
		output.Execute(w, out)
	} else {
		output.Execute(w, err.Error())
	}
}

// run executes the specified command and returns its output and an error.
func run(dir string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout
	err := cmd.Run()
	return buf.Bytes(), err
}

var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
var output = template.Must(template.New("output").Parse(outputText))          // HTML template

var outputText = `<pre>{{printf "%s" . |html}}</pre>`

var frontPageText = `<!doctype html>

<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{printf "%s" .Contents |html}}</textarea>

(Shift-Enter to compile and run.)
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
<button id="noteButton" onclick="toggleNotes()">Hide notes</button>
<button onclick="window.location.href = '/?s={{ printf "%d" .PrevSlide }}'">Previous</button>
<button onclick="window.location.href = '/?s={{ printf "%d" .NextSlide }}'">Next</button>

{{ printf "%s" .Notes |html}}

`
<commit_msg>static HTML generator<commit_after>// Copyright 2013 Christopher Swenson. All rights reserved.
// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"
)

type Slide struct {
	Contents string
	Notes    string
}

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput = flag.Bool("html", false, "render program output as HTML")
	slidesFile = flag.String("slides", "slides.go", "Slides file to read in")
	staticHTML = flag.String("static", "", "write slides to static HTML file")
	slides     []Slide
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)
)

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	readSlides()
	if *staticHTML != "" {
		fmt.Println("Writing to file", *staticHTML)
		f, err := os.Create(*staticHTML)
		if err != nil {
			log.Fatal(err)
		}
		err = staticPage.Execute(f, slides)
		f.Close()
	} else {
		http.HandleFunc("/", FrontPage)
		http.HandleFunc("/compile", Compile)
		fmt.Printf("Listening on %s\n", *httpListen)
		log.Fatal(http.ListenAndServe(*httpListen, nil))
	}
}

func readSlides() {
	slidesRaw, err := ioutil.ReadFile(*slidesFile)
	if err != nil {
		panic(err)
	}
	splitSlides := strings.Split(string(slidesRaw), "//!")
	slides = make([]Slide, 0, len(splitSlides))
	for _, slideString := range splitSlides {
		trimmed := strings.TrimSpace(slideString)
		if len(trimmed) == 0 {
			continue
		}
		s := strings.Split(trimmed, "/*--")
		notes := ""
		if len(s) == 2 {
			notes = strings.TrimSuffix(s[1], "*/")
		}
		slides = append(slides, Slide{s[0], notes})
	}
}

type PageData struct {
	Contents  string
	Notes     string
	PrevSlide int64
	NextSlide int64
}

// FrontPage is an HTTP handler that renders the goplay interface.
// If a filename is supplied in the path component of the URI,
// its contents will be put in the interface's text area.
// Otherwise, the default "hello, world" program is displayed.
func FrontPage(w http.ResponseWriter, req *http.Request) {
	data, err := ioutil.ReadFile(req.URL.Path[1:])
	notes := ""
	slide := int64(0)
	if s := req.URL.Query()["s"]; s != nil {
		slide, _ = strconv.ParseInt(s[0], 10, 16)
	}
	var cont string
	if err != nil {
		cont = slides[slide].Contents
		notes = slides[slide].Notes
	} else {
		cont = string(data)
	}
	prevSlide := slide - 1
	if prevSlide < 0 {
		prevSlide = 0
	}
	nextSlide := slide + 1
	if int(nextSlide) >= len(slides) {
		nextSlide = slide
	}
	params := PageData{cont, notes, prevSlide, nextSlide}
	frontPage.Execute(w, params)
}

// Compile is an HTTP handler that reads Go source code from the request,
// runs the program (returning any errors),
// and sends the program's output as the HTTP response.
func Compile(w http.ResponseWriter, req *http.Request) {
	out, err := compile(req)
	if err != nil {
		error_(w, out, err)
		return
	}

	// write the output of x as the http response
	if *htmlOutput {
		w.Write(out)
	} else {
		output.Execute(w, out)
	}
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	packageRe = regexp.MustCompile(`^package`)
	importRe  = regexp.MustCompile(`\nimport .*`)
	tmpdir    string
)

func init() {
	// find real temporary directory (for rewriting filename in output)
	var err error
	tmpdir, err = filepath.EvalSymlinks(os.TempDir())
	if err != nil {
		log.Fatal(err)
	}
}

func compile(req *http.Request) (out []byte, err error) {
	// x is the base name for .go, .6, executable files
	x := filepath.Join(tmpdir, "compile"+strconv.Itoa(<-uniq))
	src := x + ".go"
	bin := x
	if runtime.GOOS == "windows" {
		bin += ".exe"
	}

	// rewrite filename in error output
	defer func() {
		if err != nil {
			// drop messages from the go tool like '# _/compile0'
			out = commentRe.ReplaceAll(out, nil)
		}
		out = bytes.Replace(out, []byte(src+":"), []byte("main.go:"), -1)
	}()

	// write body to x.go
	body := new(bytes.Buffer)
	if _, err = body.ReadFrom(req.Body); err != nil {
		return
	}

	originalBodyBytes := body.Bytes()
	var bodyBytes []byte

	// check to see if the body starts with a "package"
	if packageRe.Find(originalBodyBytes) == nil {
		newBody := new(bytes.Buffer)
		newBody.WriteString("package main\n")
		// move all import lines to the top
		for _, importLine := range importRe.FindAll(originalBodyBytes, -1) {
			newBody.Write(importLine)
			newBody.WriteRune(10)
		}
		newBody.WriteString("func main() {\n")
		newBody.Write(importRe.ReplaceAll(originalBodyBytes, make([]byte, 0)))
		newBody.WriteString("\n}\n")
		bodyBytes = newBody.Bytes()
	} else {
		bodyBytes = originalBodyBytes
	}

	defer os.Remove(src)
	if err = ioutil.WriteFile(src, bodyBytes, 0666); err != nil {
		return
	}

	// build x.go, creating x
	dir, file := filepath.Split(src)
	out, err = run(dir, "go", "build", "-o", bin, file)
	defer os.Remove(bin)
	if err != nil {
		return
	}

	// run x
	return run("", bin)
}

// error writes compile, link, or runtime errors to the HTTP connection.
// The JavaScript interface uses the 404 status code to identify the error.
func error_(w http.ResponseWriter, out []byte, err error) {
	w.WriteHeader(404)
	if out != nil {
		output.Execute(w, out)
	} else {
		output.Execute(w, err.Error())
	}
}

// run executes the specified command and returns its output and an error.
func run(dir string, args ...string) ([]byte, error) {
	var buf bytes.Buffer
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Dir = dir
	cmd.Stdout = &buf
	cmd.Stderr = cmd.Stdout
	err := cmd.Run()
	return buf.Bytes(), err
}

var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template
var staticPage = template.Must(template.New("staticPage").Parse(staticPageText))
var output = template.Must(template.New("output").Parse(outputText)) // HTML template

var outputText = `<pre>{{printf "%s" . |html}}</pre>`

var staticPageText = `<!doctype html>

{{range $i, $contents := .}}

{{printf "%s" $contents.Contents |html}}

{{end}}

<button id="noteButton" onclick="toggleNotes()">Show notes</button>
<button onclick="prev()">Previous</button>
<button onclick="next()">Next</button>

{{range $i, $contents := .}}

{{printf "%s" $contents.Notes |html}}

{{end}}

`

var frontPageText = `<!doctype html>

<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler(event);" onkeyup="autocompile();">{{printf "%s" .Contents |html}}</textarea>

(Shift-Enter to compile and run.)
<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
<button id="noteButton" onclick="toggleNotes()">Hide notes</button>
<button onclick="window.location.href = '/?s={{ printf "%d" .PrevSlide }}'">Previous</button>
<button onclick="window.location.href = '/?s={{ printf "%d" .NextSlide }}'">Next</button>

{{ printf "%s" .Notes |html}}

`
<|endoftext|>


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

//go:generate ./hooks/run_extpoints.sh

package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/heapster/common/flags"
	"k8s.io/heapster/events/api"
	"k8s.io/heapster/events/manager"
	"k8s.io/heapster/events/sinks"
	"k8s.io/heapster/events/sources"
	"k8s.io/heapster/version"
)

var (
	argFrequency   = flag.Duration("frequency", 30*time.Second, "The resolution at which Eventer pushes events to sinks")
	argMaxProcs    = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores)")
	argSources     flags.Uris
	argSinks       flags.Uris
	argVersion     bool
	argHealthzIP   = flag.String("healthz-ip", "0.0.0.0", "ip eventer health check service uses")
	argHealthzPort = flag.Uint("healthz-port", 8084, "port eventer health check listens on")
)

func main() {
	quitChannel := make(chan struct{}, 0)

	flag.Var(&argSources, "source", "source(s) to read events from")
	flag.Var(&argSinks, "sink", "external sink(s) that receive events")
	flag.BoolVar(&argVersion, "version", false, "print version info and exit")
	flag.Parse()

	if argVersion {
		fmt.Println(version.VersionInfo())
		os.Exit(0)
	}

	logs.InitLogs()
	defer logs.FlushLogs()

	setMaxProcs()

	glog.Infof(strings.Join(os.Args, " "))
	glog.Infof("Eventer version %v", version.HeapsterVersion)
	if err := validateFlags(); err != nil {
		glog.Fatal(err)
	}

	// sources
	if len(argSources) != 1 {
		glog.Fatal("Wrong number of sources specified")
	}
	sourceFactory := sources.NewSourceFactory()
	sources, err := sourceFactory.BuildAll(argSources)
	if err != nil {
		glog.Fatalf("Failed to create sources: %v", err)
	}
	if len(sources) != 1 {
		glog.Fatal("Requires exactly 1 source")
	}

	// sinks
	sinksFactory := sinks.NewSinkFactory()
	sinkList := sinksFactory.BuildAll(argSinks)
	if len([]flags.Uri(argSinks)) != 0 && len(sinkList) == 0 {
		glog.Fatal("No available sink to use")
	}

	for _, sink := range sinkList {
		glog.Infof("Starting with %s sink", sink.Name())
	}
	sinkManager, err := sinks.NewEventSinkManager(sinkList, sinks.DefaultSinkExportEventsTimeout, sinks.DefaultSinkStopTimeout)
	if err != nil {
		glog.Fatalf("Failed to create sink manager: %v", err)
	}

	// main manager
	manager, err := manager.NewManager(sources[0], sinkManager, *argFrequency)
	if err != nil {
		glog.Fatalf("Failed to create main manager: %v", err)
	}

	manager.Start()
	glog.Infof("Starting eventer")

	go startHTTPServer()

	<-quitChannel
}

func startHTTPServer() {
	glog.Info("Starting eventer http service")

	glog.Fatal(http.ListenAndServe(net.JoinHostPort(*argHealthzIP, strconv.Itoa(int(*argHealthzPort))), nil))
}

func validateFlags() error {
	var minFrequency = 5 * time.Second

	if *argFrequency < minFrequency {
		return fmt.Errorf("frequency needs to be greater than %s, supplied %s", minFrequency,
			*argFrequency)
	}

	if *argFrequency > api.MaxEventsScrapeDelay {
		return fmt.Errorf("frequency needs to be smaller than %s, supplied %s",
			api.MaxEventsScrapeDelay, *argFrequency)
	}

	return nil
}

func setMaxProcs() {
	// Allow as many threads as we have cores unless the user specified a value.
	var numProcs int
	if *argMaxProcs < 1 {
		numProcs = runtime.NumCPU()
	} else {
		numProcs = *argMaxProcs
	}
	runtime.GOMAXPROCS(numProcs)

	// Check if the setting was successful.
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != numProcs {
		glog.Warningf("Specified max procs of %d but using %d", numProcs, actualNumProcs)
	}
}
<commit_msg>fix incorrect comparison error message<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:generate ./hooks/run_extpoints.sh

package main

import (
	"flag"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/golang/glog"
	"k8s.io/apiserver/pkg/util/logs"
	"k8s.io/heapster/common/flags"
	"k8s.io/heapster/events/api"
	"k8s.io/heapster/events/manager"
	"k8s.io/heapster/events/sinks"
	"k8s.io/heapster/events/sources"
	"k8s.io/heapster/version"
)

var (
	argFrequency   = flag.Duration("frequency", 30*time.Second, "The resolution at which Eventer pushes events to sinks")
	argMaxProcs    = flag.Int("max_procs", 0, "max number of CPUs that can be used simultaneously. Less than 1 for default (number of cores)")
	argSources     flags.Uris
	argSinks       flags.Uris
	argVersion     bool
	argHealthzIP   = flag.String("healthz-ip", "0.0.0.0", "ip eventer health check service uses")
	argHealthzPort = flag.Uint("healthz-port", 8084, "port eventer health check listens on")
)

func main() {
	quitChannel := make(chan struct{}, 0)

	flag.Var(&argSources, "source", "source(s) to read events from")
	flag.Var(&argSinks, "sink", "external sink(s) that receive events")
	flag.BoolVar(&argVersion, "version", false, "print version info and exit")
	flag.Parse()

	if argVersion {
		fmt.Println(version.VersionInfo())
		os.Exit(0)
	}

	logs.InitLogs()
	defer logs.FlushLogs()

	setMaxProcs()

	glog.Infof(strings.Join(os.Args, " "))
	glog.Infof("Eventer version %v", version.HeapsterVersion)
	if err := validateFlags(); err != nil {
		glog.Fatal(err)
	}

	// sources
	if len(argSources) != 1 {
		glog.Fatal("Wrong number of sources specified")
	}
	sourceFactory := sources.NewSourceFactory()
	sources, err := sourceFactory.BuildAll(argSources)
	if err != nil {
		glog.Fatalf("Failed to create sources: %v", err)
	}
	if len(sources) != 1 {
		glog.Fatal("Requires exactly 1 source")
	}

	// sinks
	sinksFactory := sinks.NewSinkFactory()
	sinkList := sinksFactory.BuildAll(argSinks)
	if len([]flags.Uri(argSinks)) != 0 && len(sinkList) == 0 {
		glog.Fatal("No available sink to use")
	}

	for _, sink := range sinkList {
		glog.Infof("Starting with %s sink", sink.Name())
	}
	sinkManager, err := sinks.NewEventSinkManager(sinkList, sinks.DefaultSinkExportEventsTimeout, sinks.DefaultSinkStopTimeout)
	if err != nil {
		glog.Fatalf("Failed to create sink manager: %v", err)
	}

	// main manager
	manager, err := manager.NewManager(sources[0], sinkManager, *argFrequency)
	if err != nil {
		glog.Fatalf("Failed to create main manager: %v", err)
	}

	manager.Start()
	glog.Infof("Starting eventer")

	go startHTTPServer()

	<-quitChannel
}

func startHTTPServer() {
	glog.Info("Starting eventer http service")

	glog.Fatal(http.ListenAndServe(net.JoinHostPort(*argHealthzIP, strconv.Itoa(int(*argHealthzPort))), nil))
}

func validateFlags() error {
	var minFrequency = 5 * time.Second

	if *argFrequency < minFrequency {
		return fmt.Errorf("frequency needs to be no less than %s, supplied %s", minFrequency,
			*argFrequency)
	}

	if *argFrequency > api.MaxEventsScrapeDelay {
		return fmt.Errorf("frequency needs to be no greater than %s, supplied %s",
			api.MaxEventsScrapeDelay, *argFrequency)
	}

	return nil
}

func setMaxProcs() {
	// Allow as many threads as we have cores unless the user specified a value.
	var numProcs int
	if *argMaxProcs < 1 {
		numProcs = runtime.NumCPU()
	} else {
		numProcs = *argMaxProcs
	}
	runtime.GOMAXPROCS(numProcs)

	// Check if the setting was successful.
	actualNumProcs := runtime.GOMAXPROCS(0)
	if actualNumProcs != numProcs {
		glog.Warningf("Specified max procs of %d but using %d", numProcs, actualNumProcs)
	}
}
<|endoftext|>


<commit_before>package events

type ClientInfo struct {
	AcceptLanguage string `json:"accept-language"`
	ClientName     string `json:"client-name"`
	ClientOS       string `json:"client-os"`
	ClientType     string `json:"client-type"`
	DeviceType     string `json:"device-type"`
	IP             string `json:"ip"`
	UserAgent      string `json:"user-agent"`
}

type GeoLocation struct {
	City    string `json:"city"`
	Country string `json:"country"`
	Region  string `json:"region"`
}

type MailingList struct {
	Address string `json:"address"`
	ListID  string `json:"list-id"`
	SID     string `json:"sid"`
}

type Message struct {
	Headers     MessageHeaders `json:"headers"`
	Attachments []Attachment   `json:"attachments"`
	Recipients  []string       `json:"recipients"`
	Size        int            `json:"size"`
}

type Envelope struct {
	MailFrom    string `json:"mail-from"`
	Sender      string `json:"sender"`
	Transport   string `json:"transport"`
	Targets     string `json:"targets"`
	SendingHost string `json:"sending-host"`
	SendingIP   string `json:"sending-ip"`
}

type Storage struct {
	Key string `json:"key"`
	URL string `json:"url"`
}

type Flags struct {
	IsAuthenticated bool `json:"is-authenticated"`
	IsBig           bool `json:"is-big"`
	IsSystemTest    bool `json:"is-system-test"`
	IsTestMode      bool `json:"is-test-mode"`
	IsDelayedBounce bool `json:"is-delayed-bounce"`
}

type Attachment struct {
	FileName    string `json:"filename"`
	ContentType string `json:"content-type"`
	Size        int    `json:"size"`
}

type MessageHeaders struct {
	To        string `json:"to"`
	MessageID string `json:"message-id"`
	From      string `json:"from"`
	Subject   string `json:"subject"`
}

type Campaign struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type DeliveryStatus struct {
	// The code is an int or a string from time to time so
	// we can't uncomment this field until all emitters unified.
	// Code        string  `json:"code"`
	Message        string  `json:"message"`
	SessionSeconds float64 `json:"session-seconds"`
}
<commit_msg>Uncommented DeliveryStatus.Code and change it to an integer<commit_after>package events

type ClientInfo struct {
	AcceptLanguage string `json:"accept-language"`
	ClientName     string `json:"client-name"`
	ClientOS       string `json:"client-os"`
	ClientType     string `json:"client-type"`
	DeviceType     string `json:"device-type"`
	IP             string `json:"ip"`
	UserAgent      string `json:"user-agent"`
}

type GeoLocation struct {
	City    string `json:"city"`
	Country string `json:"country"`
	Region  string `json:"region"`
}

type MailingList struct {
	Address string `json:"address"`
	ListID  string `json:"list-id"`
	SID     string `json:"sid"`
}

type Message struct {
	Headers     MessageHeaders `json:"headers"`
	Attachments []Attachment   `json:"attachments"`
	Recipients  []string       `json:"recipients"`
	Size        int            `json:"size"`
}

type Envelope struct {
	MailFrom    string `json:"mail-from"`
	Sender      string `json:"sender"`
	Transport   string `json:"transport"`
	Targets     string `json:"targets"`
	SendingHost string `json:"sending-host"`
	SendingIP   string `json:"sending-ip"`
}

type Storage struct {
	Key string `json:"key"`
	URL string `json:"url"`
}

type Flags struct {
	IsAuthenticated bool `json:"is-authenticated"`
	IsBig           bool `json:"is-big"`
	IsSystemTest    bool `json:"is-system-test"`
	IsTestMode      bool `json:"is-test-mode"`
	IsDelayedBounce bool `json:"is-delayed-bounce"`
}

type Attachment struct {
	FileName    string `json:"filename"`
	ContentType string `json:"content-type"`
	Size        int    `json:"size"`
}

type MessageHeaders struct {
	To        string `json:"to"`
	MessageID string `json:"message-id"`
	From      string `json:"from"`
	Subject   string `json:"subject"`
}

type Campaign struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type DeliveryStatus struct {
	Code           int     `json:"code"`
	Message        string  `json:"message"`
	SessionSeconds float64 `json:"session-seconds"`
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/boboman13/go-ftp"
)

func main() {
	server := &FTPServer{
		host: "0.0.0.0",
		port: "21",
	}

	err := server.Start()
	if err != nil {
		fmt.Println("Error occurred starting FTP server: " + err.Error())
	}
}<commit_msg>Still working out the kinks<commit_after>package main

import (
	"fmt"
	"github.com/boboman13/go-ftp/ftp"
)

// Starts server
func main() {
	server := &ftp.FTPServer{
		Host: "0.0.0.0",
		Port: 21,
		Config: new(ftp.AuthenticationConfig),
	}

	// Configures authentication; WARNING: do not use this code, it is insecure
	server.config.ConfigAuthentication(func(user string, password string) (authenticated bool, dir string) {
		fmt.Println("Logged in " + user + " w/ pass " + password)
		return true, "/home/" + user + "/ftp"
		})

	// Starts server
	err := server.Start()
	if err != nil {
		fmt.Println("Error occurred starting FTP server: " + err.Error())
	}
}<|endoftext|>


<commit_before>package sortp

import (
	"sort"
	"testing"
)

// Make sure InterfaceStruct implements sort.Interface
var _ sort.Interface = InterfaceStruct{}

func TestSortF(t *testing.T) {
	data := []int{5, 3, 1, 8, 0}

	SortF(len(data), func(i, j int) bool {
		return data[i] < data[j]
	}, func(i, j int) {
		data[i], data[j] = data[j], data[i]
	})

	if !sort.IntsAreSorted(data) {
		t.Errorf("Data is not sorted by SortF: %v", data)
	}
}
<commit_msg>Change testcase to examples<commit_after>package sortp

import (
	"fmt"
	"sort"
)

// Make sure InterfaceStruct implements sort.Interface
var _ sort.Interface = InterfaceStruct{}

func ExampleSortF() {
	data := []int{5, 3, 1, 8, 0}

	SortF(len(data), func(i, j int) bool {
		return data[i] < data[j]
	}, func(i, j int) {
		data[i], data[j] = data[j], data[i]
	})

	fmt.Println(data)
	// OUTPUT:
	// [0 1 3 5 8]
}

func ExampleInterfaceStruct() {
	data := []int{5, 3, 1, 8, 0}

	sort.Sort(InterfaceStruct{
		LenF: func() int {
			return len(data)
		}, LessF: func(i, j int) bool {
			return data[i] < data[j]
		}, SwapF: func(i, j int) {
			data[i], data[j] = data[j], data[i]
		},
	})

	fmt.Println(data)
	// OUTPUT:
	// [0 1 3 5 8]
}
<|endoftext|>


<commit_before>package speakeasy

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// Ask the user to enter a password with input hidden. prompt is a string to
// display before the user's input. Returns the provided password, or an error
// if the command failed.
func Ask(prompt string) (password string, err error) {
	if prompt != "" {
		fmt.Fprint(os.Stdout, prompt) // Display the prompt.
	}
	return getPassword()
}

func readline() (value string, err error) {
	var valb []byte
	var n int
	b := make([]byte, 1)
	for {
		// read one byte at a time so we don't accidentally read extra bytes
		n, err = os.Stdin.Read(b)
		if err != nil && err != io.EOF {
			return "", err
		}
		if n == 0 || b[0] == '\n' {
			break
		}
		valb = append(valb, b[0])
	}

	// Carriage return after the user input.
	fmt.Println("")
	return strings.TrimSuffix(string(valb), "\r"), nil
}
<commit_msg>Allow specifying output. Closes #1<commit_after>package speakeasy

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// Ask the user to enter a password with input hidden. prompt is a string to
// display before the user's input. Returns the provided password, or an error
// if the command failed.
func Ask(prompt string) (password string, err error) {
	return FAsk(os.Stdout, prompt)
}

// Same as the Ask function, except it is possible to specify the file to write
// the prompt to.
func FAsk(file *os.File, prompt string) (password string, err error) {
	if prompt != "" {
		fmt.Fprint(file, prompt) // Display the prompt.
	}
	return getPassword()
}

func readline() (value string, err error) {
	var valb []byte
	var n int
	b := make([]byte, 1)
	for {
		// read one byte at a time so we don't accidentally read extra bytes
		n, err = os.Stdin.Read(b)
		if err != nil && err != io.EOF {
			return "", err
		}
		if n == 0 || b[0] == '\n' {
			break
		}
		valb = append(valb, b[0])
	}

	// Carriage return after the user input.
	fmt.Println("")
	return strings.TrimSuffix(string(valb), "\r"), nil
}
<|endoftext|>


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

package sql

import (
	"fmt"
	"math"
	"strconv"

	"github.com/cockroachdb/cockroach/sql/parser"
)

// evalLimit evaluates the Count and Offset fields. If Count is missing, the
// value is MaxInt64. If Offset is missing, the value is 0
func (p *planner) evalLimit(limit *parser.Limit) (count, offset int64, err error) {
	count = math.MaxInt64
	offset = 0

	if limit == nil {
		return count, offset, nil
	}

	data := []struct {
		name string
		src  parser.Expr
		dst  *int64
	}{
		{"LIMIT", limit.Count, &count},
		{"OFFSET", limit.Offset, &offset},
	}

	for _, datum := range data {
		if datum.src != nil {
			typedSrc, err := parser.TypeCheckAndRequire(datum.src, p.evalCtx.Args,
				parser.TypeInt, datum.name)
			if err != nil {
				return 0, 0, err
			}

			normalized, err := p.parser.NormalizeExpr(p.evalCtx, typedSrc)
			if err != nil {
				return 0, 0, err
			}

			if p.evalCtx.PrepareOnly {
				continue
			}

			dstDatum, err := normalized.Eval(p.evalCtx)
			if err != nil {
				return 0, 0, err
			}

			if dstDatum == parser.DNull {
				// Use the default value.
				continue
			}

			dstDInt := *dstDatum.(*parser.DInt)
			val := int64(dstDInt)
			if val < 0 {
				return 0, 0, fmt.Errorf("negative value for %s", datum.name)
			}
			*datum.dst = val
		}
	}
	return count, offset, nil
}

// limit constructs a limitNode based on the LIMIT and OFFSET clauses.
func (p *planner) limit(count, offset int64, plan planNode) planNode {
	if count == math.MaxInt64 && offset == 0 {
		return plan
	}

	if count != math.MaxInt64 {
		plan.SetLimitHint(offset+count, false /* hard */)
	}

	return &limitNode{planNode: plan, count: count, offset: offset}
}

type limitNode struct {
	planNode
	count     int64
	offset    int64
	rowIndex  int64
	explain   explainMode
	debugVals debugValues
}

func (n *limitNode) MarkDebug(mode explainMode) {
	if mode != explainDebug {
		panic(fmt.Sprintf("unknown debug mode %d", mode))
	}
	n.explain = mode
	n.planNode.MarkDebug(mode)
}

func (n *limitNode) DebugValues() debugValues {
	if n.explain != explainDebug {
		panic(fmt.Sprintf("node not in debug mode (mode %d)", n.explain))
	}
	return n.debugVals
}

func (n *limitNode) Next() bool {
	// n.rowIndex is the 0-based index of the next row.
	// We don't do (n.rowIndex >= n.offset + n.count) to avoid overflow (count can be MaxInt64).
	if n.rowIndex-n.offset >= n.count {
		return false
	}

	for {
		if !n.planNode.Next() {
			return false
		}

		if n.explain == explainDebug {
			n.debugVals = n.planNode.DebugValues()
			if n.debugVals.output != debugValueRow {
				// Let the non-row debug values pass through.
				return true
			}
		}

		n.rowIndex++
		if n.rowIndex > n.offset {
			// Row within limits, return it.
			return true
		}

		if n.explain == explainDebug {
			// Return as a filtered row.
			n.debugVals.output = debugValueFiltered
			return true
		}
		// Fetch the next row.
	}
}

func (n *limitNode) ExplainPlan(_ bool) (string, string, []planNode) {
	var count string
	if n.count == math.MaxInt64 {
		count = "ALL"
	} else {
		count = strconv.FormatInt(n.count, 10)
	}

	return "limit", fmt.Sprintf("count: %s, offset: %d", count, n.offset), []planNode{n.planNode}
}

func (*limitNode) SetLimitHint(_ int64, _ bool) {}
<commit_msg>Make the limitNode a fully fledged planNode.<commit_after>// Copyright 2015 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Tamir Duberstein (tamird@gmail.com)

package sql

import (
	"fmt"
	"math"
	"strconv"

	"github.com/cockroachdb/cockroach/sql/parser"
)

// evalLimit evaluates the Count and Offset fields. If Count is missing, the
// value is MaxInt64. If Offset is missing, the value is 0
func (p *planner) evalLimit(limit *parser.Limit) (count, offset int64, err error) {
	count = math.MaxInt64
	offset = 0

	if limit == nil {
		return count, offset, nil
	}

	data := []struct {
		name string
		src  parser.Expr
		dst  *int64
	}{
		{"LIMIT", limit.Count, &count},
		{"OFFSET", limit.Offset, &offset},
	}

	for _, datum := range data {
		if datum.src != nil {
			typedSrc, err := parser.TypeCheckAndRequire(datum.src, p.evalCtx.Args,
				parser.TypeInt, datum.name)
			if err != nil {
				return 0, 0, err
			}

			normalized, err := p.parser.NormalizeExpr(p.evalCtx, typedSrc)
			if err != nil {
				return 0, 0, err
			}

			if p.evalCtx.PrepareOnly {
				continue
			}

			dstDatum, err := normalized.Eval(p.evalCtx)
			if err != nil {
				return 0, 0, err
			}

			if dstDatum == parser.DNull {
				// Use the default value.
				continue
			}

			dstDInt := *dstDatum.(*parser.DInt)
			val := int64(dstDInt)
			if val < 0 {
				return 0, 0, fmt.Errorf("negative value for %s", datum.name)
			}
			*datum.dst = val
		}
	}
	return count, offset, nil
}

// limit constructs a limitNode based on the LIMIT and OFFSET clauses.
func (p *planner) limit(count, offset int64, plan planNode) planNode {
	if count == math.MaxInt64 && offset == 0 {
		return plan
	}

	if count != math.MaxInt64 {
		plan.SetLimitHint(offset+count, false /* hard */)
	}

	return &limitNode{plan: plan, count: count, offset: offset}
}

type limitNode struct {
	plan      planNode
	count     int64
	offset    int64
	rowIndex  int64
	explain   explainMode
	debugVals debugValues
}

func (n *limitNode) ExplainTypes(f func(string, string)) { n.plan.ExplainTypes(f) }
func (n *limitNode) Err() error                          { return n.plan.Err() }
func (n *limitNode) Start() error                        { return n.plan.Start() }
func (n *limitNode) Columns() []ResultColumn             { return n.plan.Columns() }
func (n *limitNode) Values() parser.DTuple               { return n.plan.Values() }
func (n *limitNode) Ordering() orderingInfo              { return n.plan.Ordering() }

func (n *limitNode) MarkDebug(mode explainMode) {
	if mode != explainDebug {
		panic(fmt.Sprintf("unknown debug mode %d", mode))
	}
	n.explain = mode
	n.plan.MarkDebug(mode)
}

func (n *limitNode) DebugValues() debugValues {
	if n.explain != explainDebug {
		panic(fmt.Sprintf("node not in debug mode (mode %d)", n.explain))
	}
	return n.debugVals
}

func (n *limitNode) Next() bool {
	// n.rowIndex is the 0-based index of the next row.
	// We don't do (n.rowIndex >= n.offset + n.count) to avoid overflow (count can be MaxInt64).
	if n.rowIndex-n.offset >= n.count {
		return false
	}

	for {
		if !n.plan.Next() {
			return false
		}

		if n.explain == explainDebug {
			n.debugVals = n.plan.DebugValues()
			if n.debugVals.output != debugValueRow {
				// Let the non-row debug values pass through.
				return true
			}
		}

		n.rowIndex++
		if n.rowIndex > n.offset {
			// Row within limits, return it.
			return true
		}

		if n.explain == explainDebug {
			// Return as a filtered row.
			n.debugVals.output = debugValueFiltered
			return true
		}
		// Fetch the next row.
	}
}

func (n *limitNode) ExplainPlan(_ bool) (string, string, []planNode) {
	var count string
	if n.count == math.MaxInt64 {
		count = "ALL"
	} else {
		count = strconv.FormatInt(n.count, 10)
	}

	return "limit", fmt.Sprintf("count: %s, offset: %d", count, n.offset), []planNode{n.plan}
}

func (*limitNode) SetLimitHint(_ int64, _ bool) {}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"strings"
	"sync"
	"time"
)

// A LongPoller (aka tunnel) is the server-side implementation
// of long-polling. We connect the http client (our pelican socks proxy)
// with the downstream target, typically an http server or sshd.
// For the client side implementation of long polling, see the
// file alphabeta.go and the Chaser structure and methods.
//
// Inside the reverse proxy, the LongPoller represents a 1:1, one
// client to one (downstream target) server connection,
// if you ignore the socks-proxy and reverse-proxy in the middle.
// A ReverseProxy can have many LongPollers, mirroring the number of
// connections on the client side to the socks proxy. The key
// distinguishes them. The LongerPoller is where we implement the
// server side of the long polling.
//
// http request flow (client initiating direction), http replies
// flow in the opposite direction of the arrows below.
//
//        "upstream"                               "downstream"
//           V                                         ^
//     e.g. web-browser                          e.g. web-server
//           |                                         ^
//           v                                         |
// -----------------------             -------------------------
// | TcpUpstreamReceiver |             |  net.Conn TCP connect |
// |    |                |             |               ^       |
// |    v                |             |           ServerRW    |
// | ClientRW            |             |               ^       |
// |    v                |    http     |               |       |
// | Chaser->alpha/beta->|------------>|WebServer--> LongPoller|
// -----------------------             -------------------------
//   pelican-socks-proxy                 pelican-reverse-proxy
//
//
type LongPoller struct {
	reqStop           chan bool
	Done              chan bool
	ClientPacketRecvd chan *tunnelPacket

	rw        *ServerRW // manage the goroutines that read and write dnConn
	recvCount int
	conn      net.Conn

	// server issues a unique key for the connection, which allows multiplexing
	// of multiple client connections from this one ip if need be.
	// The ssh integrity checks inside the tunnel prevent malicious tampering.
	key     string
	pollDur time.Duration

	Dest Addr

	mut          sync.Mutex
	CloseKeyChan chan string
}

// Make a new LongPoller as a part of the server (ReverseProxy is the server;
// PelicanSocksProxy is the client).
//
// If a CloseKeyChan receives a key, we return any associated client -> server
// http request immediately for that key, to facilitate quick shutdown.
//
func NewLongPoller(dest Addr, pollDur time.Duration) *LongPoller {
	key := GenPelicanKey()
	if dest.Port == 0 {
		dest.Port = GetAvailPort()
	}
	if dest.Ip == "" {
		dest.Ip = "0.0.0.0"
	}
	dest.SetIpPort()

	s := &LongPoller{
		reqStop:           make(chan bool),
		Done:              make(chan bool),
		ClientPacketRecvd: make(chan *tunnelPacket),
		key:               string(key),
		Dest:              dest,
		CloseKeyChan:      make(chan string),
		pollDur:           pollDur,
	}

	return s
}

func (s *LongPoller) Stop() {
	po("%p LongPoller stop received", s)
	s.RequestStop()
	<-s.Done
	po("%p LongPoller stop done", s)
}

// RequestStop makes sure we only close
// the s.reqStop channel once. Returns
// true iff we closed s.reqStop on this call.
func (s *LongPoller) RequestStop() bool {
	s.mut.Lock()
	defer s.mut.Unlock()

	select {
	case <-s.reqStop:
		return false
	default:
		close(s.reqStop)
		return true
	}
}

func (s *LongPoller) finish() {
	s.rw.Stop()
	close(s.Done)
}

// LongPoller::Start() implements the long-polling logic.
//
// When a new client request comes in (2nd one), we bump any
// already waiting long-poll into replying to its request.
//
//     new reader ------> bumps waiting/long-polling reader & takes its place.
//       ^                      |
//       |                      V
//       ^                      |
//       |                      V
//    client <-- returns to <---/
//
// it's a closed loop track with only one goroutine per tunnel
// actively holding on a long poll.
//
// There are only ever two client (http) requests outstanding
// at any given moment in time.
//
func (s *LongPoller) Start() error {

	skey := string(s.key[:5])

	err := s.dial()
	if err != nil {
		return fmt.Errorf("%s '%s' LongPoller could not dial '%s': '%s'", s, skey, s.Dest.IpPort, err)
	}

	// s.dial() sets s.conn on success.
	s.rw = NewServerRW(s.conn, 0, nil, nil)
	s.rw.Start()

	go func() {
		defer func() { s.finish() }()

		// duration of the long poll
		longPollTimeUp := time.After(s.pollDur)

		var pack *tunnelPacket

		// in cliReq and bytesFromServer, the client is upstream and the
		// server is downstream. In LongPoller, we read from the server
		// and write those bytes in Replies to the client. In LongPoller, we read
		// from the client Requests and write those bytes to the server.

		// keep at most 2 cliRequests on hand, cycle them in FIFO order.
		// they are: oldestReqPack, and waitingCliReqs[0], in that order.
		waitingCliReqs := make([]*tunnelPacket, 0, 2)
		var oldestReqPack *tunnelPacket
		var countForUpstream int64

		// sends replies upsteram
		sendUp := func() {
			if oldestReqPack != nil {
				po("%p '%s' LongPoll::Start(): sendUp() is sending along oldest ClientRequest with response, countForUpstream(%d) >0 || len(waitingCliReqs)==%d was > 0   ...response: '%s'", s, skey, countForUpstream, len(waitingCliReqs), string(oldestReqPack.respdup.Bytes()))
				close(oldestReqPack.done) // send!
				countForUpstream = 0
				if len(waitingCliReqs) > 0 {
					oldestReqPack = waitingCliReqs[0]
					waitingCliReqs = waitingCliReqs[1:]
				} else {
					oldestReqPack = nil
					longPollTimeUp = nil
				}
			}
		}

		for {
			po("%p '%s' longpoller: at top of LongPoller loop, inside Start(). len(wait)=%d", s, skey, len(waitingCliReqs))

			if oldestReqPack != nil {
				po("%p '%s' longpoller: at top of LongPoller loop, inside Start(). string(oldestReqPack.body='%s'", s, skey, string(oldestReqPack.body))
			} else {
				po("%p '%s' longpoller: oldestReqPack = nil", s, skey)
			}
			select {

			case <-longPollTimeUp:
				po("longPollTimeUp!!")
				// SEND reply! (by closing oldestReq.done)
				sendUp()

			// Only receive if we have a waiting packet body to write to.
			// Otherwise let the RecvFromDownCh() do the fixed size buffering.
			case b500 := <-func() chan []byte {
				if oldestReqPack != nil {
					return s.rw.RecvFromDownCh()
				} else {
					return nil
				}
			}():
				po("%p '%s' LongPoller got data from downstream <-s.rw.RecvFromDownCh() got b500='%s'\n", s, skey, string(b500))

				countForUpstream += int64(len(b500))
				_, err := oldestReqPack.resp.Write(b500)
				if err != nil {
					panic(err)
				}

				_, err = oldestReqPack.respdup.Write(b500)
				if err != nil {
					panic(err)
				}
				sendUp()

			case pack = <-s.ClientPacketRecvd:
				s.recvCount++
				po("%p '%s' longPoller got client packet! recvCount now: %d", s, skey, s.recvCount)

				// reset timer. only hold this packet open for at most 'dur' time.
				// since we will be replying to oldestReqPack (if any) immediately,
				// we can replace this timer.
				// TODO: is their a simpler reset instead of replace the timer?
				longPollTimeUp = time.After(s.pollDur)

				po("%p '%s' LongPoller, just received ClientPacket with pack.body = '%s'\n", s, skey, string(pack.body))

				// have to both send and receive

				pack.resp.Header().Set("Content-type", "application/octet-stream")

				// we got data from the client for server!
				// read from the request body and write to the ResponseWriter
				select {
				// s.rw.SendToDownCh() is a 1000 buffered channel so okay to not use a timeout;
				// in fact we do want the back pressure to keep us from
				// writing too much too fast.
				case s.rw.SendToDownCh() <- pack.body:

				case <-s.reqStop:
					// avoid deadlock on shutdown, but do
					// finish processing this packet, don't return yet
				}

				// transfer data from server to client

				// get the oldest packet, and reply using that. http requests
				// get serviced mostly FIFO this way, and our long-poll
				// timer reflects the time since the most recent packet
				// arrival.
				waitingCliReqs = append(waitingCliReqs, pack)
				oldestReqPack = waitingCliReqs[0]
				waitingCliReqs = waitingCliReqs[1:]

				// add any data from the next 10 msec to return packet to client
				select {
				case b500 := <-s.rw.RecvFromDownCh():
					po("%p '%s' longpoller  <-s.rw.RecvFromDownCh() got b500='%s'\n", s, skey, string(b500))

					countForUpstream += int64(len(b500))
					_, err := oldestReqPack.resp.Write(b500)
					if err != nil {
						panic(err)
					}

					_, err = oldestReqPack.respdup.Write(b500)
					if err != nil {
						panic(err)
					}

				case <-time.After(10 * time.Millisecond):
					// stop trying to read from server downstream, and send what
					// we got upstream to client.
				}

				if countForUpstream > 0 || len(waitingCliReqs) > 0 {
					sendUp()
				} else {
					po("%p '%s' LongPoll countForUpstream(%d); len(waitingCliReqs)==%d  ...response so far: '%s'", s, skey, countForUpstream, len(waitingCliReqs), string(oldestReqPack.respdup.Bytes()))
				}

				// end case pack = <-s.ClientPacketRecvd:
			case <-s.reqStop:
				return
			case <-s.CloseKeyChan:
				po("%p '%s' LongPoller in nil packet state, got closekeychan. Shutting down.", s, skey)

				// empty out the oldest and wait queue, replying to zero, one, or both requests.
				if oldestReqPack != nil {
					close(oldestReqPack.done)
					for _, p := range waitingCliReqs {
						close(p.done)
					}
					waitingCliReqs = waitingCliReqs[len(waitingCliReqs):]
					oldestReqPack = nil
				}
				return
			} //end select
		} // end for

		/*
				// *** not sure this is correct: where is the 2nd packet held open???

				// wait for a read for a possibly long duration. this is the "long poll" part.
				dur := 30 * time.Second
				// the client will spin up another goroutine/thread/sender if it has
				// an additional send in the meantime.

				po("LongPoll::Start(): tunnel.go starting to wait up to %v", dur)

				var n64 int64
				longPollTimeUp := time.After(dur)

				select {
				case <-s.reqStop:
					close(pack.done)
					pack = nil
					return

				case b500 := <-s.rw.RecvFromDownCh():
					po("tunnel.go: <-s.rw.RecvFromDownCh() got b500='%s'\n", string(b500))

					n64 += int64(len(b500))
					_, err := pack.resp.Write(b500)
					if err != nil {
						panic(err)
					}

					_, err = pack.respdup.Write(b500)
					if err != nil {
						panic(err)
					}
					close(pack.done)
					pack = nil

				case <-longPollTimeUp:
					po("tunnel.go: longPollTimeUp!!\n")
					// send it along its way anyhow
					close(pack.done)
					pack = nil

				case <-s.CloseKeyChan:
					po("tunnel.go: LongPoller with pending packet got closekey. returning packet and then exiting LongPoller")
					close(pack.done)
					pack = nil
					return

				case newpacket := <-s.ClientPacketRecvd:
					po("tunnel.go: <-s.ClientPakcetRecvd!!: %#v\n", newpacket)
					s.recvCount++
					// finish previous packet without data, because client sent another packet
					close(pack.done)
					pack = newpacket
				}

				po("LongPoll::Start(): at end of select/long wait.")
			}
		*/
	}()

	return nil
}

func (s *LongPoller) dial() error {

	po("ReverseProxy::NewTunnel: Attempting connect to our target '%s'\n", s.Dest.IpPort)
	dialer := net.Dialer{
		Timeout:   1000 * time.Millisecond,
		KeepAlive: 30 * time.Second,
	}

	var err error
	s.conn, err = dialer.Dial("tcp", s.Dest.IpPort)
	switch err.(type) {
	case *net.OpError:
		if strings.HasSuffix(err.Error(), "connection refused") {
			// could not reach destination
			return err
		}
	default:
		panicOn(err)
	}

	return err
}
<commit_msg>cleanup longpoll.go, green<commit_after>package main

import (
	"fmt"
	"net"
	"strings"
	"sync"
	"time"
)

// A LongPoller (aka tunnel) is the server-side implementation
// of long-polling. We connect the http client (our pelican socks proxy)
// with the downstream target, typically an http server or sshd.
// For the client side implementation of long polling, see the
// file alphabeta.go and the Chaser structure and methods.
//
// Inside the reverse proxy, the LongPoller represents a 1:1, one
// client to one (downstream target) server connection,
// if you ignore the socks-proxy and reverse-proxy in the middle.
// A ReverseProxy can have many LongPollers, mirroring the number of
// connections on the client side to the socks proxy. The key
// distinguishes them. The LongerPoller is where we implement the
// server side of the long polling.
//
// http request flow (client initiating direction), http replies
// flow in the opposite direction of the arrows below.
//
//        "upstream"                               "downstream"
//           V                                         ^
//     e.g. web-browser                          e.g. web-server
//           |                                         ^
//           v                                         |
// -----------------------             -------------------------
// | TcpUpstreamReceiver |             |  net.Conn TCP connect |
// |    |                |             |               ^       |
// |    v                |             |           ServerRW    |
// | ClientRW            |             |               ^       |
// |    v                |    http     |               |       |
// | Chaser->alpha/beta->|------------>|WebServer--> LongPoller|
// -----------------------             -------------------------
//   pelican-socks-proxy                 pelican-reverse-proxy
//
//
type LongPoller struct {
	reqStop           chan bool
	Done              chan bool
	ClientPacketRecvd chan *tunnelPacket

	rw        *ServerRW // manage the goroutines that read and write dnConn
	recvCount int
	conn      net.Conn

	// server issues a unique key for the connection, which allows multiplexing
	// of multiple client connections from this one ip if need be.
	// The ssh integrity checks inside the tunnel prevent malicious tampering.
	key     string
	pollDur time.Duration

	Dest Addr

	mut          sync.Mutex
	CloseKeyChan chan string
}

// Make a new LongPoller as a part of the server (ReverseProxy is the server;
// PelicanSocksProxy is the client).
//
// If a CloseKeyChan receives a key, we return any associated client -> server
// http request immediately for that key, to facilitate quick shutdown.
//
func NewLongPoller(dest Addr, pollDur time.Duration) *LongPoller {
	key := GenPelicanKey()
	if dest.Port == 0 {
		dest.Port = GetAvailPort()
	}
	if dest.Ip == "" {
		dest.Ip = "0.0.0.0"
	}
	dest.SetIpPort()

	s := &LongPoller{
		reqStop:           make(chan bool),
		Done:              make(chan bool),
		ClientPacketRecvd: make(chan *tunnelPacket),
		key:               string(key),
		Dest:              dest,
		CloseKeyChan:      make(chan string),
		pollDur:           pollDur,
	}

	return s
}

func (s *LongPoller) Stop() {
	po("%p LongPoller stop received", s)
	s.RequestStop()
	<-s.Done
	po("%p LongPoller stop done", s)
}

// RequestStop makes sure we only close
// the s.reqStop channel once. Returns
// true iff we closed s.reqStop on this call.
func (s *LongPoller) RequestStop() bool {
	s.mut.Lock()
	defer s.mut.Unlock()

	select {
	case <-s.reqStop:
		return false
	default:
		close(s.reqStop)
		return true
	}
}

func (s *LongPoller) finish() {
	s.rw.Stop()
	close(s.Done)
}

// LongPoller::Start() implements the long-polling logic.
//
// When a new client request comes in (2nd one), we bump any
// already waiting long-poll into replying to its request.
//
//     new reader ------> bumps waiting/long-polling reader & takes its place.
//       ^                      |
//       |                      V
//       ^                      |
//       |                      V
//    client <-- returns to <---/
//
// it's a closed loop track with only one goroutine per tunnel
// actively holding on a long poll.
//
// There are only ever two client (http) requests outstanding
// at any given moment in time.
//
func (s *LongPoller) Start() error {

	skey := string(s.key[:5])

	err := s.dial()
	if err != nil {
		return fmt.Errorf("%s '%s' LongPoller could not dial '%s': '%s'", s, skey, s.Dest.IpPort, err)
	}

	// s.dial() sets s.conn on success.
	s.rw = NewServerRW(s.conn, 0, nil, nil)
	s.rw.Start()

	go func() {
		defer func() { s.finish() }()

		// duration of the long poll
		longPollTimeUp := time.After(s.pollDur)

		var pack *tunnelPacket

		// in cliReq and bytesFromServer, the client is upstream and the
		// server is downstream. In LongPoller, we read from the server
		// and write those bytes in Replies to the client. In LongPoller, we read
		// from the client Requests and write those bytes to the server.

		// keep at most 2 cliRequests on hand, cycle them in FIFO order.
		// they are: oldestReqPack, and waitingCliReqs[0], in that order.

		waitingCliReqs := make([]*tunnelPacket, 0, 2)
		var oldestReqPack *tunnelPacket
		var countForUpstream int64

		// sends replies upsteram
		sendReplyUpstream := func() {
			if oldestReqPack != nil {
				po("%p '%s' LongPoll::Start(): sendReplyUpstream() is sending along oldest ClientRequest with response, countForUpstream(%d) >0 || len(waitingCliReqs)==%d was > 0   ...response: '%s'", s, skey, countForUpstream, len(waitingCliReqs), string(oldestReqPack.respdup.Bytes()))
				close(oldestReqPack.done) // send!
				countForUpstream = 0
				if len(waitingCliReqs) > 0 {
					oldestReqPack = waitingCliReqs[0]
					waitingCliReqs = waitingCliReqs[1:]
				} else {
					oldestReqPack = nil
					longPollTimeUp = nil
				}
			}
		}

		for {
			po("%p '%s' longpoller: at top of LongPoller loop, inside Start(). len(wait)=%d", s, skey, len(waitingCliReqs))

			if oldestReqPack != nil {
				po("%p '%s' longpoller: at top of LongPoller loop, inside Start(). string(oldestReqPack.body='%s'", s, skey, string(oldestReqPack.body))
			} else {
				po("%p '%s' longpoller: oldestReqPack = nil", s, skey)
			}
			select {

			case <-longPollTimeUp:
				po("longPollTimeUp!!")
				sendReplyUpstream()

			// Only receive if we have a waiting packet body to write to.
			// Otherwise let the RecvFromDownCh() do the fixed size buffering.
			case b500 := <-func() chan []byte {
				if oldestReqPack != nil {
					return s.rw.RecvFromDownCh()
				} else {
					return nil
				}
			}():
				po("%p '%s' LongPoller got data from downstream <-s.rw.RecvFromDownCh() got b500='%s'\n", s, skey, string(b500))

				countForUpstream += int64(len(b500))
				_, err := oldestReqPack.resp.Write(b500)
				if err != nil {
					panic(err)
				}

				_, err = oldestReqPack.respdup.Write(b500)
				if err != nil {
					panic(err)
				}
				sendReplyUpstream()

			case pack = <-s.ClientPacketRecvd:
				s.recvCount++
				po("%p '%s' longPoller got client packet! recvCount now: %d", s, skey, s.recvCount)

				// reset timer. only hold this packet open for at most 'dur' time.
				// since we will be replying to oldestReqPack (if any) immediately,
				// we can replace this timer.
				// TODO: is their a simpler reset instead of replace the timer?
				longPollTimeUp = time.After(s.pollDur)

				po("%p '%s' LongPoller, just received ClientPacket with pack.body = '%s'\n", s, skey, string(pack.body))

				// have to both send and receive

				pack.resp.Header().Set("Content-type", "application/octet-stream")

				// we got data from the client for server!
				// read from the request body and write to the ResponseWriter
				select {
				// s.rw.SendToDownCh() is a 1000 buffered channel so okay to not use a timeout;
				// in fact we do want the back pressure to keep us from
				// writing too much too fast.
				case s.rw.SendToDownCh() <- pack.body:

				case <-s.reqStop:
					// avoid deadlock on shutdown, but do
					// finish processing this packet, don't return yet
				}

				// transfer data from server to client

				// get the oldest packet, and reply using that. http requests
				// get serviced mostly FIFO this way, and our long-poll
				// timer reflects the time since the most recent packet
				// arrival.
				waitingCliReqs = append(waitingCliReqs, pack)
				oldestReqPack = waitingCliReqs[0]
				waitingCliReqs = waitingCliReqs[1:]

				// add any data from the next 10 msec to return packet to client
				select {
				case b500 := <-s.rw.RecvFromDownCh():
					po("%p '%s' longpoller  <-s.rw.RecvFromDownCh() got b500='%s'\n", s, skey, string(b500))

					countForUpstream += int64(len(b500))
					_, err := oldestReqPack.resp.Write(b500)
					if err != nil {
						panic(err)
					}

					_, err = oldestReqPack.respdup.Write(b500)
					if err != nil {
						panic(err)
					}

				case <-time.After(10 * time.Millisecond):
					// stop trying to read from server downstream, and send what
					// we got upstream to client.
				}

				if countForUpstream > 0 || len(waitingCliReqs) > 0 {
					sendReplyUpstream()
				} else {
					po("%p '%s' LongPoll countForUpstream(%d); len(waitingCliReqs)==%d  ...response so far: '%s'", s, skey, countForUpstream, len(waitingCliReqs), string(oldestReqPack.respdup.Bytes()))
				}

				// end case pack = <-s.ClientPacketRecvd:
			case <-s.reqStop:
				return
			case <-s.CloseKeyChan:
				po("%p '%s' LongPoller in nil packet state, got closekeychan. Shutting down.", s, skey)

				// empty out the oldest and wait queue, replying to zero, one, or both requests.
				if oldestReqPack != nil {
					close(oldestReqPack.done)
					for _, p := range waitingCliReqs {
						close(p.done)
					}
					waitingCliReqs = waitingCliReqs[len(waitingCliReqs):]
					oldestReqPack = nil
				}
				return
			} //end select
		} // end for

	}()

	return nil
}

func (s *LongPoller) dial() error {

	po("ReverseProxy::NewTunnel: Attempting connect to our target '%s'\n", s.Dest.IpPort)
	dialer := net.Dialer{
		Timeout:   1000 * time.Millisecond,
		KeepAlive: 30 * time.Second,
	}

	var err error
	s.conn, err = dialer.Dial("tcp", s.Dest.IpPort)
	switch err.(type) {
	case *net.OpError:
		if strings.HasSuffix(err.Error(), "connection refused") {
			// could not reach destination
			return err
		}
	default:
		panicOn(err)
	}

	return err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"encoding/json"
	"os"
	"net/url"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/redsift/go-render"
	"image/png"
	"text/template"
	"bytes"
	"strings"
)

var (
	app      		= kingpin.New("render", "Command-line WebKit based web page rendering tool.")
	debugOpt    		= app.Flag("debug", "Enable debug mode.").Short('d').Default("false").Bool()
	uaAppNameOpt   		= app.Flag("user-agent-app", "User agent application name.").Default("go-render").String()
	uaAppVersionOpt 	= app.Flag("user-agent-version", "User agent application version.").Default("v1").String()
	consoleOpt    		= app.Flag("console", "Output webpage console to stdout.").Default("false").Bool()
	imagesOpt    		= app.Flag("images", "Load images from webpage.").Bool()
	timeoutOpt		= app.Flag("timeout", "Timeout for page load.").Short('t').Duration()

	snapshotCommand     	= app.Command("snapshot", "Generate a snapshot of the page.")
	snapshotFormat		= snapshotCommand.Flag("format", "File format for output").Short('f').Default("auto").Enum("auto", "png", "jpeg", "webp", "gif", "mono")
	snapshotQuality		= snapshotCommand.Flag("quality", "Quality of image when using lossy compression").Default("100").Int()
	snapshotOutput		= snapshotCommand.Flag("output", "Filename for output").Short('o').Required().String()
	snapshotOpt		= snapshotCommand.Arg("url", "URL").Required().URL()

	javascriptCommand     	= app.Command("javascript", "Execute javascript in the context of the page.")
	javascriptContent	= javascriptCommand.Flag("js", "Javascript to execute").Short('j').Required().String()
	javascriptOpt		= javascriptCommand.Arg("url", "URL").Required().URL()

	metadataCommand		= app.Command("metadata", "Get page metadata.")
	metadataFormat		= metadataCommand.Flag("format", "Format the output using the given go template").Short('f').Default("").String()
	metadataOpt		= metadataCommand.Arg("url", "URL").Required().URL()
)

// Based on docker template functions
var templateFuncs = template.FuncMap{
	"json": func(m interface{}) string {
		a, _ := json.MarshalIndent(m, "", "\t")
		return string(a)
	},
	"split": strings.Split,
	"join":  strings.Join,
	"title": strings.Title,
	"lower": strings.ToLower,
	"upper": strings.ToUpper,
}

type timing struct {
	Start float64
	Load float64
	Finish float64
}

type metadata struct {
	Title string
	URI string
	Timing timing
}

func newLoadedView(url *url.URL, autoLoadImages bool) *render.View {
	u := url.String()

	r := render.NewRenderer()
	v := r.NewView(*uaAppNameOpt, *uaAppVersionOpt, autoLoadImages, *consoleOpt)

	if *debugOpt {
		fmt.Printf("Loading URL:%q\n", u)
	}

	err := v.LoadURI(u)
	app.FatalIfError(err, "Unable to request URL %q", u)

	err = v.Wait(timeoutOpt)
	app.FatalIfError(err, "Unable to load page")

	return v
}

func main() {
	app.HelpFlag.Short('h')

	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case snapshotCommand.FullCommand(): {
		al := true	// Give that this is a snapshot, load the images
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*snapshotOpt, al)
		defer v.Close()

		i, err := v.NewSnapshot(timeoutOpt)
		app.FatalIfError(err, "Unable to create snapshot")

		if i.Pix == nil {
			app.Fatalf("No Pix in captured image")
		}

		if i.Stride == 0 || i.Rect.Max.X == 0 || i.Rect.Max.Y == 0 {
			app.Fatalf("No image data in captured image")
		}

		imgFile := *snapshotOutput
		f, err := os.Create(imgFile)
		app.FatalIfError(err, "Could not create image %s", imgFile)
		defer f.Close()

		png.Encode(f, i)
	}
	case javascriptCommand.FullCommand(): {
		al := false
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*javascriptOpt, al)
		defer v.Close()

		j, err := v.EvaluateJavaScript(*javascriptContent, timeoutOpt)
		app.FatalIfError(err, "Unable to execute javascript")

		fmt.Println(j)
	}
	case metadataCommand.FullCommand(): {
		al := false
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*metadataOpt, al)
		defer v.Close()

		ts, _ := v.TimeToStart()
		tl, _ := v.TimeToLoad()
		tf, _ := v.TimeToFinish()

		m := metadata{
			Title: v.Title(),
			URI: v.URI(),
			Timing: timing{ Start: ts.Seconds(), Load: tl.Seconds(), Finish: tf.Seconds() },
		}

		var b []byte
		var err error

		if *metadataFormat != "" {
			temp, err := template.New("").Funcs(templateFuncs).Parse(*metadataFormat)
			app.FatalIfError(err, "Unable to parse template")

			buffer := new(bytes.Buffer)
			err = temp.Execute(buffer, m)
			app.FatalIfError(err, "Unable to format metadata")

			b = buffer.Bytes()
		} else {
			b, err = json.MarshalIndent(m, "", "\t")
			app.FatalIfError(err, "Unable to format metadata")
		}
		fmt.Println(string(b))
	}
	default: {
		app.FatalUsage("No known command supplied")
	}
	}

	/*
		c := make(chan *gojs.Value, 1)
		defer close(c)
		glib.IdleAdd(func() bool {
			v.RunJavaScript("window.location.hostname", func(val *gojs.Value, err error) {
				if err != nil {
					panic(err)
				} else {
					fmt.Printf("Hostname (from JavaScript): %q\n", val)
					c <- val
				}
			})

			return false
		})

		c := make(chan error, 1)
		glib.IdleAdd(func() bool {
			v.GetSnapshot(func(img *image.RGBA, err error) {
				defer close(c)
				if err != nil {
					fmt.Printf("GetSnapshot error: %q", err)
					fmt.Printf("GetSnapshot img: %v", img)
					c <- err
					return
				}
				if img == nil {
					fmt.Printf("!img")
					return
				}

				if img.Pix == nil {
					fmt.Printf("!img.Pix")
					return
				}

				if img.Stride == 0 || img.Rect.Max.X == 0 || img.Rect.Max.Y == 0 {
					fmt.Printf("!img.Stride or !img.Rect.Max.X or !img.Rect.Max.Y")
					return
				}

				f, err := os.Create("x" + strconv.Itoa(1) + ".png")
				png.Encode(f, img)

				fmt.Println("Grab finished.")
			})
			return false
		})

		result := <- c
		if result != nil {
			println(result.Error())
		}
		*/
}

// LIBGL_DEBUG=verbose
// http://unix.stackexchange.com/questions/1437/what-does-libgl-always-indirect-1-actually-do
// LIBGL_ALWAYS_INDIRECT=1<commit_msg>Tweak versions<commit_after>package main

import (
	"fmt"
	"encoding/json"
	"os"
	"net/url"
	"gopkg.in/alecthomas/kingpin.v2"
	"github.com/redsift/go-render"
	"image/png"
	"text/template"
	"bytes"
	"strings"
	"github.com/redsift/go-render/version"
)

var (
	app      		= kingpin.New("render", "Command-line WebKit based web page rendering tool.")
	debugOpt    		= app.Flag("debug", "Enable debug mode.").Short('d').Default("false").Bool()
	uaAppNameOpt   		= app.Flag("user-agent-app", "User agent application name.").Default("go-render").String()
	uaAppVersionOpt 	= app.Flag("user-agent-version", "User agent application version.").Default(version.Tag).String()
	consoleOpt    		= app.Flag("console", "Output webpage console to stdout.").Default("false").Bool()
	imagesOpt    		= app.Flag("images", "Load images from webpage.").Bool()
	timeoutOpt		= app.Flag("timeout", "Timeout for page load.").Short('t').Duration()

	snapshotCommand     	= app.Command("snapshot", "Generate a snapshot of the page.")
	snapshotFormat		= snapshotCommand.Flag("format", "File format for output").Short('f').Default("auto").Enum("auto", "png", "jpeg", "webp", "gif", "mono")
	snapshotQuality		= snapshotCommand.Flag("quality", "Quality of image when using lossy compression").Default("100").Int()
	snapshotOutput		= snapshotCommand.Flag("output", "Filename for output").Short('o').Required().String()
	snapshotOpt		= snapshotCommand.Arg("url", "URL").Required().URL()

	javascriptCommand     	= app.Command("javascript", "Execute javascript in the context of the page.")
	javascriptContent	= javascriptCommand.Flag("js", "Javascript to execute").Short('j').Required().String()
	javascriptOpt		= javascriptCommand.Arg("url", "URL").Required().URL()

	metadataCommand		= app.Command("metadata", "Get page metadata.")
	metadataFormat		= metadataCommand.Flag("format", "Format the output using the given go template").Short('f').Default("").String()
	metadataOpt		= metadataCommand.Arg("url", "URL").Required().URL()
)

// Based on docker template functions
var templateFuncs = template.FuncMap{
	"json": func(m interface{}) string {
		a, _ := json.MarshalIndent(m, "", "\t")
		return string(a)
	},
	"split": strings.Split,
	"join":  strings.Join,
	"title": strings.Title,
	"lower": strings.ToLower,
	"upper": strings.ToUpper,
}

type timing struct {
	Start float64
	Load float64
	Finish float64
}

type metadata struct {
	Title string
	URI string
	Timing timing
}

func newLoadedView(url *url.URL, autoLoadImages bool) *render.View {
	if url.Scheme == "" {
		url.Scheme = "http"
	}
 	u := url.String()

	r := render.NewRenderer()
	v := r.NewView(*uaAppNameOpt, *uaAppVersionOpt, autoLoadImages, *consoleOpt)

	if *debugOpt {
		fmt.Printf("Loading URL:%q\n", u)
	}

	err := v.LoadURI(u)
	app.FatalIfError(err, "Unable to request URL %q", u)

	err = v.Wait(timeoutOpt)
	app.FatalIfError(err, "Unable to load page")

	return v
}

func formatInterface(m interface{}, tmpl string) string {
	var b []byte
	var err error

	if tmpl != "" {
		temp, err := template.New("").Funcs(templateFuncs).Parse(tmpl)
		app.FatalIfError(err, "Unable to parse template")

		buffer := new(bytes.Buffer)
		err = temp.Execute(buffer, m)
		app.FatalIfError(err, "Unable to format metadata")

		b = buffer.Bytes()
	} else {
		b, err = json.MarshalIndent(m, "", "\t")
		app.FatalIfError(err, "Unable to format metadata")
	}
	return string(b)
}

func main() {
	app.HelpFlag.Short('h')
	app.Version(version.Version())
	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
	case snapshotCommand.FullCommand(): {
		al := true	// Give that this is a snapshot, load the images
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*snapshotOpt, al)
		defer v.Close()

		i, err := v.NewSnapshot(timeoutOpt)
		app.FatalIfError(err, "Unable to create snapshot")

		if i.Pix == nil {
			app.Fatalf("No Pix in captured image")
		}

		if i.Stride == 0 || i.Rect.Max.X == 0 || i.Rect.Max.Y == 0 {
			app.Fatalf("No image data in captured image")
		}

		imgFile := *snapshotOutput
		f, err := os.Create(imgFile)
		app.FatalIfError(err, "Could not create image %s", imgFile)
		defer f.Close()

		png.Encode(f, i)
	}
	case javascriptCommand.FullCommand(): {
		al := false
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*javascriptOpt, al)
		defer v.Close()

		j, err := v.EvaluateJavaScript(*javascriptContent, timeoutOpt)
		app.FatalIfError(err, "Unable to execute javascript")

		fmt.Println(j)
	}
	case metadataCommand.FullCommand(): {
		al := false
		if imagesOpt != nil {
			al = *imagesOpt
		}
		v := newLoadedView(*metadataOpt, al)
		defer v.Close()

		ts, _ := v.TimeToStart()
		tl, _ := v.TimeToLoad()
		tf, _ := v.TimeToFinish()

		m := metadata{
			Title: v.Title(),
			URI: v.URI(),
			Timing: timing{ Start: ts.Seconds(), Load: tl.Seconds(), Finish: tf.Seconds() },
		}

		fmt.Println(formatInterface(m, *metadataFormat))
	}
	default: {
		app.FatalUsage("No known command supplied")
	}
	}

	/*
		c := make(chan *gojs.Value, 1)
		defer close(c)
		glib.IdleAdd(func() bool {
			v.RunJavaScript("window.location.hostname", func(val *gojs.Value, err error) {
				if err != nil {
					panic(err)
				} else {
					fmt.Printf("Hostname (from JavaScript): %q\n", val)
					c <- val
				}
			})

			return false
		})

		c := make(chan error, 1)
		glib.IdleAdd(func() bool {
			v.GetSnapshot(func(img *image.RGBA, err error) {
				defer close(c)
				if err != nil {
					fmt.Printf("GetSnapshot error: %q", err)
					fmt.Printf("GetSnapshot img: %v", img)
					c <- err
					return
				}
				if img == nil {
					fmt.Printf("!img")
					return
				}

				if img.Pix == nil {
					fmt.Printf("!img.Pix")
					return
				}

				if img.Stride == 0 || img.Rect.Max.X == 0 || img.Rect.Max.Y == 0 {
					fmt.Printf("!img.Stride or !img.Rect.Max.X or !img.Rect.Max.Y")
					return
				}

				f, err := os.Create("x" + strconv.Itoa(1) + ".png")
				png.Encode(f, img)

				fmt.Println("Grab finished.")
			})
			return false
		})

		result := <- c
		if result != nil {
			println(result.Error())
		}
		*/
}

// LIBGL_DEBUG=verbose
// http://unix.stackexchange.com/questions/1437/what-does-libgl-always-indirect-1-actually-do
// LIBGL_ALWAYS_INDIRECT=1<|endoftext|>


<commit_before>package algoliasearch

import (
	"bytes"
	_ "crypto/sha512" // Fix certificates
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	version = "2.11.0"
)

// Define the constants used to specify the type of request.
const (
	search = 1 << iota
	write
	read
)

// Seed the RNG used to shuffle the hosts slice (see `defaultHosts` function).
func init() {
	rand.Seed(int64(time.Now().Nanosecond()))
}

// Transport is responsible for the connection and the retry strategy to
// Algolia servers.
type Transport struct {
	activeReadHost    string
	activeReadSince   time.Time
	activeWriteHost   string
	activeWriteSince  time.Time
	apiKey            string
	appId             string
	dialTimeout       time.Duration
	headers           map[string]string
	httpClient        *http.Client
	keepAliveDuration time.Duration
	providedHosts     []string
}

// NewTransport instantiates a new Transport with the default Algolia hosts to
// connect to.
func NewTransport(appId, apiKey string) *Transport {
	return &Transport{
		activeReadHost:    "",
		activeWriteHost:   "",
		apiKey:            apiKey,
		appId:             appId,
		dialTimeout:       1 * time.Second,
		headers:           defaultHeaders(appId, apiKey),
		httpClient:        defaultHttpClient(),
		keepAliveDuration: 5 * time.Minute,
		providedHosts:     nil,
	}
}

// NewTransport instantiates a new Transport with the specificed hosts as main
// servers to connect to.
func NewTransportWithHosts(appId, apiKey string, hosts []string) *Transport {
	return &Transport{
		activeReadHost:    "",
		activeWriteHost:   "",
		apiKey:            apiKey,
		appId:             appId,
		dialTimeout:       1 * time.Second,
		headers:           defaultHeaders(appId, apiKey),
		httpClient:        defaultHttpClient(),
		keepAliveDuration: 5 * 60 * time.Second,
		providedHosts:     hosts,
	}
}

// defaultHeaders is used to set the default HTTP headers to use with each
// requests.
func defaultHeaders(appId, apiKey string) map[string]string {
	return map[string]string{
		"Connection":               "keep-alive",
		"User-Agent":               "Algolia for Go (" + version + ")",
		"X-Algolia-API-Key":        apiKey,
		"X-Algolia-Application-Id": appId,
	}
}

// defaultHosts returns the list of the default Algolia hosts to use. The
// entries are shuffled.
func (t *Transport) defaultHosts() []string {
	hosts := []string{
		t.appId + "-1.algolianet.com",
		t.appId + "-2.algolianet.com",
		t.appId + "-3.algolianet.com",
	}

	shuffled := make([]string, len(hosts))
	for i, v := range rand.Perm(len(hosts)) {
		shuffled[i] = hosts[v]
	}

	return shuffled
}

// defaultHttpClient returns the `*http.Client` which will perform all the
// requests. All the timeout settings are explicitely defined here.
func defaultHttpClient() *http.Client {
	return &http.Client{
		Timeout:   time.Second * 30,
		Transport: defaultTransport(1 * time.Second),
	}
}

// defaultTransport returns the `*http.Transport` which starts and maintain the
// connection with the server. The `dialTimeout` is used to specify the timeout
// beyond which the connection is considered as failed (used to control DNS
// lookup timeouts).
func defaultTransport(dialTimeout time.Duration) *http.Transport {
	return &http.Transport{
		Dial: (&net.Dialer{
			KeepAlive: 180 * time.Second,
			Timeout:   dialTimeout,
		}).Dial,
		DisableKeepAlives:   false,
		MaxIdleConnsPerHost: 2,
		TLSHandshakeTimeout: 2 * time.Second,
	}
}

// addHeaders add the key/value pairs from `headers` to the header list of the
// `req` request.
func addHeaders(req *http.Request, headers map[string]string) {
	for k, v := range headers {
		req.Header.Add(k, v)
	}
}

// setExtraHeader lets the user (through the exported `Client.SetExtraHeader`)
// add custom headers to the requests.
func (t *Transport) setExtraHeader(key, value string) {
	t.headers[key] = value
}

// setTimeout lets the user (through the exported `Client.SetTimeout`) replace
// the default values of `TLSHandshakeTimeout` (via `connectTimeout`) and
// `ResponseHeaderTimeout` (via `readTimeout`).
func (t *Transport) setTimeout(connectTimeout, readTimeout time.Duration) {
	switch transport := t.httpClient.Transport.(type) {
	case *http.Transport:
		transport.TLSHandshakeTimeout = connectTimeout
		transport.ResponseHeaderTimeout = readTimeout
	default:
		fmt.Fprintln(os.Stderr, "Timeouts not set for nonstandard underlying Transport")
	}
}

// request is the method used by the `Client` to perform the request against
// the Algolia servers (or to the list of specified hosts).
func (t *Transport) request(method, path string, body interface{}, typeCall int) ([]byte, error) {
	var res []byte
	var err error

	for _, host := range t.hostsToTry(typeCall) {
		res, err = t.tryRequest(method, host, path, body)
		if err == nil {
			t.resetDialTimeout()
			if typeCall == write {
				t.activeWriteSince = time.Now()
				t.activeWriteHost = host
			} else {
				t.activeReadSince = time.Now()
				t.activeReadHost = host
			}
			return res, nil
		}
		t.increaseDialTimeout()
	}

	if typeCall == write {
		t.activeWriteHost = ""
	} else {
		t.activeReadHost = ""
	}

	return nil, err
}

// hostsToTry returns the list of hosts to try ordered by priority according to
// the type of request (write vs. read/search) and if a previous host was
// marked as active.
func (t *Transport) hostsToTry(typeCall int) []string {
	var hosts []string

	// Step 1:
	//
	// We set the first host to try to the last active one if any and
	// if it was active recently.

	if typeCall == write {
		// In case the request is a write query, we put the last active write
		// host first in the list of hosts to try if it was used in the last
		// `keepAliveDuration` seconds. We then put the main algolia.net host.
		if t.activeWriteHost != "" &&
			time.Now().Sub(t.activeWriteSince) <= t.keepAliveDuration {
			hosts = []string{t.activeWriteHost}
		}
	} else {
		// In case the request is not a write query, we put the last active
		// read host first in the list of hosts to try if it was used in the
		// last `keepAliveDuration` seconds. We then put the DSN host.
		if t.activeReadHost != "" &&
			time.Now().Sub(t.activeReadSince) <= t.keepAliveDuration {
			hosts = []string{t.activeReadHost}
		}
	}

	// Step 2:
	//
	// If the hosts were provided we use them first to make sure they are tried
	// first. Otherwise, we use put the default ones after the ones already
	// generated.

	if len(t.providedHosts) > 0 {
		hosts = append(hosts, t.providedHosts...)
	}

	// Step 3:
	//
	// The main host is added to the list, along with the default ones.

	if typeCall == write {
		hosts = append(hosts, t.appId+".algolia.net")
	} else {
		hosts = append(hosts, t.appId+"-dsn.algolia.net")
	}
	hosts = append(hosts, t.defaultHosts()...)

	return hosts
}

// tryRequest is the underlying method which actually performs the request. It
// returns the response as a byte slice or a non-nil error if anything went
// wrong.
func (t *Transport) tryRequest(method, host, path string, body interface{}) ([]byte, error) {
	// Build the request
	req, err := t.buildRequest(method, host, path, body)
	if err != nil {
		return nil, err
	}

	// Perform the request
	res, err := t.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Cannot perform request [%s] %s (%s): %s", method, path, host, err)
	}
	defer res.Body.Close()

	// Read response's body
	bodyRes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body: %s", err)
	}

	// Return the body as an error if the status code is not 2XX
	code := res.StatusCode
	if !(200 <= code && code < 300) {
		return nil, errors.New(string(bodyRes))
	}

	return bodyRes, nil
}

// buildRequest returns a valid `http.Request` with the headers and body (if
// any) correctly set. The return error is non-nil if the request is invalid or
// if the body, if non-nil, is not a valid JSON.
func (t *Transport) buildRequest(method, host, path string, body interface{}) (*http.Request, error) {
	var req *http.Request
	var err error
	urlStr := "https://" + host + path

	if body == nil {
		// As the body is nil, an empty body request is instantiated
		req, err = http.NewRequest(method, urlStr, nil)
		if err != nil {
			return nil, fmt.Errorf("Cannot instantiate request: [%s] %s", method, urlStr)
		}
	} else {
		// As the body is non-nil, the content is read
		data, err := json.Marshal(body)
		if err != nil {
			return nil, errors.New("Invalid JSON in the query")
		}
		reader := bytes.NewReader(data)

		// The request is then instantiated with the body content
		req, err = http.NewRequest(method, urlStr, reader)
		if err != nil {
			return nil, fmt.Errorf("Cannot instantiate request: [%s] %s", method, urlStr)
		}

		// Add content specific headers
		req.Header.Add("Content-Length", strconv.Itoa(len(string(data))))
		req.Header.Add("Content-Type", "application/json; charset=utf-8")
	}

	// Add default and Algolia specific headers
	addHeaders(req, t.headers)

	if strings.Contains(path, "/*/") {
		req.URL = &url.URL{
			Scheme: "https",
			Host:   host,
			Opaque: "//" + host + path, //Remove url encoding
		}
	}

	return req, nil
}

// resetDialTimeout increases the `Timeout` value of the underlying dialer by 1
// second.
func (t *Transport) increaseDialTimeout() {
	t.dialTimeout = t.dialTimeout + time.Second
	t.httpClient.Transport = defaultTransport(t.dialTimeout)
}

// resetDialTimeout resets the `Timeout` value of the underlying dialer to 1
// second.
func (t *Transport) resetDialTimeout() {
	t.dialTimeout = 1 * time.Second
	t.httpClient.Transport = defaultTransport(t.dialTimeout)
}
<commit_msg>feat: Add default ProxyFunc to the default transport layer of the HTTP client<commit_after>package algoliasearch

import (
	"bytes"
	_ "crypto/sha512" // Fix certificates
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net"
	"net/http"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
)

const (
	version = "2.11.0"
)

// Define the constants used to specify the type of request.
const (
	search = 1 << iota
	write
	read
)

// Seed the RNG used to shuffle the hosts slice (see `defaultHosts` function).
func init() {
	rand.Seed(int64(time.Now().Nanosecond()))
}

// Transport is responsible for the connection and the retry strategy to
// Algolia servers.
type Transport struct {
	activeReadHost    string
	activeReadSince   time.Time
	activeWriteHost   string
	activeWriteSince  time.Time
	apiKey            string
	appId             string
	dialTimeout       time.Duration
	headers           map[string]string
	httpClient        *http.Client
	keepAliveDuration time.Duration
	providedHosts     []string
}

// NewTransport instantiates a new Transport with the default Algolia hosts to
// connect to.
func NewTransport(appId, apiKey string) *Transport {
	return &Transport{
		activeReadHost:    "",
		activeWriteHost:   "",
		apiKey:            apiKey,
		appId:             appId,
		dialTimeout:       1 * time.Second,
		headers:           defaultHeaders(appId, apiKey),
		httpClient:        defaultHttpClient(),
		keepAliveDuration: 5 * time.Minute,
		providedHosts:     nil,
	}
}

// NewTransport instantiates a new Transport with the specificed hosts as main
// servers to connect to.
func NewTransportWithHosts(appId, apiKey string, hosts []string) *Transport {
	return &Transport{
		activeReadHost:    "",
		activeWriteHost:   "",
		apiKey:            apiKey,
		appId:             appId,
		dialTimeout:       1 * time.Second,
		headers:           defaultHeaders(appId, apiKey),
		httpClient:        defaultHttpClient(),
		keepAliveDuration: 5 * 60 * time.Second,
		providedHosts:     hosts,
	}
}

// defaultHeaders is used to set the default HTTP headers to use with each
// requests.
func defaultHeaders(appId, apiKey string) map[string]string {
	return map[string]string{
		"Connection":               "keep-alive",
		"User-Agent":               "Algolia for Go (" + version + ")",
		"X-Algolia-API-Key":        apiKey,
		"X-Algolia-Application-Id": appId,
	}
}

// defaultHosts returns the list of the default Algolia hosts to use. The
// entries are shuffled.
func (t *Transport) defaultHosts() []string {
	hosts := []string{
		t.appId + "-1.algolianet.com",
		t.appId + "-2.algolianet.com",
		t.appId + "-3.algolianet.com",
	}

	shuffled := make([]string, len(hosts))
	for i, v := range rand.Perm(len(hosts)) {
		shuffled[i] = hosts[v]
	}

	return shuffled
}

// defaultHttpClient returns the `*http.Client` which will perform all the
// requests. All the timeout settings are explicitely defined here.
func defaultHttpClient() *http.Client {
	return &http.Client{
		Timeout:   time.Second * 30,
		Transport: defaultTransport(1 * time.Second),
	}
}

// defaultTransport returns the `*http.Transport` which starts and maintain the
// connection with the server. The `dialTimeout` is used to specify the timeout
// beyond which the connection is considered as failed (used to control DNS
// lookup timeouts).
func defaultTransport(dialTimeout time.Duration) *http.Transport {
	return &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			KeepAlive: 180 * time.Second,
			Timeout:   dialTimeout,
		}).Dial,
		DisableKeepAlives:   false,
		MaxIdleConnsPerHost: 2,
		TLSHandshakeTimeout: 2 * time.Second,
	}
}

// addHeaders add the key/value pairs from `headers` to the header list of the
// `req` request.
func addHeaders(req *http.Request, headers map[string]string) {
	for k, v := range headers {
		req.Header.Add(k, v)
	}
}

// setExtraHeader lets the user (through the exported `Client.SetExtraHeader`)
// add custom headers to the requests.
func (t *Transport) setExtraHeader(key, value string) {
	t.headers[key] = value
}

// setTimeout lets the user (through the exported `Client.SetTimeout`) replace
// the default values of `TLSHandshakeTimeout` (via `connectTimeout`) and
// `ResponseHeaderTimeout` (via `readTimeout`).
func (t *Transport) setTimeout(connectTimeout, readTimeout time.Duration) {
	switch transport := t.httpClient.Transport.(type) {
	case *http.Transport:
		transport.TLSHandshakeTimeout = connectTimeout
		transport.ResponseHeaderTimeout = readTimeout
	default:
		fmt.Fprintln(os.Stderr, "Timeouts not set for nonstandard underlying Transport")
	}
}

// request is the method used by the `Client` to perform the request against
// the Algolia servers (or to the list of specified hosts).
func (t *Transport) request(method, path string, body interface{}, typeCall int) ([]byte, error) {
	var res []byte
	var err error

	for _, host := range t.hostsToTry(typeCall) {
		res, err = t.tryRequest(method, host, path, body)
		if err == nil {
			t.resetDialTimeout()
			if typeCall == write {
				t.activeWriteSince = time.Now()
				t.activeWriteHost = host
			} else {
				t.activeReadSince = time.Now()
				t.activeReadHost = host
			}
			return res, nil
		}
		t.increaseDialTimeout()
	}

	if typeCall == write {
		t.activeWriteHost = ""
	} else {
		t.activeReadHost = ""
	}

	return nil, err
}

// hostsToTry returns the list of hosts to try ordered by priority according to
// the type of request (write vs. read/search) and if a previous host was
// marked as active.
func (t *Transport) hostsToTry(typeCall int) []string {
	var hosts []string

	// Step 1:
	//
	// We set the first host to try to the last active one if any and
	// if it was active recently.

	if typeCall == write {
		// In case the request is a write query, we put the last active write
		// host first in the list of hosts to try if it was used in the last
		// `keepAliveDuration` seconds. We then put the main algolia.net host.
		if t.activeWriteHost != "" &&
			time.Now().Sub(t.activeWriteSince) <= t.keepAliveDuration {
			hosts = []string{t.activeWriteHost}
		}
	} else {
		// In case the request is not a write query, we put the last active
		// read host first in the list of hosts to try if it was used in the
		// last `keepAliveDuration` seconds. We then put the DSN host.
		if t.activeReadHost != "" &&
			time.Now().Sub(t.activeReadSince) <= t.keepAliveDuration {
			hosts = []string{t.activeReadHost}
		}
	}

	// Step 2:
	//
	// If the hosts were provided we use them first to make sure they are tried
	// first. Otherwise, we use put the default ones after the ones already
	// generated.

	if len(t.providedHosts) > 0 {
		hosts = append(hosts, t.providedHosts...)
	}

	// Step 3:
	//
	// The main host is added to the list, along with the default ones.

	if typeCall == write {
		hosts = append(hosts, t.appId+".algolia.net")
	} else {
		hosts = append(hosts, t.appId+"-dsn.algolia.net")
	}
	hosts = append(hosts, t.defaultHosts()...)

	return hosts
}

// tryRequest is the underlying method which actually performs the request. It
// returns the response as a byte slice or a non-nil error if anything went
// wrong.
func (t *Transport) tryRequest(method, host, path string, body interface{}) ([]byte, error) {
	// Build the request
	req, err := t.buildRequest(method, host, path, body)
	if err != nil {
		return nil, err
	}

	// Perform the request
	res, err := t.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("Cannot perform request [%s] %s (%s): %s", method, path, host, err)
	}
	defer res.Body.Close()

	// Read response's body
	bodyRes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, fmt.Errorf("Cannot read response body: %s", err)
	}

	// Return the body as an error if the status code is not 2XX
	code := res.StatusCode
	if !(200 <= code && code < 300) {
		return nil, errors.New(string(bodyRes))
	}

	return bodyRes, nil
}

// buildRequest returns a valid `http.Request` with the headers and body (if
// any) correctly set. The return error is non-nil if the request is invalid or
// if the body, if non-nil, is not a valid JSON.
func (t *Transport) buildRequest(method, host, path string, body interface{}) (*http.Request, error) {
	var req *http.Request
	var err error
	urlStr := "https://" + host + path

	if body == nil {
		// As the body is nil, an empty body request is instantiated
		req, err = http.NewRequest(method, urlStr, nil)
		if err != nil {
			return nil, fmt.Errorf("Cannot instantiate request: [%s] %s", method, urlStr)
		}
	} else {
		// As the body is non-nil, the content is read
		data, err := json.Marshal(body)
		if err != nil {
			return nil, errors.New("Invalid JSON in the query")
		}
		reader := bytes.NewReader(data)

		// The request is then instantiated with the body content
		req, err = http.NewRequest(method, urlStr, reader)
		if err != nil {
			return nil, fmt.Errorf("Cannot instantiate request: [%s] %s", method, urlStr)
		}

		// Add content specific headers
		req.Header.Add("Content-Length", strconv.Itoa(len(string(data))))
		req.Header.Add("Content-Type", "application/json; charset=utf-8")
	}

	// Add default and Algolia specific headers
	addHeaders(req, t.headers)

	if strings.Contains(path, "/*/") {
		req.URL = &url.URL{
			Scheme: "https",
			Host:   host,
			Opaque: "//" + host + path, //Remove url encoding
		}
	}

	return req, nil
}

// resetDialTimeout increases the `Timeout` value of the underlying dialer by 1
// second.
func (t *Transport) increaseDialTimeout() {
	t.dialTimeout = t.dialTimeout + time.Second
	t.httpClient.Transport = defaultTransport(t.dialTimeout)
}

// resetDialTimeout resets the `Timeout` value of the underlying dialer to 1
// second.
func (t *Transport) resetDialTimeout() {
	t.dialTimeout = 1 * time.Second
	t.httpClient.Transport = defaultTransport(t.dialTimeout)
}
<|endoftext|>


<commit_before>package algoliasearch

type Key struct {
	ACL                    []string `json:"acl"`
	CreatedAt              int      `json:"createdAt,omitempty"`
	Description            string   `json:"description,omitempty"`
	MaxHitsPerQuery        int      `json:"maxHitsPerQuery,omitempty"`
	MaxQueriesPerIPPerHour int      `json:"maxQueriesPerIPPerHour,omitempty"`
	QueryParamaters        string   `json:"queryParameters,omitempty"`
	Referers               []string `json:"referers,omitempty"`
	Validity               int      `json:"validity,omitempty"`
	Value                  string   `json:"value,omitempty"`
}

type listKeysRes struct {
	Keys []Key `json:"keys"`
}

type AddKeyRes struct {
	CreatedAt string `json:"createdAt"`
	Key       string `json:"key"`
}

type UpdateKeyRes struct {
	Key       string `json:"key"`
	UpdatedAt string `json:"updatedAt"`
}
<commit_msg>Add Indexes to Key<commit_after>package algoliasearch

type Key struct {
	ACL                    []string `json:"acl"`
	CreatedAt              int      `json:"createdAt,omitempty"`
	Description            string   `json:"description,omitempty"`
	Indexes                []string `json:"indexes,omitempty"`
	MaxHitsPerQuery        int      `json:"maxHitsPerQuery,omitempty"`
	MaxQueriesPerIPPerHour int      `json:"maxQueriesPerIPPerHour,omitempty"`
	QueryParamaters        string   `json:"queryParameters,omitempty"`
	Referers               []string `json:"referers,omitempty"`
	Validity               int      `json:"validity,omitempty"`
	Value                  string   `json:"value,omitempty"`
}

type listKeysRes struct {
	Keys []Key `json:"keys"`
}

type AddKeyRes struct {
	CreatedAt string `json:"createdAt"`
	Key       string `json:"key"`
}

type UpdateKeyRes struct {
	Key       string `json:"key"`
	UpdatedAt string `json:"updatedAt"`
}
<|endoftext|>


<commit_before>package JWTMiddleWares

import (
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/francoishill/go-simple-token-auth/Auth/JWT/JWTBackend"
	"net/http"
)

var TokenHandlers iTokenHandlers = nil

type iTokenHandlers interface {
	HandleTokenExtractedSuccessfully(http.ResponseWriter, *http.Request, *jwt.Token)
}

func RequireTokenAuthentication(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
	authBackend := JWTBackend.CurrentGlobalAuthenticationBackend

	token, err := jwt.ParseFromRequest(req, authBackend.GetPublicKey)
	//TODO: We should probably check for specific errors like 'jwt.ValidationErrorExpired'
	if TokenHandlers != nil {
		TokenHandlers.HandleTokenExtractedSuccessfully(rw, req, token)
	}

	if err == nil && token.Valid && !authBackend.IsInBlacklist(req.Header.Get("Authorization")) {
		next(rw, req)
	} else {
		rw.WriteHeader(http.StatusUnauthorized)
	}
}
<commit_msg>Fixed previous commit bug introduced.<commit_after>package JWTMiddleWares

import (
	jwt "github.com/dgrijalva/jwt-go"
	"github.com/francoishill/go-simple-token-auth/Auth/JWT/JWTBackend"
	"net/http"
)

var TokenHandlers iTokenHandlers = nil

type iTokenHandlers interface {
	HandleTokenExtractedSuccessfully(http.ResponseWriter, *http.Request, *jwt.Token)
}

func RequireTokenAuthentication(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
	authBackend := JWTBackend.CurrentGlobalAuthenticationBackend

	token, err := jwt.ParseFromRequest(req, authBackend.GetPublicKey)
	//TODO: We should probably check for specific errors like 'jwt.ValidationErrorExpired'

	if err == nil && token.Valid && !authBackend.IsInBlacklist(req.Header.Get("Authorization")) {
		if TokenHandlers != nil {
			TokenHandlers.HandleTokenExtractedSuccessfully(rw, req, token)
		}
		next(rw, req)
	} else {
		rw.WriteHeader(http.StatusUnauthorized)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"os/exec"
	"strings"
)

func getVendorSubmodules() (map[string]string, error) {
	output, err := execute(
		exec.Command("git", "submodule", "status"),
	)
	if err != nil {
		return nil, err
	}

	vendors := map[string]string{}

	lines := strings.Split(output, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}

		parts := strings.Split(line, " ")
		if len(parts) == 4 {
			path := parts[2]
			commit := parts[1]
			if strings.HasPrefix(path, "vendor/") {
				path = strings.TrimPrefix(path, "vendor/")
				vendors[path] = commit
			}
		}
	}

	return vendors, nil
}

func addVendorSubmodule(importpath string) error {
	var (
		target   = "vendor/" + importpath
		prefixes = []string{"git://", "git+ssh://", "ssh://", "https://"}

		errs []string
	)

	for _, prefix := range prefixes {
		url := prefix + importpath

		_, err := execute(
			exec.Command("git", "submodule", "add", "-f", url, target),
		)
		if err == nil {
			return nil
		}

		errs = append(errs, err.Error())
	}

	return errors.New(strings.Join(errs, "\n"))
}

func removeVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(exec.Command("git", "submodule", "deinit", "-f", path))
	if err != nil {
		return err
	}

	_, err = execute(exec.Command("git", "rm", "-f", path))
	if err != nil {
		return err
	}

	return nil
}

func updateVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(
		exec.Command("git", "--work-tree="+path, "pull", "origin", "master"),
	)

	return err
}
<commit_msg>submodule: improve parsing git submodule status<commit_after>package main

import (
	"errors"
	"os/exec"
	"strings"
)

func getVendorSubmodules() (map[string]string, error) {
	output, err := execute(
		exec.Command("git", "submodule", "status"),
	)
	if err != nil {
		return nil, err
	}

	vendors := map[string]string{}

	lines := strings.Split(output, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}

		parts := strings.Split(strings.TrimLeft(line, " -"), " ")
		if len(parts) >= 2 {
			path := parts[1]
			commit := parts[0]
			if strings.HasPrefix(path, "vendor/") {
				path = strings.TrimPrefix(path, "vendor/")
				vendors[path] = commit
			}
		}
	}

	return vendors, nil
}

func addVendorSubmodule(importpath string) error {
	var (
		target   = "vendor/" + importpath
		prefixes = []string{"git://", "git+ssh://", "ssh://", "https://"}

		errs []string
	)

	for _, prefix := range prefixes {
		url := prefix + importpath

		_, err := execute(
			exec.Command("git", "submodule", "add", "-f", url, target),
		)
		if err == nil {
			return nil
		}

		errs = append(errs, err.Error())
	}

	return errors.New(strings.Join(errs, "\n"))
}

func removeVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(exec.Command("git", "submodule", "deinit", "-f", path))
	if err != nil {
		return err
	}

	_, err = execute(exec.Command("git", "rm", "-f", path))
	if err != nil {
		return err
	}

	return nil
}

func updateVendorSubmodule(importpath string) error {
	path := "vendor/" + importpath

	_, err := execute(
		exec.Command("git", "--work-tree="+path, "pull", "origin", "master"),
	)

	return err
}
<|endoftext|>