<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"strconv"
	"text/template"
	"time"
	"unicode"

	"github.com/drone/drone-go/drone"
	"github.com/drone/drone-go/plugin"
)

// HipChat represents the settings needed to send a HipChat notification.
type HipChat struct {
	Notify   bool            `json:"notify"`
	From     string          `json:"from"`
	Room     drone.StringInt `json:"room_id_or_name"`
	Token    string          `json:"auth_token"`
	Template Template        `json:"template"`
}

// Template represents template options for custom HipChat message
// notifications on success and failure.
type Template struct {
	Success string `json:"success"`
	Failure string `json:"failure"`
}

func main() {

	payload := drone.Payload{}

	fmt.Println(plugin.Stdin)

	if err := plugin.Stdin.Unmarshal(&payload); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(payload)

	// plugin settings
	repo := drone.Repo{}
	build := drone.Build{}
	system := drone.System{}
	vargs := HipChat{}

	// set plugin parameters
	plugin.Param("build", &build)
	plugin.Param("repo", &repo)
	plugin.Param("system", &system)
	plugin.Param("vargs", &vargs)

	// parse the parameters
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// create the HipChat client
	client := NewClient(vargs.Room.String(), vargs.Token)

	// build the HipChat message
	msg := Message{
		From:    vargs.From,
		Notify:  vargs.Notify,
		Color:   Color(&build),
		Message: BuildMessage(&repo, &build, &system, vargs.Template),
	}

	// sends the HipChat message
	if err := client.Send(&msg); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// BuildMessage takes a number of drone parameters and builds a message.
func BuildMessage(repo *drone.Repo, build *drone.Build, sys *drone.System, t Template) string {

	// data for custom template rendering, if we need it
	data := struct {
		Repo  *drone.Repo  `json:"repo"`
		Build *drone.Build `json:"build"`
	}{repo, build}

	// since notification messages are first based
	// upon build status, we switch on that
	switch build.Status {
	case drone.StatusSuccess:
		if len(t.Success) > 0 {
			return Render(t.Success, &data)
		}
		return DefaultMessage(repo, build, sys)
	case drone.StatusFailure:
		if len(t.Failure) > 0 {
			return Render(t.Failure, &data)
		}
		return DefaultMessage(repo, build, sys)
	default:
		return DefaultMessage(repo, build, sys)
	}
}

// DefaultMessage takes a number of drone parameters and builds a default
// notification message.
func DefaultMessage(repo *drone.Repo, build *drone.Build, sys *drone.System) string {
	return fmt.Sprintf("%s %s (%s) by %s in %s
 - %s ",
		FirstRuneToUpper(build.Status),
		BuildLink(repo, build, sys),
		build.Branch,
		build.Author,
		time.Duration(build.Finished-build.Started)*time.Second,
		build.Message,
	)
}

// Color takes a *plugin.Build object and determines the appropriate
// notification/message color.
func Color(build *drone.Build) string {
	switch build.Status {
	case drone.StatusSuccess:
		return "green"
	case drone.StatusFailure, drone.StatusError, drone.StatusKilled:
		return "red"
	default:
		return "yellow"
	}
}

// FirstRuneToUpper takes a string and capitalizes the first letter.
func FirstRuneToUpper(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	s = string(a)
	return s
}

// BuildLink builds the html link to a build.
func BuildLink(repo *drone.Repo, build *drone.Build, sys *drone.System) string {
	repoName := repo.Owner + "/" + repo.Name
	url := sys.Link + "/" + repoName + "/" + strconv.Itoa(build.Number)
	return fmt.Sprintf("%s#%s", url, repoName, build.Commit[:8])
}

// Render takes a string template and data interface to render the provided
// template to a string.
func Render(tmpl string, data interface{}) string {
	var buf bytes.Buffer
	t, err := template.New("_").Parse(tmpl)
	if err != nil {
		fmt.Printf("Error parsing content template. %s\n", err)
		os.Exit(1)
	}
	if err := t.Execute(&buf, &data); err != nil {
		fmt.Printf("Error executing content template. %s\n", err)
		os.Exit(1)
	}
	return buf.String()
}
<commit_msg>printing more info out<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"strconv"
	"text/template"
	"time"
	"unicode"

	"github.com/drone/drone-go/drone"
	"github.com/drone/drone-go/plugin"
)

// HipChat represents the settings needed to send a HipChat notification.
type HipChat struct {
	Notify   bool            `json:"notify"`
	From     string          `json:"from"`
	Room     drone.StringInt `json:"room_id_or_name"`
	Token    string          `json:"auth_token"`
	Template Template        `json:"template"`
}

// Template represents template options for custom HipChat message
// notifications on success and failure.
type Template struct {
	Success string `json:"success"`
	Failure string `json:"failure"`
}

func main() {

	payload := drone.Payload{}

	fmt.Printf("%#v\n", plugin.Stdin)

	if err := plugin.Stdin.Unmarshal(&payload); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("%#v\n", payload)

	// plugin settings
	repo := drone.Repo{}
	build := drone.Build{}
	system := drone.System{}
	vargs := HipChat{}

	// set plugin parameters
	plugin.Param("build", &build)
	plugin.Param("repo", &repo)
	plugin.Param("system", &system)
	plugin.Param("vargs", &vargs)

	// parse the parameters
	if err := plugin.Parse(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	// create the HipChat client
	client := NewClient(vargs.Room.String(), vargs.Token)

	// build the HipChat message
	msg := Message{
		From:    vargs.From,
		Notify:  vargs.Notify,
		Color:   Color(&build),
		Message: BuildMessage(&repo, &build, &system, vargs.Template),
	}

	// sends the HipChat message
	if err := client.Send(&msg); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

// BuildMessage takes a number of drone parameters and builds a message.
func BuildMessage(repo *drone.Repo, build *drone.Build, sys *drone.System, t Template) string {

	// data for custom template rendering, if we need it
	data := struct {
		Repo  *drone.Repo  `json:"repo"`
		Build *drone.Build `json:"build"`
	}{repo, build}

	// since notification messages are first based
	// upon build status, we switch on that
	switch build.Status {
	case drone.StatusSuccess:
		if len(t.Success) > 0 {
			return Render(t.Success, &data)
		}
		return DefaultMessage(repo, build, sys)
	case drone.StatusFailure:
		if len(t.Failure) > 0 {
			return Render(t.Failure, &data)
		}
		return DefaultMessage(repo, build, sys)
	default:
		return DefaultMessage(repo, build, sys)
	}
}

// DefaultMessage takes a number of drone parameters and builds a default
// notification message.
func DefaultMessage(repo *drone.Repo, build *drone.Build, sys *drone.System) string {
	return fmt.Sprintf("%s %s (%s) by %s in %s
 - %s ",
		FirstRuneToUpper(build.Status),
		BuildLink(repo, build, sys),
		build.Branch,
		build.Author,
		time.Duration(build.Finished-build.Started)*time.Second,
		build.Message,
	)
}

// Color takes a *plugin.Build object and determines the appropriate
// notification/message color.
func Color(build *drone.Build) string {
	switch build.Status {
	case drone.StatusSuccess:
		return "green"
	case drone.StatusFailure, drone.StatusError, drone.StatusKilled:
		return "red"
	default:
		return "yellow"
	}
}

// FirstRuneToUpper takes a string and capitalizes the first letter.
func FirstRuneToUpper(s string) string {
	a := []rune(s)
	a[0] = unicode.ToUpper(a[0])
	s = string(a)
	return s
}

// BuildLink builds the html link to a build.
func BuildLink(repo *drone.Repo, build *drone.Build, sys *drone.System) string {
	repoName := repo.Owner + "/" + repo.Name
	url := sys.Link + "/" + repoName + "/" + strconv.Itoa(build.Number)
	return fmt.Sprintf("%s#%s", url, repoName, build.Commit[:8])
}

// Render takes a string template and data interface to render the provided
// template to a string.
func Render(tmpl string, data interface{}) string {
	var buf bytes.Buffer
	t, err := template.New("_").Parse(tmpl)
	if err != nil {
		fmt.Printf("Error parsing content template. %s\n", err)
		os.Exit(1)
	}
	if err := t.Execute(&buf, &data); err != nil {
		fmt.Printf("Error executing content template. %s\n", err)
		os.Exit(1)
	}
	return buf.String()
}
<|endoftext|>


<commit_before>// Copyright 2014 James McGuire. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"database/sql"
	"encoding/json"
	irc "github.com/fluffle/goirc/client"
	_ "github.com/go-sql-driver/mysql"
	"html"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"regexp"
	"strings"
	"time"
	"unicode/utf8"
)

var (
	config   Config
	urlRegex = regexp.MustCompile(`(?i)\b((?:https?://|www\d{0,3}[.]|[` +
		`a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+` +
		`\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s` + "`" + `!()\[` +
		`\]{};:'".,<>?«»“”‘’]))`)
	httpRegex = regexp.MustCompile(`https?://.*`)
	db        *sql.DB
	badWords  = make(map[string]*regexp.Regexp)
)

type Config struct {
	Channel       string
	DBConn        string
	Nick          string
	Ident         string
	FullName      string
	FlickrAPIKey  string
	WolframAPIKey string
	IRCPass       string
	RebuildWords  bool
	Commands      []struct {
		Name string
		Text string
	}
	BadWords []struct {
		Word  string
		Query string
	}
}

// Try and grab the title for any URL's posted in the channel
func sendUrl(channel, unparsedURL string, conn *irc.Conn) {
	if !httpRegex.MatchString(unparsedURL) {
		unparsedURL = `http://` + unparsedURL
	}
	postedUrl, err := url.Parse(unparsedURL)
	if err != nil {
		log.Println(err)
		return
	}
	log.Println("Fetching title for " + postedUrl.String() + " In channel " + channel)

	resp, err := http.Get(postedUrl.String())
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 400 {
		log.Println("http server return error.")
		return
	}
	respbody := []byte{}
	if resp.Header.Get("Content-Type") == "" {
		buf := make([]byte, 512)
		bufsize, err := resp.Body.Read(buf)
		if err != nil {
			log.Println("adding content type failed")
		}
		resp.Header.Set("Content-Type", http.DetectContentType(buf[:bufsize]))
		respbody = append(respbody, buf[:bufsize]...)
	}

	if !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
		log.Println("content-type is not text/html")
		return
	}

	restofbody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 50000))
	if err != nil {
		log.Println("error reading posted link")
		return
	}
	respbody = append(respbody, restofbody...)
	stringbody := string(respbody)
	titlestart := strings.Index(stringbody, "<title>")
	titleend := strings.Index(stringbody, "</title>")
	if titlestart != -1 && titlestart != -1 {
		title := string(respbody[titlestart+7 : titleend])
		title = strings.TrimSpace(title)
		if title != "" && utf8.ValidString(title) {
			// Example:
			// Title: sadbox . org (at sadbox.org)
			title = "Title: " + html.UnescapeString(title) + " (at " + postedUrl.Host + ")"
			log.Println(title)
			conn.Privmsg(channel, title)
		}
	}
}

func logMessage(line *irc.Line, channel, message string) {
	_, err := db.Exec("insert into messages (Nick, Ident, Host, Src, Cmd, Channel,"+
		" Message, Time) values (?, ?, ?, ?, ?, ?, ?, ?)", line.Nick, line.Ident,
		line.Host, line.Src, line.Cmd, channel, message, line.Time)
	if err != nil {
		log.Println(err)
	}
	err = updateWords(line.Nick, message)
	if err != nil {
		log.Println(err)
	}
}

func checkForUrl(channel string, splitmessage []string, conn *irc.Conn) {
	urllist := []string{}
	numlinks := 0
NextWord:
	for _, word := range splitmessage {
		word = strings.TrimSpace(word)
		if urlRegex.MatchString(word) {
			for _, subUrl := range urllist {
				if subUrl == word {
					continue NextWord
				}
			}
			numlinks++
			if numlinks > 3 {
				break
			}
			urllist = append(urllist, word)
			go sendUrl(channel, word, conn)
		}
	}
}

// This function does all the dispatching for various commands
// as well as logging each message to the database
func handleMessage(conn *irc.Conn, line *irc.Line) {
	// This is so that the bot can properly respond to pm's
	var channel string
	if conn.Me.Nick == line.Args[0] {
		channel = line.Nick
	} else {
		channel = line.Args[0]
	}
	message := line.Args[1]
	splitmessage := strings.Split(message, " ")

	// Special commands
	switch strings.TrimSpace(splitmessage[0]) {
	case "!dance":
		if line.Nick == "sadbox" {
			go dance(channel, conn)
		}
	case "!audio":
		if line.Nick == "sadbox" {
			go conn.Privmsg(channel, "https://sadbox.org/static/stuff/audiophile.html")
		}
	case "!cst":
		if line.Nick == "sadbox" {
			go conn.Privmsg(channel, "\u00039,13#CSTMASTERRACE")
		}
	case "!haata":
		go haata(channel, conn)
	case "!search":
		go googSearch(channel, message, conn)
	case "!chatter":
		if line.Nick == "sadbox" {
			go markov(channel, conn)
		}
	case "!ask":
		go wolfram(channel, message, line.Nick, conn)
	case "!meebcast":
		var command string
		if len(splitmessage) >= 2 {
			command = strings.TrimSpace(splitmessage[1])
		}
		go meeba(channel, line.Nick, command, conn)
	}

	// Commands that are read in from the config file
	for _, command := range config.Commands {
		if strings.TrimSpace(splitmessage[0]) == command.Name {
			go conn.Privmsg(channel, command.Text)
		}
	}

	// This is what looks at each word and tries to figure out if it's a URL
	go checkForUrl(channel, splitmessage, conn)

	// Shove that shit in the database!
	go logMessage(line, channel, message)
}

func init() {
	log.Println("Starting sadbot")

	rand.Seed(time.Now().UTC().UnixNano())

	configfile, err := os.Open("config.json")
	if err != nil {
		log.Fatal(err)
	}
	err = json.NewDecoder(configfile).Decode(&config)
	if err != nil {
		log.Fatal(err)
	}

	for _, word := range config.BadWords {
		badWords[word.Word] = regexp.MustCompile(word.Query)
	}

	log.Println("Loaded config file!")
	log.Printf("Joining channel %s", config.Channel)
	log.Printf("Nick: %s", config.Nick)
	log.Printf("Ident: %s", config.Ident)
	log.Printf("FullName: %s", config.FullName)

	log.Printf("Found %d commands", len(config.Commands))
	for index, command := range config.Commands {
		log.Printf("%d %s: %s", index+1, command.Name, command.Text)
	}
}

func main() {
	var err error
	db, err = sql.Open("mysql", config.DBConn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	db.SetMaxIdleConns(50)
	db.SetMaxOpenConns(100)

	go makeMarkov()

	if config.RebuildWords {
		go genTables()
	}
	c := irc.SimpleClient(config.Nick, config.Ident, config.FullName)

	c.SSL = true

	c.AddHandler(irc.CONNECTED,
		func(conn *irc.Conn, line *irc.Line) {
			conn.Join(config.Channel)
			log.Println("Connected!")
		})

	quit := make(chan bool)

	c.AddHandler(irc.DISCONNECTED,
		func(conn *irc.Conn, line *irc.Line) { quit <- true })

	c.AddHandler("PRIVMSG", handleMessage)
	c.AddHandler("ACTION", handleMessage)

	if err := c.Connect("irc.freenode.net", config.Nick+":"+config.IRCPass); err != nil {
		log.Fatalln("Connection error: %s\n", err)
	}

	<-quit
}
<commit_msg>use a signal instead of a config option to rebuild curse database<commit_after>// Copyright 2014 James McGuire. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	"database/sql"
	"encoding/json"
	irc "github.com/fluffle/goirc/client"
	_ "github.com/go-sql-driver/mysql"
	"html"
	"io"
	"io/ioutil"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"
	"unicode/utf8"
)

var (
	config   Config
	urlRegex = regexp.MustCompile(`(?i)\b((?:https?://|www\d{0,3}[.]|[` +
		`a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+` +
		`\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s` + "`" + `!()\[` +
		`\]{};:'".,<>?«»“”‘’]))`)
	httpRegex = regexp.MustCompile(`https?://.*`)
	db        *sql.DB
	badWords  = make(map[string]*regexp.Regexp)
)

type Config struct {
	Channel       string
	DBConn        string
	Nick          string
	Ident         string
	FullName      string
	FlickrAPIKey  string
	WolframAPIKey string
	IRCPass       string
	RebuildWords  bool
	Commands      []struct {
		Name string
		Text string
	}
	BadWords []struct {
		Word  string
		Query string
	}
}

// Try and grab the title for any URL's posted in the channel
func sendUrl(channel, unparsedURL string, conn *irc.Conn) {
	if !httpRegex.MatchString(unparsedURL) {
		unparsedURL = `http://` + unparsedURL
	}
	postedUrl, err := url.Parse(unparsedURL)
	if err != nil {
		log.Println(err)
		return
	}
	log.Println("Fetching title for " + postedUrl.String() + " In channel " + channel)

	resp, err := http.Get(postedUrl.String())
	if err != nil {
		log.Println(err)
		return
	}
	defer resp.Body.Close()
	if resp.StatusCode >= 400 {
		log.Println("http server return error.")
		return
	}
	respbody := []byte{}
	if resp.Header.Get("Content-Type") == "" {
		buf := make([]byte, 512)
		bufsize, err := resp.Body.Read(buf)
		if err != nil {
			log.Println("adding content type failed")
		}
		resp.Header.Set("Content-Type", http.DetectContentType(buf[:bufsize]))
		respbody = append(respbody, buf[:bufsize]...)
	}

	if !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
		log.Println("content-type is not text/html")
		return
	}

	restofbody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 50000))
	if err != nil {
		log.Println("error reading posted link")
		return
	}
	respbody = append(respbody, restofbody...)
	stringbody := string(respbody)
	titlestart := strings.Index(stringbody, "<title>")
	titleend := strings.Index(stringbody, "</title>")
	if titlestart != -1 && titlestart != -1 {
		title := string(respbody[titlestart+7 : titleend])
		title = strings.TrimSpace(title)
		if title != "" && utf8.ValidString(title) {
			// Example:
			// Title: sadbox . org (at sadbox.org)
			title = "Title: " + html.UnescapeString(title) + " (at " + postedUrl.Host + ")"
			log.Println(title)
			conn.Privmsg(channel, title)
		}
	}
}

func logMessage(line *irc.Line, channel, message string) {
	_, err := db.Exec("insert into messages (Nick, Ident, Host, Src, Cmd, Channel,"+
		" Message, Time) values (?, ?, ?, ?, ?, ?, ?, ?)", line.Nick, line.Ident,
		line.Host, line.Src, line.Cmd, channel, message, line.Time)
	if err != nil {
		log.Println(err)
	}
	err = updateWords(line.Nick, message)
	if err != nil {
		log.Println(err)
	}
}

func checkForUrl(channel string, splitmessage []string, conn *irc.Conn) {
	urllist := []string{}
	numlinks := 0
NextWord:
	for _, word := range splitmessage {
		word = strings.TrimSpace(word)
		if urlRegex.MatchString(word) {
			for _, subUrl := range urllist {
				if subUrl == word {
					continue NextWord
				}
			}
			numlinks++
			if numlinks > 3 {
				break
			}
			urllist = append(urllist, word)
			go sendUrl(channel, word, conn)
		}
	}
}

// This function does all the dispatching for various commands
// as well as logging each message to the database
func handleMessage(conn *irc.Conn, line *irc.Line) {
	// This is so that the bot can properly respond to pm's
	var channel string
	if conn.Me.Nick == line.Args[0] {
		channel = line.Nick
	} else {
		channel = line.Args[0]
	}
	message := line.Args[1]
	splitmessage := strings.Split(message, " ")

	// Special commands
	switch strings.TrimSpace(splitmessage[0]) {
	case "!dance":
		if line.Nick == "sadbox" {
			go dance(channel, conn)
		}
	case "!audio":
		if line.Nick == "sadbox" {
			go conn.Privmsg(channel, "https://sadbox.org/static/stuff/audiophile.html")
		}
	case "!cst":
		if line.Nick == "sadbox" {
			go conn.Privmsg(channel, "\u00039,13#CSTMASTERRACE")
		}
	case "!haata":
		go haata(channel, conn)
	case "!search":
		go googSearch(channel, message, conn)
	case "!chatter":
		if line.Nick == "sadbox" {
			go markov(channel, conn)
		}
	case "!ask":
		go wolfram(channel, message, line.Nick, conn)
	case "!meebcast":
		var command string
		if len(splitmessage) >= 2 {
			command = strings.TrimSpace(splitmessage[1])
		}
		go meeba(channel, line.Nick, command, conn)
	}

	// Commands that are read in from the config file
	for _, command := range config.Commands {
		if strings.TrimSpace(splitmessage[0]) == command.Name {
			go conn.Privmsg(channel, command.Text)
		}
	}

	// This is what looks at each word and tries to figure out if it's a URL
	go checkForUrl(channel, splitmessage, conn)

	// Shove that shit in the database!
	go logMessage(line, channel, message)
}

func init() {
	log.Println("Starting sadbot")

	rand.Seed(time.Now().UTC().UnixNano())

	configfile, err := os.Open("config.json")
	if err != nil {
		log.Fatal(err)
	}
	err = json.NewDecoder(configfile).Decode(&config)
	if err != nil {
		log.Fatal(err)
	}

	for _, word := range config.BadWords {
		badWords[word.Word] = regexp.MustCompile(word.Query)
	}

	log.Println("Loaded config file!")
	log.Printf("Joining channel %s", config.Channel)
	log.Printf("Nick: %s", config.Nick)
	log.Printf("Ident: %s", config.Ident)
	log.Printf("FullName: %s", config.FullName)

	log.Printf("Found %d commands", len(config.Commands))
	for index, command := range config.Commands {
		log.Printf("%d %s: %s", index+1, command.Name, command.Text)
	}
}

func main() {
	var err error
	db, err = sql.Open("mysql", config.DBConn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	db.SetMaxIdleConns(100)
	db.SetMaxOpenConns(200)

	go makeMarkov()

	buildchan := make(chan os.Signal, 1)
	signal.Notify(buildchan, syscall.SIGUSR1)
	go func() {
		for _ = range buildchan {
			genTables()
		}
	}()

	c := irc.SimpleClient(config.Nick, config.Ident, config.FullName)

	c.SSL = true

	c.AddHandler(irc.CONNECTED,
		func(conn *irc.Conn, line *irc.Line) {
			conn.Join(config.Channel)
			log.Println("Connected!")
		})

	quit := make(chan bool)

	c.AddHandler(irc.DISCONNECTED,
		func(conn *irc.Conn, line *irc.Line) { quit <- true })

	c.AddHandler("PRIVMSG", handleMessage)
	c.AddHandler("ACTION", handleMessage)

	if err := c.Connect("irc.freenode.net", config.Nick+":"+config.IRCPass); err != nil {
		log.Fatalln("Connection error: %s\n", err)
	}

	<-quit
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	glmenu "github.com/4ydx/glmenu"
	glfw "github.com/go-gl/glfw3"
	gl32 "github.com/go-gl/glow/gl-core/3.2/gl"
	"github.com/go-gl/glow/gl-core/3.3/gl"
	"runtime"
)

var useStrictCoreProfile = (runtime.GOOS == "darwin")

func errorCallback(err glfw.ErrorCode, desc string) {
	fmt.Printf("%v: %v\n", err, desc)
}

func keyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if key == glfw.KeyM && action == glfw.Press {
		menu.Toggle()
	}
}

func mouseButtonCallback(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
	if button == glfw.MouseButtonLeft && action == glfw.Press {
		xPos, yPos := window.GetCursorPosition()
		//fmt.Println("button", button, xPos, yPos)
		menu.ScreenClick(xPos, yPos)
	}
}

var menu glmenu.Menu
var window *glfw.Window

func main() {
	var err error

	runtime.LockOSThread()

	glfw.SetErrorCallback(errorCallback)
	if !glfw.Init() {
		panic("glfw error")
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	if useStrictCoreProfile {
		glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True)
		glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile)
	}
	glfw.WindowHint(glfw.OpenglDebugContext, glfw.True)

	window, err = glfw.CreateWindow(640, 480, "Testing", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	window.SetKeyCallback(keyCallback)
	window.SetMouseButtonCallback(mouseButtonCallback)

	if err := gl.Init(); err != nil {
		panic(err)
	}
	if err := gl32.Init(); err != nil {
		fmt.Println("could not initialize GL 3.2")
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println("Opengl version", version)

	menuInit(window)
	gl.ClearColor(0, 0, 0, 0.0)
	for !window.ShouldClose() {
		gl.Clear(gl.COLOR_BUFFER_BIT)

		xPos, yPos := window.GetCursorPosition()
		menu.ScreenHover(xPos, yPos)
		if menu.Draw() {
			// pause gameplay
		} else {
			// do stuff
		}
		window.SwapBuffers()
		glfw.PollEvents()
	}
}
<commit_msg>Toggle prior to open screen.<commit_after>package main

import (
	"fmt"
	glmenu "github.com/4ydx/glmenu"
	glfw "github.com/go-gl/glfw3"
	gl32 "github.com/go-gl/glow/gl-core/3.2/gl"
	"github.com/go-gl/glow/gl-core/3.3/gl"
	"runtime"
)

var useStrictCoreProfile = (runtime.GOOS == "darwin")

func errorCallback(err glfw.ErrorCode, desc string) {
	fmt.Printf("%v: %v\n", err, desc)
}

func keyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	if key == glfw.KeyM && action == glfw.Press {
		menu.Toggle()
	}
}

func mouseButtonCallback(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
	if button == glfw.MouseButtonLeft && action == glfw.Press {
		xPos, yPos := window.GetCursorPosition()
		//fmt.Println("button", button, xPos, yPos)
		menu.ScreenClick(xPos, yPos)
	}
}

var menu glmenu.Menu
var window *glfw.Window

func main() {
	var err error

	runtime.LockOSThread()

	glfw.SetErrorCallback(errorCallback)
	if !glfw.Init() {
		panic("glfw error")
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	if useStrictCoreProfile {
		glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True)
		glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile)
	}
	glfw.WindowHint(glfw.OpenglDebugContext, glfw.True)

	window, err = glfw.CreateWindow(640, 480, "Testing", nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()
	window.SetKeyCallback(keyCallback)
	window.SetMouseButtonCallback(mouseButtonCallback)

	if err := gl.Init(); err != nil {
		panic(err)
	}
	if err := gl32.Init(); err != nil {
		fmt.Println("could not initialize GL 3.2")
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println("Opengl version", version)

	menuInit(window)
	menu.Toggle()

	gl.ClearColor(0, 0, 0, 0.0)
	for !window.ShouldClose() {
		gl.Clear(gl.COLOR_BUFFER_BIT)

		xPos, yPos := window.GetCursorPosition()
		menu.ScreenHover(xPos, yPos)
		if menu.Draw() {
			// pause gameplay
		} else {
			// do stuff
		}
		window.SwapBuffers()
		glfw.PollEvents()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"flag"
	"net/http"
)

var (
	ListenAddr = flag.String("addr", ":80", "The ADDRESS:PORT to listen on")
	DocumentRoot = flag.String("dir", "", "The directory to serve up")
)

func main() {
	flag.Parse()
	if *DocumentRoot == "" {
		log.Fatalln("You must specify a directory to serve, with '-dir=\"...\"'")
	}

	handler := http.FileServer(http.Dir(*DocumentRoot))
	log.Printf("Serving %q", *DocumentRoot)
	log.Printf("Listening on %q", *ListenAddr)
	if err := http.ListenAndServe(*ListenAddr, handler); err != nil {
		log.Fatalln(err)
	}

	return
}
<commit_msg>go fmt<commit_after>package main

import (
	"flag"
	"log"
	"net/http"
)

var (
	ListenAddr   = flag.String("addr", ":80", "The ADDRESS:PORT to listen on")
	DocumentRoot = flag.String("dir", "", "The directory to serve up")
)

func main() {
	flag.Parse()
	if *DocumentRoot == "" {
		log.Fatalln("You must specify a directory to serve, with '-dir=\"...\"'")
	}

	handler := http.FileServer(http.Dir(*DocumentRoot))
	log.Printf("Serving %q", *DocumentRoot)
	log.Printf("Listening on %q", *ListenAddr)
	if err := http.ListenAndServe(*ListenAddr, handler); err != nil {
		log.Fatalln(err)
	}

	return
}
<|endoftext|>


<commit_before>hilarity to ensue
<commit_msg>Delete unneeded main.go file<commit_after><|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

var teaSites = []string{
	"https://verdanttea.com/",
}

var teaTypes = []string{
	`pu'er`,
	`puer`,
	`pu 'er`,
	`pu er`,
	`pu-er`,
	`chai`,
	`matcha`,
	`rooibos`,
	`oolong`,
	`black`,
	`white`,
	`green`,
	`herbal`,
	`yellow`,
	`fermented`,
}

var teaCategoryPattern = strings.Join(teaTypes, " tea ") + " tea"

func Match(toFind string, in string) bool {
	return regexp.MustCompile(fmt.Sprintf(`(?i)\b%s\b`, toFind)).MatchString(in)
}

func MatchStart(substring string, in string) bool {
	return regexp.MustCompile(`(?i)^`+substring).MatchString(in) ||
		regexp.MustCompile(`(?i)^`+in).MatchString(substring)
}

var tags = []string{
	"a",
}

type Tea struct {
	MaybeTea
	data string
}

type MaybeTea struct {
	name string
	link string
}

func (t *MaybeTea) Convert(name string, data string) *Tea {
	return &Tea{
		MaybeTea{
			name,
			t.link,
		},
		data,
	}
}

func (t *MaybeTea) ConfirmConvertTeaType() (*Tea, bool) {
	doc := t.GetDocument()
	headers := doc.Find("h1").FilterFunction(func(i int, node *goquery.Selection) bool {
		title := node.Text()
		return MatchStart(title, t.name)
	})

	if headers.Length() == 1 {
		header := headers.First().Text()
		data := doc.Text()

		// in the case that the previously found name has extra stuff on the end
		// and assuming that the header will only contain the name
		return t.Convert(header, data), true
	}

	return &Tea{MaybeTea{"", ""}, ""}, false
}

func (t *MaybeTea) GetDocument() *goquery.Document {
	doc, err := goquery.NewDocument(t.link)
	if err != nil {
		log.Fatal(err)
	}

	return doc
}

/*
	The crawler must be able to keep track of information about the user flow
	spawn multiple crawlers?
	how to find matching data between pages?
	if a link's labeled as a certain thing which is then found in a header on the page it leads to, that's a tea
	but it's not always that easy, sometimes the descriptor is not a link
	but the link is only near the descriptor
	how to determine that a link and a descriptor go together?
	either descriptor is child to the link or the link and the descriptor have a common parent
	the href and the descriptor will overlap in some way
	confirm that tea type is real by getting next page in flow
	confirm that it's in the page's data
*/
type Crawler struct {
	links       []string
	seen        map[string]bool
	possibleTea []*MaybeTea
	tea         []*Tea
}

func (t *Crawler) GetNextLink() string {
	totalLinks := len(t.links)

	if totalLinks > 0 {
		next := t.links[0:1][0]

		if totalLinks > 1 {
			t.links = t.links[1:]
		} else {
			t.links = make([]string, 0)
		}

		if !t.seen[next] {
			t.seen[next] = true
			return next
		}
		return t.GetNextLink()
	}
	return ""
}

func (t *Crawler) ScrapeSites() *Crawler {
	nextLink := t.GetNextLink()
	fmt.Printf("nextLink: %s", nextLink)
	fmt.Println("")

	if nextLink != "" {
		doc, err := goquery.NewDocument(nextLink)
		if err != nil {
			fmt.Println("There was an error while getting the document for this link: %s", nextLink)
			return t.ScrapeSites()
		}

		t.ScrapePage(doc)
		return t.ScrapeSites()
	}

	fmt.Println("done", t.tea)
	return t
}

func (t *Crawler) AddMaybeTea(link string, name string) *MaybeTea {
	tea := &MaybeTea{
		name,
		link,
	}

	t.possibleTea = append(t.possibleTea, tea)

	return tea
}

func (t *Crawler) ScrapePage(doc *goquery.Document) *Crawler {
	for _, teaType := range teaTypes {
		for _, tag := range tags {
			found := doc.Find(tag).FilterFunction(func(i int, node *goquery.Selection) bool {
				href, exists := node.Attr("href")

				if exists && t.seen[href] {
					return false
				}

				text := node.Text()
				return Match(teaType, text)
			})

			found.Each(func(i int, s *goquery.Selection) {
				href, exists := s.Attr("href")
				text := s.Text()

				if !Match(text, teaCategoryPattern) {
					// let MaybeTea handle more specific tea finding

					t.AddMaybeTea(href, text)
					t.ProcessMaybes()
				} else if exists {
					// let main crawler handle getting through tea categories and going
					// between sites

					t.links = append(t.links, href)
				}

			})

		}
	}

	return t

}

/*
	ProcessMaybes handles examining elements that may be specific tea types
	Updates seen in crawler so that the crawler doesn't explore it
*/
func (t *Crawler) ProcessMaybes() {
	total := len(t.possibleTea)

	if total > 0 {
		next := t.possibleTea[0:1][0]
		tea, converted := next.ConfirmConvertTeaType()

		if converted {
			fmt.Printf("processmaybe: tea name: %s, link: %s", tea.name, tea.link)
			fmt.Println("")
			t.tea = append(t.tea, tea)
		}

		t.seen[tea.link] = true

		if total > 1 {
			t.possibleTea = t.possibleTea[1:]
			t.ProcessMaybes()
		} else {
			t.possibleTea = make([]*MaybeTea, 0)
		}

	}
}

/*
	visit site
	look for teaTypes
	if hyperlink, crawl if not seen
	if not hyperlink, save for language processing
*/

func ScrapeSite() {
	tg := Crawler{
		teaSites,
		make(map[string]bool),
		make([]*MaybeTea, 0),
		make([]*Tea, 0),
	}

	tg.ScrapeSites()
}

func main() {
	fmt.Println(teaCategoryPattern)
	ScrapeSite()
}
<commit_msg>Normalizes relative hrefs<commit_after>package main

import (
	"fmt"
	"log"
	"regexp"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

var teaSites = []string{
	"http://www.adagio.com",
	"https://verdanttea.com",
}

var teaTypes = []string{
	`pu'er`,
	`puer`,
	`pu 'er`,
	`pu er`,
	`pu-er`,
	`chai`,
	`matcha`,
	`rooibos`,
	`oolong`,
	`black`,
	`white`,
	`green`,
	`herbal`,
	`yellow`,
	`fermented`,
}

var relativePathPattern = regexp.MustCompile("^/")
var teaCategoryPattern = strings.Join(teaTypes, " tea ") + " tea" + strings.Join(teaTypes, " teas ") + " teas"
var originPattern = regexp.MustCompile("(https://www..+.com|http://www..+.com)")
var urlDelimeterReplacer = strings.NewReplacer("_", " ", "-", " ", ".", " ", "/", " ")

func RemoveUrlDelmeters(url string) string {
	return urlDelimeterReplacer.Replace(url)
}

func Match(toFind string, in string) bool {
	return regexp.MustCompile(fmt.Sprintf(`(?i)\b%s\b`, toFind)).MatchString(in)
}

func MatchStart(substring string, in string) bool {
	return regexp.MustCompile(`(?i)^`+substring).MatchString(in) ||
		regexp.MustCompile(`(?i)^`+in).MatchString(substring)
}

func GetOrigin(url string) string {
	return originPattern.FindString(url)
}

func NormalizeLink(link string, originLink string) string {
	if relativePathPattern.MatchString(link) {
		// normalize the relative path
		extractedOrigin := GetOrigin(originLink)
		return fmt.Sprintf("%s%s", extractedOrigin, link)
	}

	return link
}

type Tea struct {
	MaybeTea
	data string
}

type MaybeTea struct {
	name string
	link string
}

func (t *MaybeTea) Convert(name string, data string) *Tea {
	return &Tea{
		MaybeTea{
			name,
			t.link,
		},
		data,
	}
}

func (t *MaybeTea) ConfirmConvertTeaType() (*Tea, bool) {
	doc := t.GetDocument()
	headers := doc.Find("h1").FilterFunction(func(i int, node *goquery.Selection) bool {
		title := node.Text()
		return MatchStart(title, t.name)
	})

	if headers.Length() == 1 {
		header := headers.First().Text()
		data := doc.Text()

		// in the case that the previously found name has extra stuff on the end
		// and assuming that the header will only contain the name
		return t.Convert(header, data), true
	}

	return &Tea{MaybeTea{"", ""}, ""}, false
}

func (t *MaybeTea) GetDocument() *goquery.Document {
	doc, err := goquery.NewDocument(t.link)
	if err != nil {
		log.Fatal(err)
	}

	return doc
}

/*
	The crawler must be able to keep track of information about the user flow
	spawn multiple crawlers?
	how to find matching data between pages?
	if a link's labeled as a certain thing which is then found in a header on the page it leads to, that's a tea
	but it's not always that easy, sometimes the descriptor is not a link
	but the link is only near the descriptor
	how to determine that a link and a descriptor go together?
	either descriptor is child to the link or the link and the descriptor have a common parent
	the href and the descriptor will overlap in some way
	confirm that tea type is real by getting next page in flow
	confirm that it's in the page's data
*/
type Crawler struct {
	links       []string
	seen        map[string]bool
	possibleTea []*MaybeTea
	tea         []*Tea
}

func (t *Crawler) GetNextLink() string {
	totalLinks := len(t.links)

	if totalLinks > 0 {
		next := t.links[0:1][0]

		if totalLinks > 1 {
			t.links = t.links[1:]
		} else {
			t.links = make([]string, 0)
		}

		if !t.Visited(next) {
			t.UpdateVisited(next)
			return next
		}
		return t.GetNextLink()
	}
	return ""
}

func (t *Crawler) ScrapeSites() *Crawler {
	nextLink := t.GetNextLink()
	fmt.Printf("nextLink: %s", nextLink)
	fmt.Println("")

	if nextLink != "" {
		doc, err := goquery.NewDocument(nextLink)
		if err != nil {
			fmt.Println("There was an error while getting the document for this link: %s", nextLink)
			return t.ScrapeSites()
		}

		t.ScrapePage(doc, nextLink)
		return t.ScrapeSites()
	}

	fmt.Println("done", t.tea)
	return t
}

func (t *Crawler) AddMaybeTea(link string, name string) *MaybeTea {
	tea := &MaybeTea{
		name,
		link,
	}

	t.possibleTea = append(t.possibleTea, tea)

	return tea
}

func (t *Crawler) ScrapePage(doc *goquery.Document, baseLink string) *Crawler {
	for _, teaType := range teaTypes {
		found := doc.Find("a").FilterFunction(func(i int, node *goquery.Selection) bool {
			href, exists := node.Attr("href")

			if exists {

				if t.Visited(href) {
					// TODO checking if seen only works here if the href is not relative
					return false
				}

				text := node.Text()

				if text != "" {
					return Match(teaType, text)
				}

				normalizedHref := RemoveUrlDelmeters(href)

				return Match(teaType, normalizedHref)

			}
			return false
		})

		found.Each(func(i int, s *goquery.Selection) {
			href, exists := s.Attr("href")
			href = NormalizeLink(href, baseLink)
			text := s.Text()

			if !Match(text, teaCategoryPattern) {
				// let MaybeTea handle more specific tea finding

				t.AddMaybeTea(href, text)
				t.ProcessMaybes()
			} else if exists {
				// let main crawler handle getting through tea categories and going
				// between sites

				t.links = append(t.links, href)
			}

		})

	}

	return t

}

func (t *Crawler) Visited(link string) bool {
	return t.seen[link]
}

func (t *Crawler) UpdateVisited(link string) {
	t.seen[link] = true
}

/*
	ProcessMaybes handles examining elements that may be specific tea types
	Updates seen in crawler so that the crawler doesn't explore it
*/
func (t *Crawler) ProcessMaybes() {
	total := len(t.possibleTea)

	if total > 0 {
		next := t.possibleTea[0:1][0]
		tea, converted := next.ConfirmConvertTeaType()

		if converted {
			fmt.Printf("processmaybe: tea name: %s, link: %s", tea.name, tea.link)
			fmt.Println("")
			t.tea = append(t.tea, tea)
		}

		t.UpdateVisited(tea.link)

		if total > 1 {
			t.possibleTea = t.possibleTea[1:]
			t.ProcessMaybes()
		} else {
			t.possibleTea = make([]*MaybeTea, 0)
		}

	}
}

/*
	visit site
	look for teaTypes
	if hyperlink, crawl if not seen
	if not hyperlink, save for language processing
*/

func ScrapeSite() {
	tg := Crawler{
		teaSites,
		make(map[string]bool),
		make([]*MaybeTea, 0),
		make([]*Tea, 0),
	}

	tg.ScrapeSites()
}

func main() {
	ScrapeSite()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"strings"
	"net"
	//"golang.org/x/crypto/openpgp"
)

var outputChannel = make(chan chan string, 5)
var peers []Peer
var myname string = "leijurv"
type Peer struct {
	conn net.Conn
	username string
}
func main() {
	go printAll(outputChannel)
	listen()
}
func onMessageReceived(message string, peerFrom Peer) {
	messageChannel := make(chan string, 100)
	outputChannel <- messageChannel
	go func(){
		defer close(messageChannel)
	 	processMessage(message,messageChannel,peerFrom)
	}()
}
func processMessage(message string, messageChannel chan string, peerFrom Peer) {
	messageChannel<-"Hey, a message from "+peerFrom.username+". "
	messageChannel<-"Beginning processsing. "
	messageChannel<-"Done processing. "
	messageChannel<-"Here's the message: "
	messageChannel<-message
}

func handleConn(conn net.Conn, peerChannel chan Peer) {
	fmt.Println("CONNECTION BABE. Sending our name")
	conn.Write([]byte(myname+"\n"));
	username, err := bufio.NewReader(conn).ReadString('\n')
	if err != nil {
		return
	}
	username=strings.TrimSpace(username)
	fmt.Println("Received username: "+username)
	//here make sure that username is valid
	peerObj:=Peer{conn:conn,username:username}
	peerChannel<-peerObj
}
func onConnClose(peer Peer){
	//remove from list of peers, but idk how to do that in go =(
	fmt.Println("Disconnected from "+peer.username)
}
func peerListen(peer Peer){
	defer peer.conn.Close()
	defer onConnClose(peer)
	conn:=peer.conn
	username:=peer.username
	fmt.Println("Beginning to listen to "+username)
	for {
		message, err := bufio.NewReader(conn).ReadString('\n')
		if err!=nil{
			return
		}
		message=strings.TrimSpace(message)
		onMessageReceived(message,peer)
	}
}
func peerWithName(name string) int{
	for i:=0; i<len(peers); i++{
		if peers[i].username == name{
			return i
		}
	}
	return -1
}
func listen() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	defer ln.Close()
	peerChannel := make(chan Peer)
	defer close(peerChannel)
	go func(){
		for{
			peer,ok := <-peerChannel
			if ok{
				if peerWithName(peer.username)==-1{
					peers = append(peers,peer)
					go peerListen(peer)
				}else{
				 	peer.conn.Close()
					fmt.Println("Sadly we are already connected to "+peer.username+". Disconnecting")
				}
			}else{
				return
			}
		}
	}()
	for {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
		go handleConn(conn,peerChannel)
	}
}

func printAll(stringChanChan <-chan chan string) {
	for {
		strChan := <-stringChanChan
		for{
			str, ok:= <-strChan
			if ok{
				fmt.Printf(str)
			}else{
				break
			}
		}
		fmt.Println()
	}
}
<commit_msg>updated<commit_after>package main

import (
	"bufio"
	"fmt"
	"strings"
	"net"
	//"golang.org/x/crypto/openpgp"
)

var outputChannel = make(chan chan string, 5)
var peers []Peer
var myname string = "leijurv"
var messagesReceivedAlready = make(map[string]bool)
type Peer struct {
	conn net.Conn
	username string
}
func main() {
	go printAll(outputChannel)
	listen()
}
func onMessageReceived(message string, peerFrom Peer) {
	_, found := messagesReceivedAlready[message]
	if found{
		fmt.Println("Lol wait. "+peerFrom.username+" sent us something we already has. Ignoring...");
		return
	}
	messagesReceivedAlready[message] = true
	messageChannel := make(chan string, 100)
	outputChannel <- messageChannel
	go func(){
		defer close(messageChannel)
	 	processMessage(message,messageChannel,peerFrom)
	}()
}
func processMessage(message string, messageChannel chan string, peerFrom Peer) {
	messageChannel<-"Hey, a message from "+peerFrom.username+". "
	messageChannel<-"Beginning processsing. "
	messageChannel<-"Done processing. "
	messageChannel<-"Here's the message: "
	messageChannel<-message
}

func handleConn(conn net.Conn, peerChannel chan Peer) {
	fmt.Println("CONNECTION BABE. Sending our name")
	conn.Write([]byte(myname+"\n"));
	username, err := bufio.NewReader(conn).ReadString('\n')
	if err != nil {
		return
	}
	username=strings.TrimSpace(username)
	fmt.Println("Received username: "+username)
	//here make sure that username is valid
	peerObj:=Peer{conn:conn,username:username}
	peerChannel<-peerObj
}
func onConnClose(peer Peer){
	//remove from list of peers, but idk how to do that in go =(
	fmt.Println("Disconnected from "+peer.username)
}
func peerListen(peer Peer){
	defer peer.conn.Close()
	defer onConnClose(peer)
	conn:=peer.conn
	username:=peer.username
	fmt.Println("Beginning to listen to "+username)
	for {
		message, err := bufio.NewReader(conn).ReadString('\n')
		if err!=nil{
			return
		}
		message=strings.TrimSpace(message)
		onMessageReceived(message,peer)
	}
}
func peerWithName(name string) int{
	for i:=0; i<len(peers); i++{
		if peers[i].username == name{
			return i
		}
	}
	return -1
}
func listen() {
	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		panic(err)
	}
	defer ln.Close()
	peerChannel := make(chan Peer)
	defer close(peerChannel)
	go func(){
		for{
			peer,ok := <-peerChannel
			if ok{
				if peerWithName(peer.username)==-1{
					peers = append(peers,peer)
					go peerListen(peer)
				}else{
				 	peer.conn.Close()
					fmt.Println("Sadly we are already connected to "+peer.username+". Disconnecting")
				}
			}else{
				return
			}
		}
	}()
	for {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
		go handleConn(conn,peerChannel)
	}
}

func printAll(stringChanChan <-chan chan string) {
	for {
		strChan := <-stringChanChan
		for{
			str, ok:= <-strChan
			if ok{
				fmt.Printf(str)
			}else{
				break
			}
		}
		fmt.Println()
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strconv"

	"time"

	"strings"

	"syscall"

	"os/signal"

	"github.com/claudetech/loggo"
	. "github.com/claudetech/loggo/default"
	flag "github.com/ogier/pflag"
	"golang.org/x/sys/unix"
)

func main() {
	// get the users home dir
	user, err := user.Current()
	if nil != err {
		panic(fmt.Sprintf("Could not read users homedir %v\n", err))
	}

	// parse the command line arguments
	argLogLevel := flag.IntP("verbosity", "v", 0, "Set the log level (0 = error, 1 = warn, 2 = info, 3 = debug, 4 = trace)")
	argConfigPath := flag.StringP("config", "c", filepath.Join(user.HomeDir, ".plexdrive"), "The path to the configuration directory")
	argTempPath := flag.StringP("temp", "t", os.TempDir(), "Path to a temporary directory to store temporary data")
	argChunkSize := flag.String("chunk-size", "5M", "The size of each chunk that is downloaded (units: B, K, M, G)")
	argRefreshInterval := flag.Duration("refresh-interval", 5*time.Minute, "The time to wait till checking for changes")
	argClearInterval := flag.Duration("clear-chunk-interval", 1*time.Minute, "The time to wait till clearing the chunk directory")
	argClearChunkAge := flag.Duration("clear-chunk-age", 30*time.Minute, "The maximum age of a cached chunk file")
	argClearChunkMaxSize := flag.String("clear-chunk-max-size", "", "The maximum size of the temporary chunk directory (units: B, K, M, G)")
	argMountOptions := flag.StringP("fuse-options", "o", "", "Fuse mount options (e.g. -fuse-options allow_other,...)")
	argVersion := flag.Bool("version", false, "Displays program's version information")
	argUID := flag.Int64("uid", -1, "Set the mounts UID (-1 = default permissions)")
	argGID := flag.Int64("gid", -1, "Set the mounts GID (-1 = default permissions)")
	argUmask := flag.Uint32("umask", 0, "Override the default file permissions")
	argDownloadSpeedLimit := flag.String("speed-limit", "", "This value limits the download speed, e.g. 5M = 5MB/s (units: B, K, M, G)")
	flag.Parse()

	// display version information
	if *argVersion {
		fmt.Println("2.2.0")
		return
	}

	// check if mountpoint is specified
	argMountPoint := flag.Arg(0)
	if "" == argMountPoint {
		flag.Usage()
		panic(fmt.Errorf("Mountpoint not specified"))
	}

	// calculate uid / gid
	uid := uint32(unix.Geteuid())
	gid := uint32(unix.Getegid())
	if *argUID > -1 {
		uid = uint32(*argUID)
	}
	if *argGID > -1 {
		gid = uint32(*argGID)
	}

	// parse filemode
	umask := os.FileMode(*argUmask)

	// parse the mount options
	var mountOptions []string
	if "" != *argMountOptions {
		mountOptions = strings.Split(*argMountOptions, ",")
	}

	// initialize the logger with the specific log level
	var logLevel loggo.Level
	switch *argLogLevel {
	case 0:
		logLevel = loggo.Error
	case 1:
		logLevel = loggo.Warning
	case 2:
		logLevel = loggo.Info
	case 3:
		logLevel = loggo.Debug
	case 4:
		logLevel = loggo.Trace
	default:
		logLevel = loggo.Warning
	}
	Log.SetLevel(logLevel)

	// debug all given parameters
	Log.Debugf("verbosity            : %v", logLevel)
	Log.Debugf("config               : %v", *argConfigPath)
	Log.Debugf("temp                 : %v", *argTempPath)
	Log.Debugf("chunk-size           : %v", *argChunkSize)
	Log.Debugf("refresh-interval     : %v", *argRefreshInterval)
	Log.Debugf("clear-chunk-interval : %v", *argClearInterval)
	Log.Debugf("clear-chunk-age      : %v", *argClearChunkAge)
	Log.Debugf("clear-chunk-max-size : %v", *argClearChunkMaxSize)
	Log.Debugf("fuse-options         : %v", *argMountOptions)
	Log.Debugf("UID                  : %v", uid)
	Log.Debugf("GID                  : %v", gid)
	Log.Debugf("Umask                : %v", umask)
	Log.Debugf("speed-limit          : %v", *argDownloadSpeedLimit)
	// version missing here

	// create all directories
	if err := os.MkdirAll(*argConfigPath, 0766); nil != err {
		Log.Errorf("Could not create configuration directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}
	chunkPath := filepath.Join(*argTempPath, "chunks")
	if err := os.MkdirAll(chunkPath, 0777); nil != err {
		Log.Errorf("Could not create temp chunk directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}

	// set the global buffer configuration
	SetChunkPath(chunkPath)
	chunkSize, err := parseSizeArg(*argChunkSize)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetChunkSize(chunkSize)
	clearMaxChunkSize, err := parseSizeArg(*argClearChunkMaxSize)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetChunkDirMaxSize(clearMaxChunkSize)
	downloadSpeedLimit, err := parseSizeArg(*argDownloadSpeedLimit)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetDownloadSpeedLimit(downloadSpeedLimit)

	// read the configuration
	configPath := filepath.Join(*argConfigPath, "config.json")
	config, err := ReadConfig(configPath)
	if nil != err {
		config, err = CreateConfig(configPath)
		if nil != err {
			Log.Errorf("Could not read configuration")
			Log.Debugf("%v", err)
			os.Exit(3)
		}
	}

	cache, err := NewCache(*argConfigPath, *argLogLevel > 3)
	if nil != err {
		Log.Errorf("Could not initialize cache")
		Log.Debugf("%v", err)
		os.Exit(4)
	}
	defer cache.Close()

	drive, err := NewDriveClient(config, cache, *argRefreshInterval)
	if nil != err {
		Log.Errorf("Could not initialize Google Drive Client")
		Log.Debugf("%v", err)
		os.Exit(4)
	}

	// check os signals like SIGINT/TERM
	checkOsSignals(argMountPoint)
	go CleanChunkDir(chunkPath, *argClearInterval, *argClearChunkAge, clearMaxChunkSize)
	if err := Mount(drive, argMountPoint, mountOptions, uid, gid, umask); nil != err {
		Log.Debugf("%v", err)
		os.Exit(5)
	}
}

func checkOsSignals(mountpoint string) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT)

	go func() {
		for sig := range signals {
			if sig == syscall.SIGINT {
				if err := Unmount(mountpoint, false); nil != err {
					Log.Warningf("%v", err)
				}
			}
		}
	}()
}

func parseSizeArg(input string) (int64, error) {
	if "" == input {
		return 0, nil
	}

	suffix := input[len(input)-1]
	suffixLen := 1
	var multiplier float64
	switch suffix {
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
		suffixLen = 0
	case 'b', 'B':
		multiplier = 1
	case 'k', 'K':
		multiplier = 1024
	case 'm', 'M':
		multiplier = 1024 * 1024
	case 'g', 'G':
		multiplier = 1024 * 1024 * 1024
	default:
		return 0, fmt.Errorf("Invalid unit %v for %v", suffix, input)
	}
	input = input[:len(input)-suffixLen]
	value, err := strconv.ParseFloat(input, 64)
	if nil != err {
		Log.Debugf("%v", err)
		return 0, fmt.Errorf("Could not parse numeric value %v", input)
	}
	if value < 0 {
		return 0, fmt.Errorf("Numeric value must not be negative %v", input)
	}
	value *= multiplier
	return int64(value), nil
}
<commit_msg>upgraded version to 3.0.0<commit_after>package main

import (
	"fmt"
	"os"
	"os/user"
	"path/filepath"
	"strconv"

	"time"

	"strings"

	"syscall"

	"os/signal"

	"github.com/claudetech/loggo"
	. "github.com/claudetech/loggo/default"
	flag "github.com/ogier/pflag"
	"golang.org/x/sys/unix"
)

func main() {
	// get the users home dir
	user, err := user.Current()
	if nil != err {
		panic(fmt.Sprintf("Could not read users homedir %v\n", err))
	}

	// parse the command line arguments
	argLogLevel := flag.IntP("verbosity", "v", 0, "Set the log level (0 = error, 1 = warn, 2 = info, 3 = debug, 4 = trace)")
	argConfigPath := flag.StringP("config", "c", filepath.Join(user.HomeDir, ".plexdrive"), "The path to the configuration directory")
	argTempPath := flag.StringP("temp", "t", os.TempDir(), "Path to a temporary directory to store temporary data")
	argChunkSize := flag.String("chunk-size", "5M", "The size of each chunk that is downloaded (units: B, K, M, G)")
	argRefreshInterval := flag.Duration("refresh-interval", 5*time.Minute, "The time to wait till checking for changes")
	argClearInterval := flag.Duration("clear-chunk-interval", 1*time.Minute, "The time to wait till clearing the chunk directory")
	argClearChunkAge := flag.Duration("clear-chunk-age", 30*time.Minute, "The maximum age of a cached chunk file")
	argClearChunkMaxSize := flag.String("clear-chunk-max-size", "", "The maximum size of the temporary chunk directory (units: B, K, M, G)")
	argMountOptions := flag.StringP("fuse-options", "o", "", "Fuse mount options (e.g. -fuse-options allow_other,...)")
	argVersion := flag.Bool("version", false, "Displays program's version information")
	argUID := flag.Int64("uid", -1, "Set the mounts UID (-1 = default permissions)")
	argGID := flag.Int64("gid", -1, "Set the mounts GID (-1 = default permissions)")
	argUmask := flag.Uint32("umask", 0, "Override the default file permissions")
	argDownloadSpeedLimit := flag.String("speed-limit", "", "This value limits the download speed, e.g. 5M = 5MB/s (units: B, K, M, G)")
	flag.Parse()

	// display version information
	if *argVersion {
		fmt.Println("3.0.0")
		return
	}

	// check if mountpoint is specified
	argMountPoint := flag.Arg(0)
	if "" == argMountPoint {
		flag.Usage()
		panic(fmt.Errorf("Mountpoint not specified"))
	}

	// calculate uid / gid
	uid := uint32(unix.Geteuid())
	gid := uint32(unix.Getegid())
	if *argUID > -1 {
		uid = uint32(*argUID)
	}
	if *argGID > -1 {
		gid = uint32(*argGID)
	}

	// parse filemode
	umask := os.FileMode(*argUmask)

	// parse the mount options
	var mountOptions []string
	if "" != *argMountOptions {
		mountOptions = strings.Split(*argMountOptions, ",")
	}

	// initialize the logger with the specific log level
	var logLevel loggo.Level
	switch *argLogLevel {
	case 0:
		logLevel = loggo.Error
	case 1:
		logLevel = loggo.Warning
	case 2:
		logLevel = loggo.Info
	case 3:
		logLevel = loggo.Debug
	case 4:
		logLevel = loggo.Trace
	default:
		logLevel = loggo.Warning
	}
	Log.SetLevel(logLevel)

	// debug all given parameters
	Log.Debugf("verbosity            : %v", logLevel)
	Log.Debugf("config               : %v", *argConfigPath)
	Log.Debugf("temp                 : %v", *argTempPath)
	Log.Debugf("chunk-size           : %v", *argChunkSize)
	Log.Debugf("refresh-interval     : %v", *argRefreshInterval)
	Log.Debugf("clear-chunk-interval : %v", *argClearInterval)
	Log.Debugf("clear-chunk-age      : %v", *argClearChunkAge)
	Log.Debugf("clear-chunk-max-size : %v", *argClearChunkMaxSize)
	Log.Debugf("fuse-options         : %v", *argMountOptions)
	Log.Debugf("UID                  : %v", uid)
	Log.Debugf("GID                  : %v", gid)
	Log.Debugf("Umask                : %v", umask)
	Log.Debugf("speed-limit          : %v", *argDownloadSpeedLimit)
	// version missing here

	// create all directories
	if err := os.MkdirAll(*argConfigPath, 0766); nil != err {
		Log.Errorf("Could not create configuration directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}
	chunkPath := filepath.Join(*argTempPath, "chunks")
	if err := os.MkdirAll(chunkPath, 0777); nil != err {
		Log.Errorf("Could not create temp chunk directory")
		Log.Debugf("%v", err)
		os.Exit(1)
	}

	// set the global buffer configuration
	SetChunkPath(chunkPath)
	chunkSize, err := parseSizeArg(*argChunkSize)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetChunkSize(chunkSize)
	clearMaxChunkSize, err := parseSizeArg(*argClearChunkMaxSize)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetChunkDirMaxSize(clearMaxChunkSize)
	downloadSpeedLimit, err := parseSizeArg(*argDownloadSpeedLimit)
	if nil != err {
		Log.Errorf("%v", err)
		os.Exit(2)
	}
	SetDownloadSpeedLimit(downloadSpeedLimit)

	// read the configuration
	configPath := filepath.Join(*argConfigPath, "config.json")
	config, err := ReadConfig(configPath)
	if nil != err {
		config, err = CreateConfig(configPath)
		if nil != err {
			Log.Errorf("Could not read configuration")
			Log.Debugf("%v", err)
			os.Exit(3)
		}
	}

	cache, err := NewCache(*argConfigPath, *argLogLevel > 3)
	if nil != err {
		Log.Errorf("Could not initialize cache")
		Log.Debugf("%v", err)
		os.Exit(4)
	}
	defer cache.Close()

	drive, err := NewDriveClient(config, cache, *argRefreshInterval)
	if nil != err {
		Log.Errorf("Could not initialize Google Drive Client")
		Log.Debugf("%v", err)
		os.Exit(4)
	}

	// check os signals like SIGINT/TERM
	checkOsSignals(argMountPoint)
	go CleanChunkDir(chunkPath, *argClearInterval, *argClearChunkAge, clearMaxChunkSize)
	if err := Mount(drive, argMountPoint, mountOptions, uid, gid, umask); nil != err {
		Log.Debugf("%v", err)
		os.Exit(5)
	}
}

func checkOsSignals(mountpoint string) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT)

	go func() {
		for sig := range signals {
			if sig == syscall.SIGINT {
				if err := Unmount(mountpoint, false); nil != err {
					Log.Warningf("%v", err)
				}
			}
		}
	}()
}

func parseSizeArg(input string) (int64, error) {
	if "" == input {
		return 0, nil
	}

	suffix := input[len(input)-1]
	suffixLen := 1
	var multiplier float64
	switch suffix {
	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.':
		suffixLen = 0
	case 'b', 'B':
		multiplier = 1
	case 'k', 'K':
		multiplier = 1024
	case 'm', 'M':
		multiplier = 1024 * 1024
	case 'g', 'G':
		multiplier = 1024 * 1024 * 1024
	default:
		return 0, fmt.Errorf("Invalid unit %v for %v", suffix, input)
	}
	input = input[:len(input)-suffixLen]
	value, err := strconv.ParseFloat(input, 64)
	if nil != err {
		Log.Debugf("%v", err)
		return 0, fmt.Errorf("Could not parse numeric value %v", input)
	}
	if value < 0 {
		return 0, fmt.Errorf("Numeric value must not be negative %v", input)
	}
	value *= multiplier
	return int64(value), nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

type TestCase struct {
	Description string `json:"description"`
	Calls       []Call `json:"calls"`
}

type Call struct {
	On       On                `json:"on"`
	Expect   Expect            `json:"expect"`
	Remember map[string]string `json:"remember"`
}

type On struct {
	Method  string            `json:"method"`
	Url     string            `json:"url"`
	Headers map[string]string `json:"headers"`
	Params  map[string]string `json:"params"`
	Body    string            `json:"body"`
}

type Expect struct {
	StatusCode  int               `json:"statusCode"`
	ContentType string            `json:"contentType"`
	Body        map[string]string `json:"body"`
	BodySchema  string            `json:"bodySchema"`
}

var (
	suiteDir = flag.String("d", ".", "Path to the directory that contains test suite.")
	host     = flag.String("h", "http://localhost:8080", "Test server address")
)

func main() {
	flag.Parse()

	loader := testCaseLoader{}
	testCases, err := loader.loadDir(*suiteDir)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}

	//fmt.Printf("Test Cases: %v\n", testCases)

	rememberedMap := make(map[string]string)
	failedExpectations := []string{}

	var callFailedExpectations []string
	var callErrs []error

	reporter := NewConsoleReporter()

	// test case runner?
	for _, testCase := range testCases {
		for _, c := range testCase.Calls {
			callFailedExpectations, err = call(testCase, c, reporter, rememberedMap)
			if err != nil {
				callErrs = append(callErrs, err)
			}
			failedExpectations = append(failedExpectations, callFailedExpectations...)
		}
	}

	reporter.Flush()
}

type testCaseLoader struct {
	tests []TestCase
}

func (s *testCaseLoader) loadDir(dir string) ([]TestCase, error) {
	err := filepath.Walk(dir, s.loadFile)
	if err != nil {
		return nil, err
	}

	return s.tests, nil
}

func (s *testCaseLoader) loadFile(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	if !strings.HasSuffix(info.Name(), ".json") {
		return nil
	}

	fmt.Printf("Process file: %s\n", info.Name())
	content, e := ioutil.ReadFile(path)

	if e != nil {
		fmt.Printf("File error: %v\n", e)
		return nil
	}

	var testCases []TestCase
	err = json.Unmarshal(content, &testCases)
	if err != nil {
		fmt.Printf("Parse error: %v\n", err)
		return nil
	}

	s.tests = append(s.tests, testCases...)
	return nil
}

func call(testCase TestCase, call Call, reporter Reporter, rememberMap map[string]string) (failedExpectations []string, err error) {
	on := call.On

	req, _ := http.NewRequest(on.Method, *host+on.Url, bytes.NewBuffer([]byte(on.Body)))

	for key, value := range on.Headers {
		req.Header.Add(key, putRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, putRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()
	// fmt.Println(req)

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		fmt.Println("Error when sending request", err)
		return
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response")
		return
	}

	//fmt.Printf("Code: %v\n", resp.Status)
	// fmt.Printf("Resp: %v\n", string(body))

	testResp := Response{http: *resp, body: body}
	result := TestResult{Case: testCase, Resp: testResp}

	exps := expectations(call)
	for _, exp := range exps {
		checkErr := exp.check(testResp)
		if checkErr != nil {
			result.Cause = checkErr
			failedExpectations = append(failedExpectations, checkErr.Error())

			break
		}
	}
	reporter.Report(result)

	err = remember(testResp.bodyAsMap(), call.Remember, rememberMap)
	fmt.Printf("rememberMap: %v\n", rememberMap)
	if err != nil {
		fmt.Println("Error remember")
		return
	}

	return
}

func putRememberedVars(str string, rememberMap map[string]string) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, val, -1)
	}
	return res
}

func expectations(call Call) []ResponseExpectation {
	var exps []ResponseExpectation

	if call.Expect.StatusCode != -1 {
		exps = append(exps, StatusExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.BodySchema != "" {
		// for now use path relative to suiteDir
		uri, err := filepath.Abs(*suiteDir)
		if err != nil {
			fmt.Println(err)
		}

		uri = "file:///" + filepath.ToSlash(filepath.Join(uri, call.Expect.BodySchema))
		exps = append(exps, BodySchemaExpectation{schemaURI: uri})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	// and so on
	return exps
}

func remember(bodyMap map[string]interface{}, remember map[string]string, rememberedMap map[string]string) (err error) {

	for varName, path := range remember {

		splitPath := strings.Split(path, ".")

		rememberVar := getByPath(bodyMap, splitPath...)
		if rememberVar != nil {
			rememberedMap[varName] = rememberVar.(string)
		} else {
			err = errors.New("Remembered value not found: %v\n")
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))

	}

	return err
}

func getByPath(m interface{}, path ...string) interface{} {

	for _, p := range path {
		//fmt.Println(p)
		idx, err := strconv.Atoi(p)
		if err != nil {
			m = m.(map[string]interface{})[p]
		} else {
			m = m.([]interface{})[idx]
		}

	}
	return m
}

func searchByPath(m interface{}, s string, path ...string) bool {
	for idx, p := range path {
		//fmt.Println("s ", idx, "p ", p)
		// TODO refactor to separate function part from path parts
		if idx == len(path)-1 {
			if p == "size()" {
				if arr, ok := m.([]interface{}); ok {
					arrLen, err := strconv.Atoi(s)
					if err == nil && arrLen == len(arr) {
						return true
					}
				}
			}
		} // last path part could be a function

		switch typedM := m.(type) {
		case map[string]interface{}:
			m = typedM[p]
			//fmt.Println("[",m, "] [", s,"]", reflect.TypeOf(m))

			if str, ok := m.(string); ok {
				if str == s {
					return true
				}
			} else if flt, ok := m.(float64); ok {
				// numbers (like ids) are parsed as float64 from json
				if strconv.FormatFloat(flt, 'f', 0, 64) == s {
					return true
				}
			}
		case []interface{}:
			//fmt.Println("path ", path[idx:])
			for _, obj := range typedM {
				found := searchByPath(obj, s, path[idx:]...)
				if found {
					return true
				}
			}
		}

	}

	return false
}

type TestResult struct {
	Case TestCase
	Resp Response
	// in case test failed, cause must be specified
	Cause error
}

type Response struct {
	http http.Response
	body []byte
}

func (e Response) bodyAsMap() map[string]interface{} {
	var bodyMap map[string]interface{}
	var err error

	contentType, _, _ := mime.ParseMediaType(e.http.Header.Get("content-type"))
	if contentType == "application/xml" {
		err = xml.Unmarshal(e.body, &bodyMap)
	}
	if contentType == "application/json" {
		err = json.Unmarshal(e.body, &bodyMap)
	}

	if err != nil {
		panic(err.Error())
	}

	return bodyMap
}

type ResponseExpectation interface {
	check(resp Response) error
}

type StatusExpectation struct {
	statusCode int
}

func (e StatusExpectation) check(resp Response) error {
	if resp.http.StatusCode != e.statusCode {
		msg := fmt.Sprintf("Unexpected Status Code. Expected: %d, Actual: %d", e.statusCode, resp.http.StatusCode)
		return errors.New(msg)
	}
	return nil
}

type BodySchemaExpectation struct {
	schemaURI string
}

func (e BodySchemaExpectation) check(resp Response) error {
	schemaLoader := gojsonschema.NewReferenceLoader(e.schemaURI)
	documentLoader := gojsonschema.NewStringLoader(string(resp.body))

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		panic(err.Error())
	}

	if !result.Valid() {
		msg := "Unexpected Body Schema:\n"
		for _, desc := range result.Errors() {
			msg = fmt.Sprintf(msg+"%s\n", desc)
		}
		return errors.New(msg)
	}

	return nil
}

type BodyExpectation struct {
	pathExpectations map[string]string
}

func (e BodyExpectation) check(resp Response) error {

	errs := []string{}
	for path, expectedValue := range e.pathExpectations {
		splitPath := strings.Split(path, ".")
		// TODO need rememberedMap here:  expectedValue = putRememberedVars(expectedValue, rememberedMap)
		found := searchByPath(resp.bodyAsMap(), expectedValue, splitPath...)
		if !found {
			err := "Expected value: [" + expectedValue + "] on path: [" + path + "] is not found" // TODO specific message for functions
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		var msg string
		for _, err := range errs {
			msg += err + "\n"
		}
		return errors.New(msg)
	}

	return nil
}

// TODO exit with non-zero if has failed tests
// TODO jenkins
// TODO expect response headers
// TODO xml support

// TODO "description" in Call for better reporting
// TODO on.body loading from file (move large files out of test case json)
// TODO matchers: not() ?
// TODO rename remember > keep or memo ?
<commit_msg>added header expectation. support special cases as content-type<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/xeipuuv/gojsonschema"
)

type TestCase struct {
	Description string `json:"description"`
	Calls       []Call `json:"calls"`
}

type Call struct {
	On       On                `json:"on"`
	Expect   Expect            `json:"expect"`
	Remember map[string]string `json:"remember"`
}

type On struct {
	Method  string            `json:"method"`
	Url     string            `json:"url"`
	Headers map[string]string `json:"headers"`
	Params  map[string]string `json:"params"`
	Body    string            `json:"body"`
}

type Expect struct {
	StatusCode  int               `json:"statusCode"`
	ContentType string            `json:"contentType"`
	Body        map[string]string `json:"body"`
	BodySchema  string            `json:"bodySchema"`
}

var (
	suiteDir = flag.String("d", ".", "Path to the directory that contains test suite.")
	host     = flag.String("h", "http://localhost:8080", "Test server address")
)

func main() {
	flag.Parse()

	loader := testCaseLoader{}
	testCases, err := loader.loadDir(*suiteDir)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}

	//fmt.Printf("Test Cases: %v\n", testCases)

	rememberedMap := make(map[string]string)
	failedExpectations := []string{}

	var callFailedExpectations []string
	var callErrs []error

	reporter := NewConsoleReporter()

	// test case runner?
	for _, testCase := range testCases {
		for _, c := range testCase.Calls {
			callFailedExpectations, err = call(testCase, c, reporter, rememberedMap)
			if err != nil {
				callErrs = append(callErrs, err)
			}
			failedExpectations = append(failedExpectations, callFailedExpectations...)
		}
	}

	reporter.Flush()
}

type testCaseLoader struct {
	tests []TestCase
}

func (s *testCaseLoader) loadDir(dir string) ([]TestCase, error) {
	err := filepath.Walk(dir, s.loadFile)
	if err != nil {
		return nil, err
	}

	return s.tests, nil
}

func (s *testCaseLoader) loadFile(path string, info os.FileInfo, err error) error {
	if err != nil {
		return nil
	}

	if info.IsDir() {
		return nil
	}

	if !strings.HasSuffix(info.Name(), ".json") {
		return nil
	}

	fmt.Printf("Process file: %s\n", info.Name())
	content, e := ioutil.ReadFile(path)

	if e != nil {
		fmt.Printf("File error: %v\n", e)
		return nil
	}

	var testCases []TestCase
	err = json.Unmarshal(content, &testCases)
	if err != nil {
		fmt.Printf("Parse error: %v\n", err)
		return nil
	}

	s.tests = append(s.tests, testCases...)
	return nil
}

func call(testCase TestCase, call Call, reporter Reporter, rememberMap map[string]string) (failedExpectations []string, err error) {
	on := call.On

	req, _ := http.NewRequest(on.Method, *host+on.Url, bytes.NewBuffer([]byte(on.Body)))

	for key, value := range on.Headers {
		req.Header.Add(key, putRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, putRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()
	// fmt.Println(req)

	client := &http.Client{}
	resp, err := client.Do(req)

	if err != nil {
		fmt.Println("Error when sending request", err)
		return
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error reading response")
		return
	}

	//fmt.Printf("Code: %v\n", resp.Status)
	// fmt.Printf("Resp: %v\n", string(body))

	testResp := Response{http: *resp, body: body}
	result := TestResult{Case: testCase, Resp: testResp}

	exps := expectations(call)
	for _, exp := range exps {
		checkErr := exp.check(testResp)
		if checkErr != nil {
			result.Cause = checkErr
			failedExpectations = append(failedExpectations, checkErr.Error())

			break
		}
	}
	reporter.Report(result)

	err = remember(testResp.bodyAsMap(), call.Remember, rememberMap)
	fmt.Printf("rememberMap: %v\n", rememberMap)
	if err != nil {
		fmt.Println("Error remember")
		return
	}

	return
}

func putRememberedVars(str string, rememberMap map[string]string) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, val, -1)
	}
	return res
}

func expectations(call Call) []ResponseExpectation {
	var exps []ResponseExpectation

	if call.Expect.StatusCode != -1 {
		exps = append(exps, StatusExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.BodySchema != "" {
		// for now use path relative to suiteDir
		uri, err := filepath.Abs(*suiteDir)
		if err != nil {
			fmt.Println(err)
		}

		uri = "file:///" + filepath.ToSlash(filepath.Join(uri, call.Expect.BodySchema))
		exps = append(exps, BodySchemaExpectation{schemaURI: uri})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	if call.Expect.ContentType != "" {
		extractFunc := func(resp http.Response) string {
			contentType, _, _ := mime.ParseMediaType(resp.Header.Get("content-type"))
			return contentType
		}
		exps = append(exps, HeaderExpectation{"content-type", call.Expect.ContentType, extractFunc})
	}

	// and so on
	return exps
}

func remember(bodyMap map[string]interface{}, remember map[string]string, rememberedMap map[string]string) (err error) {

	for varName, path := range remember {

		splitPath := strings.Split(path, ".")

		rememberVar := getByPath(bodyMap, splitPath...)
		if rememberVar != nil {
			rememberedMap[varName] = rememberVar.(string)
		} else {
			err = errors.New("Remembered value not found: %v\n")
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))

	}

	return err
}

func getByPath(m interface{}, path ...string) interface{} {

	for _, p := range path {
		//fmt.Println(p)
		idx, err := strconv.Atoi(p)
		if err != nil {
			m = m.(map[string]interface{})[p]
		} else {
			m = m.([]interface{})[idx]
		}

	}
	return m
}

func searchByPath(m interface{}, s string, path ...string) bool {
	for idx, p := range path {
		//fmt.Println("s ", idx, "p ", p)
		// TODO refactor to separate function part from path parts
		if idx == len(path)-1 {
			if p == "size()" {
				if arr, ok := m.([]interface{}); ok {
					arrLen, err := strconv.Atoi(s)
					if err == nil && arrLen == len(arr) {
						return true
					}
				}
			}
		} // last path part could be a function

		switch typedM := m.(type) {
		case map[string]interface{}:
			m = typedM[p]
			//fmt.Println("[",m, "] [", s,"]", reflect.TypeOf(m))

			if str, ok := m.(string); ok {
				if str == s {
					return true
				}
			} else if flt, ok := m.(float64); ok {
				// numbers (like ids) are parsed as float64 from json
				if strconv.FormatFloat(flt, 'f', 0, 64) == s {
					return true
				}
			}
		case []interface{}:
			//fmt.Println("path ", path[idx:])
			for _, obj := range typedM {
				found := searchByPath(obj, s, path[idx:]...)
				if found {
					return true
				}
			}
		}

	}

	return false
}

type TestResult struct {
	Case TestCase
	Resp Response
	// in case test failed, cause must be specified
	Cause error
}

type Response struct {
	http http.Response
	body []byte
}

func (e Response) bodyAsMap() map[string]interface{} {
	var bodyMap map[string]interface{}
	var err error

	contentType, _, _ := mime.ParseMediaType(e.http.Header.Get("content-type"))
	if contentType == "application/xml" {
		err = xml.Unmarshal(e.body, &bodyMap)
	}
	if contentType == "application/json" {
		err = json.Unmarshal(e.body, &bodyMap)
	}

	if err != nil {
		panic(err.Error())
	}

	return bodyMap
}

type ResponseExpectation interface {
	check(resp Response) error
}

type StatusExpectation struct {
	statusCode int
}

func (e StatusExpectation) check(resp Response) error {
	if resp.http.StatusCode != e.statusCode {
		msg := fmt.Sprintf("Unexpected Status Code. Expected: %d, Actual: %d", e.statusCode, resp.http.StatusCode)
		return errors.New(msg)
	}
	return nil
}

type BodySchemaExpectation struct {
	schemaURI string
}

func (e BodySchemaExpectation) check(resp Response) error {
	schemaLoader := gojsonschema.NewReferenceLoader(e.schemaURI)
	documentLoader := gojsonschema.NewStringLoader(string(resp.body))

	result, err := gojsonschema.Validate(schemaLoader, documentLoader)
	if err != nil {
		panic(err.Error())
	}

	if !result.Valid() {
		msg := "Unexpected Body Schema:\n"
		for _, desc := range result.Errors() {
			msg = fmt.Sprintf(msg+"%s\n", desc)
		}
		return errors.New(msg)
	}

	return nil
}

type BodyExpectation struct {
	pathExpectations map[string]string
}

func (e BodyExpectation) check(resp Response) error {

	errs := []string{}
	for path, expectedValue := range e.pathExpectations {
		splitPath := strings.Split(path, ".")
		// TODO need rememberedMap here:  expectedValue = putRememberedVars(expectedValue, rememberedMap)
		found := searchByPath(resp.bodyAsMap(), expectedValue, splitPath...)
		if !found {
			err := "Expected value: [" + expectedValue + "] on path: [" + path + "] is not found" // TODO specific message for functions
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		var msg string
		for _, err := range errs {
			msg += err + "\n"
		}
		return errors.New(msg)
	}

	return nil
}

type HeaderExpectation struct {
	headerName  string
	headerValue string
	extractFunc func(http.Response) string
}

func (e HeaderExpectation) check(resp Response) error {
	var value string
	if e.extractFunc == nil {
		value = resp.http.Header.Get(e.headerName)
	} else {
		value = e.extractFunc(resp.http)
	}

	value = strings.TrimSpace(value)
	if value == "" {
		return fmt.Errorf("Missing header. Expected \"%s: %s\"", e.headerName, e.headerValue)
	}
	if e.headerValue != "" && e.headerValue != value {
		msg := "Unexpected header. Expected \"%s: %s\". Actual \"%s: %s\""
		return fmt.Errorf(msg, e.headerName, e.headerValue, e.headerName, value)
	}
	return nil
}

// TODO exit with non-zero if has failed tests
// TODO jenkins
// TODO expect response headers
// TODO xml support

// TODO "description" in Call for better reporting
// TODO on.body loading from file (move large files out of test case json)
// TODO matchers: not() ?
// TODO rename remember > keep or memo ?
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"

	"github.com/apcera/nats"
	cf_debug_server "github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/routing-api"
	token_fetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gorouter/access_log"
	vcap "github.com/cloudfoundry/gorouter/common"
	"github.com/cloudfoundry/gorouter/config"
	"github.com/cloudfoundry/gorouter/proxy"
	rregistry "github.com/cloudfoundry/gorouter/registry"
	"github.com/cloudfoundry/gorouter/route_fetcher"
	"github.com/cloudfoundry/gorouter/router"
	rvarz "github.com/cloudfoundry/gorouter/varz"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/yagnats"

	"flag"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"
)

var configFile string

func init() {
	flag.StringVar(&configFile, "c", "", "Configuration File")

	flag.Parse()
}

func main() {
	c := config.DefaultConfig()
	logCounter := vcap.NewLogCounter()

	if configFile != "" {
		c = config.InitConfigFromFile(configFile)
	}

	InitLoggerFromConfig(c, logCounter)
	logger := steno.NewLogger("router.main")

	err := dropsonde.Initialize(c.Logging.MetronAddress, c.Logging.JobName)
	if err != nil {
		logger.Errorf("Dropsonde failed to initialize: %s", err.Error())
		os.Exit(1)
	}

	// setup number of procs
	if c.GoMaxProcs != 0 {
		runtime.GOMAXPROCS(c.GoMaxProcs)
	}

	if c.DebugAddr != "" {
		cf_debug_server.Run(c.DebugAddr)
	}

	natsServers := c.NatsServers()
	var natsClient yagnats.NATSConn
	attempts := 3
	for attempts > 0 {
		natsClient, err = yagnats.Connect(natsServers)
		if err == nil {
			break
		} else {
			attempts--
			time.Sleep(100 * time.Millisecond)
		}
	}

	if err != nil {
		logger.Errorf("Error connecting to NATS: %s\n", err)
		os.Exit(1)
	}

	natsClient.AddClosedCB(func(conn *nats.Conn) {
		logger.Errorf("Close on NATS client. nats.Conn: %+v", *conn)
		os.Exit(1)
	})

	registry := rregistry.NewRouteRegistry(c, natsClient)

	if c.RoutingApiEnabled() {
		logger.Info("Setting up routing_api route fetcher")
		tokenFetcher := token_fetcher.NewTokenFetcher(&c.OAuth)
		routingApiUri := fmt.Sprintf("%s:%d", c.RoutingApi.Uri, c.RoutingApi.Port)
		routingApiClient := routing_api.NewClient(routingApiUri)
		routeFetcher := route_fetcher.NewRouteFetcher(steno.NewLogger("router.route_fetcher"), tokenFetcher, registry, c, routingApiClient, 1)
		routeFetcher.StartFetchCycle()
		routeFetcher.StartEventCycle()
	}

	varz := rvarz.NewVarz(registry)

	accessLogger, err := access_log.CreateRunningAccessLogger(c)
	if err != nil {
		logger.Fatalf("Error creating access logger: %s\n", err)
	}

	args := proxy.ProxyArgs{
		EndpointTimeout: c.EndpointTimeout,
		Ip:              c.Ip,
		TraceKey:        c.TraceKey,
		Registry:        registry,
		Reporter:        varz,
		AccessLogger:    accessLogger,
		SecureCookies:   c.SecureCookies,
		TLSConfig: &tls.Config{
			CipherSuites:       c.CipherSuites,
			InsecureSkipVerify: c.SSLSkipValidation,
		},
	}
	p := proxy.NewProxy(args)

	router, err := router.NewRouter(c, p, natsClient, registry, varz, logCounter)
	if err != nil {
		logger.Errorf("An error occurred: %s", err.Error())
		os.Exit(1)
	}

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)

	errChan := router.Run()

	logger.Info("gorouter.started")

	select {
	case err := <-errChan:
		if err != nil {
			logger.Errorf("Error occurred: %s", err.Error())
			os.Exit(1)
		}
	case sig := <-signals:
		go func() {
			for sig := range signals {
				logger.Infod(
					map[string]interface{}{
						"signal": sig.String(),
					},
					"gorouter.signal.ignored",
				)
			}
		}()

		if sig == syscall.SIGUSR1 {
			logger.Infod(
				map[string]interface{}{
					"timeout": (c.DrainTimeout).String(),
				},
				"gorouter.draining",
			)

			router.Drain(c.DrainTimeout)
		}

		stoppingAt := time.Now()

		logger.Info("gorouter.stopping")

		router.Stop()

		logger.Infod(
			map[string]interface{}{
				"took": time.Since(stoppingAt).String(),
			},
			"gorouter.stopped",
		)
	}

	os.Exit(0)
}

func InitLoggerFromConfig(c *config.Config, logCounter *vcap.LogCounter) {
	l, err := steno.GetLogLevel(c.Logging.Level)
	if err != nil {
		panic(err)
	}

	s := make([]steno.Sink, 0, 3)
	if c.Logging.File != "" {
		s = append(s, steno.NewFileSink(c.Logging.File))
	} else {
		s = append(s, steno.NewIOSink(os.Stdout))
	}

	if c.Logging.Syslog != "" {
		s = append(s, steno.NewSyslogSink(c.Logging.Syslog))
	}

	s = append(s, logCounter)

	stenoConfig := &steno.Config{
		Sinks: s,
		Codec: steno.NewJsonCodec(),
		Level: l,
	}

	steno.Init(stenoConfig)
}
<commit_msg>Refactor main.go into more readable funcs [#97578180]<commit_after>package main

import (
	"crypto/tls"

	"github.com/apcera/nats"
	cf_debug_server "github.com/cloudfoundry-incubator/cf-debug-server"
	"github.com/cloudfoundry-incubator/routing-api"
	token_fetcher "github.com/cloudfoundry-incubator/uaa-token-fetcher"
	"github.com/cloudfoundry/dropsonde"
	"github.com/cloudfoundry/gorouter/access_log"
	vcap "github.com/cloudfoundry/gorouter/common"
	"github.com/cloudfoundry/gorouter/config"
	"github.com/cloudfoundry/gorouter/proxy"
	rregistry "github.com/cloudfoundry/gorouter/registry"
	"github.com/cloudfoundry/gorouter/route_fetcher"
	"github.com/cloudfoundry/gorouter/router"
	rvarz "github.com/cloudfoundry/gorouter/varz"
	steno "github.com/cloudfoundry/gosteno"
	"github.com/cloudfoundry/yagnats"

	"flag"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"syscall"
	"time"
)

var configFile string

func init() {
	flag.StringVar(&configFile, "c", "", "Configuration File")

	flag.Parse()
}

func main() {
	c := config.DefaultConfig()
	logCounter := vcap.NewLogCounter()

	if configFile != "" {
		c = config.InitConfigFromFile(configFile)
	}

	InitLoggerFromConfig(c, logCounter)
	logger := steno.NewLogger("router.main")

	err := dropsonde.Initialize(c.Logging.MetronAddress, c.Logging.JobName)
	if err != nil {
		logger.Errorf("Dropsonde failed to initialize: %s", err.Error())
		os.Exit(1)
	}

	// setup number of procs
	if c.GoMaxProcs != 0 {
		runtime.GOMAXPROCS(c.GoMaxProcs)
	}

	if c.DebugAddr != "" {
		cf_debug_server.Run(c.DebugAddr)
	}

	logger.Info("Setting up NATs connection")
	natsClient := connectToNatsServer(c, logger)

	registry := rregistry.NewRouteRegistry(c, natsClient)

	logger.Info("Setting up routing_api route fetcher")
	setupRouteFetcher(c, registry)

	varz := rvarz.NewVarz(registry)

	accessLogger, err := access_log.CreateRunningAccessLogger(c)
	if err != nil {
		logger.Fatalf("Error creating access logger: %s\n", err)
	}

	proxy := buildProxy(c, registry, accessLogger, varz)

	router, err := router.NewRouter(c, proxy, natsClient, registry, varz, logCounter)
	if err != nil {
		logger.Errorf("An error occurred: %s", err.Error())
		os.Exit(1)
	}

	errChan := router.Run()

	logger.Info("gorouter.started")

	waitOnErrOrSignal(c, logger, errChan, router)

	os.Exit(0)
}

func waitOnErrOrSignal(c *config.Config, logger *steno.Logger, errChan <-chan error, router *router.Router) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)

	select {
	case err := <-errChan:
		if err != nil {
			logger.Errorf("Error occurred: %s", err.Error())
			os.Exit(1)
		}
	case sig := <-signals:
		go func() {
			for sig := range signals {
				logger.Infod(
					map[string]interface{}{
						"signal": sig.String(),
					},
					"gorouter.signal.ignored",
				)
			}
		}()

		if sig == syscall.SIGUSR1 {
			logger.Infod(
				map[string]interface{}{
					"timeout": (c.DrainTimeout).String(),
				},
				"gorouter.draining",
			)

			router.Drain(c.DrainTimeout)
		}

		stoppingAt := time.Now()

		logger.Info("gorouter.stopping")

		router.Stop()

		logger.Infod(
			map[string]interface{}{
				"took": time.Since(stoppingAt).String(),
			},
			"gorouter.stopped",
		)
	}
}

func buildProxy(c *config.Config, registry rregistry.RegistryInterface, accessLogger access_log.AccessLogger, varz rvarz.Varz) proxy.Proxy {
	args := proxy.ProxyArgs{
		EndpointTimeout: c.EndpointTimeout,
		Ip:              c.Ip,
		TraceKey:        c.TraceKey,
		Registry:        registry,
		Reporter:        varz,
		AccessLogger:    accessLogger,
		SecureCookies:   c.SecureCookies,
		TLSConfig: &tls.Config{
			CipherSuites:       c.CipherSuites,
			InsecureSkipVerify: c.SSLSkipValidation,
		},
	}
	return proxy.NewProxy(args)
}

func setupRouteFetcher(c *config.Config, registry rregistry.RegistryInterface) {
	if c.RoutingApiEnabled() {
		tokenFetcher := token_fetcher.NewTokenFetcher(&c.OAuth)
		routingApiUri := fmt.Sprintf("%s:%d", c.RoutingApi.Uri, c.RoutingApi.Port)
		routingApiClient := routing_api.NewClient(routingApiUri)
		routeFetcher := route_fetcher.NewRouteFetcher(steno.NewLogger("router.route_fetcher"), tokenFetcher, registry, c, routingApiClient, 1)
		routeFetcher.StartFetchCycle()
		routeFetcher.StartEventCycle()
	}
}

func connectToNatsServer(c *config.Config, logger *steno.Logger) yagnats.NATSConn {
	var natsClient yagnats.NATSConn
	var err error

	natsServers := c.NatsServers()
	attempts := 3
	for attempts > 0 {
		natsClient, err = yagnats.Connect(natsServers)
		if err == nil {
			break
		} else {
			attempts--
			time.Sleep(100 * time.Millisecond)
		}
	}

	if err != nil {
		logger.Errorf("Error connecting to NATS: %s\n", err)
		os.Exit(1)
	}

	natsClient.AddClosedCB(func(conn *nats.Conn) {
		logger.Errorf("Close on NATS client. nats.Conn: %+v", *conn)
		os.Exit(1)
	})

	return natsClient
}

func InitLoggerFromConfig(c *config.Config, logCounter *vcap.LogCounter) {
	l, err := steno.GetLogLevel(c.Logging.Level)
	if err != nil {
		panic(err)
	}

	s := make([]steno.Sink, 0, 3)
	if c.Logging.File != "" {
		s = append(s, steno.NewFileSink(c.Logging.File))
	} else {
		s = append(s, steno.NewIOSink(os.Stdout))
	}

	if c.Logging.Syslog != "" {
		s = append(s, steno.NewSyslogSink(c.Logging.Syslog))
	}

	s = append(s, logCounter)

	stenoConfig := &steno.Config{
		Sinks: s,
		Codec: steno.NewJsonCodec(),
		Level: l,
	}

	steno.Init(stenoConfig)
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"net/http"
	"os"

	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB
var err error

func init() {
	db, err = spl.Open("mysql",
		"user:password@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		fmt.Println(err)
	}
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	http.HandleFunc("/", Router)
	http.HandleFunc("/new/", AddURL)
	http.ListenAndServe(":"+port, nil)
}

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

}

func GetURL(w http.ResponseWriter, r *http.Request) {
	var shortUrl string
	err = db.QueryRow("SELECT original_url FROM urls WHERE short_url = ?", shortUrl)
}

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

}
<commit_msg>add variable for original url and error if statement<commit_after>package main

import (
	"database/sql"
	"fmt"
	"net/http"
	"os"

	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB
var err error

func init() {
	db, err = spl.Open("mysql",
		"user:password@tcp(127.0.0.1:3306)/hello")
	if err != nil {
		fmt.Println(err)
	}

	defer db.Close()
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	http.HandleFunc("/", Router)
	http.HandleFunc("/new/", AddURL)
	http.ListenAndServe(":"+port, nil)
}

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

}

func GetURL(w http.ResponseWriter, r *http.Request) {
	var shortUrl string
	var originalUrl string
	err = db.QueryRow("SELECT original_url FROM urls WHERE short_url = ?", shortUrl).Scan(&originalUrl)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println(originalUrl)
}

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

}
<|endoftext|>