<commit_before>package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/imdario/mergo"
	"github.com/sethvargo/go-fastly"
)

var pendingVersions map[string]fastly.Version
var siteConfigs map[string]SiteConfig

type SiteConfig struct {
	Backends    []*fastly.Backend
	SSLHostname string
}

func readConfig() error {
	//	var parsed interface{}
	//	f, _ := os.Open("config.json")
	//	dec := json.NewDecoder(f)
	//	if err := dec.Decode(&parsed); err != nil {
	//		log.Fatal(err)
	//	}
	//	fmt.Println(parsed)

	body, _ := ioutil.ReadFile("config.json")
	err := json.Unmarshal(body, &siteConfigs)
	if err != nil {
		log.Fatal(err)
	}

	for name, config := range siteConfigs {
		if name == "_default_" {
			continue
		}

		if err := mergo.Merge(&config, siteConfigs["_default_"]); err != nil {
			return err
		}
		siteConfigs[name] = config
		for _, backend := range config.Backends {
			backend.SSLHostname = strings.Replace(backend.SSLHostname, "_servicename_", name, -1)
		}

	}
	return nil
}

func prepareNewVersion(client *fastly.Client, s *fastly.Service) (fastly.Version, error) {
	if version, ok := pendingVersions[s.ID]; ok {
		return version, nil
	}

	// Otherwise, create a new version
	newversion, err := client.CloneVersion(&fastly.CloneVersionInput{Service: s.ID, Version: strconv.Itoa(int(s.ActiveVersion))})
	if err != nil {
		return *newversion, err
	}
	pendingVersions[s.ID] = *newversion
	return *newversion, nil
}

func syncVcls(client *fastly.Client, s *fastly.Service) error {
	hasher := sha256.New()
	var activeVersion = strconv.Itoa(int(s.ActiveVersion))
	vcls, err := client.ListVCLs(&fastly.ListVCLsInput{Service: s.ID, Version: activeVersion})
	if err != nil {
		return err
	}

	for _, v := range vcls {
		filename := v.Name + ".vcl"
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		if _, err := io.Copy(hasher, f); err != nil {
			return err
		}
		localsum := hasher.Sum(nil)
		hasher.Reset()

		hasher.Write([]byte(v.Content))
		remotesum := hasher.Sum(nil)
		hasher.Reset()

		if !bytes.Equal(localsum, remotesum) {
			fmt.Printf("VCL mismatch on service %s VCL %s. Updating.\n", s.Name, v.Name)
			content, err := ioutil.ReadFile(filename)
			if err != nil {
				return err
			}

			//newversion, err := client.CloneVersion(&fastly.CloneVersionInput{Service: s.ID, Version: activeVersion})
			newversion, err := prepareNewVersion(client, s)
			if err != nil {
				return err
			}
			if _, err = client.UpdateVCL(&fastly.UpdateVCLInput{Name: v.Name, Service: s.ID, Version: newversion.Number, Content: string(content)}); err != nil {
				return err
			}
		}

	}
	return nil
}

func syncBackends(client *fastly.Client, s *fastly.Service, currentBackends []*fastly.Backend, newBackends []*fastly.Backend) error {
	newversion, err := prepareNewVersion(client, s)
	if err != nil {
		return err
	}

	for _, backend := range currentBackends {
		err := client.DeleteBackend(&fastly.DeleteBackendInput{Service: s.ID, Name: backend.Name, Version: newversion.Number})
		if err != nil {
			return err
		}
	}
	for _, backend := range newBackends {
		var i fastly.CreateBackendInput
		i.Address = backend.Address
		i.Name = backend.Name
		i.Service = newversion.ServiceID
		i.Version = newversion.Number
		i.UseSSL = backend.UseSSL
		i.SSLCheckCert = backend.SSLCheckCert
		i.SSLSNIHostname = backend.SSLSNIHostname
		i.SSLHostname = backend.SSLHostname
		i.AutoLoadbalance = backend.AutoLoadbalance
		i.Weight = backend.Weight
		i.MaxConn = backend.MaxConn
		i.ConnectTimeout = backend.ConnectTimeout
		i.FirstByteTimeout = backend.FirstByteTimeout
		i.BetweenBytesTimeout = backend.BetweenBytesTimeout
		i.HealthCheck = backend.HealthCheck
		i.RequestCondition = backend.RequestCondition
		if _, err = client.CreateBackend(&i); err != nil {
			return err
		}
	}

	return nil
}

func syncConfig(client *fastly.Client, s *fastly.Service) error {
	var activeVersion = strconv.Itoa(int(s.ActiveVersion))
	var config SiteConfig
	if _, ok := siteConfigs[s.Name]; ok {
		config = siteConfigs[s.Name]
	} else {
		config = siteConfigs["_default_"]
	}
	remoteBackends, _ := client.ListBackends(&fastly.ListBackendsInput{Service: s.ID, Version: activeVersion})
	if !reflect.DeepEqual(config.Backends, remoteBackends) {
		if err := syncBackends(client, s, remoteBackends, config.Backends); err != nil {
			return err
		}
	}

	return nil

}

func main() {
	client, err := fastly.NewClient(os.Getenv("FASTLY_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	if err := readConfig(); err != nil {
		log.Fatal(err)
	}
	pendingVersions = make(map[string]fastly.Version)

	services, err := client.ListServices(&fastly.ListServicesInput{})
	for _, s := range services {
		if err = syncVcls(client, s); err != nil {
			log.Fatal(err)
		}
		if err = syncConfig(client, s); err != nil {
			log.Fatal(err)
		}
	}
}
<commit_msg>Sync conditions.<commit_after>package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"reflect"
	"strconv"
	"strings"

	"github.com/imdario/mergo"
	"github.com/sethvargo/go-fastly"
)

var pendingVersions map[string]fastly.Version
var siteConfigs map[string]SiteConfig

type SiteConfig struct {
	Backends    []*fastly.Backend
	Conditions  []*fastly.Condition
	SSLHostname string
}

func readConfig() error {
	//	var parsed interface{}
	//	f, _ := os.Open("config.json")
	//	dec := json.NewDecoder(f)
	//	if err := dec.Decode(&parsed); err != nil {
	//		log.Fatal(err)
	//	}
	//	fmt.Println(parsed)

	body, _ := ioutil.ReadFile("config.json")
	err := json.Unmarshal(body, &siteConfigs)
	if err != nil {
		log.Fatal(err)
	}

	for name, config := range siteConfigs {
		if name == "_default_" {
			continue
		}

		if err := mergo.Merge(&config, siteConfigs["_default_"]); err != nil {
			return err
		}
		siteConfigs[name] = config
		for _, backend := range config.Backends {
			backend.SSLHostname = strings.Replace(backend.SSLHostname, "_servicename_", name, -1)
		}

	}
	return nil
}

func prepareNewVersion(client *fastly.Client, s *fastly.Service) (fastly.Version, error) {
	if version, ok := pendingVersions[s.ID]; ok {
		return version, nil
	}

	// Otherwise, create a new version
	newversion, err := client.CloneVersion(&fastly.CloneVersionInput{Service: s.ID, Version: strconv.Itoa(int(s.ActiveVersion))})
	if err != nil {
		return *newversion, err
	}
	pendingVersions[s.ID] = *newversion
	return *newversion, nil
}

func syncVcls(client *fastly.Client, s *fastly.Service) error {
	hasher := sha256.New()
	var activeVersion = strconv.Itoa(int(s.ActiveVersion))
	vcls, err := client.ListVCLs(&fastly.ListVCLsInput{Service: s.ID, Version: activeVersion})
	if err != nil {
		return err
	}

	for _, v := range vcls {
		filename := v.Name + ".vcl"
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		if _, err := io.Copy(hasher, f); err != nil {
			return err
		}
		localsum := hasher.Sum(nil)
		hasher.Reset()

		hasher.Write([]byte(v.Content))
		remotesum := hasher.Sum(nil)
		hasher.Reset()

		if !bytes.Equal(localsum, remotesum) {
			fmt.Printf("VCL mismatch on service %s VCL %s. Updating.\n", s.Name, v.Name)
			content, err := ioutil.ReadFile(filename)
			if err != nil {
				return err
			}

			//newversion, err := client.CloneVersion(&fastly.CloneVersionInput{Service: s.ID, Version: activeVersion})
			newversion, err := prepareNewVersion(client, s)
			if err != nil {
				return err
			}
			if _, err = client.UpdateVCL(&fastly.UpdateVCLInput{Name: v.Name, Service: s.ID, Version: newversion.Number, Content: string(content)}); err != nil {
				return err
			}
		}

	}
	return nil
}

func syncConditions(client *fastly.Client, s *fastly.Service, currentConditions []*fastly.Condition, newConditions []*fastly.Condition) error {
	newversion, err := prepareNewVersion(client, s)
	if err != nil {
		return err
	}

	for _, condition := range currentConditions {
		err := client.DeleteCondition(&fastly.DeleteConditionInput{Service: s.ID, Name: condition.Name, Version: newversion.Number})
		if err != nil {
			return err
		}
	}
	for _, condition := range newConditions {
		var i fastly.CreateConditionInput
		i.Name = condition.Name
		i.Type = condition.Type
		i.Service = s.ID
		i.Version = newversion.Number
		i.Priority = condition.Priority
		i.Statement = condition.Statement
		if _, err = client.CreateCondition(&i); err != nil {
			return err
		}

	}
	return nil
}

func syncBackends(client *fastly.Client, s *fastly.Service, currentBackends []*fastly.Backend, newBackends []*fastly.Backend) error {
	newversion, err := prepareNewVersion(client, s)
	if err != nil {
		return err
	}

	for _, backend := range currentBackends {
		err := client.DeleteBackend(&fastly.DeleteBackendInput{Service: s.ID, Name: backend.Name, Version: newversion.Number})
		if err != nil {
			return err
		}
	}
	for _, backend := range newBackends {
		var i fastly.CreateBackendInput
		i.Address = backend.Address
		i.Name = backend.Name
		i.Service = newversion.ServiceID
		i.Version = newversion.Number
		i.UseSSL = backend.UseSSL
		i.SSLCheckCert = backend.SSLCheckCert
		i.SSLSNIHostname = backend.SSLSNIHostname
		i.SSLHostname = backend.SSLHostname
		i.AutoLoadbalance = backend.AutoLoadbalance
		i.Weight = backend.Weight
		i.MaxConn = backend.MaxConn
		i.ConnectTimeout = backend.ConnectTimeout
		i.FirstByteTimeout = backend.FirstByteTimeout
		i.BetweenBytesTimeout = backend.BetweenBytesTimeout
		i.HealthCheck = backend.HealthCheck
		i.RequestCondition = backend.RequestCondition
		if _, err = client.CreateBackend(&i); err != nil {
			return err
		}
	}

	return nil
}

func syncConfig(client *fastly.Client, s *fastly.Service) error {
	var activeVersion = strconv.Itoa(int(s.ActiveVersion))
	var config SiteConfig
	if _, ok := siteConfigs[s.Name]; ok {
		config = siteConfigs[s.Name]
	} else {
		config = siteConfigs["_default_"]
	}

	remoteConditions, err := client.ListConditions(&fastly.ListConditionsInput{Service: s.ID, Version: activeVersion})
	if err != nil {
		return err
	}
	// Conditions must be sync'd first, as if they're referenced in any other setup
	// the API will reject if they don't exist.
	if !reflect.DeepEqual(config.Conditions, remoteConditions) {
		if err := syncConditions(client, s, remoteConditions, config.Conditions); err != nil {
			return err
		}
	}
	remoteBackends, _ := client.ListBackends(&fastly.ListBackendsInput{Service: s.ID, Version: activeVersion})
	if !reflect.DeepEqual(config.Backends, remoteBackends) {
		if err := syncBackends(client, s, remoteBackends, config.Backends); err != nil {
			return err
		}
	}

	return nil

}

func main() {
	client, err := fastly.NewClient(os.Getenv("FASTLY_KEY"))
	if err != nil {
		log.Fatal(err)
	}

	if err := readConfig(); err != nil {
		log.Fatal(err)
	}
	pendingVersions = make(map[string]fastly.Version)

	services, err := client.ListServices(&fastly.ListServicesInput{})
	for _, s := range services {
		if err = syncVcls(client, s); err != nil {
			log.Fatal(err)
		}
		if err = syncConfig(client, s); err != nil {
			log.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/fatih/color"
	"github.com/fsouza/go-dockerclient"
	"github.com/peterh/liner"
)

const (
	defaultPrompt = "sysrepl"
	defaultImage  = "ubuntu:trusty"
)

func help() {
	usage := `sysrepl - help
:help	show help
:from	set base image
:run	execute shell command
:quit	quit sysrepl - <ctrl-d>
`
	fmt.Println(usage)
}

func printResults(res EvalResult) {
	fmt.Println()
	fmt.Println("Exit:", res.Code)
	fmt.Println("Took:", res.Duration)
	fmt.Println("From:", res.Image)
	if res.Code == 0 {
		fmt.Println("Committed:", res.NewImage[:12])
	}
	printChanges(res.Changes)
}

func printChanges(changes []docker.Change) {
	fmt.Println("Changes:")
	if len(changes) == 0 {
		fmt.Println("<none>")
	}
	prunedChanges := pruneChanges(changes)
	for _, change := range prunedChanges {
		if change.Path == "/work" {
			continue
		}
		switch change.Kind {
		case 0:
			color.Yellow("~ %s", change.Path)
		case 1:
			color.Green("+ %s", change.Path)
		case 2:
			color.Red("- %s", change.Path)
		}
	}
}

func pruneChanges(changes []docker.Change) []docker.Change {
	var c = []docker.Change{}
	var p string = ""
	for i := len(changes)-1; i > 0; i -= 1 {
		if changes[i].Kind == 0 {
			if !strings.Contains(p, changes[i].Path) {
				c = append(c, changes[i])
			}
		} else {
			c = append(c, changes[i])
		}
		p = changes[i].Path
	}
	// reverse the slice results
	for i := len(c)/2-1; i >= 0; i-- {
		opp := len(c)-1-i
		c[i], c[opp] = c[opp], c[i]
	}
	return c
}

func main() {
	dc, err := NewDockerClient(os.Getenv("DOCKER_HOST"), os.Getenv("DOCKER_TLS_VERIFY"), os.Getenv("DOCKER_CERT_PATH"))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	} else {
		fmt.Println("Connected to docker daemon...")
	}

	ws := NewWorkspace(dc, "bash", defaultImage)

	line := liner.NewLiner()
	defer line.Close()

	prompt := defaultPrompt

	if f, err := os.Open("/tmp/.sysrepl_history"); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

mainloop:
	for {
		if input, err := line.Prompt(prompt + "> "); err != nil {
			if err == io.EOF {
				fmt.Println() //Returns user to prompt on a new line
				break
			}
		} else {
			switch input {
			case ":help":
				help()
			case ":quit":
				fmt.Println("Exiting...")
				break mainloop
			default:
				if strings.HasPrefix(input, ":run") {
					cmd := strings.TrimPrefix(input, ":run ")
					line.AppendHistory(input)
					if res, err := ws.Eval(cmd); err != nil {
						fmt.Println(err)
					} else {
						printResults(res)
					}
				} else if strings.HasPrefix(input, ":from") {
					line.AppendHistory(input)
					image := strings.TrimPrefix(input, ":from ")
					ws.SetImage(image)
					fmt.Println("Image: ", image)
				} else if strings.HasPrefix(input, ":print") {
					line.AppendHistory(input)
					if out, err := ws.Sprint(); err == nil {
						for _, line := range out {
							fmt.Println(line)
						}
					}
				} else if input == "" {
					continue
				} else {
					fmt.Println(input)
					line.AppendHistory(input)
				}
			}
		}

		if f, err := os.Create("/tmp/.sysrepl_history"); err != nil {
			fmt.Println("error writing history", err)
		} else {
			line.WriteHistory(f)
			f.Close()
		}
	}
}
<commit_msg>Removing verbose empty string assignment of variable in pruneChanges<commit_after>package main

import (
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/fatih/color"
	"github.com/fsouza/go-dockerclient"
	"github.com/peterh/liner"
)

const (
	defaultPrompt = "sysrepl"
	defaultImage  = "ubuntu:trusty"
)

func help() {
	usage := `sysrepl - help
:help	show help
:from	set base image
:run	execute shell command
:quit	quit sysrepl - <ctrl-d>
`
	fmt.Println(usage)
}

func printResults(res EvalResult) {
	fmt.Println()
	fmt.Println("Exit:", res.Code)
	fmt.Println("Took:", res.Duration)
	fmt.Println("From:", res.Image)
	if res.Code == 0 {
		fmt.Println("Committed:", res.NewImage[:12])
	}
	printChanges(res.Changes)
}

func printChanges(changes []docker.Change) {
	fmt.Println("Changes:")
	if len(changes) == 0 {
		fmt.Println("<none>")
	}
	prunedChanges := pruneChanges(changes)
	for _, change := range prunedChanges {
		if change.Path == "/work" {
			continue
		}
		switch change.Kind {
		case 0:
			color.Yellow("~ %s", change.Path)
		case 1:
			color.Green("+ %s", change.Path)
		case 2:
			color.Red("- %s", change.Path)
		}
	}
}

func pruneChanges(changes []docker.Change) []docker.Change {
	var c = []docker.Change{}
	var p string
	for i := len(changes)-1; i > 0; i -= 1 {
		if changes[i].Kind == 0 {
			if !strings.Contains(p, changes[i].Path) {
				c = append(c, changes[i])
			}
		} else {
			c = append(c, changes[i])
		}
		p = changes[i].Path
	}
	// reverse the slice results
	for i := len(c)/2-1; i >= 0; i-- {
		opp := len(c)-1-i
		c[i], c[opp] = c[opp], c[i]
	}
	return c
}

func main() {
	dc, err := NewDockerClient(os.Getenv("DOCKER_HOST"), os.Getenv("DOCKER_TLS_VERIFY"), os.Getenv("DOCKER_CERT_PATH"))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	} else {
		fmt.Println("Connected to docker daemon...")
	}

	ws := NewWorkspace(dc, "bash", defaultImage)

	line := liner.NewLiner()
	defer line.Close()

	prompt := defaultPrompt

	if f, err := os.Open("/tmp/.sysrepl_history"); err == nil {
		line.ReadHistory(f)
		f.Close()
	}

mainloop:
	for {
		if input, err := line.Prompt(prompt + "> "); err != nil {
			if err == io.EOF {
				fmt.Println() //Returns user to prompt on a new line
				break
			}
		} else {
			switch input {
			case ":help":
				help()
			case ":quit":
				fmt.Println("Exiting...")
				break mainloop
			default:
				if strings.HasPrefix(input, ":run") {
					cmd := strings.TrimPrefix(input, ":run ")
					line.AppendHistory(input)
					if res, err := ws.Eval(cmd); err != nil {
						fmt.Println(err)
					} else {
						printResults(res)
					}
				} else if strings.HasPrefix(input, ":from") {
					line.AppendHistory(input)
					image := strings.TrimPrefix(input, ":from ")
					ws.SetImage(image)
					fmt.Println("Image: ", image)
				} else if strings.HasPrefix(input, ":print") {
					line.AppendHistory(input)
					if out, err := ws.Sprint(); err == nil {
						for _, line := range out {
							fmt.Println(line)
						}
					}
				} else if input == "" {
					continue
				} else {
					fmt.Println(input)
					line.AppendHistory(input)
				}
			}
		}

		if f, err := os.Create("/tmp/.sysrepl_history"); err != nil {
			fmt.Println("error writing history", err)
		} else {
			line.WriteHistory(f)
			f.Close()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/ahaynssen/slack-go-webhook"
	"github.com/objectpartners/rancher-service-updater/utils"
	"github.com/rancher/go-rancher/client"
)

type (
	//Config is the service configuration
	Config struct {
		EnableLabel      string
		EnvironmentNames []string
		Port             int
		CattleSecretKey  string
		CattleAccessKey  string
		CattleURL        string
		SlackWebhookURL  string
		SlackBotName     string
		Debug            bool
	}

	//ServiceUpdater is the service
	ServiceUpdater struct {
		Config *Config
		// client  *client.RancherClient
		service Service
		account Account
	}

	//UpdateCommand is payload for new image availability
	UpdateCommand struct {
		Image      string `json:"docker_image"`
		StartFirst bool   `json:"start_first"`
		Confirm    bool   `json:"confirm"`
		Timeout    int    `json:"timeout"`
	}

	//Service is Rancher Service interface
	Service interface {
		ById(id string) (*client.Service, error)
		List(opts *client.ListOpts) (*client.ServiceCollection, error)
		ActionFinishupgrade(*client.Service) (*client.Service, error)
		ActionUpgrade(*client.Service, *client.ServiceUpgrade) (*client.Service, error)
	}

	//Account is Rancher Environment interface
	Account interface {
		List(opts *client.ListOpts) (*client.AccountCollection, error)
	}
)

func main() {
	config := &Config{
		EnableLabel:      utils.GetEnvOrDefault("AUTOUPDATE_ENABLE_LABEL", "autoupdate.enable"),
		EnvironmentNames: utils.GetEnvOrDefaultArray("AUTOUPDATE_ENVIRONMENT_NAMES", []string{".*"}),
		Port:             utils.GetEnvOrDefaultInt("AUTOUPDATE_HTTP_PORT", 8080),
		CattleAccessKey:  os.Getenv("CATTLE_ACCESS_KEY"),
		CattleSecretKey:  os.Getenv("CATTLE_SECRET_KEY"),
		CattleURL:        os.Getenv("CATTLE_URL"),
		SlackWebhookURL:  os.Getenv("AUTOUPDATE_SLACK_WEBHOOK_URL"),
		SlackBotName:     utils.GetEnvOrDefault("AUTOUPDATE_SLACK_BOT_NAME", "rancher-service-updater"),
		Debug:            os.Getenv("DEBUG") != "",
	}
	serviceUpdater := &ServiceUpdater{
		Config: config,
	}
	serviceUpdater.init()
	serviceUpdater.listen()
}

func (s *ServiceUpdater) init() {
	c, err := client.NewRancherClient(&client.ClientOpts{
		AccessKey: s.Config.CattleAccessKey,
		SecretKey: s.Config.CattleSecretKey,
		Url:       s.Config.CattleURL,
	})
	if err != nil {
		log.Fatalf("Unable to create Rancher client: %s\n", err)
	}
	s.service = c.Service
	s.account = c.Account
}

func (s *ServiceUpdater) listen() {
	http.HandleFunc("/upgrade", s.upgrade)
	http.HandleFunc("/ping", s.ping)
	log.Printf("Started service on port %d\n", s.Config.Port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", s.Config.Port), nil)
	if err != nil {
		log.Fatalf("Unable to start service on port %d\n", s.Config.Port)
	}
}

func (s *ServiceUpdater) ping(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Pong!"))
	return
}

func (s *ServiceUpdater) upgrade(w http.ResponseWriter, r *http.Request) {
	command := UpdateCommand{
		StartFirst: false,
		Timeout:    30,
	}

	err := json.NewDecoder(r.Body).Decode(&command)
	if err != nil {
		log.Printf("%s\n", err.Error())
		utils.SendError(w, err.Error(), 400)
		return
	}
	txt, _ := json.Marshal(command)
	if s.Config.Debug {
		fmt.Printf("Received upgrade: %s", string(txt))
	}
	go s.upgradeService(command)
	w.WriteHeader(200)
	return
}

func (s *ServiceUpdater) upgradeService(command UpdateCommand) {
	if !strings.HasPrefix(command.Image, "docker:") {
		command.Image = fmt.Sprintf("docker:%s", command.Image)
	}
	parts := strings.Split(command.Image, ":")
	wantedImage := parts[1]
	wantedVer := parts[2]

	services, err := s.service.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to list rancher services: %s\n", err)
		return
	}

	environments, err := s.account.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to get environments: %s\n", err)
		return
	}
	envs := make(map[string]string)
	for environments != nil {
		for _, env := range environments.Data {
			envs[env.Id] = env.Name
		}
		environments, err = environments.Next()
		if err != nil {
			fmt.Printf("Failed: %s\n", err)
			return
		}
	}

	var enabledLabel = s.Config.EnableLabel
	for services != nil {
		for _, svc := range services.Data {
			if s.Config.Debug {
				log.Printf("Checking service: %s", svc.Name)
			}
			if svc.LaunchConfig != nil {
				if enable, ok := svc.LaunchConfig.Labels[enabledLabel]; ok && enable != "false" {
					if s.Config.Debug {
						log.Printf("Attempting to update service %s\n", svc.Name)
					}
					parts := strings.Split(svc.LaunchConfig.ImageUuid, ":")
					foundImage := parts[1]
					foundVer := parts[2]
					if utils.EnvironmentEnabled(envs[svc.AccountId], s.Config.EnvironmentNames) {
						if s.Config.Debug {
							log.Printf("Service %s Comparision: found-image %s, found-version %s, wanted-image %s, wanted-version %s\n", svc.Name, foundImage, foundVer, wantedImage, wantedVer)
						}
						if foundImage == wantedImage && ((foundVer < wantedVer) || (wantedVer == "latest")) {
							fmt.Println("Trying to upgrade...")
							err := s.doUpgrade(command, svc)
							if err != nil {
								fmt.Println(err.Error())
							} else {
								if command.Confirm {
									fmt.Println("Trying to confirm...")
									err := s.confirmUpgrade(command, svc)
									url := fmt.Sprintf("%s/env/%s/apps/stacks/%s", s.Config.CattleURL, svc.AccountId, svc.EnvironmentId)
									if err != nil {
										fmt.Printf("Unable to upgrade service %s: %s\n", svc.Name, err.Error())
										message := fmt.Sprintf("Unable to confirm upgrade to `%s`.\nCheck status at <%[2]s|%[1]s>", svc.Name, url)
										s.slackMessage("danger", message)
									} else {
										fmt.Printf("Upgraded %s to %s\n", svc.Name, command.Image)
										message := fmt.Sprintf("`%[1]s` has been successfully upgraded to `%[2]s` "+
											"in %[4]s\n View in Rancher here: <%[3]s|%[1]s>", svc.Name, wantedVer, url, envs[svc.AccountId])
										s.slackMessage("good", message)

									}
								}
							}
							continue
						} else if s.Config.Debug {
							log.Printf("Updating enabled from environment [%s], service [%s], but published version [%s] was not newer than current version [%s]\n", envs[svc.AccountId], svc.Name, wantedVer, foundVer)
						}
					} else if s.Config.Debug {
						log.Printf("Updating not enabled for environment %s\n", envs[svc.AccountId])
					}
				}
			}
		}
		services, _ = services.Next()
	}
}

func (s *ServiceUpdater) doUpgrade(command UpdateCommand, service client.Service) error {
	service.LaunchConfig.ImageUuid = command.Image
	upgrade := &client.ServiceUpgrade{}
	upgrade.InServiceStrategy = &client.InServiceUpgradeStrategy{
		LaunchConfig:           service.LaunchConfig,
		SecondaryLaunchConfigs: service.SecondaryLaunchConfigs,
		StartFirst:             command.StartFirst,
	}
	upgrade.ToServiceStrategy = &client.ToServiceUpgradeStrategy{}
	_, err := s.service.ActionUpgrade(&service, upgrade)
	return err
}

func (s *ServiceUpdater) confirmUpgrade(command UpdateCommand, service client.Service) error {
	srv, err := utils.Retry(func() (interface{}, error) {
		s, e := s.service.ById(service.Id)
		if e != nil {
			return nil, e
		}
		if s.State != "upgraded" {
			return nil, fmt.Errorf("Service not upgraded: %s\n", s.State)
		}
		return s, nil
	}, time.Duration(command.Timeout)*time.Second, 3*time.Second)
	if err != nil {
		return err
	}

	srv, err = s.service.ActionFinishupgrade(srv.(*client.Service))
	if err != nil {
		return err
	}
	fmt.Printf("Finished upgrade on %s\n", srv.(*client.Service).Name)
	return err
}

func (s *ServiceUpdater) slackMessage(status string, message string) {
	if s.Config.SlackWebhookURL != "" {
		attachment := slack.Attachment{Color: &status, Text: &message}
		mrkdwn := "text"
		attachment.AddMrkdwn(&mrkdwn)
		payload := slack.Payload{
			Username:    s.Config.SlackBotName,
			Attachments: []slack.Attachment{attachment},
		}
		printable, _ := json.Marshal(payload)
		fmt.Println(string(printable))
		err := slack.Send(s.Config.SlackWebhookURL, "", payload)
		if len(err) > 0 {
			fmt.Printf("error sending Slack message: %s\n", err)
		}
	}
}
<commit_msg>Better logic for splitting image and tag.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/ahaynssen/slack-go-webhook"
	"github.com/objectpartners/rancher-service-updater/utils"
	"github.com/rancher/go-rancher/client"
)

type (
	//Config is the service configuration
	Config struct {
		EnableLabel      string
		EnvironmentNames []string
		Port             int
		CattleSecretKey  string
		CattleAccessKey  string
		CattleURL        string
		SlackWebhookURL  string
		SlackBotName     string
		Debug            bool
	}

	//ServiceUpdater is the service
	ServiceUpdater struct {
		Config *Config
		// client  *client.RancherClient
		service Service
		account Account
	}

	//UpdateCommand is payload for new image availability
	UpdateCommand struct {
		Image      string `json:"docker_image"`
		StartFirst bool   `json:"start_first"`
		Confirm    bool   `json:"confirm"`
		Timeout    int    `json:"timeout"`
	}

	//Service is Rancher Service interface
	Service interface {
		ById(id string) (*client.Service, error)
		List(opts *client.ListOpts) (*client.ServiceCollection, error)
		ActionFinishupgrade(*client.Service) (*client.Service, error)
		ActionUpgrade(*client.Service, *client.ServiceUpgrade) (*client.Service, error)
	}

	//Account is Rancher Environment interface
	Account interface {
		List(opts *client.ListOpts) (*client.AccountCollection, error)
	}
)

func main() {
	config := &Config{
		EnableLabel:      utils.GetEnvOrDefault("AUTOUPDATE_ENABLE_LABEL", "autoupdate.enable"),
		EnvironmentNames: utils.GetEnvOrDefaultArray("AUTOUPDATE_ENVIRONMENT_NAMES", []string{".*"}),
		Port:             utils.GetEnvOrDefaultInt("AUTOUPDATE_HTTP_PORT", 8080),
		CattleAccessKey:  os.Getenv("CATTLE_ACCESS_KEY"),
		CattleSecretKey:  os.Getenv("CATTLE_SECRET_KEY"),
		CattleURL:        os.Getenv("CATTLE_URL"),
		SlackWebhookURL:  os.Getenv("AUTOUPDATE_SLACK_WEBHOOK_URL"),
		SlackBotName:     utils.GetEnvOrDefault("AUTOUPDATE_SLACK_BOT_NAME", "rancher-service-updater"),
		Debug:            os.Getenv("DEBUG") != "",
	}
	serviceUpdater := &ServiceUpdater{
		Config: config,
	}
	serviceUpdater.init()
	serviceUpdater.listen()
}

func (s *ServiceUpdater) init() {
	c, err := client.NewRancherClient(&client.ClientOpts{
		AccessKey: s.Config.CattleAccessKey,
		SecretKey: s.Config.CattleSecretKey,
		Url:       s.Config.CattleURL,
	})
	if err != nil {
		log.Fatalf("Unable to create Rancher client: %s\n", err)
	}
	s.service = c.Service
	s.account = c.Account
}

func (s *ServiceUpdater) listen() {
	http.HandleFunc("/upgrade", s.upgrade)
	http.HandleFunc("/ping", s.ping)
	log.Printf("Started service on port %d\n", s.Config.Port)
	err := http.ListenAndServe(fmt.Sprintf(":%d", s.Config.Port), nil)
	if err != nil {
		log.Fatalf("Unable to start service on port %d\n", s.Config.Port)
	}
}

func (s *ServiceUpdater) ping(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Pong!"))
	return
}

func (s *ServiceUpdater) upgrade(w http.ResponseWriter, r *http.Request) {
	command := UpdateCommand{
		StartFirst: false,
		Timeout:    30,
	}

	err := json.NewDecoder(r.Body).Decode(&command)
	if err != nil {
		log.Printf("%s\n", err.Error())
		utils.SendError(w, err.Error(), 400)
		return
	}
	txt, _ := json.Marshal(command)
	if s.Config.Debug {
		fmt.Printf("Received upgrade: %s", string(txt))
	}
	go s.upgradeService(command)
	w.WriteHeader(200)
	return
}

func (s *ServiceUpdater) upgradeService(command UpdateCommand) {
	if !strings.HasPrefix(command.Image, "docker:") {
		command.Image = fmt.Sprintf("docker:%s", command.Image)
	}
	idx := strings.LastIndex(command.Image, ":")
	wantedImage := command.Image[0 : idx-1]
	wantedVer := command.Image[idx:]

	services, err := s.service.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to list rancher services: %s\n", err)
		return
	}

	environments, err := s.account.List(&client.ListOpts{})
	if err != nil {
		fmt.Printf("Failed to get environments: %s\n", err)
		return
	}
	envs := make(map[string]string)
	for environments != nil {
		for _, env := range environments.Data {
			envs[env.Id] = env.Name
		}
		environments, err = environments.Next()
		if err != nil {
			fmt.Printf("Failed: %s\n", err)
			return
		}
	}

	var enabledLabel = s.Config.EnableLabel
	for services != nil {
		for _, svc := range services.Data {
			if s.Config.Debug {
				log.Printf("Checking service: %s", svc.Name)
			}
			if svc.LaunchConfig != nil {
				if enable, ok := svc.LaunchConfig.Labels[enabledLabel]; ok && enable != "false" {
					if s.Config.Debug {
						log.Printf("Attempting to update service %s\n", svc.Name)
					}
					idx := strings.LastIndex(svc.LaunchConfig.ImageUuid, ":")

					foundImage := svc.LaunchConfig.ImageUuid[0 : idx-1]
					foundVer := svc.LaunchConfig.ImageUuid[idx:]
					if utils.EnvironmentEnabled(envs[svc.AccountId], s.Config.EnvironmentNames) {
						if s.Config.Debug {
							log.Printf("Service %s Comparision: found-image %s, found-version %s, wanted-image %s, wanted-version %s\n", svc.Name, foundImage, foundVer, wantedImage, wantedVer)
						}
						if foundImage == wantedImage && ((foundVer < wantedVer) || (wantedVer == "latest")) {
							fmt.Println("Trying to upgrade...")
							err := s.doUpgrade(command, svc)
							if err != nil {
								fmt.Println(err.Error())
							} else {
								if command.Confirm {
									fmt.Println("Trying to confirm...")
									err := s.confirmUpgrade(command, svc)
									url := fmt.Sprintf("%s/env/%s/apps/stacks/%s", s.Config.CattleURL, svc.AccountId, svc.EnvironmentId)
									if err != nil {
										fmt.Printf("Unable to upgrade service %s: %s\n", svc.Name, err.Error())
										message := fmt.Sprintf("Unable to confirm upgrade to `%s`.\nCheck status at <%[2]s|%[1]s>", svc.Name, url)
										s.slackMessage("danger", message)
									} else {
										fmt.Printf("Upgraded %s to %s\n", svc.Name, command.Image)
										message := fmt.Sprintf("`%[1]s` has been successfully upgraded to `%[2]s` "+
											"in %[4]s\n View in Rancher here: <%[3]s|%[1]s>", svc.Name, wantedVer, url, envs[svc.AccountId])
										s.slackMessage("good", message)

									}
								}
							}
							continue
						} else if s.Config.Debug {
							log.Printf("Updating enabled from environment [%s], service [%s], but published version [%s] was not newer than current version [%s]\n", envs[svc.AccountId], svc.Name, wantedVer, foundVer)
						}
					} else if s.Config.Debug {
						log.Printf("Updating not enabled for environment %s\n", envs[svc.AccountId])
					}
				}
			}
		}
		services, _ = services.Next()
	}
}

func (s *ServiceUpdater) doUpgrade(command UpdateCommand, service client.Service) error {
	service.LaunchConfig.ImageUuid = command.Image
	upgrade := &client.ServiceUpgrade{}
	upgrade.InServiceStrategy = &client.InServiceUpgradeStrategy{
		LaunchConfig:           service.LaunchConfig,
		SecondaryLaunchConfigs: service.SecondaryLaunchConfigs,
		StartFirst:             command.StartFirst,
	}
	upgrade.ToServiceStrategy = &client.ToServiceUpgradeStrategy{}
	_, err := s.service.ActionUpgrade(&service, upgrade)
	return err
}

func (s *ServiceUpdater) confirmUpgrade(command UpdateCommand, service client.Service) error {
	srv, err := utils.Retry(func() (interface{}, error) {
		s, e := s.service.ById(service.Id)
		if e != nil {
			return nil, e
		}
		if s.State != "upgraded" {
			return nil, fmt.Errorf("Service not upgraded: %s\n", s.State)
		}
		return s, nil
	}, time.Duration(command.Timeout)*time.Second, 3*time.Second)
	if err != nil {
		return err
	}

	srv, err = s.service.ActionFinishupgrade(srv.(*client.Service))
	if err != nil {
		return err
	}
	fmt.Printf("Finished upgrade on %s\n", srv.(*client.Service).Name)
	return err
}

func (s *ServiceUpdater) slackMessage(status string, message string) {
	if s.Config.SlackWebhookURL != "" {
		attachment := slack.Attachment{Color: &status, Text: &message}
		mrkdwn := "text"
		attachment.AddMrkdwn(&mrkdwn)
		payload := slack.Payload{
			Username:    s.Config.SlackBotName,
			Attachments: []slack.Attachment{attachment},
		}
		printable, _ := json.Marshal(payload)
		fmt.Println(string(printable))
		err := slack.Send(s.Config.SlackWebhookURL, "", payload)
		if len(err) > 0 {
			fmt.Printf("error sending Slack message: %s\n", err)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"

	"github.com/subutai-io/agent/log"

	"github.com/jasonlvhit/gocron"
	"github.com/subutai-io/gorjun/apt"
	"github.com/subutai-io/gorjun/auth"
	"github.com/subutai-io/gorjun/auto"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
	"github.com/subutai-io/gorjun/raw"
	"github.com/subutai-io/gorjun/template"
	"github.com/subutai-io/gorjun/upload"
)

var version = "6.3.0"

var (
	srv      *http.Server
	testMode bool = false
	stop     chan bool
)

func RunTask() {
	gocron.Every(6).Hours().Do(apt.GenerateReleaseFile)
	<-gocron.Start()
}
func main() {
	defer db.Close()
	// defer torrent.Close()
	// go torrent.SeedLocal()
	go RunTask()
	go auto.CleanGarbage()
	if len(config.CDN.Node) > 0 {
		target := url.URL{Scheme: "https", Host: config.CDN.Node}
		proxy := httputil.NewSingleHostReverseProxy(&target)
		targetQuery := target.RawQuery
		proxy.Director = func(req *http.Request) {
			req.URL.Scheme = target.Scheme
			req.URL.Host = target.Host
			req.Host = config.CDN.Node
			req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
			if targetQuery == "" || req.URL.RawQuery == "" {
				req.URL.RawQuery = targetQuery + req.URL.RawQuery
			} else {
				req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
			}
			if _, ok := req.Header["User-Agent"]; !ok {
				// explicitly disable User-Agent so it's not set to default value
				req.Header.Set("User-Agent", "")
			}
		}
		log.Check(log.ErrorLevel, "Starting to listen :"+config.Network.Port, http.ListenAndServe(":"+config.Network.Port, proxy))
		return
	}

	log.Info("Server has started. " + "Listening at " + "127.0.0.1:8080")

	http.HandleFunc("/kurjun/rest/file/get", raw.Download)
	http.HandleFunc("/kurjun/rest/file/info", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/get", raw.Download)
	http.HandleFunc("/kurjun/rest/template/get", template.Download)

	http.HandleFunc("/kurjun/rest/apt/", apt.Download)
	http.HandleFunc("/kurjun/rest/apt/info", apt.Info)
	http.HandleFunc("/kurjun/rest/apt/list", apt.Info)
	http.HandleFunc("/kurjun/rest/apt/delete", apt.Delete)
	http.HandleFunc("/kurjun/rest/apt/upload", apt.Upload)
	http.HandleFunc("/kurjun/rest/apt/download", apt.Download)
	http.HandleFunc("/kurjun/rest/apt/generate", apt.Generate)

	http.HandleFunc("/kurjun/rest/raw/", raw.Download)
	http.HandleFunc("/kurjun/rest/raw/info", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/list", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/delete", raw.Delete)
	http.HandleFunc("/kurjun/rest/raw/upload", raw.Upload)
	http.HandleFunc("/kurjun/rest/raw/download", raw.Download)

	http.HandleFunc("/kurjun/rest/template/", template.Download)
	http.HandleFunc("/kurjun/rest/template/tag", template.Tag)
	http.HandleFunc("/kurjun/rest/template/info", template.Info)
	http.HandleFunc("/kurjun/rest/template/list", template.Info)
	http.HandleFunc("/kurjun/rest/template/update", template.ModifyConfig)
	http.HandleFunc("/kurjun/rest/template/delete", template.Delete)
	http.HandleFunc("/kurjun/rest/template/upload", template.Upload)
	http.HandleFunc("/kurjun/rest/template/download", template.Download)
	// http.HandleFunc("/kurjun/rest/template/torrent", template.Torrent)

	http.HandleFunc("/kurjun/rest/auth/key", auth.Key)
	http.HandleFunc("/kurjun/rest/auth/keys", auth.Keys)
	http.HandleFunc("/kurjun/rest/auth/sign", auth.Sign)
	http.HandleFunc("/kurjun/rest/auth/owner", auth.Owner)
	http.HandleFunc("/kurjun/rest/auth/token", auth.Token)
	http.HandleFunc("/kurjun/rest/auth/register", auth.Register)
	http.HandleFunc("/kurjun/rest/auth/validate", auth.Validate)

	http.HandleFunc("/kurjun/rest/share", upload.Share)
	http.HandleFunc("/kurjun/rest/quota", upload.Quota)
	http.HandleFunc("/kurjun/rest/about", about)

	if testMode {
		http.HandleFunc("/kurjun/rest/shutdown", shutdown)
	}

	srv = &http.Server{
		Addr:    ":" + config.Network.Port,
		Handler: nil,
	}

	srv.ListenAndServe()

}

func shutdown(w http.ResponseWriter, r *http.Request) {
	log.Info("Shutting down the server")
	stop <- true
}

func about(w http.ResponseWriter, r *http.Request) {
	if strings.Split(r.RemoteAddr, ":")[0] == "127.0.0.1" {
		_, err := w.Write([]byte(version))
		log.Check(log.DebugLevel, "Writing Kurjun version", err)
	} else {
		w.WriteHeader(http.StatusUnauthorized)
	}
}

func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

func runMain() {
	// start the stop channel
	stop = make(chan bool)
	// put the service in "testMode"
	testMode = true
	// run the main entry point
	go main()
	// watch for the stop channel
	<-stop
	// stop the graceful server
	ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
	srv.Shutdown(ctx)
}
<commit_msg>Add health check response<commit_after>package main

import (
	"context"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"

	"github.com/subutai-io/agent/log"

	"github.com/jasonlvhit/gocron"
	"github.com/subutai-io/gorjun/apt"
	"github.com/subutai-io/gorjun/auth"
	"github.com/subutai-io/gorjun/auto"
	"github.com/subutai-io/gorjun/config"
	"github.com/subutai-io/gorjun/db"
	"github.com/subutai-io/gorjun/raw"
	"github.com/subutai-io/gorjun/template"
	"github.com/subutai-io/gorjun/upload"
)

var version = "6.3.0"

var (
	srv      *http.Server
	testMode bool = false
	stop     chan bool
)

func RunTask() {
	gocron.Every(6).Hours().Do(apt.GenerateReleaseFile)
	<-gocron.Start()
}
func main() {
	defer db.Close()
	// defer torrent.Close()
	// go torrent.SeedLocal()
	go RunTask()
	go auto.CleanGarbage()
	if len(config.CDN.Node) > 0 {
		target := url.URL{Scheme: "https", Host: config.CDN.Node}
		proxy := httputil.NewSingleHostReverseProxy(&target)
		targetQuery := target.RawQuery
		proxy.Director = func(req *http.Request) {
			req.URL.Scheme = target.Scheme
			req.URL.Host = target.Host
			req.Host = config.CDN.Node
			req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
			if targetQuery == "" || req.URL.RawQuery == "" {
				req.URL.RawQuery = targetQuery + req.URL.RawQuery
			} else {
				req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
			}
			if _, ok := req.Header["User-Agent"]; !ok {
				// explicitly disable User-Agent so it's not set to default value
				req.Header.Set("User-Agent", "")
			}
		}
		log.Check(log.ErrorLevel, "Starting to listen :"+config.Network.Port, http.ListenAndServe(":"+config.Network.Port, proxy))
		return
	}

	log.Info("Server has started. " + "Listening at " + "127.0.0.1:8080")

	http.HandleFunc("/kurjun/rest/file/get", raw.Download)
	http.HandleFunc("/kurjun/rest/file/info", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/get", raw.Download)
	http.HandleFunc("/kurjun/rest/template/get", template.Download)

	http.HandleFunc("/kurjun/rest/apt/", apt.Download)
	http.HandleFunc("/kurjun/rest/apt/info", apt.Info)
	http.HandleFunc("/kurjun/rest/apt/list", apt.Info)
	http.HandleFunc("/kurjun/rest/apt/delete", apt.Delete)
	http.HandleFunc("/kurjun/rest/apt/upload", apt.Upload)
	http.HandleFunc("/kurjun/rest/apt/download", apt.Download)
	http.HandleFunc("/kurjun/rest/apt/generate", apt.Generate)

	http.HandleFunc("/kurjun/rest/raw/", raw.Download)
	http.HandleFunc("/kurjun/rest/raw/info", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/list", raw.Info)
	http.HandleFunc("/kurjun/rest/raw/delete", raw.Delete)
	http.HandleFunc("/kurjun/rest/raw/upload", raw.Upload)
	http.HandleFunc("/kurjun/rest/raw/download", raw.Download)

	http.HandleFunc("/kurjun/rest/template/", template.Download)
	http.HandleFunc("/kurjun/rest/template/tag", template.Tag)
	http.HandleFunc("/kurjun/rest/template/info", template.Info)
	http.HandleFunc("/kurjun/rest/template/list", template.Info)
	http.HandleFunc("/kurjun/rest/template/update", template.ModifyConfig)
	http.HandleFunc("/kurjun/rest/template/delete", template.Delete)
	http.HandleFunc("/kurjun/rest/template/upload", template.Upload)
	http.HandleFunc("/kurjun/rest/template/download", template.Download)
	// http.HandleFunc("/kurjun/rest/template/torrent", template.Torrent)

	http.HandleFunc("/kurjun/rest/auth/key", auth.Key)
	http.HandleFunc("/kurjun/rest/auth/keys", auth.Keys)
	http.HandleFunc("/kurjun/rest/auth/sign", auth.Sign)
	http.HandleFunc("/kurjun/rest/auth/owner", auth.Owner)
	http.HandleFunc("/kurjun/rest/auth/token", auth.Token)
	http.HandleFunc("/kurjun/rest/auth/register", auth.Register)
	http.HandleFunc("/kurjun/rest/auth/validate", auth.Validate)

	http.HandleFunc("/kurjun/rest/healthcheck", healthcheck)
	http.HandleFunc("/kurjun/rest/share", upload.Share)
	http.HandleFunc("/kurjun/rest/quota", upload.Quota)
	http.HandleFunc("/kurjun/rest/about", about)

	if testMode {
		http.HandleFunc("/kurjun/rest/shutdown", shutdown)
	}

	srv = &http.Server{
		Addr:    ":" + config.Network.Port,
		Handler: nil,
	}

	srv.ListenAndServe()

}

func shutdown(w http.ResponseWriter, r *http.Request) {
	log.Info("Shutting down the server")
	stop <- true
}

func about(w http.ResponseWriter, r *http.Request) {
	if strings.Split(r.RemoteAddr, ":")[0] == "127.0.0.1" {
		_, err := w.Write([]byte(version))
		log.Check(log.DebugLevel, "Writing Kurjun version", err)
	} else {
		w.WriteHeader(http.StatusUnauthorized)
	}
}

func singleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

func healthcheck(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
}
func runMain() {
	// start the stop channel
	stop = make(chan bool)
	// put the service in "testMode"
	testMode = true
	// run the main entry point
	go main()
	// watch for the stop channel
	<-stop
	// stop the graceful server
	ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
	srv.Shutdown(ctx)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/lucapette/fakedata/pkg/fakedata"
	flag "github.com/spf13/pflag"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var version = "master"

var generatorsFlag = flag.BoolP("generators", "g", false, "lists available generators")
var limitFlag = flag.IntP("limit", "l", 10, "limits rows up to n")
var formatFlag = flag.StringP("format", "f", "", "generators rows in f format. Available formats: csv|tab|sql")
var versionFlag = flag.BoolP("version", "v", false, "shows version information")
var tableFlag = flag.StringP("table", "t", "TABLE", "table name of the sql format")
var templateFlag = flag.StringP("template", "", "", "Use template as input")

func getFormatter(format string) (f fakedata.Formatter) {
	switch format {
	case "csv":
		f = fakedata.NewSeparatorFormatter(",")
	case "tab":
		f = fakedata.NewSeparatorFormatter("\t")
	case "sql":
		f = fakedata.NewSQLFormatter(*tableFlag)
	default:
		f = fakedata.NewSeparatorFormatter(" ")
	}
	return f
}

func generatorsHelp() string {
	generators := fakedata.Generators()
	var buffer bytes.Buffer

	var max int

	for _, gen := range generators {
		if len(gen.Name) > max {
			max = len(gen.Name)
		}
	}

	pattern := fmt.Sprintf("%%-%ds%%s\n", max+2) //+2 makes the output more readable
	for _, gen := range generators {
		fmt.Fprintf(&buffer, pattern, gen.Name, gen.Desc)
	}

	return buffer.String()
}

func main() {
	if *versionFlag {
		fmt.Println(version)
		os.Exit(0)
	}

	if *generatorsFlag {
		fmt.Print(generatorsHelp())
		os.Exit(0)
	}

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

	if *templateFlag != "" {
		if err := fakedata.ParseTemplate(*templateFlag, *limitFlag); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		os.Exit(0)
	}

	stat, _ := os.Stdin.Stat()
	// Check if template data is piped to fakedata
	if (stat.Mode() & os.ModeCharDevice) == 0 {
		t, err := ioutil.ReadAll(os.Stdin)

		if err != nil {
			fmt.Printf("Unable to read input: %s", err)
			os.Exit(1)
		}

		if err = fakedata.ParseTemplateFromPipe(string(t), *limitFlag); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(0)
	}

	columns, err := fakedata.NewColumns(flag.Args())
	if err != nil {
		fmt.Printf("%v\n\nSee fakedata --generators for a list of available generators.\n", err)
		os.Exit(0)
	}

	formatter := getFormatter(*formatFlag)

	for i := 0; i < *limitFlag; i++ {
		fmt.Print(fakedata.GenerateRow(columns, formatter))
	}
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: fakedata [option ...] field...\n\n")
		flag.PrintDefaults()
	}
	flag.Parse()
}
<commit_msg>(template): Ass isPipe func for clarity<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/lucapette/fakedata/pkg/fakedata"
	flag "github.com/spf13/pflag"
	"io/ioutil"
	"math/rand"
	"os"
	"time"
)

var version = "master"

var generatorsFlag = flag.BoolP("generators", "g", false, "lists available generators")
var limitFlag = flag.IntP("limit", "l", 10, "limits rows up to n")
var formatFlag = flag.StringP("format", "f", "", "generators rows in f format. Available formats: csv|tab|sql")
var versionFlag = flag.BoolP("version", "v", false, "shows version information")
var tableFlag = flag.StringP("table", "t", "TABLE", "table name of the sql format")
var templateFlag = flag.StringP("template", "", "", "Use template as input")

func getFormatter(format string) (f fakedata.Formatter) {
	switch format {
	case "csv":
		f = fakedata.NewSeparatorFormatter(",")
	case "tab":
		f = fakedata.NewSeparatorFormatter("\t")
	case "sql":
		f = fakedata.NewSQLFormatter(*tableFlag)
	default:
		f = fakedata.NewSeparatorFormatter(" ")
	}
	return f
}

func generatorsHelp() string {
	generators := fakedata.Generators()
	var buffer bytes.Buffer

	var max int

	for _, gen := range generators {
		if len(gen.Name) > max {
			max = len(gen.Name)
		}
	}

	pattern := fmt.Sprintf("%%-%ds%%s\n", max+2) //+2 makes the output more readable
	for _, gen := range generators {
		fmt.Fprintf(&buffer, pattern, gen.Name, gen.Desc)
	}

	return buffer.String()
}

func isPipe() bool {
	stat, _ := os.Stdin.Stat()
	// Check if template data is piped to fakedata
	return (stat.Mode() & os.ModeCharDevice) == 0
}

func main() {
	if *versionFlag {
		fmt.Println(version)
		os.Exit(0)
	}

	if *generatorsFlag {
		fmt.Print(generatorsHelp())
		os.Exit(0)
	}

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

	if *templateFlag != "" {
		if err := fakedata.ParseTemplate(*templateFlag, *limitFlag); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		os.Exit(0)
	}

	if isPipe() {
		t, err := ioutil.ReadAll(os.Stdin)

		if err != nil {
			fmt.Printf("Unable to read input: %s", err)
			os.Exit(1)
		}

		if err = fakedata.ParseTemplateFromPipe(string(t), *limitFlag); err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		os.Exit(0)
	}

	if len(flag.Args()) == 0 {
		flag.Usage()
		os.Exit(0)
	}

	columns, err := fakedata.NewColumns(flag.Args())
	if err != nil {
		fmt.Printf("%v\n\nSee fakedata --generators for a list of available generators.\n", err)
		os.Exit(0)
	}

	formatter := getFormatter(*formatFlag)

	for i := 0; i < *limitFlag; i++ {
		fmt.Print(fakedata.GenerateRow(columns, formatter))
	}
}

func init() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: fakedata [option ...] field...\n\n")
		flag.PrintDefaults()
	}
	flag.Parse()
}
<|endoftext|>


<commit_before>// +build linux darwin freebsd

package main

import (
	"./commands/"
	"fmt"
	"log"
	"log/syslog"
	"os"
	"runtime"
)

// CompileDate tracks when the binary was compiled. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var CompileDate = "No date provided."

// GitCommit tracks the SHA of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var GitCommit = "No revision provided."

// Version is the version of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var Version = "No version provided."

// GoVersion details the version of Go this was compiled with.
var GoVersion = runtime.Version()

func main() {
	logwriter, e := syslog.New(syslog.LOG_NOTICE, "kvexpress")
	if e == nil {
		log.SetFlags(log.Lmicroseconds)
		log.SetOutput(logwriter)
	}
	commands.Log(fmt.Sprintf("kvexpress version:%s", Version), "info")

	args := os.Args[1:]
	for _, arg := range args {
		if arg == "-v" || arg == "--version" {
			fmt.Printf("Version  : %s\nRevision : %s\nDate     : %s\nGo       : %s\n", Version, GitCommit, CompileDate, GoVersion)
			os.Exit(0)
		}
	}

	runtime.GOMAXPROCS(runtime.NumCPU())
	commands.RootCmd.Execute()
}
<commit_msg>That's much nicer. Closes #75.<commit_after>// +build linux darwin freebsd

package main

import (
	"./commands/"
	"fmt"
	"log"
	"log/syslog"
	"os"
	"runtime"
)

// CompileDate tracks when the binary was compiled. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var CompileDate = "No date provided."

// GitCommit tracks the SHA of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var GitCommit = "No revision provided."

// Version is the version of the built binary. It's inserted during a build
// with build flags. Take a look at the Makefile for information.
var Version = "No version provided."

// GoVersion details the version of Go this was compiled with.
var GoVersion = runtime.Version()

func main() {
	logwriter, e := syslog.New(syslog.LOG_NOTICE, "kvexpress")
	if e == nil {
		log.SetFlags(log.Lmicroseconds)
		log.SetOutput(logwriter)
	}
	commands.Log(fmt.Sprintf("kvexpress version:%s", Version), "info")

	args := os.Args[1:]
	for _, arg := range args {
		if arg == "-v" || arg == "--version" {
			fmt.Printf("%-8s : %s\n%-8s : %s\n%-8s : %s\n%-8s : %s\n", "Version", Version, "Revision", GitCommit, "Date", CompileDate, "Go", GoVersion)
			os.Exit(0)
		}
	}

	runtime.GOMAXPROCS(runtime.NumCPU())
	commands.RootCmd.Execute()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/ChimeraCoder/anaconda"
)

func getLines(fname string) ([]string, error) {
	fp, err := os.Open(fname)
	if err != nil {
		panic(err)
	}
	defer fp.Close()
	scanner := bufio.NewScanner(fp)
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	return lines, nil
}

func getApi() *anaconda.TwitterApi {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	return anaconda.NewTwitterApi(info[2], info[3])
}

func authenticate() {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	url, token, err := anaconda.AuthorizationURL("")
	if err != nil {
		panic(err)
	}
	fmt.Println(url)
	fmt.Println(token.Token, token.Secret)

	var verifier string
	fmt.Print("Input PIN Code: ")
	fmt.Scan(&verifier)
	token, val, err := anaconda.GetCredentials(token, verifier)
	fmt.Println(token)
	fmt.Println(val)
	if err != nil {
		panic(err)
	}
	//api := anaconda.NewTwitterApi(token.Token, token.Secret)
}

func test() {
	fmt.Println("0")
}

func main() {
	dbgflag := false
	if dbgflag {
		fmt.Println("Debug mode ON!")
		test()
		return
	}

	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}

	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	api := anaconda.NewTwitterApi(info[2], info[3])

	// Delete user's tweets (up to 3200)
	LIM := 16
	v := url.Values{}
	v.Set("count", "200")
	for page := 1; page <= LIM; page++ {
		v.Set("page", strconv.Itoa(page))
		timeline, err := api.GetUserTimeline(v)
		if err != nil {
			panic(err)
		}
		if dbgflag {
			fmt.Println("Len: ", len(timeline))
		}
		if len(timeline) == 0 {
			break
		}

		for _, tweet := range timeline {
			t, err := api.DeleteTweet(tweet.Id, false)
			if err != nil {
				panic(err)
			}
			fmt.Println(t.Text)
		}
	}

	fmt.Println("Done")
}
<commit_msg>Add flags<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"net/url"
	"os"
	"strconv"

	"github.com/ChimeraCoder/anaconda"
)

var (
	limit   int
	minfav  int
	minrt   int
	dbgflag bool
)

func getLines(fname string) ([]string, error) {
	fp, err := os.Open(fname)
	if err != nil {
		panic(err)
	}
	defer fp.Close()
	scanner := bufio.NewScanner(fp)
	var lines []string
	for scanner.Scan() {
		line := scanner.Text()
		lines = append(lines, line)
	}
	return lines, nil
}

func getApi() *anaconda.TwitterApi {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	return anaconda.NewTwitterApi(info[2], info[3])
}

func authenticate() {
	info, err := getLines("oauth.txt")
	if err != nil {
		panic(err)
	}
	anaconda.SetConsumerKey(info[0])
	anaconda.SetConsumerSecret(info[1])
	url, token, err := anaconda.AuthorizationURL("")
	if err != nil {
		panic(err)
	}
	fmt.Println(url)
	fmt.Println(token.Token, token.Secret)

	var verifier string
	fmt.Print("Input PIN Code: ")
	fmt.Scan(&verifier)
	token, val, err := anaconda.GetCredentials(token, verifier)
	fmt.Println(token)
	fmt.Println(val)
	if err != nil {
		panic(err)
	}
	//api := anaconda.NewTwitterApi(token.Token, token.Secret)
}

func test() {
	fmt.Println(limit, minfav, minrt, dbgflag)
}

func init() {
	// Set flags
	INF := 114514
	flag.IntVar(&limit, "limit", 3200, "Limit of number to delete tweets")
	flag.IntVar(&minfav, "minfav", INF, "Delete tweet less than minfav")
	flag.IntVar(&minrt, "minrt", INF, "Delete tweet less than minrt")
	flag.BoolVar(&dbgflag, "dbg", false, "Debug mode on if dbg=true")

	flag.Parse()
}

func main() {
	if dbgflag {
		fmt.Println("Debug mode ON!")
		test()
		return
	}

	api := getApi()

	// Delete user's tweets (up to 3200)
	LIM := limit / 200
	v := url.Values{}
	v.Set("count", "200")
	for page := 1; page <= LIM; page++ {
		if page == LIM {
			v.Set("count", strconv.Itoa(limit%200))
		}
		v.Set("page", strconv.Itoa(page))
		timeline, err := api.GetUserTimeline(v)
		if err != nil {
			panic(err)
		}
		if dbgflag {
			fmt.Println("Len: ", len(timeline))
		}
		if len(timeline) == 0 {
			break
		}

		for _, tweet := range timeline {
			if tweet.FavoriteCount >= minfav || tweet.RetweetCount >= minrt {
				continue
			}
			t, err := api.DeleteTweet(tweet.Id, false)
			if err != nil {
				panic(err)
			}
			if dbgflag {
				fmt.Println(t.Text)
			}
		}
	}

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


<commit_before>package main

import (
	"fmt"
	"github.com/doxxan/appindicator"
	"github.com/doxxan/appindicator/gtk-extensions/gotk3"
	"github.com/doxxan/gotk3/gtk"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type NetState int

const (
	StateDisconnected NetState = iota
	StateConnected
)

const (
	SizeKB = 1024
	SizeMB = SizeKB * 1024
	SizeGB = SizeMB * 1024
	SizeTB = SizeGB * 1024
	SizePB = SizeTB * 1024
)

var StrengthTable = []string{"0", "0", "25", "50", "75", "100"}
var RadioTable = []string{"-", "LTE", "EVD0", "CDMA1x", "WCDMA", "GSM", "HSUPA", "HSPA+", "DC-HSPA+", "EDGE", "GPRS"}

type NetworkStatus struct {
	Strength      int
	State         NetState
	RoamStatus    int
	Radio         int
	Network       string
	PINStatus     int
	ShowUnreadSMS int
	LastTime      int
	GetUnreadSMS  int
	ConnectedTime int
	CurrentUp     int
	CurrentDown   int
	TotalUp       int
	TotalDown     int
	ServiceStatus int
}

var modemOnline = false
var networkStatus = NetworkStatus{}

func bytesToHumanReadable(bytes int) string {
	switch {
	case bytes >= SizePB:
		return fmt.Sprintf("%.2fPB", float32(bytes)/float32(SizePB))
	case bytes >= SizeTB:
		return fmt.Sprintf("%.2fTB", float32(bytes)/float32(SizeTB))
	case bytes >= SizeGB:
		return fmt.Sprintf("%.2fGB", float32(bytes)/float32(SizeGB))
	case bytes >= SizeMB:
		return fmt.Sprintf("%.2fMB", float32(bytes)/float32(SizeMB))
	case bytes >= SizeKB:
		return fmt.Sprintf("%.2fKB", float32(bytes)/float32(SizeKB))
	default:
		return fmt.Sprintf("%dB", bytes)
	}
}

//5;2;0;9;Telenor SE;1;;;;797;4044181;1603028;59801;1274938731;83429417;2;3608;4848;
func parseStatusString(data string) {
	status := strings.Split(data, ";")

	networkStatus.Strength, _ = strconv.Atoi(status[0])
	netState, _ := strconv.Atoi(status[1])
	if netState == 2 {
		networkStatus.State = StateConnected
	} else {
		networkStatus.State = StateDisconnected
	}
	networkStatus.RoamStatus, _ = strconv.Atoi(status[2])
	networkStatus.Radio, _ = strconv.Atoi(status[3])
	networkStatus.Network = status[4]
	networkStatus.PINStatus, _ = strconv.Atoi(status[5])
	networkStatus.ShowUnreadSMS, _ = strconv.Atoi(status[6])
	networkStatus.LastTime, _ = strconv.Atoi(status[7])
	networkStatus.GetUnreadSMS, _ = strconv.Atoi(status[8])
	networkStatus.ConnectedTime, _ = strconv.Atoi(status[9])
	networkStatus.CurrentDown, _ = strconv.Atoi(status[10])
	networkStatus.CurrentUp, _ = strconv.Atoi(status[11])
	networkStatus.TotalDown, _ = strconv.Atoi(status[13])
	networkStatus.TotalUp, _ = strconv.Atoi(status[14])
	networkStatus.ServiceStatus, _ = strconv.Atoi(status[15])

	if networkStatus.Radio > -1 {
		fmt.Printf("Radio: %s\n", RadioTable[networkStatus.Radio])
	}
	fmt.Printf("Network: %s\n", networkStatus.Network)
	fmt.Printf("PINStatus: %d\n", networkStatus.PINStatus)
	//fmt.Printf("LastTime: %s\n", time.Unix(int64(networkStatus.LastTime), 0).String())
	hour := networkStatus.ConnectedTime / 3000
	min := networkStatus.ConnectedTime / 60
	sec := networkStatus.ConnectedTime - (hour * 360) - (min * 60)
	fmt.Printf("ConnectedTime: %d:%d:%d\n", hour, min, sec)
	fmt.Printf("CurrentDown: %s\n", bytesToHumanReadable(networkStatus.CurrentDown))
	fmt.Printf("CurrentUp: %s\n", bytesToHumanReadable(networkStatus.CurrentUp))
	fmt.Printf("TotalDown: %s\n", bytesToHumanReadable(networkStatus.TotalDown))
	fmt.Printf("TotalUp: %s\n", bytesToHumanReadable(networkStatus.TotalUp))
	fmt.Printf("ServiceStatus: %d\n", networkStatus.ServiceStatus)
}

func pollStatus(indicator *gotk3.AppIndicatorGotk3, menuCurrent, menuTotal *gtk.MenuItem) {
	ticker := time.Tick(time.Second)

	for _ = range ticker {
		req := fmt.Sprintf("http://192.168.0.1/goform/status_update?status_flag=1&rd=%f", rand.Float32())
		if response, err := http.Get(req); err != nil {
			if modemOnline {
				modemOnline = false
				indicator.SetIcon("network-error", "Modem offline")
			}
			fmt.Println("Could not connect, modem not available?")
		} else {
			defer response.Body.Close()
			if data, err := ioutil.ReadAll(response.Body); err != nil {
				fmt.Println("Error occurred while reading data.")
			} else {
				if !modemOnline {
					modemOnline = true
				}
				fmt.Println(string(data))
				parseStatusString(string(data))

				strength := StrengthTable[networkStatus.Strength]
				indicator.SetIcon("nm-signal-"+strength, "Modem online")
				if networkStatus.Radio > -1 {
					indicator.SetLabel(RadioTable[networkStatus.Radio], "")
				} else {
					indicator.SetLabel("", "")
				}

				<-time.After(time.Millisecond * 10)
				currentStr := fmt.Sprintf("Current Transfer - U:%s | D:%s", bytesToHumanReadable(networkStatus.CurrentUp), bytesToHumanReadable(networkStatus.CurrentDown))
				menuCurrent.SetLabel(currentStr)

				<-time.After(time.Millisecond * 10)
				totalStr := fmt.Sprintf("Total Transfer - U:%s | D:%s", bytesToHumanReadable(networkStatus.TotalUp), bytesToHumanReadable(networkStatus.TotalDown))
				menuTotal.SetLabel(totalStr)
			}
		}
	}
}

func main() {
	gtk.Init(nil)

	menu, _ := gtk.MenuNew()

	menuCurrentTransfer, _ := gtk.MenuItemNewWithLabel("Current Transfer - ##")
	menuCurrentTransfer.Show()
	menu.Append(menuCurrentTransfer)

	menuTotalTransfer, _ := gtk.MenuItemNewWithLabel("Total Transfer - ##")
	menuTotalTransfer.Show()
	menu.Append(menuTotalTransfer)

	menuQuit, _ := gtk.MenuItemNewWithLabel("Quit")
	menuQuit.Connect("activate", func() {
		gtk.MainQuit()
	})
	menuQuit.Show()
	menu.Append(menuQuit)

	indicator := gotk3.NewAppIndicator("bb-4g-modem-indicator", "nm-signal-0", appindicator.CategoryCommunications)
	indicator.SetStatus(appindicator.StatusActive)
	indicator.SetMenu(menu)

	go pollStatus(indicator, menuCurrentTransfer, menuTotalTransfer)

	gtk.Main()
}
<commit_msg>Some cleanup.<commit_after>package main

import (
	"fmt"
	"github.com/doxxan/appindicator"
	"github.com/doxxan/appindicator/gtk-extensions/gotk3"
	"github.com/doxxan/gotk3/gtk"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"strings"
	"time"
)

type NetState int

const (
	StateDisconnected NetState = iota
	StateConnected
)

const (
	SizeKB = 1024
	SizeMB = SizeKB * 1024
	SizeGB = SizeMB * 1024
	SizeTB = SizeGB * 1024
	SizePB = SizeTB * 1024
)

var StrengthTable = []string{"0", "0", "25", "50", "75", "100"}
var RadioTable = []string{"-", "LTE", "EVD0", "CDMA1x", "WCDMA", "GSM", "HSUPA", "HSPA+", "DC-HSPA+", "EDGE", "GPRS"}

type NetworkStatus struct {
	Strength      int
	State         NetState
	RoamStatus    int
	Radio         int
	Network       string
	PINStatus     int
	ShowUnreadSMS int
	LastTime      int
	GetUnreadSMS  int
	ConnectedTime int
	CurrentUp     int
	CurrentDown   int
	TotalUp       int
	TotalDown     int
	ServiceStatus int
	SpeedDown     int
	SpeedUp       int
}

var modemOnline = false
var networkStatus = NetworkStatus{}

func bytesToQualifier(bytes int) int {
	switch {
	case bytes >= SizePB:
		return SizePB
	case bytes >= SizeTB:
		return SizeTB
	case bytes >= SizeGB:
		return SizeGB
	case bytes >= SizeMB:
		return SizeMB
	case bytes >= SizeKB:
		return SizeKB
	default:
		return 1
	}
}

func bytesToHumanReadable(bytes int) string {
	switch {
	case bytes >= SizePB:
		return fmt.Sprintf("%.2fPB", float32(bytes)/float32(SizePB))
	case bytes >= SizeTB:
		return fmt.Sprintf("%.2fTB", float32(bytes)/float32(SizeTB))
	case bytes >= SizeGB:
		return fmt.Sprintf("%.2fGB", float32(bytes)/float32(SizeGB))
	case bytes >= SizeMB:
		return fmt.Sprintf("%.2fMB", float32(bytes)/float32(SizeMB))
	case bytes >= SizeKB:
		return fmt.Sprintf("%.2fKB", float32(bytes)/float32(SizeKB))
	default:
		return fmt.Sprintf("%dB", bytes)
	}
}

func qualifierToString(qualifier int) string {
	switch qualifier {
	case SizePB:
		return "PB"
	case SizeTB:
		return "TB"
	case SizeGB:
		return "GB"
	case SizeMB:
		return "MB"
	case SizeKB:
		return "KB"
	default:
		return "B"
	}
}

func transferToHumanReadable(upBytes, downBytes int) (up float32, down float32, qualifier string) {
	upQualifier := bytesToQualifier(upBytes)
	downQualifier := bytesToQualifier(downBytes)

	if upQualifier > downQualifier {
		up = float32(upBytes) / float32(upQualifier)
		down = float32(downBytes) / float32(upQualifier)
		qualifier = qualifierToString(upQualifier)
	} else {
		up = float32(upBytes) / float32(downQualifier)
		down = float32(downBytes) / float32(downQualifier)
		qualifier = qualifierToString(downQualifier)
	}

	return up, down, qualifier
}

//5;2;0;9;Telenor SE;1;;;;797;4044181;1603028;59801;1274938731;83429417;2;3608;4848;
func parseStatusString(data string) {
	status := strings.Split(data, ";")

	networkStatus.Strength, _ = strconv.Atoi(status[0])
	netState, _ := strconv.Atoi(status[1])
	if netState == 2 {
		networkStatus.State = StateConnected
	} else {
		networkStatus.State = StateDisconnected
	}
	networkStatus.RoamStatus, _ = strconv.Atoi(status[2])
	networkStatus.Radio, _ = strconv.Atoi(status[3])
	networkStatus.Network = status[4]
	networkStatus.PINStatus, _ = strconv.Atoi(status[5])
	networkStatus.ShowUnreadSMS, _ = strconv.Atoi(status[6])
	networkStatus.LastTime, _ = strconv.Atoi(status[7])
	networkStatus.GetUnreadSMS, _ = strconv.Atoi(status[8])
	networkStatus.ConnectedTime, _ = strconv.Atoi(status[9])
	networkStatus.CurrentDown, _ = strconv.Atoi(status[10])
	networkStatus.CurrentUp, _ = strconv.Atoi(status[11])
	networkStatus.TotalDown, _ = strconv.Atoi(status[13])
	networkStatus.TotalUp, _ = strconv.Atoi(status[14])
	networkStatus.ServiceStatus, _ = strconv.Atoi(status[15])
	networkStatus.SpeedDown, _ = strconv.Atoi(status[16])
	networkStatus.SpeedUp, _ = strconv.Atoi(status[17])

	if networkStatus.Radio > -1 {
		fmt.Printf("Radio: %s\n", RadioTable[networkStatus.Radio])
	}
	fmt.Printf("Network: %s\n", networkStatus.Network)
	fmt.Printf("PINStatus: %d\n", networkStatus.PINStatus)
	//fmt.Printf("LastTime: %s\n", time.Unix(int64(networkStatus.LastTime), 0).String())
	hour := networkStatus.ConnectedTime / 3000
	min := networkStatus.ConnectedTime / 60
	sec := networkStatus.ConnectedTime - (hour * 360) - (min * 60)
	fmt.Printf("ConnectedTime: %d:%d:%d\n", hour, min, sec)
	fmt.Printf("CurrentDown: %s\n", bytesToHumanReadable(networkStatus.CurrentDown))
	fmt.Printf("CurrentUp: %s\n", bytesToHumanReadable(networkStatus.CurrentUp))
	fmt.Printf("TotalDown: %s\n", bytesToHumanReadable(networkStatus.TotalDown))
	fmt.Printf("TotalUp: %s\n", bytesToHumanReadable(networkStatus.TotalUp))
	fmt.Printf("ServiceStatus: %d\n", networkStatus.ServiceStatus)
	fmt.Printf("SpeedDown: %s\n", bytesToHumanReadable(networkStatus.SpeedDown))
	fmt.Printf("SpeedUp: %s\n", bytesToHumanReadable(networkStatus.SpeedUp))
}

func pollStatus(indicator *gotk3.AppIndicatorGotk3, menuCurrent, menuTotal *gtk.MenuItem) {
	ticker := time.Tick(time.Second)

	for _ = range ticker {
		req := fmt.Sprintf("http://192.168.0.1/goform/status_update?status_flag=1&rd=%f", rand.Float32())
		if response, err := http.Get(req); err != nil {
			if modemOnline {
				modemOnline = false
				indicator.SetIcon("network-error", "Modem offline")
				indicator.SetLabel("", "")
			}
			fmt.Println("Could not connect, modem not available?")
		} else {
			defer response.Body.Close()
			if data, err := ioutil.ReadAll(response.Body); err != nil {
				fmt.Println("Error occurred while reading data.")
			} else {
				if !modemOnline {
					modemOnline = true
				}
				fmt.Println(string(data))
				parseStatusString(string(data))

				strength := StrengthTable[networkStatus.Strength]
				indicator.SetIcon("nm-signal-"+strength, "Modem online")
				if networkStatus.Radio > -1 {
					indicator.SetLabel(RadioTable[networkStatus.Radio], "")
				} else {
					indicator.SetLabel("", "")
				}

				<-time.After(time.Millisecond * 10)
				cUp, cDown, cQual := transferToHumanReadable(networkStatus.CurrentUp, networkStatus.CurrentDown)
				currentStr := fmt.Sprintf("Current Transfer - %.2f/%.2f%s", cUp, cDown, cQual)
				menuCurrent.SetLabel(currentStr)

				<-time.After(time.Millisecond * 10)
				tUp, tDown, tQual := transferToHumanReadable(networkStatus.TotalUp, networkStatus.TotalDown)
				totalStr := fmt.Sprintf("Total Transfer - %.2f/%.2f%s", tUp, tDown, tQual)
				menuTotal.SetLabel(totalStr)
			}
		}
	}
}

func main() {
	gtk.Init(nil)

	menu, _ := gtk.MenuNew()

	menuCurrentTransfer, _ := gtk.MenuItemNewWithLabel("Current Transfer - ##")
	menuCurrentTransfer.Show()
	menu.Append(menuCurrentTransfer)

	menuTotalTransfer, _ := gtk.MenuItemNewWithLabel("Total Transfer - ##")
	menuTotalTransfer.Show()
	menu.Append(menuTotalTransfer)

	menuQuit, _ := gtk.MenuItemNewWithLabel("Quit")
	menuQuit.Connect("activate", func() {
		gtk.MainQuit()
	})
	menuQuit.Show()
	menu.Append(menuQuit)

	indicator := gotk3.NewAppIndicator("bb-4g-modem-indicator", "network-error", appindicator.CategoryCommunications)
	indicator.SetStatus(appindicator.StatusActive)
	indicator.SetMenu(menu)

	go pollStatus(indicator, menuCurrentTransfer, menuTotalTransfer)

	gtk.Main()
}
<|endoftext|>


<commit_before>// go-callvis: a tool to help visualize the call graph of a Go program.
//
package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/pointer"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"
)

var Version = "0.0.0-src"

var (
	focusFlag   = flag.String("focus", "main", "Focus package with name or import path.")
	limitFlag   = flag.String("limit", "", "Limit package paths to prefix. (separate multiple by comma)")
	groupFlag   = flag.String("group", "", "Grouping functions by [pkg, type] (separate multiple by comma).")
	ignoreFlag  = flag.String("ignore", "", "Ignore package paths with prefix (separate multiple by comma).")
	nostdFlag   = flag.Bool("nostd", false, "Omit calls to/from std packages.")
	testFlag    = flag.Bool("tests", false, "Include test code.")
	debugFlag   = flag.Bool("debug", false, "Enable verbose log.")
	versionFlag = flag.Bool("version", false, "Show version and exit.")
)

func main() {
	// Graphviz options
	flag.UintVar(&minlen, "minlen", 2, "Minimum edge length (for wider output).")
	flag.Float64Var(&nodesep, "nodesep", 0.35, "Minimum space between two adjacent nodes in the same rank (for taller output).")

	flag.Parse()

	if *versionFlag {
		fmt.Fprintf(os.Stderr, "go-callvis %s\n", Version)
		os.Exit(0)
	}
	if *debugFlag {
		log.SetFlags(log.Lmicroseconds)
	}

	args := flag.Args()
	tests := *testFlag
	focus := *focusFlag
	nostd := *nostdFlag
	/*if mains, err := getMains(conf focusFlag, groupBy, limitPaths, ignorePaths, *nostdFlag, *testFlag,, flag.Args()); err != nil {
		fmt.Fprintf(os.Stderr, "go-callvis: %s\n", err)
		os.Exit(1)
	}*/
	if len(args) == 0 {
		log.Fatalln("missing arguments")
	}

	t0 := time.Now()
	conf := loader.Config{Build: &build.Default}
	_, err := conf.FromArgs(args, tests)
	if err != nil {
		log.Fatalln("invalid args:", err)
	}
	load, err := conf.Load()
	if err != nil {
		log.Fatalln("failed conf load:", err)
	}
	logf("loading took: %v", time.Since(t0))
	logf("%d imported (%d created)", len(load.Imported), len(load.Created))

	t0 = time.Now()
	prog := ssautil.CreateProgram(load, 0)
	prog.Build()
	pkgs := prog.AllPackages()
	logf("building took: %v", time.Since(t0))

	var mains []*ssa.Package
	if tests {
		for _, pkg := range pkgs {
			if main := prog.CreateTestMainPackage(pkg); main != nil {
				mains = append(mains, main)
			}
		}
		if mains == nil {
			log.Fatalln("no tests")
		}
	} else {
		mains = append(mains, ssautil.MainPackages(pkgs)...)
		if len(mains) == 0 {
			log.Fatalln("no main packages")
		}
	}
	logf("%d packages (%d main)", len(pkgs), len(mains))

	t0 = time.Now()
	ptrcfg := &pointer.Config{
		Mains:          mains,
		BuildCallGraph: true,
	}
	result, err := pointer.Analyze(ptrcfg)
	if err != nil {
		log.Fatalln("analyze failed:", err)
	}
	logf("analysis took: %v", time.Since(t0))

	handler := func(w http.ResponseWriter, r *http.Request) {
		if f := r.FormValue("f"); f != "" {
			focus = f
		}

		groupBy := make(map[string]bool)
		for _, g := range strings.Split(*groupFlag, ",") {
			g := strings.TrimSpace(g)
			if g == "" {
				continue
			}
			if g != "pkg" && g != "type" {
				fmt.Fprintf(os.Stderr, "go-callvis: %s\n", "invalid group option")
				os.Exit(1)
			}
			groupBy[g] = true
		}

		limitPaths := []string{}
		for _, p := range strings.Split(*limitFlag, ",") {
			p = strings.TrimSpace(p)
			if p != "" {
				limitPaths = append(limitPaths, p)
			}
		}

		ignorePaths := []string{}
		for _, p := range strings.Split(*ignoreFlag, ",") {
			p = strings.TrimSpace(p)
			if p != "" {
				ignorePaths = append(ignorePaths, p)
			}
		}

		var focusPkg *build.Package
		if focus != "" {
			focusPkg, err = conf.Build.Import(focus, "", 0)
			if err != nil {
				if strings.Contains(focus, "/") {
					log.Fatalln("failed:", err)
				}
				// try to find package by name
				var foundPaths []string
				for _, p := range pkgs {
					if p.Pkg.Name() == focus {
						foundPaths = append(foundPaths, p.Pkg.Path())
					}
				}
				if len(foundPaths) == 0 {
					log.Fatalln("failed:", err)
				} else if len(foundPaths) > 1 {
					for _, p := range foundPaths {
						fmt.Fprintf(os.Stderr, " - %s\n", p)
					}
					log.Fatalf("found %d packages with name %q, use import path not name", len(foundPaths), focus)
				}
				if focusPkg, err = conf.Build.Import(foundPaths[0], "", 0); err != nil {
					log.Fatalln("failed:", err)
				}
			}
			logf("focusing: %v", focusPkg.ImportPath)
		}

		out, err := printOutput(mains[0].Pkg, result.CallGraph,
			focusPkg, limitPaths, ignorePaths, groupBy, nostd)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		fmt.Fprintln(w, out)
	}

	//handler()
	/*	fmt.Println("\n\n//-----")
		nostd = false
		handler()*/

	http.HandleFunc("/", handler)

	log.Println("serving..")

	log.Fatal(http.ListenAndServe(":7878", nil))
}

/*
func getMains( ctxt *build.Context, focus string, groupBy map[string]bool, limitPaths, ignorePaths []string, nostd, tests bool, args []string) ([]*ssa.Package, error) {

    return mains, result, nil
}*/
/*
func serve(mainPkg *types.Package, ) {
}*/

func logf(f string, a ...interface{}) {
	if *debugFlag {
		log.Printf(f, a...)
	}
}
<commit_msg>Serving SVG images<commit_after>// go-callvis: a tool to help visualize the call graph of a Go program.
//
package main

import (
	"flag"
	"fmt"
	"go/build"
	"log"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/go/pointer"
	"golang.org/x/tools/go/ssa"
	"golang.org/x/tools/go/ssa/ssautil"
)

var Version = "0.0.0-src"

var (
	focusFlag   = flag.String("focus", "main", "Focus package with name or import path.")
	limitFlag   = flag.String("limit", "", "Limit package paths to prefix. (separate multiple by comma)")
	groupFlag   = flag.String("group", "", "Grouping functions by [pkg, type] (separate multiple by comma).")
	ignoreFlag  = flag.String("ignore", "", "Ignore package paths with prefix (separate multiple by comma).")
	nostdFlag   = flag.Bool("nostd", false, "Omit calls to/from std packages.")
	testFlag    = flag.Bool("tests", false, "Include test code.")
	debugFlag   = flag.Bool("debug", false, "Enable verbose log.")
	versionFlag = flag.Bool("version", false, "Show version and exit.")
)

func main() {
	// Graphviz options
	flag.UintVar(&minlen, "minlen", 2, "Minimum edge length (for wider output).")
	flag.Float64Var(&nodesep, "nodesep", 0.35, "Minimum space between two adjacent nodes in the same rank (for taller output).")

	flag.Parse()

	if *versionFlag {
		fmt.Fprintf(os.Stderr, "go-callvis %s\n", Version)
		os.Exit(0)
	}
	if *debugFlag {
		log.SetFlags(log.Lmicroseconds)
	}

	args := flag.Args()
	tests := *testFlag
	focus := *focusFlag
	nostd := *nostdFlag
	/*if mains, err := getMains(conf focusFlag, groupBy, limitPaths, ignorePaths, *nostdFlag, *testFlag,, flag.Args()); err != nil {
		fmt.Fprintf(os.Stderr, "go-callvis: %s\n", err)
		os.Exit(1)
	}*/
	if len(args) == 0 {
		log.Fatalln("missing arguments")
	}

	t0 := time.Now()
	conf := loader.Config{Build: &build.Default}
	_, err := conf.FromArgs(args, tests)
	if err != nil {
		log.Fatalln("invalid args:", err)
	}
	load, err := conf.Load()
	if err != nil {
		log.Fatalln("failed conf load:", err)
	}
	logf("loading took: %v", time.Since(t0))
	logf("%d imported (%d created)", len(load.Imported), len(load.Created))

	t0 = time.Now()
	prog := ssautil.CreateProgram(load, 0)
	prog.Build()
	pkgs := prog.AllPackages()
	logf("building took: %v", time.Since(t0))

	var mains []*ssa.Package
	if tests {
		for _, pkg := range pkgs {
			if main := prog.CreateTestMainPackage(pkg); main != nil {
				mains = append(mains, main)
			}
		}
		if mains == nil {
			log.Fatalln("no tests")
		}
	} else {
		mains = append(mains, ssautil.MainPackages(pkgs)...)
		if len(mains) == 0 {
			log.Fatalln("no main packages")
		}
	}
	logf("%d packages (%d main)", len(pkgs), len(mains))

	t0 = time.Now()
	ptrcfg := &pointer.Config{
		Mains:          mains,
		BuildCallGraph: true,
	}
	result, err := pointer.Analyze(ptrcfg)
	if err != nil {
		log.Fatalln("analyze failed:", err)
	}
	logf("analysis took: %v", time.Since(t0))

	handler := func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path != "/" {
			http.NotFound(w, r)
			return
		}

		f := r.FormValue("f")
		if f != "" {
			focus = f
		}

		groupBy := make(map[string]bool)
		for _, g := range strings.Split(*groupFlag, ",") {
			g := strings.TrimSpace(g)
			if g == "" {
				continue
			}
			if g != "pkg" && g != "type" {
				//fmt.Fprintf(os.Stderr, "go-callvis: %s\n", "invalid group option")
				//os.Exit(1)
				http.Error(w, "invalid group option", http.StatusInternalServerError)
				return
			}
			groupBy[g] = true
		}

		limitPaths := []string{}
		for _, p := range strings.Split(*limitFlag, ",") {
			p = strings.TrimSpace(p)
			if p != "" {
				limitPaths = append(limitPaths, p)
			}
		}

		ignorePaths := []string{}
		for _, p := range strings.Split(*ignoreFlag, ",") {
			p = strings.TrimSpace(p)
			if p != "" {
				ignorePaths = append(ignorePaths, p)
			}
		}

		var focusPkg *build.Package
		if focus != "" {
			focusPkg, err = conf.Build.Import(focus, "", 0)
			if err != nil {
				if strings.Contains(focus, "/") {
					http.Error(w, "focus failed", http.StatusInternalServerError)
					return
				}
				// try to find package by name
				var foundPaths []string
				for _, p := range pkgs {
					if p.Pkg.Name() == focus {
						foundPaths = append(foundPaths, p.Pkg.Path())
					}
				}
				if len(foundPaths) == 0 {
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				} else if len(foundPaths) > 1 {
					for _, p := range foundPaths {
						fmt.Fprintf(os.Stderr, " - %s\n", p)
					}
					err := fmt.Errorf("found %d packages with name %q, use import path not name", len(foundPaths), focus)
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
				if focusPkg, err = conf.Build.Import(foundPaths[0], "", 0); err != nil {
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}
			}
			logf("focusing: %v", focusPkg.ImportPath)
		}

		dot, err := printOutput(mains[0].Pkg, result.CallGraph,
			focusPkg, limitPaths, ignorePaths, groupBy, nostd)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		log.Println("dot to image..")
		//fmt.Fprintln(w, dot)
		img, err := dotToImage(dot)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		log.Println("serving file:", img)
		http.ServeFile(w, r, img)
	}

	//handler()
	/*	fmt.Println("\n\n//-----")
		nostd = false
		handler()*/

	http.HandleFunc("/", handler)

	log.Println("serving..")

	log.Fatal(http.ListenAndServe(":7878", nil))
}

func dotToImage(dot string) (string, error) {
	img := "/tmp/test000.svg"
	cmd := exec.Command("/usr/bin/dot", "-Tsvg", "-o", img)
	cmd.Stdin = strings.NewReader(dot)
	/*cmd.Stderr = os.Stderr
	stdin, err := cmd.StdinPipe()
	if err != nil {
		return "", err
	}*/
	/*stdout, err := cmd.StdoutPipe()
	if nil != err {
		return "", err
	}
	reader := bufio.NewReader(stdout)
	go func(reader io.Reader) {
		scanner := bufio.NewScanner(reader)
		for scanner.Scan() {
			log.Printf("Reading from subprocess: %s", scanner.Text())
			stdin.Write([]byte(dot))
		}
	}(reader)*/
	/*go func() {
		_, err := stdin.Write([]byte(dot))
		if err != nil {
			log.Println("stdin.Write error", err)
		}
	}()*/
	if err := cmd.Run(); err != nil {
		return "", err
	}
	return img, nil
}

/*
func getMains( ctxt *build.Context, focus string, groupBy map[string]bool, limitPaths, ignorePaths []string, nostd, tests bool, args []string) ([]*ssa.Package, error) {

    return mains, result, nil
}*/
/*
func serve(mainPkg *types.Package, ) {
}*/

func logf(f string, a ...interface{}) {
	if *debugFlag {
		log.Printf(f, a...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/phayes/hookserve/hookserve"
	"io"
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
)

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

	InitConfig()
	InitDB()
	InitANSI2HTML()

	// Set up HTTP paths
	githubreceive := hookserve.NewServer()
	if Config.Github.Enabled {
		githubreceive.Secret = Config.Github.Secret
		http.Handle("/postreceive", githubreceive)
		fmt.Println("Github webhook URL: http://" + Config.Host + ":" + strconv.Itoa(Config.Port) + "/postreceive")
	}
	http.HandleFunc("/", handleUI)

	// Listen and serve HTTP
	go func() {
		fmt.Println("Listening on port " + strconv.Itoa(Config.Port))
		err := http.ListenAndServe(":"+strconv.Itoa(Config.Port), nil)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	// Launch workers for running jobs
	// We have a number of workers equal to the number of cores
	for i := 1; i <= runtime.NumCPU(); i++ {
		go func() {
			for {
				event, err := PopEvent()
				if err != nil {
					log.Println(err)
				} else if event != nil {
					err = event.Report()
					if err != nil {
						log.Println(err)
					} else {
						go func() {
							status, err := event.Run()
							err = event.Finalize(status, err)
							if err != nil {
								log.Println(err)
							}
						}()
					}
				}
				time.Sleep(50 * time.Millisecond)
			}
		}()
	}

	// Loop for adding new events to the queue
	for {
		select {
		case commit := <-githubreceive.Events:
			event := Event{
				Event:  commit,
				Domain: "github.com", // For now we only support github
				Status: StatusPending,
				Time:   time.Now(),
			}

			// First check to see if the event already exists, and if it is reque it if it's not running
			checkEvent, err := GetEvent(event.Domain, event.Owner, event.Repo, event.Branch, event.Commit)
			if err != nil {
				log.Println(err)
			}
			if checkEvent != nil {
				// It's an old event, requeue it if we can
				if checkEvent.Status != StatusRunning {
					checkEvent.Status = StatusPending
					err = checkEvent.Update()
					if err != nil {
						log.Println(err)
					}
					err = checkEvent.Report()
					if err != nil {
						log.Println(err)
					}
				}
			} else {
				// It's a new event, insert it anew
				err = event.Insert()
				if err != nil {
					log.Println(err)
				}
				err = event.Report()
				if err != nil {
					log.Println(err)
				}
			}
		default:
			time.Sleep(50 * time.Millisecond)
		}
	}
}

// Handle regular UI requests
func handleUI(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	path, err := parsePath(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	// If it's a POST we re-run it
	if r.Method == "POST" {
		handleReRun(path, w, r)
		return
	}

	// Check the method
	if r.Method != "GET" {
		http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	if len(path) == 5 { // It's a single item
		handleView(path, w, r)
	} else { // It's an index request
		handleIndex(path, w, r)
	}
}

func handleReRun(path []string, w http.ResponseWriter, r *http.Request) {
	if len(path) != 5 {
		http.NotFound(w, r)
		return
	}

	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		// For now we only support github
		if path[0] != "github.com" {
			http.Error(w, "Only github.com currently supported", http.StatusInternalServerError)
		}

		// Event doesn't exist, create it and mark pending to queue it
		event := Event{
			Event: hookserve.Event{
				Owner:  path[1],
				Repo:   path[2],
				Branch: path[3],
				Commit: path[4],
				Type:   "push",
			},
			Domain: "github.com", // For now we only support github
			Status: StatusPending,
			Time:   time.Now(),
		}
		err := event.Insert()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/"+event.Path(), http.StatusSeeOther)
	} else {
		if event.Status == StatusRunning {
			http.Error(w, "Unable to re-run already running item", http.StatusInternalServerError)
			return
		}

		// We have the event, run it again
		// Save it back to the database marked as running
		event.Status = StatusRunning
		event.Log = []byte("Retrying...\n")
		err := event.Update()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}

		go func() {
			status, err := event.Run()
			err = event.Finalize(status, err)
			if err != nil {
				log.Println(err)
			}
		}()

		http.Redirect(w, r, "/"+event.Path(), 303)
	}
}

func handleView(path []string, w http.ResponseWriter, r *http.Request) {
	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		http.NotFound(w, r)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(event, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else { // Serve HTML
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		ansi2html, err := ANSI2HTML(event.String())
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Print output
		fmt.Fprintln(w, "")
		io.Copy(w, ansi2html)
		if event.Status == StatusSuccess || event.Status == StatusFailed || event.Status == StatusFailedBoot {
			fmt.Fprintln(w, "<form method='POST'><input type='submit' value='re-run'></form>")
		}
		fmt.Fprintln(w, "")
	}
}

func handleIndex(path []string, w http.ResponseWriter, r *http.Request) {
	// Handle main index -- list all events
	events, err := GetEvents(path...)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(events, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else {
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		fmt.Fprintln(w, "
")
		for _, event := range events {
			fmt.Fprintln(w, "
")
			fmt.Fprintln(w, ""+event.Time.String()+"	"+event.Status+"	"+event.Path()+"	")
			fmt.Fprintln(w, "
")
		}
		fmt.Fprintln(w, "
")
	}
}

func parsePath(path string) ([]string, error) {
	parts := strings.Split(path, "/")
	// If we have more than 6 parts, then we are trying to access a branch with a slash in it
	// as only part that is allowed to have a slash in it is the branch name
	if numparts := len(parts); numparts > 6 {
		rawparts := parts
		parts = make([]string, 6)
		parts[0] = rawparts[0]                               // root
		parts[1] = rawparts[1]                               // domain
		parts[2] = rawparts[2]                               // user
		parts[3] = rawparts[3]                               // repo
		parts[4] = strings.Join(rawparts[4:numparts-1], "/") // branch
		parts[5] = rawparts[numparts-1]                      // commit
	}
	// Filter illigal characters
	for _, part := range parts {
		if strings.ContainsAny(part, " \"\\\b\f\n\r\t\v") {
			return nil, errors.New("Illigal character in path")
		}
	}
	if len(parts) == 2 && parts[1] == "" {
		return make([]string, 0), nil
	} else {
		return parts[1:], nil
	}
}
<commit_msg>Don't abort if we cant connect to VCS mothership<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/phayes/hookserve/hookserve"
	"io"
	"log"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"
)

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

	InitConfig()
	InitDB()
	InitANSI2HTML()

	// Set up HTTP paths
	githubreceive := hookserve.NewServer()
	if Config.Github.Enabled {
		githubreceive.Secret = Config.Github.Secret
		http.Handle("/postreceive", githubreceive)
		fmt.Println("Github webhook URL: http://" + Config.Host + ":" + strconv.Itoa(Config.Port) + "/postreceive")
	}
	http.HandleFunc("/", handleUI)

	// Listen and serve HTTP
	go func() {
		fmt.Println("Listening on port " + strconv.Itoa(Config.Port))
		err := http.ListenAndServe(":"+strconv.Itoa(Config.Port), nil)
		if err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	// Launch workers for running jobs
	// We have a number of workers equal to the number of cores
	for i := 1; i <= runtime.NumCPU(); i++ {
		go func() {
			for {
				event, err := PopEvent()
				if err != nil {
					log.Println(err)
				} else if event != nil {
					err = event.Report()
					if err != nil {
						// If we can't update the status on the source-control system, then just log it and continue
						event.Log = append(event.Log, []byte(err.Error()+"\n")...)
						event.Update()
						log.Println(err)
					}
					status, err := event.Run()
					err = event.Finalize(status, err)
					if err != nil {
						log.Println(err)
					}
				}
				time.Sleep(50 * time.Millisecond)
			}
		}()
	}

	// Loop for adding new events to the queue
	for {
		select {
		case commit := <-githubreceive.Events:
			event := Event{
				Event:  commit,
				Domain: "github.com", // For now we only support github
				Status: StatusPending,
				Time:   time.Now(),
			}

			// First check to see if the event already exists, and if it is reque it if it's not running
			checkEvent, err := GetEvent(event.Domain, event.Owner, event.Repo, event.Branch, event.Commit)
			if err != nil {
				log.Println(err)
			}
			if checkEvent != nil {
				// It's an old event, requeue it if we can
				if checkEvent.Status != StatusRunning {
					checkEvent.Status = StatusPending
					err = checkEvent.Update()
					if err != nil {
						log.Println(err)
					}
					err = checkEvent.Report()
					if err != nil {
						log.Println(err)
					}
				}
			} else {
				// It's a new event, insert it anew
				err = event.Insert()
				if err != nil {
					log.Println(err)
				}
				err = event.Report()
				if err != nil {
					log.Println(err)
				}
			}
		default:
			time.Sleep(50 * time.Millisecond)
		}
	}
}

// Handle regular UI requests
func handleUI(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()

	path, err := parsePath(r.URL.Path)
	if err != nil {
		http.NotFound(w, r)
		return
	}

	// If it's a POST we re-run it
	if r.Method == "POST" {
		handleReRun(path, w, r)
		return
	}

	// Check the method
	if r.Method != "GET" {
		http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
		return
	}

	if len(path) == 5 { // It's a single item
		handleView(path, w, r)
	} else { // It's an index request
		handleIndex(path, w, r)
	}
}

func handleReRun(path []string, w http.ResponseWriter, r *http.Request) {
	if len(path) != 5 {
		http.NotFound(w, r)
		return
	}

	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		// For now we only support github
		if path[0] != "github.com" {
			http.Error(w, "Only github.com currently supported", http.StatusInternalServerError)
		}

		// Event doesn't exist, create it and mark pending to queue it
		event := Event{
			Event: hookserve.Event{
				Owner:  path[1],
				Repo:   path[2],
				Branch: path[3],
				Commit: path[4],
				Type:   "push",
			},
			Domain: "github.com", // For now we only support github
			Status: StatusPending,
			Time:   time.Now(),
		}
		err := event.Insert()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}
		http.Redirect(w, r, "/"+event.Path(), http.StatusSeeOther)
	} else {
		if event.Status == StatusRunning {
			http.Error(w, "Unable to re-run already running item", http.StatusInternalServerError)
			return
		}

		// We have the event, run it again
		// Save it back to the database marked as running
		event.Status = StatusRunning
		event.Log = []byte("Retrying...\n")
		err := event.Update()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		err = event.Report()
		if err != nil {
			log.Println(err)
		}

		go func() {
			status, err := event.Run()
			err = event.Finalize(status, err)
			if err != nil {
				log.Println(err)
			}
		}()

		http.Redirect(w, r, "/"+event.Path(), 303)
	}
}

func handleView(path []string, w http.ResponseWriter, r *http.Request) {
	event, err := GetEvent(path[0], path[1], path[2], path[3], path[4])
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if event == nil {
		http.NotFound(w, r)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(event, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else { // Serve HTML
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		ansi2html, err := ANSI2HTML(event.String())
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Print output
		fmt.Fprintln(w, "")
		io.Copy(w, ansi2html)
		if event.Status == StatusSuccess || event.Status == StatusFailed || event.Status == StatusFailedBoot {
			fmt.Fprintln(w, "<form method='POST'><input type='submit' value='re-run'></form>")
		}
		fmt.Fprintln(w, "")
	}
}

func handleIndex(path []string, w http.ResponseWriter, r *http.Request) {
	// Handle main index -- list all events
	events, err := GetEvents(path...)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	if r.Header.Get("Accept") == "application/json" {
		w.Header().Set("Content-Type", "application/json; charset=UTF-8")
		jbytes, err := json.MarshalIndent(events, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else {
		w.Header().Set("Content-Type", "text/html; charset=UTF-8")
		fmt.Fprintln(w, "
")
		for _, event := range events {
			fmt.Fprintln(w, "
")
			fmt.Fprintln(w, ""+event.Time.String()+"	"+event.Status+"	"+event.Path()+"	")
			fmt.Fprintln(w, "
")
		}
		fmt.Fprintln(w, "
")
	}
}

func parsePath(path string) ([]string, error) {
	parts := strings.Split(path, "/")
	// If we have more than 6 parts, then we are trying to access a branch with a slash in it
	// as only part that is allowed to have a slash in it is the branch name
	if numparts := len(parts); numparts > 6 {
		rawparts := parts
		parts = make([]string, 6)
		parts[0] = rawparts[0]                               // root
		parts[1] = rawparts[1]                               // domain
		parts[2] = rawparts[2]                               // user
		parts[3] = rawparts[3]                               // repo
		parts[4] = strings.Join(rawparts[4:numparts-1], "/") // branch
		parts[5] = rawparts[numparts-1]                      // commit
	}
	// Filter illigal characters
	for _, part := range parts {
		if strings.ContainsAny(part, " \"\\\b\f\n\r\t\v") {
			return nil, errors.New("Illigal character in path")
		}
	}
	if len(parts) == 2 && parts[1] == "" {
		return make([]string, 0), nil
	} else {
		return parts[1:], nil
	}
}
<|endoftext|>