<commit_before>//Command ponydownloader uses Derpibooru.org API to download pony images
//by ID or by tags, with some client-side filtration ability
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println("Derpibooru.org Downloader version 0.9.2")

	opts, lostArgs := getOptions()

	lInfo("Program start")
	// Checking for extra arguments we got no idea what to do with
	if len(lostArgs) != 0 {
		lErr("Too many arguments, skipping following:", lostArgs)
	}
	//If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
	if len(opts.Args.IDs) == 0 && opts.Tag == "" {
		lDone("Nothing to download, bye!")
		return
	}

	if opts.UnsafeHTTPS {
		makeHTTPSUnsafe()
	}
	if opts.Key != "" {
		derpiquery.Add("key", opts.Key)
	}

	//Creating directory for downloads if it does not yet exist
	err := os.MkdirAll(opts.ImageDir, 0644)

	if err != nil { //Execute bit means different thing for directories that for files. And I was stupid.
		lFatal(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(ImageCh, opts.QDepth) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal performance on my system

	if opts.Tag == "" { //Because we can put Image ID with flags. Why not?

		if len(opts.Args.IDs) == 1 {
			lInfo("Processing image №", opts.Args.IDs[0])
		} else {
			lInfo("Processing images №", debracket(opts.Args.IDs))
		}
		go imgdat.ParseImg(opts.Args.IDs, opts.Key) // Sending Image ID to parser. Here validity is our problem

	} else {

		// And here we send tags to getter/parser. Query and JSON validity is mostly server problem
		// Server response validity is ours
		lInfo("Processing tags", opts.Tag)
		go imgdat.ParseTag(opts.TagOpts, opts.Key)
	}

	lInfo("Starting worker") //It would be funny if worker goroutine does not start

	filterInit(opts.FiltOpts, bool(opts.Config.LogFilters)) //Initiating filters based on our given flags
	filtimgdat := FilterChannel(imgdat)                     //Actual filtration

	filtimgdat.interrupt().downloadImages(opts.Config) // Now that we got asynchronous list of images we want to get done, we can get them.

	lDone("Finished")
	return
	//And we are done here! Hooray!
}
<commit_msg>undoing stupidity from gas<commit_after>//Command ponydownloader uses Derpibooru.org API to download pony images
//by ID or by tags, with some client-side filtration ability
package main

import (
	"fmt"
	"os"
)

func main() {
	fmt.Println("Derpibooru.org Downloader version 0.9.2")

	opts, lostArgs := getOptions()

	lInfo("Program start")
	// Checking for extra arguments we got no idea what to do with
	if len(lostArgs) != 0 {
		lErr("Too many arguments, skipping following:", lostArgs)
	}
	//If no arguments after flags and empty/unchanged tag, what we should download? Sane end of line.
	if len(opts.Args.IDs) == 0 && opts.Tag == "" {
		lDone("Nothing to download, bye!")
		return
	}

	if opts.UnsafeHTTPS {
		makeHTTPSUnsafe()
	}
	if opts.Key != "" {
		derpiquery.Add("key", opts.Key)
	}

	//Creating directory for downloads if it does not yet exist
	err := os.MkdirAll(opts.ImageDir, 0755)

	if err != nil { //Execute bit means different thing for directories that for files. And I was stupid.
		lFatal(err) //We can not create folder for images, end of line.
	}

	//	Creating channels to pass info to downloader and to signal job well done
	imgdat := make(ImageCh, opts.QDepth) //Better leave default queue depth. Experiment shown that depth about 20 provides optimal performance on my system

	if opts.Tag == "" { //Because we can put Image ID with flags. Why not?

		if len(opts.Args.IDs) == 1 {
			lInfo("Processing image №", opts.Args.IDs[0])
		} else {
			lInfo("Processing images №", debracket(opts.Args.IDs))
		}
		go imgdat.ParseImg(opts.Args.IDs, opts.Key) // Sending Image ID to parser. Here validity is our problem

	} else {

		// And here we send tags to getter/parser. Query and JSON validity is mostly server problem
		// Server response validity is ours
		lInfo("Processing tags", opts.Tag)
		go imgdat.ParseTag(opts.TagOpts, opts.Key)
	}

	lInfo("Starting worker") //It would be funny if worker goroutine does not start

	filterInit(opts.FiltOpts, bool(opts.Config.LogFilters)) //Initiating filters based on our given flags
	filtimgdat := FilterChannel(imgdat)                     //Actual filtration

	filtimgdat.interrupt().downloadImages(opts.Config) // Now that we got asynchronous list of images we want to get done, we can get them.

	lDone("Finished")
	return
	//And we are done here! Hooray!
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/fabioxgn/go-bot/commands"
	"github.com/thoj/go-ircevent"
	"log"
	"os"
	"strings"
)

const (
	CONFIG_FILE = "config.json"
)

var (
	irccon *irc.Connection
	config = &Config{}
)

func printAvailableCommands(channel string) {
	irccon.Privmsg(channel, "Available Commands:")
	cmds := ""
	for k, _ := range commands.Commands {
		cmds += k + ", "
	}
	irccon.Privmsg(channel, cmds[:len(cmds)-2])
}

func onPRIVMSG(e *irc.Event) {
	log.Println(e.Message)
	if !strings.Contains(e.Message, config.Cmd) {
		return
	}

	channel := e.Arguments[0]
	cmd, err := Parse(StrAfter(e.Message, config.Cmd))
	if err != nil {
		irccon.Privmsg(channel, err.Error())
		return
	}

	log.Printf("cmd: %v", cmd)

	irc_cmd := commands.Commands[cmd.Command]
	if irc_cmd == nil {
		irccon.Privmsg(channel, fmt.Sprintf("Command %v not found.", cmd.Command))
		printAvailableCommands(channel)
	} else {
		log.Printf("cmd %v args %v", cmd.Command, cmd.Args)
		irccon.Privmsg(channel, irc_cmd(cmd.Args))
	}
}

func connect() {
	irccon = irc.IRC(config.User, config.Nick)
	irccon.UseTLS = config.UseTLS
	err := irccon.Connect(config.Server)
	if err != nil {
		log.Fatal(err)
	}
}

func configureEvents() {
	irccon.AddCallback("001", func(e *irc.Event) {
		irccon.Join(config.Channels[0])
	})

	irccon.AddCallback("366", func(e *irc.Event) {
		irccon.Privmsg(config.Channels[0], "Hi there.\n")
	})

	irccon.AddCallback("PRIVMSG", onPRIVMSG)
}

func readConfig() {
	configFile, err := os.Open(CONFIG_FILE)
	if err != nil {
		panic(err)
	}
	config.Read(configFile)
	fmt.Printf("%v", config)
}

func main() {
	readConfig()
	connect()
	configureEvents()
	irccon.Loop()
}
<commit_msg>Added logic to responde to private msgs<commit_after>package main

import (
	"fmt"
	"github.com/fabioxgn/go-bot/commands"
	"github.com/thoj/go-ircevent"
	"log"
	"os"
)

const (
	CONFIG_FILE = "config.json"
)

var (
	irccon *irc.Connection
	config = &Config{}
)

func printAvailableCommands(channel string) {
	irccon.Privmsg(channel, "Available Commands:")
	cmds := ""
	for k, _ := range commands.Commands {
		cmds += k + ", "
	}
	irccon.Privmsg(channel, cmds[:len(cmds)-2])
}

func handleCmd(cmd *Command, channel string) {
	irc_cmd := commands.Commands[cmd.Command]
	if irc_cmd == nil {
		irccon.Privmsg(channel, fmt.Sprintf("Command %v not found.", cmd.Command))
		printAvailableCommands(channel)
	} else {
		log.Printf("cmd %v args %v", cmd.Command, cmd.Args)
		irccon.Privmsg(channel, irc_cmd(cmd.Args))
	}
}

func onPRIVMSG(e *irc.Event) {
	channel := e.Arguments[0]
	args := ""
	if channel == config.Nick {
		channel = e.Nick
		args = e.Message
	} else {
		args = StrAfter(e.Message, config.Cmd)
	}

	cmd, err := Parse(args)
	if err != nil {
		irccon.Privmsg(channel, err.Error())
		return
	}

	handleCmd(cmd, channel)
}

func connect() {
	irccon = irc.IRC(config.User, config.Nick)
	irccon.UseTLS = config.UseTLS
	err := irccon.Connect(config.Server)
	if err != nil {
		log.Fatal(err)
	}
}

func configureEvents() {
	irccon.AddCallback("001", func(e *irc.Event) {
		irccon.Join(config.Channels[0])
	})

	irccon.AddCallback("366", func(e *irc.Event) {
		irccon.Privmsg(config.Channels[0], "Hi there.\n")
	})

	irccon.AddCallback("PRIVMSG", onPRIVMSG)
}

func readConfig() {
	configFile, err := os.Open(CONFIG_FILE)
	if err != nil {
		panic(err)
	}
	config.Read(configFile)
	fmt.Printf("%v", config)
}

func main() {
	readConfig()
	connect()
	configureEvents()
	irccon.Loop()
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/go-html-transform/css/selector"
	"code.google.com/p/go-html-transform/h5"
	"code.google.com/p/go.net/html"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"sync"
)

func main() {
	if len(os.Args) != 3 {
		log.Fatalln("You must specify your DAAS login and password")
	}

	email := os.Args[1]
	password := os.Args[2]

	cookieJar, _ := cookiejar.New(nil)
	client := http.Client{nil, nil, cookieJar}

	signIn(&client, email, password)

	screencastUrls := make(chan *url.URL, 5)

	wait := sync.WaitGroup{}
	wait.Add(1)
	go func() {
		for screencastUrl := range screencastUrls {
			downloadScreencast(&client, screencastUrl)
		}
		wait.Done()
	}()

	getScreencastUrls(&client, screencastUrls)
	close(screencastUrls)

	wait.Wait()
}

func signIn(client *http.Client, email, password string) {
	log.Println("Fetching DAS signin form")
	// grab https://www.destroyallsoftware.com/screencasts/users/sign_in
	//  - store cookies
	//  - get the form
	//  - fill in user & pass
	// submit the form (remember the cross site request hidden input!)
	signInUrl := "https://www.destroyallsoftware.com/screencasts/users/sign_in"
	signInResponse, err := client.Get(signInUrl)
	if err != nil {
		log.Fatalf("Error getting signin form: %v\n", err)
	}

	matchingNodes := extractMatchingHtmlNodes(signInResponse, "form input")

	formParams := make(url.Values)

	for _, node := range matchingNodes {
		var name, value string
		for _, attr := range node.Attr {
			if attr.Key == "name" {
				name = attr.Val
			} else if attr.Key == "value" {
				value = attr.Val
			}
		}
		formParams.Set(name, value)
	}
	formParams.Set("user[email]", email)
	formParams.Set("user[password]", password)

	log.Println("Submitting Login Form")

	signinResponse, err := client.PostForm(signInUrl, formParams)
	if err != nil {
		log.Fatalf("Error signing in: %v", err)
	}
	//
Invalid email or password.

	//status := signinResponse.Header.Get("Status")
	rawBody, _ := ioutil.ReadAll(signinResponse.Body)
	body := string(rawBody)
	if strings.Contains(body, "Signed in successfully") {
		log.Println("Signed in OK")
	} else {
		log.Fatalln("Failed to login")
	}
}

func getScreencastUrls(client *http.Client, screencastUrls chan *url.URL) {
	log.Println("Fetching Screencast Catalog")
	// get list of all screencast pages from https://www.destroyallsoftware.com/screencasts/catalog
	catalogResponse, err := client.Get("https://www.destroyallsoftware.com/screencasts/catalog")
	if err != nil {
		log.Fatalf("Error retreiving catalog page: %v\n", err)
	}

	// foreach screencast link (.screencast .title a)
	// TODO figure out why my real selector didn't work
	matchingNodes := extractMatchingHtmlNodes(catalogResponse, "a")

	log.Printf("Found %v matching screencast urls", len(matchingNodes))

	for _, node := range matchingNodes {
		for _, attr := range node.Attr {
			if attr.Key == "href" && strings.HasPrefix(attr.Val, "/screencasts/catalog/") {
				fullDownloadUrl := fmt.Sprintf("https://www.destroyallsoftware.com%v/download", attr.Val)
				url, err := url.Parse(fullDownloadUrl)
				if err == nil {
					screencastUrls <- url
				} else {
					log.Fatalf("Error parsing url %v with err: %v", attr.Val, err)
				}
			}
		}
	}
}

func downloadScreencast(client *http.Client, screencastUrl *url.URL) {
	//   - visit page
	//   - find the link with text "Download for Desktop"
	//   - follow it & any redirect
	//   - save it to a folder
	log.Printf("Trying %v\n", screencastUrl)

	resp, err := client.Get(screencastUrl.String())
	if err != nil {
		log.Printf("ERROR downloading %v: %v", screencastUrl, err)
		return
	}
	defer resp.Body.Close()

	// TODO set filename properly
	if resp.StatusCode == 404 {
		// logResponseForDebug(resp)
		log.Printf("404 for %v", screencastUrl)
	} else {

		split_file_path := strings.Split(resp.Request.URL.Path, "/")
		filename := split_file_path[len(split_file_path)-1]

		stat, err := os.Stat(filename)
		if err == nil {
			log.Printf("File %v already exists", stat.Name())
			return
		}

		file, err := os.Create(filename)
		if err != nil {
			log.Printf("Error creating file %v: %v\n", filename, err)
			return
		}
		defer file.Close()

		log.Printf("Started writing %v", filename)
		n, err := io.Copy(file, resp.Body)
		log.Printf("Wrote %v bytes to %v\n\n", n, filename)
	}

	// TODO skip if file exists and is correct size
	// contentLength := resp.Header.Get("Content-Length")
}

func extractMatchingHtmlNodes(response *http.Response, cssSelector string) []*html.Node {
	tree, err := h5.New(response.Body)
	if err != nil {
		log.Fatalf("Error parsing body into tree: %v\n", err)
	}

	selectorChain, err := selector.Selector(cssSelector)
	if err != nil {
		log.Fatalf("Error parsing cssSelector %v: %v\n", cssSelector, err)
	}

	return selectorChain.Find(tree.Top())
}

func logResponseForDebug(response *http.Response) {
	log.Printf("Headers: %v\n", response.Header)
	body, _ := ioutil.ReadAll(response.Body)
	log.Printf("Body:\n%s\n\n", body)
}
<commit_msg>Tidy up code.<commit_after>package main

import (
	"code.google.com/p/go-html-transform/css/selector"
	"code.google.com/p/go-html-transform/h5"
	"code.google.com/p/go.net/html"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"sync"
)

func main() {
	if len(os.Args) != 3 {
		log.Fatalln("You must specify your DAAS login and password")
	}

	email := os.Args[1]
	password := os.Args[2]

	cookieJar, _ := cookiejar.New(nil)
	client := http.Client{nil, nil, cookieJar}

	signIn(&client, email, password)

	screencastUrls := make(chan *url.URL, 5)

	wait := sync.WaitGroup{}
	wait.Add(1)
	go func() {
		for screencastUrl := range screencastUrls {
			downloadScreencast(&client, screencastUrl)
		}
		wait.Done()
	}()

	getScreencastUrls(&client, screencastUrls)
	close(screencastUrls)

	wait.Wait()
}

// grab https://www.destroyallsoftware.com/screencasts/users/sign_in
//  - store cookies
//  - get the form
//  - fill in user & pass
// submit the form (remember the cross site request hidden input!)
func signIn(client *http.Client, email, password string) {
	log.Println("Fetching DAS signin form")
	signInUrl := "https://www.destroyallsoftware.com/screencasts/users/sign_in"
	signInResponse, err := client.Get(signInUrl)
	if err != nil {
		log.Fatalf("Error getting signin form: %v\n", err)
	}

	matchingNodes := extractMatchingHtmlNodes(signInResponse, "form input")

	formParams := make(url.Values)

	for _, node := range matchingNodes {
		var name, value string
		for _, attr := range node.Attr {
			if attr.Key == "name" {
				name = attr.Val
			} else if attr.Key == "value" {
				value = attr.Val
			}
		}
		formParams.Set(name, value)
	}
	formParams.Set("user[email]", email)
	formParams.Set("user[password]", password)

	log.Println("Submitting Login Form")

	signinResponse, err := client.PostForm(signInUrl, formParams)
	if err != nil {
		log.Fatalf("Error signing in: %v", err)
	}
	rawBody, _ := ioutil.ReadAll(signinResponse.Body)
	body := string(rawBody)
	if strings.Contains(body, "Signed in successfully") {
		log.Println("Signed in OK")
	} else {
		log.Fatalln("Failed to login")
	}
}

// get list of all screencast pages from https://www.destroyallsoftware.com/screencasts/catalog
func getScreencastUrls(client *http.Client, screencastUrls chan *url.URL) {
	log.Println("Fetching Screencast Catalog")
	catalogResponse, err := client.Get("https://www.destroyallsoftware.com/screencasts/catalog")
	if err != nil {
		log.Fatalf("Error retreiving catalog page: %v\n", err)
	}

	// foreach screencast link (.screencast .title a)
	// TODO figure out why my real selector didn't work
	matchingNodes := extractMatchingHtmlNodes(catalogResponse, "a")

	log.Printf("Found %v matching screencast urls", len(matchingNodes))

	for _, node := range matchingNodes {
		for _, attr := range node.Attr {
			if attr.Key == "href" && strings.HasPrefix(attr.Val, "/screencasts/catalog/") {
				fullDownloadUrl := fmt.Sprintf("https://www.destroyallsoftware.com%v/download", attr.Val)
				url, err := url.Parse(fullDownloadUrl)
				if err == nil {
					screencastUrls <- url
				} else {
					log.Fatalf("Error parsing url %v with err: %v", attr.Val, err)
				}
			}
		}
	}
}

// Hit the screencast URL, stream the file into a local folder
// skip any files that already exist in the folder.
func downloadScreencast(client *http.Client, screencastUrl *url.URL) {
	log.Printf("Trying %v\n", screencastUrl)

	resp, err := client.Get(screencastUrl.String())
	if err != nil {
		log.Printf("ERROR downloading %v: %v", screencastUrl, err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		log.Printf("%v for %v", resp.Status, screencastUrl)
	} else {

		split_file_path := strings.Split(resp.Request.URL.Path, "/")
		filename := split_file_path[len(split_file_path)-1]

		stat, err := os.Stat(filename)
		if err == nil {
			log.Printf("File %v already exists", stat.Name())
			// TODO check length of response vs existing file
			// contentLength := resp.Header.Get("Content-Length")
			return
		}

		file, err := os.Create(filename)
		if err != nil {
			log.Printf("Error creating file %v: %v\n", filename, err)
			return
		}
		defer file.Close()

		log.Printf("Started writing %v", filename)
		n, err := io.Copy(file, resp.Body)
		log.Printf("Wrote %v bytes to %v\n\n", n, filename)
	}
}

func extractMatchingHtmlNodes(response *http.Response, cssSelector string) []*html.Node {
	tree, err := h5.New(response.Body)
	if err != nil {
		log.Fatalf("Error parsing body into tree: %v\n", err)
	}

	selectorChain, err := selector.Selector(cssSelector)
	if err != nil {
		log.Fatalf("Error parsing cssSelector %v: %v\n", cssSelector, err)
	}

	return selectorChain.Find(tree.Top())
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/fatih/color"
	"github.com/mattes/migrate/file"
	"github.com/mattes/migrate/migrate"
	"github.com/mattes/migrate/migrate/direction"
	pipep "github.com/mattes/migrate/pipe"
	"os"
	"strconv"
	"strings"
	"time"
)

var url = flag.String("url", "", "Driver connection URL, like schema://url")
var migrationsPath = flag.String("path", "", "Path to migrations")

func main() {
	flag.Parse()
	command := flag.Arg(0)

	switch command {
	case "create":
		verifyMigrationsPath(*migrationsPath)
		name := flag.Arg(1)
		if name == "" {
			fmt.Println("Please specify name.")
			os.Exit(1)
		}
		createCmd(*url, *migrationsPath, name)

	case "migrate":
		verifyMigrationsPath(*migrationsPath)
		relativeN := flag.Arg(1)
		relativeNInt, err := strconv.Atoi(relativeN)
		if err != nil {
			fmt.Println("Unable to parse parse param <n>.")
			os.Exit(1)
		}
		migrateCmd(*url, *migrationsPath, relativeNInt)

	case "up":
		verifyMigrationsPath(*migrationsPath)
		upCmd(*url, *migrationsPath)

	case "down":
		verifyMigrationsPath(*migrationsPath)
		downCmd(*url, *migrationsPath)

	case "redo":
		verifyMigrationsPath(*migrationsPath)
		redoCmd(*url, *migrationsPath)

	case "reset":
		verifyMigrationsPath(*migrationsPath)
		resetCmd(*url, *migrationsPath)

	case "version":
		verifyMigrationsPath(*migrationsPath)
		versionCmd(*url, *migrationsPath)

	case "help":
		helpCmd()

	default:
		helpCmd()
	}
}

func verifyMigrationsPath(path string) {
	if path == "" {
		fmt.Println("Please specify path")
		os.Exit(1)
	}
}

func textPadding(text string) string {
	textSplit := strings.Split(text, "\n")
	newText := make([]string, 0)
	for _, line := range textSplit {
		newText = append(newText, "    "+line)
	}
	return strings.Join(newText, "\n")
}

func writePipe(pipe chan interface{}) {
	if pipe != nil {
		for {
			select {
			case item, ok := <-pipe:
				if !ok {
					return
				} else {
					switch item.(type) {

					case string:
						fmt.Println(item.(string))

					case error:
						c := color.New(color.FgRed)
						c.Println(item.(error).Error())

					case file.File:
						f := item.(file.File)

						if f.Direction == direction.Up {
							fmt.Print("[ → ]")
						} else if f.Direction == direction.Down {
							fmt.Print("[ ← ]")
						}
						fmt.Printf(" %s\n", f.FileName)

					default:
						text := fmt.Sprint(item)
						fmt.Println(text)
					}
				}
			}
		}
	}
}

var timerStart time.Time

func printTimer() {
	fmt.Printf("\n%.4f seconds\n", time.Now().Sub(timerStart).Seconds())
}

func createCmd(url, migrationsPath, name string) {
	migrationFile, err := migrate.Create(url, migrationsPath, name)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("Version %v migration files created in %v:\n", migrationFile.Version, migrationsPath)
	fmt.Println(migrationFile.UpFile.FileName)
	fmt.Println(migrationFile.DownFile.FileName)
}

func upCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Up(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func downCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Down(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func redoCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Redo(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func resetCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Reset(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func migrateCmd(url, migrationsPath string, relativeN int) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Migrate(pipe, url, migrationsPath, relativeN)
	writePipe(pipe)
	printTimer()
}

func versionCmd(url, migrationsPath string) {
	version, err := migrate.Version(url, migrationsPath)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println(version)
}

func helpCmd() {
	os.Stderr.WriteString(
		`usage: migrate [-path=<path>] [-url=<url>] <command> [<args>]

Commands:
   create <name>  Create a new migration
   up             Apply all -up- migrations
   down           Apply all -down- migrations
   reset          Down followed by Up
   redo           Roll back most recent migration, then apply it again
   version        Show current migration version
   migrate <n>    Apply migrations -n|+n
   help           Show this help
`)
}
<commit_msg>update direction string<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/fatih/color"
	"github.com/mattes/migrate/file"
	"github.com/mattes/migrate/migrate"
	"github.com/mattes/migrate/migrate/direction"
	pipep "github.com/mattes/migrate/pipe"
	"os"
	"strconv"
	"strings"
	"time"
)

var url = flag.String("url", "", "Driver connection URL, like schema://url")
var migrationsPath = flag.String("path", "", "Path to migrations")

func main() {
	flag.Parse()
	command := flag.Arg(0)

	switch command {
	case "create":
		verifyMigrationsPath(*migrationsPath)
		name := flag.Arg(1)
		if name == "" {
			fmt.Println("Please specify name.")
			os.Exit(1)
		}
		createCmd(*url, *migrationsPath, name)

	case "migrate":
		verifyMigrationsPath(*migrationsPath)
		relativeN := flag.Arg(1)
		relativeNInt, err := strconv.Atoi(relativeN)
		if err != nil {
			fmt.Println("Unable to parse parse param <n>.")
			os.Exit(1)
		}
		migrateCmd(*url, *migrationsPath, relativeNInt)

	case "up":
		verifyMigrationsPath(*migrationsPath)
		upCmd(*url, *migrationsPath)

	case "down":
		verifyMigrationsPath(*migrationsPath)
		downCmd(*url, *migrationsPath)

	case "redo":
		verifyMigrationsPath(*migrationsPath)
		redoCmd(*url, *migrationsPath)

	case "reset":
		verifyMigrationsPath(*migrationsPath)
		resetCmd(*url, *migrationsPath)

	case "version":
		verifyMigrationsPath(*migrationsPath)
		versionCmd(*url, *migrationsPath)

	case "help":
		helpCmd()

	default:
		helpCmd()
	}
}

func verifyMigrationsPath(path string) {
	if path == "" {
		fmt.Println("Please specify path")
		os.Exit(1)
	}
}

func textPadding(text string) string {
	textSplit := strings.Split(text, "\n")
	newText := make([]string, 0)
	for _, line := range textSplit {
		newText = append(newText, "    "+line)
	}
	return strings.Join(newText, "\n")
}

func writePipe(pipe chan interface{}) {
	if pipe != nil {
		for {
			select {
			case item, ok := <-pipe:
				if !ok {
					return
				} else {
					switch item.(type) {

					case string:
						fmt.Println(item.(string))

					case error:
						c := color.New(color.FgRed)
						c.Println(item.(error).Error())

					case file.File:
						f := item.(file.File)

						if f.Direction == direction.Up {
							fmt.Print("[-> ]")
						} else if f.Direction == direction.Down {
							fmt.Print("[ <-]")
						}
						fmt.Printf(" %s\n", f.FileName)

					default:
						text := fmt.Sprint(item)
						fmt.Println(text)
					}
				}
			}
		}
	}
}

var timerStart time.Time

func printTimer() {
	fmt.Printf("\n%.4f seconds\n", time.Now().Sub(timerStart).Seconds())
}

func createCmd(url, migrationsPath, name string) {
	migrationFile, err := migrate.Create(url, migrationsPath, name)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Printf("Version %v migration files created in %v:\n", migrationFile.Version, migrationsPath)
	fmt.Println(migrationFile.UpFile.FileName)
	fmt.Println(migrationFile.DownFile.FileName)
}

func upCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Up(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func downCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Down(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func redoCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Redo(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func resetCmd(url, migrationsPath string) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Reset(pipe, url, migrationsPath)
	writePipe(pipe)
	printTimer()
}

func migrateCmd(url, migrationsPath string, relativeN int) {
	timerStart = time.Now()
	pipe := pipep.New()
	go migrate.Migrate(pipe, url, migrationsPath, relativeN)
	writePipe(pipe)
	printTimer()
}

func versionCmd(url, migrationsPath string) {
	version, err := migrate.Version(url, migrationsPath)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	fmt.Println(version)
}

func helpCmd() {
	os.Stderr.WriteString(
		`usage: migrate [-path=<path>] [-url=<url>] <command> [<args>]

Commands:
   create <name>  Create a new migration
   up             Apply all -up- migrations
   down           Apply all -down- migrations
   reset          Down followed by Up
   redo           Roll back most recent migration, then apply it again
   version        Show current migration version
   migrate <n>    Apply migrations -n|+n
   help           Show this help
`)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"unsafe"
)

var (
	modshell32         = syscall.NewLazyDLL("shell32.dll")
	procShellExecuteEx = modshell32.NewProc("ShellExecuteExW")
)

const (
	_SEE_MASK_NOCLOSEPROCESS = 0x00000040
)

const (
	_ERROR_BAD_FORMAT = 11
)

const (
	_SE_ERR_FNF             = 2
	_SE_ERR_PNF             = 3
	_SE_ERR_ACCESSDENIED    = 5
	_SE_ERR_OOM             = 8
	_SE_ERR_DLLNOTFOUND     = 32
	_SE_ERR_SHARE           = 26
	_SE_ERR_ASSOCINCOMPLETE = 27
	_SE_ERR_DDETIMEOUT      = 28
	_SE_ERR_DDEFAIL         = 29
	_SE_ERR_DDEBUSY         = 30
	_SE_ERR_NOASSOC         = 31
)

type (
	dword     uint32
	hinstance syscall.Handle
	hkey      syscall.Handle
	hwnd      syscall.Handle
	ulong     uint32
	lpctstr   uintptr
	lpvoid    uintptr
)

// SHELLEXECUTEINFO struct
type SHELLEXECUTEINFO struct {
	cbSize         dword
	fMask          ulong
	hwnd           hwnd
	lpVerb         lpctstr
	lpFile         lpctstr
	lpParameters   lpctstr
	lpDirectory    lpctstr
	nShow          int
	hInstApp       hinstance
	lpIDList       lpvoid
	lpClass        lpctstr
	hkeyClass      hkey
	dwHotKey       dword
	hIconOrMonitor syscall.Handle
	hProcess       syscall.Handle
}

// ShellExecuteAndWait is version of ShellExecuteEx which want process
func ShellExecuteAndWait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
	var lpctstrVerb, lpctstrParameters, lpctstrDirectory lpctstr
	if len(lpOperation) != 0 {
		lpctstrVerb = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
	}
	if len(lpParameters) != 0 {
		lpctstrParameters = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
	}
	if len(lpDirectory) != 0 {
		lpctstrDirectory = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
	}
	i := &SHELLEXECUTEINFO{
		fMask:        _SEE_MASK_NOCLOSEPROCESS,
		hwnd:         hwnd,
		lpVerb:       lpctstrVerb,
		lpFile:       lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
		lpParameters: lpctstrParameters,
		lpDirectory:  lpctstrDirectory,
		nShow:        nShowCmd,
	}
	i.cbSize = dword(unsafe.Sizeof(*i))
	return ShellExecuteEx(i)
}

// ShellExecuteEx is Windows API
func ShellExecuteEx(pExecInfo *SHELLEXECUTEINFO) error {
	ret, _, _ := procShellExecuteEx.Call(uintptr(unsafe.Pointer(pExecInfo)))
	if ret == 1 && pExecInfo.fMask&_SEE_MASK_NOCLOSEPROCESS != 0 {
		s, e := syscall.WaitForSingleObject(syscall.Handle(pExecInfo.hProcess), syscall.INFINITE)
		switch s {
		case syscall.WAIT_OBJECT_0:
			break
		case syscall.WAIT_FAILED:
			return os.NewSyscallError("WaitForSingleObject", e)
		default:
			return errors.New("Unexpected result from WaitForSingleObject")
		}
	}
	errorMsg := ""
	if pExecInfo.hInstApp != 0 && pExecInfo.hInstApp <= 32 {
		switch int(pExecInfo.hInstApp) {
		case _SE_ERR_FNF:
			errorMsg = "The specified file was not found"
		case _SE_ERR_PNF:
			errorMsg = "The specified path was not found"
		case _ERROR_BAD_FORMAT:
			errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)"
		case _SE_ERR_ACCESSDENIED:
			errorMsg = "The operating system denied access to the specified file"
		case _SE_ERR_ASSOCINCOMPLETE:
			errorMsg = "The file name association is incomplete or invalid"
		case _SE_ERR_DDEBUSY:
			errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed"
		case _SE_ERR_DDEFAIL:
			errorMsg = "The DDE transaction failed"
		case _SE_ERR_DDETIMEOUT:
			errorMsg = "The DDE transaction could not be completed because the request timed out"
		case _SE_ERR_DLLNOTFOUND:
			errorMsg = "The specified DLL was not found"
		case _SE_ERR_NOASSOC:
			errorMsg = "There is no application associated with the given file name extension"
		case _SE_ERR_OOM:
			errorMsg = "There was not enough memory to complete the operation"
		case _SE_ERR_SHARE:
			errorMsg = "A sharing violation occurred"
		default:
			errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", pExecInfo.hInstApp)
		}
	} else {
		return nil
	}
	return errors.New(errorMsg)
}

type msg struct {
	Name  string
	Exit  int
	Error string
	Data  []byte
}

func msgWrite(enc *gob.Encoder, typ string) io.WriteCloser {
	r, w := io.Pipe()
	go func() {
		defer r.Close()
		var b [4096]byte
		for {
			n, err := r.Read(b[:])
			if err != nil {
				break
			}
			err = enc.Encode(&msg{Name: typ, Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()
	return w
}

func client(addr string) int {
	// connect to server
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		panic(err.Error())
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	cmd := exec.Command(flag.Arg(0), flag.Args()[1:]...)

	// stdin
	inw, err := cmd.StdinPipe()
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot execute command: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	defer inw.Close()

	// stdout
	outw := msgWrite(enc, "stdout")
	defer outw.Close()
	cmd.Stdout = outw

	// stderr
	errw := msgWrite(enc, "stderr")
	defer errw.Close()
	cmd.Stderr = errw

	go func() {
		defer inw.Close()
	in_loop:
		for {
			var m msg
			err = dec.Decode(&m)
			if err != nil {
				return
			}
			switch m.Name {
			case "close":
				break in_loop
			case "ctrlc":
				if runtime.GOOS == "windows" {
					// windows doesn't support os.Interrupt
					cmd.Process.Kill()
				} else {
					cmd.Process.Signal(os.Interrupt)
				}
			case "stdin":
				inw.Write(m.Data)
			}
		}
	}()

	err = cmd.Run()

	code := 1
	if err != nil {
		if status, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok {
			code = status.ExitStatus()
		}
	} else {
		code = 0
	}

	err = enc.Encode(&msg{Name: "exit", Exit: code})
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot detect exit code: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	return 0
}

func makeCmdLine(args []string) string {
	var s string
	for _, v := range args {
		if s != "" {
			s += " "
		}
		s += syscall.EscapeArg(v)
	}
	return s
}

func server() int {
	// make listner to communicate child process
	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot make listener\n", os.Args[0])
		return 1
	}
	defer lis.Close()

	// make sure executable name to avoid detecting same executable name
	exe, err := os.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot find executable\n", os.Args[0])
		return 1
	}
	args := []string{"-mode", lis.Addr().String()}
	args = append(args, flag.Args()...)

	var errExec error
	go func() {
		err = ShellExecuteAndWait(0, "runas", exe, makeCmdLine(args), "", syscall.SW_HIDE)
		if err != nil {
			errExec = err
			lis.Close()
		}
	}()

	conn, err := lis.Accept()
	if err != nil {
		if errExec != nil {
			fmt.Fprintf(os.Stderr, "%v: %v\n", os.Args[0], errExec)
		} else {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
		}
		return 1
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, os.Interrupt)
	go func() {
		for range sc {
			enc.Encode(&msg{Name: "ctrlc"})
		}
	}()
	defer close(sc)

	go func() {
		var b [256]byte
		for {
			n, err := os.Stdin.Read(b[:])
			if err != nil {
				// stdin was closed
				enc.Encode(&msg{Name: "close"})
				break
			}
			err = enc.Encode(&msg{Name: "stdin", Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()

	for {
		var m msg
		err = dec.Decode(&m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
			return 1
		}
		switch m.Name {
		case "stdout":
			syscall.Write(syscall.Stdout, m.Data)
		case "stderr":
			syscall.Write(syscall.Stderr, m.Data)
		case "error":
			fmt.Fprintln(os.Stderr, m.Error)
		case "exit":
			return m.Exit
		}
	}
}

func main() {
	var mode string
	flag.StringVar(&mode, "mode", "", "mode")
	flag.Parse()
	if mode != "" {
		os.Exit(client(mode))
	}
	os.Exit(server())
}
<commit_msg>golint<commit_after>package main

import (
	"encoding/gob"
	"errors"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"runtime"
	"syscall"
	"unsafe"
)

var (
	modshell32         = syscall.NewLazyDLL("shell32.dll")
	procShellExecuteEx = modshell32.NewProc("ShellExecuteExW")
)

const (
	_SEE_MASK_NOCLOSEPROCESS = 0x00000040
)

const (
	_ERROR_BAD_FORMAT = 11
)

const (
	_SE_ERR_FNF             = 2
	_SE_ERR_PNF             = 3
	_SE_ERR_ACCESSDENIED    = 5
	_SE_ERR_OOM             = 8
	_SE_ERR_DLLNOTFOUND     = 32
	_SE_ERR_SHARE           = 26
	_SE_ERR_ASSOCINCOMPLETE = 27
	_SE_ERR_DDETIMEOUT      = 28
	_SE_ERR_DDEFAIL         = 29
	_SE_ERR_DDEBUSY         = 30
	_SE_ERR_NOASSOC         = 31
)

type (
	dword     uint32
	hinstance syscall.Handle
	hkey      syscall.Handle
	hwnd      syscall.Handle
	ulong     uint32
	lpctstr   uintptr
	lpvoid    uintptr
)

// SHELLEXECUTEINFO struct
type _SHELLEXECUTEINFO struct {
	cbSize         dword
	fMask          ulong
	hwnd           hwnd
	lpVerb         lpctstr
	lpFile         lpctstr
	lpParameters   lpctstr
	lpDirectory    lpctstr
	nShow          int
	hInstApp       hinstance
	lpIDList       lpvoid
	lpClass        lpctstr
	hkeyClass      hkey
	dwHotKey       dword
	hIconOrMonitor syscall.Handle
	hProcess       syscall.Handle
}

// _ShellExecuteAndWait is version of ShellExecuteEx which want process
func _ShellExecuteAndWait(hwnd hwnd, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
	var lpctstrVerb, lpctstrParameters, lpctstrDirectory lpctstr
	if len(lpOperation) != 0 {
		lpctstrVerb = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
	}
	if len(lpParameters) != 0 {
		lpctstrParameters = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
	}
	if len(lpDirectory) != 0 {
		lpctstrDirectory = lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
	}
	i := &_SHELLEXECUTEINFO{
		fMask:        _SEE_MASK_NOCLOSEPROCESS,
		hwnd:         hwnd,
		lpVerb:       lpctstrVerb,
		lpFile:       lpctstr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
		lpParameters: lpctstrParameters,
		lpDirectory:  lpctstrDirectory,
		nShow:        nShowCmd,
	}
	i.cbSize = dword(unsafe.Sizeof(*i))
	return _ShellExecuteEx(i)
}

// ShellExecuteEx is Windows API
func _ShellExecuteEx(pExecInfo *_SHELLEXECUTEINFO) error {
	ret, _, _ := procShellExecuteEx.Call(uintptr(unsafe.Pointer(pExecInfo)))
	if ret == 1 && pExecInfo.fMask&_SEE_MASK_NOCLOSEPROCESS != 0 {
		s, e := syscall.WaitForSingleObject(syscall.Handle(pExecInfo.hProcess), syscall.INFINITE)
		switch s {
		case syscall.WAIT_OBJECT_0:
			break
		case syscall.WAIT_FAILED:
			return os.NewSyscallError("WaitForSingleObject", e)
		default:
			return errors.New("Unexpected result from WaitForSingleObject")
		}
	}
	errorMsg := ""
	if pExecInfo.hInstApp != 0 && pExecInfo.hInstApp <= 32 {
		switch int(pExecInfo.hInstApp) {
		case _SE_ERR_FNF:
			errorMsg = "The specified file was not found"
		case _SE_ERR_PNF:
			errorMsg = "The specified path was not found"
		case _ERROR_BAD_FORMAT:
			errorMsg = "The .exe file is invalid (non-Win32 .exe or error in .exe image)"
		case _SE_ERR_ACCESSDENIED:
			errorMsg = "The operating system denied access to the specified file"
		case _SE_ERR_ASSOCINCOMPLETE:
			errorMsg = "The file name association is incomplete or invalid"
		case _SE_ERR_DDEBUSY:
			errorMsg = "The DDE transaction could not be completed because other DDE transactions were being processed"
		case _SE_ERR_DDEFAIL:
			errorMsg = "The DDE transaction failed"
		case _SE_ERR_DDETIMEOUT:
			errorMsg = "The DDE transaction could not be completed because the request timed out"
		case _SE_ERR_DLLNOTFOUND:
			errorMsg = "The specified DLL was not found"
		case _SE_ERR_NOASSOC:
			errorMsg = "There is no application associated with the given file name extension"
		case _SE_ERR_OOM:
			errorMsg = "There was not enough memory to complete the operation"
		case _SE_ERR_SHARE:
			errorMsg = "A sharing violation occurred"
		default:
			errorMsg = fmt.Sprintf("Unknown error occurred with error code %v", pExecInfo.hInstApp)
		}
	} else {
		return nil
	}
	return errors.New(errorMsg)
}

type msg struct {
	Name  string
	Exit  int
	Error string
	Data  []byte
}

func msgWrite(enc *gob.Encoder, typ string) io.WriteCloser {
	r, w := io.Pipe()
	go func() {
		defer r.Close()
		var b [4096]byte
		for {
			n, err := r.Read(b[:])
			if err != nil {
				break
			}
			err = enc.Encode(&msg{Name: typ, Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()
	return w
}

func client(addr string) int {
	// connect to server
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		panic(err.Error())
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	cmd := exec.Command(flag.Arg(0), flag.Args()[1:]...)

	// stdin
	inw, err := cmd.StdinPipe()
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot execute command: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	defer inw.Close()

	// stdout
	outw := msgWrite(enc, "stdout")
	defer outw.Close()
	cmd.Stdout = outw

	// stderr
	errw := msgWrite(enc, "stderr")
	defer errw.Close()
	cmd.Stderr = errw

	go func() {
		defer inw.Close()
	in_loop:
		for {
			var m msg
			err = dec.Decode(&m)
			if err != nil {
				return
			}
			switch m.Name {
			case "close":
				break in_loop
			case "ctrlc":
				if runtime.GOOS == "windows" {
					// windows doesn't support os.Interrupt
					cmd.Process.Kill()
				} else {
					cmd.Process.Signal(os.Interrupt)
				}
			case "stdin":
				inw.Write(m.Data)
			}
		}
	}()

	err = cmd.Run()

	code := 1
	if err != nil {
		if status, ok := cmd.ProcessState.Sys().(syscall.WaitStatus); ok {
			code = status.ExitStatus()
		}
	} else {
		code = 0
	}

	err = enc.Encode(&msg{Name: "exit", Exit: code})
	if err != nil {
		enc.Encode(&msg{Name: "error", Error: fmt.Sprintf("cannot detect exit code: %v", makeCmdLine(flag.Args()))})
		return 1
	}
	return 0
}

func makeCmdLine(args []string) string {
	var s string
	for _, v := range args {
		if s != "" {
			s += " "
		}
		s += syscall.EscapeArg(v)
	}
	return s
}

func server() int {
	// make listner to communicate child process
	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot make listener\n", os.Args[0])
		return 1
	}
	defer lis.Close()

	// make sure executable name to avoid detecting same executable name
	exe, err := os.Executable()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v: cannot find executable\n", os.Args[0])
		return 1
	}
	args := []string{"-mode", lis.Addr().String()}
	args = append(args, flag.Args()...)

	var errExec error
	go func() {
		err = _ShellExecuteAndWait(0, "runas", exe, makeCmdLine(args), "", syscall.SW_HIDE)
		if err != nil {
			errExec = err
			lis.Close()
		}
	}()

	conn, err := lis.Accept()
	if err != nil {
		if errExec != nil {
			fmt.Fprintf(os.Stderr, "%v: %v\n", os.Args[0], errExec)
		} else {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
		}
		return 1
	}
	defer conn.Close()

	enc, dec := gob.NewEncoder(conn), gob.NewDecoder(conn)

	sc := make(chan os.Signal, 1)
	signal.Notify(sc, os.Interrupt)
	go func() {
		for range sc {
			enc.Encode(&msg{Name: "ctrlc"})
		}
	}()
	defer close(sc)

	go func() {
		var b [256]byte
		for {
			n, err := os.Stdin.Read(b[:])
			if err != nil {
				// stdin was closed
				enc.Encode(&msg{Name: "close"})
				break
			}
			err = enc.Encode(&msg{Name: "stdin", Data: b[:n]})
			if err != nil {
				break
			}
		}
	}()

	for {
		var m msg
		err = dec.Decode(&m)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v: cannot execute command: %v\n", os.Args[0], makeCmdLine(flag.Args()))
			return 1
		}
		switch m.Name {
		case "stdout":
			syscall.Write(syscall.Stdout, m.Data)
		case "stderr":
			syscall.Write(syscall.Stderr, m.Data)
		case "error":
			fmt.Fprintln(os.Stderr, m.Error)
		case "exit":
			return m.Exit
		}
	}
}

func main() {
	var mode string
	flag.StringVar(&mode, "mode", "", "mode")
	flag.Parse()
	if mode != "" {
		os.Exit(client(mode))
	}
	os.Exit(server())
}
<|endoftext|>


<commit_before>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"fmt"
	"github.com/rjeczalik/notify"
	"github.com/urfave/cli"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

// settings for the server
type Settings struct {
	Directory string

}

type DirTreeMap map[string][]string
//type DirTreeMap map[string][]os.FileInfo

var globalSettings Settings = Settings{
	Directory: "",
}

func main() {
	fmt.Println("replicat initializing....")

	app := cli.NewApp()
	app.Name = "Replicat"
	app.Usage = "rsync for the cloud"
	app.Action = func(c *cli.Context) error {
		globalSettings.Directory = c.GlobalString("directory")

		if globalSettings.Directory == "" {
			panic("directory is required to serve files\n")
		}

		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "directory, d",
			Value:  globalSettings.Directory,
			Usage:  "Specify a directory where the files to share are located.",
			EnvVar: "directory, d",
		},
	}

	app.Run(os.Args)

	listOfFileInfo, err := createListOfFolders(globalSettings.Directory)
	if err != nil {
		log.Fatal(err)
	}

	// Make the channel buffered to ensure no event is dropped. Notify will drop
	// an event if the receiver is not able to keep up the sending pace.
	fsEventsChannel := make(chan notify.EventInfo, 1)

	// Set up a watchpoint listening for events within a directory tree rooted at the specified folder
	if err := notify.Watch(globalSettings.Directory + "/...", fsEventsChannel, notify.All); err != nil {
		log.Fatal(err)
	}
	defer notify.Stop(fsEventsChannel)

	fmt.Println("replicat online....")
	defer fmt.Println("End of line")

	fmt.Printf("Now listening on: %d folders under: %s\n", len(listOfFileInfo), globalSettings.Directory)

	totalFiles := 0
	for _, fileInfoList := range listOfFileInfo {
		totalFiles += len(fileInfoList)
	}

	fmt.Printf("Tracking %d folders with %d files\n", len(listOfFileInfo), totalFiles)

	go func(c chan notify.EventInfo) {
		for {
			ei := <-c
			log.Println("Got event:", ei)
		}
	}(fsEventsChannel)

	for {
		time.Sleep(time.Second * 5)
		checkForChanges(globalSettings.Directory, listOfFileInfo)
		fmt.Println("******************************************************")
	}

}

func checkForChanges(basePath string, originalState DirTreeMap) {
	//  (map[string][]string, error) {
	updatedState, err := createListOfFolders(basePath)
	if err != nil {
		panic(err)
	}

	// Get a list of paths and compare them
	originalPaths := make([]string, 0, len(originalState))
	updatedPaths := make([]string, 0, len(updatedState))

	for key := range originalState {
		originalPaths = append(originalPaths, key)
	}
	sort.Strings(originalPaths)

	for key := range updatedState {
		updatedPaths = append(updatedPaths, key)
	}
	sort.Strings(updatedPaths)

	// We now have two sworted lists of strings. Go through the original ones and compare the files
	var originalPosition, updatedPosition int

	deletedPaths := make([]string, 0, 100)
	newPaths := make([]string, 0, 100)
	matchingPaths := make([]string, 0, len(originalPaths))

	for {
		if originalPosition >= len(originalPaths) {
			// all remaining updated paths are new
			newPaths = append(newPaths, updatedPaths[updatedPosition:]...)
			break
		} else if updatedPosition >= len(updatedPaths) {
			// all remaining original paths are new
			deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
			break
		} else {
			result := strings.Compare(originalPaths[originalPosition], updatedPaths[updatedPosition])
			if result == -1 {
				deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
				originalPosition++
			} else if result == 1 {
				newPaths = append(newPaths, updatedPaths[updatedPosition])
				updatedPosition++
			} else {
				matchingPaths = append(matchingPaths, updatedPaths[updatedPosition])
				updatedPosition++
				originalPosition++
			}
		}
	}

	fmt.Printf("Path report: new %d, deleted %d, matching %d, original %d, updated %d\n", len(newPaths), len(deletedPaths), len(matchingPaths), len(originalPaths), len(updatedPaths))
	fmt.Printf("New paths: %v\n", newPaths)
	fmt.Printf("Deleted paths: %v\n", deletedPaths)
}

func createListOfFolders(basePath string) (DirTreeMap, error) {
	paths := make([]string, 0, 100)
	pendingPaths := make([]string, 0, 100)
	pendingPaths = append(pendingPaths, basePath)
	listOfFileInfo := make(DirTreeMap)

	for len(pendingPaths) > 0 {
		currentPath := pendingPaths[0]
		paths = append(paths, currentPath)
		fileList := make([]string, 0, 100)
		//fileList := make([]os.FileInfo, 0, 100)
		pendingPaths = pendingPaths[1:]

		// Read the directories in the path
		f, err := os.Open(currentPath)
		if err != nil {
			return nil, err
		}
		dirEntries, err := f.Readdir(-1)
		for _, entry := range dirEntries {
			if entry.IsDir() {
				entry.Mode()
				newDirectory := filepath.Join(currentPath, entry.Name())
				//newDirectory := filepath.Join(currentPath, entry)
				pendingPaths = append(pendingPaths, newDirectory)
			} else {
				fileList = append(fileList, entry.Name())
			}
		}
		f.Close()
		if err != nil {
			return nil, err
		}

		sort.Strings(fileList)
		listOfFileInfo[currentPath] = fileList
	}

	return listOfFileInfo, nil
}
<commit_msg>sending update event to webcat<commit_after>// Copyright 2016 Jacob Taylor jacob@ablox.io
// License: Apache2 - http://www.apache.org/licenses/LICENSE-2.0
package main

import (
	"fmt"
	"github.com/rjeczalik/notify"
	"github.com/urfave/cli"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
	"bytes"
	"io/ioutil"
	"net/http"
	"encoding/base64"
	"encoding/json"
)

type Event struct {
	Name    string
	Message string
}

// settings for the server
type Settings struct {
	Directory string

}

type DirTreeMap map[string][]string
//type DirTreeMap map[string][]os.FileInfo

var globalSettings Settings = Settings{
	Directory: "",
}

func main() {
	fmt.Println("replicat initializing....")

	app := cli.NewApp()
	app.Name = "Replicat"
	app.Usage = "rsync for the cloud"
	app.Action = func(c *cli.Context) error {
		globalSettings.Directory = c.GlobalString("directory")

		if globalSettings.Directory == "" {
			panic("directory is required to serve files\n")
		}

		return nil
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "directory, d",
			Value:  globalSettings.Directory,
			Usage:  "Specify a directory where the files to share are located.",
			EnvVar: "directory, d",
		},
	}

	app.Run(os.Args)

	listOfFileInfo, err := createListOfFolders(globalSettings.Directory)
	if err != nil {
		log.Fatal(err)
	}

	// Make the channel buffered to ensure no event is dropped. Notify will drop
	// an event if the receiver is not able to keep up the sending pace.
	fsEventsChannel := make(chan notify.EventInfo, 1)

	// Set up a watchpoint listening for events within a directory tree rooted at the specified folder
	if err := notify.Watch(globalSettings.Directory + "/...", fsEventsChannel, notify.All); err != nil {
		log.Fatal(err)
	}
	defer notify.Stop(fsEventsChannel)

	fmt.Println("replicat online....")
	defer fmt.Println("End of line")

	fmt.Printf("Now listening on: %d folders under: %s\n", len(listOfFileInfo), globalSettings.Directory)

	totalFiles := 0
	for _, fileInfoList := range listOfFileInfo {
		totalFiles += len(fileInfoList)
	}

	fmt.Printf("Tracking %d folders with %d files\n", len(listOfFileInfo), totalFiles)

	go func(c chan notify.EventInfo) {
		for {
			ei := <-c
			sendEvent(&Event{Name: ei.Event().String(), Message: ei.Path()})
			log.Println("Got event:" + ei.Event().String() + ", with Path:" + ei.Path())
		}
	}(fsEventsChannel)

	for {
		time.Sleep(time.Second * 5)
		checkForChanges(globalSettings.Directory, listOfFileInfo)
		fmt.Println("******************************************************")
	}

}

func checkForChanges(basePath string, originalState DirTreeMap) {
	//  (map[string][]string, error) {
	updatedState, err := createListOfFolders(basePath)
	if err != nil {
		panic(err)
	}

	// Get a list of paths and compare them
	originalPaths := make([]string, 0, len(originalState))
	updatedPaths := make([]string, 0, len(updatedState))

	for key := range originalState {
		originalPaths = append(originalPaths, key)
	}
	sort.Strings(originalPaths)

	for key := range updatedState {
		updatedPaths = append(updatedPaths, key)
	}
	sort.Strings(updatedPaths)

	// We now have two sworted lists of strings. Go through the original ones and compare the files
	var originalPosition, updatedPosition int

	deletedPaths := make([]string, 0, 100)
	newPaths := make([]string, 0, 100)
	matchingPaths := make([]string, 0, len(originalPaths))

	for {
		if originalPosition >= len(originalPaths) {
			// all remaining updated paths are new
			newPaths = append(newPaths, updatedPaths[updatedPosition:]...)
			break
		} else if updatedPosition >= len(updatedPaths) {
			// all remaining original paths are new
			deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
			break
		} else {
			result := strings.Compare(originalPaths[originalPosition], updatedPaths[updatedPosition])
			if result == -1 {
				deletedPaths = append(deletedPaths, originalPaths[originalPosition:]...)
				originalPosition++
			} else if result == 1 {
				newPaths = append(newPaths, updatedPaths[updatedPosition])
				updatedPosition++
			} else {
				matchingPaths = append(matchingPaths, updatedPaths[updatedPosition])
				updatedPosition++
				originalPosition++
			}
		}
	}

	fmt.Printf("Path report: new %d, deleted %d, matching %d, original %d, updated %d\n", len(newPaths), len(deletedPaths), len(matchingPaths), len(originalPaths), len(updatedPaths))
	fmt.Printf("New paths: %v\n", newPaths)
	fmt.Printf("Deleted paths: %v\n", deletedPaths)
}

func createListOfFolders(basePath string) (DirTreeMap, error) {
	paths := make([]string, 0, 100)
	pendingPaths := make([]string, 0, 100)
	pendingPaths = append(pendingPaths, basePath)
	listOfFileInfo := make(DirTreeMap)

	for len(pendingPaths) > 0 {
		currentPath := pendingPaths[0]
		paths = append(paths, currentPath)
		fileList := make([]string, 0, 100)
		//fileList := make([]os.FileInfo, 0, 100)
		pendingPaths = pendingPaths[1:]

		// Read the directories in the path
		f, err := os.Open(currentPath)
		if err != nil {
			return nil, err
		}
		dirEntries, err := f.Readdir(-1)
		for _, entry := range dirEntries {
			if entry.IsDir() {
				entry.Mode()
				newDirectory := filepath.Join(currentPath, entry.Name())
				//newDirectory := filepath.Join(currentPath, entry)
				pendingPaths = append(pendingPaths, newDirectory)
			} else {
				fileList = append(fileList, entry.Name())
			}
		}
		f.Close()
		if err != nil {
			return nil, err
		}

		sort.Strings(fileList)
		listOfFileInfo[currentPath] = fileList
	}

	return listOfFileInfo, nil
}

func sendEvent(event *Event) {
	url := "http://localhost:8080/event/"

	jsonStr, _ := json.Marshal(event)
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
	req.Header.Set("Content-Type", "application/json")

	data := []byte("replicat:isthecat")
	authHash := base64.StdEncoding.EncodeToString(data)
	req.Header.Add("Authorization", "Basic " + authHash)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Println("response Status:", resp.Status)
	fmt.Println("response Headers:", resp.Header)
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))
}<|endoftext|>


<commit_before>package main

import (
  "net"
  "log"
  "fmt"
  //"strconv"
  "os"
  "bufio"
  //"bytes"
  "io"
  //"io/ioutil"
  //"quantum-sicarius.za.net/p2pChat/utils"
  "sync"
  "crypto/md5"
  "time"
  "encoding/hex"
  "github.com/fatih/color"
  "encoding/json"
  //"reflect"
  "github.com/fatih/structs"
  "sort"
)

var inchan chan Node
var outchan chan string
var toWrite chan string
// Channel to buffer nodes that need closing
var cleanUpNodesChan chan Node
var newNodesChan chan Node
var toSyncNodes chan Node

var nodes map[string]Node
var data DataTable

// Current revision of chat
// Calculated by the hash of all values in map
var data_state string

var nick string

type Node struct {
  Connection net.Conn
  IPAddr string
  DataChecksum string
  Data string
}

type Packet struct {
  Type string
  Data map[string]interface{}
}

type Message struct {
  Key string
  Time string
  Nick string
  Data string
}

type SyncCheck struct {
  Checksum string
  KnownHosts []string
}

type SyncIndex struct {
  Keys []string
}

type SyncPacket struct {
  Key string
  Value Message
}

type RequestPacket struct {
  Key string
}

type DataTable struct{
  Mutex sync.Mutex
  // Map of chat
  Data_table map[string]Message
}

func init() {
  inchan = make(chan Node)
  outchan = make(chan string)
  toWrite = make(chan string)
  cleanUpNodesChan = make(chan Node)
  newNodesChan = make(chan Node)
  toSyncNodes = make(chan Node)

  nodes = make(map[string]Node)

  //data_table = make(map[string][]string)
  data.Data_table = make(map[string]Message)
  //data := new(DataTable{}
  data_state = data.getDataCheckSum()
  fmt.Println("Currect DataChecksum: ", data_state)
}

func main() {
  var host string
  var port string
  var new_node string

  fmt.Printf("Enter host (Leave blank for localhost): ")
  fmt.Scanln(&host)

  fmt.Printf("Enter port (Leave blank for 8080): ")
  fmt.Scanln(&port)

  fmt.Print("Enter a nick name:")
  fmt.Scanln(&nick)

  fmt.Print("Enter another node's address:")
  fmt.Scanln(&new_node)

  if len(host) == 0 || host == "" {
    host = "localhost"
  }

  if len(port) == 0 || port == "" {
    port = "8080"
  }

  if len(nick) == 0 || nick == "" {
    nick = "IsItSoHardToGetANick?"
  }

  // Linten to user keystrokes
  go clientInput()
  // Start printing routine
  go handleIncoming()
  // Handle cleanup
  go cleanUpNodes()
  // Sync keep alive
  go syncCheck()
  // Sync index
  go syncIndex()

  go client(new_node)

  server(host,port)
}

// Get checksum
func (data *DataTable) getDataCheckSum() string {
  data.Mutex.Lock()
  defer data.Mutex.Unlock()

  return Calculate_data_checksum(data.Data_table)
}

func Calculate_data_checksum(table map[string]Message)string {
  mk := make([]string, len(table))
  i := 0
  for k, _ := range table {
    mk[i] = k
    i++
  }
  sort.Strings(mk)

  temp_values := ""
  for _,v := range mk{
    temp_values = temp_values + v
  }

  byte_values := []byte(temp_values)
  md5_sum := md5.Sum(byte_values)

  return hex.EncodeToString(md5_sum[:])
}

func GetIndex(table map[string]Message)[]string {
  var keys []string

  for k,_ := range table {
    keys = append(keys, k)
  }

  return keys
}

// Compares 2 sets of keys and returns an array of keys that are missing
func CompareKeys(table map[string]Message, other []string)[]string {
  var keys []string
  var exists bool

  for _,v := range other {
    exists = false

    for k,_ := range table {
      if (k == v) {
        exists = true
        //fmt.Println("Exists")
        break
      }
    }

    if exists != true {
      //fmt.Println("Does not exist")
      keys = append(keys, v)
    }
  }

  return keys
}

// Write to table
func (data *DataTable) writeToTable(message Message){
  data.Mutex.Lock()
  defer data.Mutex.Unlock()

  data.Data_table[message.Key] = message
  //fmt.Println("data updated")
}

// Encode JSON
func Encode_msg(packet Packet) string {
  jsonString, err := json.Marshal(packet)
  if err != nil {
    return "ERROR"
  }
  return string(jsonString[:]) + "\n"
}

// Decode JSON
func Decode_msg(msg string)(Packet, bool){
  var packet Packet
  err := json.Unmarshal([]byte(msg), &packet)
  if err != nil {
    fmt.Println(msg ,err)
    return packet,false
  }
  return packet, true
}

func syncRequest(key string, node Node) {
  message := Encode_msg(Packet{"RequestPacket",structs.Map(RequestPacket{key})})
  unicastMessage(message, node)
}

func syncNode(key string, node Node) {

  msg := data.Data_table[key]

  message := Encode_msg(Packet{"SyncPacket",structs.Map(SyncPacket{key,msg})})
  unicastMessage(message, node)
}

// Send key value pair
func syncIndex() {
  for {
    node := <-toSyncNodes
    message := Encode_msg(Packet{"SyncIndex",structs.Map(SyncIndex{GetIndex(data.Data_table)})})
    unicastMessage(message, node)
  }
}

// Broadcast current checksum and known hosts
func syncCheck() {
  for {
    var knownHosts []string

    for k,_ := range nodes {
      knownHosts = append(knownHosts, k)
    }
    broadCastMessage(Encode_msg(Packet{"SyncCheck",structs.Map(SyncCheck{data_state,knownHosts})}))
    time.Sleep(time.Second * 5)
  }
}

func printReply(message Message) {
  //node := data.Data_table[key]

  timestamp, _ := time.Parse(time.RFC1123, message.Time)
  //fmt.Println(timestamp)
  local_time := timestamp.Local().Format(time.Kitchen)
  //fmt.Println(node[0], node[1], node[2])
  color.Set(color.FgYellow)
  fmt.Printf("<%s> ", local_time)
  color.Set(color.FgGreen)
  fmt.Printf("%s: ", message.Nick)
  color.Set(color.FgCyan)
  fmt.Printf(message.Data)
  color.Unset()
}

// Display incoming messages
func handleIncoming() {
  for {
    node := <-inchan
    //fmt.Println("Got: " ,node.Data)
    packet,success := Decode_msg(node.Data)
    //fmt.Println(key,value)
    if success {
      //printReply(packet)
      //fmt.Println(packet)
      if packet.Type == "Message" {
        //message := packet.Data
        //fmt.Println(message)
        key := packet.Data["Key"].(string)
        time_stamp := packet.Data["Time"].(string)
        nickname := packet.Data["Nick"].(string)
        data_packet := packet.Data["Data"].(string)
        message := Message{key,time_stamp,nickname,data_packet}
        data.writeToTable(message)
        go printCheckSum()
        printReply(message)
        // This packet is just a keep alive
      } else if packet.Type == "SyncCheck" {
        node.DataChecksum = packet.Data["Checksum"].(string)
        if node.DataChecksum != data_state {
          toSyncNodes <- node
        }
        // If we receive this packet it means there is a mismatch with the data and we need to correct it
      } else if packet.Type == "SyncIndex" {
        if packet.Data["Keys"] != nil {
          index := packet.Data["Keys"].([]interface{})
          var index_string []string
          for _,v := range index {
            index_string = append(index_string, v.(string))
          }

          missing_keys := CompareKeys(data.Data_table, index_string)
          //fmt.Println(missing_keys)

          for _,v := range missing_keys {
            syncRequest(v, node)
          }
        }

        //go unicastMessage(Encode_msg(), node)
        // If we receive this packet it means the node whishes to get a value of a key
      } else if packet.Type == "RequestPacket" {
        key := packet.Data["Key"].(string)
        syncNode(key, node)
        //fmt.Println(packet)
        // If we receive this packet it means we got data from the other node to populate our table
      } else if packet.Type == "SyncPacket" {
        if packet.Data["Key"] != nil && packet.Data["Value"] != nil{
          //key := packet.Data["Key"].(string)
          var message Message
          //fmt.Println(packet)
          value := packet.Data["Value"].(map[string]interface{})
          for k,v := range value{
            if k == "Data" {
              message.Data = v.(string)
            } else if k == "Key" {
              message.Key = v.(string)
            } else if k == "Time" {
              message.Time = v.(string)
            } else if k == "Nick" {
              message.Nick = v.(string)
            }
          }

          data.writeToTable(message)
          printReply(message)
          go printCheckSum()
        }
      }
    }
    nodes[node.IPAddr]=node
  }
}

// ASYNC update checksum
func printCheckSum() {
  data_state = data.getDataCheckSum()
  fmt.Println(data_state)
}

// Message a single node
func unicastMessage(msg string, node Node) {
  _ ,err := node.Connection.Write([]byte(msg))
  if err != nil {
    fmt.Println("Error sending message!", err)
    cleanUpNodesChan <- node
  } else {
    //fmt.Println("Sent to node: ", msg)
  }
}

// Broad cast to all Nodes
func broadCastMessage(msg string) {
  for _,node := range nodes{
    _ ,err := node.Connection.Write([]byte(msg))
    if err != nil {
      fmt.Println("Error sending message!", err)
      cleanUpNodesChan <- node
    } else {
      //fmt.Println("Sent: ", msg)
    }
  }
}

func cleanUpNodes() {
  for {
    node := <-cleanUpNodesChan
    fmt.Println("Cleaning up Connection: " + node.IPAddr)
    node.Connection.Close()
    delete(nodes, node.IPAddr)
  }
}

func processInput(msg string) {

  timestamp := time.Now().Format(time.RFC1123)
  md5_sum_key := md5.Sum([]byte(timestamp + msg))
  key := hex.EncodeToString(md5_sum_key[:])
  //msg_array := []string{key,timestamp,nick,msg}

  //data_map := make(map[string][]string)
  //data_map["Message"] = msg_array
  message := Message{key,timestamp,nick,msg}

  input := Encode_msg(Packet{"Message",structs.Map(message)})
  //fmt.Println(input)

  go broadCastMessage(input)

  data.writeToTable(message)
  go printCheckSum()

}

// Handle client input
func clientInput() {
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    // Sleep to prevent duplicates
    time.Sleep(time.Millisecond)

    input := scanner.Text()
    // Check for input
    if (input != "" || len(input) > 0) {
      processInput(input)
    }
  }
}

// Client
func client(host string) {
  conn, err := net.Dial("tcp", host)
  if err != nil {
    fmt.Println("Failed to connect to host!", err)
    return
  }
  go handleConnection(conn)
}

// Server function
func server(host string, port string) {
  host_string := host + ":" + port

  // Start listening
  ln, err := net.Listen("tcp", host_string)
  if err != nil {
    log.Fatalf("Failed to listen:", err)
  }

  fmt.Println("Listening on: ", ln.Addr())

  // Handle connections
  for {
    if conn, err := ln.Accept(); err == nil {
      fmt.Println("Incomming connection: ", conn.RemoteAddr())
      go handleConnection(conn);
    }
  }
}

func readConnection(node Node) {
  //buf := make([]byte, 4096)
  for {
    //n, err := node.Connection.Read(reader)
    //n, err := reader.ReadLine("\n")
    line, err := bufio.NewReader(node.Connection).ReadBytes('\n')
    if err != nil{
      if err != io.EOF {
        fmt.Printf("Reached EOF")
      }
      cleanUpNodesChan <- node
      break
    }

    node.Data = (string(line))

    inchan <- node
  }
}

func handleConnection(conn net.Conn) {
  nodes[conn.RemoteAddr().String()]= Node{conn, conn.RemoteAddr().String(), "",""}
  readConnection(nodes[conn.RemoteAddr().String()])
}
<commit_msg>Started working on self connecting nodes<commit_after>package main

import (
  "net"
  "log"
  "fmt"
  //"strconv"
  "os"
  "bufio"
  //"bytes"
  "io"
  //"io/ioutil"
  //"quantum-sicarius.za.net/p2pChat/utils"
  "sync"
  "crypto/md5"
  "time"
  "encoding/hex"
  "github.com/fatih/color"
  "encoding/json"
  //"reflect"
  "github.com/fatih/structs"
  "sort"
)

var inchan chan Node
var outchan chan string
var toWrite chan string
// Channel to buffer nodes that need closing
var cleanUpNodesChan chan Node
var newNodesChan chan Node
var toSyncNodes chan Node
var toConnectNodes chan string

var nodes map[string]Node
var data DataTable

// Current revision of chat
// Calculated by the hash of all values in map
var data_state string

var nick string

type Node struct {
  ConnectionType string
  Connection net.Conn
  IPAddr string
  DataChecksum string
  Data string
}

type Packet struct {
  Type string
  Data map[string]interface{}
}

type Message struct {
  Key string
  Time string
  Nick string
  Data string
}

type SyncCheck struct {
  Checksum string
  KnownHosts []string
}

type SyncIndex struct {
  Keys []string
}

type SyncPacket struct {
  Key string
  Value Message
}

type RequestPacket struct {
  Key string
}

type DataTable struct{
  Mutex sync.Mutex
  // Map of chat
  Data_table map[string]Message
}

func init() {
  inchan = make(chan Node)
  outchan = make(chan string)
  toWrite = make(chan string)
  cleanUpNodesChan = make(chan Node)
  newNodesChan = make(chan Node)
  toSyncNodes = make(chan Node)
  toConnectNodes = make(chan string)
  nodes = make(map[string]Node)

  //data_table = make(map[string][]string)
  data.Data_table = make(map[string]Message)
  //data := new(DataTable{}
  data_state = data.getDataCheckSum()
  fmt.Println("Currect DataChecksum: ", data_state)
}

func main() {
  var host string
  var port string
  var new_node string

  fmt.Printf("Enter host (Leave blank for localhost): ")
  fmt.Scanln(&host)

  fmt.Printf("Enter port (Leave blank for 8080): ")
  fmt.Scanln(&port)

  fmt.Print("Enter a nick name:")
  fmt.Scanln(&nick)

  fmt.Print("Enter another node's address:")
  fmt.Scanln(&new_node)

  if len(host) == 0 || host == "" {
    host = "localhost"
  }

  if len(port) == 0 || port == "" {
    port = "8080"
  }

  if len(nick) == 0 || nick == "" {
    nick = "IsItSoHardToGetANick?"
  }

  // Linten to user keystrokes
  go clientInput()
  // Start printing routine
  go handleIncoming()
  // Handle cleanup
  go cleanUpNodes()
  // Sync keep alive
  go syncCheck()
  // Sync index
  go syncIndex()
  // Connect nodes
  go connectNodes()

  go client(new_node)

  server(host,port)
}

// Get checksum
func (data *DataTable) getDataCheckSum() string {
  data.Mutex.Lock()
  defer data.Mutex.Unlock()

  return Calculate_data_checksum(data.Data_table)
}

func Calculate_data_checksum(table map[string]Message)string {
  mk := make([]string, len(table))
  i := 0
  for k, _ := range table {
    mk[i] = k
    i++
  }
  sort.Strings(mk)

  temp_values := ""
  for _,v := range mk{
    temp_values = temp_values + v
  }

  byte_values := []byte(temp_values)
  md5_sum := md5.Sum(byte_values)

  return hex.EncodeToString(md5_sum[:])
}

func GetIndex(table map[string]Message)[]string {
  var keys []string

  for k,_ := range table {
    keys = append(keys, k)
  }

  return keys
}

// Compares 2 sets of keys and returns an array of keys that are missing
func CompareKeys(table map[string]Message, other []string)[]string {
  var keys []string
  var exists bool

  for _,v := range other {
    exists = false

    for k,_ := range table {
      if (k == v) {
        exists = true
        //fmt.Println("Exists")
        break
      }
    }

    if exists != true {
      //fmt.Println("Does not exist")
      keys = append(keys, v)
    }
  }

  return keys
}

// Write to table
func (data *DataTable) writeToTable(message Message){
  data.Mutex.Lock()
  defer data.Mutex.Unlock()

  data.Data_table[message.Key] = message
  //fmt.Println("data updated")
}

// Encode JSON
func Encode_msg(packet Packet) string {
  jsonString, err := json.Marshal(packet)
  if err != nil {
    return "ERROR"
  }
  return string(jsonString[:]) + "\n"
}

// Decode JSON
func Decode_msg(msg string)(Packet, bool){
  var packet Packet
  err := json.Unmarshal([]byte(msg), &packet)
  if err != nil {
    fmt.Println(msg ,err)
    return packet,false
  }
  return packet, true
}

func syncRequest(key string, node Node) {
  message := Encode_msg(Packet{"RequestPacket",structs.Map(RequestPacket{key})})
  unicastMessage(message, node)
}

func syncNode(key string, node Node) {

  msg := data.Data_table[key]

  message := Encode_msg(Packet{"SyncPacket",structs.Map(SyncPacket{key,msg})})
  unicastMessage(message, node)
}

// Send key value pair
func syncIndex() {
  for {
    node := <-toSyncNodes
    message := Encode_msg(Packet{"SyncIndex",structs.Map(SyncIndex{GetIndex(data.Data_table)})})
    unicastMessage(message, node)
  }
}

func connectNodes() {
  for {
    host := <-toConnectNodes
    client(host)
  }
}

// Broadcast current checksum and known hosts
func syncCheck() {
  for {
    var knownHosts []string

    for k,v := range nodes {
      if v.ConnectionType == "Client" {
        knownHosts = append(knownHosts, k)
      }
    }
    broadCastMessage(Encode_msg(Packet{"SyncCheck",structs.Map(SyncCheck{data_state,knownHosts})}))
    time.Sleep(time.Second * 5)
  }
}

func printReply(message Message) {
  //node := data.Data_table[key]

  timestamp, _ := time.Parse(time.RFC1123, message.Time)
  //fmt.Println(timestamp)
  local_time := timestamp.Local().Format(time.Kitchen)
  //fmt.Println(node[0], node[1], node[2])
  color.Set(color.FgYellow)
  fmt.Printf("<%s> ", local_time)
  color.Set(color.FgGreen)
  fmt.Printf("%s: ", message.Nick)
  color.Set(color.FgCyan)
  fmt.Printf(message.Data)
  color.Unset()
}

// Display incoming messages
func handleIncoming() {
  for {
    node := <-inchan
    //fmt.Println("Got: " ,node.Data)
    packet,success := Decode_msg(node.Data)
    //fmt.Println(key,value)
    if success {
      //printReply(packet)
      //fmt.Println(packet)
      if packet.Type == "Message" {
        //message := packet.Data
        //fmt.Println(message)
        key := packet.Data["Key"].(string)
        time_stamp := packet.Data["Time"].(string)
        nickname := packet.Data["Nick"].(string)
        data_packet := packet.Data["Data"].(string)
        message := Message{key,time_stamp,nickname,data_packet}
        data.writeToTable(message)
        go printCheckSum()
        printReply(message)
        // This packet is just a keep alive
      } else if packet.Type == "SyncCheck" {
        node.DataChecksum = packet.Data["Checksum"].(string)
        if node.DataChecksum != data_state {
          toSyncNodes <- node
        }
        if packet.Data["KnownHosts"] != nil {
          knownHosts := packet.Data["KnownHosts"].([]interface{})
          var knownHosts_string []string

          //fmt.Println(knownHosts)

          for _,v := range knownHosts {
            knownHosts_string = append(knownHosts_string, v.(string))
          }

          for _,v := range knownHosts_string {
            found := false
            for _,node := range nodes {
              if node.IPAddr == v || node.Connection.LocalAddr().String() == v{
                found = true
                break
              }
            }

            if found != true {
              toConnectNodes <- v
            }
          }

        }
        // If we receive this packet it means there is a mismatch with the data and we need to correct it
      } else if packet.Type == "SyncIndex" {
        if packet.Data["Keys"] != nil {
          index := packet.Data["Keys"].([]interface{})
          var index_string []string
          for _,v := range index {
            index_string = append(index_string, v.(string))
          }

          missing_keys := CompareKeys(data.Data_table, index_string)
          //fmt.Println(missing_keys)

          for _,v := range missing_keys {
            syncRequest(v, node)
          }
        }

        //go unicastMessage(Encode_msg(), node)
        // If we receive this packet it means the node whishes to get a value of a key
      } else if packet.Type == "RequestPacket" {
        key := packet.Data["Key"].(string)
        syncNode(key, node)
        //fmt.Println(packet)
        // If we receive this packet it means we got data from the other node to populate our table
      } else if packet.Type == "SyncPacket" {
        if packet.Data["Key"] != nil && packet.Data["Value"] != nil{
          //key := packet.Data["Key"].(string)
          var message Message
          //fmt.Println(packet)
          value := packet.Data["Value"].(map[string]interface{})
          for k,v := range value{
            if k == "Data" {
              message.Data = v.(string)
            } else if k == "Key" {
              message.Key = v.(string)
            } else if k == "Time" {
              message.Time = v.(string)
            } else if k == "Nick" {
              message.Nick = v.(string)
            }
          }

          data.writeToTable(message)
          printReply(message)
          go printCheckSum()
        }
      }
    }
    nodes[node.IPAddr]=node
  }
}

// ASYNC update checksum
func printCheckSum() {
  data_state = data.getDataCheckSum()
  fmt.Println(data_state)
}

// Message a single node
func unicastMessage(msg string, node Node) {
  _ ,err := node.Connection.Write([]byte(msg))
  if err != nil {
    fmt.Println("Error sending message!", err)
    cleanUpNodesChan <- node
  } else {
    //fmt.Println("Sent to node: ", msg)
  }
}

// Broad cast to all Nodes
func broadCastMessage(msg string) {
  for _,node := range nodes{
    _ ,err := node.Connection.Write([]byte(msg))
    if err != nil {
      fmt.Println("Error sending message!", err)
      cleanUpNodesChan <- node
    } else {
      //fmt.Println("Sent: ", msg)
    }
  }
}

func cleanUpNodes() {
  for {
    node := <-cleanUpNodesChan
    fmt.Println("Cleaning up Connection: " + node.IPAddr)
    node.Connection.Close()
    delete(nodes, node.IPAddr)
  }
}

func processInput(msg string) {

  timestamp := time.Now().Format(time.RFC1123)
  md5_sum_key := md5.Sum([]byte(timestamp + msg))
  key := hex.EncodeToString(md5_sum_key[:])
  //msg_array := []string{key,timestamp,nick,msg}

  //data_map := make(map[string][]string)
  //data_map["Message"] = msg_array
  message := Message{key,timestamp,nick,msg}

  input := Encode_msg(Packet{"Message",structs.Map(message)})
  //fmt.Println(input)

  go broadCastMessage(input)

  data.writeToTable(message)
  go printCheckSum()

}

// Handle client input
func clientInput() {
  scanner := bufio.NewScanner(os.Stdin)
  for scanner.Scan() {
    // Sleep to prevent duplicates
    time.Sleep(time.Millisecond)

    input := scanner.Text()
    // Check for input
    if (input != "" || len(input) > 0) {
      processInput(input)
    }
  }
}

// Client
func client(host string) {
  conn, err := net.Dial("tcp", host)
  if err != nil {
    fmt.Println("Failed to connect to host!", err)
    return
  }
  fmt.Println("Connecting to: ", conn.RemoteAddr())
  go handleConnection("Client",conn)
}

// Server function
func server(host string, port string) {
  host_string := host + ":" + port

  // Start listening
  ln, err := net.Listen("tcp", host_string)
  if err != nil {
    log.Fatalf("Failed to listen:", err)
  }

  fmt.Println("Listening on: ", ln.Addr())

  // Handle connections
  for {
    if conn, err := ln.Accept(); err == nil {
      fmt.Println("Incomming connection: ", conn.RemoteAddr())
      go handleConnection("Server",conn);
    }
  }
}

func readConnection(node Node) {
  //buf := make([]byte, 4096)
  for {
    //n, err := node.Connection.Read(reader)
    //n, err := reader.ReadLine("\n")
    line, err := bufio.NewReader(node.Connection).ReadBytes('\n')
    if err != nil{
      if err != io.EOF {
        fmt.Printf("Reached EOF")
      }
      cleanUpNodesChan <- node
      break
    }

    node.Data = (string(line))

    inchan <- node
  }
}

func handleConnection(type_of_connection string, conn net.Conn) {
  nodes[conn.RemoteAddr().String()]= Node{type_of_connection,conn, conn.RemoteAddr().String(), "",""}
  readConnection(nodes[conn.RemoteAddr().String()])
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/kubernetes-incubator/external-dns/controller"
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns"
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns/validation"
	"github.com/kubernetes-incubator/external-dns/plan"
	"github.com/kubernetes-incubator/external-dns/provider"
	"github.com/kubernetes-incubator/external-dns/registry"
	"github.com/kubernetes-incubator/external-dns/source"
	"github.com/spf13/pflag"
)

var (
	version = "unknown"
)

func main() {
	cfg := externaldns.NewConfig()
	if err := cfg.ParseFlags(os.Args); err != nil {
		if err == pflag.ErrHelp {
			os.Exit(0)
		}
		log.Fatalf("flag parsing error: %v", err)
	}
	if cfg.Version {
		fmt.Println(version)
		os.Exit(0)
	}

	if err := validation.ValidateConfig(cfg); err != nil {
		log.Fatalf("config validation failed: %v", err)
	}

	if cfg.LogFormat == "json" {
		log.SetFormatter(&log.JSONFormatter{})
	}
	if cfg.DryRun {
		log.Info("running in dry-run mode. No changes to DNS records will be made.")
	}
	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	}

	stopChan := make(chan struct{}, 1)

	go serveMetrics(cfg.MetricsAddress)
	go handleSigterm(stopChan)

	client, err := newClient(cfg)
	if err != nil {
		log.Fatal(err)
	}

	source.Register("service", source.NewServiceSource(client, cfg.Namespace, cfg.Compatibility))
	source.Register("ingress", source.NewIngressSource(client, cfg.Namespace))

	sources, err := source.LookupMultiple(cfg.Sources)
	if err != nil {
		log.Fatal(err)
	}

	multiSource := source.NewMultiSource(sources)

	var p provider.Provider
	switch cfg.Provider {
	case "google":
		p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun)
	case "aws":
		p, err = provider.NewAWSProvider(cfg.Domain, cfg.DryRun)
	default:
		log.Fatalf("unknown dns provider: %s", cfg.Provider)
	}
	if err != nil {
		log.Fatal(err)
	}

	var r registry.Registry
	switch cfg.Registry {
	case "noop":
		r, err = registry.NewNoopRegistry(p)
	case "txt":
		r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.RecordOwnerID)
	default:
		log.Fatalf("unknown registry: %s", cfg.Registry)
	}

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

	policy, exists := plan.Policies[cfg.Policy]
	if !exists {
		log.Fatalf("unknown policy: %s", cfg.Policy)
	}

	ctrl := controller.Controller{
		Zone:     cfg.Zone,
		Source:   multiSource,
		Registry: r,
		Policy:   policy,
		Interval: cfg.Interval,
	}

	if cfg.Once {
		err := ctrl.RunOnce()
		if err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
	}

	ctrl.Run(stopChan)
	for {
		log.Infoln("pod waiting to be deleted")
		time.Sleep(time.Second * 30)
	}
}

func handleSigterm(stopChan chan struct{}) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM)
	<-signals
	log.Infoln("received SIGTERM. Terminating...")
	close(stopChan)
}

func newClient(cfg *externaldns.Config) (*kubernetes.Clientset, error) {
	if !cfg.InCluster && cfg.KubeConfig == "" {
		cfg.KubeConfig = clientcmd.RecommendedHomeFile
	}

	config, err := clientcmd.BuildConfigFromFlags("", cfg.KubeConfig)
	if err != nil {
		return nil, err
	}

	log.Infof("targeting cluster at %s", config.Host)

	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func serveMetrics(address string) {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	http.Handle("/metrics", promhttp.Handler())

	log.Fatal(http.ListenAndServe(address, nil))
}
<commit_msg>log config on startup (#161)<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/prometheus/client_golang/prometheus/promhttp"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/clientcmd"

	"github.com/kubernetes-incubator/external-dns/controller"
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns"
	"github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns/validation"
	"github.com/kubernetes-incubator/external-dns/plan"
	"github.com/kubernetes-incubator/external-dns/provider"
	"github.com/kubernetes-incubator/external-dns/registry"
	"github.com/kubernetes-incubator/external-dns/source"
	"github.com/spf13/pflag"
)

var (
	version = "unknown"
)

func main() {
	cfg := externaldns.NewConfig()
	if err := cfg.ParseFlags(os.Args); err != nil {
		if err == pflag.ErrHelp {
			os.Exit(0)
		}
		log.Fatalf("flag parsing error: %v", err)
	}
	if cfg.Version {
		fmt.Println(version)
		os.Exit(0)
	}

	log.Infof("config: %+v", cfg)

	if err := validation.ValidateConfig(cfg); err != nil {
		log.Fatalf("config validation failed: %v", err)
	}

	if cfg.LogFormat == "json" {
		log.SetFormatter(&log.JSONFormatter{})
	}
	if cfg.DryRun {
		log.Info("running in dry-run mode. No changes to DNS records will be made.")
	}
	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	}

	stopChan := make(chan struct{}, 1)

	go serveMetrics(cfg.MetricsAddress)
	go handleSigterm(stopChan)

	client, err := newClient(cfg)
	if err != nil {
		log.Fatal(err)
	}

	source.Register("service", source.NewServiceSource(client, cfg.Namespace, cfg.Compatibility))
	source.Register("ingress", source.NewIngressSource(client, cfg.Namespace))

	sources, err := source.LookupMultiple(cfg.Sources)
	if err != nil {
		log.Fatal(err)
	}

	multiSource := source.NewMultiSource(sources)

	var p provider.Provider
	switch cfg.Provider {
	case "google":
		p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun)
	case "aws":
		p, err = provider.NewAWSProvider(cfg.Domain, cfg.DryRun)
	default:
		log.Fatalf("unknown dns provider: %s", cfg.Provider)
	}
	if err != nil {
		log.Fatal(err)
	}

	var r registry.Registry
	switch cfg.Registry {
	case "noop":
		r, err = registry.NewNoopRegistry(p)
	case "txt":
		r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.RecordOwnerID)
	default:
		log.Fatalf("unknown registry: %s", cfg.Registry)
	}

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

	policy, exists := plan.Policies[cfg.Policy]
	if !exists {
		log.Fatalf("unknown policy: %s", cfg.Policy)
	}

	ctrl := controller.Controller{
		Zone:     cfg.Zone,
		Source:   multiSource,
		Registry: r,
		Policy:   policy,
		Interval: cfg.Interval,
	}

	if cfg.Once {
		err := ctrl.RunOnce()
		if err != nil {
			log.Fatal(err)
		}

		os.Exit(0)
	}

	ctrl.Run(stopChan)
	for {
		log.Infoln("pod waiting to be deleted")
		time.Sleep(time.Second * 30)
	}
}

func handleSigterm(stopChan chan struct{}) {
	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGTERM)
	<-signals
	log.Infoln("received SIGTERM. Terminating...")
	close(stopChan)
}

func newClient(cfg *externaldns.Config) (*kubernetes.Clientset, error) {
	if !cfg.InCluster && cfg.KubeConfig == "" {
		cfg.KubeConfig = clientcmd.RecommendedHomeFile
	}

	config, err := clientcmd.BuildConfigFromFlags("", cfg.KubeConfig)
	if err != nil {
		return nil, err
	}

	log.Infof("targeting cluster at %s", config.Host)

	client, err := kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	return client, nil
}

func serveMetrics(address string) {
	http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("OK"))
	})

	http.Handle("/metrics", promhttp.Handler())

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


<commit_before>package main

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"

	"github.com/boltdb/bolt"
	"github.com/gorilla/sessions"
	"github.com/julienschmidt/httprouter"
	"github.com/tejo/dropbox"
)

var store = sessions.NewCookieStore([]byte("182hetsgeih8765$aasdhj"))

var AppToken = dropbox.AppToken{
	Key:    "2vhv4i5dqyl92l1",
	Secret: "0k1q9zpbt1x3czk",
}

var callbackUrl = "http://localhost:8080/oauth/callback"
var db *bolt.DB

func init() {
	store.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 30 * 12,
		HttpOnly: true,
	}
	var err error
	db, err = bolt.Open("blog.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte("UserData"))
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		return nil
	})
	gob.Register(dropbox.RequestToken{})
}

func main() {
	defer db.Close()

	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/login", Login)
	router.GET("/oauth/callback", Callback)

	log.Fatal(http.ListenAndServe(":8080", router))
}
func Login(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	session, _ := store.Get(r, "godropblog")
	RequestToken, _ := dropbox.StartAuth(AppToken)
	session.Values["RequestToken"] = RequestToken
	session.Save(r, w)
	url, _ := url.Parse(callbackUrl)
	authUrl := dropbox.GetAuthorizeURL(RequestToken, url)
	http.Redirect(w, r, authUrl.String(), 302)
}

func Callback(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	session, _ := store.Get(r, "godropblog")
	RequestToken := session.Values["RequestToken"].(dropbox.RequestToken)
	AccessToken, _ := dropbox.FinishAuth(AppToken, RequestToken)
	info, err := dbClient(AccessToken).GetAccountInfo()
	if err != nil {
		log.Println(err)
	}
	db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte("UserData"))
		t, _ := json.Marshal(AccessToken)
		uid := strconv.Itoa(int(info.Uid))
		err := b.Put([]byte(uid+":token"), []byte(t))
		i, _ := json.Marshal(info)
		err = b.Put([]byte(uid), []byte(i))
		return err
	})
	session.Values["uid"] = info.Uid
	session.Save(r, w)
	fmt.Printf("AccessToken = %+v\n", AccessToken)
	http.Redirect(w, r, "/", 302)
}

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	session, _ := store.Get(r, "godropblog")
	var AccessToken dropbox.AccessToken

	if uid := session.Values["uid"]; uid == nil {
		log.Println("no uid found")
		return
	} else {
		uid := strconv.Itoa(int(session.Values["uid"].(uint64)))
		db.View(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte("UserData"))
			token := b.Get([]byte(uid + ":token"))
			json.Unmarshal(token, &AccessToken)
			fmt.Printf("The answer is: %s\n", AccessToken)
			return nil
		})
	}
	db := dbClient(AccessToken)
	info, err := db.GetAccountInfo()
	fmt.Printf("err = %+v\n", err)

	if err != nil {
		//access token is not valid anymore
		fmt.Fprintf(w, " %+v\n", err)
		// reset all session
		session.Values["key"], session.Values["secret"] = "", ""
		session.Save(r, w)
		// http.Redirect(w, r, "/login", 302)
		return
	}

	fmt.Printf("err = %+v\n", err)
	fmt.Printf("err = %+v\n", info)
	db.CreateDir("drafts")
	db.CreateDir("published")
	delta, err := db.GetDelta()
	fmt.Printf("delta = %+v\n", delta)
	fmt.Printf("delta err = %+v\n", err)
}

func dbClient(t dropbox.AccessToken) *dropbox.Client {
	return &dropbox.Client{
		AppToken:    AppToken,
		AccessToken: t,
		Config: dropbox.Config{
			Access: dropbox.AppFolder,
			Locale: "us",
		}}
}
<commit_msg>adds context<commit_after>package main

import (
	"encoding/gob"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"strconv"

	"github.com/boltdb/bolt"
	"github.com/gorilla/sessions"
	"github.com/julienschmidt/httprouter"
	"github.com/tejo/dropbox"
)

var AppToken = dropbox.AppToken{
	Key:    "2vhv4i5dqyl92l1",
	Secret: "0k1q9zpbt1x3czk",
}

var callbackUrl = "http://localhost:8080/oauth/callback"
var db *bolt.DB

func withSession(w http.ResponseWriter, r *http.Request, fn func(*sessions.Session)) {
	store := sessions.NewCookieStore([]byte("182hetsgeih8765$aasdhj"))
	store.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 30 * 12,
		HttpOnly: true,
	}
	session, _ := store.Get(r, "godropblog")
	fn(session)
}

func init() {
	var err error
	db, err = bolt.Open("blog.db", 0600, nil)
	if err != nil {
		log.Fatal(err)
	}

	db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte("UserData"))
		if err != nil {
			return fmt.Errorf("create bucket: %s", err)
		}
		return nil
	})
	gob.Register(dropbox.RequestToken{})
}

func main() {
	defer db.Close()

	router := httprouter.New()
	router.GET("/", Index)
	router.GET("/login", Login)
	router.GET("/oauth/callback", Callback)

	log.Fatal(http.ListenAndServe(":8080", router))
}
func Login(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	withSession(w, r, func(session *sessions.Session) {
		RequestToken, _ := dropbox.StartAuth(AppToken)
		session.Values["RequestToken"] = RequestToken
		url, _ := url.Parse(callbackUrl)
		authUrl := dropbox.GetAuthorizeURL(RequestToken, url)
		session.Save(r, w)
		http.Redirect(w, r, authUrl.String(), 302)
	})
}

func Callback(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	withSession(w, r, func(session *sessions.Session) {
		RequestToken := session.Values["RequestToken"].(dropbox.RequestToken)
		AccessToken, _ := dropbox.FinishAuth(AppToken, RequestToken)
		info, err := dbClient(AccessToken).GetAccountInfo()
		if err != nil {
			log.Println(err)
		}
		db.Update(func(tx *bolt.Tx) error {
			b := tx.Bucket([]byte("UserData"))
			t, _ := json.Marshal(AccessToken)
			uid := strconv.Itoa(int(info.Uid))
			err := b.Put([]byte(uid+":token"), []byte(t))
			i, _ := json.Marshal(info)
			err = b.Put([]byte(uid), []byte(i))
			return err
		})
		session.Values["uid"] = info.Uid
		session.Save(r, w)
		fmt.Printf("AccessToken = %+v\n", AccessToken)
		http.Redirect(w, r, "/", 302)
	})
}

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	withSession(w, r, func(session *sessions.Session) {
		var AccessToken dropbox.AccessToken

		if uid := session.Values["uid"]; uid == nil {
			log.Println("no uid found")
			return
		} else {
			uid := strconv.Itoa(int(session.Values["uid"].(uint64)))
			db.View(func(tx *bolt.Tx) error {
				b := tx.Bucket([]byte("UserData"))
				token := b.Get([]byte(uid + ":token"))
				json.Unmarshal(token, &AccessToken)
				fmt.Printf("The answer is: %s\n", AccessToken)
				return nil
			})
		}
		db := dbClient(AccessToken)
		info, err := db.GetAccountInfo()
		fmt.Printf("err = %+v\n", err)

		if err != nil {
			//access token is not valid anymore
			fmt.Fprintf(w, " %+v\n", err)
			// reset all session
			session.Values["key"], session.Values["secret"] = "", ""
			// http.Redirect(w, r, "/login", 302)
			return
		}

		fmt.Printf("err = %+v\n", err)
		fmt.Printf("err = %+v\n", info)
		db.CreateDir("drafts")
		db.CreateDir("published")
		delta, err := db.GetDelta()
		fmt.Printf("delta = %+v\n", delta)
		fmt.Printf("delta err = %+v\n", err)
	})
}

func dbClient(t dropbox.AccessToken) *dropbox.Client {
	return &dropbox.Client{
		AppToken:    AppToken,
		AccessToken: t,
		Config: dropbox.Config{
			Access: dropbox.AppFolder,
			Locale: "us",
		}}
}
<|endoftext|>