<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/nickjones/proc_box/Godeps/_workspace/src/github.com/Sirupsen/logrus"
	"github.com/nickjones/proc_box/Godeps/_workspace/src/github.com/streadway/amqp"
	"github.com/nickjones/proc_box/agents"
)

var (
	uri              = flag.String("uri", "amqp://guest:guest@localhost:5672", "AMQP connection URI.")
	exchange         = flag.String("exchange", "amq.topic", "AMQP exchange to bind.")
	rmtKey           = flag.String("rkey", "proc_box.remote_control", "AMQP routing key for remote process control.")
	procStatsKey     = flag.String("skey", "proc_box.stats", "AMQP routing key prefix for proc stats.")
	statsInterval    = flag.Duration("sint", 1*time.Minute, "Interval to emit process statistics.")
	wallclockTimeout = flag.Duration("timeout", 10*time.Minute, "The time until wallclock timeout of the process.")
	stdoutByteLimit  = flag.Int64("stdoutlimit", 100*1024*1024*1024, "Threshold of emitted bytes to STDOUT by the child before calling Stop on the process (default 100GB).")
	debugMode        = flag.Bool("debug", false, "Debug logging enable")
	noWarn           = flag.Bool("nowarn", false, "Disable warnings on stats collection.")
)

func init() {
	flag.Parse()

	// Create a map of pointers to all the current flags
	flags := map[string]*flag.Flag{}
	flag.VisitAll(func(f *flag.Flag) {
		flags[f.Name] = f
	})

	// Remove the flags that were set on the command line
	flag.Visit(func(f *flag.Flag) {
		delete(flags, f.Name)
	})

	// Now for the flags that weren't set on the cli,
	// Look at the env for 'PBOX_<uppercase flag name>'
	// If it exists, use it to set the corresponding flag.
	for _, f := range flags {
		var buffer bytes.Buffer
		buffer.WriteString("PBOX_")
		buffer.WriteString(strings.ToUpper(f.Name))
		if os.Getenv(buffer.String()) != "" {
			f.Value.Set(os.Getenv(buffer.String()))
		}
	}
}

func main() {
	if *debugMode {
		log.SetLevel(log.DebugLevel)
	} else if *noWarn {
		log.SetLevel(log.ErrorLevel)
	}

	amqpConn, err := amqp.Dial(*uri)
	if err != nil {
		log.Fatalf("Failed to connect to AMQP: %s\n", err)
	}

	// Establish remote control channel prior to execution
	rc, err := agents.NewRemoteControl(amqpConn, *rmtKey, *exchange)
	if err != nil {
		log.Fatalf("NewRemoteControl failed: %s\n", err)
	}

	args := flag.Args()
	var cmdArgs []string
	var cmd string
	if len(args) > 0 {
		cmd = args[0]
	} else {
		log.Fatal("Did you forget a command to run?")
		return
	}

	log.Debugf("cmd: %s cmdArgs: %q\n", cmd, cmdArgs)

	done := make(chan error)

	// Initialize job
	job, err := agents.NewControlledProcess(cmd, args, done, *stdoutByteLimit)
	if err != nil {
		log.Fatalf("Failed to create a NewControlledProcess: %s\n", err)
		return
	}

	// Establish process statistics gathering agent
	// Agent will need to initially wait for the process to start, but should
	// establish an AMQP channel for message generation prior to the process
	// starting.
	stats, err := agents.NewProcessStats(
		amqpConn,
		*procStatsKey,
		*exchange,
		&job,
		*statsInterval,
	)

	log.Debugf("%#v\n", stats)

	log.Debugf("%#v\n", job)

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

	timer, err := agents.NewTimer(*wallclockTimeout)
	log.Debugf("Starting timer with timeout of: %v\n", *wallclockTimeout)
	timer.Start()

	go monitor(signals, rc, job, stats, timer, done)

	_ = <-done

	elapsedTime, _ := timer.ElapsedTime()
	// Print to standard out
	fmt.Printf("Task elapsed time: %.2f seconds.\n", elapsedTime.Seconds())
}

func monitor(
	signals chan os.Signal,
	rc *agents.RemoteControl,
	job agents.JobControl,
	ps agents.ProcessStats,
	timer agents.Timer,
	done chan error,
) {
	var err error
	var logSampling <-chan time.Time

	if *stdoutByteLimit > 0 {
		ticker := time.NewTicker(100 * time.Millisecond)
		// Replace the time channel with an actual ticker if this is in use
		logSampling = ticker.C
	}

	for {
		select {
		// Catch incoming signals and operate on them as if they were remote commands
		case sig := <-signals:
			switch sig {
			case syscall.SIGINT:
				log.Debugln("Caught SIGINT, graceful shutdown")
				ps.Sample()
				err = job.Stop()
			case syscall.SIGTERM:
				log.Debugln("Caught SIGTERM, end abruptly")
				job.Kill(-9)
			case syscall.SIGHUP:
				log.Debugln("Caught SIGHUP, emit stats")
				ps.Sample()
			case syscall.SIGQUIT:
				log.Debugln("Caught SIGQUIT, graceful shutdown")
				ps.Sample()
				err = job.Stop()
			}
		// Process incoming remote commands, toss unknown requests
		case cmd := <-rc.Commands:
			log.Debugf("Got a command %#v\n", cmd)
			switch cmd.Command {
			case "suspend":
				log.Debugln("RemoteCommand: Suspend")
				job.Suspend()
			case "resume":
				log.Debugln("RemoteCommand: Resume")
				job.Resume()
			case "kill":
				log.Debugln("RemoteCommand: Kill")
				var args int64
				var err error
				if len(cmd.Arguments) == 0 {
					args = -9
				} else {
					args, err = strconv.ParseInt(cmd.Arguments[0], 10, 32)
					if err != nil {
						log.Warnf("Unable to parse kill command argument[0] into int: %s\n", err)
						args = -9
					}
				}
				job.Kill(args)
			case "stop":
				log.Debugln("RemoteCommand: Stop")
				ps.Sample()
				if err := job.Stop(); err != nil {
					log.Fatalf("Error received while stopping sub-process: %s\n", err)
				}
			case "sample":
				log.Debugln("RemoteCommand: Sample")
				ps.Sample()
			case "change_sample_rate":
				log.Debugln("RemoteCommand: Change Stats Sample Rate")
				if len(cmd.Arguments) > 0 {
					log.Debugf("change_sample_rate arg[0]: %s\n", cmd.Arguments[0])
					d, err := time.ParseDuration(cmd.Arguments[0])
					if err == nil {
						ps.NewTicker(d)
					} else {
						log.Warnf("Unparseable duration argument to command change_sample_rate")
					}
				} else {
					log.Warnf("Missing argument to command change_sample_rate")
				}
			case "timer_reset":
				log.Debugln("RemoteCommand: Timer Reset")
				if err := timer.Reset(); err != nil {
					log.Fatalf("Error received from timer calling Reset: %s\n", err)
				}
			case "timer_start":
				log.Debugln("RemoteCommand: Timer Start")
				if err := timer.Start(); err != nil {
					log.Fatalf("Error received from timer calling Start: %s\n", err)
				}
			case "timer_stop":
				log.Debugln("RemoteCommand: Timer Stop")
				if err := timer.Stop(); err != nil {
					log.Fatalf("Error received from timer calling Stop: %s\n", err)
				}
			case "timer_resume":
				log.Debugln("RemoteCommand: Timer Resume")
				if err := timer.Resume(); err != nil {
					log.Fatalf("Error received from timer calling Resume: %s\n", err)
				}
			default:
				log.Debugf("Unknown command: %s\n", cmd)
			}
		case timeoutMsg := <-timer.Done():
			log.Debugf("Timer timeout message: %s\n", timeoutMsg)
			if err := job.Stop(); err != nil {
				log.Fatalf("Error received while stopping sub-process: %v\n", err)
				// If there was an error stopping the process, kill the porcess.
				job.Kill(-9)
			}
		case _ = <-job.Done():
			log.Debugln("Command exited gracefully; shutting down.")
			done <- err
		case _ = <-logSampling:
			if job.StdoutByteCount() > 2*(*stdoutByteLimit) {
				err = job.Kill(-9)
			} else if job.StdoutByteCount() > *stdoutByteLimit {
				err = job.Stop()
			}
		}
	}
}
<commit_msg>Fix #21 - Missing amqpConn.Close()<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"
	"time"

	log "github.com/nickjones/proc_box/Godeps/_workspace/src/github.com/Sirupsen/logrus"
	"github.com/nickjones/proc_box/Godeps/_workspace/src/github.com/streadway/amqp"
	"github.com/nickjones/proc_box/agents"
)

var (
	uri              = flag.String("uri", "amqp://guest:guest@localhost:5672", "AMQP connection URI.")
	exchange         = flag.String("exchange", "amq.topic", "AMQP exchange to bind.")
	rmtKey           = flag.String("rkey", "proc_box.remote_control", "AMQP routing key for remote process control.")
	procStatsKey     = flag.String("skey", "proc_box.stats", "AMQP routing key prefix for proc stats.")
	statsInterval    = flag.Duration("sint", 1*time.Minute, "Interval to emit process statistics.")
	wallclockTimeout = flag.Duration("timeout", 10*time.Minute, "The time until wallclock timeout of the process.")
	stdoutByteLimit  = flag.Int64("stdoutlimit", 100*1024*1024*1024, "Threshold of emitted bytes to STDOUT by the child before calling Stop on the process (default 100GB).")
	debugMode        = flag.Bool("debug", false, "Debug logging enable")
	noWarn           = flag.Bool("nowarn", false, "Disable warnings on stats collection.")
)

func init() {
	flag.Parse()

	// Create a map of pointers to all the current flags
	flags := map[string]*flag.Flag{}
	flag.VisitAll(func(f *flag.Flag) {
		flags[f.Name] = f
	})

	// Remove the flags that were set on the command line
	flag.Visit(func(f *flag.Flag) {
		delete(flags, f.Name)
	})

	// Now for the flags that weren't set on the cli,
	// Look at the env for 'PBOX_<uppercase flag name>'
	// If it exists, use it to set the corresponding flag.
	for _, f := range flags {
		var buffer bytes.Buffer
		buffer.WriteString("PBOX_")
		buffer.WriteString(strings.ToUpper(f.Name))
		if os.Getenv(buffer.String()) != "" {
			f.Value.Set(os.Getenv(buffer.String()))
		}
	}
}

func main() {
	if *debugMode {
		log.SetLevel(log.DebugLevel)
	} else if *noWarn {
		log.SetLevel(log.ErrorLevel)
	}

	amqpConn, err := amqp.Dial(*uri)
	if err != nil {
		log.Fatalf("Failed to connect to AMQP: %s\n", err)
	}
	defer amqpConn.Close()

	// Establish remote control channel prior to execution
	rc, err := agents.NewRemoteControl(amqpConn, *rmtKey, *exchange)
	if err != nil {
		log.Fatalf("NewRemoteControl failed: %s\n", err)
	}

	args := flag.Args()
	var cmdArgs []string
	var cmd string
	if len(args) > 0 {
		cmd = args[0]
	} else {
		log.Fatal("Did you forget a command to run?")
		return
	}

	log.Debugf("cmd: %s cmdArgs: %q\n", cmd, cmdArgs)

	done := make(chan error)

	// Initialize job
	job, err := agents.NewControlledProcess(cmd, args, done, *stdoutByteLimit)
	if err != nil {
		log.Fatalf("Failed to create a NewControlledProcess: %s\n", err)
		return
	}

	// Establish process statistics gathering agent
	// Agent will need to initially wait for the process to start, but should
	// establish an AMQP channel for message generation prior to the process
	// starting.
	stats, err := agents.NewProcessStats(
		amqpConn,
		*procStatsKey,
		*exchange,
		&job,
		*statsInterval,
	)

	log.Debugf("%#v\n", stats)

	log.Debugf("%#v\n", job)

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

	timer, err := agents.NewTimer(*wallclockTimeout)
	log.Debugf("Starting timer with timeout of: %v\n", *wallclockTimeout)
	timer.Start()

	go monitor(signals, rc, job, stats, timer, done)

	_ = <-done

	elapsedTime, _ := timer.ElapsedTime()
	// Print to standard out
	fmt.Printf("Task elapsed time: %.2f seconds.\n", elapsedTime.Seconds())
}

func monitor(
	signals chan os.Signal,
	rc *agents.RemoteControl,
	job agents.JobControl,
	ps agents.ProcessStats,
	timer agents.Timer,
	done chan error,
) {
	var err error
	var logSampling <-chan time.Time

	if *stdoutByteLimit > 0 {
		ticker := time.NewTicker(100 * time.Millisecond)
		// Replace the time channel with an actual ticker if this is in use
		logSampling = ticker.C
	}

	for {
		select {
		// Catch incoming signals and operate on them as if they were remote commands
		case sig := <-signals:
			switch sig {
			case syscall.SIGINT:
				log.Debugln("Caught SIGINT, graceful shutdown")
				ps.Sample()
				err = job.Stop()
			case syscall.SIGTERM:
				log.Debugln("Caught SIGTERM, end abruptly")
				job.Kill(-9)
			case syscall.SIGHUP:
				log.Debugln("Caught SIGHUP, emit stats")
				ps.Sample()
			case syscall.SIGQUIT:
				log.Debugln("Caught SIGQUIT, graceful shutdown")
				ps.Sample()
				err = job.Stop()
			}
		// Process incoming remote commands, toss unknown requests
		case cmd := <-rc.Commands:
			log.Debugf("Got a command %#v\n", cmd)
			switch cmd.Command {
			case "suspend":
				log.Debugln("RemoteCommand: Suspend")
				job.Suspend()
			case "resume":
				log.Debugln("RemoteCommand: Resume")
				job.Resume()
			case "kill":
				log.Debugln("RemoteCommand: Kill")
				var args int64
				var err error
				if len(cmd.Arguments) == 0 {
					args = -9
				} else {
					args, err = strconv.ParseInt(cmd.Arguments[0], 10, 32)
					if err != nil {
						log.Warnf("Unable to parse kill command argument[0] into int: %s\n", err)
						args = -9
					}
				}
				job.Kill(args)
			case "stop":
				log.Debugln("RemoteCommand: Stop")
				ps.Sample()
				if err := job.Stop(); err != nil {
					log.Fatalf("Error received while stopping sub-process: %s\n", err)
				}
			case "sample":
				log.Debugln("RemoteCommand: Sample")
				ps.Sample()
			case "change_sample_rate":
				log.Debugln("RemoteCommand: Change Stats Sample Rate")
				if len(cmd.Arguments) > 0 {
					log.Debugf("change_sample_rate arg[0]: %s\n", cmd.Arguments[0])
					d, err := time.ParseDuration(cmd.Arguments[0])
					if err == nil {
						ps.NewTicker(d)
					} else {
						log.Warnf("Unparseable duration argument to command change_sample_rate")
					}
				} else {
					log.Warnf("Missing argument to command change_sample_rate")
				}
			case "timer_reset":
				log.Debugln("RemoteCommand: Timer Reset")
				if err := timer.Reset(); err != nil {
					log.Fatalf("Error received from timer calling Reset: %s\n", err)
				}
			case "timer_start":
				log.Debugln("RemoteCommand: Timer Start")
				if err := timer.Start(); err != nil {
					log.Fatalf("Error received from timer calling Start: %s\n", err)
				}
			case "timer_stop":
				log.Debugln("RemoteCommand: Timer Stop")
				if err := timer.Stop(); err != nil {
					log.Fatalf("Error received from timer calling Stop: %s\n", err)
				}
			case "timer_resume":
				log.Debugln("RemoteCommand: Timer Resume")
				if err := timer.Resume(); err != nil {
					log.Fatalf("Error received from timer calling Resume: %s\n", err)
				}
			default:
				log.Debugf("Unknown command: %s\n", cmd)
			}
		case timeoutMsg := <-timer.Done():
			log.Debugf("Timer timeout message: %s\n", timeoutMsg)
			if err := job.Stop(); err != nil {
				log.Fatalf("Error received while stopping sub-process: %v\n", err)
				// If there was an error stopping the process, kill the porcess.
				job.Kill(-9)
			}
		case _ = <-job.Done():
			log.Debugln("Command exited gracefully; shutting down.")
			done <- err
		case _ = <-logSampling:
			if job.StdoutByteCount() > 2*(*stdoutByteLimit) {
				err = job.Kill(-9)
			} else if job.StdoutByteCount() > *stdoutByteLimit {
				err = job.Stop()
			}
		}
	}
}
<|endoftext|>


<commit_before>// 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"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

func main() {
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

func callbackHandler(w http.ResponseWriter, r *http.Request) {
	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {
			text, err := content.TextContent()
			_, err = bot.SendText([]string{content.From}, "OK "+text.Text)
			if err != nil {
				log.Println(err)
			}
		}
	}
}
<commit_msg>v.2.0.1<commit_after>// 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"
	"log"
	"net/http"
	"os"
	"strconv"
	"net/url"
  	"io/ioutil"
	"github.com/line/line-bot-sdk-go/linebot"
        "encoding/json"
)

var bot *linebot.Client

type GeoContent struct {
	LatLong string `json:"latLon"`
	Utm string `json:"utm"`
        Mgrs string `json:"mgrs"`
}

type ResultGeoLoc struct {
	Results GeoContent `json:"result"`
}
func getGeoLoc(body []byte) (*ResultGeoLoc, error) {
    var s = new(ResultGeoLoc)
    err := json.Unmarshal(body, &s)
    if(err != nil){
        fmt.Println("whoops:", err)
    }
    return s, err
}

func main() {
	// fixie
	fixieUrl, err := url.Parse(os.Getenv("FIXIE_URL"))
  	customClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(fixieUrl)}}
  	resp, err := customClient.Get("http://welcome.usefixie.com")
  	if (err != nil) {
    		println(err.Error())
    		return
  	}
  	defer resp.Body.Close()
  	body, err := ioutil.ReadAll(resp.Body)
  	println(string(body))

	// end fixie

	// line bot
	strID := os.Getenv("ChannelID")
	numID, err := strconv.ParseInt(strID, 10, 64)
	if err != nil {
		log.Fatal("Wrong environment setting about ChannelID")
	}

	bot, err = linebot.NewClient(numID, os.Getenv("ChannelSecret"), os.Getenv("MID"))
	log.Println("Bot:", bot, " err:", err)
	http.HandleFunc("/callback", callbackHandler)
	port := os.Getenv("PORT")
	addr := fmt.Sprintf(":%s", port)
	http.ListenAndServe(addr, nil)
}

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

	received, err := bot.ParseRequest(r)
	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}
	for _, result := range received.Results {
		content := result.Content()
		log.Println("-->", content)

		//Log detail receive content
		if content != nil {
			log.Println("RECEIVE Msg:", content.IsMessage, " OP:", content.IsOperation, " type:", content.ContentType, " from:", content.From, "to:", content.To, " ID:", content.ID)
		}
		/*
		if content != nil && content.IsMessage && content.ContentType == linebot.ContentTypeText {
			text, err := content.TextContent()
			_, err = bot.SendText([]string{content.From}, "Bot received : "+text.Text)

			if err != nil {
				log.Println(err)
			}
		}*/
		if content != nil && content.ContentType == linebot.ContentTypeLocation {
			loc, err := content.LocationContent()

			// add eggyo geo test
			resp, err := http.Get("http://eggyo-geo-node.herokuapp.com/geo/" + FloatToString(loc.Latitude) + "/" + FloatToString(loc.Longitude))
			if (err != nil) {
    				println(err.Error())
    				return
  			}
  			defer resp.Body.Close()
			body, err := ioutil.ReadAll(resp.Body)
                        log.Println(string(body))

                        geo, err := getGeoLoc([]byte(body))
			//_, err = bot.SendText([]string{content.From}, "OK "+text.Text)
			_, err = bot.SendText([]string{content.From}, "LatLong :" + geo.Results.LatLong)
_, err = bot.SendText([]string{content.From}, "Utm :" + geo.Results.Utm)
_, err = bot.SendText([]string{content.From}, "Mgrs :" + geo.Results.Mgrs)

                        if err != nil {
				log.Println(err)
			}
		}
	}
}
func FloatToString(input_num float64) string {
    // to convert a float number to a string
    return strconv.FormatFloat(input_num, 'f', 6, 64)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/service/s3"
	"log"
	"net/url"
	"os"
	"strings"
	"sync"
)

type Bucket struct {
	Name   string
	Prefix string
	Client *s3.S3
}

func NewBucket(bucketUrl string, region string) (*Bucket, error) {
	u, err := url.Parse(bucketUrl)

	if err != nil {
		return nil, err
	}

	if u.Scheme != "s3" {
		return nil, fmt.Errorf("Invalid S3 URL scheme: %s", u.Scheme)
	}

	if region == "" {
		req := s3.GetBucketLocationInput{
			Bucket: aws.String(u.Host),
		}

		res, err := s3.New(nil).GetBucketLocation(&req)

		if err != nil {
			return nil, fmt.Errorf("Error while retrieving bucket location: %s", err)
		}

		region = *res.LocationConstraint
	}

	client := s3.New(aws.NewConfig().WithRegion(region))

	prefix := u.Path[1:]

	if !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	return &Bucket{
		Name:   u.Host,
		Prefix: prefix,
		Client: client,
	}, nil
}

func listBucket(bucket *Bucket, out chan string) error {
	defer close(out)

	listRequest := s3.ListObjectsInput{
		Bucket: aws.String(bucket.Name),
		Prefix: aws.String(bucket.Prefix),
	}

	callback := func(result *s3.ListObjectsOutput, lastPage bool) bool {
		for _, obj := range result.Contents {
			out <- (*obj.Key)[len(bucket.Prefix):]
		}

		return true
	}

	return bucket.Client.ListObjectsPages(&listRequest, callback)
}

func copyKeys(sourceBucket, destBucket *Bucket, keys <-chan string) error {
	const concurrency = 50
	copyErrors := make(chan error, concurrency)
	wg := sync.WaitGroup{}

	worker := func() error {
		defer wg.Done()

		for key := range keys {
			if err := copyKey(sourceBucket, destBucket, key); err != nil {
				return fmt.Errorf("Error while copying key %s: %s", key, err)
			}
		}

		return nil
	}

	wg.Add(concurrency)

	for i := 0; i < concurrency; i++ {
		go func() {
			copyErrors <- worker()
		}()
	}

	wg.Wait()

	var err error

	for i := 0; i < concurrency; i++ {
		if copyError := <-copyErrors; copyError != nil {
			err = copyError
		}
	}

	return err
}

func copyKey(sourceBucket, destBucket *Bucket, key string) error {
	sourceKey := sourceBucket.Prefix + key
	req := s3.CopyObjectInput{
		Bucket:     aws.String(destBucket.Name),
		CopySource: aws.String(sourceBucket.Name + "/" + sourceKey),
		Key:        aws.String(destBucket.Prefix + key),
	}

	log.Printf("%s → %s", sourceKey, *req.Key)

	if *dryRun {
		return nil
	}

	_, err := destBucket.Client.CopyObject(&req)

	if err != nil {
		return err
	}

	return nil
}

func deleteKeys(bucket *Bucket, keys <-chan string) error {
	buffer := make([]string, 0, 100)

	doDelete := func() error {
		objects := make([]*s3.ObjectIdentifier, len(buffer))

		for i, v := range buffer {
			objects[i] = &s3.ObjectIdentifier{
				Key: aws.String(bucket.Prefix + v),
			}
		}

		req := s3.DeleteObjectsInput{
			Bucket: &bucket.Name,
			Delete: &s3.Delete{
				Objects: objects,
			},
		}

		if _, err := bucket.Client.DeleteObjects(&req); err != nil {
			return err
		}

		return nil
	}

	for key := range keys {
		buffer = append(buffer, key)

		if len(buffer) == cap(buffer) {
			if err := doDelete(); err != nil {
				return err
			}
		}
	}

	if len(buffer) > 0 {
		if err := doDelete(); err != nil {
			return err
		}
	}

	return nil
}

func compareKeys(sourceKeys, destKeys <-chan string, toCopy, toDelete chan<- string) {
	sourceFinished := false
	destFinished := false

	var sourceCurrent *string
	var destCurrent *string

	buffer := func(from <-chan string, to **string, finished *bool) {
		if *finished || *to != nil {
			return
		}

		key, ok := <-from

		*finished = !ok

		if ok {
			*to = &key
		}
	}

	cmp := func(a, b *string) int {
		if a == nil && b == nil {
			return 0
		}

		if a == nil {
			return 1
		}

		if b == nil {
			return -1
		}

		if *a == *b {
			return 0
		}

		if *a > *b {
			return 1
		}

		return -1
	}

	for {
		buffer(sourceKeys, &sourceCurrent, &sourceFinished)
		buffer(destKeys, &destCurrent, &destFinished)

		if sourceFinished && destFinished {
			close(toCopy)
			close(toDelete)
			return
		}

		switch cmp(sourceCurrent, destCurrent) {
		case -1:
			toCopy <- *sourceCurrent
			sourceCurrent = nil
		case 0:
			sourceCurrent = nil
			destCurrent = nil
		case 1:
			toDelete <- *destCurrent
			destCurrent = nil
		}
	}
}

func runCopy(sourceBucket, destBucket *Bucket) error {
	sourceKeys := make(chan string)
	destKeys := make(chan string)
	keysToCopy := make(chan string)
	keysToDelete := make(chan string)
	listSourceKeysError := make(chan error, 1)
	listDestKeysError := make(chan error, 1)
	copyError := make(chan error, 1)
	deleteError := make(chan error, 1)

	go func() {
		listSourceKeysError <- listBucket(sourceBucket, sourceKeys)
	}()

	go func() {
		listDestKeysError <- listBucket(destBucket, destKeys)
	}()

	go func() {
		copyError <- copyKeys(sourceBucket, destBucket, keysToCopy)
	}()

	go func() {
		deleteError <- deleteKeys(destBucket, keysToDelete)
	}()

	compareKeys(sourceKeys, destKeys, keysToCopy, keysToDelete)

	for {
		if listSourceKeysError == nil && listDestKeysError == nil && copyError == nil && deleteError == nil {
			return nil
		}

		select {
		case err := <-listSourceKeysError:
			if err != nil {
				return fmt.Errorf("Error while listing keys in source bucket: %s", err)
			}

			listSourceKeysError = nil
		case err := <-listDestKeysError:
			if err != nil {
				return fmt.Errorf("Error while listing keys in destination bucket: %s", err)
			}

			listDestKeysError = nil
		case err := <-copyError:
			if err != nil {
				return fmt.Errorf("Error while copying keys to destination bucket: %s", err)
			}

			copyError = nil
		case err := <-deleteError:
			if err != nil {
				return fmt.Errorf("Error while deleting keys from destination bucket: %s", err)
			}

			deleteError = nil
		}
	}
}

var sourceRegion = flag.String("sourceRegion", "", "Region of the source S3 bucket (auto detected if not specified)")
var destRegion = flag.String("destRegion", "", "Region of the destination S3 bucket (auto detected if not specified)")
var dryRun = flag.Bool("dryRun", false, "Don't actually do the copy")

func main() {
	flag.Usage = func() {
		const usage = `Usage: %s SOURCE DEST

Mirrors a S3 folder to another one, potentially in a different bucket.

SOURCE and DEST should be S3 URLs in the form s3://bucket-name/prefix .
Objects metadata is preserved during the copy.

Additional command line options:
`

		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(1)
	}

	// We only use the default client to fetch bucket location.
	defaults.DefaultConfig.Region = aws.String("us-east-1")
	defaults.DefaultConfig.S3ForcePathStyle = aws.Bool(true)

	sourceUrl := flag.Arg(0)
	destUrl := flag.Arg(1)

	sourceBucket, err := NewBucket(sourceUrl, *sourceRegion)

	if err != nil {
		log.Fatalf("Error while configuring source bucket: %s", err)
	}

	destBucket, err := NewBucket(destUrl, *destRegion)

	if err != nil {
		log.Fatalf("Error while configuring destination bucket: %s", err)
	}

	if err := runCopy(sourceBucket, destBucket); err != nil {
		log.Fatalf(err.Error())
	}
}
<commit_msg>Add command line option to force overwriting existing keys<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/service/s3"
	"log"
	"net/url"
	"os"
	"strings"
	"sync"
)

type Bucket struct {
	Name   string
	Prefix string
	Client *s3.S3
}

func NewBucket(bucketUrl string, region string) (*Bucket, error) {
	u, err := url.Parse(bucketUrl)

	if err != nil {
		return nil, err
	}

	if u.Scheme != "s3" {
		return nil, fmt.Errorf("Invalid S3 URL scheme: %s", u.Scheme)
	}

	if region == "" {
		req := s3.GetBucketLocationInput{
			Bucket: aws.String(u.Host),
		}

		res, err := s3.New(nil).GetBucketLocation(&req)

		if err != nil {
			return nil, fmt.Errorf("Error while retrieving bucket location: %s", err)
		}

		region = *res.LocationConstraint
	}

	client := s3.New(aws.NewConfig().WithRegion(region))

	prefix := u.Path[1:]

	if !strings.HasSuffix(prefix, "/") {
		prefix += "/"
	}

	return &Bucket{
		Name:   u.Host,
		Prefix: prefix,
		Client: client,
	}, nil
}

func listBucket(bucket *Bucket, out chan string) error {
	defer close(out)

	listRequest := s3.ListObjectsInput{
		Bucket: aws.String(bucket.Name),
		Prefix: aws.String(bucket.Prefix),
	}

	callback := func(result *s3.ListObjectsOutput, lastPage bool) bool {
		for _, obj := range result.Contents {
			out <- (*obj.Key)[len(bucket.Prefix):]
		}

		return true
	}

	return bucket.Client.ListObjectsPages(&listRequest, callback)
}

func copyKeys(sourceBucket, destBucket *Bucket, keys <-chan string) error {
	const concurrency = 50
	copyErrors := make(chan error, concurrency)
	wg := sync.WaitGroup{}

	worker := func() error {
		defer wg.Done()

		for key := range keys {
			if err := copyKey(sourceBucket, destBucket, key); err != nil {
				return fmt.Errorf("Error while copying key %s: %s", key, err)
			}
		}

		return nil
	}

	wg.Add(concurrency)

	for i := 0; i < concurrency; i++ {
		go func() {
			copyErrors <- worker()
		}()
	}

	wg.Wait()

	var err error

	for i := 0; i < concurrency; i++ {
		if copyError := <-copyErrors; copyError != nil {
			err = copyError
		}
	}

	return err
}

func copyKey(sourceBucket, destBucket *Bucket, key string) error {
	sourceKey := sourceBucket.Prefix + key
	req := s3.CopyObjectInput{
		Bucket:     aws.String(destBucket.Name),
		CopySource: aws.String(sourceBucket.Name + "/" + sourceKey),
		Key:        aws.String(destBucket.Prefix + key),
	}

	log.Printf("%s → %s", sourceKey, *req.Key)

	if *dryRun {
		return nil
	}

	_, err := destBucket.Client.CopyObject(&req)

	if err != nil {
		return err
	}

	return nil
}

func deleteKeys(bucket *Bucket, keys <-chan string) error {
	buffer := make([]string, 0, 100)

	doDelete := func() error {
		objects := make([]*s3.ObjectIdentifier, len(buffer))

		for i, v := range buffer {
			objects[i] = &s3.ObjectIdentifier{
				Key: aws.String(bucket.Prefix + v),
			}
		}

		req := s3.DeleteObjectsInput{
			Bucket: &bucket.Name,
			Delete: &s3.Delete{
				Objects: objects,
			},
		}

		if _, err := bucket.Client.DeleteObjects(&req); err != nil {
			return err
		}

		return nil
	}

	for key := range keys {
		buffer = append(buffer, key)

		if len(buffer) == cap(buffer) {
			if err := doDelete(); err != nil {
				return err
			}
		}
	}

	if len(buffer) > 0 {
		if err := doDelete(); err != nil {
			return err
		}
	}

	return nil
}

func compareKeys(sourceKeys, destKeys <-chan string, toCopy, toDelete chan<- string) {
	sourceFinished := false
	destFinished := false

	var sourceCurrent *string
	var destCurrent *string

	buffer := func(from <-chan string, to **string, finished *bool) {
		if *finished || *to != nil {
			return
		}

		key, ok := <-from

		*finished = !ok

		if ok {
			*to = &key
		}
	}

	type Action int

	const (
		Copy Action = iota
		Skip
		Delete
	)

	cmp := func(a, b *string) Action {
		if a == nil && b == nil {
			return Skip
		}

		if a == nil {
			return Delete
		}

		if b == nil {
			return Copy
		}

		if *a == *b {
			return Skip
		}

		if *a > *b {
			return Delete
		}

		return Copy
	}

	for {
		buffer(sourceKeys, &sourceCurrent, &sourceFinished)
		buffer(destKeys, &destCurrent, &destFinished)

		if sourceFinished && destFinished {
			close(toCopy)
			close(toDelete)
			return
		}

		action := cmp(sourceCurrent, destCurrent)

		if action == Skip && *overwrite {
			action = Copy
		}

		switch action {
		case Copy:
			toCopy <- *sourceCurrent
			sourceCurrent = nil
		case Skip:
			sourceCurrent = nil
			destCurrent = nil
		case Delete:
			toDelete <- *destCurrent
			destCurrent = nil
		}
	}
}

func runCopy(sourceBucket, destBucket *Bucket) error {
	sourceKeys := make(chan string)
	destKeys := make(chan string)
	keysToCopy := make(chan string)
	keysToDelete := make(chan string)
	listSourceKeysError := make(chan error, 1)
	listDestKeysError := make(chan error, 1)
	copyError := make(chan error, 1)
	deleteError := make(chan error, 1)

	go func() {
		listSourceKeysError <- listBucket(sourceBucket, sourceKeys)
	}()

	go func() {
		listDestKeysError <- listBucket(destBucket, destKeys)
	}()

	go func() {
		copyError <- copyKeys(sourceBucket, destBucket, keysToCopy)
	}()

	go func() {
		deleteError <- deleteKeys(destBucket, keysToDelete)
	}()

	compareKeys(sourceKeys, destKeys, keysToCopy, keysToDelete)

	for {
		if listSourceKeysError == nil && listDestKeysError == nil && copyError == nil && deleteError == nil {
			return nil
		}

		select {
		case err := <-listSourceKeysError:
			if err != nil {
				return fmt.Errorf("Error while listing keys in source bucket: %s", err)
			}

			listSourceKeysError = nil
		case err := <-listDestKeysError:
			if err != nil {
				return fmt.Errorf("Error while listing keys in destination bucket: %s", err)
			}

			listDestKeysError = nil
		case err := <-copyError:
			if err != nil {
				return fmt.Errorf("Error while copying keys to destination bucket: %s", err)
			}

			copyError = nil
		case err := <-deleteError:
			if err != nil {
				return fmt.Errorf("Error while deleting keys from destination bucket: %s", err)
			}

			deleteError = nil
		}
	}
}

var sourceRegion = flag.String("sourceRegion", "", "Region of the source S3 bucket (auto detected if not specified)")
var destRegion = flag.String("destRegion", "", "Region of the destination S3 bucket (auto detected if not specified)")
var dryRun = flag.Bool("dryRun", false, "Don't actually do the copy")
var overwrite = flag.Bool("overwrite", false, "Force copy even if destination key already exists")

func main() {
	flag.Usage = func() {
		const usage = `Usage: %s SOURCE DEST

Mirrors a S3 folder to another one, potentially in a different bucket.

SOURCE and DEST should be S3 URLs in the form s3://bucket-name/prefix .
Objects metadata is preserved during the copy.

Additional command line options:
`

		fmt.Fprintf(os.Stderr, usage, os.Args[0])
		flag.PrintDefaults()
	}

	flag.Parse()

	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(1)
	}

	// We only use the default client to fetch bucket location.
	defaults.DefaultConfig.Region = aws.String("us-east-1")
	defaults.DefaultConfig.S3ForcePathStyle = aws.Bool(true)

	sourceUrl := flag.Arg(0)
	destUrl := flag.Arg(1)

	sourceBucket, err := NewBucket(sourceUrl, *sourceRegion)

	if err != nil {
		log.Fatalf("Error while configuring source bucket: %s", err)
	}

	destBucket, err := NewBucket(destUrl, *destRegion)

	if err != nil {
		log.Fatalf("Error while configuring destination bucket: %s", err)
	}

	if err := runCopy(sourceBucket, destBucket); err != nil {
		log.Fatalf(err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"http"
	"rpc"
)

var (
	listenAddr = flag.String("http", ":9980", "http listen address")
	dataFile   = flag.String("file", "store.gob", "data store file name")
	hostname   = flag.String("host", "r.nf.id.au", "http host name")
	masterAddr = flag.String("master", "", "RPC master address")
	rpcEnabled = flag.Bool("rpc", false, "act as RPC master server")
)

var store Store

func main() {
	flag.Parse()
	if *masterAddr != "" {
		store = NewProxyStore(*masterAddr)
	} else {
		store = NewURLStore(*dataFile)
	}
	if *rpcEnabled {
		rpc.RegisterName("Store", store)
		rpc.HandleHTTP()
	}
	http.HandleFunc("/", Redirect)
	http.HandleFunc("/add", Add)
	http.ListenAndServe(*listenAddr, nil)
}

func Redirect(w http.ResponseWriter, r *http.Request) {
	key := r.URL.Path[1:]
	if key == "favicon.ico" || key == "" {
		http.NotFound(w, r)
		return
	}
	var url string
	if err := store.Get(&key, &url); err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, url, http.StatusFound)
}

func Add(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if url == "" {
		fmt.Fprint(w, addform)
		return
	}
	var key string
	if err := store.Put(&url, &key); err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "http://%s/%s", *hostname, key)
}

const addform = `
<form method="POST" action="/add">
URL: <input type="text" name="url">
<input type="submit" value="Add">
</form>
`
<commit_msg>tweaks<commit_after>package main

import (
	"flag"
	"fmt"
	"http"
	"rpc"
)

var (
	listenAddr = flag.String("http", ":9980", "http listen address")
	dataFile   = flag.String("file", "store.gob", "data store file name")
	hostname   = flag.String("host", "r.nf.id.au", "http host name")
	masterAddr = flag.String("master", "", "RPC master address")
	rpcEnabled = flag.Bool("rpc", false, "enable RPC server")
)

var store Store

func main() {
	flag.Parse()
	if *masterAddr != "" {
		store = NewProxyStore(*masterAddr)
	} else {
		store = NewURLStore(*dataFile)
	}
	if *rpcEnabled {
		rpc.RegisterName("Store", store)
		rpc.HandleHTTP()
	}
	http.HandleFunc("/", Redirect)
	http.HandleFunc("/add", Add)
	http.ListenAndServe(*listenAddr, nil)
}

func Redirect(w http.ResponseWriter, r *http.Request) {
	key := r.URL.Path[1:]
	if key == "favicon.ico" || key == "" {
		http.NotFound(w, r)
		return
	}
	var url string
	if err := store.Get(&key, &url); err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, url, http.StatusFound)
}

func Add(w http.ResponseWriter, r *http.Request) {
	url := r.FormValue("url")
	if url == "" {
		fmt.Fprint(w, addform)
		return
	}
	var key string
	if err := store.Put(&url, &key); err != nil {
		http.Error(w, err.String(), http.StatusInternalServerError)
		return
	}
	fmt.Fprintf(w, "http://%s/%s", *hostname, key)
}

const addform = `
<form method="POST" action="/add">
URL: <input type="text" name="url">
<input type="submit" value="Add">
</form>
`
<|endoftext|>


<commit_before>package main

import (
	"github.com/ant0ine/go-json-rest/rest"
	"log"
	"net/http"
	"sync"
	"path/filepath"
	"os"
	"./utils"
)

func main() {
	api := rest.NewApi()
	api.Use(rest.DefaultDevStack...)
	router, err := rest.MakeRouter(
		rest.Get("/files", GetFiles),
		rest.Post("/kick", RestartApp),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}

type FileEntry struct {
	Name     string
	Checksum string
}

var store = []*FileEntry{}

var lock = sync.RWMutex{}

func GetFiles(w rest.ResponseWriter, r *rest.Request) {
	dir := "./";
	lock.RLock()
	err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if f.IsDir() {
			return nil
		}
		fileEntry := FileEntry{}
		fileEntry.Name = path
		checksum, _ := utils.ChecksumsForFile(path)
		fileEntry.Checksum = checksum.SHA256
		store = append(store, &fileEntry)
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	lock.RUnlock()

	w.WriteJson(store)
}

func RestartApp(w rest.ResponseWriter, r *rest.Request) {
	lock.RLock()
	lock.RUnlock()
	fileEntry := FileEntry{}
	w.WriteJson(fileEntry)
}
<commit_msg>restart daemon<commit_after>package main

import (
	"github.com/ant0ine/go-json-rest/rest"
	"log"
	"net/http"
	"sync"
	"path/filepath"
	"os"
	"./utils"
	"strings"
	"os/exec"
	"github.com/matryer/runner"
)

var app_cmd = "python -m http.server"

func main() {
	api := rest.NewApi()
	api.Use(rest.DefaultDevStack...)
	router, err := rest.MakeRouter(
		rest.Get("/files", GetFiles),
		rest.Post("/kick", RestartApp),
	)
	if err != nil {
		log.Fatal(err)
	}
	api.SetApp(router)
	log.Fatal(http.ListenAndServe(":8080", api.MakeHandler()))
}

type FileEntry struct {
	Name     string
	Checksum string
}

var store = []*FileEntry{}

var lock = sync.RWMutex{}
var task *runner.Task

func GetFiles(w rest.ResponseWriter, r *rest.Request) {
	dir := "./";
	lock.RLock()
	err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if f.IsDir() {
			return nil
		}
		fileEntry := FileEntry{}
		fileEntry.Name = path
		checksum, _ := utils.ChecksumsForFile(path)
		fileEntry.Checksum = checksum.SHA256
		store = append(store, &fileEntry)
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
	lock.RUnlock()

	w.WriteJson(store)
}

func RestartApp(w rest.ResponseWriter, r *rest.Request) {
	lock.RLock()
	parts := strings.Fields(app_cmd)
    head := parts[0]
    parts = parts[1:len(parts)]
	cmd := exec.Command(head, parts...)

	if task != nil {
		task.Stop()
	}

	task = runner.Go(func(shouldStop runner.S) error {
		for {
			cmd.Start()
			if shouldStop() {
				cmd.Process.Kill()
				break
			}
		}
		return nil
	})

	lock.RUnlock()
	fileEntry := FileEntry{}
	w.WriteJson(fileEntry)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"github.com/msgehard/go-exercism/configuration"
)

func main() {
	app := cli.NewApp()
	app.Name = "exercism"
	app.Usage = "A command line tool to interact with http://exercism.io"
	app.Version = VERSION
	app.Commands = []cli.Command{
		{
			Name:      "current",
			ShortName: "c",
			Usage:     "Show the current assignments",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				currentAssignments, err := FetchAssignments(config, FetchEndpoints["current"])
				if err != nil {
					fmt.Println(err)
					return
				}

				fmt.Println("Current Assignments")

				for _, a := range currentAssignments {
					fmt.Printf("%v: %v\n", strings.Title(a.Track), a.Slug)
				}
			},
		},
		{
			Name:      "demo",
			ShortName: "d",
			Usage:     "Fetch first assignment for each language from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					config, err = configuration.Demo()
					if err != nil {
						fmt.Println(err)
						return
					}
				}
				assignments, err := FetchAssignments(config, FetchEndpoints["demo"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}
			},
		},
		{
			Name:      "fetch",
			ShortName: "f",
			Usage:     "Fetch current assignment from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				assignments, err := FetchAssignments(config,
					FetchEndpoints["current"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}
			},
		},
		{
			Name:      "login",
			ShortName: "l",
			Usage:     "Save exercism.io api credentials",
			Action: func(c *cli.Context) {
				configuration.ToFile(configuration.HomeDir(), askForConfigInfo())
			},
		},
		{
			Name:      "logout",
			ShortName: "o",
			Usage:     "Clear exercism.io api credentials",
			Action: func(c *cli.Context) {
				Logout(configuration.HomeDir())
			},
		},
		{
			Name:      "peek",
			ShortName: "p",
			Usage:     "Fetch upcoming assignment from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				assignments, err := FetchAssignments(config,
					FetchEndpoints["next"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}
			},
		},
		{
			Name:      "submit",
			ShortName: "s",
			Usage:     "Submit code to exercism.io on your current assignment",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				if len(c.Args()) == 0 {
					fmt.Println("Please enter a file name")
					return
				}

				filename := c.Args()[0]

				// Make filename relative to config.ExercismDirectory.
				absPath, err := absolutePath(filename)
				if err != nil {
					fmt.Printf("Couldn't find %v: %v\n", filename, err)
					return
				}
				exDir := config.ExercismDirectory + string(filepath.Separator)
				if !strings.HasPrefix(absPath, exDir) {
					fmt.Printf("%v is not under your exercism project path (%v)\n", absPath, exDir)
					return
				}
				filename = absPath[len(exDir):]

				if IsTest(filename) {
					fmt.Println("It looks like this is a test, please enter an example file name.")
					return
				}

				code, err := ioutil.ReadFile(absPath)
				if err != nil {
					fmt.Printf("Error reading %v: %v\n", absPath, err)
					return
				}

				response, err := SubmitAssignment(config, filename, code)
				if err != nil {
					fmt.Printf("There was an issue with your submission: %v\n", err)
					return
				}

				fmt.Printf("For feedback on your submission visit %s%s%s.\n",
					config.Hostname, "/submissions/", response.Id)

			},
		},
		{
			Name:      "unsubmit",
			ShortName: "u",
			Usage:     "Delete the last submission",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				response, err := UnsubmitAssignment(config)
				if err != nil {
					fmt.Println(err)
					return
				}

				if response != "" {
					return
				}

				fmt.Println("The last submission was successfully deleted.")
			},
		},
		{
			Name:      "whoami",
			ShortName: "w",
			Usage:     "Get the github username that you are logged in as",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				fmt.Println(config.GithubUsername)
			},
		},
	}
	app.Run(os.Args)
}

func askForConfigInfo() (c configuration.Config) {
	var un, key, dir string

	currentDir, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	fmt.Print("Your GitHub username: ")
	_, err = fmt.Scanln(&un)
	if err != nil {
		panic(err)
	}

	fmt.Print("Your exercism.io API key: ")
	_, err = fmt.Scanln(&key)
	if err != nil {
		panic(err)
	}

	fmt.Println("What is your exercism exercises project path?")
	fmt.Printf("Press Enter to select the default (%s):\n", currentDir)
	fmt.Print("> ")
	_, err = fmt.Scanln(&dir)
	if err != nil && err.Error() != "unexpected newline" {
		panic(err)
	}
	dir, err = absolutePath(dir)
	if err != nil {
		panic(err)
	}

	if dir == "" {
		dir = currentDir
	}

	return configuration.Config{GithubUsername: un, ApiKey: key, ExercismDirectory: configuration.ReplaceTilde(dir), Hostname: "http://exercism.io"}
}

func absolutePath(path string) (string, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return "", err
	}
	return filepath.EvalSymlinks(path)
}
<commit_msg>Tell the user where exercises got fetched to.<commit_after>package main

import (
	"fmt"
	"github.com/codegangsta/cli"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"github.com/msgehard/go-exercism/configuration"
)

func main() {
	app := cli.NewApp()
	app.Name = "exercism"
	app.Usage = "A command line tool to interact with http://exercism.io"
	app.Version = VERSION
	app.Commands = []cli.Command{
		{
			Name:      "current",
			ShortName: "c",
			Usage:     "Show the current assignments",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				currentAssignments, err := FetchAssignments(config, FetchEndpoints["current"])
				if err != nil {
					fmt.Println(err)
					return
				}

				fmt.Println("Current Assignments")

				for _, a := range currentAssignments {
					fmt.Printf("%v: %v\n", strings.Title(a.Track), a.Slug)
				}
			},
		},
		{
			Name:      "demo",
			ShortName: "d",
			Usage:     "Fetch first assignment for each language from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					config, err = configuration.Demo()
					if err != nil {
						fmt.Println(err)
						return
					}
				}
				assignments, err := FetchAssignments(config, FetchEndpoints["demo"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}
			},
		},
		{
			Name:      "fetch",
			ShortName: "f",
			Usage:     "Fetch current assignment from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				assignments, err := FetchAssignments(config,
					FetchEndpoints["current"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}

				fmt.Printf("Exercises written to %s\n", config.ExercismDirectory)
			},
		},
		{
			Name:      "login",
			ShortName: "l",
			Usage:     "Save exercism.io api credentials",
			Action: func(c *cli.Context) {
				configuration.ToFile(configuration.HomeDir(), askForConfigInfo())
			},
		},
		{
			Name:      "logout",
			ShortName: "o",
			Usage:     "Clear exercism.io api credentials",
			Action: func(c *cli.Context) {
				Logout(configuration.HomeDir())
			},
		},
		{
			Name:      "peek",
			ShortName: "p",
			Usage:     "Fetch upcoming assignment from exercism.io",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}
				assignments, err := FetchAssignments(config,
					FetchEndpoints["next"])
				if err != nil {
					fmt.Println(err)
					return
				}

				for _, a := range assignments {
					err := SaveAssignment(config.ExercismDirectory, a)
					if err != nil {
						fmt.Println(err)
					}
				}
			},
		},
		{
			Name:      "submit",
			ShortName: "s",
			Usage:     "Submit code to exercism.io on your current assignment",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				if len(c.Args()) == 0 {
					fmt.Println("Please enter a file name")
					return
				}

				filename := c.Args()[0]

				// Make filename relative to config.ExercismDirectory.
				absPath, err := absolutePath(filename)
				if err != nil {
					fmt.Printf("Couldn't find %v: %v\n", filename, err)
					return
				}
				exDir := config.ExercismDirectory + string(filepath.Separator)
				if !strings.HasPrefix(absPath, exDir) {
					fmt.Printf("%v is not under your exercism project path (%v)\n", absPath, exDir)
					return
				}
				filename = absPath[len(exDir):]

				if IsTest(filename) {
					fmt.Println("It looks like this is a test, please enter an example file name.")
					return
				}

				code, err := ioutil.ReadFile(absPath)
				if err != nil {
					fmt.Printf("Error reading %v: %v\n", absPath, err)
					return
				}

				response, err := SubmitAssignment(config, filename, code)
				if err != nil {
					fmt.Printf("There was an issue with your submission: %v\n", err)
					return
				}

				fmt.Printf("For feedback on your submission visit %s%s%s.\n",
					config.Hostname, "/submissions/", response.Id)

			},
		},
		{
			Name:      "unsubmit",
			ShortName: "u",
			Usage:     "Delete the last submission",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				response, err := UnsubmitAssignment(config)
				if err != nil {
					fmt.Println(err)
					return
				}

				if response != "" {
					return
				}

				fmt.Println("The last submission was successfully deleted.")
			},
		},
		{
			Name:      "whoami",
			ShortName: "w",
			Usage:     "Get the github username that you are logged in as",
			Action: func(c *cli.Context) {
				config, err := configuration.FromFile(configuration.HomeDir())
				if err != nil {
					fmt.Println("Are you sure you are logged in? Please login again.")
					return
				}

				fmt.Println(config.GithubUsername)
			},
		},
	}
	app.Run(os.Args)
}

func askForConfigInfo() (c configuration.Config) {
	var un, key, dir string

	currentDir, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	fmt.Print("Your GitHub username: ")
	_, err = fmt.Scanln(&un)
	if err != nil {
		panic(err)
	}

	fmt.Print("Your exercism.io API key: ")
	_, err = fmt.Scanln(&key)
	if err != nil {
		panic(err)
	}

	fmt.Println("What is your exercism exercises project path?")
	fmt.Printf("Press Enter to select the default (%s):\n", currentDir)
	fmt.Print("> ")
	_, err = fmt.Scanln(&dir)
	if err != nil && err.Error() != "unexpected newline" {
		panic(err)
	}
	dir, err = absolutePath(dir)
	if err != nil {
		panic(err)
	}

	if dir == "" {
		dir = currentDir
	}

	return configuration.Config{GithubUsername: un, ApiKey: key, ExercismDirectory: configuration.ReplaceTilde(dir), Hostname: "http://exercism.io"}
}

func absolutePath(path string) (string, error) {
	path, err := filepath.Abs(path)
	if err != nil {
		return "", err
	}
	return filepath.EvalSymlinks(path)
}
<|endoftext|>


<commit_before>package zipkinproxy

import (
	"github.com/flachnetz/dd-zipkin-proxy/datadog"
	"github.com/flachnetz/dd-zipkin-proxy/proxy"
	"github.com/flachnetz/go-admin"
	"github.com/flachnetz/startup"
	"github.com/flachnetz/startup/startup_base"
	"github.com/flachnetz/startup/startup_http"
	"github.com/flachnetz/startup/startup_metrics"
	"github.com/jessevdk/go-flags"
	"github.com/julienschmidt/httprouter"
	"github.com/pkg/profile"
	"github.com/sirupsen/logrus"
	"net/http"

	"regexp"
	"strings"

	_ "github.com/apache/thrift/lib/go/thrift"
)

var log = logrus.WithField("prefix", "main")

type SpanConverter func(span proxy.Span) (proxy.Span, error)

func Main(spanConverter SpanConverter) {
	var opts struct {
		Base    startup_base.BaseOptions       `group:"Base options"`
		HTTP    startup_http.HTTPOptions       `group:"HTTP server options"`
		Metrics startup_metrics.MetricsOptions `group:"Metrics configuration"`

		DisableSpanCorrection bool `long:"disable-span-correction" description:"Do not to correct the spans."`

		TraceAgent struct {
			Host string `long:"trace-host" value:"localhost" description:"Hostname of the trace agent."`
			Port string `long:"trace-port" value:"8126" description:"Port of the trace agent."`
		}
	}

	defer profile.Start().Stop()

	opts.Metrics.Inputs.MetricsPrefix = "zipkin.proxy"

	startup.MustParseCommandLine(&opts)

	var channels []chan<- proxy.Span

	{
		log.Info("Enable forwarding of spans to datadog trace-agent")
		datadog.Initialize(opts.TraceAgent.Host + ":" + opts.TraceAgent.Port)

		// accept zipkin spans
		spans := make(chan proxy.Span, 1024)
		channels = append(channels, spans)

		go datadog.Sink(spans)
	}

	// a channel to store the last spans that were received
	var buffer *SpansBuffer
	{
		zipkinSpans := make(chan proxy.Span, 1024)
		channels = append(channels, zipkinSpans)

		// just keep references to previous spans.
		buffer = NewSpansBuffer(2048)
		go buffer.ReadFrom(zipkinSpans)
	}

	// multiplex input channel to all the target channels
	proxySpans := make(chan proxy.Span, 16)
	go forwardSpansToChannels(proxySpans, channels, spanConverter)

	originalZipkinSpans := make(chan proxy.Span, 1024)
	if opts.DisableSpanCorrection {
		go PipeThroughSpans(originalZipkinSpans, proxySpans)
	} else {
		// do error correction for spans
		go ErrorCorrectSpans(originalZipkinSpans, proxySpans)
	}

	opts.HTTP.Serve(startup_http.Config{
		Name: "dd-zipkin-proxy",

		AdminHandlers: []admin.RouteConfig{
			admin.Describe("A buffer of the previous traces (in openzipkin-format) in the order they were received.",
				admin.WithGenericValue("/spans", buffer.ToSlice)),
		},

		Routing: func(router *httprouter.Router) http.Handler {
			// we emulate the zipkin api
			router.POST("/api/v1/spans", handleSpans(originalZipkinSpans, 1))
			router.POST("/api/v2/spans", handleSpans(originalZipkinSpans, 2))
			return router
		},
	})
}

func configureEnvironmentVariables(group *flags.Group) {
	for _, gr := range group.Groups() {
		configureEnvironmentVariables(gr)
	}

	expr := regexp.MustCompile("[^A-Z0-9]+")
	for _, op := range group.Options() {

		name := strings.ToUpper(op.LongNameWithNamespace())
		op.EnvDefaultKey = "DDZK_" + expr.ReplaceAllString(name, "_")
	}
}

func forwardSpansToChannels(source <-chan proxy.Span, targets []chan<- proxy.Span, converter SpanConverter) {
	for span := range source {
		for _, target := range targets {
			if converted, err := converter(span); err == nil {
				target <- converted
			}
		}
	}
}
<commit_msg>Only convert span once.<commit_after>package zipkinproxy

import (
	"github.com/flachnetz/dd-zipkin-proxy/datadog"
	"github.com/flachnetz/dd-zipkin-proxy/proxy"
	"github.com/flachnetz/go-admin"
	"github.com/flachnetz/startup"
	"github.com/flachnetz/startup/startup_base"
	"github.com/flachnetz/startup/startup_http"
	"github.com/flachnetz/startup/startup_metrics"
	"github.com/jessevdk/go-flags"
	"github.com/julienschmidt/httprouter"
	"github.com/pkg/profile"
	"github.com/sirupsen/logrus"
	"net/http"

	"regexp"
	"strings"

	_ "github.com/apache/thrift/lib/go/thrift"
)

var log = logrus.WithField("prefix", "main")

type SpanConverter func(span proxy.Span) (proxy.Span, error)

func Main(spanConverter SpanConverter) {
	var opts struct {
		Base    startup_base.BaseOptions       `group:"Base options"`
		HTTP    startup_http.HTTPOptions       `group:"HTTP server options"`
		Metrics startup_metrics.MetricsOptions `group:"Metrics configuration"`

		DisableSpanCorrection bool `long:"disable-span-correction" description:"Do not to correct the spans."`

		TraceAgent struct {
			Host string `long:"trace-host" value:"localhost" description:"Hostname of the trace agent."`
			Port string `long:"trace-port" value:"8126" description:"Port of the trace agent."`
		}
	}

	defer profile.Start().Stop()

	opts.Metrics.Inputs.MetricsPrefix = "zipkin.proxy"

	startup.MustParseCommandLine(&opts)

	var channels []chan<- proxy.Span

	{
		log.Info("Enable forwarding of spans to datadog trace-agent")
		datadog.Initialize(opts.TraceAgent.Host + ":" + opts.TraceAgent.Port)

		// accept zipkin spans
		spans := make(chan proxy.Span, 1024)
		channels = append(channels, spans)

		go datadog.Sink(spans)
	}

	// a channel to store the last spans that were received
	var buffer *SpansBuffer
	{
		zipkinSpans := make(chan proxy.Span, 1024)
		channels = append(channels, zipkinSpans)

		// just keep references to previous spans.
		buffer = NewSpansBuffer(2048)
		go buffer.ReadFrom(zipkinSpans)
	}

	// multiplex input channel to all the target channels
	proxySpans := make(chan proxy.Span, 16)
	go forwardSpansToChannels(proxySpans, channels, spanConverter)

	originalZipkinSpans := make(chan proxy.Span, 1024)
	if opts.DisableSpanCorrection {
		go PipeThroughSpans(originalZipkinSpans, proxySpans)
	} else {
		// do error correction for spans
		go ErrorCorrectSpans(originalZipkinSpans, proxySpans)
	}

	opts.HTTP.Serve(startup_http.Config{
		Name: "dd-zipkin-proxy",

		AdminHandlers: []admin.RouteConfig{
			admin.Describe("A buffer of the previous traces (in openzipkin-format) in the order they were received.",
				admin.WithGenericValue("/spans", buffer.ToSlice)),
		},

		Routing: func(router *httprouter.Router) http.Handler {
			// we emulate the zipkin api
			router.POST("/api/v1/spans", handleSpans(originalZipkinSpans, 1))
			router.POST("/api/v2/spans", handleSpans(originalZipkinSpans, 2))
			return router
		},
	})
}

func configureEnvironmentVariables(group *flags.Group) {
	for _, gr := range group.Groups() {
		configureEnvironmentVariables(gr)
	}

	expr := regexp.MustCompile("[^A-Z0-9]+")
	for _, op := range group.Options() {

		name := strings.ToUpper(op.LongNameWithNamespace())
		op.EnvDefaultKey = "DDZK_" + expr.ReplaceAllString(name, "_")
	}
}

func forwardSpansToChannels(source <-chan proxy.Span, targets []chan<- proxy.Span, converter SpanConverter) {
	for span := range source {
		converted, err := converter(span)
		if err == nil {
			for _, target := range targets {
				target <- converted
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/url"
	"net/http"
	"net/http/httputil"
	"encoding/json"

	"github.com/spf13/viper"
	"github.com/xiwenc/cf-fastpush-controller/lib"
)

var appCmd string
var listenOn string
var backendOn string

func main() {

	viper.SetConfigName("cf-fastpush-controller")
	viper.AddConfigPath("/etc/")
	viper.AddConfigPath("$HOME/.config/")
	viper.AddConfigPath(".")
	viper.ReadInConfig()
	viper.AutomaticEnv()

	viper.SetDefault(lib.CONFIG_BIND_ADDRESS, "127.0.0.1")
	viper.SetDefault(lib.CONFIG_PORT, "9000")
	viper.SetDefault(lib.CONFIG_BACKEND_DIRS, "./")
	viper.SetDefault(lib.CONFIG_RESTART_REGEX, "*.py^")
	viper.SetDefault(lib.CONFIG_IGNORE_REGEX, "")
	viper.SetDefault(lib.CONFIG_BACKEND_COMMAND, "python -m http.server")
	viper.SetDefault(lib.CONFIG_BACKEND_PORT, "8080")
	viper.SetDefault(lib.CONFIG_BASE_PATH, "/_fastpush")

	appCmd = viper.GetString(lib.CONFIG_BACKEND_COMMAND)
	listenOn = viper.GetString(lib.CONFIG_BIND_ADDRESS) + ":" + viper.GetString(lib.CONFIG_PORT)
	backendOn = viper.GetString(lib.CONFIG_BIND_ADDRESS) + ":" + viper.GetString(lib.CONFIG_BACKEND_PORT)
	basePath := viper.GetString(lib.CONFIG_BASE_PATH)

	log.Println("Controller listening to: " + listenOn)

	http.HandleFunc(basePath + "/files", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			ListFiles(w, r)
		} else if r.Method == "PUT" {
			UploadFiles(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc(basePath + "/restart", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			RestartApp(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc(basePath + "/status", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			GetStatus(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	reverseProxy := httputil.NewSingleHostReverseProxy(&url.URL{
		Scheme: "http",
		Host:   backendOn,
	})
	http.HandleFunc("/", reverseProxyHandler(reverseProxy))

	go lib.RestartApp(appCmd)
	go lib.ListFiles()
	http.ListenAndServe(listenOn, nil)
}

func reverseProxyHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.URL)
		r.URL.Path = "/"
		p.ServeHTTP(w, r)
	}
}

func ListFiles(w http.ResponseWriter, r *http.Request) {
	files := lib.ListFiles()
	json.NewEncoder(w).Encode(files)
}

func RestartApp(w http.ResponseWriter, r *http.Request) {
	result := lib.RestartApp(appCmd)
	json.NewEncoder(w).Encode(result)
}

func GetStatus(w http.ResponseWriter, r *http.Request) {
	result := lib.GetStatus()
	json.NewEncoder(w).Encode(result)
}

func UploadFiles(w http.ResponseWriter, r *http.Request) {
	inputFiles := map[string]*lib.FileEntry{}
	err := json.NewDecoder(r.Body).Decode(&inputFiles)
	if err != nil {
		log.Println(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
	result := lib.UploadFiles(inputFiles)
	json.NewEncoder(w).Encode(result)
}
<commit_msg>set json as content-type<commit_after>package main

import (
	"log"
	"net/url"
	"net/http"
	"net/http/httputil"
	"encoding/json"

	"github.com/spf13/viper"
	"github.com/xiwenc/cf-fastpush-controller/lib"
)

var appCmd string
var listenOn string
var backendOn string

func main() {

	viper.SetConfigName("cf-fastpush-controller")
	viper.AddConfigPath("/etc/")
	viper.AddConfigPath("$HOME/.config/")
	viper.AddConfigPath(".")
	viper.ReadInConfig()
	viper.AutomaticEnv()

	viper.SetDefault(lib.CONFIG_BIND_ADDRESS, "127.0.0.1")
	viper.SetDefault(lib.CONFIG_PORT, "9000")
	viper.SetDefault(lib.CONFIG_BACKEND_DIRS, "./")
	viper.SetDefault(lib.CONFIG_RESTART_REGEX, "*.py^")
	viper.SetDefault(lib.CONFIG_IGNORE_REGEX, "")
	viper.SetDefault(lib.CONFIG_BACKEND_COMMAND, "python -m http.server")
	viper.SetDefault(lib.CONFIG_BACKEND_PORT, "8080")
	viper.SetDefault(lib.CONFIG_BASE_PATH, "/_fastpush")

	appCmd = viper.GetString(lib.CONFIG_BACKEND_COMMAND)
	listenOn = viper.GetString(lib.CONFIG_BIND_ADDRESS) + ":" + viper.GetString(lib.CONFIG_PORT)
	backendOn = viper.GetString(lib.CONFIG_BIND_ADDRESS) + ":" + viper.GetString(lib.CONFIG_BACKEND_PORT)
	basePath := viper.GetString(lib.CONFIG_BASE_PATH)

	log.Println("Controller listening to: " + listenOn)

	http.HandleFunc(basePath + "/files", func(w http.ResponseWriter, r *http.Request) {
		SetJsonContentType(w)
		if r.Method == "GET" {
			ListFiles(w, r)
		} else if r.Method == "PUT" {
			UploadFiles(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc(basePath + "/restart", func(w http.ResponseWriter, r *http.Request) {
		SetJsonContentType(w)
		if r.Method == "POST" {
			RestartApp(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	http.HandleFunc(basePath + "/status", func(w http.ResponseWriter, r *http.Request) {
		SetJsonContentType(w)
		if r.Method == "GET" {
			GetStatus(w, r)
		} else {
			http.Error(w, "Invalid request method.", http.StatusMethodNotAllowed)
		}
	})
	reverseProxy := httputil.NewSingleHostReverseProxy(&url.URL{
		Scheme: "http",
		Host:   backendOn,
	})
	http.HandleFunc("/", reverseProxyHandler(reverseProxy))

	go lib.RestartApp(appCmd)
	go lib.ListFiles()
	http.ListenAndServe(listenOn, nil)
}

func SetJsonContentType(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json")
}

func reverseProxyHandler(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		log.Println(r.URL)
		r.URL.Path = "/"
		p.ServeHTTP(w, r)
	}
}

func ListFiles(w http.ResponseWriter, r *http.Request) {
	files := lib.ListFiles()
	json.NewEncoder(w).Encode(files)
}

func RestartApp(w http.ResponseWriter, r *http.Request) {
	result := lib.RestartApp(appCmd)
	json.NewEncoder(w).Encode(result)
}

func GetStatus(w http.ResponseWriter, r *http.Request) {
	result := lib.GetStatus()
	json.NewEncoder(w).Encode(result)
}

func UploadFiles(w http.ResponseWriter, r *http.Request) {
	inputFiles := map[string]*lib.FileEntry{}
	err := json.NewDecoder(r.Body).Decode(&inputFiles)
	if err != nil {
		log.Println(err.Error())
		http.Error(w, err.Error(), http.StatusBadRequest)
	}
	result := lib.UploadFiles(inputFiles)
	json.NewEncoder(w).Encode(result)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/kiwiirc/webircgateway/pkg/webircgateway"
)

const VERSION = "0.2.3"

func init() {
	webircgateway.Version = VERSION
}

func main() {
	printVersion := flag.Bool("version", false, "Print the version")
	configFile := flag.String("config", "config.conf", "Config file location")
	runConfigTest := flag.Bool("test", false, "Just test the config file")
	flag.Parse()

	if *printVersion {
		fmt.Println(webircgateway.Version)
		os.Exit(0)
	}

	webircgateway.SetConfigFile(*configFile)
	log.Printf("Using config %s", webircgateway.CurrentConfigFile())

	err := webircgateway.LoadConfig()
	if err != nil {
		log.Printf("Config file error: %s", err.Error())
		os.Exit(1)
	}

	if *runConfigTest {
		// TODO: This
		log.Println("Config file is OK")
		os.Exit(0)
	}

	watchForSignals()
	webircgateway.Start()
}

func watchForSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)
	go func() {
		for {
			<-c
			fmt.Println("Recieved SIGHUP, reloading config file")
			webircgateway.LoadConfig()
		}
	}()
}
<commit_msg>Version bump<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/kiwiirc/webircgateway/pkg/webircgateway"
)

const VERSION = "0.2.4"

func init() {
	webircgateway.Version = VERSION
}

func main() {
	printVersion := flag.Bool("version", false, "Print the version")
	configFile := flag.String("config", "config.conf", "Config file location")
	runConfigTest := flag.Bool("test", false, "Just test the config file")
	flag.Parse()

	if *printVersion {
		fmt.Println(webircgateway.Version)
		os.Exit(0)
	}

	webircgateway.SetConfigFile(*configFile)
	log.Printf("Using config %s", webircgateway.CurrentConfigFile())

	err := webircgateway.LoadConfig()
	if err != nil {
		log.Printf("Config file error: %s", err.Error())
		os.Exit(1)
	}

	if *runConfigTest {
		// TODO: This
		log.Println("Config file is OK")
		os.Exit(0)
	}

	watchForSignals()
	webircgateway.Start()
}

func watchForSignals() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGHUP)
	go func() {
		for {
			<-c
			fmt.Println("Recieved SIGHUP, reloading config file")
			webircgateway.LoadConfig()
		}
	}()
}
<|endoftext|>


<commit_before>// Useful tags for Bishkek
// addr:street+addr:housenumber - Get all known addresses
// place~city - Get all cities
// place~suburb - Get districts
// place~village - Get villages
// building,shop - get all buildings and shops
// highway - Get all roads

package main

import (
	"flag"
	"github.com/gen1us2k/osm-geogoder/osm-importer"
	"github.com/qedus/osmpbf"
	"gopkg.in/olivere/elastic.v3"
	"os"
	"runtime"
)

var PlaceSynonyms = map[string][]string{
	"American University of Central Asia": []string{"АУЦА", "Американский университет в центральной азии", "AUCA"},
}

var CitiesAndTowns, Roads []importer.JsonWay

func getSettings() importer.Settings {

	// command line flags
	batchSize := flag.Int("batch", 50000, "batch leveldb writes in batches of this size")

	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		importer.Logger.Fatal("invalid args, you must specify a PBF file")
	}

	return importer.Settings{args[0], *batchSize}
}

func getDecoder(file *os.File) *osmpbf.Decoder {
	decoder := osmpbf.NewDecoder(file)
	err := decoder.Start(runtime.GOMAXPROCS(-1)) // use several goroutines for faster decoding
	if err != nil {
		importer.Logger.Fatal(err.Error())
	}
	return decoder
}

func main() {

	config := getSettings()
	db := importer.OpenLevelDB("db")
	defer db.Close()

	file := importer.OpenFile(config.PbfPath)
	defer file.Close()
	decoder := getDecoder(file)

	client, err := elastic.NewClient()
	if err != nil {
		// Handle error
	}
	_, err = client.CreateIndex("addresses").BodyString(importer.ESSettings).Do()
	if err != nil {
		// Handle error
		importer.Logger.Error(err.Error())
	}

	importer.Logger.Info("Searching cities, villages, towns and districts")
	tags := importer.BuildTags("place~city,place~village,place~suburb,place~town")
	CitiesAndTowns, _ = importer.Run(decoder, db, tags)

	importer.Logger.Info("Cities, villages, towns and districts found")

	file = importer.OpenFile(config.PbfPath)
	defer file.Close()
	decoder = getDecoder(file)

	importer.Logger.Info("Searching addresses")
	tags = importer.BuildTags("addr:street+addr:housenumber,amenity,shop")
	AddressWays, AddressNodes := importer.Run(decoder, db, tags)
	importer.Logger.Info("Addresses found")
	importer.JsonWaysToES(AddressWays, CitiesAndTowns, client)
	importer.JsonNodesToEs(AddressNodes, CitiesAndTowns, client)
	//	file = openFile(config.PbfPath)
	//	defer file.Close()
	//	decoder = getDecoder(file)

	//	tags = buildTags("highway")
	//	Roads, _ = run(decoder, db, tags)
	//	RoadsToPg()
	//	fmt.Println("Searching all roads intersecitons")
	//	Intersections := GetRoadIntersectionsFromPG()
	//	JsonNodesToEs(Intersections, client)
}

var Translations []importer.Translate
<commit_msg>restored full functionality<commit_after>package main

import (
	"flag"
	"github.com/gen1us2k/osm-geogoder/osm-importer"
	"github.com/qedus/osmpbf"
	"gopkg.in/olivere/elastic.v3"
	"os"
	"runtime"
)

var CitiesAndTowns, Roads []importer.JsonWay

func getSettings() importer.Settings {

	// command line flags
	batchSize := flag.Int("batch", 50000, "batch leveldb writes in batches of this size")

	flag.Parse()
	args := flag.Args()

	if len(args) < 1 {
		importer.Logger.Fatal("invalid args, you must specify a PBF file")
	}

	return importer.Settings{args[0], *batchSize}
}

func getDecoder(file *os.File) *osmpbf.Decoder {
	decoder := osmpbf.NewDecoder(file)
	err := decoder.Start(runtime.GOMAXPROCS(-1)) // use several goroutines for faster decoding
	if err != nil {
		importer.Logger.Fatal(err.Error())
	}
	return decoder
}

func main() {

	config := getSettings()
	db := importer.OpenLevelDB("db")
	defer db.Close()

	file := importer.OpenFile(config.PbfPath)
	defer file.Close()
	decoder := getDecoder(file)

	client, err := elastic.NewClient()
	if err != nil {
		// Handle error
	}
	_, err = client.CreateIndex("addresses").BodyString(importer.ESSettings).Do()
	if err != nil {
		// Handle error
		importer.Logger.Error(err.Error())
	}

	importer.Logger.Info("Searching cities, villages, towns and districts")
	tags := importer.BuildTags("place~city,place~village,place~suburb,place~town")
	CitiesAndTowns, _ = importer.Run(decoder, db, tags)

	importer.Logger.Info("Cities, villages, towns and districts found")

	file = importer.OpenFile(config.PbfPath)
	defer file.Close()
	decoder = getDecoder(file)

	importer.Logger.Info("Searching addresses")
	tags = importer.BuildTags("addr:street+addr:housenumber,amenity,shop")
	AddressWays, AddressNodes := importer.Run(decoder, db, tags)
	importer.Logger.Info("Addresses found")
	importer.JsonWaysToES(AddressWays, CitiesAndTowns, client)
	importer.JsonNodesToEs(AddressNodes, CitiesAndTowns, client)
	file = importer.OpenFile(config.PbfPath)
	defer file.Close()
	decoder = getDecoder(file)

	tags = importer.BuildTags("highway")
	Roads, _ = importer.Run(decoder, db, tags)
	importer.RoadsToPg(Roads)
	importer.Logger.Info("Searching all roads intersecitons")
	Intersections := importer.GetRoadIntersectionsFromPG()
	importer.JsonNodesToEs(Intersections,CitiesAndTowns, client)
}<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"net"
	"regexp"
	"strings"
	"time"
)

type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() map[string]string
	ChangeNode(node string)
	Ping() (string, error)
}

var providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3)}

func validateProvider(p string) (string, error) {
	match, _ := regexp.MatchString("(telia|level3)", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	} else {
		return "", errors.New("provider not support")
	}
}

func main() {
	var (
		err    error
		cPName string = "local"
	)

	rep := make(chan string, 1)
	cmd := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(cmd, nxt)

	r, _ := regexp.Compile(`(ping|connect|node|local) (.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for {
		select {
		case req := <-cmd:
			subReq := r.FindStringSubmatch(req)
			if len(subReq) == 0 {
				println("syntax error")
				nxt <- struct{}{}
				continue
			}
			cmd := strings.TrimSpace(subReq[1])
			args := strings.TrimSpace(subReq[2])
			switch {
			case cmd == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", args)
				if err != nil {
					println("cannot resolve", args, ": Unknown host")
					nxt <- struct{}{}
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				nxt <- struct{}{}
			case cmd == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(args, "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				nxt <- struct{}{}
			case cmd == "node":
				providers[cPName].ChangeNode(args)
				c.SetPrompt(cPName + "/" + args)
				nxt <- struct{}{}
			case cmd == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				nxt <- struct{}{}
			case cmd == "connect":
				var pName string
				if pName, err = validateProvider(args); err != nil {
					println("provider not available")
					nxt <- struct{}{}
					continue
				}
				cPName = pName
				c.SetPrompt(cPName + "/" + providers[cPName].GetDefaultNode())
				nxt <- struct{}{}
			}
		}
	}
}
<commit_msg>dynamic change nodes based on the lg provider<commit_after>package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"net"
	"regexp"
	"strings"
	"time"
)

type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() map[string]string
	ChangeNode(node string)
	Ping() (string, error)
}

var providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3)}

func validateProvider(p string) (string, error) {
	match, _ := regexp.MatchString("(telia|level3)", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	} else {
		return "", errors.New("provider not support")
	}
}

func main() {
	var (
		err    error
		cPName string = "local"
	)

	rep := make(chan string, 1)
	cmd := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(cmd, nxt)

	r, _ := regexp.Compile(`(ping|connect|node|local) (.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for {
		select {
		case req := <-cmd:
			subReq := r.FindStringSubmatch(req)
			if len(subReq) == 0 {
				println("syntax error")
				nxt <- struct{}{}
				continue
			}
			cmd := strings.TrimSpace(subReq[1])
			args := strings.TrimSpace(subReq[2])
			switch {
			case cmd == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", args)
				if err != nil {
					println("cannot resolve", args, ": Unknown host")
					nxt <- struct{}{}
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				nxt <- struct{}{}
			case cmd == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(args, "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				nxt <- struct{}{}
			case cmd == "node":
				providers[cPName].ChangeNode(args)
				c.SetPrompt(cPName + "/" + args)
				nxt <- struct{}{}
			case cmd == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				nxt <- struct{}{}
			case cmd == "connect":
				var pName string
				if pName, err = validateProvider(args); err != nil {
					println("provider not available")
					nxt <- struct{}{}
					continue
				}
				cPName = pName
				c.SetPrompt(cPName + "/" + providers[cPName].GetDefaultNode())
				c.UpdateCompleter("node", providers[cPName].GetNodes())
				nxt <- struct{}{}
			}
		}
	}
}
<|endoftext|>


<commit_before>// A command line tool that shows the status of (many) Go packages.
package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"sync"

	"github.com/shurcooL/gostatus/status"

	. "github.com/shurcooL/go/gists/gist7480523"
	. "github.com/shurcooL/go/gists/gist7651991"
)

var allFlag = flag.Bool("all", false, "Show all Go packages, not just ones with notable status.")
var plumbingFlag = flag.Bool("plumbing", false, "Give the output in an easy-to-parse format for scripts.")
var debugFlag = flag.Bool("debug", false, "Give the output with verbose debug information.")

func usage() {
	fmt.Fprint(os.Stderr, "Usage: [newline separated packages] | gostatus [flags]\n")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, `
Examples:
  # Show status of packages with notable status.
  go list all | gostatus

  # Show status of all dependencies (recursive) of package in cur working dir.
  go list -f '{{join .Deps "\n"}}' . | gostatus --all

Legend:
  ???? - Not under (recognized) version control
  b - Non-master branch checked out
  * - Uncommited changes in working dir
  + - Update available
  - - Local revision is ahead of remote (need to push?)
  ! - No remote
  # - Remote path doesn't match import path
  $ - Stash exists
`)
	os.Exit(2)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Usage = usage
	flag.Parse()

	shouldShow := func(goPackage *GoPackage) bool {
		// Check for notable status.
		return status.PorcelainPresenter(goPackage)[:4] != "    " && status.PorcelainPresenter(goPackage)[:4] != "????"
	}

	if *allFlag == true {
		shouldShow = func(_ *GoPackage) bool { return true }
	}

	var presenter GoPackageStringer = status.PorcelainPresenter

	if *debugFlag == true {
		presenter = status.DebugPresenter
	} else if *plumbingFlag == true {
		presenter = status.PlumbingPresenter
	}

	// A map of repos that have been checked, to avoid doing same repo more than once
	var lock sync.Mutex
	checkedRepos := map[string]bool{}

	// Input: Go package Import Path
	// Output: If a valid Go package and not part of standard library, output a status string, else nil
	reduceFunc := func(in string) interface{} {
		if goPackage := GoPackageFromImportPath(in); goPackage != nil {
			if !goPackage.Standard {
				// HACK: Check that the same repo hasn't already been done
				if goPackage.UpdateVcs(); goPackage.Dir.Repo != nil {
					rootPath := goPackage.Dir.Repo.Vcs.RootPath()
					lock.Lock()
					if !checkedRepos[rootPath] {
						checkedRepos[rootPath] = true
						lock.Unlock()
					} else {
						lock.Unlock()
						// TODO: Instead of skipping repos that were done, cache their state and reuse it
						return nil
					}
				}

				goPackage.UpdateVcsFields()
				if shouldShow(goPackage) == false {
					return nil
				}
				return presenter(goPackage)
			}
		}
		return nil
	}

	// Run reduceFunc on all lines from stdin in parallel (max 8 goroutines)
	outChan := GoReduceLinesFromReader(os.Stdin, 8, reduceFunc)

	// Output results
	for out := range outChan {
		fmt.Println(out.(string))
	}
}
<commit_msg>Refactor reduceFunc to reduce indentation levels.<commit_after>// A command line tool that shows the status of (many) Go packages.
package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"sync"

	"github.com/shurcooL/gostatus/status"

	. "github.com/shurcooL/go/gists/gist7480523"
	. "github.com/shurcooL/go/gists/gist7651991"
	"github.com/shurcooL/go/gists/gist7802150"
)

var allFlag = flag.Bool("all", false, "Show all Go packages, not just ones with notable status.")
var plumbingFlag = flag.Bool("plumbing", false, "Give the output in an easy-to-parse format for scripts.")
var debugFlag = flag.Bool("debug", false, "Give the output with verbose debug information.")

func usage() {
	fmt.Fprint(os.Stderr, "Usage: [newline separated packages] | gostatus [flags]\n")
	flag.PrintDefaults()
	fmt.Fprint(os.Stderr, `
Examples:
  # Show status of packages with notable status.
  go list all | gostatus

  # Show status of all dependencies (recursive) of package in cur working dir.
  go list -f '{{join .Deps "\n"}}' . | gostatus --all

Legend:
  ???? - Not under (recognized) version control
  b - Non-master branch checked out
  * - Uncommited changes in working dir
  + - Update available
  - - Local revision is ahead of remote (need to push?)
  ! - No remote
  # - Remote path doesn't match import path
  $ - Stash exists
`)
	os.Exit(2)
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Usage = usage
	flag.Parse()

	shouldShow := func(goPackage *GoPackage) bool {
		// Check for notable status.
		return status.PorcelainPresenter(goPackage)[:4] != "    " && status.PorcelainPresenter(goPackage)[:4] != "????"
	}

	if *allFlag == true {
		shouldShow = func(_ *GoPackage) bool { return true }
	}

	var presenter GoPackageStringer = status.PorcelainPresenter

	if *debugFlag == true {
		presenter = status.DebugPresenter
	} else if *plumbingFlag == true {
		presenter = status.PlumbingPresenter
	}

	// A map of repos that have been checked, to avoid doing same repo more than once
	var lock sync.Mutex
	checkedRepos := map[string]bool{}

	// Input: Go package Import Path
	// Output: If a valid Go package and not part of standard library, output a status string, else nil
	reduceFunc := func(in string) interface{} {
		goPackage := GoPackageFromImportPath(in)
		if goPackage == nil {
			return nil
		}
		if goPackage.Standard {
			return nil
		}

		goPackage.UpdateVcs()
		// HACK: Check that the same repo hasn't already been done
		if goPackage.Dir.Repo != nil {
			rootPath := goPackage.Dir.Repo.Vcs.RootPath()
			lock.Lock()
			if !checkedRepos[rootPath] {
				checkedRepos[rootPath] = true
				lock.Unlock()
			} else {
				lock.Unlock()
				// TODO: Instead of skipping repos that were done, cache their state and reuse it
				return nil
			}
		}

		if goPackage.Dir.Repo != nil {
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsLocal)
			gist7802150.MakeUpdated(goPackage.Dir.Repo.VcsRemote)
		}

		if shouldShow(goPackage) == false {
			return nil
		}
		return presenter(goPackage)
	}

	// Run reduceFunc on all lines from stdin in parallel (max 8 goroutines)
	outChan := GoReduceLinesFromReader(os.Stdin, 8, reduceFunc)

	// Output results
	for out := range outChan {
		fmt.Println(out.(string))
	}
}
<|endoftext|>


<commit_before>// myLG is command line looking glass that written with Go language
// it tries from its own icmp and external looking glasses tools
package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"net"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"github.com/mehrdadrad/mylg/ns"
	"github.com/mehrdadrad/mylg/ripe"
)

// Provider is a interface to accessing lg
type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() []string
	ChangeNode(node string)
	Ping() (string, error)
}

var (
	providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3), "cogent": new(lg.Cogent)}
	pNames    = providerNames()
	nsr       *ns.Request
)

func providerNames() []string {
	pNames := []string{}
	for p := range providers {
		pNames = append(pNames, p)
	}
	return pNames
}

func validateProvider(p string) (string, error) {
	pNames := []string{}
	match, _ := regexp.MatchString("("+strings.Join(pNames, "|")+")", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	}
	return "", errors.New("provider not support")

}
func init() {
	// Initialize name server data
	nsr = ns.NewRequest()
	go nsr.Init()
}

func main() {
	var (
		err     error
		request string
		loop    = true
		cPName  = "local"
	)

	rep := make(chan string, 1)
	req := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(req, nxt)

	r, _ := regexp.Compile(`(ping|lg|ns|asn|connect|node|local|mode|help|exit|quit)\s{0,1}(.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for loop {
		select {
		case request, loop = <-req:
			if !loop {
				break
			}
			subReq := r.FindStringSubmatch(request)
			if len(subReq) == 0 {
				println("syntax error")
				c.Next()
				continue
			}
			prompt := c.GetPrompt()
			cmd := strings.TrimSpace(subReq[1])
			args := strings.TrimSpace(subReq[2])
			switch {
			case cmd == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", args)
				if err != nil {
					println("cannot resolve", args, ": Unknown host")
					c.Next()
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				c.Next()
			case cmd == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(args, "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				c.Next()
			case cmd == "node":
				if _, ok := providers[cPName]; ok {
					providers[cPName].ChangeNode(args)
					c.SetPrompt(cPName + "/" + args)
				} else {
					println("it doesn't support")
				}
				c.Next()
			case cmd == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				c.Next()
			case cmd == "lg":
				c.SetPrompt("lg")
				c.UpdateCompleter("connect", pNames)
				c.Next()
			case cmd == "connect":
				switch {
				case strings.HasPrefix(prompt, "ns"):
					println("todo")
				case strings.HasPrefix(prompt, "lg"):
					var pName string
					if pName, err = validateProvider(args); err != nil {
						println("provider not available")
						c.Next()
						continue
					}
					cPName = pName
					if _, ok := providers[cPName]; ok {
						c.SetPrompt(cPName + "/" + providers[cPName].GetDefaultNode())
						go func() {
							c.UpdateCompleter("node", providers[cPName].GetNodes())
						}()
					} else {
						println("it doesn't support")
					}
				}
				c.Next()
			case cmd == "ns":
				nsr.SetCountryList(c)
				c.SetPrompt("ns")
				c.Next()
			case cmd == "asn":
				asn := ripe.ASN{Number: args}
				asn.GetData()
				asn.PrettyPrint()
				c.Next()
			case cmd == "mode":
				if args == "vim" {
					c.SetVim()
				} else if args == "emacs" {
					c.SetEmacs()
				} else {
					println("the request mode doesn't support")
				}
				c.Next()
			case cmd == "help":
				c.Help()
				c.Next()
			case cmd == "exit", cmd == "quit":
				c.Close(nxt)
				close(req)
				// todo
			}
		}
	}
}
<commit_msg>added switch at node section<commit_after>// myLG is command line looking glass that written with Go language
// it tries from its own icmp and external looking glasses tools
package main

import (
	"errors"
	"github.com/briandowns/spinner"
	"net"
	"regexp"
	"strings"
	"time"

	"github.com/mehrdadrad/mylg/cli"
	"github.com/mehrdadrad/mylg/icmp"
	"github.com/mehrdadrad/mylg/lg"
	"github.com/mehrdadrad/mylg/ns"
	"github.com/mehrdadrad/mylg/ripe"
)

// Provider is a interface to accessing lg
type Provider interface {
	Set(host, version string)
	GetDefaultNode() string
	GetNodes() []string
	ChangeNode(node string)
	Ping() (string, error)
}

var (
	providers = map[string]Provider{"telia": new(lg.Telia), "level3": new(lg.Level3), "cogent": new(lg.Cogent)}
	pNames    = providerNames()
	nsr       *ns.Request
)

func providerNames() []string {
	pNames := []string{}
	for p := range providers {
		pNames = append(pNames, p)
	}
	return pNames
}

func validateProvider(p string) (string, error) {
	pNames := []string{}
	match, _ := regexp.MatchString("("+strings.Join(pNames, "|")+")", p)
	p = strings.ToLower(p)
	if match {
		return p, nil
	}
	return "", errors.New("provider not support")

}
func init() {
	// Initialize name server data
	nsr = ns.NewRequest()
	go nsr.Init()
}

func main() {
	var (
		err     error
		request string
		loop    = true
		cPName  = "local"
	)

	rep := make(chan string, 1)
	req := make(chan string, 1)
	nxt := make(chan struct{}, 1)

	c := cli.Init("local")
	go c.Run(req, nxt)

	r, _ := regexp.Compile(`(ping|lg|ns|asn|connect|node|local|mode|help|exit|quit)\s{0,1}(.*)`)
	s := spinner.New(spinner.CharSets[26], 220*time.Millisecond)

	for loop {
		select {
		case request, loop = <-req:
			if !loop {
				break
			}
			subReq := r.FindStringSubmatch(request)
			if len(subReq) == 0 {
				println("syntax error")
				c.Next()
				continue
			}
			prompt := c.GetPrompt()
			cmd := strings.TrimSpace(subReq[1])
			args := strings.TrimSpace(subReq[2])
			switch {
			case cmd == "ping" && cPName == "local":
				p := icmp.NewPing()
				ra, err := net.ResolveIPAddr("ip", args)
				if err != nil {
					println("cannot resolve", args, ": Unknown host")
					c.Next()
					continue
				}
				p.IP(ra.String())
				for n := 0; n < 4; n++ {
					p.Ping(rep)
					println(<-rep)
				}
				c.Next()
			case cmd == "ping":
				s.Prefix = "please wait "
				s.Start()
				providers[cPName].Set(args, "ipv4")
				m, _ := providers[cPName].Ping()
				s.Stop()
				println(m)
				c.Next()
			case cmd == "node":
				switch {
				case strings.HasPrefix(prompt, "lg"):
					if _, ok := providers[cPName]; ok {
						providers[cPName].ChangeNode(args)
						c.UpdatePromptN(args, 3)
					} else {
						println("the specified node doesn't support")
					}
				case strings.HasPrefix(prompt, "ns"):
					c.UpdatePromptN(args, 3)
				}
				c.Next()
			case cmd == "local":
				cPName = "local"
				c.SetPrompt(cPName)
				c.Next()
			case cmd == "lg":
				c.SetPrompt("lg")
				c.UpdateCompleter("connect", pNames)
				c.Next()
			case cmd == "connect":
				switch {
				case strings.HasPrefix(prompt, "ns"):
					if !nsr.ValidateCountry(args) {
						println("error: arguments not validated")
						continue
					}
					c.SetPrompt("ns/" + args)
					nsr.SetNodeList(c)
				case strings.HasPrefix(prompt, "lg"):
					var pName string
					if pName, err = validateProvider(args); err != nil {
						println("provider not available")
						c.Next()
						continue
					}
					cPName = pName
					if _, ok := providers[cPName]; ok {
						c.SetPrompt("lg/" + cPName + "/" + providers[cPName].GetDefaultNode())
						go func() {
							c.UpdateCompleter("node", providers[cPName].GetNodes())
						}()
					} else {
						println("it doesn't support")
					}
				}
				c.Next()
			case cmd == "ns":
				nsr.SetCountryList(c)
				c.SetPrompt("ns")
				c.Next()
			case cmd == "asn":
				asn := ripe.ASN{Number: args}
				asn.GetData()
				asn.PrettyPrint()
				c.Next()
			case cmd == "mode":
				if args == "vim" {
					c.SetVim()
				} else if args == "emacs" {
					c.SetEmacs()
				} else {
					println("the request mode doesn't support")
				}
				c.Next()
			case cmd == "help":
				c.Help()
				c.Next()
			case cmd == "exit", cmd == "quit":
				c.Close(nxt)
				close(req)
				// todo
			}
		}
	}
}
<|endoftext|>