<commit_before>// gzvis is a tool to assist you visualising the operation of
// the go runtime garbage collector.
//
// usage:
//
//     gcvis program [arguments]...
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"text/template"

	"github.com/pkg/browser"
)

var subprocessDone = make(chan struct{})
var parserDone = make(chan struct{})

func startSubprocess(w io.Writer) {
	defer close(subprocessDone)
	env := os.Environ()
	env = append(env, "GODEBUG=gctrace=1")
	args := os.Args[1:]
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = w // os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

type gctrace struct {
	NumGC       int
	Nproc       int
	t1          int
	t2          int
	t3          int
	t4          int
	Heap0       int // heap size before, in megabytes
	Heap1       int // heap size after, in megabytes
	Obj         int
	NMalloc     int
	NFree       int
	NSpan       int
	NBGSweep    int
	NPauseSweep int
	NHandoff    int
	NHandoffCnt int
	NSteal      int
	NStealCnt   int
	NProcYield  int
	NOsYield    int
	NSleep      int
}

type graphPoints [2]int

var graphData []graphPoints

func index(w http.ResponseWriter, req *http.Request) {
	visTmpl.Execute(w, struct {
		YMin         int
		GraphData    []graphPoints
	}{
		10,
		graphData,
	})

}

var visTmpl = template.Must(template.New("vis").Parse(`

`))

func startParser(r io.Reader, trace chan *gctrace) {
	var re = regexp.MustCompile(`gc\d+\(\d+\): \d+\+\d+\+\d+\+\d+ us, \d+ -> \d+ MB, \d+ \(\d+-\d+\) objects, \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`)

	defer close(parserDone)

	sc := bufio.NewScanner(r)
	for sc.Scan() {
		line := sc.Text()
		if !re.MatchString(line) {
			continue
		}
		var gc gctrace
		_, err := fmt.Sscanf(line, "gc%d(%d): %d+%d+%d+%d us, %d -> %d MB, %d (%d-%d) objects, %d/%d/%d sweeps, %d(%d) handoff, %d(%d) steal, %d/%d/%d yields\n",
			&gc.NumGC, &gc.Nproc, &gc.t1, &gc.t2, &gc.t3, &gc.t4, &gc.Heap0, &gc.Heap1, &gc.Obj, &gc.NMalloc, &gc.NFree,
			&gc.NSpan, &gc.NBGSweep, &gc.NPauseSweep, &gc.NHandoff, &gc.NHandoffCnt, &gc.NSteal, &gc.NStealCnt, &gc.NProcYield, &gc.NOsYield, &gc.NSleep)
		if err != nil {
			log.Printf("corrupt gctrace: %v: %s", err, line)
			continue
		}
		trace <- &gc

	}
	if err := sc.Err(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	if len(os.Args) < 2 {
		log.Fatalf("usage: %s command <args>...", os.Args[0])
	}
	pr, pw, _ := os.Pipe()
	trace := make(chan *gctrace, 1)

	go startSubprocess(pw)
	go startParser(pr, trace)

	l, err := net.Listen("tcp4", "127.0.0.1:0")
	if err != nil {
		log.Fatal(err)
	}
	http.HandleFunc("/", index)
	go http.Serve(l, nil)

	addr := l.Addr()
	browser.OpenURL(fmt.Sprintf("http://%s/", addr))

	for t := range trace {
		graphData = append(graphData, graphPoints{t.NumGC, t.Heap0})
	}

	<-parserDone
	<-subprocessDone
}
<commit_msg>hack, hack, hackity hack<commit_after>// gzvis is a tool to assist you visualising the operation of
// the go runtime garbage collector.
//
// usage:
//
//     gcvis program [arguments]...
package main

import (
	"bufio"
	"fmt"
	"html/template"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/pkg/browser"
)

var subprocessDone = make(chan struct{})
var parserDone = make(chan struct{})

func startSubprocess(w io.Writer) {
	defer close(subprocessDone)
	env := os.Environ()
	env = append(env, "GODEBUG=gctrace=1")
	args := os.Args[1:]
	cmd := exec.Command(args[0], args[1:]...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = w // os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

type gctrace struct {
	NumGC       int
	Nproc       int
	t1          int
	t2          int
	t3          int
	t4          int
	Heap0       int // heap size before, in megabytes
	Heap1       int // heap size after, in megabytes
	Obj         int
	NMalloc     int
	NFree       int
	NSpan       int
	NBGSweep    int
	NPauseSweep int
	NHandoff    int
	NHandoffCnt int
	NSteal      int
	NStealCnt   int
	NProcYield  int
	NOsYield    int
	NSleep      int
}

type graphPoints [2]int

var heap0, heap1, nmalloc, nfree, nobj []graphPoints

func index(w http.ResponseWriter, req *http.Request) {
	visTmpl.Execute(w, struct {
		Heap0, Heap1, NMalloc, NFree, NObj []graphPoints
		Title                              string
	}{
		heap0, heap1, nmalloc, nfree, nobj, strings.Join(os.Args[1:], " "),
	})

}

var visTmpl = template.Must(template.New("vis").Parse(`

{{ .Title }}

`))

func startParser(r io.Reader, trace chan *gctrace) {
	var re = regexp.MustCompile(`gc\d+\(\d+\): \d+\+\d+\+\d+\+\d+ us, \d+ -> \d+ MB, \d+ \(\d+-\d+\) objects, \d+\/\d+\/\d+ sweeps, \d+\(\d+\) handoff, \d+\(\d+\) steal, \d+\/\d+\/\d+ yields`)

	defer close(parserDone)

	sc := bufio.NewScanner(r)
	for sc.Scan() {
		line := sc.Text()
		if !re.MatchString(line) {
			fmt.Println(line)
			continue
		}
		var gc gctrace
		_, err := fmt.Sscanf(line, "gc%d(%d): %d+%d+%d+%d us, %d -> %d MB, %d (%d-%d) objects, %d/%d/%d sweeps, %d(%d) handoff, %d(%d) steal, %d/%d/%d yields\n",
			&gc.NumGC, &gc.Nproc, &gc.t1, &gc.t2, &gc.t3, &gc.t4, &gc.Heap0, &gc.Heap1, &gc.Obj, &gc.NMalloc, &gc.NFree,
			&gc.NSpan, &gc.NBGSweep, &gc.NPauseSweep, &gc.NHandoff, &gc.NHandoffCnt, &gc.NSteal, &gc.NStealCnt, &gc.NProcYield, &gc.NOsYield, &gc.NSleep)
		if err != nil {
			log.Printf("corrupt gctrace: %v: %s", err, line)
			continue
		}
		trace <- &gc

	}
	if err := sc.Err(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	if len(os.Args) < 2 {
		log.Fatalf("usage: %s command <args>...", os.Args[0])
	}
	pr, pw, _ := os.Pipe()
	trace := make(chan *gctrace, 1)

	go startSubprocess(pw)
	go startParser(pr, trace)

	l, err := net.Listen("tcp4", "127.0.0.1:0")
	if err != nil {
		log.Fatal(err)
	}
	http.HandleFunc("/", index)
	go http.Serve(l, nil)

	addr := l.Addr()
	browser.OpenURL(fmt.Sprintf("http://%s/", addr))

	for t := range trace {
		ts := int(time.Now().UnixNano() / 1e6)
		heap0 = append(heap0, graphPoints{ts, t.Heap0})
		heap1 = append(heap1, graphPoints{ts, t.Heap1})
		nmalloc = append(nmalloc, graphPoints{ts, t.NMalloc})
		nfree = append(nmalloc, graphPoints{ts, t.NFree})
		nobj = append(nobj, graphPoints{ts, t.Obj})
	}

	<-parserDone
	<-subprocessDone
}
<|endoftext|>


<commit_before>package main

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

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/cloudfoundry/gunk/command_runner/linux_command_runner"
	"github.com/pivotal-golang/archiver/extractor"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/sourcefetcher"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var tmpdir = flag.String(
	"tmpdir",
	os.Getenv("TMPDIR"),
	"directory in which to store ephemeral data",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

func main() {
	flag.Parse()

	logger := log.New(os.Stdout, "", 0)

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	extractor := extractor.NewDetectable()
	sourceFetcher := sourcefetcher.NewSourceFetcher(
		*tmpdir,
		extractor,
		linux_command_runner.New(true),
	)

	builder := builder.NewBuilder(sourceFetcher, wardenClient)

	handler, err := api.New(scheduler.NewScheduler(builder))
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	err = http.ListenAndServe(*listenAddr, handler)
	logger.Fatalln("listen error:", err)
}
<commit_msg>inject tmpdir into builder<commit_after>package main

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

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"
	"github.com/cloudfoundry/gunk/command_runner/linux_command_runner"
	"github.com/pivotal-golang/archiver/extractor"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/sourcefetcher"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var tmpdir = flag.String(
	"tmpdir",
	os.Getenv("TMPDIR"),
	"directory in which to store ephemeral data",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

func main() {
	flag.Parse()

	logger := log.New(os.Stdout, "", 0)

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	extractor := extractor.NewDetectable()
	sourceFetcher := sourcefetcher.NewSourceFetcher(
		*tmpdir,
		extractor,
		linux_command_runner.New(true),
	)

	builder := builder.NewBuilder(*tmpdir, sourceFetcher, wardenClient)

	handler, err := api.New(scheduler.NewScheduler(builder))
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	err = http.ListenAndServe(*listenAddr, handler)
	logger.Fatalln("listen error:", err)
}
<|endoftext|>


<commit_before>package main

import (
	"code.google.com/p/goauth2/oauth"
	"fmt"
	"github.com/digitalocean/godo"
	"github.com/masayukioguni/godo-cli/command"
	"github.com/masayukioguni/godo-cli/config"

	"github.com/mitchellh/cli"
	"os"
)

var GitCommit string

const ApplicationName = "godo-cli"
const Version = "0.0.1"
const VersionPrerelease = ""

func getClinet(accessToken string) *godo.Client {

	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: accessToken},
	}
	return godo.NewClient(t.Client())

}

func main() {
	ui := &cli.BasicUi{Writer: os.Stdout}

	path, _ := config.GetConfigPath()
	config, _ := config.LoadConfig(path)
	godoCli := getClinet(config.Authentication.APIKey)

	c := cli.NewCLI("app", "1.0.0")
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"authorize": func() (cli.Command, error) {
			return &command.AuthorizeCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"version": func() (cli.Command, error) {
			return &command.VersionCommand{
				Ui:      ui,
				AppName: ApplicationName,
				Version: Version,
			}, nil
		},
		"sizes": func() (cli.Command, error) {
			return &command.SizesCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"regions": func() (cli.Command, error) {
			return &command.RegionsCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"images": func() (cli.Command, error) {
			return &command.ImagesCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"droplets": func() (cli.Command, error) {
			return &command.DropletsCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"keys": func() (cli.Command, error) {
			return &command.KeysCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"account": func() (cli.Command, error) {
			return &command.AccountCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"create": func() (cli.Command, error) {
			return &command.CreateCommand{
				Ui:     ui,
				Client: godoCli,
				Config: config,
			}, nil
		},
		"info": func() (cli.Command, error) {
			return &command.InfoCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"destroy": func() (cli.Command, error) {
			return &command.DestroyCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"config": func() (cli.Command, error) {
			return &command.ConfigCommand{
				Ui:     ui,
				Config: config,
				Client: godoCli,
			}, nil
		},
		"ssh": func() (cli.Command, error) {
			return &command.SSHCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
	}

	exitStatus, err := c.Run()
	if err != nil {
		fmt.Println(exitStatus, err)
	}
	os.Exit(exitStatus)
}
<commit_msg>update version<commit_after>package main

import (
	"code.google.com/p/goauth2/oauth"
	"fmt"
	"github.com/digitalocean/godo"
	"github.com/masayukioguni/godo-cli/command"
	"github.com/masayukioguni/godo-cli/config"

	"github.com/mitchellh/cli"
	"os"
)

var GitCommit string

const ApplicationName = "godo-cli"
const Version = "0.0.1"

func getClinet(accessToken string) *godo.Client {

	t := &oauth.Transport{
		Token: &oauth.Token{AccessToken: accessToken},
	}
	return godo.NewClient(t.Client())

}

func main() {
	ui := &cli.BasicUi{Writer: os.Stdout}

	path, _ := config.GetConfigPath()
	config, _ := config.LoadConfig(path)
	godoCli := getClinet(config.Authentication.APIKey)

	c := cli.NewCLI(ApplicationName, Version)
	c.Args = os.Args[1:]
	c.Commands = map[string]cli.CommandFactory{
		"authorize": func() (cli.Command, error) {
			return &command.AuthorizeCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"version": func() (cli.Command, error) {
			return &command.VersionCommand{
				Ui:      ui,
				AppName: ApplicationName,
				Version: Version,
			}, nil
		},
		"sizes": func() (cli.Command, error) {
			return &command.SizesCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"regions": func() (cli.Command, error) {
			return &command.RegionsCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"images": func() (cli.Command, error) {
			return &command.ImagesCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"droplets": func() (cli.Command, error) {
			return &command.DropletsCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"keys": func() (cli.Command, error) {
			return &command.KeysCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"account": func() (cli.Command, error) {
			return &command.AccountCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"create": func() (cli.Command, error) {
			return &command.CreateCommand{
				Ui:     ui,
				Client: godoCli,
				Config: config,
			}, nil
		},
		"info": func() (cli.Command, error) {
			return &command.InfoCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"destroy": func() (cli.Command, error) {
			return &command.DestroyCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
		"config": func() (cli.Command, error) {
			return &command.ConfigCommand{
				Ui:     ui,
				Config: config,
				Client: godoCli,
			}, nil
		},
		"ssh": func() (cli.Command, error) {
			return &command.SSHCommand{
				Ui:     ui,
				Client: godoCli,
			}, nil
		},
	}

	exitStatus, err := c.Run()
	if err != nil {
		fmt.Println(exitStatus, err)
	}
	os.Exit(exitStatus)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"io/ioutil"
	"encoding/json"
	"strings"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/go-redis/redis"
	"strconv"
	// "time"
)

type device struct {
	// Gps_num float32 `json:"gps_num"`
	// App string `json:"app"`
	// Gps_alt float32 `json:"gps_alt"`
	// Fmt_opt int `json:"fmt_opt"`
	// Device string `json:"device"`
	// S_d2 float32 `json:"s_d2"`
	S_d0 float32 `json:"s_d0"`
	// S_d1 float32 `json:"s_d1"`
	S_h0 float32 `json:"s_h0"`
	SiteName string `json:"SiteName"`
	// Gps_fix float32 `json:"gps_fix"`
	// Ver_app string `json:"ver_app"`
	Gps_lat float32 `json:"gps_lat"`
	S_t0 float32 `json:"s_t0"`
	Timestamp string `json:"timestamp"`
	Gps_lon float32 `json:"gps_lon"`
	// Date string `json:"date"`
	// Tick float32 `json:"tick"`
	Device_id string `json:"device_id"`
	// S_1 float32 `json:"s_1"`
	// S_0 float32 `json:"s_0"`
	// S_3 float32 `json:"s_3"`
	// S_2 float32 `json:"s_2"`
	// Ver_format string `json:"ver_format"`
	// Time string `json:"time"`
}

type airbox struct {
	Source string `json:"source"`
	Feeds []device `json:"feeds"`
	Version string `json:"version"`
	Num_of_records int `json:"num_of_records"`
}

type subscribeid struct {
	Device_id []string `json:"device_id"`
}

var bot *linebot.Client
var airbox_json airbox
var lass_json airbox
var maps_json airbox
var all_device []device
var history_json subscribeid
var	client=redis.NewClient(&redis.Options{
		Addr:"hipposerver.ddns.net:6379",
		Password:"",
		DB:0,
	})

func main() {
	url := "https://data.lass-net.org/data/last-all-airbox.json"
	req, _ := http.NewRequest("GET", url, nil)
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	errs := json.Unmarshal(body, &airbox_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-lass.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &lass_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-maps.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &maps_json)
	if errs != nil {
		fmt.Println(errs)
	}

	all_device=append(maps_json.Feeds,lass_json.Feeds...)
	all_device=append(all_device,airbox_json.Feeds...)

	url = "https://data.lass-net.org/data/airbox_list.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &history_json)
	if errs != nil {
		fmt.Println(errs)
	}
	// pushmessage()
	// fmt.Println(airbox_json)
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	// _,_=bot.PushMessage("U3617adbdd46283d7e859f36302f4f471", linebot.NewTextMessage("hi!")).Do()
	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) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var txtmessage string
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText,"訂閱"){
					userID:=event.Source.UserID
					// pong, _ := client.Ping().Result()
					// txtmessage=pong
					for i:=0; i<len(history_json.Device_id); i++ {
						if strings.Contains(inText,strings.ToLower(history_json.Device_id[i])) {
							val, err:=client.Get(history_json.Device_id[i]).Result()
							if err!=nil{
								client.Set(history_json.Device_id[i],userID,0)
								txtmessage="訂閱成功!"
								break
							}
							if strings.Contains(inText,"取消"){
								txtmessage="抱歉!目前尚未提供取消訂閱的功能。"
								break
							} else{
								stringSlice:=strings.Split(val,",")
								if stringInSlice(userID,stringSlice){
									txtmessage="您已訂閱過此ID!"
									break
								} else{
									val=val+","+userID
									client.Set(history_json.Device_id[i],val,0)
									txtmessage="訂閱成功!"
									break
								}
							}
						}
					}
				} else{
					for i:=0; i<len(all_device); i++ {
						if strings.Contains(inText,strings.ToLower(all_device[i].Device_id)) {
							txtmessage="Device_id: "+all_device[i].Device_id+"\n"
							txtmessage=txtmessage+"Site Name: "+all_device[i].SiteName+"\n"
							txtmessage=txtmessage+"Location: ("+strconv.FormatFloat(float64(all_device[i].Gps_lon),'f',3,64)+","+strconv.FormatFloat(float64(all_device[i].Gps_lat),'f',3,64)+")"+"\n"
							txtmessage=txtmessage+"Timestamp: "+all_device[i].Timestamp+"\n"
							txtmessage=txtmessage+"PM2.5: "+strconv.FormatFloat(float64(all_device[i].S_d0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Humidity: "+strconv.FormatFloat(float64(all_device[i].S_h0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Temperature: "+strconv.FormatFloat(float64(all_device[i].S_t0),'f',0,64)
							break
						}
					}
				}
				if len(txtmessage)==0{
					txtmessage="Sorry! No this device ID, please check again."
				}
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(txtmessage)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

<commit_msg>新增取消訂閱<commit_after>package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"io/ioutil"
	"encoding/json"
	"strings"
	"github.com/line/line-bot-sdk-go/linebot"
	"github.com/go-redis/redis"
	"strconv"
	// "time"
)

type device struct {
	// Gps_num float32 `json:"gps_num"`
	// App string `json:"app"`
	// Gps_alt float32 `json:"gps_alt"`
	// Fmt_opt int `json:"fmt_opt"`
	// Device string `json:"device"`
	// S_d2 float32 `json:"s_d2"`
	S_d0 float32 `json:"s_d0"`
	// S_d1 float32 `json:"s_d1"`
	S_h0 float32 `json:"s_h0"`
	SiteName string `json:"SiteName"`
	// Gps_fix float32 `json:"gps_fix"`
	// Ver_app string `json:"ver_app"`
	Gps_lat float32 `json:"gps_lat"`
	S_t0 float32 `json:"s_t0"`
	Timestamp string `json:"timestamp"`
	Gps_lon float32 `json:"gps_lon"`
	// Date string `json:"date"`
	// Tick float32 `json:"tick"`
	Device_id string `json:"device_id"`
	// S_1 float32 `json:"s_1"`
	// S_0 float32 `json:"s_0"`
	// S_3 float32 `json:"s_3"`
	// S_2 float32 `json:"s_2"`
	// Ver_format string `json:"ver_format"`
	// Time string `json:"time"`
}

type airbox struct {
	Source string `json:"source"`
	Feeds []device `json:"feeds"`
	Version string `json:"version"`
	Num_of_records int `json:"num_of_records"`
}

type subscribeid struct {
	Device_id []string `json:"device_id"`
}

var bot *linebot.Client
var airbox_json airbox
var lass_json airbox
var maps_json airbox
var all_device []device
var history_json subscribeid
var	client=redis.NewClient(&redis.Options{
		Addr:"hipposerver.ddns.net:6379",
		Password:"",
		DB:0,
	})

func main() {
	url := "https://data.lass-net.org/data/last-all-airbox.json"
	req, _ := http.NewRequest("GET", url, nil)
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)
	errs := json.Unmarshal(body, &airbox_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-lass.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &lass_json)
	if errs != nil {
		fmt.Println(errs)
	}

	url = "https://data.lass-net.org/data/last-all-maps.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &maps_json)
	if errs != nil {
		fmt.Println(errs)
	}

	all_device=append(maps_json.Feeds,lass_json.Feeds...)
	all_device=append(all_device,airbox_json.Feeds...)

	url = "https://data.lass-net.org/data/airbox_list.json"
	req, _ = http.NewRequest("GET", url, nil)
	res, _ = http.DefaultClient.Do(req)
	defer res.Body.Close()
	body, _ = ioutil.ReadAll(res.Body)
	errs = json.Unmarshal(body, &history_json)
	if errs != nil {
		fmt.Println(errs)
	}
	// pushmessage()
	// fmt.Println(airbox_json)
	var err error
	bot, err = linebot.New(os.Getenv("ChannelSecret"), os.Getenv("ChannelAccessToken"))
	// _,_=bot.PushMessage("U3617adbdd46283d7e859f36302f4f471", linebot.NewTextMessage("hi!")).Do()
	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) {
	events, err := bot.ParseRequest(r)

	if err != nil {
		if err == linebot.ErrInvalidSignature {
			w.WriteHeader(400)
		} else {
			w.WriteHeader(500)
		}
		return
	}

	for _, event := range events {
		if event.Type == linebot.EventTypeMessage {
			switch message := event.Message.(type) {
			case *linebot.TextMessage:
				var txtmessage string
				inText := strings.ToLower(message.Text)
				if strings.Contains(inText,"訂閱"){
					userID:=event.Source.UserID
					// pong, _ := client.Ping().Result()
					// txtmessage=pong
					for i:=0; i<len(history_json.Device_id); i++ {
						if strings.Contains(inText,strings.ToLower(history_json.Device_id[i])) {
							val, err:=client.Get(history_json.Device_id[i]).Result()
							if err!=nil{
								client.Set(history_json.Device_id[i],userID,0)
								txtmessage="訂閱成功!"
								break
							}
							if strings.Contains(inText,"取消"){
								stringSlice:=strings.Split(val,",")
								if stringInSlice(userID,stringSlice){
									if len(stringSlice)==1{
										client.Del(history_json.Device_id[i])
										txtmessage="取消訂閱成功!"
									}
									else{
										val = removeStringInSlice(stringSlice, userID)
										client.Set(history_json.Device_id[i],val,0)
										txtmessage="取消訂閱成功!"
									}
									break
								}else{
									txtmessage="你並沒有訂閱此ID。"
									break
								}
								// txtmessage="抱歉!目前尚未提供取消訂閱的功能。
							} else{
								stringSlice:=strings.Split(val,",")
								if stringInSlice(userID,stringSlice){
									txtmessage="您已訂閱過此ID!"
									break
								} else{
									val=val+","+userID
									client.Set(history_json.Device_id[i],val,0)
									txtmessage="訂閱成功!"
									break
								}
							}
						}
					}
				} else{
					for i:=0; i<len(all_device); i++ {
						if strings.Contains(inText,strings.ToLower(all_device[i].Device_id)) {
							txtmessage="Device_id: "+all_device[i].Device_id+"\n"
							txtmessage=txtmessage+"Site Name: "+all_device[i].SiteName+"\n"
							txtmessage=txtmessage+"Location: ("+strconv.FormatFloat(float64(all_device[i].Gps_lon),'f',3,64)+","+strconv.FormatFloat(float64(all_device[i].Gps_lat),'f',3,64)+")"+"\n"
							txtmessage=txtmessage+"Timestamp: "+all_device[i].Timestamp+"\n"
							txtmessage=txtmessage+"PM2.5: "+strconv.FormatFloat(float64(all_device[i].S_d0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Humidity: "+strconv.FormatFloat(float64(all_device[i].S_h0),'f',0,64)+"\n"
							txtmessage=txtmessage+"Temperature: "+strconv.FormatFloat(float64(all_device[i].S_t0),'f',0,64)
							break
						}
					}
				}
				if len(txtmessage)==0{
					txtmessage="Sorry! No this device ID, please check again."
				}
				if _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(txtmessage)).Do(); err != nil {
					log.Print(err)
				}
			}
		}
	}
}

func stringInSlice(a string, list []string) bool {
    for _, b := range list {
        if b == a {
            return true
        }
    }
    return false
}

func removeStringInSlice(s []string, r string) []string {
    for i, v := range s {
        if v == r {
            return append(s[:i], s[i+1:]...)
        }
    }
    return s
}

<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/alecthomas/kingpin"
	"github.com/goji/httpauth"
	"github.com/gorilla/handlers"
)

type Configure struct {
	Addr       string
	Root       string
	HttpAuth   string
	Cert       string
	Key        string
	Cors       bool
	Theme      string
	XProxy     bool
	Upload     bool
	PlistProxy *url.URL
}

var (
	gcfg = Configure{}
)

func parseFlags() {
	kingpin.HelpFlag.Short('h')
	kingpin.Flag("root", "root directory").Short('r').Default("./").StringVar(&gcfg.Root)
	kingpin.Flag("addr", "listen address").Short('a').Default(":8000").StringVar(&gcfg.Addr)
	kingpin.Flag("cert", "tls cert.pem path").StringVar(&gcfg.Cert)
	kingpin.Flag("key", "tls key.pem path").StringVar(&gcfg.Key)
	kingpin.Flag("cors", "enable cross-site HTTP request").BoolVar(&gcfg.Cors)
	kingpin.Flag("httpauth", "HTTP basic auth (ex: user:pass)").Default("").StringVar(&gcfg.HttpAuth)
	kingpin.Flag("theme", "web theme, one of <black|green>").Default("black").StringVar(&gcfg.Theme)
	kingpin.Flag("xproxy", "Used when behide proxy like nginx").BoolVar(&gcfg.XProxy)
	kingpin.Flag("upload", "Enable upload support").BoolVar(&gcfg.Upload)
	kingpin.Flag("plistproxy", "IPA Plist file proxy, https needed").Short('p').URLVar(&gcfg.PlistProxy)

	kingpin.Parse()
}

func main() {
	parseFlags()

	ss := NewHTTPStaticServer(gcfg.Root)
	ss.Theme = gcfg.Theme

	log.Println(gcfg.PlistProxy)
	if gcfg.Upload {
		ss.EnableUpload()
	}
	if gcfg.PlistProxy != nil {
		ss.PlistProxy = gcfg.PlistProxy.String()
	}

	var hdlr http.Handler = ss
	// HTTP Basic Authentication
	userpass := strings.SplitN(gcfg.HttpAuth, ":", 2)
	if len(userpass) == 2 {
		user, pass := userpass[0], userpass[1]
		hdlr = httpauth.SimpleBasicAuth(user, pass)(hdlr)
	}
	// CORS
	if gcfg.Cors {
		hdlr = handlers.CORS()(hdlr)
	}
	if gcfg.XProxy {
		hdlr = handlers.ProxyHeaders(hdlr)
	}

	http.Handle("/", hdlr)

	log.Printf("Listening on addr: %s\n", strconv.Quote(gcfg.Addr))

	var err error
	if gcfg.Key != "" && gcfg.Cert != "" {
		err = http.ListenAndServeTLS(gcfg.Addr, gcfg.Cert, gcfg.Key, nil)
	} else {
		err = http.ListenAndServe(gcfg.Addr, nil)
	}
	log.Fatal(err)
}
<commit_msg>add access log for golang<commit_after>package main

import (
	"log"
	"net/http"
	"net/url"
	"strconv"
	"strings"

	"github.com/alecthomas/kingpin"
	"github.com/goji/httpauth"
	"github.com/gorilla/handlers"
	accesslog "github.com/mash/go-accesslog"
)

type Configure struct {
	Addr       string
	Root       string
	HttpAuth   string
	Cert       string
	Key        string
	Cors       bool
	Theme      string
	XProxy     bool
	Upload     bool
	PlistProxy *url.URL
}

type logger struct {
}

func (l logger) Log(record accesslog.LogRecord) {
	log.Println(record.Method + " " + record.Uri)
}

var (
	gcfg = Configure{}
	l    = logger{}
)

func parseFlags() {
	kingpin.HelpFlag.Short('h')
	kingpin.Flag("root", "root directory").Short('r').Default("./").StringVar(&gcfg.Root)
	kingpin.Flag("addr", "listen address").Short('a').Default(":8000").StringVar(&gcfg.Addr)
	kingpin.Flag("cert", "tls cert.pem path").StringVar(&gcfg.Cert)
	kingpin.Flag("key", "tls key.pem path").StringVar(&gcfg.Key)
	kingpin.Flag("cors", "enable cross-site HTTP request").BoolVar(&gcfg.Cors)
	kingpin.Flag("httpauth", "HTTP basic auth (ex: user:pass)").Default("").StringVar(&gcfg.HttpAuth)
	kingpin.Flag("theme", "web theme, one of <black|green>").Default("black").StringVar(&gcfg.Theme)
	kingpin.Flag("xproxy", "Used when behide proxy like nginx").BoolVar(&gcfg.XProxy)
	kingpin.Flag("upload", "Enable upload support").BoolVar(&gcfg.Upload)
	kingpin.Flag("plistproxy", "IPA Plist file proxy, https needed").Short('p').URLVar(&gcfg.PlistProxy)

	kingpin.Parse()
}

func main() {
	parseFlags()

	ss := NewHTTPStaticServer(gcfg.Root)
	ss.Theme = gcfg.Theme

	log.Println(gcfg.PlistProxy)
	if gcfg.Upload {
		ss.EnableUpload()
	}
	if gcfg.PlistProxy != nil {
		ss.PlistProxy = gcfg.PlistProxy.String()
	}

	var hdlr http.Handler = ss

	hdlr = accesslog.NewLoggingHandler(hdlr, l)

	// HTTP Basic Authentication
	userpass := strings.SplitN(gcfg.HttpAuth, ":", 2)
	if len(userpass) == 2 {
		user, pass := userpass[0], userpass[1]
		hdlr = httpauth.SimpleBasicAuth(user, pass)(hdlr)
	}
	// CORS
	if gcfg.Cors {
		hdlr = handlers.CORS()(hdlr)
	}
	if gcfg.XProxy {
		hdlr = handlers.ProxyHeaders(hdlr)
	}

	http.Handle("/", hdlr)

	log.Printf("Listening on addr: %s\n", strconv.Quote(gcfg.Addr))

	var err error
	if gcfg.Key != "" && gcfg.Cert != "" {
		err = http.ListenAndServeTLS(gcfg.Addr, gcfg.Cert, gcfg.Key, nil)
	} else {
		err = http.ListenAndServe(gcfg.Addr, nil)
	}
	log.Fatal(err)
}
<|endoftext|>


<commit_before>package main // import "github.com/CenturyLinkLabs/panamaxcli"

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"strings"

	"github.com/CenturyLinkLabs/panamaxcli/actions"
	"github.com/CenturyLinkLabs/panamaxcli/config"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

var Commands []cli.Command

func init() {
	Commands = []cli.Command{
		{
			Name:  "remote",
			Usage: "Manage remotes",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "List remotes",
					Action: remoteListAction,
				},
				{
					Name:        "add",
					Usage:       "Add a remote",
					Description: "Arguments are the name of the remote and the path to the token file.",
					Before:      actionRequiresArgument("remote name", "file path"),
					Action:      remoteAddAction,
				},
				{
					Name:        "active",
					Usage:       "Set or get the active remote",
					Description: "Passing a remote name as an argument makes it the active remote.",
					Before:      actionRequiresArgument("remote name"),
					Action:      noopAction,
				},
				{
					Name:        "remove",
					Usage:       "Remove a remote",
					Description: "Argument is a remote name.",
					Before:      actionRequiresArgument("remote name"),
					Action:      noopAction,
				},
			},
		},
		{
			Name:  "deployment",
			Usage: "Manage deployments",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "List deployments",
					Action: noopAction,
				},
				{
					Name:        "describe",
					Usage:       "Describe a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
				{
					Name:        "redeploy",
					Usage:       "Redeploy a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
				{
					Name:        "delete",
					Usage:       "Delete a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
			},
		},
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "panamaxcli"
	app.Version = "0.0.1"
	app.Usage = "Panamax command-line utility."
	app.Authors = []cli.Author{{"CenturyLink Labs", "clt-labs-futuretech@centurylink.com"}}
	app.Commands = Commands

	app.Run(os.Args)
}

func actionRequiresArgument(args ...string) func(c *cli.Context) error {
	return func(c *cli.Context) error {
		if len(c.Args()) != len(args) {
			s := strings.Join(args, ", ")
			message := fmt.Sprintf("This command requires the following arguments: %s", s)
			log.Errorln(message)
			return errors.New(message)
		}

		return nil
	}
}

func noopAction(c *cli.Context) {
	fmt.Println("This command is not implemented.")
}

func remoteAddAction(c *cli.Context) {
	name := c.Args().First()
	path := c.Args().Get(1)

	usr, _ := user.Current()
	dir := usr.HomeDir
	fileConfig := config.FileConfig{Path: dir + "/.agents"}
	err := fileConfig.Load()
	if err != nil {
		log.Fatal(err)
	}
	config := config.Config(&fileConfig)

	output, err := actions.AddRemote(config, name, path)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf(output)
}

func remoteListAction(c *cli.Context) {
	usr, _ := user.Current()
	dir := usr.HomeDir
	fileConfig := config.FileConfig{Path: dir + "/.agents"}
	err := fileConfig.Load()
	if err != nil {
		log.Fatal(err)
	}
	config := config.Config(&fileConfig)

	output := actions.ListRemotes(config)

	fmt.Printf(output)
}
<commit_msg>Refactor config loading.<commit_after>package main // import "github.com/CenturyLinkLabs/panamaxcli"

import (
	"errors"
	"fmt"
	"os"
	"os/user"
	"strings"

	"github.com/CenturyLinkLabs/panamaxcli/actions"
	"github.com/CenturyLinkLabs/panamaxcli/config"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

var (
	Config   config.Config
	Commands []cli.Command
)

func init() {
	Commands = []cli.Command{
		{
			Name:  "remote",
			Usage: "Manage remotes",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "List remotes",
					Action: remoteListAction,
				},
				{
					Name:        "add",
					Usage:       "Add a remote",
					Description: "Arguments are the name of the remote and the path to the token file.",
					Before:      actionRequiresArgument("remote name", "file path"),
					Action:      remoteAddAction,
				},
				{
					Name:        "active",
					Usage:       "Set or get the active remote",
					Description: "Passing a remote name as an argument makes it the active remote.",
					Before:      actionRequiresArgument("remote name"),
					Action:      noopAction,
				},
				{
					Name:        "remove",
					Usage:       "Remove a remote",
					Description: "Argument is a remote name.",
					Before:      actionRequiresArgument("remote name"),
					Action:      noopAction,
				},
			},
		},
		{
			Name:  "deployment",
			Usage: "Manage deployments",
			Subcommands: []cli.Command{
				{
					Name:   "list",
					Usage:  "List deployments",
					Action: noopAction,
				},
				{
					Name:        "describe",
					Usage:       "Describe a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
				{
					Name:        "redeploy",
					Usage:       "Redeploy a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
				{
					Name:        "delete",
					Usage:       "Delete a deployment",
					Description: "Argument is a deployment ID.",
					Before:      actionRequiresArgument("deployment ID"),
					Action:      noopAction,
				},
			},
		},
	}
}

func main() {
	app := cli.NewApp()
	app.Name = "panamaxcli"
	app.Version = "0.0.1"
	app.Usage = "Panamax command-line utility."
	app.Authors = []cli.Author{{"CenturyLink Labs", "clt-labs-futuretech@centurylink.com"}}
	app.Commands = Commands
	app.Before = loadConfig

	app.Run(os.Args)
}

func loadConfig(c *cli.Context) error {
	usr, _ := user.Current()
	dir := usr.HomeDir
	fileConfig := config.FileConfig{Path: dir + "/.agents"}
	err := fileConfig.Load()
	if err != nil {
		log.Error(err)
		return err
	}
	Config = config.Config(&fileConfig)

	return nil
}

func actionRequiresArgument(args ...string) func(c *cli.Context) error {
	return func(c *cli.Context) error {
		if len(c.Args()) != len(args) {
			s := strings.Join(args, ", ")
			message := fmt.Sprintf("This command requires the following arguments: %s", s)
			log.Errorln(message)
			return errors.New(message)
		}

		return nil
	}
}

func noopAction(c *cli.Context) {
	fmt.Println("This command is not implemented.")
}

func remoteAddAction(c *cli.Context) {
	name := c.Args().First()
	path := c.Args().Get(1)

	output, err := actions.AddRemote(Config, name, path)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf(output)
}

func remoteListAction(c *cli.Context) {
	output := actions.ListRemotes(Config)

	fmt.Printf(output)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var (
	port          = flag.Int("port", 8090, "TCP port to listen on")
	webserverPort = flag.Int("webserver_port", 8084, "TCP port to listen on")
	environment   = flag.String("environment", "development", "environment")
	redisHost     = flag.String("redis", "127.0.0.1:6379", "host:ip of Redis instance")
)

var redisPool *redis.Pool

type (
	Controller struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}
	Sensor struct {
		ID int64 `json:"id"`
	}
	Tick struct {
		Datetime        time.Time `json:"datetime"`
		SensorID        int64     `json:"sensor_id"`
		NextDataSession string    `json:"next_data_session,omitempty"` // sec
		BatteryVoltage  string    `json:"battery_voltage,omitempty"`   // mV
		Sensor1         string    `json:"sensor1,omitempty"`
		Sensor2         string    `json:"sensor2,omitempty"`
		RadioQuality    string    `json:"radio_quality,omitempty"` // (LQI=0..255)
	}
	PaginatedTicks struct {
		Ticks []*Tick `json:"ticks"`
		Total int     `json:"total"`
	}
)

func main() {
	flag.Parse()

	redisPool = getRedisPool(*redisHost)
	defer redisPool.Close()

	http.HandleFunc("/controllers", getControllers)
	http.HandleFunc("/controller/{controller_id}/sensors", getControllers)
	http.HandleFunc("/sensors", getSensors)
	http.HandleFunc("/sensors/{sensor_id}/ticks", getSensorTicks)
	http.HandleFunc("/log", getLogs)
	http.HandleFunc("/logs", getLogs)

	if *environment == "production" || *environment == "test" {
		f, err := os.OpenFile(filepath.Join("log", *environment+".log"), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	ln, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		log.Println("Upload server started on port", *port)
		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Println("Error while accepting connection:", err)
				continue
			}
			go handleConnection(conn)
		}
	}()

	log.Println("HTTP server started on port", *webserverPort)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *webserverPort), http.DefaultServeMux))
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	log.Println("New connection")
	buf := &bytes.Buffer{}
	for {
		data := make([]byte, 256)
		n, err := conn.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Println("Error while reading from connection:", err)
			return
		}
		buf.Write(data[:n])
		if data[0] == 13 && data[1] == 10 {
			break
		}
	}

	go func() {
		redisClient := redisPool.Get()
		defer redisClient.Close()
		if _, err := redisClient.Do("LPUSH", "sensor_server:logs", time.Now().String()+" "+buf.String()); err != nil {
			log.Println(err)
			return
		}
		if _, err := redisClient.Do("LTRIM", "sensor_server:logs", 0, 1000); err != nil {
			log.Println(err)
			return
		}
	}()

	start := time.Now()
	count, err := ProcessTicks(buf.String())
	if err != nil {
		log.Println("Error while processing ticks:", err)
		return
	}
	log.Println("Processed", count, "ticks in", time.Since(start))
}

func getLogs(w http.ResponseWriter, r *http.Request) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("LRANGE", "sensor_server:logs", 0, 1000)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	for _, b := range bb.([][]byte) {
		w.Write(b)
		w.Write([]byte("\n\r"))
	}
}

const keyControllers = "zeitl:controllers"

func getControllers(w http.ResponseWriter, r *http.Request) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("SMEMBERS", keyControllers)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	controllers := make([]*Controller, 0)
	for _, b := range bb.([][]byte) {
		controllerID := string(b)
		controllerName := "FIXME: get controller name using HGET"
		controller := &Controller{ID: controllerID, Name: controllerName}
		controllers = append(controllers, controller)
	}

	b, err := json.Marshal(controllers)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getSensors(w http.ResponseWriter, r *http.Request) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("SMEMBERS", "known_sensors")
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	sensors := make([]*Sensor, 0)
	for _, b := range bb.([][]byte) {
		sensorID, err := strconv.ParseInt(string(b), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		sensor := &Sensor{ID: sensorID}
		sensors = append(sensors, sensor)
	}

	b, err := json.Marshal(sensors)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getSensorTicks(w http.ResponseWriter, r *http.Request) {
	// Parse sensor ID
	s, ok := mux.Vars(r)["sensor_id"]
	if !ok {
		http.Error(w, "Missing sensor_id", http.StatusInternalServerError)
		return
	}
	sensorID, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Parse start index of tick range
	startIndex, err := strconv.Atoi(r.FormValue("start_index"))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Parse stop index of tick range
	stopIndex, err := strconv.Atoi(r.FormValue("stop_index"))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Find ticks in the given start index - stop index range
	result, err := FindTicks(sensorID, startIndex, stopIndex)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	b, err := json.Marshal(result)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getRedisPool(host string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			return redis.Dial("tcp", host)
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func NewTick(input string) (*Tick, error) {
	log.Println("NewTick, input: ", input)
	contents := input[1 : len(input)-1]
	parts := strings.Split(contents, ";")
	datetime, err := time.Parse("2006-1-2 15:4:5", parts[0])
	if err != nil {
		return nil, err
	}
	sensorID, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return nil, err
	}
	tick := &Tick{
		Datetime:        datetime,
		SensorID:        sensorID,
		NextDataSession: parts[2],
		BatteryVoltage:  parts[3],
		Sensor1:         parts[4],
		Sensor2:         parts[5],
		RadioQuality:    parts[6],
	}
	return tick, err
}

func FindTicks(sensorID int64, startIndex, stopIndex int) (*PaginatedTicks, error) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	total, err := redis.Int(redisClient.Do("ZCARD", keyOfSensorTicks(sensorID)))
	if err != nil {
		return nil, err
	}

	bb, err := redisClient.Do("ZREVRANGE", keyOfSensorTicks(sensorID), startIndex, stopIndex)
	if err != nil {
		return nil, err
	}

	result := PaginatedTicks{Total: total}
	for _, b := range bb.([][]byte) {
		tick := &Tick{}
		if err := json.Unmarshal(b, &tick); err != nil {
			return nil, err
		}
		result.Ticks = append(result.Ticks, tick)
	}

	return &result, nil
}

func (tick Tick) Save() error {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	b, err := json.Marshal(tick)
	if err != nil {
		return err
	}

	_, err = redisClient.Do("ZADD", tick.key(), tick.rank(), b)
	return err
}

func (tick Tick) rank() float64 {
	return float64(tick.Datetime.Unix())
}

func (tick Tick) key() string {
	return keyOfSensorTicks(tick.SensorID)
}

func keyOfSensorTicks(sensorID int64) string {
	return fmt.Sprintf("sensor:%d:ticks", sensorID)
}

func (tick Tick) String() string {
	return fmt.Sprintf("datetime: %v, sensor ID: %d, next: %s, battery: %s, sensor1: %s, sensor2: %s, radio: %s",
		tick.Datetime, tick.SensorID, tick.NextDataSession, tick.BatteryVoltage, tick.Sensor1, tick.Sensor2, tick.RadioQuality)
}

func ProcessTicks(tickList string) (int, error) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	tickList = strings.Replace(tickList, "\r", "\n", -1)
	registeredSensorIds := make(map[int64]bool)
	processedCount := 0
	for _, s := range strings.Split(tickList, "\n") {
		if len(s) == 0 {
			continue
		}
		tick, err := NewTick(s)
		if err != nil {
			return 0, err
		}
		if err := tick.Save(); err != nil {
			return 0, err
		}
		log.Println("Saved:", tick)
		processedCount += 1
		// Register sensor for later lookup
		_, sensorRegistered := registeredSensorIds[tick.SensorID]
		if sensorRegistered {
			continue
		}
		if _, err := redisClient.Do("SADD", "known_sensors", fmt.Sprintf("%d", tick.SensorID)); err != nil {
			return 0, err
		}
		registeredSensorIds[tick.SensorID] = true
	}
	return processedCount, nil
}
<commit_msg>Set controller ID as temp. value for now<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/mux"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var (
	port          = flag.Int("port", 8090, "TCP port to listen on")
	webserverPort = flag.Int("webserver_port", 8084, "TCP port to listen on")
	environment   = flag.String("environment", "development", "environment")
	redisHost     = flag.String("redis", "127.0.0.1:6379", "host:ip of Redis instance")
)

var redisPool *redis.Pool

const keyControllers = "osp:controllers"
const keyLogs = "osp:logs"

func keyOfControllerSensors(controllerID string) string {
	return "osp:controller:" + controllerID + ":sensors"
}

func keyOfSensorTicks(sensorID int64) string {
	return fmt.Sprintf("osp:sensor:%d:ticks", sensorID)
}

type (
	Controller struct {
		ID   string `json:"id"`
		Name string `json:"name"`
	}
	Sensor struct {
		ID int64 `json:"id"`
	}
	Tick struct {
		Datetime        time.Time `json:"datetime"`
		SensorID        int64     `json:"sensor_id"`
		NextDataSession string    `json:"next_data_session,omitempty"` // sec
		BatteryVoltage  string    `json:"battery_voltage,omitempty"`   // mV
		Sensor1         string    `json:"sensor1,omitempty"`
		Sensor2         string    `json:"sensor2,omitempty"`
		RadioQuality    string    `json:"radio_quality,omitempty"` // (LQI=0..255)
	}
	PaginatedTicks struct {
		Ticks []*Tick `json:"ticks"`
		Total int     `json:"total"`
	}
)

func main() {
	flag.Parse()

	redisPool = getRedisPool(*redisHost)
	defer redisPool.Close()

	http.HandleFunc("/controllers", getControllers)
	http.HandleFunc("/controller/{controller_id}/sensors", getControllerSensors)
	http.HandleFunc("/sensors/{sensor_id}/ticks", getSensorTicks)
	http.HandleFunc("/log", getLogs)
	http.HandleFunc("/logs", getLogs)

	if *environment == "production" || *environment == "test" {
		f, err := os.OpenFile(filepath.Join("log", *environment+".log"), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0640)
		if err != nil {
			log.Fatal(err)
		}
		defer f.Close()
		log.SetOutput(f)
	}

	runtime.GOMAXPROCS(runtime.NumCPU())

	ln, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatal(err)
	}
	go func() {
		log.Println("Upload server started on port", *port)
		for {
			conn, err := ln.Accept()
			if err != nil {
				log.Println("Error while accepting connection:", err)
				continue
			}
			go handleConnection(conn)
		}
	}()

	log.Println("HTTP server started on port", *webserverPort)
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *webserverPort), http.DefaultServeMux))
}

func handleConnection(conn net.Conn) {
	defer conn.Close()
	log.Println("New connection")
	buf := &bytes.Buffer{}
	for {
		data := make([]byte, 256)
		n, err := conn.Read(data)
		if err != nil {
			if err == io.EOF {
				break
			}
			log.Println("Error while reading from connection:", err)
			return
		}
		buf.Write(data[:n])
		if data[0] == 13 && data[1] == 10 {
			break
		}
	}

	go func() {
		redisClient := redisPool.Get()
		defer redisClient.Close()
		if _, err := redisClient.Do("LPUSH", keyLogs, time.Now().String()+" "+buf.String()); err != nil {
			log.Println(err)
			return
		}
		if _, err := redisClient.Do("LTRIM", keyLogs, 0, 1000); err != nil {
			log.Println(err)
			return
		}
	}()

	start := time.Now()
	count, err := ProcessTicks(buf.String())
	if err != nil {
		log.Println("Error while processing ticks:", err)
		return
	}
	log.Println("Processed", count, "ticks in", time.Since(start))
}

func getLogs(w http.ResponseWriter, r *http.Request) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("LRANGE", keyLogs, 0, 1000)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/plain")
	for _, b := range bb.([][]byte) {
		w.Write(b)
		w.Write([]byte("\n\r"))
	}
}

func getControllers(w http.ResponseWriter, r *http.Request) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("SMEMBERS", keyControllers)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	controllers := make([]*Controller, 0)
	for _, b := range bb.([][]byte) {
		controllerID := string(b)
		controllerName := "FIXME: get controller name using HGET"
		controller := &Controller{ID: controllerID, Name: controllerName}
		controllers = append(controllers, controller)
	}

	b, err := json.Marshal(controllers)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getControllerSensors(w http.ResponseWriter, r *http.Request) {
	// Parse controller ID
	controllerID, ok := mux.Vars(r)["controller_id"]
	if !ok {
		http.Error(w, "Missing controller_id", http.StatusInternalServerError)
		return
	}

	redisClient := redisPool.Get()
	defer redisClient.Close()

	bb, err := redisClient.Do("SMEMBERS", keyOfControllerSensors(controllerID))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	sensors := make([]*Sensor, 0)
	for _, b := range bb.([][]byte) {
		sensorID, err := strconv.ParseInt(string(b), 10, 64)
		if err != nil {
			log.Println(err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		sensor := &Sensor{ID: sensorID}
		sensors = append(sensors, sensor)
	}

	b, err := json.Marshal(sensors)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getSensorTicks(w http.ResponseWriter, r *http.Request) {
	// Parse sensor ID
	s, ok := mux.Vars(r)["sensor_id"]
	if !ok {
		http.Error(w, "Missing sensor_id", http.StatusInternalServerError)
		return
	}
	sensorID, err := strconv.ParseInt(s, 10, 64)
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Parse start index of tick range
	startIndex, err := strconv.Atoi(r.FormValue("start_index"))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Parse stop index of tick range
	stopIndex, err := strconv.Atoi(r.FormValue("stop_index"))
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Find ticks in the given start index - stop index range
	result, err := FindTicks(sensorID, startIndex, stopIndex)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	b, err := json.Marshal(result)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write(b)
}

func getRedisPool(host string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			return redis.Dial("tcp", host)
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func NewTick(input string) (*Tick, error) {
	log.Println("NewTick, input: ", input)
	contents := input[1 : len(input)-1]
	parts := strings.Split(contents, ";")
	datetime, err := time.Parse("2006-1-2 15:4:5", parts[0])
	if err != nil {
		return nil, err
	}
	sensorID, err := strconv.ParseInt(parts[1], 10, 64)
	if err != nil {
		return nil, err
	}
	tick := &Tick{
		Datetime:        datetime,
		SensorID:        sensorID,
		NextDataSession: parts[2],
		BatteryVoltage:  parts[3],
		Sensor1:         parts[4],
		Sensor2:         parts[5],
		RadioQuality:    parts[6],
	}
	return tick, err
}

func FindTicks(sensorID int64, startIndex, stopIndex int) (*PaginatedTicks, error) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	total, err := redis.Int(redisClient.Do("ZCARD", keyOfSensorTicks(sensorID)))
	if err != nil {
		return nil, err
	}

	bb, err := redisClient.Do("ZREVRANGE", keyOfSensorTicks(sensorID), startIndex, stopIndex)
	if err != nil {
		return nil, err
	}

	result := PaginatedTicks{Total: total}
	for _, b := range bb.([][]byte) {
		tick := &Tick{}
		if err := json.Unmarshal(b, &tick); err != nil {
			return nil, err
		}
		result.Ticks = append(result.Ticks, tick)
	}

	return &result, nil
}

func (tick Tick) Save() error {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	b, err := json.Marshal(tick)
	if err != nil {
		return err
	}

	_, err = redisClient.Do("ZADD", tick.key(), tick.rank(), b)
	return err
}

func (tick Tick) rank() float64 {
	return float64(tick.Datetime.Unix())
}

func (tick Tick) key() string {
	return keyOfSensorTicks(tick.SensorID)
}

func (tick Tick) String() string {
	return fmt.Sprintf("datetime: %v, sensor ID: %d, next: %s, battery: %s, sensor1: %s, sensor2: %s, radio: %s",
		tick.Datetime, tick.SensorID, tick.NextDataSession, tick.BatteryVoltage, tick.Sensor1, tick.Sensor2, tick.RadioQuality)
}

func ProcessTicks(tickList string) (int, error) {
	redisClient := redisPool.Get()
	defer redisClient.Close()

	tickList = strings.Replace(tickList, "\r", "\n", -1)
	registeredSensorIds := make(map[int64]bool)
	processedCount := 0
	for _, s := range strings.Split(tickList, "\n") {
		if len(s) == 0 {
			continue
		}
		tick, err := NewTick(s)
		if err != nil {
			return 0, err
		}
		if err := tick.Save(); err != nil {
			return 0, err
		}
		log.Println("Saved:", tick)
		processedCount += 1

		// controller ID will be sent
		controllerID := "myfancycontroller"

		// Register sensor for later lookup
		_, sensorRegistered := registeredSensorIds[tick.SensorID]
		if sensorRegistered {
			continue
		}
		if _, err := redisClient.Do("SADD", keyOfControllerSensors(controllerID), fmt.Sprintf("%d", tick.SensorID)); err != nil {
			return 0, err
		}
		registeredSensorIds[tick.SensorID] = true
	}
	return processedCount, nil
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/go-redis/cache"
	"github.com/go-redis/redis"
	"github.com/gofn/gofn"
	"github.com/gofn/gofn/provision"
	"github.com/gorilla/mux"
	"github.com/urfave/negroni"
	msgpack "gopkg.in/vmihailenco/msgpack.v2"
)

const (
	// coverQMax is the maximum number of coverage run to be executed simultaneously
	coverQMax = 0
	// coverQName is the Redis channel name where the requests are queued
	coverQName = "coverqueue"

	// inProgrsKey is the redis HSet key in which all repo + tags which are currently being run
	// are saved
	inProgrsKey = "cover-in-progress"

	// DefaultTag is the Go version to run the tests with when no version
	// is specified
	DefaultTag = "golang-1.10"
)

var (
	// errLogger is the log instance with all the required flags set for error logging
	errLogger = log.New(os.Stderr, "Cover.Run ", log.LstdFlags|log.Lshortfile)

	// coverQCur is the current number of cover run requests being executed simultaneously
	coverQCur = int32(0)

	httpClient = &http.Client{
		// img.shields.io response time is very slow
		Timeout: 30 * time.Second,
	}

	// ErrImgUnSupported is the error returned when the Go version requested is
	// not in the supported list
	ErrImgUnSupported = errors.New("Unsupported Go version provided")
	// ErrRepoNotFound is the error returned when the repository does not exist
	ErrRepoNotFound = errors.New("Repository not found")
	// ErrUnknown is the error returned when an unidentified error is encountered
	ErrUnknown = errors.New("Unknown error occurred")
	// ErrQueueFull is the error returned when the cover run queueu is full
	ErrQueueFull = errors.New("Cover run queue is full")
	// ErrCovInPrgrs is the error returned when the repo coverage test is in progress
	ErrCovInPrgrs = errors.New("Cover run is in progress")

	redisRing = redis.NewRing(&redis.RingOptions{
		Addrs: map[string]string{
			"server1": "redis:6379",
		},
	})
	redisCodec = &cache.Codec{
		Redis: redisRing,

		Marshal: func(v interface{}) ([]byte, error) {
			return msgpack.Marshal(v)
		},
		Unmarshal: func(b []byte, v interface{}) error {
			return msgpack.Unmarshal(b, v)
		},
	}
	redisClient = redis.NewClient(&redis.Options{
		Addr:         "redis:6379",
		ReadTimeout:  time.Second * 2,
		DialTimeout:  time.Second * 5,
		WriteTimeout: time.Second * 5,
		PoolTimeout:  time.Second * 120,
	})

	qLock = sync.Mutex{}

	repoTmpl = template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/repo.tmpl"))
	homeTmpl = template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/home.tmpl"))
)

// imageSupported returns true if the given Go version is supported
func imageSupported(tag string) bool {
	switch tag {
	case "golang-1.10",
		"golang-1.9",
		"golang-1.8":
		return true
	}
	return false
}

// repoExists checks if the given repository exists (works only if HTTP request returns 200)
func repoExists(repo string) (bool, error) {
	resp, err := httpClient.Get(fmt.Sprintf("https://%s", repo))
	if err != nil {
		return false, err
	}

	if resp.StatusCode == http.StatusNotFound {
		return false, ErrRepoNotFound
	}

	if resp.StatusCode > 399 {
		return false, ErrUnknown
	}
	return true, nil
}

// run runs the custom script to get the coverage details; using gofn
func run(imageRepoName, dockerTag, repo string) (string, string, error) {
	_, err := repoExists(repo)
	if err != nil {
		return "", "", err
	}

	buildOpts := &provision.BuildOptions{
		DoNotUsePrefixImageName: true,
		ImageName:               strings.ToLower(fmt.Sprintf("%s:%s", imageRepoName, dockerTag)),
		StdIN:                   fmt.Sprintf("sh /run.sh %s", repo),
	}

	// 5 minutes timeout
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*300)
	defer cancel()

	StdOut, StdErr, err := gofn.Run(ctx, buildOpts, &provision.ContainerOptions{})
	if err != nil {
		errLogger.Println(err)
	}

	return StdOut, StdErr, err
}

// Object struct holds all the details of a repository
type Object struct {
	Repo   string
	Tag    string
	Cover  string
	Output bool
}

// repoFullName generates a name by combining the Go tag
func repoFullName(repo, tag string) string {
	return fmt.Sprintf("%s:%s", repo, tag)
}

// repoTagFromFullName returns the repo name and Go tag, given the generated full name
func repoTagFromFullName(msg string) (string, string) {
	parts := strings.Split(msg, ":")
	if len(parts) == 2 {
		return parts[0], parts[1]
	}
	return "", ""
}

// addToQ pushes a new cover run request to the Redis channel
func addToQ(repo, tag string) error {
	qLock.Lock()
	err := redisClient.Publish(coverQName, repoFullName(repo, tag)).Err()
	qLock.Unlock()
	return err
}

// repoCoverStatus returns true if a repository + tag cover run is in progress
func repoCoverStatus(repo, tag string) (bool, error) {
	// Check if cover run is already in progress for the given repo and tag
	err := redisRing.HGet(inProgrsKey, repoFullName(repo, tag)).Err()
	if err == nil {
		return true, nil
	}
	errLogger.Println(err)
	return false, err
}

// setInProgress sets the repo + tag as in progress by adding to inPrgorsKey
func setInProgress(repo, tag string) error {
	err := redisRing.HSet(inProgrsKey, repoFullName(repo, tag), "y").Err()
	if err != nil {
		errLogger.Println(err)
	}
	return err
}

// unsetInProgress unsets the repo + tag from inprogress status
func unsetInProgress(repo, tag string) error {
	err := redisRing.HDel(inProgrsKey, repoFullName(repo, tag)).Err()
	if err != nil {
		errLogger.Println(err)
	}
	return err
}

// cover evaluates the coverage of a repository
// - Before starting evaluation, it sets the repo's status as in progress
// - Removes the inprogress status of a repo after it's done
func cover(repo, tag string) error {
	atomic.AddInt32(&coverQCur, 1)

	setInProgress(repo, tag)

	StdOut, StdErr, err := run("avelino/cover.run", tag, repo)
	if err != nil {
		errLogger.Println(err)
		unsetInProgress(repo, tag)
		if coverQCur > -1 {
			atomic.AddInt32(&coverQCur, -1)
		}
		return err
	}

	unsetInProgress(repo, tag)

	obj := &Object{
		Repo:   repo,
		Tag:    tag,
		Cover:  StdErr,
		Output: false,
	}

	stdOut := strings.Trim(StdOut, " \n")
	if stdOut != "" {
		obj.Cover = stdOut
		obj.Output = true
	}

	err = redisCodec.Set(&cache.Item{
		Key:        repoFullName(repo, tag),
		Object:     obj,
		Expiration: time.Hour,
	})
	if err != nil {
		errLogger.Println(err)
	}

	// reduce the simultaneous process number by 1
	if coverQCur > -1 {
		atomic.AddInt32(&coverQCur, -1)
	}
	return nil
}

// repoCover returns code coverage details for the given repository and Go version
// - It checks if the coverage details is available in cache or not
// - It checks if the cover run is in progress or not
// - It checks if cover can be run simultaneously, if not request is pushed to Q
func repoCover(repo, imageTag string) (*Object, error) {
	obj := &Object{
		Repo: repo,
		Tag:  imageTag,
	}

	if redisCodec.Get(repoFullName(repo, imageTag), &obj) == nil {
		return obj, nil
	}

	if !imageSupported(imageTag) {
		obj.Cover = fmt.Sprintf("Sorry, docker image not found, avelino/cover.run:%s, see Supported languages: https://github.com/avelino/cover.run#supported", imageTag)
		return obj, ErrImgUnSupported
	}

	if ok, _ := repoCoverStatus(repo, imageTag); ok {
		return obj, ErrCovInPrgrs
	}

	// Checking if limit of simultaneous processing has reached or not
	if coverQCur >= coverQMax {
		err := addToQ(repo, imageTag)
		if err != nil {
			errLogger.Println(err)
		}
		return obj, ErrQueueFull
	}

	go cover(repo, imageTag)

	return obj, ErrCovInPrgrs
}

type Repository struct {
	Repo  string
	Tag   string
	Cover string
}

func repoLatest() ([]*Repository, error) {
	repos := make([]*Repository, 0)
	keys, _, err := redisRing.Scan(0, "*", 10).Result()
	if err != nil {
		errLogger.Println(err)
		return repos, err
	}

	var obj Object
	for _, key := range keys {
		if len(repos) == 5 {
			return repos, nil
		}
		if err := redisCodec.Get(key, &obj); err == nil {
			if obj.Output {
				repos = append(repos, &Repository{obj.Repo, obj.Tag, obj.Cover})
			}
		}
	}
	return repos, nil
}

// subscribe subscribes to the Redis channel
func subscribe(qname string) {
	pubsub, err := redisClient.Subscribe(qname)
	if err != nil {
		errLogger.Println(err)
		return
	}
	defer pubsub.Close()

	for {
		msg, err := pubsub.ReceiveMessage()
		if err != nil {
			errLogger.Println(err)
		}
		repo, tag := repoTagFromFullName(msg.Payload)
		if ok, _ := repoCoverStatus(repo, tag); !ok {
			cover(repo, tag)
		}
	}
}

func main() {
	n := negroni.Classic()
	r := mux.NewRouter()
	r.HandleFunc("/", Handler)
	r.HandleFunc("/go/{repo:.*}.json", HandlerRepoJSON)
	r.HandleFunc("/go/{repo:.*}.svg", HandlerRepoSVG)
	r.HandleFunc("/go/{repo:.*}", HandlerRepo)
	r.PathPrefix("/assets").Handler(
		http.StripPrefix("/assets", http.FileServer(http.Dir("./assets/"))))
	n.UseHandler(r)

	go subscribe("coverQueue")

	n.Run(":3000")
}
<commit_msg>was subscribed to the wrong Qgit diff<commit_after>package main

import (
	"context"
	"errors"
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/go-redis/cache"
	"github.com/go-redis/redis"
	"github.com/gofn/gofn"
	"github.com/gofn/gofn/provision"
	"github.com/gorilla/mux"
	"github.com/urfave/negroni"
	msgpack "gopkg.in/vmihailenco/msgpack.v2"
)

const (
	// coverQMax is the maximum number of coverage run to be executed simultaneously
	coverQMax = 0
	// coverQName is the Redis channel name where the requests are queued
	coverQName = "coverqueue"

	// inProgrsKey is the redis HSet key in which all repo + tags which are currently being run
	// are saved
	inProgrsKey = "cover-in-progress"

	// DefaultTag is the Go version to run the tests with when no version
	// is specified
	DefaultTag = "golang-1.10"
)

var (
	// errLogger is the log instance with all the required flags set for error logging
	errLogger = log.New(os.Stderr, "Cover.Run ", log.LstdFlags|log.Lshortfile)

	// coverQCur is the current number of cover run requests being executed simultaneously
	coverQCur = int32(0)

	httpClient = &http.Client{
		// img.shields.io response time is very slow
		Timeout: 30 * time.Second,
	}

	// ErrImgUnSupported is the error returned when the Go version requested is
	// not in the supported list
	ErrImgUnSupported = errors.New("Unsupported Go version provided")
	// ErrRepoNotFound is the error returned when the repository does not exist
	ErrRepoNotFound = errors.New("Repository not found")
	// ErrUnknown is the error returned when an unidentified error is encountered
	ErrUnknown = errors.New("Unknown error occurred")
	// ErrQueueFull is the error returned when the cover run queueu is full
	ErrQueueFull = errors.New("Cover run queue is full")
	// ErrCovInPrgrs is the error returned when the repo coverage test is in progress
	ErrCovInPrgrs = errors.New("Cover run is in progress")

	redisRing = redis.NewRing(&redis.RingOptions{
		Addrs: map[string]string{
			"server1": "redis:6379",
		},
	})
	redisCodec = &cache.Codec{
		Redis: redisRing,

		Marshal: func(v interface{}) ([]byte, error) {
			return msgpack.Marshal(v)
		},
		Unmarshal: func(b []byte, v interface{}) error {
			return msgpack.Unmarshal(b, v)
		},
	}
	redisClient = redis.NewClient(&redis.Options{
		Addr:         "redis:6379",
		ReadTimeout:  time.Second * 2,
		DialTimeout:  time.Second * 5,
		WriteTimeout: time.Second * 5,
		PoolTimeout:  time.Second * 120,
	})

	qLock = sync.Mutex{}

	repoTmpl = template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/repo.tmpl"))
	homeTmpl = template.Must(template.ParseFiles("./templates/layout.tmpl", "./templates/home.tmpl"))
)

// imageSupported returns true if the given Go version is supported
func imageSupported(tag string) bool {
	switch tag {
	case "golang-1.10",
		"golang-1.9",
		"golang-1.8":
		return true
	}
	return false
}

// repoExists checks if the given repository exists (works only if HTTP request returns 200)
func repoExists(repo string) (bool, error) {
	resp, err := httpClient.Get(fmt.Sprintf("https://%s", repo))
	if err != nil {
		return false, err
	}

	if resp.StatusCode == http.StatusNotFound {
		return false, ErrRepoNotFound
	}

	if resp.StatusCode > 399 {
		return false, ErrUnknown
	}
	return true, nil
}

// run runs the custom script to get the coverage details; using gofn
func run(imageRepoName, dockerTag, repo string) (string, string, error) {
	_, err := repoExists(repo)
	if err != nil {
		return "", "", err
	}

	buildOpts := &provision.BuildOptions{
		DoNotUsePrefixImageName: true,
		ImageName:               strings.ToLower(fmt.Sprintf("%s:%s", imageRepoName, dockerTag)),
		StdIN:                   fmt.Sprintf("sh /run.sh %s", repo),
	}

	// 5 minutes timeout
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*300)
	defer cancel()

	StdOut, StdErr, err := gofn.Run(ctx, buildOpts, &provision.ContainerOptions{})
	if err != nil {
		errLogger.Println(err)
	}

	return StdOut, StdErr, err
}

// Object struct holds all the details of a repository
type Object struct {
	Repo   string
	Tag    string
	Cover  string
	Output bool
}

// repoFullName generates a name by combining the Go tag
func repoFullName(repo, tag string) string {
	return fmt.Sprintf("%s:%s", repo, tag)
}

// repoTagFromFullName returns the repo name and Go tag, given the generated full name
func repoTagFromFullName(msg string) (string, string) {
	parts := strings.Split(msg, ":")
	if len(parts) == 2 {
		return parts[0], parts[1]
	}
	return "", ""
}

// addToQ pushes a new cover run request to the Redis channel
func addToQ(repo, tag string) error {
	qLock.Lock()
	err := redisClient.Publish(coverQName, repoFullName(repo, tag)).Err()
	qLock.Unlock()
	return err
}

// repoCoverStatus returns true if a repository + tag cover run is in progress
func repoCoverStatus(repo, tag string) (bool, error) {
	// Check if cover run is already in progress for the given repo and tag
	err := redisRing.HGet(inProgrsKey, repoFullName(repo, tag)).Err()
	if err == nil {
		return true, nil
	}
	errLogger.Println(err)
	return false, err
}

// setInProgress sets the repo + tag as in progress by adding to inPrgorsKey
func setInProgress(repo, tag string) error {
	err := redisRing.HSet(inProgrsKey, repoFullName(repo, tag), "y").Err()
	if err != nil {
		errLogger.Println(err)
	}
	return err
}

// unsetInProgress unsets the repo + tag from inprogress status
func unsetInProgress(repo, tag string) error {
	err := redisRing.HDel(inProgrsKey, repoFullName(repo, tag)).Err()
	if err != nil {
		errLogger.Println(err)
	}
	return err
}

// cover evaluates the coverage of a repository
// - Before starting evaluation, it sets the repo's status as in progress
// - Removes the inprogress status of a repo after it's done
func cover(repo, tag string) error {
	atomic.AddInt32(&coverQCur, 1)

	setInProgress(repo, tag)

	StdOut, StdErr, err := run("avelino/cover.run", tag, repo)
	if err != nil {
		errLogger.Println(err)
		unsetInProgress(repo, tag)
		if coverQCur > -1 {
			atomic.AddInt32(&coverQCur, -1)
		}
		return err
	}

	unsetInProgress(repo, tag)

	obj := &Object{
		Repo:   repo,
		Tag:    tag,
		Cover:  StdErr,
		Output: false,
	}

	stdOut := strings.Trim(StdOut, " \n")
	if stdOut != "" {
		obj.Cover = stdOut
		obj.Output = true
	}

	err = redisCodec.Set(&cache.Item{
		Key:        repoFullName(repo, tag),
		Object:     obj,
		Expiration: time.Hour,
	})
	if err != nil {
		errLogger.Println(err)
	}

	// reduce the simultaneous process number by 1
	if coverQCur > -1 {
		atomic.AddInt32(&coverQCur, -1)
	}
	return nil
}

// repoCover returns code coverage details for the given repository and Go version
// - It checks if the coverage details is available in cache or not
// - It checks if the cover run is in progress or not
// - It checks if cover can be run simultaneously, if not request is pushed to Q
func repoCover(repo, imageTag string) (*Object, error) {
	obj := &Object{
		Repo: repo,
		Tag:  imageTag,
	}

	if redisCodec.Get(repoFullName(repo, imageTag), &obj) == nil {
		return obj, nil
	}

	if !imageSupported(imageTag) {
		obj.Cover = fmt.Sprintf("Sorry, docker image not found, avelino/cover.run:%s, see Supported languages: https://github.com/avelino/cover.run#supported", imageTag)
		return obj, ErrImgUnSupported
	}

	if ok, _ := repoCoverStatus(repo, imageTag); ok {
		return obj, ErrCovInPrgrs
	}

	// Checking if limit of simultaneous processing has reached or not
	if coverQCur >= coverQMax {
		err := addToQ(repo, imageTag)
		if err != nil {
			errLogger.Println(err)
		}
		return obj, ErrQueueFull
	}

	go cover(repo, imageTag)

	return obj, ErrCovInPrgrs
}

type Repository struct {
	Repo  string
	Tag   string
	Cover string
}

func repoLatest() ([]*Repository, error) {
	repos := make([]*Repository, 0)
	keys, _, err := redisRing.Scan(0, "*", 10).Result()
	if err != nil {
		errLogger.Println(err)
		return repos, err
	}

	var obj Object
	for _, key := range keys {
		if len(repos) == 5 {
			return repos, nil
		}
		if err := redisCodec.Get(key, &obj); err == nil {
			if obj.Output {
				repos = append(repos, &Repository{obj.Repo, obj.Tag, obj.Cover})
			}
		}
	}
	return repos, nil
}

// subscribe subscribes to the Redis channel
func subscribe(qname string) {
	pubsub, err := redisClient.Subscribe(qname)
	if err != nil {
		errLogger.Println(err)
		return
	}
	defer pubsub.Close()

	for {
		msg, err := pubsub.ReceiveMessage()
		if err != nil {
			errLogger.Println(err)
		}
		repo, tag := repoTagFromFullName(msg.Payload)
		if ok, _ := repoCoverStatus(repo, tag); !ok {
			cover(repo, tag)
		}
	}
}

func main() {
	n := negroni.Classic()
	r := mux.NewRouter()
	r.HandleFunc("/", Handler)
	r.HandleFunc("/go/{repo:.*}.json", HandlerRepoJSON)
	r.HandleFunc("/go/{repo:.*}.svg", HandlerRepoSVG)
	r.HandleFunc("/go/{repo:.*}", HandlerRepo)
	r.PathPrefix("/assets").Handler(
		http.StripPrefix("/assets", http.FileServer(http.Dir("./assets/"))))
	n.UseHandler(r)

	go subscribe(coverQName)

	n.Run(":3000")
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"time"

	_ "net/http/pprof"

	"github.com/Sirupsen/logrus"
	"github.com/jacksontj/dnms/aggregator"
	"github.com/jacksontj/dnms/mapper"
	"github.com/jacksontj/memberlist"
)

func main() {
	// Some CLI args for better testing

	advertiseStr := flag.String("gossipAddr", "", "address to advertise gossip on")
	peerStr := flag.String("peer", "", "address to gossip with")
	aggNode := flag.Bool("aggregator", false, "are you an aggregator node?")

	flag.Parse()

	// #TODO: load from a config file
	cfg := memberlist.DefaultLANConfig()

	// TODO: load from config
	cfg.BindPort = 33434
	cfg.AdvertisePort = 33434
	if *advertiseStr != "" {
		cfg.AdvertiseAddr = *advertiseStr
	} else {
		i, err := GetLocalIP()
		if err != nil {
			logrus.Fatalf("Err: %v", err)
		}
		cfg.AdvertiseAddr = i
	}
	logrus.Infof("AdvertiseAddr: %v", cfg.AdvertiseAddr)

	// Start the mapper (at this point no peers-- so it will do nothing)
	m := mapper.NewMapper(cfg.AdvertiseAddr)
	m.Start()

	// TODO pass additional config
	// Start HTTP API
	api := NewHTTPApi(m)
	api.Start()

	// If we are an aggregator start that
	var aggMap *aggregator.AggGraphMap
	if *aggNode {
		aggMap = aggregator.NewAggGraphMap()
		api := aggregator.NewHTTPApi(aggMap)
		api.Start()
		// subscribe to ourself
		aggregator.Subscribe(aggMap, "127.0.0.1")
	}

	// Wire up the delegate-- he'll handle pings and node up/down events
	delegate := NewDNMSDelegate(m, aggMap)
	cfg.Delegate = delegate
	cfg.Events = delegate

	// Create the memberlist with the config we just made
	mlist, err := memberlist.Create(cfg)
	delegate.Mlist = mlist
	if err != nil {
		logrus.Fatalf("Unable to create memberlist: %v", err)
	}

	// TODO: background thing to join if we end up alone?
	// Join if we can
	mlist.Join([]string{*peerStr})

	// start the pinger
	p := Pinger{
		M: m,
		Self: mapper.Peer{
			Name: mlist.LocalNode().Addr.String(),
			Port: int(mlist.LocalNode().Port),
		},
	}
	p.Start()

	// print state of the world for ease of debugging
	for {
		time.Sleep(time.Second)
		logrus.Infof("peers=%d nodes=%d links=%d routes=%d",
			mlist.NumMembers()-1,
			m.Graph.GetNodeCount(),
			m.Graph.GetLinkCount(),
			m.Graph.GetRouteCount(),
		)
	}

}
<commit_msg>More TODO markers<commit_after>package main

import (
	"flag"
	"time"

	_ "net/http/pprof"

	"github.com/Sirupsen/logrus"
	"github.com/jacksontj/dnms/aggregator"
	"github.com/jacksontj/dnms/mapper"
	"github.com/jacksontj/memberlist"
)

func main() {
	// Some CLI args for better testing

	advertiseStr := flag.String("gossipAddr", "", "address to advertise gossip on")
	peerStr := flag.String("peer", "", "address to gossip with")
	aggNode := flag.Bool("aggregator", false, "are you an aggregator node?")

	flag.Parse()

	// #TODO: load from a config file
	cfg := memberlist.DefaultLANConfig()

	// TODO: load from config
	cfg.BindPort = 33434
	cfg.AdvertisePort = 33434
	if *advertiseStr != "" {
		cfg.AdvertiseAddr = *advertiseStr
	} else {
		i, err := GetLocalIP()
		if err != nil {
			logrus.Fatalf("Err: %v", err)
		}
		cfg.AdvertiseAddr = i
	}
	logrus.Infof("AdvertiseAddr: %v", cfg.AdvertiseAddr)

	// Start the mapper (at this point no peers-- so it will do nothing)
	m := mapper.NewMapper(cfg.AdvertiseAddr)
	m.Start()

	// TODO pass additional config
	// Start HTTP API
	api := NewHTTPApi(m)
	api.Start()

	// If we are an aggregator start that
	var aggMap *aggregator.AggGraphMap
	if *aggNode {
		aggMap = aggregator.NewAggGraphMap()
		api := aggregator.NewHTTPApi(aggMap)
		api.Start()
		// TODO: through something better than http, it is local after all
		// subscribe to ourself
		aggregator.Subscribe(aggMap, "127.0.0.1")
	}

	// Wire up the delegate-- he'll handle pings and node up/down events
	delegate := NewDNMSDelegate(m, aggMap)
	cfg.Delegate = delegate
	cfg.Events = delegate

	// Create the memberlist with the config we just made
	mlist, err := memberlist.Create(cfg)
	delegate.Mlist = mlist
	if err != nil {
		logrus.Fatalf("Unable to create memberlist: %v", err)
	}

	// TODO: background thing to join if we end up alone?
	// Join if we can
	mlist.Join([]string{*peerStr})

	// start the pinger
	p := Pinger{
		M: m,
		Self: mapper.Peer{
			Name: mlist.LocalNode().Addr.String(),
			Port: int(mlist.LocalNode().Port),
		},
	}
	p.Start()

	// print state of the world for ease of debugging
	for {
		time.Sleep(time.Second)
		logrus.Infof("peers=%d nodes=%d links=%d routes=%d",
			mlist.NumMembers()-1,
			m.Graph.GetNodeCount(),
			m.Graph.GetLinkCount(),
			m.Graph.GetRouteCount(),
		)
	}

}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/cenkalti/remux"
)

const maxContentLength = 256 * 1024

var transport = &http.Transport{
	DisableCompression: true,
}

var client = &http.Client{
	Transport: transport,
}

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	var r remux.Remux
	r.HandleFunc("/md5/(?P<target>.+)", handleMD5).Get()
	http.ListenAndServe(":"+port, r)
}

func handleMD5(w http.ResponseWriter, r *http.Request) {
	target := r.FormValue(":target")
	log.Println(target)
	resp, err := client.Get(target)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	if resp.StatusCode >= 400 {
		http.Error(w, "bad status code: "+strconv.Itoa(resp.StatusCode), http.StatusBadGateway)
		return
	}
	if resp.ContentLength == -1 {
		http.Error(w, "no content length", http.StatusBadGateway)
		return
	}
	h := md5.New()
	_, err = io.Copy(h, resp.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	fmt.Fprintf(w, "%x", h.Sum(nil))
}
<commit_msg>add secret<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strconv"

	"github.com/cenkalti/remux"
)

const maxContentLength = 256 * 1024

var transport = &http.Transport{
	DisableCompression: true,
}

var client = &http.Client{
	Transport: transport,
}

var secret string

func main() {
	port := os.Getenv("PORT")
	if port == "" {
		log.Fatal("$PORT must be set")
	}
	secret = os.Getenv("SECRET")
	if secret == "" {
		log.Fatal("$SECRET must be set")
	}
	var r remux.Remux
	r.HandleFunc("/(?P<secret>.+)/md5/(?P<target>.+)", handleMD5).Get()
	http.ListenAndServe(":"+port, r)
}

func handleMD5(w http.ResponseWriter, r *http.Request) {
	if r.FormValue(":secret") != secret {
		http.Error(w, "invalid secret", http.StatusUnauthorized)
		return
	}
	target := r.FormValue(":target")
	log.Println(target)
	resp, err := client.Get(target)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	if resp.StatusCode >= 400 {
		http.Error(w, "bad status code: "+strconv.Itoa(resp.StatusCode), http.StatusBadGateway)
		return
	}
	if resp.ContentLength == -1 {
		http.Error(w, "no content length", http.StatusBadGateway)
		return
	}
	h := md5.New()
	_, err = io.Copy(h, resp.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	fmt.Fprintf(w, "%x", h.Sum(nil))
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"

	"github.com/jessevdk/go-flags"
	"github.com/yuya-takeyama/argf"
)

func usage() {
	os.Stderr.WriteString(`
Usage: rl [OPTION]... [FILE]...
Reverse lines of FILE(s), or standard input.

Options:
  -d, --delimiter=DELIM    delimit line by DELIM
      --help               display this help text and exit
      --version            output version information and exit
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.1.0
`[1:])
}

type Option struct {
	Delimiter string `short:"d" long:"delimiter"`
	isHelp    bool   `          long:"help"`
	isVersion bool   `          long:"version"`
	Files     []string
}

func printErr(err error) {
	fmt.Fprintln(os.Stderr, "rl:", err)
}

func guideToHelp() {
	os.Stderr.WriteString(`
Try 'rl --help' for more information.
`[1:])
}

func do(rev *Reverser, r io.Reader) error {
	b := bufio.NewScanner(r)
	for b.Scan() {
		fmt.Println(rev.Reverse(b.Text()))
	}
	return b.Err()
}

func _main() int {
	r, err := argf.From(os.Args[1:])
	if err != nil {
		printErr(err)
		return 2
	}

	rev := NewReverser()
	if err = do(rev, r); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<commit_msg>Implement parseOption<commit_after>package main

import (
	"bufio"
	"fmt"
	"io"
	"os"

	"github.com/jessevdk/go-flags"
	"github.com/yuya-takeyama/argf"
)

func usage() {
	os.Stderr.WriteString(`
Usage: rl [OPTION]... [FILE]...
Reverse lines of FILE(s), or standard input.

Options:
  -d, --delimiter=DELIM    delimit line by DELIM
      --help               display this help text and exit
      --version            output version information and exit
`[1:])
}

func version() {
	os.Stderr.WriteString(`
0.1.0
`[1:])
}

type Option struct {
	Delimiter string `short:"d" long:"delimiter"`
	isHelp    bool   `          long:"help"`
	isVersion bool   `          long:"version"`
	Files     []string
}

func parseOption(args []string) (opt *Option, err error) {
	opt = &Option{}
	flag := flags.NewParser(opt, flags.PassDoubleDash)

	opt.Files, err = flag.ParseArgs(args)
	if err != nil {
		return nil, err
	}
	return opt, nil
}

func printErr(err error) {
	fmt.Fprintln(os.Stderr, "rl:", err)
}

func guideToHelp() {
	os.Stderr.WriteString(`
Try 'rl --help' for more information.
`[1:])
}

func do(rev *Reverser, r io.Reader) error {
	b := bufio.NewScanner(r)
	for b.Scan() {
		fmt.Println(rev.Reverse(b.Text()))
	}
	return b.Err()
}

func _main() int {
	r, err := argf.From(os.Args[1:])
	if err != nil {
		printErr(err)
		return 2
	}

	rev := NewReverser()
	if err = do(rev, r); err != nil {
		printErr(err)
		return 1
	}
	return 0
}

func main() {
	e := _main()
	os.Exit(e)
}
<|endoftext|>


<commit_before>package main

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <stdio.h>
// #include <stdlib.h>
// #include <rados/librados.h>
// #include <radosstriper/libradosstriper.h>
import "C"
import "unsafe"

import (
	"errors"
	"fmt"
	"io"
	"os"
)

type RadosStripedObject struct {
	objectName  string
	striper     C.rados_striper_t
	ioctx       C.rados_ioctx_t
	read_offset int64
}

func (rso *RadosStripedObject) WriteAt(p []byte, off int64) (n int, err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))
	c_offset := C.uint64_t(off)
	c_data := (*C.char)(unsafe.Pointer(&p[0]))
	c_size := C.size_t(len(p))
	ret := C.rados_striper_write(rso.striper, obj, c_data, c_size, c_offset)
	if ret < 0 {
		return int(ret), errors.New("Unable to write")
	} else {
		return len(p), nil
	}
}

func (rso RadosStripedObject) Write(p []byte) (n int, err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))

	c_data := (*C.char)(unsafe.Pointer(&p[0]))
	c_size := C.size_t(len(p))

	ret := C.rados_striper_append(rso.striper, obj, c_data, c_size)
	if ret < 0 {
		return int(ret), errors.New("Unable to write")
	} else {
		return len(p), nil
	}
}

func (rso RadosStripedObject) Read(p []byte) (n int, err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))

	c_size := C.size_t(len(p))
	ret := C.rados_striper_read(rso.striper, obj,
		(*C.char)(unsafe.Pointer(&p[0])), C.size_t(c_size),
		C.uint64_t(rso.read_offset))
	if ret < 0 {
		return int(ret), errors.New("Unable to write")
	} else {
		rso.read_offset = rso.read_offset + int64(len(p))
		fmt.Println("updated read_offset", rso.read_offset, len(p))

		return len(p), nil
	}
}

func main() {
	var cluster C.rados_t
	conf := C.CString("/etc/ceph/ceph.conf")
	pool := C.CString("test")
	defer C.free(unsafe.Pointer(conf))
	defer C.free(unsafe.Pointer(pool))

	err := C.rados_create(&cluster, nil)
	if err < 0 {
		fmt.Println("create failed")
	}

	err1 := C.rados_conf_read_file(cluster, conf)
	if err1 < 0 {
		fmt.Println("conf failed")
	}

	err2 := C.rados_connect(cluster)
	if err2 < 0 {
		fmt.Println("connect failed")
	}
	defer C.rados_shutdown(cluster)

	obj := RadosStripedObject{}
	err = C.rados_ioctx_create(cluster, pool, &obj.ioctx)
	if err < 0 {
		fmt.Println("create ioctx failed")
	}
	defer C.rados_ioctx_destroy(obj.ioctx)

	ret := C.rados_striper_create(obj.ioctx, &obj.striper)
	if ret < 0 {
		fmt.Println("create striper failed")
	}
	defer C.rados_striper_destroy(obj.striper)

	f, e := os.Open("/home/vagrant/input.txt")
	if e != nil {
		panic(e)
	}
	obj.objectName = "obj"
	io.Copy(obj, f)

	out, e := os.Create("/home/vagrant/output.txt")
	if e != nil {
		panic(e)
	}

	// TODO Read is not working
	io.Copy(out, obj)

}
<commit_msg>fix Read<commit_after>package main

// #cgo LDFLAGS: -lrados -lradosstriper
// #include <stdio.h>
// #include <stdlib.h>
// #include <rados/librados.h>
// #include <radosstriper/libradosstriper.h>
import "C"
import "unsafe"

import (
	"errors"
	"fmt"
	"io"
	"os"
)

type RadosStripedObject struct {
	objectName   string
	striper      C.rados_striper_t
	ioctx        C.rados_ioctx_t
	read_offset  int64
	write_offset int64
}

// Synchronously removes a striped object
func (rso *RadosStripedObject) Remove() (err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))
	ret, err := C.rados_striper_remove(rso.striper, obj)
	if ret < 0 {
		return err
	} else {
		return nil
	}
}

// Resize an object
// TODO: doesn't work! call to rados_striper_trunc fails
func (rso *RadosStripedObject) Truncate(size int64) (err error) {

	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))
	c_size := C.uint64_t(size)
	ret, err := C.rados_striper_trunc(rso.ioctx, obj, c_size)
	if ret < 0 {
		return err
	} else {
		return nil
	}
	return
}

// Write data to a striped object at the specified offset
// Implements the WriterAt interface
func (rso *RadosStripedObject) WriteAt(p []byte, off int64) (n int, err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))
	c_offset := C.uint64_t(off)
	c_data := (*C.char)(unsafe.Pointer(&p[0]))
	c_size := C.size_t(len(p))
	ret := C.rados_striper_write(rso.striper, obj, c_data, c_size, c_offset)
	if ret < 0 {
		return int(ret), errors.New("Unable to write")
	} else {
		return len(p), nil
	}
}

// Write data to a striped object
// Implements the Writer interface
func (rso *RadosStripedObject) Write(p []byte) (n int, err error) {
	written, err := rso.WriteAt(p, rso.write_offset)
	if err != nil {
		return -1, err
	}
	rso.write_offset = rso.write_offset + int64(written)
	return written, nil
}

// Read data from a striped object
func (rso *RadosStripedObject) Read(p []byte) (n int, err error) {
	obj := C.CString(rso.objectName)
	defer C.free(unsafe.Pointer(obj))

	ret, err := C.rados_striper_read(rso.striper, obj,
		(*C.char)(unsafe.Pointer(&p[0])), C.size_t(len(p)),
		C.uint64_t(rso.read_offset))
	if ret < 0 {
		return int(ret), err
	} else {
		// update offset value for next read
		rso.read_offset = rso.read_offset + int64(ret)

		// if actual read was less than buffer size than reached end of object
		if int(ret) < len(p) {
			err = io.EOF
		} else {
			err = nil
		}
		return int(ret), err
	}
}

// test
func main() {
	var cluster C.rados_t
	conf := C.CString("/etc/ceph/ceph.conf")
	pool := C.CString("test")
	defer C.free(unsafe.Pointer(conf))
	defer C.free(unsafe.Pointer(pool))

	err := C.rados_create(&cluster, nil)
	if err < 0 {
		fmt.Println("create failed")
	}

	err1 := C.rados_conf_read_file(cluster, conf)
	if err1 < 0 {
		fmt.Println("conf failed")
	}

	err2 := C.rados_connect(cluster)
	if err2 < 0 {
		fmt.Println("connect failed")
	}
	defer C.rados_shutdown(cluster)

	obj := &RadosStripedObject{}
	obj.objectName = "obj"

	err = C.rados_ioctx_create(cluster, pool, &obj.ioctx)
	if err < 0 {
		fmt.Println("create ioctx failed")
	}
	defer C.rados_ioctx_destroy(obj.ioctx)

	ret := C.rados_striper_create(obj.ioctx, &obj.striper)
	if ret < 0 {
		fmt.Println("create striper failed")
	}
	defer C.rados_striper_destroy(obj.striper)

	f, e := os.Open("/home/vagrant/input.txt")
	if e != nil {
		panic(e)
	}

	// clean up any existing object with same name
	// TODO: ideally would use truncate here
	e = obj.Remove()
	if e != nil {
		panic(e)
	}

	// write to librados object
	io.Copy(obj, f)

	out, e := os.Create("/home/vagrant/output.txt")
	if e != nil {
		panic(e)
	}

	// read from librados object
	io.Copy(out, obj)

}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/config"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/sourcefetcher"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

var resourceTypes = flag.String(
	"resourceTypes",
	`{"git":"winston/git-resource"}`,
	"map of resource type to its docker image",
)

func main() {
	flag.Parse()

	logger := log.New(os.Stdout, "", 0)

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	resourceTypesMap := map[string]string{}
	err := json.Unmarshal([]byte(*resourceTypes), &resourceTypesMap)
	if err != nil {
		log.Fatalln("failed to parse resource types:", err)
	}

	var resourceTypesConfig config.ResourceTypes
	for typ, image := range resourceTypesMap {
		resourceTypesConfig = append(resourceTypesConfig, config.ResourceType{
			Name:  typ,
			Image: image,
		})
	}

	sourceFetcher := sourcefetcher.NewSourceFetcher(resourceTypesConfig, wardenClient)

	builder := builder.NewBuilder(sourceFetcher, wardenClient)

	handler, err := api.New(scheduler.NewScheduler(builder))
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	err = http.ListenAndServe(*listenAddr, handler)
	logger.Fatalln("listen error:", err)
}
<commit_msg>construct checker in main and pass it in to api<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"

	WardenClient "github.com/cloudfoundry-incubator/garden/client"
	WardenConnection "github.com/cloudfoundry-incubator/garden/client/connection"

	"github.com/winston-ci/prole/api"
	"github.com/winston-ci/prole/builder"
	"github.com/winston-ci/prole/checker"
	"github.com/winston-ci/prole/config"
	"github.com/winston-ci/prole/scheduler"
	"github.com/winston-ci/prole/sourcefetcher"
)

var listenAddr = flag.String(
	"listenAddr",
	"0.0.0.0:4637",
	"listening address",
)

var wardenNetwork = flag.String(
	"wardenNetwork",
	"unix",
	"warden API connection network (unix or tcp)",
)

var wardenAddr = flag.String(
	"wardenAddr",
	"/tmp/warden.sock",
	"warden API connection address",
)

var resourceTypes = flag.String(
	"resourceTypes",
	`{"git":"winston/git-resource"}`,
	"map of resource type to its docker image",
)

func main() {
	flag.Parse()

	logger := log.New(os.Stdout, "", 0)

	wardenClient := WardenClient.New(&WardenConnection.Info{
		Network: *wardenNetwork,
		Addr:    *wardenAddr,
	})

	resourceTypesMap := map[string]string{}
	err := json.Unmarshal([]byte(*resourceTypes), &resourceTypesMap)
	if err != nil {
		log.Fatalln("failed to parse resource types:", err)
	}

	var resourceTypesConfig config.ResourceTypes
	for typ, image := range resourceTypesMap {
		resourceTypesConfig = append(resourceTypesConfig, config.ResourceType{
			Name:  typ,
			Image: image,
		})
	}

	sourceFetcher := sourcefetcher.NewSourceFetcher(resourceTypesConfig, wardenClient)
	checker := checker.NewChecker(resourceTypesConfig, wardenClient)

	builder := builder.NewBuilder(sourceFetcher, wardenClient)

	handler, err := api.New(scheduler.NewScheduler(builder), checker)
	if err != nil {
		log.Fatalln("failed to initialize handler:", err)
	}

	err = http.ListenAndServe(*listenAddr, handler)
	logger.Fatalln("listen error:", err)
}
<|endoftext|>