<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],
			},
			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" {
		jbytes, err := json.MarshalIndent(event, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else { // Serve HTML
		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" {
		jbytes, err := json.MarshalIndent(events, " ", "  ")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		w.Write(jbytes)
	} else {
		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 len(parts) > 6 {
		return nil, errors.New("Invalid Path")
	}
	// 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>Properly handling http content negotiation<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 {
						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],
			},
			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.Add("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.Add("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.Add("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.Add("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 len(parts) > 6 {
		return nil, errors.New("Invalid Path")
	}
	// 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|>


<commit_before>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// var Version string
const Version = "0.9.4"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	stubzones     = ""
	hostPort      = ""
	listen        = ""
)

var exitErr error

func init() {
	log.SetFormatter(&log.TextFormatter{DisableTimestamp: true})
	log.SetOutput(os.Stderr)
}

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS proxy for Docker containers"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "listen address: ‘host[:port]‘",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "make go-dnsmasq the local primary nameserver (updates /etc/resolv.conf)",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "comma-separated list of name servers: ‘host[:port]‘",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringFlag{
			Name:   "stubzones, z",
			Value:  "",
			Usage:  "domains to resolve using a specific nameserver: ‘fqdn[,fqdn]/host[:port]‘",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "full path to hostsfile (e.g. ‘/etc/hosts‘)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "how frequently to poll hostsfile (in seconds, ‘0‘ to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "specify SEARCH domains taking precedence over /etc/resolv.conf: ‘fqdn[,fqdn]‘",
			EnvVar: "DNSMASQ_SEARCH",
		},
		cli.BoolFlag{
			Name:   "append-search-domains, a",
			Usage:  "enable suffixing single-label queries with SEARCH domains",
			EnvVar: "DNSMASQ_APPEND",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "capacity of the response cache (‘0‘ to disable caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  server.RCacheTtl,
			Usage:  "TTL of entries in the response cache",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "enable round robin of A/AAAA replies",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "bind to socket(s) activated by systemd (ignores --listen)",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
	}
	app.Action = func(c *cli.Context) {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
			sig := <-c
			log.Infoln("Application exit requested by signal:", sig)
			exitReason <- nil
		}()

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}

				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("This nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {

				if dns.CountLabel(domain) < 2 {
					log.Fatalf("This search domain is not a FQDN: %s", domain)
				}
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		if listen = c.String("listen"); !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("The listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			AppendDomain:    c.Bool("append-search-domains"),
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			ReadTimeout:     0,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.SetDefaults(config); err != nil {
			if !config.NoRec && len(config.Nameservers) == 0 {
				log.Fatalf("No nameservers found in resolv.conf and --nameservers option not supplied: %s", err)
			} else if config.AppendDomain && len(config.SearchDomains) == 0 {
				log.Fatalf("No search domains found in resolv.conf and --search-domains option not supplied: %s", err)
			} else {
				log.Warnf("Error parsing resolv.conf: %s", err)
			}
		}

		if stubzones = c.String("stubzones"); stubzones != "" {
			stubmap := make(map[string][]string)
			segments := strings.Split(stubzones, "/")
			if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
				log.Fatalf("The --stubzones argument is invalid")
			}

			hostPort = segments[1]
			if !strings.Contains(hostPort, ":") {
				hostPort += ":53"
			}

			if err := validateHostPort(hostPort); err != nil {
				log.Fatalf("This stubzones server address invalid: %s", err)
			}

			for _, sdomain := range strings.Split(segments[0], ",") {
				if dns.CountLabel(sdomain) < 2 {
					log.Fatalf("This stubzones domain is not a FQDN: %s", sdomain)
				}
				sdomain = dns.Fqdn(sdomain)
				stubmap[sdomain] = append(stubmap[sdomain], hostPort)
			}

			config.Stub = &stubmap
		}

		log.Infof("Starting go-dnsmasq server %s ...", Version)
		if config.AppendDomain {
			log.Infof("Search domains in use: %v", config.SearchDomains)
		}

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("Error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Warnf("Failed to register as default resolver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("Server error: %s", err)
		}
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("Bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("Bad port number %s", port)
	}
	return nil
}
<commit_msg>Adds logging to syslog<commit_after>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"log/syslog"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog"
	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// var Version string
const Version = "0.9.4"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	stubzones     = ""
	hostPort      = ""
	listen        = ""
)

var exitErr error

func init() {
	log.SetFormatter(&log.TextFormatter{DisableTimestamp: true})
	log.SetOutput(os.Stderr)
}

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS proxy for Docker containers"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "listen address: ‘host[:port]‘",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "make go-dnsmasq the local primary nameserver (updates /etc/resolv.conf)",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "comma-separated list of name servers: ‘host[:port]‘",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringFlag{
			Name:   "stubzones, z",
			Value:  "",
			Usage:  "domains to resolve using a specific nameserver: ‘fqdn[,fqdn]/host[:port]‘",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "full path to hostsfile (e.g. ‘/etc/hosts‘)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "how frequently to poll hostsfile (in seconds, ‘0‘ to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "specify SEARCH domains taking precedence over /etc/resolv.conf: ‘fqdn[,fqdn]‘",
			EnvVar: "DNSMASQ_SEARCH",
		},
		cli.BoolFlag{
			Name:   "append-search-domains, a",
			Usage:  "enable suffixing single-label queries with SEARCH domains",
			EnvVar: "DNSMASQ_APPEND",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "capacity of the response cache (‘0‘ to disable caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  server.RCacheTtl,
			Usage:  "TTL of entries in the response cache",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "enable round robin of A/AAAA replies",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "bind to socket(s) activated by systemd (ignores --listen)",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
		cli.BoolFlag{
			Name:   "syslog",
			Usage:  "enable syslog logging",
			EnvVar: "DNSMASQ_SYSLOG",
		},
	}
	app.Action = func(c *cli.Context) {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
			sig := <-c
			log.Infoln("Application exit requested by signal:", sig)
			exitReason <- nil
		}()

		if c.Bool("verbose") {
			log.SetLevel(log.DebugLevel)
		}

		if c.Bool("syslog") {
			hook, err := logrus_syslog.NewSyslogHook("", "", syslog.LOG_LOCAL0|syslog.LOG_INFO, "go-dnsmasq")
			if err != nil {
				log.Error("Unable to connect to local syslog daemon")
			} else {
				log.AddHook(hook)
			}
		}

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}

				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("This nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {

				if dns.CountLabel(domain) < 2 {
					log.Fatalf("This search domain is not a FQDN: %s", domain)
				}
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		if listen = c.String("listen"); !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("The listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			AppendDomain:    c.Bool("append-search-domains"),
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			ReadTimeout:     0,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.SetDefaults(config); err != nil {
			if !config.NoRec && len(config.Nameservers) == 0 {
				log.Fatalf("No nameservers found in resolv.conf and --nameservers option not supplied: %s", err)
			} else if config.AppendDomain && len(config.SearchDomains) == 0 {
				log.Fatalf("No search domains found in resolv.conf and --search-domains option not supplied: %s", err)
			} else {
				log.Warnf("Error parsing resolv.conf: %s", err)
			}
		}

		if stubzones = c.String("stubzones"); stubzones != "" {
			stubmap := make(map[string][]string)
			segments := strings.Split(stubzones, "/")
			if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
				log.Fatalf("The --stubzones argument is invalid")
			}

			hostPort = segments[1]
			if !strings.Contains(hostPort, ":") {
				hostPort += ":53"
			}

			if err := validateHostPort(hostPort); err != nil {
				log.Fatalf("This stubzones server address invalid: %s", err)
			}

			for _, sdomain := range strings.Split(segments[0], ",") {
				if dns.CountLabel(sdomain) < 2 {
					log.Fatalf("This stubzones domain is not a FQDN: %s", sdomain)
				}
				sdomain = dns.Fqdn(sdomain)
				stubmap[sdomain] = append(stubmap[sdomain], hostPort)
			}

			config.Stub = &stubmap
		}

		log.Infof("Starting go-dnsmasq server %s ...", Version)
		if config.AppendDomain {
			log.Infof("Search domains in use: %v", config.SearchDomains)
		}

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("Error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Warnf("Failed to register as default resolver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("Server error: %s", err)
		}
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("Bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("Bad port number %s", port)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"encoding/csv"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/smtp"
	"os"
	"strings"
	"sync"
	"time"

	ini "gopkg.in/ini.v1"
)

var (
	errExpiringSoon error = errors.New("expiring soon")
	errExpired            = errors.New("expired")
	errTimeout            = errors.New("timeout connecting to host")
)

func main() {
	urlFile := flag.String("urls", "/etc/certwatcher/urls.csv", "path to CSV containing list of URLs to monitor")
	iniFile := flag.String("config", "/etc/certwatcher/config.ini", "path to config.ini")
	days := flag.Int("days", 30, "number of days before triggering alert")
	verbose := flag.Bool("v", false, "verbose output")

	flag.Parse()

	// read config
	cfg, err := ini.Load(*iniFile)
	if err != nil {
		log.Fatalf("could not open config file: %s", err)
	}

	// load list of hosts to watch
	f, err := os.Open(*urlFile)
	if err != nil {
		log.Fatalf("could not open URL file: %s", err)
	}

	rdr := csv.NewReader(f)
	rdr.FieldsPerRecord = 2
	records, err := rdr.ReadAll()
	if err != nil {
		log.Fatalf("could not read %s: %s", *urlFile, err)
	}

	var wg sync.WaitGroup
	for _, r := range records {
		var host, desc string
		if r[1] != "" {
			host, desc = r[0], r[1]
		} else {
			host, desc = r[0], r[0]
		}

		wg.Add(1)

		go func() {
			defer wg.Done()
			if err := check(host, "443", *days, *verbose); err != nil {
				switch err {
				case errExpiringSoon, errExpired:
					notify(host, desc, cfg, *days, err, *verbose)
					log.Printf("main: sent notification for host %s - %s", host, err)
				default:
					log.Printf("main: ERROR: unexpected error checking host %s - %s", host, err)
				}
			}
		}()
	}

	wg.Wait()
}

func check(host, port string, days int, verbose bool) error {
	var conn *tls.Conn

	errc := make(chan error, 1)
	go func() {
		var err error
		conn, err = tls.Dial("tcp", host+":"+port, &tls.Config{
			InsecureSkipVerify: true,
		})
		if err != nil {
			errc <- err
		}

		errc <- nil
	}()

	select {
	case err := <-errc:
		if err != nil {
			return err
		}
	case <-time.Tick(5 * time.Second):
		return errTimeout
	}

	defer conn.Close()
	if err := conn.Handshake(); err != nil {
		return err
	}

	for i, cert := range conn.ConnectionState().PeerCertificates {
		if cert.IsCA {
			continue
		}

		if verbose {
			log.Printf("check: %s certificate %d: expires after %s (%s)", host, i, cert.NotAfter, time.Until(cert.NotAfter))
			log.Printf("check: %s certificate %d: issuer: %s", host, i, cert.Issuer.Names)
			log.Printf("check: %s certificate %d: names: %s", host, i, cert.Subject.Names)
			log.Printf("check: %s certificate %d: DNSNames: %s", host, i, cert.DNSNames)
		}

		if time.Now().After(cert.NotAfter) {
			return errExpired
		}

		if time.Until(cert.NotAfter) < time.Duration(days)*time.Hour*24 {
			return errExpiringSoon
		}
	}

	log.Printf("check: %s - certificate is ok", host)

	return nil
}

func notify(host, desc string, cfg *ini.File, days int, err error, verbose bool) {
	section := cfg.Section("certwatcher")

	if !section.Key("sendmail").MustBool() {
		log.Println("notify: refusing to send email due to config.")
		return
	}

	port := "587"
	if section.Key("port").String() != "" {
		port = section.Key("port").String()
	}
	mailhost := section.Key("host").String()

	auth := smtp.PlainAuth("",
		section.Key("username").String(),
		section.Key("password").String(),
		mailhost,
	)

	to := []string{section.Key("rcpt").String()}
	var subject, body string
	if err == errExpiringSoon {
		subject = fmt.Sprintf("Subject: %s certificate expiring soon: %s", section.Key("subjectprefix").String(), desc)
		body = fmt.Sprintf("The SSL certificate for the host %s (%s) is expiring in less than %d days.", host, desc, days)
	} else if err == errExpired {
		subject = fmt.Sprintf("Subject: %s certificate has expired! %s", section.Key("subjectprefix").String(), desc)
		body = fmt.Sprintf("The SSL certificate for the host %s (%s) has expired!", host, desc)
	}
	msg := []byte(strings.Join([]string{subject,
		fmt.Sprintf("To: %s", strings.Join(to, ", ")),
		fmt.Sprintf("From: %s", section.Key("from").String()),
		"",
		body,
		"",
		"Please take appropriate action!",
	},
		"\r\n",
	))

	if verbose {
		log.Printf("notify: sending host %s expiration notification to %s", host, section.Key("rcpt").String())
	}

	if err := smtp.SendMail(mailhost+":"+port, auth, section.Key("from").String(), to, msg); err != nil {
		log.Fatalf("could not send email: %s", err)
	}
}
<commit_msg>Improve readability of source code<commit_after>package main

import (
	"crypto/tls"
	"encoding/csv"
	"errors"
	"flag"
	"fmt"
	"log"
	"net/smtp"
	"os"
	"strings"
	"sync"
	"time"

	ini "gopkg.in/ini.v1"
)

var (
	errExpiringSoon error = errors.New("expiring soon")
	errExpired            = errors.New("expired")
	errTimeout            = errors.New("timeout connecting to host")
)

func main() {
	urlFile := flag.String("urls", "/etc/certwatcher/urls.csv", "path to CSV containing list of URLs to monitor")
	iniFile := flag.String("config", "/etc/certwatcher/config.ini", "path to config.ini")
	days := flag.Int("days", 30, "number of days before triggering alert")
	verbose := flag.Bool("v", false, "verbose output")

	flag.Parse()

	// read config
	cfg, err := ini.Load(*iniFile)
	if err != nil {
		log.Fatalf("could not open config file: %s", err)
	}

	// load list of hosts to watch
	f, err := os.Open(*urlFile)
	if err != nil {
		log.Fatalf("could not open URL file: %s", err)
	}

	rdr := csv.NewReader(f)
	rdr.FieldsPerRecord = 2
	records, err := rdr.ReadAll()
	if err != nil {
		log.Fatalf("could not read %s: %s", *urlFile, err)
	}

	var wg sync.WaitGroup
	for _, r := range records {
		var host, desc string
		host := r[0]
		desc := r[1]
		if desc == "" {
			desc = host
		}

		wg.Add(1)

		go func() {
			defer wg.Done()
			if err := check(host, "443", *days, *verbose); err != nil {
				switch err {
				case errExpiringSoon, errExpired:
					notify(host, desc, cfg, *days, err, *verbose)
					log.Printf("main: sent notification for host %s - %s", host, err)
				default:
					log.Printf("main: ERROR: unexpected error checking host %s - %s", host, err)
				}
			}
		}()
	}

	wg.Wait()
}

func check(host, port string, days int, verbose bool) error {
	var conn *tls.Conn

	errc := make(chan error, 1)
	go func() {
		var err error
		conn, err = tls.Dial("tcp", host+":"+port, &tls.Config{
			InsecureSkipVerify: true,
		})
		if err != nil {
			errc <- err
		}

		errc <- nil
	}()

	select {
	case err := <-errc:
		if err != nil {
			return err
		}
	case <-time.Tick(5 * time.Second):
		return errTimeout
	}

	defer conn.Close()
	if err := conn.Handshake(); err != nil {
		return err
	}

	for i, cert := range conn.ConnectionState().PeerCertificates {
		if cert.IsCA {
			continue
		}

		if verbose {
			log.Printf("check: %s certificate %d: expires after %s (%s)", host, i, cert.NotAfter, time.Until(cert.NotAfter))
			log.Printf("check: %s certificate %d: issuer: %s", host, i, cert.Issuer.Names)
			log.Printf("check: %s certificate %d: names: %s", host, i, cert.Subject.Names)
			log.Printf("check: %s certificate %d: DNSNames: %s", host, i, cert.DNSNames)
		}

		if time.Now().After(cert.NotAfter) {
			return errExpired
		}

		if time.Until(cert.NotAfter) < time.Duration(days)*time.Hour*24 {
			return errExpiringSoon
		}
	}

	log.Printf("check: %s - certificate is ok", host)

	return nil
}

func notify(host, desc string, cfg *ini.File, days int, err error, verbose bool) {
	section := cfg.Section("certwatcher")

	if !section.Key("sendmail").MustBool() {
		log.Println("notify: refusing to send email due to config.")
		return
	}

	port := "587"
	if section.Key("port").String() != "" {
		port = section.Key("port").String()
	}
	mailhost := section.Key("host").String()

	auth := smtp.PlainAuth("",
		section.Key("username").String(),
		section.Key("password").String(),
		mailhost,
	)

	to := []string{section.Key("rcpt").String()}
	var subject, body string
	if err == errExpiringSoon {
		subject = fmt.Sprintf("Subject: %s certificate expiring soon: %s", section.Key("subjectprefix").String(), desc)
		body = fmt.Sprintf("The SSL certificate for the host %s (%s) is expiring in less than %d days.", host, desc, days)
	} else if err == errExpired {
		subject = fmt.Sprintf("Subject: %s certificate has expired! %s", section.Key("subjectprefix").String(), desc)
		body = fmt.Sprintf("The SSL certificate for the host %s (%s) has expired!", host, desc)
	}
	msg := []byte(strings.Join([]string{subject,
		fmt.Sprintf("To: %s", strings.Join(to, ", ")),
		fmt.Sprintf("From: %s", section.Key("from").String()),
		"",
		body,
		"",
		"Please take appropriate action!",
	},
		"\r\n",
	))

	if verbose {
		log.Printf("notify: sending host %s expiration notification to %s", host, section.Key("rcpt").String())
	}

	if err := smtp.SendMail(mailhost+":"+port, auth, section.Key("from").String(), to, msg); err != nil {
		log.Fatalf("could not send email: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
)

var name = "fillin"
var version = "v0.0.0"
var description = "fill-in your command line"
var author = "itchyny"

func main() {
	if err := Exec(); err != nil {
		log.Fatal(err)
	}
}
<commit_msg>bump up version to 0.0.1<commit_after>package main

import (
	"log"
)

var name = "fillin"
var version = "v0.0.1"
var description = "fill-in your command line"
var author = "itchyny"

func main() {
	if err := Exec(); err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>//go:generate goagen bootstrap -d github.com/tri125/gwentapi/design

package main

import (
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/tri125/gwentapi/app"
	"github.com/tri125/gwentapi/controllers"
)

var isDebug bool = true
var isVerbose bool = false
var enableGzip bool = true
var gzipLevel int = -1

var certFile string = "pathToCertFile"
var keyFile string = "pathToKeyFile"

func main() {
	// Create service
	service := goa.New("gwentapi")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(isVerbose))
	service.Use(middleware.ErrorHandler(service, isVerbose))
	service.Use(middleware.Recover())
	if enableGzip {
		service.Use(gzip.Middleware(gzipLevel))
	}
	// Mount "card" controller
	c := NewCardController(service)
	app.MountCardController(service, c)
	// Mount "faction" controller
	c2 := NewFactionController(service)
	app.MountFactionController(service, c2)
	// Mount "glyph" controller
	c3 := NewGlyphController(service)
	app.MountGlyphController(service, c3)
	// Mount "patch" controller
	c4 := NewPatchController(service)
	app.MountPatchController(service, c4)
	// Mount "phonebook" controller
	c5 := NewPhonebookController(service)
	app.MountPhonebookController(service, c5)
	// Mount "rarity" controller
	c6 := NewRarityController(service)
	app.MountRarityController(service, c6)
	// Mount "type" controller
	c8 := NewTypeController(service)
	app.MountTypeController(service, c8)

	//database
	var err error
	controllers.DBCon, err = controllers.NewDBConnection("client:thereisonlyonekinginthenorth@tcp/gwentapi?timeout=90s&strict=true&parseTime=true")
	if err != nil {
		panic(err.Error())
	}
	defer controllers.DBCon.Close()

	// Start service

	if isDebug {
		if err := service.ListenAndServe(":8080"); err != nil {
			service.LogError("startup", "err", err)
		}
	} else {
		if err := service.ListenAndServeTLS(":8080", "certFile", "keyfile"); err != nil {
			service.LogError("startup", "err", err)
		}
	}

}
<commit_msg>Fix using certFile and keyFile variable instead of string<commit_after>//go:generate goagen bootstrap -d github.com/tri125/gwentapi/design

package main

import (
	"github.com/goadesign/goa"
	"github.com/goadesign/goa/middleware"
	"github.com/goadesign/goa/middleware/gzip"
	"github.com/tri125/gwentapi/app"
	"github.com/tri125/gwentapi/controllers"
)

var isDebug bool = true
var isVerbose bool = false
var enableGzip bool = true
var gzipLevel int = -1

var certFile string = "pathToCertFile"
var keyFile string = "pathToKeyFile"

func main() {
	// Create service
	service := goa.New("gwentapi")

	// Mount middleware
	service.Use(middleware.RequestID())
	service.Use(middleware.LogRequest(isVerbose))
	service.Use(middleware.ErrorHandler(service, isVerbose))
	service.Use(middleware.Recover())
	if enableGzip {
		service.Use(gzip.Middleware(gzipLevel))
	}
	// Mount "card" controller
	c := NewCardController(service)
	app.MountCardController(service, c)
	// Mount "faction" controller
	c2 := NewFactionController(service)
	app.MountFactionController(service, c2)
	// Mount "glyph" controller
	c3 := NewGlyphController(service)
	app.MountGlyphController(service, c3)
	// Mount "patch" controller
	c4 := NewPatchController(service)
	app.MountPatchController(service, c4)
	// Mount "phonebook" controller
	c5 := NewPhonebookController(service)
	app.MountPhonebookController(service, c5)
	// Mount "rarity" controller
	c6 := NewRarityController(service)
	app.MountRarityController(service, c6)
	// Mount "type" controller
	c8 := NewTypeController(service)
	app.MountTypeController(service, c8)

	//database
	var err error
	controllers.DBCon, err = controllers.NewDBConnection("client:thereisonlyonekinginthenorth@tcp/gwentapi?timeout=90s&strict=true&parseTime=true")
	if err != nil {
		panic(err.Error())
	}
	defer controllers.DBCon.Close()

	// Start service

	if isDebug {
		if err := service.ListenAndServe(":8080"); err != nil {
			service.LogError("startup", "err", err)
		}
	} else {
		if err := service.ListenAndServeTLS(":8080", certFile, keyFile); err != nil {
			service.LogError("startup", "err", err)
		}
	}

}
<|endoftext|>


<commit_before>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A simple drum machine app.
//
// Note: This demo is an early preview of Go 1.5. In order to build this
// program as an Android APK using the gomobile tool, you need to install
// Go 1.5 from the source.
//
// Clone the source from the tip under $HOME/go directory. On Windows,
// you may like to clone the repo to your user folder, %USERPROFILE%\go.
//
//   $ git clone https://go.googlesource.com/go $HOME/go
//
// Go 1.5 requires Go 1.4. Read more about this requirement at
// http://golang.org/s/go15bootstrap.
// Set GOROOT_BOOTSTRAP to the GOROOT of your existing 1.4 installation or
// follow the steps below to checkout go1.4 from the source and build.
//
//   $ git clone https://go.googlesource.com/go $HOME/go1.4
//   $ cd $HOME/go1.4
//   $ git checkout go1.4.1
//   $ cd src && ./make.bash
//
// If you clone Go 1.4 to a different destination, set GOROOT_BOOTSTRAP
// environmental variable accordingly.
//
// Build Go 1.5 and add Go 1.5 bin to your path.
//
//   $ cd $HOME/go/src && ./make.bash
//   $ export PATH=$PATH:$HOME/go/bin
//
// Set a GOPATH if no GOPATH is set, add $GOPATH/bin to your path.
//
//   $ export GOPATH=$HOME
//   $ export PATH=$PATH:$GOPATH/bin
//
// Get the gomobile tool and initialize.
//
//   $ go get golang.org/x/mobile/cmd/gomobile
//   $ gomobile init
//
// It may take a while to initialize gomobile, please wait.
//
// Get the drum machine example and use gomobile to build or install it on your device.
//
//   $ go get -d github.com/rakyll/drummachine
//   $ gomobile build github.com/rakyll/drummachine # will build an APK
//
//   # plug your Android device to your computer or start an Android emulator.
//   # if you have adb installed on your machine, use gomobile install to
//   # build and deploy the APK to an Android target.
//   $ gomobile install github.com/rakyll/drummachine
//
// Switch to your device or emulator to start the Drum Machine application from
// the launcher.
// You can also run the application on your desktop by running the command
// below. (Note: It currently doesn't work on Windows.)
//   $ go install github.com/rakyll/drummachine && drummachine
package main

import (
	"image"
	"io"
	"log"
	"time"

	_ "image/jpeg"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/audio"
	"golang.org/x/mobile/event"
	"golang.org/x/mobile/f32"
	"golang.org/x/mobile/gl"
	"golang.org/x/mobile/sprite"
	"golang.org/x/mobile/sprite/clock"
	"golang.org/x/mobile/sprite/glsprite"
)

var (
	startClock = time.Now()
	lastClock  = clock.Time(-1)
	eng        = glsprite.Engine()

	texs []sprite.SubTex

	board *sprite.Node
)

const numDrums = 6

var (
	samples [numDrums]io.Closer
	players [numDrums]*audio.Player
)

func main() {
	// TODO(jbd): Handle touch to turn on/off the beats.
	app.Run(app.Callbacks{
		Start: start,
		Stop:  stop,
		Draw:  draw,
		Touch: touch,
	})
}

func touch(t event.Touch) {
	x, y := float32(t.Loc.X), float32(t.Loc.Y)
	i := int((x - offsetX) / (buttonW + 10))
	j := int((y - offsetY) / (buttonH + 10))
	if i < 0 || i > 3 || j < 0 || j > 3 {
		return
	}
	if t.Type == event.TouchStart {
		buttons[i][j] = true
	}
	go func() {
		time.Sleep(300 * time.Millisecond)
		buttons[i][j] = false
	}()
}

func start() {

}

func stop() {
	for _, p := range players {
		p.Close()
	}
	for _, s := range samples {
		s.Close()
	}
}

// TODO(jbd): Dynamically calculate the width and the height
// depending on the size of the screen.
const (
	offsetX = 20
	offsetY = 20
	buttonW = 50
	buttonH = 50
)

var buttons [4][4]bool

func draw() {
	if texs == nil {
		texs = loadTextures()
	}

	now := clock.Time(time.Since(startClock) * 60 / time.Second)
	if now == lastClock {
		// TODO: figure out how to limit draw callbacks to 60Hz instead of
		// burning the CPU as fast as possible.
		// TODO: (relatedly??) sync to vblank?
		return
	}
	lastClock = now
	gl.ClearColor(1, 1, 1, 1)
	gl.Clear(gl.COLOR_BUFFER_BIT)

	cfg := app.GetConfig()
	board = &sprite.Node{}
	eng.Register(board)
	eng.SetTransform(board, f32.Affine{
		{1, 0, 0},
		{0, 1, 0},
	})

	n := newNode()
	eng.SetSubTex(n, texs[texBG])
	eng.SetTransform(n, f32.Affine{
		{float32(cfg.Width), 0, 0},
		{0, float32(cfg.Height), 0},
	})
	for i := 0; i < 4; i++ {
		for j := 0; j < 4; j++ {
			drawButton(i, j)
		}
	}
	eng.Render(board, now)
}

func drawButton(i, j int) {
	n := newNode()
	if buttons[i][j] {
		eng.SetSubTex(n, texs[texButtonOn])
	} else {
		eng.SetSubTex(n, texs[texButtonOff])
	}
	eng.SetTransform(n, f32.Affine{
		{buttonW, 0, float32(offsetX + i*(buttonW+10))},
		{0, buttonH, float32(offsetY + j*(buttonW+10))},
	})
}

func newNode() *sprite.Node {
	n := &sprite.Node{}
	eng.Register(n)
	board.AppendChild(n)
	return n
}

const (
	texBG = iota
	texButtonOn
	texButtonOff
	texBrand
	texModel
	texOthers
)

func loadTextures() []sprite.SubTex {
	a, err := app.Open("sprite.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer a.Close()

	img, _, err := image.Decode(a)
	if err != nil {
		log.Fatal(err)
	}
	t, err := eng.LoadTexture(img)
	if err != nil {
		log.Fatal(err)
	}

	return []sprite.SubTex{
		texBG:        sprite.SubTex{t, image.Rect(0, 0, 26, 860)},
		texButtonOff: sprite.SubTex{t, image.Rect(94, 242, 94+150, 242+151)},
		texButtonOn:  sprite.SubTex{t, image.Rect(94, 413, 94+150, 413+151)},
		texBrand:     sprite.SubTex{t, image.Rect(94, 31, 94+227, 31+88)},
		texModel:     sprite.SubTex{t, image.Rect(162, 120, 162+140, 120+90)},
		texOthers:    sprite.SubTex{t, image.Rect(162, 120, 162+140, 120+90)},
	}
}
<commit_msg>add the brand and model.<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// A simple drum machine app.
//
// Note: This demo is an early preview of Go 1.5. In order to build this
// program as an Android APK using the gomobile tool, you need to install
// Go 1.5 from the source.
//
// Clone the source from the tip under $HOME/go directory. On Windows,
// you may like to clone the repo to your user folder, %USERPROFILE%\go.
//
//   $ git clone https://go.googlesource.com/go $HOME/go
//
// Go 1.5 requires Go 1.4. Read more about this requirement at
// http://golang.org/s/go15bootstrap.
// Set GOROOT_BOOTSTRAP to the GOROOT of your existing 1.4 installation or
// follow the steps below to checkout go1.4 from the source and build.
//
//   $ git clone https://go.googlesource.com/go $HOME/go1.4
//   $ cd $HOME/go1.4
//   $ git checkout go1.4.1
//   $ cd src && ./make.bash
//
// If you clone Go 1.4 to a different destination, set GOROOT_BOOTSTRAP
// environmental variable accordingly.
//
// Build Go 1.5 and add Go 1.5 bin to your path.
//
//   $ cd $HOME/go/src && ./make.bash
//   $ export PATH=$PATH:$HOME/go/bin
//
// Set a GOPATH if no GOPATH is set, add $GOPATH/bin to your path.
//
//   $ export GOPATH=$HOME
//   $ export PATH=$PATH:$GOPATH/bin
//
// Get the gomobile tool and initialize.
//
//   $ go get golang.org/x/mobile/cmd/gomobile
//   $ gomobile init
//
// It may take a while to initialize gomobile, please wait.
//
// Get the drum machine example and use gomobile to build or install it on your device.
//
//   $ go get -d github.com/rakyll/drummachine
//   $ gomobile build github.com/rakyll/drummachine # will build an APK
//
//   # plug your Android device to your computer or start an Android emulator.
//   # if you have adb installed on your machine, use gomobile install to
//   # build and deploy the APK to an Android target.
//   $ gomobile install github.com/rakyll/drummachine
//
// Switch to your device or emulator to start the Drum Machine application from
// the launcher.
// You can also run the application on your desktop by running the command
// below. (Note: It currently doesn't work on Windows.)
//   $ go install github.com/rakyll/drummachine && drummachine
package main

import (
	"image"
	"io"
	"log"
	"time"

	_ "image/jpeg"

	"golang.org/x/mobile/app"
	"golang.org/x/mobile/audio"
	"golang.org/x/mobile/event"
	"golang.org/x/mobile/f32"
	"golang.org/x/mobile/gl"
	"golang.org/x/mobile/sprite"
	"golang.org/x/mobile/sprite/clock"
	"golang.org/x/mobile/sprite/glsprite"
)

var (
	startClock = time.Now()
	lastClock  = clock.Time(-1)
	eng        = glsprite.Engine()

	texs []sprite.SubTex

	board *sprite.Node
)

const numDrums = 6

var (
	samples [numDrums]io.Closer
	players [numDrums]*audio.Player
)

func main() {
	// TODO(jbd): Handle touch to turn on/off the beats.
	app.Run(app.Callbacks{
		Start: start,
		Stop:  stop,
		Draw:  draw,
		Touch: touch,
	})
}

func touch(t event.Touch) {
	x, y := float32(t.Loc.X), float32(t.Loc.Y)
	i := int((x - offsetX) / (buttonW + 10))
	j := int((y - offsetY) / (buttonH + 10))
	if i < 0 || i > 3 || j < 0 || j > 3 {
		return
	}
	if t.Type == event.TouchStart {
		buttons[i][j] = true
	}
	go func() {
		time.Sleep(300 * time.Millisecond)
		buttons[i][j] = false
	}()
}

func start() {

}

func stop() {
	for _, p := range players {
		p.Close()
	}
	for _, s := range samples {
		s.Close()
	}
}

// TODO(jbd): Dynamically calculate the width and the height
// depending on the size of the screen.
const (
	offsetX = 20
	offsetY = 20
	buttonW = 50
	buttonH = 50
)

var buttons [4][4]bool

func draw() {
	if texs == nil {
		texs = loadTextures()
	}

	now := clock.Time(time.Since(startClock) * 60 / time.Second)
	if now == lastClock {
		// TODO: figure out how to limit draw callbacks to 60Hz instead of
		// burning the CPU as fast as possible.
		// TODO: (relatedly??) sync to vblank?
		return
	}
	lastClock = now
	gl.ClearColor(1, 1, 1, 1)
	gl.Clear(gl.COLOR_BUFFER_BIT)

	cfg := app.GetConfig()
	board = &sprite.Node{}
	eng.Register(board)
	eng.SetTransform(board, f32.Affine{
		{1, 0, 0},
		{0, 1, 0},
	})

	n := newNode()
	eng.SetSubTex(n, texs[texBG])
	eng.SetTransform(n, f32.Affine{
		{float32(cfg.Width), 0, 0},
		{0, float32(cfg.Height), 0},
	})
	for i := 0; i < 4; i++ {
		for j := 0; j < 4; j++ {
			drawButton(i, j)
		}
	}

	drawBrandModel()
	eng.Render(board, now)
}

func drawButton(i, j int) {
	n := newNode()
	if buttons[i][j] {
		eng.SetSubTex(n, texs[texButtonOn])
	} else {
		eng.SetSubTex(n, texs[texButtonOff])
	}
	eng.SetTransform(n, f32.Affine{
		{buttonW, 0, float32(offsetX + i*(buttonW+10))},
		{0, buttonH, float32(offsetY + j*(buttonW+10))},
	})
}

func drawBrandModel() {
	n := newNode()
	eng.SetSubTex(n, texs[texBrand])
	eng.SetTransform(n, f32.Affine{
		{113, 0, offsetX},
		{0, 44, 260},
	})
}

func newNode() *sprite.Node {
	n := &sprite.Node{}
	eng.Register(n)
	board.AppendChild(n)
	return n
}

const (
	texBG = iota
	texButtonOn
	texButtonOff
	texBrand
	texModel
	texOthers
)

func loadTextures() []sprite.SubTex {
	a, err := app.Open("sprite.jpg")
	if err != nil {
		log.Fatal(err)
	}
	defer a.Close()

	img, _, err := image.Decode(a)
	if err != nil {
		log.Fatal(err)
	}
	t, err := eng.LoadTexture(img)
	if err != nil {
		log.Fatal(err)
	}

	return []sprite.SubTex{
		texBG:        sprite.SubTex{t, image.Rect(0, 0, 24, 860)},
		texButtonOff: sprite.SubTex{t, image.Rect(94, 242, 94+150, 242+151)},
		texButtonOn:  sprite.SubTex{t, image.Rect(94, 413, 94+150, 413+151)},
		texBrand:     sprite.SubTex{t, image.Rect(94, 31, 94+227, 31+88)},
		texModel:     sprite.SubTex{t, image.Rect(162, 120, 162+140, 120+90)},
		texOthers:    sprite.SubTex{t, image.Rect(162, 120, 162+140, 120+90)},
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
)

// Config for hyperon server
type ServerConf struct {
	name       string
	LocalAddr  string
	RemoteAddr string
}
type Config struct {
	Servers []ServerConf
}

// NewConfigFromFile will load config from toml style file
func NewConfigFromFile(path string) (*Config, error) {
	cfg := Config{}
	_, err := toml.DecodeFile(path, &cfg)

	if err != nil {
		return nil, err
	}

	return &cfg, nil
}

func transfer(client *net.Conn, server *net.Conn) {
	var c = sync.NewCond(&sync.Mutex{})
	var done = false

	go func() {
		io.Copy(*server, *client)
		c.L.Lock()
		done = true
		c.Signal()
		c.L.Unlock()
	}()
	go func() {
		io.Copy(*client, *server)
		c.L.Lock()
		done = true
		c.Signal()
		c.L.Unlock()
	}()
	c.L.Lock()
	for !done {
		c.Wait()
	}
	c.L.Unlock()
}

func bridge(local string, remote string) {
	ln, err := net.Listen("tcp", local)
	defer ln.Close()

	if err != nil {
		log.Printf("fail to listen on %s, %s", local, err)
		return
	}
	log.Printf("listen on %s", local)
	for {
		client, err := ln.Accept()
		if err != nil {
			log.Printf("fail to accept on %s, %s", local, err)
		}
		tc, ok := client.(*net.TCPConn)
		if !ok {
			log.Printf("error to cast connection")
		}
		tc.SetKeepAlive(true)
		tc.SetKeepAlivePeriod(1 * time.Second)
		defer client.Close()

		server, err := net.Dial("tcp", remote)
		if err != nil {
			log.Printf("fail to connect to server %s, %s", remote, err)
		}
		defer server.Close()
		go func() {
			log.Printf("establish %s --> %s", local, remote)
			transfer(&client, &server)
			log.Printf("closing %s --> %s", local, remote)
		}()
	}
}

func main() {
	conf := flag.String("c", "hyperon.toml", "hyperon config file")
	flag.Parse()
	path := *conf

	cfg, err := NewConfigFromFile(path)
	if err != nil {
		fmt.Printf("unable load config from %s, %s\n", path, err)
	}

	for _, serverconf := range cfg.Servers {
		localAddr := serverconf.LocalAddr
		remoteAddr := serverconf.RemoteAddr
		go bridge(localAddr, remoteAddr)
	}
	select {}
}
<commit_msg>Fix the 'nil pointer dereference' bug<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"sync"
	"time"

	"github.com/BurntSushi/toml"
)

// Config for hyperon server
type ServerConf struct {
	name       string
	LocalAddr  string
	RemoteAddr string
}
type Config struct {
	Servers []ServerConf
}

// NewConfigFromFile will load config from toml style file
func NewConfigFromFile(path string) (*Config, error) {
	cfg := Config{}
	_, err := toml.DecodeFile(path, &cfg)

	if err != nil {
		return nil, err
	}

	return &cfg, nil
}

func transfer(client *net.Conn, server *net.Conn) {
	var c = sync.NewCond(&sync.Mutex{})
	var done = false

	go func() {
		io.Copy(*server, *client)
		c.L.Lock()
		done = true
		c.Signal()
		c.L.Unlock()
	}()
	go func() {
		io.Copy(*client, *server)
		c.L.Lock()
		done = true
		c.Signal()
		c.L.Unlock()
	}()
	c.L.Lock()
	for !done {
		c.Wait()
	}
	c.L.Unlock()
}

func handle(client net.Conn, local string, remote string) {
	tc, ok := client.(*net.TCPConn)
	if !ok {
		log.Printf("error to cast connection")
		return
	}
	tc.SetKeepAlive(true)
	tc.SetKeepAlivePeriod(1 * time.Second)
	defer client.Close()

	server, err := net.Dial("tcp", remote)
	if err != nil {
		log.Printf("fail to connect to server %s, %s", remote, err)
		return
	}
	defer server.Close()

	log.Printf("establish %s --> %s", local, remote)
	transfer(&client, &server)
	log.Printf("closing %s --> %s", local, remote)
}

func bridge(local string, remote string) {
	ln, err := net.Listen("tcp", local)

	if err != nil {
		log.Printf("%s", err)
		return
	}
	defer ln.Close()

	log.Printf("listen on %s", local)
	for {
		client, err := ln.Accept()
		if err != nil {
			log.Printf("fail to accept on %s, %s", local, err)
			continue
		}
		go handle(client, local, remote)
	}
}

func main() {
	conf := flag.String("c", "hyperon.toml", "hyperon config file")
	flag.Parse()
	path := *conf

	cfg, err := NewConfigFromFile(path)
	if err != nil {
		fmt.Printf("unable load config from %s, %s\n", path, err)
	}

	for _, serverconf := range cfg.Servers {
		localAddr := serverconf.LocalAddr
		remoteAddr := serverconf.RemoteAddr
		go bridge(localAddr, remoteAddr)
	}
	select {}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/abiosoft/ishell"
	"github.com/dlt/selfcontrol/tasks"
)

var errInvalidArgumentList = errors.New("invalid argument list")
var errInvalidNumericArgument = errors.New("invalid numeric argument")
var shell = ishell.New()

func main() {
	shell.Println("The greatest conquest is self–control")
	shell.Register("list", listTasks)
	shell.Register("add", addTask)
	shell.Register("delete", deleteTask)
	shell.Register("update", updateTask)
	shell.Register("timer", addTimerForTask)
	shell.Register("exit", exit)
	tasks.Init(getDBFile())
	tasks.Print()
	shell.Start()
}

func getDBFile() string {
	args := os.Args
	if len(args) == 1 {
		homedir := os.Getenv("HOME")
		return filepath.Join(homedir, ".selfcontrol.db")
	}
	return args[1]
}

func listTasks(args ...string) (string, error) {
	tasks.Print()
	return "", nil
}

func exit(args ...string) (string, error) {
	shell.Stop()
	return "", nil
}

func addTask(args ...string) (string, error) {
	if len(args) < 1 {
		return "", errInvalidArgumentList
	}
	name := args[0]
	if len(args) == 1 {
		args = append(args, "pri:0")
	}
	tasks.Add(name, args[1:])
	tasks.Print()
	return "task created", nil
}

func deleteTask(args ...string) (string, error) {
	if len(args) != 1 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	tasks.Delete(id)
	tasks.Print()
	return "", nil
}

func updateTask(args ...string) (string, error) {
	if len(args) < 2 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	_, err = tasks.UpdateFields(id, args[1:])
	if err != nil {
		return "couldn't update task", err
	}
	tasks.Print()
	return "", nil
}

func addTimerForTask(args ...string) (string, error) {
	if len(args) != 2 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	timeInMinutes, err := time.ParseDuration(args[1] + "m")
	if err != nil {
		return args[1], errInvalidNumericArgument
	}
	_, err = tasks.AddTimerForTask(id, timeInMinutes)
	if err != nil {
		return "", err
	}
	return "", nil
}
<commit_msg>Add shell history<commit_after>package main

import (
	"errors"
	"os"
	"path/filepath"
	"strconv"
	"time"

	"github.com/abiosoft/ishell"
	"github.com/dlt/selfcontrol/tasks"
)

var errInvalidArgumentList = errors.New("invalid argument list")
var errInvalidNumericArgument = errors.New("invalid numeric argument")
var shell = ishell.New()

func main() {
	shell.Println("The greatest conquest is self–control")
	shell.Register("list", listTasks)
	shell.Register("add", addTask)
	shell.Register("delete", deleteTask)
	shell.Register("update", updateTask)
	shell.Register("timer", addTimerForTask)
	shell.Register("exit", exit)
	shell.SetHomeHistoryPath(".ishell_history")
	tasks.Init(getDBFile())
	tasks.Print()
	shell.Start()
}

func getDBFile() string {
	args := os.Args
	if len(args) == 1 {
		homedir := os.Getenv("HOME")
		return filepath.Join(homedir, ".selfcontrol.db")
	}
	return args[1]
}

func listTasks(args ...string) (string, error) {
	tasks.Print()
	return "", nil
}

func exit(args ...string) (string, error) {
	shell.Stop()
	return "", nil
}

func addTask(args ...string) (string, error) {
	if len(args) < 1 {
		return "", errInvalidArgumentList
	}
	name := args[0]
	if len(args) == 1 {
		args = append(args, "pri:0")
	}
	tasks.Add(name, args[1:])
	tasks.Print()
	return "task created", nil
}

func deleteTask(args ...string) (string, error) {
	if len(args) != 1 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	tasks.Delete(id)
	tasks.Print()
	return "", nil
}

func updateTask(args ...string) (string, error) {
	if len(args) < 2 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	_, err = tasks.UpdateFields(id, args[1:])
	if err != nil {
		return "couldn't update task", err
	}
	tasks.Print()
	return "", nil
}

func addTimerForTask(args ...string) (string, error) {
	if len(args) != 2 {
		return "", errInvalidArgumentList
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		return args[0], errInvalidNumericArgument
	}
	timeInMinutes, err := time.ParseDuration(args[1] + "m")
	if err != nil {
		return args[1], errInvalidNumericArgument
	}
	_, err = tasks.AddTimerForTask(id, timeInMinutes)
	if err != nil {
		return "", err
	}
	return "", nil
}
<|endoftext|>


<commit_before>package main

import (
	r "github.com/scascketta/capmetro-log/Godeps/_workspace/src/github.com/dancannon/gorethink"
	"log"
	"os"
	"sync"
	"time"
)

var (
	errlogger *log.Logger = log.New(os.Stderr, "[ERR] ", log.LstdFlags|log.Lshortfile)
	session   *r.Session
	DB_NAME   string        = os.Getenv("DB_NAME")
	connOpts  r.ConnectOpts = r.ConnectOpts{Address: "localhost:28015", Database: DB_NAME}
	routes    []string      = []string{"803", "801", "550"}

	normalDuration   time.Duration        = 30 * (1000 * time.Millisecond)
	extendedDuration time.Duration        = (10 * 60) * (1000 * time.Millisecond)
	lastUpdated      map[string]time.Time = map[string]time.Time{}
	sleepHistory     map[string][]bool    = map[string][]bool{}
)

func init() {
	if len(os.Getenv("DB_NAME")) == 0 {
		errlogger.Fatal("Missing envvar DB_NAME")
	}
}

func FilterUpdatedVehicles(vehicles []VehiclePosition) []VehiclePosition {
	updated := []VehiclePosition{}
	for _, v := range vehicles {
		updateTime, _ := lastUpdated[v.VehicleID]
		lastUpdated[v.VehicleID] = v.Time
		if !updateTime.Equal(v.Time) {
			updated = append(updated, v)
		}
	}
	return updated
}

func LogVehiclePositions(session *r.Session, route string) {
	b, err := FetchVehicles(route)
	if err != nil {
		errlogger.Println(err)
		return
	}

	vehicles, err := ParseVehiclesResponse(b)
	if err != nil {
		errlogger.Println(err)
		return
	}
	if vehicles == nil {
		sleepHistory[route] = append(sleepHistory[route], true)
		return
	}

	updated := FilterUpdatedVehicles(vehicles)

	if len(updated) > 0 {
		_, err = r.Table("vehicle_position").Insert(r.Expr(updated)).Run(session)
		if err != nil {
			errlogger.Println(err)
			return
		}
		log.Printf("Log %d vehicles, route %s.\n", len(updated), route)
	} else {
		log.Printf("No new vehicle positions to record for route %s.\n", route)
	}
}

// Check if sleepHistory has 3 previous fetches, and each fetch is false
func routesAreSleeping() bool {
	for _, b := range sleepHistory {
		if len(b) < 3 {
			return false
		}
		for _, v := range b {
			if v == false {
				return false
			}
		}
	}
	return true
}

func main() {
	session, err := r.Connect(connOpts)
	if err != nil {
		errlogger.Fatal(err)
	}
	log.Printf("Established connection to RethinkDB server at %s.\n", connOpts.Address)

	var wg sync.WaitGroup

	for {
		for _, route := range routes {
			wg.Add(1)
			go func(session *r.Session, route string) {
				LogVehiclePositions(session, route)
				wg.Done()
			}(session, route)
		}
		wg.Wait()

		var duration time.Duration
		if routesAreSleeping() {
			for k, _ := range sleepHistory {
				sleepHistory[k] = []bool{}
			}
			log.Println("Sleeping for extended duration!")
			duration = extendedDuration
		} else {
			log.Println("Sleeping for normal duration!")
			duration = normalDuration
		}

		time.Sleep(duration)
		log.Println("Wake up!")
	}
}
<commit_msg>fix sleep history<commit_after>package main

import (
	r "github.com/scascketta/capmetro-log/Godeps/_workspace/src/github.com/dancannon/gorethink"
	"log"
	"os"
	"sync"
	"time"
)

var (
	errlogger *log.Logger = log.New(os.Stderr, "[ERR] ", log.LstdFlags|log.Lshortfile)
	session   *r.Session
	DB_NAME   string        = os.Getenv("DB_NAME")
	connOpts  r.ConnectOpts = r.ConnectOpts{Address: "localhost:28015", Database: DB_NAME}
	routes    []string      = []string{"803", "801", "550"}

	normalDuration   time.Duration        = 30 * (1000 * time.Millisecond)
	extendedDuration time.Duration        = (10 * 60) * (1000 * time.Millisecond)
	lastUpdated      map[string]time.Time = map[string]time.Time{}
	sleepHistory     map[string][]bool    = map[string][]bool{}
)

func init() {
	if len(os.Getenv("DB_NAME")) == 0 {
		errlogger.Fatal("Missing envvar DB_NAME")
	}
}

func FilterUpdatedVehicles(vehicles []VehiclePosition) []VehiclePosition {
	updated := []VehiclePosition{}
	for _, v := range vehicles {
		updateTime, _ := lastUpdated[v.VehicleID]
		lastUpdated[v.VehicleID] = v.Time
		if !updateTime.Equal(v.Time) {
			updated = append(updated, v)
		}
	}
	return updated
}

func LogVehiclePositions(session *r.Session, route string) {
	b, err := FetchVehicles(route)
	if err != nil {
		errlogger.Println(err)
		return
	}

	vehicles, err := ParseVehiclesResponse(b)
	if err != nil {
		errlogger.Println(err)
		return
	}
	if vehicles == nil {
		sleepHistory[route] = append(sleepHistory[route], true)
		return
	}

	updated := FilterUpdatedVehicles(vehicles)

	if len(updated) > 0 {
		_, err = r.Table("vehicle_position").Insert(r.Expr(updated)).Run(session)
		if err != nil {
			errlogger.Println(err)
			return
		}
		log.Printf("Log %d vehicles, route %s.\n", len(updated), route)
	} else {
		log.Printf("No new vehicle positions to record for route %s.\n", route)
	}
}

// Check if the the routes are inactive
// There must have been three previous attempts to fetch data,
// and all attempts must have failed
func routesAreSleeping() bool {
	for _, b := range sleepHistory {
		if len(b) < 3 {
			return false
		}
		for _, v := range b {
			if v == false {
				return false
			}
		}
	}
	return true
}

func main() {
	for _, route := range routes {
		sleepHistory[route] = []bool{}
	}

	session, err := r.Connect(connOpts)
	if err != nil {
		errlogger.Fatal(err)
	}
	log.Printf("Established connection to RethinkDB server at %s.\n", connOpts.Address)

	var wg sync.WaitGroup

	for {
		for _, route := range routes {
			wg.Add(1)
			go func(session *r.Session, route string) {
				LogVehiclePositions(session, route)
				wg.Done()
			}(session, route)
		}
		wg.Wait()

		var duration time.Duration
		if routesAreSleeping() {
			for k, _ := range sleepHistory {
				sleepHistory[k] = []bool{}
			}
			log.Println("Sleeping for extended duration!")
			duration = extendedDuration
		} else {
			log.Println("Sleeping for normal duration!")
			duration = normalDuration
		}

		time.Sleep(duration)
		log.Println("Wake up!")
	}
}
<|endoftext|>


<commit_before>package main

import "net/http"
import "fmt"
import "github.com/fengsp/knight"
import "github.com/gorilla/mux"

func log(remote_addr string, method string, path string) {
    fmt.Println(remote_addr, method, path)
}

type loggedResponse struct {
    w http.ResponseWriter
    r *http.Request
    url string
}

func UserHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    username := vars["username"]

    fmt.Fprintf(w, "Hi there %s!", username)

    logged_response := &loggedResponse{w, r, r.URL.String()}

    log(r.RemoteAddr, r.Method, r.URL.Path)
}

func main() {
    setup_routes()
    setup_reloader()
}

func setup_routes() {
    r := mux.NewRouter()
    r.HandleFunc("/user/{username}", UserHandler)
    http.Handle("/", r)
}

func setup_reloader() {
    knight := knight.NewKnight("")
    knight.ListenAndServe(":8000", nil)
}
<commit_msg>remove unused loggedResponse code<commit_after>package main

import "net/http"
import "fmt"
import "github.com/fengsp/knight"
import "github.com/gorilla/mux"

func log(remote_addr string, method string, path string) {
    fmt.Println(remote_addr, method, path)
}

func UserHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)
    username := vars["username"]

    fmt.Fprintf(w, "Hi there %s!", username)
}

func main() {
    setup_routes()
    setup_reloader()
}

func setup_routes() {
    r := mux.NewRouter()
    r.HandleFunc("/user/{username}", UserHandler)
    http.Handle("/", r)
}

func setup_reloader() {
    knight := knight.NewKnight("")
    knight.ListenAndServe(":8000", nil)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"

	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/route-registrar/config"
	"github.com/cloudfoundry-incubator/route-registrar/healthchecker"
	"github.com/cloudfoundry-incubator/route-registrar/registrar"
	"github.com/pivotal-cf-experimental/service-config"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

func main() {
	flags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	pidfile := flags.String("pidfile", "", "Path to pid file")
	cf_lager.AddFlags(flags)

	serviceConfig := service_config.New()
	serviceConfig.AddFlags(flags)
	flags.Set("configPath", "registrar_settings.yml")

	flags.Parse(os.Args[1:])

	logger, _ := cf_lager.New("Route Registrar")

	logger.Info("Initializing")

	var registrarConfig config.Config
	err := serviceConfig.Read(&registrarConfig)
	if err != nil {
		logger.Fatal("error parsing file: %s\n", err)
	}

	err = registrarConfig.Validate()
	if err != nil {
		log.Fatalln(err)
	}

	r := registrar.NewRegistrar(registrarConfig, logger)
	//add health check handler
	checker := healthchecker.InitHealthChecker(registrarConfig, logger)
	if checker != nil {
		r.AddHealthCheckHandler(checker)
	}

	if *pidfile != "" {
		pid := strconv.Itoa(os.Getpid())
		err := ioutil.WriteFile(*pidfile, []byte(pid), 0644)
		logger.Info("Writing pid", lager.Data{"pid": pid, "file": *pidfile})
		if err != nil {
			logger.Fatal(
				"error writing pid to pidfile",
				err,
				lager.Data{
					"pid":     pid,
					"pidfile": *pidfile},
			)
		}
	}

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

	logger.Info("Running")

	process := ifrit.Invoke(r)
	for {
		select {
		case s := <-c:
			logger.Info("Caught signal", lager.Data{"signal": s})
			process.Signal(s)
		case err := <-process.Wait():
			logger.Info("Shutting down")
			if err != nil {
				logger.Fatal("error occurred", err)
			}
			os.Exit(0)
		}
	}
}
<commit_msg>Provide more helpful output when shutting down.<commit_after>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/signal"
	"strconv"
	"syscall"

	"github.com/cloudfoundry-incubator/cf-lager"
	"github.com/cloudfoundry-incubator/route-registrar/config"
	"github.com/cloudfoundry-incubator/route-registrar/healthchecker"
	"github.com/cloudfoundry-incubator/route-registrar/registrar"
	"github.com/pivotal-cf-experimental/service-config"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

func main() {
	flags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)

	pidfile := flags.String("pidfile", "", "Path to pid file")
	cf_lager.AddFlags(flags)

	serviceConfig := service_config.New()
	serviceConfig.AddFlags(flags)
	flags.Set("configPath", "registrar_settings.yml")

	flags.Parse(os.Args[1:])

	logger, _ := cf_lager.New("Route Registrar")

	logger.Info("Initializing")

	var registrarConfig config.Config
	err := serviceConfig.Read(&registrarConfig)
	if err != nil {
		logger.Fatal("error parsing file: %s\n", err)
	}

	err = registrarConfig.Validate()
	if err != nil {
		log.Fatalln(err)
	}

	r := registrar.NewRegistrar(registrarConfig, logger)
	//add health check handler
	checker := healthchecker.InitHealthChecker(registrarConfig, logger)
	if checker != nil {
		r.AddHealthCheckHandler(checker)
	}

	if *pidfile != "" {
		pid := strconv.Itoa(os.Getpid())
		err := ioutil.WriteFile(*pidfile, []byte(pid), 0644)
		logger.Info("Writing pid", lager.Data{"pid": pid, "file": *pidfile})
		if err != nil {
			logger.Fatal(
				"error writing pid to pidfile",
				err,
				lager.Data{
					"pid":     pid,
					"pidfile": *pidfile},
			)
		}
	}

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

	logger.Info("Running")

	process := ifrit.Invoke(r)
	for {
		select {
		case s := <-c:
			logger.Info("Caught signal", lager.Data{"signal": s})
			process.Signal(s)
		case err := <-process.Wait():
			if err != nil {
				logger.Fatal("Exiting with error", err)
			}
			logger.Info("Exiting without error")
			os.Exit(0)
		}
	}
}
<|endoftext|>


<commit_before>// Package cqueue implement circular buffer/queue operations
package cqueue

import (
  "container/list"
  "errors"
)

// CQueue represents a circular buffer data structure
// TODO: overflow middleware function also
type CQueue struct {
  // size limit of the buffer
  size int
  // occupied size of the buffer
  Length int

  // list containing all the buffer elements
  Queue *list.List
  // element at the front-side of the buffer
  Head *list.Element
  // element at the back-side of the buffer
  Tail *list.Element
}

// New function returns a CQueue instance of custom size
func New(size int) *CQueue {
  return &CQueue{size: size, Queue: list.New()}
}

// Push adds an element to the circular buffer
func (cq *CQueue) Push(element interface{}) (el *list.Element, err error) {
  if (cq.Length < cq.size) {
    cq.Tail = cq.Queue.PushBack(element)
    if (cq.Length == 0) {
      cq.Head = cq.Tail
    }

    cq.updateLength(1)
  } else {
    cq.Pop()
    cq.Push(element)
  }

  return cq.Tail, nil
}

// Pop removes the element at the front in circular buffer
// It returns the popped element and error, if any.
func (cq *CQueue) Pop() (el *list.Element, err error) {
  if (cq.Length > 0) {
    el, err = cq.Head, nil
    newHead := cq.Head.Next()

    cq.Queue.Remove(cq.Head)
    cq.Head = newHead
    if (cq.Length == 1) {
      cq.Tail = nil
    }

    cq.updateLength(-1)
  } else {
    el, err = nil, errors.New("cqueue: buffer is empty")
  }

  return el, err
}

// Value returns the value of a list element
func (cq *CQueue) Value(element *list.Element) interface{} {
  if (element == nil) {
    return nil
  }
  return element.Value
}

// Whether the circular buffer is full or not
func (cq *CQueue) isFull() bool {
  return (cq.Length == cq.size)
}

// Whether the circular buffer is empty or not
func (cq *CQueue) isEmpty() bool {
  return (cq.Length == 0)
}

// Updates the occupied length of the circular buffer
func (cq *CQueue) updateLength(update int) {
  cq.Length += update
}
<commit_msg>Middleware function for buffer overflow case<commit_after>// Package cqueue implement circular buffer/queue operations
package cqueue

import (
  "container/list"
  "errors"
)

// CQueue represents a circular buffer data structure
// TODO: overflow middleware function also
type CQueue struct {
  // size limit of the buffer
  size int
  // occupied size of the buffer
  Length int

  // list containing all the buffer elements
  Queue *list.List
  // element at the front-side of the buffer
  Head *list.Element
  // element at the back-side of the buffer
  Tail *list.Element

  // middleware function to call when buffer overflows
  overflow func()
}

// New function returns a CQueue instance of custom size
func New(args map[string]interface{}) *CQueue {
  size := args["size"].(int)
  middleware := args["middleware"].(func())

  return &CQueue{size: size, Queue: list.New(), overflow: middleware}
}

// Push adds an element to the circular buffer
func (cq *CQueue) Push(element interface{}) (el *list.Element, err error) {
  if (cq.Length < cq.size) {
    cq.Tail = cq.Queue.PushBack(element)
    if (cq.Length == 0) {
      cq.Head = cq.Tail
    }

    cq.updateLength(1)
  } else {
    // call the middleware function
    cq.overflow()

    cq.Pop()
    cq.Push(element)
  }

  return cq.Tail, nil
}

// Pop removes the element at the front in circular buffer
// It returns the popped element and error, if any.
func (cq *CQueue) Pop() (el *list.Element, err error) {
  if (cq.Length > 0) {
    el, err = cq.Head, nil
    newHead := cq.Head.Next()

    cq.Queue.Remove(cq.Head)
    cq.Head = newHead
    if (cq.Length == 1) {
      cq.Tail = nil
    }

    cq.updateLength(-1)
  } else {
    el, err = nil, errors.New("cqueue: buffer is empty")
  }

  return el, err
}

// Value returns the value of a list element
func (cq *CQueue) Value(element *list.Element) interface{} {
  if (element == nil) {
    return nil
  }
  return element.Value
}

// Whether the circular buffer is full or not
func (cq *CQueue) isFull() bool {
  return (cq.Length == cq.size)
}

// Whether the circular buffer is empty or not
func (cq *CQueue) isEmpty() bool {
  return (cq.Length == 0)
}

// Updates the occupied length of the circular buffer
func (cq *CQueue) updateLength(update int) {
  cq.Length += update
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"net/url"
  	"io/ioutil"
	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

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

	// end fixie

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

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

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

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

			if err != nil {
				log.Println(err)
			}
		}
		if content != nil && content.ContentType == linebot.ContentTypeLocation {
			text, err := content.TextContent()

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

			//_, err = bot.SendText([]string{content.From}, "OK "+text.Text)
			_, err = bot.SendText([]string{content.From}, "Geo test :" + string(body))

			if err != nil {
				log.Println(err)
			}
		}
	}
}
<commit_msg>Update main.go<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strconv"
	"net/url"
  	"io/ioutil"
	"github.com/line/line-bot-sdk-go/linebot"
)

var bot *linebot.Client

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

	// end fixie

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

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

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

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

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

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

			//_, err = bot.SendText([]string{content.From}, "OK "+text.Text)
			_, err = bot.SendText([]string{content.From}, "Geo test :" + string(body))

			if err != nil {
				log.Println(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
    "github.com/ant0ine/go-json-rest/rest"
    "github.com/rugo/sacapi/modules/auth"
    "github.com/rugo/sacapi/modules/view"
    "github.com/rugo/sacapi/modules/apilog"
    "log"
    "net/http"
)

/*
Microservice for accessing data
*/
func main() {
    api := rest.NewApi()
    api.Use(rest.DefaultDevStack...)
    api.Use(
        &rest.AuthBasicMiddleware{
            Realm: "Smart Alarm Clock REST API",
            Authenticator: auth.AuthenticateByFile})
    router, err := rest.MakeRouter(
        rest.Get("/test", view.GetJSONMessage),
    )
    if err != nil {
        log.Fatal(err)
    }
    api.SetApp(router)
    apilog.Init()
    log.Fatal(http.ListenAndServeTLS(":8080", "keys/cert.pem", "keys/key.pem", api.MakeHandler()))
}<commit_msg>Changed port<commit_after>package main

import (
    "github.com/ant0ine/go-json-rest/rest"
    "github.com/rugo/sacapi/modules/auth"
    "github.com/rugo/sacapi/modules/view"
    "github.com/rugo/sacapi/modules/apilog"
    "log"
    "net/http"
)

/*
Microservice for accessing data
*/
func main() {
    api := rest.NewApi()
    api.Use(rest.DefaultDevStack...)
    api.Use(
        &rest.AuthBasicMiddleware{
            Realm: "Smart Alarm Clock REST API",
            Authenticator: auth.AuthenticateByFile})
    router, err := rest.MakeRouter(
        rest.Get("/test", view.GetJSONMessage),
    )
    if err != nil {
        log.Fatal(err)
    }
    api.SetApp(router)
    apilog.Init()
    log.Fatal(http.ListenAndServeTLS(":1443", "keys/cert.pem", "keys/key.pem", api.MakeHandler()))
}<|endoftext|>