<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"runtime"
	"time"

	"image"
	"image/png"

	_ "code.google.com/p/go.image/tiff"

	"github.com/shurcooL/trayhost"
)

// TODO: Load from config. Have ability to set config.
var hostFlag = flag.String("host", "", "Target server host.")
var debugFlag = flag.Bool("debug", false, "Adds menu items for debugging purposes.")

func instantShareEnabled() bool {
	fmt.Println("check if clipboard contains something usable")

	_, err := trayhost.GetClipboardImage()
	if err != nil {
		return false
	}

	return true
}

func instantShareHandler() {
	fmt.Println("grab content, content-type of clipboard")

	img, err := trayhost.GetClipboardImage()
	if err != nil {
		log.Println(err)
		return
	}

	// Convert image to desired destination format (currently, always PNG).
	var imageData []byte
	switch img.Kind {
	case trayhost.ImageKindPng:
		imageData = img.Bytes
	case trayhost.ImageKindTiff:
		m, _, err := image.Decode(bytes.NewReader(img.Bytes))
		if err != nil {
			log.Panicln("image.Decode:", err)
		}

		var buf bytes.Buffer
		err = png.Encode(&buf, m)
		if err != nil {
			log.Panicln("png.Encode:", err)
		}
		imageData = buf.Bytes()
	default:
		log.Println("unsupported source image kind:", img.Kind)
		return
	}

	fmt.Println("request URL")

	resp, err := (&http.Client{Timeout: 1 * time.Second}).Get(*hostFlag + "/api/getfilename?ext=png")
	if err != nil {
		trayhost.Notification{Title: "Upload Failed", Body: err.Error()}.Display()
		log.Println(err)
		return
	}
	defer resp.Body.Close()
	filename, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		trayhost.Notification{Title: "Upload Failed", Body: err.Error()}.Display()
		log.Println(err)
		return
	}

	fmt.Println("display/put URL in clipboard")

	url := *hostFlag + "/" + string(filename)
	trayhost.SetClipboardString(url)
	trayhost.Notification{Title: "Upload Complete", Body: url, Timeout: 3 * time.Second}.Display()

	fmt.Println("upload image in background of size", len(imageData))

	go func() {
		req, err := http.NewRequest("PUT", url, bytes.NewReader(imageData))
		if err != nil {
			log.Println(err)
			return
		}
		req.Header.Set("Content-Type", "application/octet-stream")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			log.Println(err)
			return
		}
		_ = resp.Body.Close()
		fmt.Println("done")
	}()
}

func main() {
	flag.Parse()
	runtime.LockOSThread()

	menuItems := []trayhost.MenuItem{
		trayhost.MenuItem{
			Title:   "Instant Share",
			Enabled: instantShareEnabled,
			Handler: instantShareHandler,
		},
		trayhost.SeparatorMenuItem(),
		trayhost.MenuItem{
			Title:   "Quit",
			Handler: trayhost.Exit,
		},
	}
	if *debugFlag {
		menuItems = append(menuItems,
			trayhost.SeparatorMenuItem(),
			trayhost.MenuItem{
				Title: "Debug: Get Clipboard String",
				Handler: func() {
					str, err := trayhost.GetClipboardString()
					fmt.Printf("GetClipboardString(): %q %v\n", str, err)
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Get Clipboard Image",
				Handler: func() {
					img, err := trayhost.GetClipboardImage()
					fmt.Printf("GetClipboardImage(): %v len(%v) %v\n", img.Kind, len(img.Bytes), err)
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Set Clipboard",
				Handler: func() {
					trayhost.SetClipboardString("http://www.example.com/image.png")
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Notification",
				Handler: func() {
					trayhost.Notification{Title: "Upload Complete", Body: "http://www.example.com/image.png", Timeout: 3 * time.Second}.Display()
					//trayhost.Notification{Title: "Upload Failed", Body: "error description goes here"}.Display()
				},
			},
		)
	}

	// TODO: Create a real icon and bake it into the binary.
	// TODO: Optionally, if non-Retina pixel perfection is required, generate or load 1x image and supply that as a second representation.
	iconData, err := ioutil.ReadFile("./icon@2x.png")
	if err != nil {
		panic(err)
	}

	fmt.Println("Starting.")

	trayhost.Initialize("Instant Share", iconData, menuItems)

	trayhost.EnterLoop()

	fmt.Println("Exiting.")
}
<commit_msg>Open displayed URL when clicking notification.<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"runtime"
	"time"

	"image"
	"image/png"

	_ "code.google.com/p/go.image/tiff"

	"github.com/shurcooL/go/u/u4"
	"github.com/shurcooL/trayhost"
)

// TODO: Load from config. Have ability to set config.
var hostFlag = flag.String("host", "", "Target server host.")
var debugFlag = flag.Bool("debug", false, "Adds menu items for debugging purposes.")

func instantShareEnabled() bool {
	fmt.Println("check if clipboard contains something usable")

	_, err := trayhost.GetClipboardImage()
	if err != nil {
		return false
	}

	return true
}

func instantShareHandler() {
	fmt.Println("grab content, content-type of clipboard")

	img, err := trayhost.GetClipboardImage()
	if err != nil {
		log.Println(err)
		return
	}

	// Convert image to desired destination format (currently, always PNG).
	var imageData []byte
	switch img.Kind {
	case trayhost.ImageKindPng:
		imageData = img.Bytes
	case trayhost.ImageKindTiff:
		m, _, err := image.Decode(bytes.NewReader(img.Bytes))
		if err != nil {
			log.Panicln("image.Decode:", err)
		}

		var buf bytes.Buffer
		err = png.Encode(&buf, m)
		if err != nil {
			log.Panicln("png.Encode:", err)
		}
		imageData = buf.Bytes()
	default:
		log.Println("unsupported source image kind:", img.Kind)
		return
	}

	fmt.Println("request URL")

	resp, err := (&http.Client{Timeout: 1 * time.Second}).Get(*hostFlag + "/api/getfilename?ext=png")
	if err != nil {
		trayhost.Notification{Title: "Upload Failed", Body: err.Error()}.Display()
		log.Println(err)
		return
	}
	defer resp.Body.Close()
	filename, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		trayhost.Notification{Title: "Upload Failed", Body: err.Error()}.Display()
		log.Println(err)
		return
	}

	fmt.Println("display/put URL in clipboard")

	url := *hostFlag + "/" + string(filename)
	trayhost.SetClipboardString(url)
	trayhost.Notification{
		Title:   "Upload Complete",
		Body:    url,
		Timeout: 3 * time.Second,
		Handler: func() {
			// On click, open the displayed URL.
			u4.Open(url)
		},
	}.Display()

	fmt.Println("upload image in background of size", len(imageData))

	go func() {
		req, err := http.NewRequest("PUT", url, bytes.NewReader(imageData))
		if err != nil {
			log.Println(err)
			return
		}
		req.Header.Set("Content-Type", "application/octet-stream")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			log.Println(err)
			return
		}
		_ = resp.Body.Close()
		fmt.Println("done")
	}()
}

func main() {
	flag.Parse()
	runtime.LockOSThread()

	menuItems := []trayhost.MenuItem{
		trayhost.MenuItem{
			Title:   "Instant Share",
			Enabled: instantShareEnabled,
			Handler: instantShareHandler,
		},
		trayhost.SeparatorMenuItem(),
		trayhost.MenuItem{
			Title:   "Quit",
			Handler: trayhost.Exit,
		},
	}
	if *debugFlag {
		menuItems = append(menuItems,
			trayhost.SeparatorMenuItem(),
			trayhost.MenuItem{
				Title: "Debug: Get Clipboard String",
				Handler: func() {
					str, err := trayhost.GetClipboardString()
					fmt.Printf("GetClipboardString(): %q %v\n", str, err)
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Get Clipboard Image",
				Handler: func() {
					img, err := trayhost.GetClipboardImage()
					fmt.Printf("GetClipboardImage(): %v len(%v) %v\n", img.Kind, len(img.Bytes), err)
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Set Clipboard",
				Handler: func() {
					trayhost.SetClipboardString("http://www.example.com/image.png")
				},
			},
			trayhost.MenuItem{
				Title: "Debug: Notification",
				Handler: func() {
					handler := func() {
						u4.Open("http://www.example.com/image.png")
					}
					trayhost.Notification{Title: "Upload Complete", Body: "http://www.example.com/image.png", Timeout: 3 * time.Second, Handler: handler}.Display()
					//trayhost.Notification{Title: "Upload Failed", Body: "error description goes here"}.Display()
				},
			},
		)
	}

	// TODO: Create a real icon and bake it into the binary.
	// TODO: Optionally, if non-Retina pixel perfection is required, generate or load 1x image and supply that as a second representation.
	iconData, err := ioutil.ReadFile("./icon@2x.png")
	if err != nil {
		panic(err)
	}

	fmt.Println("Starting.")

	trayhost.Initialize("Instant Share", iconData, menuItems)

	trayhost.EnterLoop()

	fmt.Println("Exiting.")
}
<|endoftext|>


<commit_before>package webloop

import (
	"github.com/sqs/gotk3/gtk"
	"log"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"
)

// StaticRenderer generates and returns static HTML based on a snapshot of a Web
// page's computed HTML.
type StaticRenderer struct {
	// TargetBaseURL is the baseURL of the dynamic content URLs.
	TargetBaseURL string

	// Context is the WebLoop context to create views in.
	Context Context

	// WaitTimeout is the maximum duration to wait for a loaded page to set
	// window.$renderStaticReady.
	WaitTimeout time.Duration

	// ReturnUnfinishedPages is whether a page that has not set
	// window.$renderStaticReady after WaitTimeout is sent to the browser in a
	// (potentially) unfinished state. If false, an HTTP 502 Bad Gateway error
	// will be returned.
	//
	// If you are unsure of whether all accessible pages set
	// window.$renderStaticReady (perhaps you could forget to do so on a few
	// pages), then setting ReturnUnfinishedPages would suppress errors for
	// those pages, at the possible expense of sending out unfinished pages that
	// take a long time to load.
	ReturnUnfinishedPages bool

	// RemoveJavaScript indicates whether <script> tags will be removed. When
	// generating static HTML pages from a dynamic JavaScript app, this is often
	// necessary because the JavaScript expects to run on a non-bootstrapped
	// page. This option is not guaranteed to disable all <script> tags and
	// should relied upon for security purposes.
	RemoveScripts bool

	// Log is the logger to use for log messages. If nil, there is no log
	// output.
	Log *log.Logger

	viewLock sync.Mutex
	view     *View
}

var startGTKOnce sync.Once

// StartGTK ensures that the GTK+ main loop has started. If it has already been
// started by StartGTK, it will not start it again. If another goroutine is
// already running the GTK+ main loop, StartGTK's behavior is undefined.
func (h *StaticRenderer) StartGTK() {
	startGTKOnce.Do(func() {
		gtk.Init(nil)
		go func() {
			runtime.LockOSThread()
			gtk.Main()
		}()
	})
}

// Release releases resources used by this handler, such as the view. If this
// handler is reused after calling Release, the view is automatically recreated.
func (h *StaticRenderer) Release() {
	h.viewLock.Lock()
	h.view.Close()
	h.view = nil
	defer h.viewLock.Unlock()
}

// ServeHTTP implements net/http.Handler.
func (h *StaticRenderer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.StartGTK()
	h.viewLock.Lock()
	defer h.viewLock.Unlock()

	if h.view == nil {
		h.view = h.Context.NewView()
	}

	targetURL := h.TargetBaseURL + r.URL.String()
	h.logf("Rendering HTML for page at URL: %s", targetURL)
	h.view.Open(targetURL)
	h.view.Wait()

	// Wait until window.$renderStaticReady is true.
	start := time.Now()
	for {
		if time.Since(start) > h.WaitTimeout {
			if h.ReturnUnfinishedPages {
				h.logf("Page at URL %s did not set $renderStaticReady within timeout %s; returning unfinished page", targetURL, h.WaitTimeout)
				break
			}
			h.logf("Page at URL %s did not set $renderStaticReady within timeout %s; returning HTTP error", targetURL, h.WaitTimeout)
			http.Error(w, "No response from origin server within "+h.WaitTimeout.String(), http.StatusBadGateway)
			return
		}

		ready, err := h.view.EvaluateJavaScript("window.$renderStaticReady")
		if err != nil {
			http.Error(w, "error checking $renderStaticReady: "+err.Error(), http.StatusInternalServerError)
			return
		}
		if ready, _ := ready.(bool); ready {
			break
		}
	}

	result, err := h.view.EvaluateJavaScript("document.documentElement.outerHTML")
	if err != nil {
		h.logf("Failed to dump HTML for page at URL %s: %s", targetURL, err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	html := result.(string)
	html = strings.Replace(html, "<body>", `<body><h3 style="padding:10px;background-color:red;color:white">This is a static page generated from <a style="color:white" href="`+r.URL.String()+`">`+r.URL.String()+`</a></h3><hr>`, 1)
	if h.RemoveScripts {
		html = strings.Replace(html, "<script", `<script type="text/disabled"`, -1)
	}
	w.Write([]byte(html))
}

func (h *StaticRenderer) logf(msg string, v ...interface{}) {
	if h.Log != nil {
		h.Log.Printf(msg, v...)
	}
}
<commit_msg>Remove banner in StaticRenderer<commit_after>package webloop

import (
	"github.com/sqs/gotk3/gtk"
	"log"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"time"
)

// StaticRenderer generates and returns static HTML based on a snapshot of a Web
// page's computed HTML.
type StaticRenderer struct {
	// TargetBaseURL is the baseURL of the dynamic content URLs.
	TargetBaseURL string

	// Context is the WebLoop context to create views in.
	Context Context

	// WaitTimeout is the maximum duration to wait for a loaded page to set
	// window.$renderStaticReady.
	WaitTimeout time.Duration

	// ReturnUnfinishedPages is whether a page that has not set
	// window.$renderStaticReady after WaitTimeout is sent to the browser in a
	// (potentially) unfinished state. If false, an HTTP 502 Bad Gateway error
	// will be returned.
	//
	// If you are unsure of whether all accessible pages set
	// window.$renderStaticReady (perhaps you could forget to do so on a few
	// pages), then setting ReturnUnfinishedPages would suppress errors for
	// those pages, at the possible expense of sending out unfinished pages that
	// take a long time to load.
	ReturnUnfinishedPages bool

	// RemoveJavaScript indicates whether <script> tags will be removed. When
	// generating static HTML pages from a dynamic JavaScript app, this is often
	// necessary because the JavaScript expects to run on a non-bootstrapped
	// page. This option is not guaranteed to disable all <script> tags and
	// should relied upon for security purposes.
	RemoveScripts bool

	// Log is the logger to use for log messages. If nil, there is no log
	// output.
	Log *log.Logger

	viewLock sync.Mutex
	view     *View
}

var startGTKOnce sync.Once

// StartGTK ensures that the GTK+ main loop has started. If it has already been
// started by StartGTK, it will not start it again. If another goroutine is
// already running the GTK+ main loop, StartGTK's behavior is undefined.
func (h *StaticRenderer) StartGTK() {
	startGTKOnce.Do(func() {
		gtk.Init(nil)
		go func() {
			runtime.LockOSThread()
			gtk.Main()
		}()
	})
}

// Release releases resources used by this handler, such as the view. If this
// handler is reused after calling Release, the view is automatically recreated.
func (h *StaticRenderer) Release() {
	h.viewLock.Lock()
	h.view.Close()
	h.view = nil
	defer h.viewLock.Unlock()
}

// ServeHTTP implements net/http.Handler.
func (h *StaticRenderer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.StartGTK()
	h.viewLock.Lock()
	defer h.viewLock.Unlock()

	if h.view == nil {
		h.view = h.Context.NewView()
	}

	targetURL := h.TargetBaseURL + r.URL.String()
	h.logf("Rendering HTML for page at URL: %s", targetURL)
	h.view.Open(targetURL)
	h.view.Wait()

	// Wait until window.$renderStaticReady is true.
	start := time.Now()
	for {
		if time.Since(start) > h.WaitTimeout {
			if h.ReturnUnfinishedPages {
				h.logf("Page at URL %s did not set $renderStaticReady within timeout %s; returning unfinished page", targetURL, h.WaitTimeout)
				break
			}
			h.logf("Page at URL %s did not set $renderStaticReady within timeout %s; returning HTTP error", targetURL, h.WaitTimeout)
			http.Error(w, "No response from origin server within "+h.WaitTimeout.String(), http.StatusBadGateway)
			return
		}

		ready, err := h.view.EvaluateJavaScript("window.$renderStaticReady")
		if err != nil {
			http.Error(w, "error checking $renderStaticReady: "+err.Error(), http.StatusInternalServerError)
			return
		}
		if ready, _ := ready.(bool); ready {
			break
		}
	}

	result, err := h.view.EvaluateJavaScript("document.documentElement.outerHTML")
	if err != nil {
		h.logf("Failed to dump HTML for page at URL %s: %s", targetURL, err)
		http.Error(w, "", http.StatusInternalServerError)
		return
	}

	html := result.(string)
	if h.RemoveScripts {
		html = strings.Replace(html, "<script", `<script type="text/disabled"`, -1)
	}
	w.Write([]byte(html))
}

func (h *StaticRenderer) logf(msg string, v ...interface{}) {
	if h.Log != nil {
		h.Log.Printf(msg, v...)
	}
}
<|endoftext|>


<commit_before>package goat

import (
	"os"
	"strconv"
)

// Application name
const App = "goat"

// Application version
const Version = "git-master"

// Manager is responsible for coordinating the application
func Manager(killChan chan bool, exitChan chan int) {
	// Set up graceful shutdown channel
	shutdownChan := make(chan bool)
	Static.ShutdownChan = shutdownChan

	// Set up logger
	logChan := make(chan string)
	Static.LogChan = logChan
	go LogManager()

	Static.LogChan <- "Starting " + App + " " + Version

	// Print startup status banner
	go PrintStatusBanner()

	// Load configuration
	config := LoadConfig()
	if config == (Conf{}) {
		Static.LogChan <- "Cannot load configuration, exiting now."
		os.Exit(1)
	}

	// Set up graceful shutdown channels
	httpDoneChan := make(chan bool)
	udpDoneChan := make(chan bool)

	// Launch listeners as configured
	if Static.Config.HTTP {
		go new(HTTPListener).Listen(httpDoneChan)
		Static.LogChan <- "HTTP listener launched on port " + strconv.Itoa(Static.Config.Port)
	}
	if Static.Config.UDP {
		go new(UDPListener).Listen(udpDoneChan)
		Static.LogChan <- "UDP listener launched on port " + strconv.Itoa(Static.Config.Port)
	}

	// Wait for shutdown signal
	for {
		select {
		case <-killChan:
			// Trigger a graceful shutdown
			Static.LogChan <- "triggering graceful shutdown, press Ctrl+C again to force halt"
			Static.ShutdownChan <- true

			// Stop listeners
			if Static.Config.HTTP {
				Static.LogChan <- "stopping HTTP listener"
				//<-httpDoneChan
			}
			if Static.Config.UDP {
				Static.LogChan <- "stopping UDP listener"
				//<-udpDoneChan
			}

			// Report that program should exit gracefully
			exitChan <- 0
		}
	}
}
<commit_msg>Fix error with configuration loading<commit_after>package goat

import (
	"os"
	"strconv"
)

// Application name
const App = "goat"

// Application version
const Version = "git-master"

// Manager is responsible for coordinating the application
func Manager(killChan chan bool, exitChan chan int) {
	// Set up graceful shutdown channel
	shutdownChan := make(chan bool)
	Static.ShutdownChan = shutdownChan

	// Set up logger
	logChan := make(chan string)
	Static.LogChan = logChan
	go LogManager()

	Static.LogChan <- "Starting " + App + " " + Version

	// Print startup status banner
	go PrintStatusBanner()

	// Load configuration
	config := LoadConfig()
	if config == (Conf{}) {
		Static.LogChan <- "Cannot load configuration, exiting now."
		os.Exit(1)
	}
	Static.Config = config

	// Set up graceful shutdown channels
	httpDoneChan := make(chan bool)
	udpDoneChan := make(chan bool)

	// Launch listeners as configured
	if Static.Config.HTTP {
		go new(HTTPListener).Listen(httpDoneChan)
		Static.LogChan <- "HTTP listener launched on port " + strconv.Itoa(Static.Config.Port)
	}
	if Static.Config.UDP {
		go new(UDPListener).Listen(udpDoneChan)
		Static.LogChan <- "UDP listener launched on port " + strconv.Itoa(Static.Config.Port)
	}

	// Wait for shutdown signal
	for {
		select {
		case <-killChan:
			// Trigger a graceful shutdown
			Static.LogChan <- "triggering graceful shutdown, press Ctrl+C again to force halt"
			Static.ShutdownChan <- true

			// Stop listeners
			if Static.Config.HTTP {
				Static.LogChan <- "stopping HTTP listener"
				//<-httpDoneChan
			}
			if Static.Config.UDP {
				Static.LogChan <- "stopping UDP listener"
				//<-udpDoneChan
			}

			// Report that program should exit gracefully
			exitChan <- 0
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"github.com/Redundancy/go-sync/filechecksum"
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/Redundancy/go-sync/blocksources"
	"github.com/Redundancy/go-sync/patcher/sequential"
	"github.com/codegangsta/cli"
)

const USAGE = "gosync patch <localfile> <reference index> <reference source> [<output>]"

func init() {
	app.Commands = append(
		app.Commands,
		cli.Command{
			Name:      "patch",
			ShortName: "p",
			Usage:     USAGE,
			Description: `Recreate the reference source file, using an index and a local file that is believed to be similar.
The index should be produced by "gosync build".

<reference index> is a .gosync file and may be a local, unc network path or http/https url
<reference source> is corresponding target and may be a local, unc network path or http/https url
<output> is optional. If not specified, the local file will be overwritten when done.`,
			Action: Patch,
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "p",
					Value: runtime.NumCPU(),
					Usage: "The number of streams to use concurrently",
				},
			},
		},
	)
}

// Making up a number
const MAX_PATCHING_BLOCK_STORAGE = 40

func Patch(c *cli.Context) {
	fmt.Fprintln(os.Stderr, "Starting patching process")
	var err error = nil

	// handle error cases and exit as the last thing we do
	// don't use os.Exit elsewhere, let defer handlers clean up
	defer func() {
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}()

	if l := len(c.Args()); l < 3 || l > 4 {
		fmt.Fprintf(os.Stderr, "Usage is \"%v\" (invalid number of arguments)", USAGE)
		return
	}

	local_filename := c.Args()[0]
	gosync_arg := c.Args()[1]
	reference_arg := c.Args()[2]

	var local_file_closed bool
	local_file, err := os.Open(local_filename)

	if err != nil {
		err = formatFileError(local_filename, err)
		return
	}

	defer func() {
		if e := local_file.Close(); err == nil && !local_file_closed {
			err = e
		}
	}()

	var out_file *os.File = nil

	out_filename := local_filename
	if len(c.Args()) == 4 {
		out_filename = c.Args()[3]
	}

	fmt.Fprintln(os.Stderr, "Output file is", out_filename)

	use_temp_file := false
	if same, err := is_same_file(out_filename, local_filename); err != nil {
		return
	} else if same {
		use_temp_file = true
	}

	temp_file_name := ""
	if use_temp_file {
		out_file, err = ioutil.TempFile(".", "tmp_")
		temp_file_name = out_file.Name()
		fmt.Printf("Using temporary file: %v\n", temp_file_name)
	} else if _, err := os.Stat(out_filename); os.IsNotExist(err) {
		out_file, err = os.Create(out_filename)
		fmt.Printf("Creating file: %v\n", out_filename)
	} else {
		out_file, err = os.OpenFile(out_filename, os.O_WRONLY, 0)
		fmt.Printf("Using existing file: %v\n", out_filename)
	}

	if err != nil {
		return
	}

	var blocksize uint32
	indexReader, err := getLocalOrRemoteFile(gosync_arg)

	if err != nil {
		err = formatFileError(local_filename, err)
		return
	}

	_, _, _, filesize, blocksize, e := read_headers_and_check(indexReader, magic_string, major_version)

	if e != nil {
		indexReader.Close()
		fmt.Printf("Error loading index: %v", e)
		os.Exit(1)
	}

	index, checksumLookup, err := read_index(indexReader, uint(blocksize))
	indexReader.Close()

	if err != nil {
		return
	}

	fi, err := local_file.Stat()

	if err != nil {
		return
	}

	num_matchers := int64(c.Int("p"))

	local_file_size := fi.Size()

	// Don't split up small files
	if local_file_size < MB {
		num_matchers = 1
	}

	merger, _ := multithreaded_matching(
		local_file,
		index,
		local_file_size,
		num_matchers,
		uint(blocksize),
	)

	mergedBlocks := merger.GetMergedBlocks()
	missing := mergedBlocks.GetMissingBlocks(uint(index.BlockCount) - 1)

	var source *blocksources.BlockSourceBase
	resolver := blocksources.MakeFileSizedBlockResolver(
		uint64(blocksize),
		filesize,
	)

	if strings.HasPrefix(reference_arg, "http://") || strings.HasPrefix(reference_arg, "https://") {
		source = blocksources.NewHttpBlockSource(
			reference_arg,
			4,
			resolver,
			&filechecksum.HashVerifier{
				Hash:                md5.New(),
				BlockSize:           uint(blocksize),
				BlockChecksumGetter: checksumLookup,
			},
		)
	} else {
		f, err := os.Open(reference_arg)

		if err != nil {
			return
		}

		defer f.Close()

		source = blocksources.NewReadSeekerBlockSource(f, resolver)
	}

	if err = sequential.SequentialPatcher(
		local_file,
		source,
		toPatcherMissingSpan(missing, int64(blocksize)),
		toPatcherFoundSpan(mergedBlocks, int64(blocksize)),
		MAX_PATCHING_BLOCK_STORAGE,
		out_file,
	); err != nil {
		err = fmt.Errorf("Error patching to out_file: %v", err)
		return
	}

	//out_file.Close()
	if err = local_file.Close(); err != nil {
		return
	}

	local_file_closed = true

	if use_temp_file {
		// copy to local
		lf, err := os.OpenFile(local_filename, os.O_WRONLY, 0)
		if err != nil {
			return
		}

		defer func() {
			e := lf.Close()
			if err == nil {
				err = e
			}
		}()

		current, _ := out_file.Seek(1, 0)
		out_file.Truncate(current)
		lf.Truncate(current)

		out_file.Seek(0, 0)
		_, err = io.Copy(lf, out_file)

		if err != nil {
			err = fmt.Errorf("Error copying to local file: %v", err)
			return
		}
	}

	if err = out_file.Close(); err != nil {
		err = fmt.Errorf("Error closing out_file: %v", err)
		return
	}

	if use_temp_file {
		os.Remove(temp_file_name)
	}

	fmt.Printf("Downloaded %v bytes\n", source.ReadBytes())
	//fmt.Printf("Total file is %v bytes\n", int64(index.BlockCount)*int64(blocksize))
}
<commit_msg>Changing approach to truncation.<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"github.com/Redundancy/go-sync/filechecksum"
	"io"
	"io/ioutil"
	"os"
	"runtime"
	"strings"

	"github.com/Redundancy/go-sync/blocksources"
	"github.com/Redundancy/go-sync/patcher/sequential"
	"github.com/codegangsta/cli"
)

const USAGE = "gosync patch <localfile> <reference index> <reference source> [<output>]"

func init() {
	app.Commands = append(
		app.Commands,
		cli.Command{
			Name:      "patch",
			ShortName: "p",
			Usage:     USAGE,
			Description: `Recreate the reference source file, using an index and a local file that is believed to be similar.
The index should be produced by "gosync build".

<reference index> is a .gosync file and may be a local, unc network path or http/https url
<reference source> is corresponding target and may be a local, unc network path or http/https url
<output> is optional. If not specified, the local file will be overwritten when done.`,
			Action: Patch,
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "p",
					Value: runtime.NumCPU(),
					Usage: "The number of streams to use concurrently",
				},
			},
		},
	)
}

// Making up a number
const MAX_PATCHING_BLOCK_STORAGE = 40

func Patch(c *cli.Context) {
	fmt.Fprintln(os.Stderr, "Starting patching process")
	var err error = nil

	// handle error cases and exit as the last thing we do
	// don't use os.Exit elsewhere, let defer handlers clean up
	defer func() {
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}()

	if l := len(c.Args()); l < 3 || l > 4 {
		fmt.Fprintf(os.Stderr, "Usage is \"%v\" (invalid number of arguments)", USAGE)
		return
	}

	local_filename := c.Args()[0]
	gosync_arg := c.Args()[1]
	reference_arg := c.Args()[2]

	var local_file_closed bool
	local_file, err := os.Open(local_filename)

	if err != nil {
		err = formatFileError(local_filename, err)
		return
	}

	defer func() {
		if e := local_file.Close(); err == nil && !local_file_closed {
			err = e
		}
	}()

	var out_file *os.File = nil

	out_filename := local_filename
	if len(c.Args()) == 4 {
		out_filename = c.Args()[3]
	}

	fmt.Fprintln(os.Stderr, "Output file is", out_filename)

	use_temp_file := false
	if same, err := is_same_file(out_filename, local_filename); err != nil {
		return
	} else if same {
		use_temp_file = true
	}

	temp_file_name := ""
	if use_temp_file {
		out_file, err = ioutil.TempFile(".", "tmp_")
		temp_file_name = out_file.Name()
		fmt.Printf("Using temporary file: %v\n", temp_file_name)
	} else if _, err := os.Stat(out_filename); os.IsNotExist(err) {
		out_file, err = os.Create(out_filename)
		fmt.Printf("Creating file: %v\n", out_filename)
	} else {
		out_file, err = os.OpenFile(out_filename, os.O_WRONLY, 0)
		fmt.Printf("Using existing file: %v\n", out_filename)
	}

	if err != nil {
		return
	}

	var blocksize uint32
	indexReader, err := getLocalOrRemoteFile(gosync_arg)

	if err != nil {
		err = formatFileError(local_filename, err)
		return
	}

	_, _, _, filesize, blocksize, e := read_headers_and_check(indexReader, magic_string, major_version)

	if e != nil {
		indexReader.Close()
		fmt.Printf("Error loading index: %v", e)
		os.Exit(1)
	}

	index, checksumLookup, err := read_index(indexReader, uint(blocksize))
	indexReader.Close()

	if err != nil {
		return
	}

	fi, err := local_file.Stat()

	if err != nil {
		return
	}

	num_matchers := int64(c.Int("p"))

	local_file_size := fi.Size()

	// Don't split up small files
	if local_file_size < MB {
		num_matchers = 1
	}

	merger, _ := multithreaded_matching(
		local_file,
		index,
		local_file_size,
		num_matchers,
		uint(blocksize),
	)

	mergedBlocks := merger.GetMergedBlocks()
	missing := mergedBlocks.GetMissingBlocks(uint(index.BlockCount) - 1)

	var source *blocksources.BlockSourceBase
	resolver := blocksources.MakeFileSizedBlockResolver(
		uint64(blocksize),
		filesize,
	)

	if strings.HasPrefix(reference_arg, "http://") || strings.HasPrefix(reference_arg, "https://") {
		source = blocksources.NewHttpBlockSource(
			reference_arg,
			4,
			resolver,
			&filechecksum.HashVerifier{
				Hash:                md5.New(),
				BlockSize:           uint(blocksize),
				BlockChecksumGetter: checksumLookup,
			},
		)
	} else {
		f, err := os.Open(reference_arg)

		if err != nil {
			return
		}

		defer f.Close()

		source = blocksources.NewReadSeekerBlockSource(f, resolver)
	}

	if err = sequential.SequentialPatcher(
		local_file,
		source,
		toPatcherMissingSpan(missing, int64(blocksize)),
		toPatcherFoundSpan(mergedBlocks, int64(blocksize)),
		MAX_PATCHING_BLOCK_STORAGE,
		out_file,
	); err != nil {
		err = fmt.Errorf("Error patching to out_file: %v", err)
		return
	}

	//out_file.Close()
	if err = local_file.Close(); err != nil {
		return
	}

	local_file_closed = true

	if use_temp_file {
		// copy to local
		lf, err := os.OpenFile(local_filename, os.O_WRONLY, 0)
		if err != nil {
			return
		}

		defer func() {
			e := lf.Close()
			if err == nil {
				err = e
			}
		}()

		out_file.Seek(0, 0)
		_, err = io.Copy(lf, out_file)
		lf.Truncate(filesize)

		if err != nil {
			err = fmt.Errorf("Error copying to local file: %v", err)
			return
		}
	}

	if err = out_file.Close(); err != nil {
		err = fmt.Errorf("Error closing out_file: %v", err)
		return
	}

	if use_temp_file {
		os.Remove(temp_file_name)
	}

	fmt.Printf("Downloaded %v bytes\n", source.ReadBytes())
	//fmt.Printf("Total file is %v bytes\n", int64(index.BlockCount)*int64(blocksize))
}
<|endoftext|>


<commit_before>// Copyright 2011 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"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "github.com/danvargas/go-tour-br/pic"
	_ "github.com/danvargas/go-tour-br/tree"
	_ "github.com/danvargas/go-tour-br/wc"
)

const basePkg = "github.com/danvargas/go-tour-br/"

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")
)

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

	// find and serve the go tour files
	p, err := build.Default.Import(basePkg, "", build.FindOnly)
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}
	root := p.Dir
	log.Println("Serving content from", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.Handle("/talks/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Open your web browser and visit http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	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) {
	stopRun()

	// 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 := []byte(req.FormValue("body"))
	defer os.Remove(src)
	if err = ioutil.WriteFile(src, body, 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)
}

// 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

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("already running %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<commit_msg>revisão para pt_BR<commit_after>// Copyright 2011 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"
	"go/build"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"sync"

	// Imports so that goinstall automatically installs them.
	_ "github.com/danvargas/go-tour-br/pic"
	_ "github.com/danvargas/go-tour-br/tree"
	_ "github.com/danvargas/go-tour-br/wc"
)

const basePkg = "github.com/danvargas/go-tour-br/"

var (
	httpListen = flag.String("http", "127.0.0.1:3999", "para ouvir em host:port")
	htmlOutput = flag.Bool("html", false, "processar a saída do programa como HTML")
)

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

	// find and serve the go tour files
	p, err := build.Default.Import(basePkg, "", build.FindOnly)
	if err != nil {
		log.Fatalf("Não foi possível encontrar os arquivos do passeio: %v", err)
	}
	root := p.Dir
	log.Println("Servindo conteúdo de ", root)
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/" {
			fn := filepath.Join(root, "static", r.URL.Path[1:])
			http.ServeFile(w, r, fn)
			return
		}
		http.Error(w, "not found", 404)
	})
	http.Handle("/static/", http.FileServer(http.Dir(root)))
	http.Handle("/talks/", http.FileServer(http.Dir(root)))
	http.HandleFunc("/kill", kill)

	if !strings.HasPrefix(*httpListen, "127.0.0.1") &&
		!strings.HasPrefix(*httpListen, "localhost") {
		log.Print(localhostWarning)
	}

	log.Printf("Abra seu navegador web e visite http://%s/", *httpListen)
	log.Fatal(http.ListenAndServe(*httpListen, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

var running struct {
	sync.Mutex
	cmd *exec.Cmd
}

func stopRun() {
	running.Lock()
	if running.cmd != nil {
		running.cmd.Process.Kill()
		running.cmd = nil
	}
	running.Unlock()
}

func kill(w http.ResponseWriter, r *http.Request) {
	stopRun()
}

var (
	commentRe = regexp.MustCompile(`(?m)^#.*\n`)
	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) {
	stopRun()

	// 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 := []byte(req.FormValue("body"))
	defer os.Remove(src)
	if err = ioutil.WriteFile(src, body, 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)
}

// 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

	// Start command and leave in 'running'.
	running.Lock()
	if running.cmd != nil {
		defer running.Unlock()
		return nil, fmt.Errorf("já está rodando %s", running.cmd.Path)
	}
	if err := cmd.Start(); err != nil {
		running.Unlock()
		return nil, err
	}
	running.cmd = cmd
	running.Unlock()

	// Wait for the command.  Clean up,
	err := cmd.Wait()
	running.Lock()
	if running.cmd == cmd {
		running.cmd = nil
	}
	running.Unlock()
	return buf.Bytes(), err
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, 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.
*/

package vm

import (
	"flag"
	"fmt"
	"io"
	"os"
	"text/tabwriter"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

type info struct {
	*flags.ClientFlag
	*flags.OutputFlag
	*flags.SearchFlag

	WaitForIP bool
}

func init() {
	i := info{
		SearchFlag: flags.NewSearchFlag(flags.SearchVirtualMachines),
	}

	cli.Register(&i)
}

func (c *info) Register(f *flag.FlagSet) {
	f.BoolVar(&c.WaitForIP, "waitip", false, "Wait for VM to acquire IP address")
}

func (c *info) Process() error { return nil }

func (c *info) Run(f *flag.FlagSet) error {
	client, err := c.Client()
	if err != nil {
		return err
	}

	vm, err := c.VirtualMachine()
	if err != nil {
		return err
	}

	var res infoResult
	var props []string

	if c.OutputFlag.JSON {
		props = nil // Load everything
	} else {
		props = []string{"summary", "guest"} // Load summary
	}

	for {
		err = client.Properties(vm.Reference(), props, &res.VirtualMachine)
		if err != nil {
			return err
		}

		if res.VirtualMachine.Guest.IpAddress == "" {
			err = WaitForIP(vm, client)
			if err != nil {
				return err
			}

			// Reload virtual machine object
			continue
		}

		break
	}

	return c.WriteResult(&res)
}

type infoResult struct {
	VirtualMachine mo.VirtualMachine
}

func (r *infoResult) WriteTo(w io.Writer) error {
	s := r.VirtualMachine.Summary

	tw := tabwriter.NewWriter(os.Stderr, 2, 0, 2, ' ', 0)
	fmt.Fprintf(tw, "Name:\t%s\n", s.Config.Name)
	fmt.Fprintf(tw, "UUID:\t%s\n", s.Config.Uuid)
	fmt.Fprintf(tw, "Guest name:\t%s\n", s.Config.GuestFullName)
	fmt.Fprintf(tw, "Memory:\t%dMB\n", s.Config.MemorySizeMB)
	fmt.Fprintf(tw, "CPU:\t%d vCPU(s)\n", s.Config.NumCpu)
	fmt.Fprintf(tw, "Power state:\t%s\n", s.Runtime.PowerState)
	fmt.Fprintf(tw, "Boot time:\t%s\n", s.Runtime.BootTime)
	fmt.Fprintf(tw, "IP address:\t%s\n", s.Guest.IpAddress)
	return tw.Flush()
}

func WaitForIP(vm *govmomi.VirtualMachine, c *govmomi.Client) error {
	p, err := c.NewPropertyCollector()
	if err != nil {
		return err
	}

	defer p.Destroy()

	req := types.CreateFilter{
		Spec: types.PropertyFilterSpec{
			ObjectSet: []types.ObjectSpec{
				{
					Obj: vm.Reference(),
				},
			},
			PropSet: []types.PropertySpec{
				{
					PathSet: []string{"guest"},
					Type:    "VirtualMachine",
				},
			},
		},
	}

	err = p.CreateFilter(req)
	if err != nil {
		return err
	}

	for version := ""; ; {
		var gi *types.GuestInfo

		res, err := p.WaitForUpdates(version)
		if err != nil {
			return err
		}

		version = res.Version

		for _, fs := range res.FilterSet {
			for _, os := range fs.ObjectSet {
				if os.Obj == vm.Reference() {
					for _, c := range os.ChangeSet {
						if c.Name == "guest" {
							giv := c.Val.(types.GuestInfo)
							gi = &giv
						}
					}
				}
			}
		}

		if gi == nil {
			panic("expected GuestInfo update")
		}

		if gi.IpAddress != "" {
			return nil
		}
	}
}
<commit_msg>Only care about guest.ipAddress property for -waitip<commit_after>/*
Copyright (c) 2014 VMware, 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.
*/

package vm

import (
	"flag"
	"fmt"
	"io"
	"os"
	"text/tabwriter"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25/mo"
	"github.com/vmware/govmomi/vim25/types"
)

type info struct {
	*flags.ClientFlag
	*flags.OutputFlag
	*flags.SearchFlag

	WaitForIP bool
}

func init() {
	i := info{
		SearchFlag: flags.NewSearchFlag(flags.SearchVirtualMachines),
	}

	cli.Register(&i)
}

func (c *info) Register(f *flag.FlagSet) {
	f.BoolVar(&c.WaitForIP, "waitip", false, "Wait for VM to acquire IP address")
}

func (c *info) Process() error { return nil }

func (c *info) Run(f *flag.FlagSet) error {
	client, err := c.Client()
	if err != nil {
		return err
	}

	vm, err := c.VirtualMachine()
	if err != nil {
		return err
	}

	var res infoResult
	var props []string

	if c.OutputFlag.JSON {
		props = nil // Load everything
	} else {
		props = []string{"summary", "guest"} // Load summary
	}

	for {
		err = client.Properties(vm.Reference(), props, &res.VirtualMachine)
		if err != nil {
			return err
		}

		if res.VirtualMachine.Guest.IpAddress == "" {
			err = WaitForIP(vm, client)
			if err != nil {
				return err
			}

			// Reload virtual machine object
			continue
		}

		break
	}

	return c.WriteResult(&res)
}

type infoResult struct {
	VirtualMachine mo.VirtualMachine
}

func (r *infoResult) WriteTo(w io.Writer) error {
	s := r.VirtualMachine.Summary

	tw := tabwriter.NewWriter(os.Stderr, 2, 0, 2, ' ', 0)
	fmt.Fprintf(tw, "Name:\t%s\n", s.Config.Name)
	fmt.Fprintf(tw, "UUID:\t%s\n", s.Config.Uuid)
	fmt.Fprintf(tw, "Guest name:\t%s\n", s.Config.GuestFullName)
	fmt.Fprintf(tw, "Memory:\t%dMB\n", s.Config.MemorySizeMB)
	fmt.Fprintf(tw, "CPU:\t%d vCPU(s)\n", s.Config.NumCpu)
	fmt.Fprintf(tw, "Power state:\t%s\n", s.Runtime.PowerState)
	fmt.Fprintf(tw, "Boot time:\t%s\n", s.Runtime.BootTime)
	fmt.Fprintf(tw, "IP address:\t%s\n", s.Guest.IpAddress)
	return tw.Flush()
}

func WaitForIP(vm *govmomi.VirtualMachine, c *govmomi.Client) error {
	p, err := c.NewPropertyCollector()
	if err != nil {
		return err
	}

	defer p.Destroy()

	req := types.CreateFilter{
		Spec: types.PropertyFilterSpec{
			ObjectSet: []types.ObjectSpec{
				{
					Obj: vm.Reference(),
				},
			},
			PropSet: []types.PropertySpec{
				{
					PathSet: []string{"guest.ipAddress"},
					Type:    "VirtualMachine",
				},
			},
		},
	}

	err = p.CreateFilter(req)
	if err != nil {
		return err
	}

	for version := ""; ; {
		var prop *types.PropertyChange

		res, err := p.WaitForUpdates(version)
		if err != nil {
			return err
		}

		version = res.Version

		for _, fs := range res.FilterSet {
			for _, os := range fs.ObjectSet {
				if os.Obj == vm.Reference() {
					for _, c := range os.ChangeSet {
						if c.Name != "guest.ipAddress" {
							continue
						}

						if c.Op != types.PropertyChangeOpAssign {
							continue
						}

						prop = &c
						break
					}
				}
			}
		}

		if prop == nil {
			panic("expected to receive property change")
		}

		if prop.Val != nil {
			return nil
		}
	}
}
<|endoftext|>


<commit_before>package paranoidhttp

import (
	"net"
	"testing"
)

func TestRequest(t *testing.T) {
	resp, err := DefaultClient.Get("http://www.example.org")
	if err != nil && resp.StatusCode == 200 {
		t.Error("The request with an ordinal url should be successful")
	}

	resp, err = DefaultClient.Get("http://localhost")
	if err == nil {
		t.Errorf("The request for localhost should be fail")
	}
}

func TestIsHostForbidden(t *testing.T) {
	badHosts := []string{
		"localhost",
		"host has space",
	}

	for _, h := range badHosts {
		if !basicConfig().isHostForbidden(h) {
			t.Errorf("%s should be forbidden", h)
		}
	}

	notBadHosts := []string{
		"www.hatena.ne.jp",
		"www.google.com",
		"xn--t8jx73hngb.jp",
	}

	for _, h := range notBadHosts {
		if basicConfig().isHostForbidden(h) {
			t.Errorf("%s should not be forbidden", h)
		}
	}
}

func TestIsIpForbidden(t *testing.T) {
	badIPs := []string{
		"0.0.0.0",                      // Unspecified
		"127.0.0.0", "127.255.255.255", // Loopback
		"10.0.0.0", "10.255.255.255", // Private A
		"172.16.0.0", "172.31.255.255", // Private B
		"192.168.0.0", "192.168.255.255", // Private C
		"192.0.2.0", "192.0.2.255", // Test-Net
		"192.88.99.0", "192.88.99.255", // 6to4 relay
		"224.0.0.0", "239.255.255.255", // Multicast
		"169.254.0.0", "169.254.255.255", // Link local
	}

	for _, ip := range badIPs {
		if !basicConfig().isIPForbidden(net.ParseIP(ip)) {
			t.Errorf("%s should be forbidden", ip)
		}
	}

	notBadIPs := []string{
		"0.0.0.1", "8.8.8.8",
		"126.255.255.255", "128.0.0.0",
		"9.255.255.255", "11.0.0.0",
		"172.15.255.255", "172.32.0.0",
		"192.167.255.255", "192.169.0.0",
		"192.88.98.255", "192.88.100.0",
		"223.255.255.255", "240.0.0.0",
		"169.253.255.255", "169.255.0.0",
	}

	for _, ip := range notBadIPs {
		if basicConfig().isIPForbidden(net.ParseIP(ip)) {
			t.Errorf("%s should not be forbidden", ip)
		}
	}

	c := basicConfig()
	ip := "172.18.0.1"
	if !c.isIPForbidden(net.ParseIP(ip)) {
		t.Errorf("%s should be forbidden", ip)
	}

	c.PermittedIPNets = append(c.PermittedIPNets, mustParseCIDR("172.18.0.1/32"))
	if c.isIPForbidden(net.ParseIP(ip)) {
		t.Errorf("%s should not be forbidden", ip)
	}
}
<commit_msg>enhance testing<commit_after>package paranoidhttp

import (
	"net"
	"testing"
)

func TestRequest(t *testing.T) {
	resp, err := DefaultClient.Get("http://www.example.org")
	if err != nil && resp.StatusCode == 200 {
		t.Error("The request with an ordinal url should be successful")
	}

	resp, err = DefaultClient.Get("http://localhost")
	if err == nil {
		t.Errorf("The request for localhost should be fail")
	}

	if _, err := DefaultClient.Get("http://192.168.0.1"); err == nil {
		t.Errorf("The request for localhost should be fail")
	}
}

func TestIsHostForbidden(t *testing.T) {
	badHosts := []string{
		"localhost",
		"host has space",
	}

	for _, h := range badHosts {
		if !basicConfig().isHostForbidden(h) {
			t.Errorf("%s should be forbidden", h)
		}
	}

	notBadHosts := []string{
		"www.hatena.ne.jp",
		"www.google.com",
		"xn--t8jx73hngb.jp",
	}

	for _, h := range notBadHosts {
		if basicConfig().isHostForbidden(h) {
			t.Errorf("%s should not be forbidden", h)
		}
	}
}

func TestIsIpForbidden(t *testing.T) {
	badIPs := []string{
		"0.0.0.0",                      // Unspecified
		"127.0.0.0", "127.255.255.255", // Loopback
		"10.0.0.0", "10.255.255.255", // Private A
		"172.16.0.0", "172.31.255.255", // Private B
		"192.168.0.0", "192.168.255.255", // Private C
		"192.0.2.0", "192.0.2.255", // Test-Net
		"192.88.99.0", "192.88.99.255", // 6to4 relay
		"224.0.0.0", "239.255.255.255", // Multicast
		"169.254.0.0", "169.254.255.255", // Link local
	}

	for _, ip := range badIPs {
		if !basicConfig().isIPForbidden(net.ParseIP(ip)) {
			t.Errorf("%s should be forbidden", ip)
		}
	}

	notBadIPs := []string{
		"0.0.0.1", "8.8.8.8",
		"126.255.255.255", "128.0.0.0",
		"9.255.255.255", "11.0.0.0",
		"172.15.255.255", "172.32.0.0",
		"192.167.255.255", "192.169.0.0",
		"192.88.98.255", "192.88.100.0",
		"223.255.255.255", "240.0.0.0",
		"169.253.255.255", "169.255.0.0",
	}

	for _, ip := range notBadIPs {
		if basicConfig().isIPForbidden(net.ParseIP(ip)) {
			t.Errorf("%s should not be forbidden", ip)
		}
	}

	c := basicConfig()
	ip := "172.18.0.1"
	if !c.isIPForbidden(net.ParseIP(ip)) {
		t.Errorf("%s should be forbidden", ip)
	}

	c.PermittedIPNets = append(c.PermittedIPNets, mustParseCIDR("172.18.0.1/32"))
	if c.isIPForbidden(net.ParseIP(ip)) {
		t.Errorf("%s should not be forbidden", ip)
	}
}
<|endoftext|>


<commit_before>package quic

import (
	"bytes"
	"encoding/binary"
	"errors"
	"net"
	"reflect"
	"runtime"
	"time"
	"unsafe"

	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Client", func() {
	var (
		cl                              *client
		config                          *Config
		sess                            *mockSession
		packetConn                      *mockPacketConn
		addr                            net.Addr
		versionNegotiateConnStateCalled bool
	)

	BeforeEach(func() {
		versionNegotiateConnStateCalled = false
		packetConn = &mockPacketConn{}
		config = &Config{
			ConnState: func(_ Session, state ConnState) {
				if state == ConnStateVersionNegotiated {
					versionNegotiateConnStateCalled = true
				}
			},
		}
		addr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337}
		sess = &mockSession{connectionID: 0x1337}
		cl = &client{
			config:       config,
			connectionID: 0x1337,
			session:      sess,
			version:      protocol.Version36,
			conn:         &conn{pconn: packetConn, currentAddr: addr},
		}
	})

	Context("Dialing", func() {
		It("creates a new client", func() {
			packetConn.dataToRead = []byte{0x0, 0x1, 0x0}
			var err error
			sess, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).ToNot(HaveOccurred())
			Expect(*(*[]protocol.VersionNumber)(unsafe.Pointer(reflect.ValueOf(sess.(*session).cryptoSetup).Elem().FieldByName("negotiatedVersions").UnsafeAddr()))).To(BeNil())
			Expect(*(*string)(unsafe.Pointer(reflect.ValueOf(sess.(*session).cryptoSetup).Elem().FieldByName("hostname").UnsafeAddr()))).To(Equal("quic.clemente.io"))
		})

		It("errors when receiving an invalid first packet from the server", func() {
			packetConn.dataToRead = []byte{0xff}
			sess, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).To(HaveOccurred())
			Expect(sess).To(BeNil())
		})

		It("errors when receiving an error from the connection", func() {
			testErr := errors.New("connection error")
			packetConn.readErr = testErr
			_, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).To(MatchError(testErr))
		})

		// now we're only testing that Dial doesn't return directly after version negotiation
		It("doesn't return after version negotiation is established if no ConnState is defined", func() {
			packetConn.dataToRead = []byte{0x0, 0x1, 0x0}
			config.ConnState = nil
			var dialReturned bool
			go func() {
				defer GinkgoRecover()
				_, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
				Expect(err).ToNot(HaveOccurred())
				dialReturned = true
			}()
			Consistently(func() bool { return dialReturned }).Should(BeFalse())
		})

		It("only establishes a connection once it is forward-secure if no ConnState is defined", func() {
			config.ConnState = nil
			client := &client{conn: &conn{pconn: packetConn, currentAddr: addr}, config: config}
			client.connStateChangeOrErrCond.L = &client.mutex
			var returned bool
			go func() {
				defer GinkgoRecover()
				_, err := client.establishConnection()
				Expect(err).ToNot(HaveOccurred())
				returned = true
			}()
			Consistently(func() bool { return returned }).Should(BeFalse())
			// switch to a secure connection
			client.cryptoChangeCallback(nil, false)
			Consistently(func() bool { return returned }).Should(BeFalse())
			// switch to a forward-secure connection
			client.cryptoChangeCallback(nil, true)
			Eventually(func() bool { return returned }).Should(BeFalse())
		})
	})

	It("errors on invalid public header", func() {
		err := cl.handlePacket(nil, nil)
		Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidPacketHeader))
	})

	It("errors on large packets", func() {
		err := cl.handlePacket(nil, bytes.Repeat([]byte{'a'}, int(protocol.MaxPacketSize)+1))
		Expect(err).To(MatchError(qerr.PacketTooLarge))
	})

	// this test requires a real session (because it calls the close callback) and a real UDP conn (because it unblocks and errors when it is closed)
	It("properly closes", func(done Done) {
		udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
		Expect(err).ToNot(HaveOccurred())
		cl.conn = &conn{pconn: udpConn}
		err = cl.createNewSession(nil)
		testErr := errors.New("test error")
		time.Sleep(10 * time.Millisecond) // Wait for old goroutines to finish
		numGoRoutines := runtime.NumGoroutine()

		var stoppedListening bool
		go func() {
			cl.listen()
			stoppedListening = true
		}()

		err = cl.session.Close(testErr)
		Expect(err).ToNot(HaveOccurred())
		Eventually(func() bool { return stoppedListening }).Should(BeTrue())
		Eventually(runtime.NumGoroutine()).Should(Equal(numGoRoutines))
		close(done)
	}, 10)

	It("creates new sessions with the right parameters", func() {
		cl.session = nil
		cl.hostname = "hostname"
		err := cl.createNewSession(nil)
		Expect(err).ToNot(HaveOccurred())
		Expect(cl.session).ToNot(BeNil())
		Expect(cl.session.(*session).connectionID).To(Equal(cl.connectionID))
		Expect(cl.session.(*session).version).To(Equal(cl.version))
	})

	Context("handling packets", func() {
		It("errors on too large packets", func() {
			err := cl.handlePacket(nil, bytes.Repeat([]byte{'f'}, int(protocol.MaxPacketSize+1)))
			Expect(err).To(MatchError(qerr.PacketTooLarge))
		})

		It("handles packets", func() {
			ph := PublicHeader{
				PacketNumber:    1,
				PacketNumberLen: protocol.PacketNumberLen2,
				ConnectionID:    0x1337,
			}
			b := &bytes.Buffer{}
			err := ph.Write(b, protocol.Version36, protocol.PerspectiveServer)
			Expect(err).ToNot(HaveOccurred())
			packetConn.dataToRead = b.Bytes()

			Expect(sess.packetCount).To(BeZero())
			var stoppedListening bool
			go func() {
				cl.listen()
				// it should continue listening when receiving valid packets
				stoppedListening = true
			}()

			Eventually(func() int { return sess.packetCount }).Should(Equal(1))
			Expect(sess.closed).To(BeFalse())
			Consistently(func() bool { return stoppedListening }).Should(BeFalse())
		})

		It("closes the session when encountering an error while handling a packet", func() {
			Expect(sess.closeReason).ToNot(HaveOccurred())
			packetConn.dataToRead = bytes.Repeat([]byte{0xff}, 100)
			cl.listen()
			Expect(sess.closed).To(BeTrue())
			Expect(sess.closeReason).To(HaveOccurred())
		})

		It("closes the session when encountering an error while reading from the connection", func() {
			testErr := errors.New("test error")
			packetConn.readErr = testErr
			cl.listen()
			Expect(sess.closed).To(BeTrue())
			Expect(sess.closeReason).To(MatchError(testErr))
		})
	})

	Context("version negotiation", func() {
		getVersionNegotiation := func(versions []protocol.VersionNumber) []byte {
			oldVersionNegotiationPacket := composeVersionNegotiation(0x1337)
			oldSupportVersionTags := protocol.SupportedVersionsAsTags
			var b bytes.Buffer
			for _, v := range versions {
				s := make([]byte, 4)
				binary.LittleEndian.PutUint32(s, protocol.VersionNumberToTag(v))
				b.Write(s)
			}
			protocol.SupportedVersionsAsTags = b.Bytes()
			packet := composeVersionNegotiation(cl.connectionID)
			protocol.SupportedVersionsAsTags = oldSupportVersionTags
			Expect(composeVersionNegotiation(0x1337)).To(Equal(oldVersionNegotiationPacket))
			return packet
		}

		It("recognizes that a packet without VersionFlag means that the server accepted the suggested version", func() {
			ph := PublicHeader{
				PacketNumber:    1,
				PacketNumberLen: protocol.PacketNumberLen2,
				ConnectionID:    0x1337,
			}
			b := &bytes.Buffer{}
			err := ph.Write(b, protocol.VersionWhatever, protocol.PerspectiveServer)
			Expect(err).ToNot(HaveOccurred())
			err = cl.handlePacket(nil, b.Bytes())
			Expect(err).ToNot(HaveOccurred())
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Eventually(func() bool { return versionNegotiateConnStateCalled }).Should(BeTrue())
		})

		It("changes the version after receiving a version negotiation packet", func() {
			newVersion := protocol.Version35
			Expect(newVersion).ToNot(Equal(cl.version))
			Expect(sess.packetCount).To(BeZero())
			cl.connectionID = 0x1337
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{newVersion}))
			Expect(cl.version).To(Equal(newVersion))
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Eventually(func() bool { return versionNegotiateConnStateCalled }).Should(BeTrue())
			// it swapped the sessions
			Expect(cl.session).ToNot(Equal(sess))
			Expect(cl.connectionID).ToNot(Equal(0x1337)) // it generated a new connection ID
			Expect(err).ToNot(HaveOccurred())
			// it didn't pass the version negoation packet to the session (since it has no payload)
			Expect(sess.packetCount).To(BeZero())
			Expect(*(*[]protocol.VersionNumber)(unsafe.Pointer(reflect.ValueOf(cl.session.(*session).cryptoSetup).Elem().FieldByName("negotiatedVersions").UnsafeAddr()))).To(Equal([]protocol.VersionNumber{35}))
		})

		It("errors if no matching version is found", func() {
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{1}))
			Expect(err).To(MatchError(qerr.InvalidVersion))
		})

		It("ignores delayed version negotiation packets", func() {
			// if the version was not yet negotiated, handlePacket would return a VersionNegotiationMismatch error, see above test
			cl.connState = ConnStateVersionNegotiated
			Expect(sess.packetCount).To(BeZero())
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{1}))
			Expect(err).ToNot(HaveOccurred())
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Expect(sess.packetCount).To(BeZero())
			Consistently(func() bool { return versionNegotiateConnStateCalled }).Should(BeFalse())
		})

		It("errors if the server should have accepted the offered version", func() {
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{cl.version}))
			Expect(err).To(MatchError(qerr.Error(qerr.InvalidVersionNegotiationPacket, "Server already supports client's version and should have accepted the connection.")))
		})
	})
})
<commit_msg>fix flaky client test<commit_after>package quic

import (
	"bytes"
	"encoding/binary"
	"errors"
	"net"
	"reflect"
	"runtime"
	"time"
	"unsafe"

	"github.com/lucas-clemente/quic-go/protocol"
	"github.com/lucas-clemente/quic-go/qerr"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Client", func() {
	var (
		cl                              *client
		config                          *Config
		sess                            *mockSession
		packetConn                      *mockPacketConn
		addr                            net.Addr
		versionNegotiateConnStateCalled bool
	)

	BeforeEach(func() {
		versionNegotiateConnStateCalled = false
		packetConn = &mockPacketConn{}
		config = &Config{
			ConnState: func(_ Session, state ConnState) {
				if state == ConnStateVersionNegotiated {
					versionNegotiateConnStateCalled = true
				}
			},
		}
		addr = &net.UDPAddr{IP: net.IPv4(192, 168, 100, 200), Port: 1337}
		sess = &mockSession{connectionID: 0x1337}
		cl = &client{
			config:       config,
			connectionID: 0x1337,
			session:      sess,
			version:      protocol.Version36,
			conn:         &conn{pconn: packetConn, currentAddr: addr},
		}
	})

	Context("Dialing", func() {
		It("creates a new client", func() {
			packetConn.dataToRead = []byte{0x0, 0x1, 0x0}
			var err error
			sess, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).ToNot(HaveOccurred())
			Expect(*(*[]protocol.VersionNumber)(unsafe.Pointer(reflect.ValueOf(sess.(*session).cryptoSetup).Elem().FieldByName("negotiatedVersions").UnsafeAddr()))).To(BeNil())
			Expect(*(*string)(unsafe.Pointer(reflect.ValueOf(sess.(*session).cryptoSetup).Elem().FieldByName("hostname").UnsafeAddr()))).To(Equal("quic.clemente.io"))
		})

		It("errors when receiving an invalid first packet from the server", func() {
			packetConn.dataToRead = []byte{0xff}
			sess, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).To(HaveOccurred())
			Expect(sess).To(BeNil())
		})

		It("errors when receiving an error from the connection", func() {
			testErr := errors.New("connection error")
			packetConn.readErr = testErr
			_, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
			Expect(err).To(MatchError(testErr))
		})

		// now we're only testing that Dial doesn't return directly after version negotiation
		It("doesn't return after version negotiation is established if no ConnState is defined", func() {
			packetConn.dataToRead = []byte{0x0, 0x1, 0x0}
			config.ConnState = nil
			var dialReturned bool
			go func() {
				defer GinkgoRecover()
				_, err := Dial(packetConn, addr, "quic.clemente.io:1337", config)
				Expect(err).ToNot(HaveOccurred())
				dialReturned = true
			}()
			Consistently(func() bool { return dialReturned }).Should(BeFalse())
		})

		It("only establishes a connection once it is forward-secure if no ConnState is defined", func() {
			config.ConnState = nil
			client := &client{conn: &conn{pconn: packetConn, currentAddr: addr}, config: config}
			client.connStateChangeOrErrCond.L = &client.mutex
			var returned bool
			go func() {
				defer GinkgoRecover()
				_, err := client.establishConnection()
				Expect(err).ToNot(HaveOccurred())
				returned = true
			}()
			Consistently(func() bool { return returned }).Should(BeFalse())
			// switch to a secure connection
			client.cryptoChangeCallback(nil, false)
			Consistently(func() bool { return returned }).Should(BeFalse())
			// switch to a forward-secure connection
			client.cryptoChangeCallback(nil, true)
			Eventually(func() bool { return returned }).Should(BeTrue())
		})
	})

	It("errors on invalid public header", func() {
		err := cl.handlePacket(nil, nil)
		Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(qerr.InvalidPacketHeader))
	})

	It("errors on large packets", func() {
		err := cl.handlePacket(nil, bytes.Repeat([]byte{'a'}, int(protocol.MaxPacketSize)+1))
		Expect(err).To(MatchError(qerr.PacketTooLarge))
	})

	// this test requires a real session (because it calls the close callback) and a real UDP conn (because it unblocks and errors when it is closed)
	It("properly closes", func(done Done) {
		udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
		Expect(err).ToNot(HaveOccurred())
		cl.conn = &conn{pconn: udpConn}
		err = cl.createNewSession(nil)
		testErr := errors.New("test error")
		time.Sleep(10 * time.Millisecond) // Wait for old goroutines to finish
		numGoRoutines := runtime.NumGoroutine()

		var stoppedListening bool
		go func() {
			cl.listen()
			stoppedListening = true
		}()

		err = cl.session.Close(testErr)
		Expect(err).ToNot(HaveOccurred())
		Eventually(func() bool { return stoppedListening }).Should(BeTrue())
		Eventually(runtime.NumGoroutine()).Should(Equal(numGoRoutines))
		close(done)
	}, 10)

	It("creates new sessions with the right parameters", func() {
		cl.session = nil
		cl.hostname = "hostname"
		err := cl.createNewSession(nil)
		Expect(err).ToNot(HaveOccurred())
		Expect(cl.session).ToNot(BeNil())
		Expect(cl.session.(*session).connectionID).To(Equal(cl.connectionID))
		Expect(cl.session.(*session).version).To(Equal(cl.version))
	})

	Context("handling packets", func() {
		It("errors on too large packets", func() {
			err := cl.handlePacket(nil, bytes.Repeat([]byte{'f'}, int(protocol.MaxPacketSize+1)))
			Expect(err).To(MatchError(qerr.PacketTooLarge))
		})

		It("handles packets", func() {
			ph := PublicHeader{
				PacketNumber:    1,
				PacketNumberLen: protocol.PacketNumberLen2,
				ConnectionID:    0x1337,
			}
			b := &bytes.Buffer{}
			err := ph.Write(b, protocol.Version36, protocol.PerspectiveServer)
			Expect(err).ToNot(HaveOccurred())
			packetConn.dataToRead = b.Bytes()

			Expect(sess.packetCount).To(BeZero())
			var stoppedListening bool
			go func() {
				cl.listen()
				// it should continue listening when receiving valid packets
				stoppedListening = true
			}()

			Eventually(func() int { return sess.packetCount }).Should(Equal(1))
			Expect(sess.closed).To(BeFalse())
			Consistently(func() bool { return stoppedListening }).Should(BeFalse())
		})

		It("closes the session when encountering an error while handling a packet", func() {
			Expect(sess.closeReason).ToNot(HaveOccurred())
			packetConn.dataToRead = bytes.Repeat([]byte{0xff}, 100)
			cl.listen()
			Expect(sess.closed).To(BeTrue())
			Expect(sess.closeReason).To(HaveOccurred())
		})

		It("closes the session when encountering an error while reading from the connection", func() {
			testErr := errors.New("test error")
			packetConn.readErr = testErr
			cl.listen()
			Expect(sess.closed).To(BeTrue())
			Expect(sess.closeReason).To(MatchError(testErr))
		})
	})

	Context("version negotiation", func() {
		getVersionNegotiation := func(versions []protocol.VersionNumber) []byte {
			oldVersionNegotiationPacket := composeVersionNegotiation(0x1337)
			oldSupportVersionTags := protocol.SupportedVersionsAsTags
			var b bytes.Buffer
			for _, v := range versions {
				s := make([]byte, 4)
				binary.LittleEndian.PutUint32(s, protocol.VersionNumberToTag(v))
				b.Write(s)
			}
			protocol.SupportedVersionsAsTags = b.Bytes()
			packet := composeVersionNegotiation(cl.connectionID)
			protocol.SupportedVersionsAsTags = oldSupportVersionTags
			Expect(composeVersionNegotiation(0x1337)).To(Equal(oldVersionNegotiationPacket))
			return packet
		}

		It("recognizes that a packet without VersionFlag means that the server accepted the suggested version", func() {
			ph := PublicHeader{
				PacketNumber:    1,
				PacketNumberLen: protocol.PacketNumberLen2,
				ConnectionID:    0x1337,
			}
			b := &bytes.Buffer{}
			err := ph.Write(b, protocol.VersionWhatever, protocol.PerspectiveServer)
			Expect(err).ToNot(HaveOccurred())
			err = cl.handlePacket(nil, b.Bytes())
			Expect(err).ToNot(HaveOccurred())
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Eventually(func() bool { return versionNegotiateConnStateCalled }).Should(BeTrue())
		})

		It("changes the version after receiving a version negotiation packet", func() {
			newVersion := protocol.Version35
			Expect(newVersion).ToNot(Equal(cl.version))
			Expect(sess.packetCount).To(BeZero())
			cl.connectionID = 0x1337
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{newVersion}))
			Expect(cl.version).To(Equal(newVersion))
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Eventually(func() bool { return versionNegotiateConnStateCalled }).Should(BeTrue())
			// it swapped the sessions
			Expect(cl.session).ToNot(Equal(sess))
			Expect(cl.connectionID).ToNot(Equal(0x1337)) // it generated a new connection ID
			Expect(err).ToNot(HaveOccurred())
			// it didn't pass the version negoation packet to the session (since it has no payload)
			Expect(sess.packetCount).To(BeZero())
			Expect(*(*[]protocol.VersionNumber)(unsafe.Pointer(reflect.ValueOf(cl.session.(*session).cryptoSetup).Elem().FieldByName("negotiatedVersions").UnsafeAddr()))).To(Equal([]protocol.VersionNumber{35}))
		})

		It("errors if no matching version is found", func() {
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{1}))
			Expect(err).To(MatchError(qerr.InvalidVersion))
		})

		It("ignores delayed version negotiation packets", func() {
			// if the version was not yet negotiated, handlePacket would return a VersionNegotiationMismatch error, see above test
			cl.connState = ConnStateVersionNegotiated
			Expect(sess.packetCount).To(BeZero())
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{1}))
			Expect(err).ToNot(HaveOccurred())
			Expect(cl.connState).To(Equal(ConnStateVersionNegotiated))
			Expect(sess.packetCount).To(BeZero())
			Consistently(func() bool { return versionNegotiateConnStateCalled }).Should(BeFalse())
		})

		It("errors if the server should have accepted the offered version", func() {
			err := cl.handlePacket(nil, getVersionNegotiation([]protocol.VersionNumber{cl.version}))
			Expect(err).To(MatchError(qerr.Error(qerr.InvalidVersionNegotiationPacket, "Server already supports client's version and should have accepted the connection.")))
		})
	})
})
<|endoftext|>


<commit_before>package growthforecast

import (
  "bufio"
  "errors"
  "fmt"
  "net"
  "os"
  "os/exec"
  "testing"
  "time"
)

var GF_PORT int

func CreateClient() (*Client) {
  return NewClient(fmt.Sprintf("http://127.0.0.1:%d", GF_PORT))
}

func TestSanity(t *testing.T) {
  // Placeholder test to check that we can at least compile this library
  c := CreateClient()
  if c == nil {
    t.Errorf("Could not create client")
  }
}

func TestBasic(t *testing.T) {
  guard, err := startGF(t)
  if err != nil {
    t.Logf("We were unable to start GrowthForecast. Will not run live tests")
    t.Logf("Errors: %s", err)
    return
  }
  defer guard()

  c := CreateClient()
  g := NewGraph()
  g.ServiceName = "acme"
  g.SectionName = "motor"
  g.GraphName   = "oil"
  err = c.CreateGraph(g)

  if err != nil {
    t.Errorf("Failed to create graph: %s", err)
  }
}

func startGF(t *testing.T) (func(), error) {
  path, err := exec.LookPath("growthforecast.pl")
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to lookup growthforecast.pl: %s",
        err,
      ),
    )
  }

  // XXX This needs fixing
  GF_PORT = 5125

  cmd := exec.Command(path, "--port=5125", "--host=127.0.0.1")

  stderrpipe, err := cmd.StderrPipe()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to open pipe to stderr: %s",
        err,
      ),
    )
  }
  stdoutpipe, err := cmd.StdoutPipe()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to open pipe to stdout: %s",
        err,
      ),
    )
  }
  pipes := []struct {
    Out *os.File
    Rdr *bufio.Reader
  } {
    { os.Stdout, bufio.NewReader(stdoutpipe) },
    { os.Stderr, bufio.NewReader(stderrpipe) },
  }

  err  = cmd.Start()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to start growthforecast.pl: %s",
        err,
      ),
    )
  }

  killed := false
  killproc := func() {
    killed = true
    t.Logf("Killing growthforecast.pl")
    cmd.Process.Kill()
  }
  defer func() {
    if err := recover(); err != nil {
      killproc()
      panic(err)
    }
  }()

  started := false
  addr    := fmt.Sprintf("127.0.0.1:%d", GF_PORT)
  for timeout := time.Now().Add(10 * time.Second); timeout.After(time.Now()); {
    _, err := net.Dial("tcp", addr)
    if err == nil {
      started = true
      break
    }
    time.Sleep(1 * time.Second)
  }

  if ! started {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to connect to port %d",
        GF_PORT,
      ),
    )
  }

  for _, p := range pipes {
    go func(out *os.File, in *bufio.Reader) {
      for !killed {
        str, err := in.ReadBytes('\n')
        if str != nil {
          out.Write(str)
          out.Sync()
        }

        if err != nil {
          break
        }
      }
    }(p.Out, p.Rdr)
  }

  t.Logf("growthforecast.pl started")
  go cmd.Wait()

  return killproc, nil
}<commit_msg>various tweaks to starting growthforecast.pl<commit_after>package growthforecast

import (
  "bufio"
  "errors"
  "fmt"
  "math/rand"
  "net"
  "os"
  "os/exec"
  "syscall"
  "testing"
  "time"
)

var GF_PORT int

func init () {
  rand.Seed(time.Now().UnixNano())
}

func CreateClient() (*Client) {
  return NewClient(fmt.Sprintf("http://127.0.0.1:%d", GF_PORT))
}

func TestSanity(t *testing.T) {
  // Placeholder test to check that we can at least compile this library
  c := CreateClient()
  if c == nil {
    t.Errorf("Could not create client")
  }
}

func TestBasic(t *testing.T) {
  guard, err := startGF(t)
  if err != nil {
    t.Logf("We were unable to start GrowthForecast. Will not run live tests")
    t.Logf("Errors: %s", err)
    return
  }
  defer guard()

  c := CreateClient()
  g := NewGraph()
  g.ServiceName = "acme"
  g.SectionName = "motor"
  g.GraphName   = "oil"
  err = c.CreateGraph(g)

  if err != nil {
    t.Errorf("Failed to create graph: %s", err)
  }
}

func startGF(t *testing.T) (func(), error) {
  path, err := exec.LookPath("growthforecast.pl")
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to lookup growthforecast.pl: %s",
        err,
      ),
    )
  }

  for p := 50000 + rand.Intn(10000); p < 65535; p++ {
    l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", p))
    if err == nil {
      l.Close()
      GF_PORT = p
      break
    }
  }

  if GF_PORT == 0 {
    return nil, errors.New("Could not find an empty port")
  }

  cmd := exec.Command(
    path,
    fmt.Sprintf("--port=%d", GF_PORT),
    "--host=127.0.0.1",
  )

  stderrpipe, err := cmd.StderrPipe()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to open pipe to stderr: %s",
        err,
      ),
    )
  }
  stdoutpipe, err := cmd.StdoutPipe()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to open pipe to stdout: %s",
        err,
      ),
    )
  }
  pipes := []struct {
    Out *os.File
    Rdr *bufio.Reader
  } {
    { os.Stdout, bufio.NewReader(stdoutpipe) },
    { os.Stderr, bufio.NewReader(stderrpipe) },
  }

  err  = cmd.Start()
  if err != nil {
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to start growthforecast.pl: %s",
        err,
      ),
    )
  }

  killed := false
  killproc := func() {
    killed = true
    t.Logf("Killing growthforecast.pl")
    cmd.Process.Signal(syscall.SIGTERM)
  }
  defer func() {
    if err := recover(); err != nil {
      killproc()
      panic(err)
    }
  }()

  started := false
  addr    := fmt.Sprintf("127.0.0.1:%d", GF_PORT)
  for timeout := time.Now().Add(10 * time.Second); timeout.After(time.Now()); {
    _, err := net.Dial("tcp", addr)
    if err == nil {
      started = true
      break
    }
    time.Sleep(1 * time.Second)
  }

  if ! started {
    killproc()
    return nil, errors.New(
      fmt.Sprintf(
        "Failed to connect to port %d",
        GF_PORT,
      ),
    )
  }

  for _, p := range pipes {
    go func(out *os.File, in *bufio.Reader) {
      for !killed {
        str, err := in.ReadBytes('\n')
        if str != nil {
          out.Write(str)
          out.Sync()
        }

        if err != nil {
          break
        }
      }
    }(p.Out, p.Rdr)
  }

  t.Logf("growthforecast.pl started on port %d", GF_PORT)
  go func() {
    t.Logf("Wait")
    cmd.Wait()
    t.Logf("Done wait")
  }()

  return killproc, nil
}<|endoftext|>


<commit_before>package main

import (
	"flag"
	"os"
	"os/signal"
	"os/exec"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session
	me *discordgo.User
	RiotKey = flag.String("k", "", "Riot API Key")

	ADMINS = []string {
		"118830934710681602", //Beni
		"118641605837062144", //Nicola
	}
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	log.Info("message created: ", m.Content)
	log.Info("Author: ", m.Author.ID)
	var (
		ourShard = true
		adminMode = false
	)

	if (len(m.Content) <= 0 || (m.Content[0] != '!' && m.Content[0] != '<')) { //@J.A.R.V.I.S = <@168313836951175168>
		return
	}

	if(contains(m.Author.ID, ADMINS)) {
		adminMode = true
	}

	parts := strings.Split(m.Content, " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if !ourShard {
		return
	}

	switch strings.ToLower(parts[0]) {
		case "!weather": weather(parts[1:], s, m)
		case "<@168313836951175168>": jarvis(parts[1:], s, m)
		case "!coin": coin(s, m)
		case "!dice": dice(s, m)
		case "!elo": elo(parts[1:], s, m, *RiotKey)
		case "!kappa": log.Info("KappaPride")
		//case "!whatis": classifyImage(parts[1:], s, m)
		case "!update": update(adminMode, s, m)
	}
}

func update(admin bool, s *discordgo.Session, m *discordgo.MessageCreate) {
	if(admin) {
		log.Info("Updating...")
		cmd := exec.Command("./update.sh")
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Run()
	} else {
		s.ChannelMessageSend(m.ID, "You can't do that...")
	}
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if(*Token == "" || *RiotKey == "") {
		flag.PrintDefaults()
		return
	}

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("JARVIS READY.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<commit_msg>removed update command, need to figure out how to get it to work<commit_after>package main

import (
	"flag"
	"os"
	"os/signal"
	"os/exec"
	"strconv"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/bwmarrin/discordgo"
	redis "gopkg.in/redis.v3"
)

var (
	// discordgo session
	discord *discordgo.Session
	me *discordgo.User
	RiotKey = flag.String("k", "", "Riot API Key")

	ADMINS = []string {
		"118830934710681602", //Beni
		"118641605837062144", //Nicola
	}
)

func onReady(s *discordgo.Session, event *discordgo.Ready) {
	log.Info("Recieved READY payload")
	s.UpdateStatus(0, "League Of Legends")
}

func onGuildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if !shardContains(event.Guild.ID) {
		return
	}

	if event.Guild.Unavailable != nil {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			s.ChannelMessageSend(channel.ID, "BEEP BOOP BOOTING")
			s.ChannelMessageSend(channel.ID, "https://media.giphy.com/media/3o85g3yQa2iG2Rdq1O/giphy.gif")
			return
		}
	}
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	log.Info("message created: ", m.Content)
	log.Info("Author: ", m.Author.ID)
	var (
		ourShard = true
		adminMode = false
	)

	if (len(m.Content) <= 0 || (m.Content[0] != '!' && m.Content[0] != '<')) { //@J.A.R.V.I.S = <@168313836951175168>
		return
	}

	if(contains(m.Author.ID, ADMINS)) {
		adminMode = true
	}

	parts := strings.Split(m.Content, " ")

	channel, _ := discord.State.Channel(m.ChannelID)
	if channel == nil {
		log.WithFields(log.Fields{
			"channel": m.ChannelID,
			"message": m.ID,
		}).Warning("Failed to grab channel")
		return
	}

	guild, _ := discord.State.Guild(channel.GuildID)
	if guild == nil {
		log.WithFields(log.Fields{
			"guild":   channel.GuildID,
			"channel": channel,
			"message": m.ID,
		}).Warning("Failed to grab guild")
		return
	}

	// If we're in sharding mode, test whether this message is relevant to us
	if !shardContains(channel.GuildID) {
		ourShard = false
	}

	if !ourShard {
		return
	}

	switch strings.ToLower(parts[0]) {
		case "!weather": weather(parts[1:], s, m)
		case "<@168313836951175168>": jarvis(parts[1:], s, m)
		case "!coin": coin(s, m)
		case "!dice": dice(s, m)
		case "!elo": elo(parts[1:], s, m, *RiotKey)
		//case "!whatis": classifyImage(parts[1:], s, m)
		case "!update": update(adminMode, s, m)
	}
}

//This should update stuff
func update(admin bool, s *discordgo.Session, m *discordgo.MessageCreate) {
	// if(admin) {
	// 	log.Info("Updating...")
	// 	cmd := exec.Command("./update.sh")
	// 	cmd.Stdout = os.Stdout
	// 	cmd.Stderr = os.Stderr
	// 	cmd.Run()
	// } else {
	// 	s.ChannelMessageSend(m.ID, "You can't do that...")
	// }
}

func main() {
	var (
		Token = flag.String("t", "", "Discord Authentication Token")
		Redis = flag.String("r", "", "Redis Connection String")
		Shard = flag.String("s", "", "Integers to shard by")
		Owner = flag.String("o", "", "Owner ID")
		err   error
	)
	flag.Parse()

	if(*Token == "" || *RiotKey == "") {
		flag.PrintDefaults()
		return
	}

	if *Owner != "" {
		OWNER = *Owner
	}

	// Make sure shard is either empty, or an integer
	if *Shard != "" {
		SHARDS = strings.Split(*Shard, ",")

		for _, shard := range SHARDS {
			if _, err := strconv.Atoi(shard); err != nil {
				log.WithFields(log.Fields{
					"shard": shard,
					"error": err,
				}).Fatal("Invalid Shard")
				return
			}
		}
	}

	// If we got passed a redis server, try to connect
	if *Redis != "" {
		log.Info("Connecting to redis...")
		rcli = redis.NewClient(&redis.Options{Addr: *Redis, DB: 0})
		_, err = rcli.Ping().Result()

		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Fatal("Failed to connect to redis")
			return
		}
	}

	// Create a discord session
	log.Info("Starting discord session...")
	discord, err = discordgo.New(*Token)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord session")
		return
	}

	discord.AddHandler(onReady)
	discord.AddHandler(onGuildCreate)
	discord.AddHandler(onMessageCreate)

	err = discord.Open()
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Failed to create discord websocket connection")
		return
	}

	// We're running!
	log.Info("JARVIS READY.")

	// Wait for a signal to quit
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	<-c
}
<|endoftext|>