<commit_before>// Package bla provides ...
package bla

import (
	"bytes"
	"flag"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"text/template"
	"time"

	"github.com/PuerkitoBio/goquery"
)

const Version = "0.1 alpha"

func New() {

	flag.Parse()
	LoadConfig(*configPath)

	server := &Server{
		Docs:        make(map[string]*Doc, 0),
		sortedDocs:  make([]*Doc, 0),
		DocLock:     &sync.RWMutex{},
		Tags:        make(map[string][]*Doc, 0),
		TagLock:     &sync.RWMutex{},
		StaticFiles: make([]string, 0),
		Version:     Version,
		StopWatch:   make(chan bool)}

	server.Reset()
	if err := server.LoadTempalte(); err != nil {
		log.Fatal(err)
	}
	server.LoadStaticFiles()
	server.LoadAllDocs()
	if err := server.SaveAllDocs(); err != nil {
		log.Fatal(err)
	}
	server.MakeHome()
	log.Print(server.MakeSitemap())
	log.Print(Cfg)
	server.Watch()
	server.ConfigWatch()

	admin := map[string]http.HandlerFunc{
		".add":    server.Add,
		".edit":   server.Edit,
		".quit":   server.Quit,
		".upload": server.UploadMedia,
	}
	for k, v := range admin {
		http.HandleFunc(path.Join(Cfg.BasePath, k), server.auth(v))
	}

	http.Handle("/", http.FileServer(http.Dir(Cfg.PublicPath)))

	if Cfg.TLSKeyFile != "" && Cfg.TLSCertFile != "" {
		log.Fatal(http.ListenAndServeTLS(Cfg.Addr, Cfg.TLSCertFile, Cfg.TLSKeyFile, nil))
	} else {
		log.Fatal(http.ListenAndServe(Cfg.Addr, nil))
	}
}

func (s *Server) auth(orig http.HandlerFunc) http.HandlerFunc {

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

		if u, p, ok := r.BasicAuth(); ok {
			if u == Cfg.Username && p == Cfg.Password {
				orig(w, r)
				return
			}
		}

		w.Header().Set("WWW-Authenticate", `Basic realm="`+Cfg.BaseURL+`"`)
		w.WriteHeader(401)
		w.Write([]byte("401 Unauthorized\n"))
	}
}

func (s *Server) Quit(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Location", strings.Replace(Cfg.BaseURL, "://", "://log:out@", 1))
	w.WriteHeader(301)
}

func (s *Server) Add(w http.ResponseWriter, r *http.Request) {

	switch r.Method {
	case "GET":
		rd := s.newRootData()
		if err := s.template.add.ExecuteTemplate(w, "root", rd); err != nil {
			log.Print(err)
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
		}
	case "POST":
		r.ParseForm()
		content := r.FormValue("mce_0")
		parsed, err := goquery.NewDocumentFromReader(bytes.NewBuffer([]byte(content)))
		if err != nil {
			log.Printf("Parse failed:%v", err)
			w.WriteHeader(500)
			return
		}
		header := parsed.Find("h1").First().Text()
		if header == "" {
			log.Print("Header not existed", header)
			w.WriteHeader(500)
			return

		}

		f, err := os.Create(filepath.Join(Cfg.ContentPath, santiSpace(header)+".html"))
		if err != nil {
			log.Print(err)
			w.WriteHeader(500)
			return
		}

		f.WriteString(content)
		f.Close()

		w.Header().Set("Location", Cfg.BasePath)
		w.WriteHeader(301)

	default:
		w.WriteHeader(403)

	}
}

func (s *Server) Edit(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		doc := r.URL.Query().Get("doc")
		if doc == "" {

			w.Write([]byte("no doc query"))
			w.WriteHeader(403)
			return
		}

		fp := filepath.Join(Cfg.ContentPath, filepath.Base(doc)+".html")
		if _, err := os.Stat(fp); os.IsNotExist(err) {
			w.Write([]byte("no such doc"))
			w.WriteHeader(404)
			return
		}

		f, err := os.Open(fp)
		if err != nil {
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
			return
		}
		defer f.Close()

		rd := s.newRootData()
		parsed, _ := goquery.NewDocumentFromReader(f)

		rd.Docs = append(rd.Docs, &Doc{Parsed: parsed})
		if err := s.template.add.ExecuteTemplate(w, "root", rd); err != nil {
			log.Print(err)
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
			f.Close()
			return
		}

		bak, err := os.Create(fp + ".bak")
		io.Copy(bak, f)
		bak.Close()
		f.Close()
		os.Remove(fp)
	}
}

func (s *Server) Reset() {

	if err := os.RemoveAll(Cfg.PublicPath); err != nil {
		log.Print(err)
	}
	os.MkdirAll(Cfg.PublicPath, 0755)

	if Cfg.Favicon != "" {
		Link(Cfg.Favicon, filepath.Join(Cfg.PublicPath, "favicon.ico"))
	}

	for _, p := range Cfg.LinkFiles {
		Link(p, filepath.Join(Cfg.PublicPath, filepath.Base(p)))
	}

	uploads, _ := filepath.Abs(Cfg.UploadPath)
	uploadBase := filepath.Base(uploads)

	os.MkdirAll(filepath.Join(Cfg.PublicPath, Cfg.BasePath), 0755)
	Link(Cfg.UploadPath, filepath.Join(Cfg.PublicPath, Cfg.BasePath, uploadBase))
}

func (s *Server) LoadStaticFiles() {

	log.Print("Rebuild from: ", Cfg.TemplatePath)
	Link(filepath.Join(Cfg.TemplatePath, "asset"),
		filepath.Join(Cfg.PublicPath, Cfg.BasePath, "asset"))

	log.Print("Loading Asset files")

	orig, err := filepath.Abs(filepath.Join(Cfg.TemplatePath, "asset"))
	if err != nil {
		log.Fatal(err)
	}

	filepath.Walk(orig,
		func(path string, info os.FileInfo, e error) (err error) {

			if info == nil || !info.Mode().IsRegular() {
				return
			}
			if !(filepath.Ext(path) == ".css" || filepath.Ext(path) == ".js") {
				return
			}
			log.Print("|- ", path)
			s.StaticFiles = append(s.StaticFiles, path)
			return
		})
}

func extractHost(s string) string {

	u, err := url.Parse(s)
	if err != nil {
		panic(err)
	}
	return u.Host
}

func (s *Server) LoadTempalte() (err error) {

	var funcMap = template.FuncMap{
		"base":        path.Base,
		"ext":         filepath.Ext,
		"now":         time.Now,
		"join":        filepath.Join,
		"extractHost": extractHost,
	}
	root := filepath.Join(Cfg.TemplatePath, "root.tmpl")
	parsed := func(fname string) (t *template.Template) {
		t, err = template.New("").Funcs(funcMap).ParseFiles(root, filepath.Join(Cfg.TemplatePath, fname))
		if err != nil {
			log.Fatal(err)
		}
		return t
	}

	s.template.home = parsed("home.tmpl")
	s.template.doc = parsed("doc.tmpl")
	s.template.index = parsed("index.tmpl")

	s.template.add = parsed("add.tmpl")
	return
}

type Server struct {
	Docs        map[string]*Doc
	sortedDocs  []*Doc
	Tags        map[string][]*Doc
	StaticFiles []string
	template    struct{ home, doc, index, add *template.Template }
	Version     string
	StopWatch   chan bool
	DocLock     *sync.RWMutex
	TagLock     *sync.RWMutex
}

func Link(orig, dest string) error {

	absOrig, err := filepath.Abs(orig)
	if err != nil {
		return err
	}
	absDest, err := filepath.Abs(dest)
	if err != nil {
		return err
	}

	if err := os.Symlink(absOrig, absDest); err != nil {
		log.Print(err)
		return err
	} else {
		log.Print("Rebuild link:", absOrig, " -> ", absDest)
	}
	return nil
}
<commit_msg>add LRU cache on session<commit_after>// Package bla provides ...
package bla

import (
	"bytes"
	"crypto/tls"
	"flag"
	"io"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"text/template"
	"time"

	"github.com/PuerkitoBio/goquery"
)

const Version = "0.1 alpha"

func New() {

	flag.Parse()
	LoadConfig(*configPath)

	server := &Server{
		Docs:        make(map[string]*Doc, 0),
		sortedDocs:  make([]*Doc, 0),
		DocLock:     &sync.RWMutex{},
		Tags:        make(map[string][]*Doc, 0),
		TagLock:     &sync.RWMutex{},
		StaticFiles: make([]string, 0),
		Version:     Version,
		StopWatch:   make(chan bool)}

	server.Reset()
	if err := server.LoadTempalte(); err != nil {
		log.Fatal(err)
	}
	server.LoadStaticFiles()
	server.LoadAllDocs()
	if err := server.SaveAllDocs(); err != nil {
		log.Fatal(err)
	}
	server.MakeHome()
	log.Print(server.MakeSitemap())
	log.Print(Cfg)
	server.Watch()
	server.ConfigWatch()

	admin := map[string]http.HandlerFunc{
		".add":    server.Add,
		".edit":   server.Edit,
		".quit":   server.Quit,
		".upload": server.UploadMedia,
	}

	for k, v := range admin {
		http.HandleFunc(path.Join(Cfg.BasePath, k), server.auth(v))
	}

	http.Handle("/", http.FileServer(http.Dir(Cfg.PublicPath)))

	if Cfg.TLSKeyFile != "" && Cfg.TLSCertFile != "" {

		tls_server := http.Server{Addr: Cfg.Addr, Handler: nil,
			TLSConfig: &tls.Config{ClientSessionCache: tls.NewLRUClientSessionCache(100)}}
		log.Fatal(tls_server.ListenAndServeTLS(Cfg.TLSCertFile, Cfg.TLSKeyFile))
	} else {
		log.Fatal(http.ListenAndServe(Cfg.Addr, nil))
	}
}

func (s *Server) auth(orig http.HandlerFunc) http.HandlerFunc {

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

		if u, p, ok := r.BasicAuth(); ok {
			if u == Cfg.Username && p == Cfg.Password {
				orig(w, r)
				return
			}
		}

		w.Header().Set("WWW-Authenticate", `Basic realm="`+Cfg.BaseURL+`"`)
		w.WriteHeader(401)
		w.Write([]byte("401 Unauthorized\n"))
	}
}

func (s *Server) Quit(w http.ResponseWriter, r *http.Request) {

	w.Header().Set("Location", strings.Replace(Cfg.BaseURL, "://", "://log:out@", 1))
	w.WriteHeader(301)
}

func (s *Server) Add(w http.ResponseWriter, r *http.Request) {

	switch r.Method {
	case "GET":
		rd := s.newRootData()
		if err := s.template.add.ExecuteTemplate(w, "root", rd); err != nil {
			log.Print(err)
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
		}
	case "POST":
		r.ParseForm()
		content := r.FormValue("mce_0")
		parsed, err := goquery.NewDocumentFromReader(bytes.NewBuffer([]byte(content)))
		if err != nil {
			log.Printf("Parse failed:%v", err)
			w.WriteHeader(500)
			return
		}
		header := parsed.Find("h1").First().Text()
		if header == "" {
			log.Print("Header not existed", header)
			w.WriteHeader(500)
			return

		}

		f, err := os.Create(filepath.Join(Cfg.ContentPath, santiSpace(header)+".html"))
		if err != nil {
			log.Print(err)
			w.WriteHeader(500)
			return
		}

		f.WriteString(content)
		f.Close()

		w.Header().Set("Location", Cfg.BasePath)
		w.WriteHeader(301)

	default:
		w.WriteHeader(403)

	}
}

func (s *Server) Edit(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		doc := r.URL.Query().Get("doc")
		if doc == "" {

			w.Write([]byte("no doc query"))
			w.WriteHeader(403)
			return
		}

		fp := filepath.Join(Cfg.ContentPath, filepath.Base(doc)+".html")
		if _, err := os.Stat(fp); os.IsNotExist(err) {
			w.Write([]byte("no such doc"))
			w.WriteHeader(404)
			return
		}

		f, err := os.Open(fp)
		if err != nil {
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
			return
		}
		defer f.Close()

		rd := s.newRootData()
		parsed, _ := goquery.NewDocumentFromReader(f)

		rd.Docs = append(rd.Docs, &Doc{Parsed: parsed})
		if err := s.template.add.ExecuteTemplate(w, "root", rd); err != nil {
			log.Print(err)
			w.Write([]byte(err.Error()))
			w.WriteHeader(500)
			f.Close()
			return
		}

		bak, err := os.Create(fp + ".bak")
		io.Copy(bak, f)
		bak.Close()
		f.Close()
		os.Remove(fp)
	}
}

func (s *Server) Reset() {

	if err := os.RemoveAll(Cfg.PublicPath); err != nil {
		log.Print(err)
	}
	os.MkdirAll(Cfg.PublicPath, 0755)

	if Cfg.Favicon != "" {
		Link(Cfg.Favicon, filepath.Join(Cfg.PublicPath, "favicon.ico"))
	}

	for _, p := range Cfg.LinkFiles {
		Link(p, filepath.Join(Cfg.PublicPath, filepath.Base(p)))
	}

	uploads, _ := filepath.Abs(Cfg.UploadPath)
	uploadBase := filepath.Base(uploads)

	os.MkdirAll(filepath.Join(Cfg.PublicPath, Cfg.BasePath), 0755)
	Link(Cfg.UploadPath, filepath.Join(Cfg.PublicPath, Cfg.BasePath, uploadBase))
}

func (s *Server) LoadStaticFiles() {

	log.Print("Rebuild from: ", Cfg.TemplatePath)
	Link(filepath.Join(Cfg.TemplatePath, "asset"),
		filepath.Join(Cfg.PublicPath, Cfg.BasePath, "asset"))

	log.Print("Loading Asset files")

	orig, err := filepath.Abs(filepath.Join(Cfg.TemplatePath, "asset"))
	if err != nil {
		log.Fatal(err)
	}

	filepath.Walk(orig,
		func(path string, info os.FileInfo, e error) (err error) {

			if info == nil || !info.Mode().IsRegular() {
				return
			}
			if !(filepath.Ext(path) == ".css" || filepath.Ext(path) == ".js") {
				return
			}
			log.Print("|- ", path)
			s.StaticFiles = append(s.StaticFiles, path)
			return
		})
}

func extractHost(s string) string {

	u, err := url.Parse(s)
	if err != nil {
		panic(err)
	}
	return u.Host
}

func (s *Server) LoadTempalte() (err error) {

	var funcMap = template.FuncMap{
		"base":        path.Base,
		"ext":         filepath.Ext,
		"now":         time.Now,
		"join":        filepath.Join,
		"extractHost": extractHost,
	}
	root := filepath.Join(Cfg.TemplatePath, "root.tmpl")
	parsed := func(fname string) (t *template.Template) {
		t, err = template.New("").Funcs(funcMap).ParseFiles(root, filepath.Join(Cfg.TemplatePath, fname))
		if err != nil {
			log.Fatal(err)
		}
		return t
	}

	s.template.home = parsed("home.tmpl")
	s.template.doc = parsed("doc.tmpl")
	s.template.index = parsed("index.tmpl")

	s.template.add = parsed("add.tmpl")
	return
}

type Server struct {
	Docs        map[string]*Doc
	sortedDocs  []*Doc
	Tags        map[string][]*Doc
	StaticFiles []string
	template    struct{ home, doc, index, add *template.Template }
	Version     string
	StopWatch   chan bool
	DocLock     *sync.RWMutex
	TagLock     *sync.RWMutex
}

func Link(orig, dest string) error {

	absOrig, err := filepath.Abs(orig)
	if err != nil {
		return err
	}
	absDest, err := filepath.Abs(dest)
	if err != nil {
		return err
	}

	if err := os.Symlink(absOrig, absDest); err != nil {
		log.Print(err)
		return err
	} else {
		log.Print("Rebuild link:", absOrig, " -> ", absDest)
	}
	return nil
}
<|endoftext|>


<commit_before>// CoAP Client and Server in Go
package coap

import (
	"log"
	"net"
	"time"
)

const maxPktLen = 1500

// Handle CoAP messages.
type Handler interface {
	// Handle the message and optionally return a response message.
	ServeCOAP(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message
}

type funcHandler func(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message

func (f funcHandler) ServeCOAP(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message {
	return f(l, a, m)
}

// Build a handler from a function.
func FuncHandler(f func(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message) Handler {
	return funcHandler(f)
}

func handlePacket(l *net.UDPConn, data []byte, u *net.UDPAddr,
	rh Handler) {

	msg, err := parseMessage(data)
	if err != nil {
		log.Printf("Error parsing %v", err)
		return
	}

	rv := rh.ServeCOAP(l, u, &msg)
	if rv != nil {
		log.Printf("Transmitting %#v", rv)
		Transmit(l, u, *rv)
	}
}

// Transmit a message.
func Transmit(l *net.UDPConn, a *net.UDPAddr, m Message) error {
	d, err := m.encode()
	if err != nil {
		return err
	}

	if a == nil {
		_, err = l.Write(d)
	} else {
		_, err = l.WriteTo(d, a)
	}
	return err
}

// Receive a message.
func Receive(l *net.UDPConn, buf []byte) (Message, error) {
	l.SetReadDeadline(time.Now().Add(RESPONSE_TIMEOUT))

	nr, _, err := l.ReadFromUDP(buf)
	if err != nil {
		return Message{}, err
	}
	return parseMessage(buf[:nr])
}

// Bind to the given address and serve requests forever.
func ListenAndServe(n, addr string, rh Handler) error {
	uaddr, err := net.ResolveUDPAddr(n, addr)
	if err != nil {
		return err
	}

	l, err := net.ListenUDP(n, uaddr)
	if err != nil {
		return err
	}

	buf := make([]byte, maxPktLen)
	for {
		nr, addr, err := l.ReadFromUDP(buf)
		if err == nil {
			tmp := make([]byte, nr)
			copy(tmp, buf)
			go handlePacket(l, tmp, addr, rh)
		}
	}
}
<commit_msg>Default maxPktLen = 1280. Added get and set methods.<commit_after>// CoAP Client and Server in Go
package coap

import (
	"log"
	"net"
	"time"
)

var maxPktLen uint32 = 1280

func getMaxPktLen() uint32, err {
    return maxPktLen, nil
}

func setMaxPktLen(newlen uint32) uint32, err {
    maxPktLen = newlen
    return maxPktLen, nil
}

// Handle CoAP messages.
type Handler interface {
	// Handle the message and optionally return a response message.
	ServeCOAP(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message
}

type funcHandler func(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message

func (f funcHandler) ServeCOAP(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message {
	return f(l, a, m)
}

// Build a handler from a function.
func FuncHandler(f func(l *net.UDPConn, a *net.UDPAddr, m *Message) *Message) Handler {
	return funcHandler(f)
}

func handlePacket(l *net.UDPConn, data []byte, u *net.UDPAddr,
	rh Handler) {

	msg, err := parseMessage(data)
	if err != nil {
		log.Printf("Error parsing %v", err)
		return
	}

	rv := rh.ServeCOAP(l, u, &msg)
	if rv != nil {
		log.Printf("Transmitting %#v", rv)
		Transmit(l, u, *rv)
	}
}

// Transmit a message.
func Transmit(l *net.UDPConn, a *net.UDPAddr, m Message) error {
	d, err := m.encode()
	if err != nil {
		return err
	}

	if a == nil {
		_, err = l.Write(d)
	} else {
		_, err = l.WriteTo(d, a)
	}
	return err
}

// Receive a message.
func Receive(l *net.UDPConn, buf []byte) (Message, error) {
	l.SetReadDeadline(time.Now().Add(RESPONSE_TIMEOUT))

	nr, _, err := l.ReadFromUDP(buf)
	if err != nil {
		return Message{}, err
	}
	return parseMessage(buf[:nr])
}

// Bind to the given address and serve requests forever.
func ListenAndServe(n, addr string, rh Handler) error {
	uaddr, err := net.ResolveUDPAddr(n, addr)
	if err != nil {
		return err
	}

	l, err := net.ListenUDP(n, uaddr)
	if err != nil {
		return err
	}

	buf := make([]byte, maxPktLen)
	for {
		nr, addr, err := l.ReadFromUDP(buf)
		if err == nil {
			tmp := make([]byte, nr)
			copy(tmp, buf)
			go handlePacket(l, tmp, addr, rh)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net"
	"net/http"
	"net/rpc"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"

	"github.com/codegangsta/cli"
	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/joho/godotenv"
	"github.com/syhlion/redisocket.v2"
	"github.com/syhlion/requestwork.v2"
)

var env *string
var (
	version     string
	compileDate string
	name        string
	cmdSlave    = cli.Command{
		Name:   "slave",
		Usage:  "start gusher.slave server",
		Action: slave,
	}
	cmdMaster = cli.Command{
		Name:   "master",
		Usage:  "start gusher.master server",
		Action: master,
	}
	rpool                      *redis.Pool
	worker                     *requestwork.Worker
	rsocket                    redisocket.App
	logger                     *Logger
	client                     *rpc.Client
	loglevel                   string
	externalIP                 string
	api_listen                 string
	master_api_listen          string
	master_addr                string
	redis_addr                 string
	remote_listen              string
	return_serverinfo_interval string
	wm                         *WsManager
	slaveInfos                 *SlaveInfos
)

func init() {
	/*logger init*/
	logger = &Logger{logrus.New()}
	//logger.Level = logrus.DebugLevel
	switch loglevel {
	case "DEV":
		logger.Level = logrus.DebugLevel
		break
	case "PRODUCTION":
		logger.Level = logrus.InfoLevel
		break
	default:
		logger.Level = logrus.DebugLevel
		break
	}

}

//slave server
func slave(c *cli.Context) {
	varInit()

	r_interval, err := strconv.Atoi(return_serverinfo_interval)
	if err != nil {
		logger.Fatal(err)
	}

	rsocket = redisocket.NewApp(rpool)
	rsocketErr := make(chan error, 1)
	go func() {
		err := rsocket.Listen()
		rsocketErr <- err
	}()

	/*api start*/
	apiListener, err := net.Listen("tcp", api_listen)
	if err != nil {
		logger.Fatal(err)
	}
	r := mux.NewRouter()

	worker = requestwork.New(50)
	wm = &WsManager{
		users:   make(map[*User]bool),
		RWMutex: &sync.RWMutex{},
		pool:    rpool,
	}
	/*api end*/

	/*remote rpc*/
	client, err = rpc.Dial("tcp", master_addr)
	if err != nil {
		logger.Fatal("Cant remote rpc %s", err)
	}

	/*remote process*/
	remoteErr := make(chan error, 1)
	go func() {
		t := time.NewTicker(time.Duration(r_interval) * time.Second)
		for {
			select {
			case <-t.C:
				var b bool
				info := getInfo()
				err = client.Call("HealthTrack.Put", &info, &b)
				if err != nil {
					remoteErr <- err
					return
				}

			}
		}
	}()

	/*remote preocess end*/

	r.HandleFunc("/ws/{app_key}", HttpUse(wm.Connect, AuthMiddleware)).Methods("GET")
	http.Handle("/", handlers.CombinedLoggingHandler(os.Stdout, r))
	serverError := make(chan error, 1)
	go func() {
		err := http.Serve(apiListener, nil)
		serverError <- err
	}()

	// block and listen syscall
	shutdow_observer := make(chan os.Signal, 1)
	logger.Info(loglevel, " mode")
	logger.Info(name, " slave start ! ")
	logger.Infof("listen redis in %s", redis_addr)
	logger.Infof("listen web api  in %s", api_listen)
	logger.Infof("localhost ip is  %s", externalIP)
	logger.Infof("master ip  %s", master_addr)
	signal.Notify(shutdow_observer, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-shutdow_observer:
		logger.Info("receive signal")
	case err := <-serverError:
		logger.Fatal(err)
	case err := <-rsocketErr:
		logger.Fatal(err)
	case err := <-remoteErr:
		logger.Fatal(err)
	}

}

// master server
func master(c *cli.Context) {

	varInit()

	slaveInfos = &SlaveInfos{
		servers: make(map[string]ServerInfo),
		lock:    &sync.Mutex{},
	}
	/*remote start*/
	healthTrack := &HealthTrack{
		s: slaveInfos,
	}
	addr, err := net.ResolveTCPAddr("tcp", remote_listen)
	if err != nil {
		logger.Fatal(err)
	}
	in, err := net.ListenTCP("tcp", addr)
	if err != nil {
		logger.Fatal(err)
	}
	rpc.Register(healthTrack)
	go func() {
		rpc.Accept(in)
	}()

	/*api start*/
	apiListener, err := net.Listen("tcp", master_api_listen)
	if err != nil {
		logger.Fatal(err)
	}
	r := mux.NewRouter()

	r.HandleFunc("/api/system/slaveinfos", SystemInfo).Methods("GET")
	r.HandleFunc("/api/exist/{app_key}", CheckAppKey).Methods("GET")
	r.HandleFunc("/api/register/{app_key}", RegisterAppKey).Methods("POST")
	r.HandleFunc("/api/query/{app_key}", QueryAppKey).Methods("GET")
	r.HandleFunc("/api/push/{app_key}/{channel}/{event}", PushMessage).Methods("POST")
	http.Handle("/", handlers.CombinedLoggingHandler(os.Stdout, r))
	serverError := make(chan error, 1)
	go func() {
		err := http.Serve(apiListener, nil)
		serverError <- err
	}()

	/*Test redis connect*/
	_, err = rpool.Get().Do("PING")
	if err != nil {
		logger.Fatal(err)
	}

	// block and listen syscall
	shutdow_observer := make(chan os.Signal, 1)
	logger.Info(loglevel, " mode")
	logger.Info(name, " master start ! ")
	logger.Infof("listen redis in %s", redis_addr)
	logger.Infof("listen web api in %s", master_api_listen)
	logger.Infof("listen master in  %s", remote_listen)
	logger.Infof("localhost ip is  %s", externalIP)
	signal.Notify(shutdow_observer, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-shutdow_observer:
		logger.Info("Receive signal")
	case err := <-serverError:
		logger.Warn(err)
	}

}

func varInit() {
	/*env init*/
	pwd, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		logger.Fatal(err)
	}
	envfile := flag.String("env", pwd+"/.env", ".env file path")
	flag.Parse()
	err = godotenv.Load(*envfile)
	if err != nil {
		logger.Fatal(err)
	}
	master_addr = os.Getenv("MASTER_ADDR")
	if master_addr == "" {
		logger.Fatal("empty master_addr")
	}

	loglevel = os.Getenv("LOGLEVEL")
	if loglevel == "" {
		logger.Fatal("empty loglevel")
	}
	redis_addr = os.Getenv("REDIS_ADDR")
	if redis_addr == "" {
		logger.Fatal("empty redis_addr")
	}
	master_api_listen = os.Getenv("MASTER_API_LISTEN")
	if master_api_listen == "" {
		logger.Fatal("empty master_api_listen")
	}
	remote_listen = os.Getenv("REMOTE_LISTEN")
	if remote_listen == "" {
		logger.Fatal("empty remote_listen")
	}
	redis_addr = os.Getenv("REDIS_ADDR")
	if redis_addr == "" {
		logger.Fatal("empty redis_addr")
	}
	api_listen = os.Getenv("API_LISTEN")
	if api_listen == "" {
		logger.Fatal("empty api_listen")
	}
	return_serverinfo_interval = os.Getenv("RETURN_SERVERINFO_INTERVAL")
	if return_serverinfo_interval == "" {
		logger.Fatal("empty return_serverinfo_interval")
	}

	/*log init*/
	switch loglevel {
	case "DEV":
		logger.Level = logrus.DebugLevel
		break
	case "PRODUCTION":
		logger.Level = logrus.InfoLevel
		break
	default:
		logger.Level = logrus.DebugLevel
		break
	}

	/*redis init*/
	rpool = redis.NewPool(func() (redis.Conn, error) {
		return redis.Dial("tcp", redis_addr)
	}, 10)

	/*externl ip*/
	externalIP, err = getExternalIP()
	if err != nil {
		logger.Fatal(err)
	}
}

func main() {
	gusher := cli.NewApp()
	gusher.Name = name
	gusher.Version = version
	gusher.Commands = []cli.Command{
		cmdSlave,
		cmdMaster,
	}
	gusher.Compiled = time.Now()
	gusher.Run(os.Args)

}
<commit_msg>fix cli package use<commit_after>package main

import (
	"net"
	"net/http"
	"net/rpc"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
	"time"

	"github.com/Sirupsen/logrus"

	"github.com/garyburd/redigo/redis"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"github.com/joho/godotenv"
	"github.com/syhlion/redisocket.v2"
	"github.com/syhlion/requestwork.v2"
	"github.com/urfave/cli"
)

var env *string
var (
	version     string
	compileDate string
	name        string
	cmdSlave    = cli.Command{
		Name:   "slave",
		Usage:  "start gusher.slave server",
		Action: slave,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "env",
				Value: "/.env",
			},
		},
	}
	cmdMaster = cli.Command{
		Name:   "master",
		Usage:  "start gusher.master server",
		Action: master,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "env",
				Value: "/.env",
			},
		},
	}
	rpool                      *redis.Pool
	worker                     *requestwork.Worker
	rsocket                    redisocket.App
	logger                     *Logger
	client                     *rpc.Client
	loglevel                   string
	externalIP                 string
	api_listen                 string
	master_api_listen          string
	master_addr                string
	redis_addr                 string
	remote_listen              string
	return_serverinfo_interval string
	wm                         *WsManager
	slaveInfos                 *SlaveInfos
)

func init() {
	/*logger init*/
	logger = &Logger{logrus.New()}
	//logger.Level = logrus.DebugLevel
	switch loglevel {
	case "DEV":
		logger.Level = logrus.DebugLevel
		break
	case "PRODUCTION":
		logger.Level = logrus.InfoLevel
		break
	default:
		logger.Level = logrus.DebugLevel
		break
	}

}

//slave server
func slave(c *cli.Context) {
	varInit(c)

	r_interval, err := strconv.Atoi(return_serverinfo_interval)
	if err != nil {
		logger.Fatal(err)
	}

	rsocket = redisocket.NewApp(rpool)
	rsocketErr := make(chan error, 1)
	go func() {
		err := rsocket.Listen()
		rsocketErr <- err
	}()

	/*api start*/
	apiListener, err := net.Listen("tcp", api_listen)
	if err != nil {
		logger.Fatal(err)
	}
	r := mux.NewRouter()

	worker = requestwork.New(50)
	wm = &WsManager{
		users:   make(map[*User]bool),
		RWMutex: &sync.RWMutex{},
		pool:    rpool,
	}
	/*api end*/

	/*remote rpc*/
	client, err = rpc.Dial("tcp", master_addr)
	if err != nil {
		logger.Fatal("Cant remote rpc %s", err)
	}

	/*remote process*/
	remoteErr := make(chan error, 1)
	go func() {
		t := time.NewTicker(time.Duration(r_interval) * time.Second)
		for {
			select {
			case <-t.C:
				var b bool
				info := getInfo()
				err = client.Call("HealthTrack.Put", &info, &b)
				if err != nil {
					remoteErr <- err
					return
				}

			}
		}
	}()

	/*remote preocess end*/

	r.HandleFunc("/ws/{app_key}", HttpUse(wm.Connect, AuthMiddleware)).Methods("GET")
	http.Handle("/", handlers.CombinedLoggingHandler(os.Stdout, r))
	serverError := make(chan error, 1)
	go func() {
		err := http.Serve(apiListener, nil)
		serverError <- err
	}()

	// block and listen syscall
	shutdow_observer := make(chan os.Signal, 1)
	logger.Info(loglevel, " mode")
	logger.Info(name, " slave start ! ")
	logger.Infof("listen redis in %s", redis_addr)
	logger.Infof("listen web api  in %s", api_listen)
	logger.Infof("localhost ip is  %s", externalIP)
	logger.Infof("master ip  %s", master_addr)
	signal.Notify(shutdow_observer, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-shutdow_observer:
		logger.Info("receive signal")
	case err := <-serverError:
		logger.Fatal(err)
	case err := <-rsocketErr:
		logger.Fatal(err)
	case err := <-remoteErr:
		logger.Fatal(err)
	}

}

// master server
func master(c *cli.Context) {

	varInit(c)

	slaveInfos = &SlaveInfos{
		servers: make(map[string]ServerInfo),
		lock:    &sync.Mutex{},
	}
	/*remote start*/
	healthTrack := &HealthTrack{
		s: slaveInfos,
	}
	addr, err := net.ResolveTCPAddr("tcp", remote_listen)
	if err != nil {
		logger.Fatal(err)
	}
	in, err := net.ListenTCP("tcp", addr)
	if err != nil {
		logger.Fatal(err)
	}
	rpc.Register(healthTrack)
	go func() {
		rpc.Accept(in)
	}()

	/*api start*/
	apiListener, err := net.Listen("tcp", master_api_listen)
	if err != nil {
		logger.Fatal(err)
	}
	r := mux.NewRouter()

	r.HandleFunc("/api/system/slaveinfos", SystemInfo).Methods("GET")
	r.HandleFunc("/api/exist/{app_key}", CheckAppKey).Methods("GET")
	r.HandleFunc("/api/register/{app_key}", RegisterAppKey).Methods("POST")
	r.HandleFunc("/api/query/{app_key}", QueryAppKey).Methods("GET")
	r.HandleFunc("/api/push/{app_key}/{channel}/{event}", PushMessage).Methods("POST")
	http.Handle("/", handlers.CombinedLoggingHandler(os.Stdout, r))
	serverError := make(chan error, 1)
	go func() {
		err := http.Serve(apiListener, nil)
		serverError <- err
	}()

	/*Test redis connect*/
	_, err = rpool.Get().Do("PING")
	if err != nil {
		logger.Fatal(err)
	}

	// block and listen syscall
	shutdow_observer := make(chan os.Signal, 1)
	logger.Info(loglevel, " mode")
	logger.Info(name, " master start ! ")
	logger.Infof("listen redis in %s", redis_addr)
	logger.Infof("listen web api in %s", master_api_listen)
	logger.Infof("listen master in  %s", remote_listen)
	logger.Infof("localhost ip is  %s", externalIP)
	signal.Notify(shutdow_observer, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
	select {
	case <-shutdow_observer:
		logger.Info("Receive signal")
	case err := <-serverError:
		logger.Warn(err)
	}

}

func varInit(c *cli.Context) {
	/*env init*/
	pwd, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		logger.Fatal(err)
	}

	envfile := pwd + "/" + c.String("env")
	//flag.Parse()
	err = godotenv.Load(envfile)
	if err != nil {
		logger.Fatal(err)
	}
	master_addr = os.Getenv("MASTER_ADDR")
	if master_addr == "" {
		logger.Fatal("empty master_addr")
	}

	loglevel = os.Getenv("LOGLEVEL")
	if loglevel == "" {
		logger.Fatal("empty loglevel")
	}
	redis_addr = os.Getenv("REDIS_ADDR")
	if redis_addr == "" {
		logger.Fatal("empty redis_addr")
	}
	master_api_listen = os.Getenv("MASTER_API_LISTEN")
	if master_api_listen == "" {
		logger.Fatal("empty master_api_listen")
	}
	remote_listen = os.Getenv("REMOTE_LISTEN")
	if remote_listen == "" {
		logger.Fatal("empty remote_listen")
	}
	redis_addr = os.Getenv("REDIS_ADDR")
	if redis_addr == "" {
		logger.Fatal("empty redis_addr")
	}
	api_listen = os.Getenv("API_LISTEN")
	if api_listen == "" {
		logger.Fatal("empty api_listen")
	}
	return_serverinfo_interval = os.Getenv("RETURN_SERVERINFO_INTERVAL")
	if return_serverinfo_interval == "" {
		logger.Fatal("empty return_serverinfo_interval")
	}

	/*log init*/
	switch loglevel {
	case "DEV":
		logger.Level = logrus.DebugLevel
		break
	case "PRODUCTION":
		logger.Level = logrus.InfoLevel
		break
	default:
		logger.Level = logrus.DebugLevel
		break
	}

	/*redis init*/
	rpool = redis.NewPool(func() (redis.Conn, error) {
		return redis.Dial("tcp", redis_addr)
	}, 10)

	/*externl ip*/
	externalIP, err = getExternalIP()
	if err != nil {
		logger.Fatal(err)
	}
}

func main() {
	gusher := cli.NewApp()
	gusher.Name = name
	gusher.Version = version
	gusher.Commands = []cli.Command{
		cmdSlave,
		cmdMaster,
	}
	gusher.Compiled = time.Now()
	gusher.Run(os.Args)

}
<|endoftext|>


<commit_before>package main

import (
  "database/sql"
  _ "github.com/go-sql-driver/mysql"
)

func main() {
  db, err := sql.Open("mysql", "root@127.0.0.1/ops")
  if err != nil { panic(err) }
  defer db.Close()
}
<commit_msg>the second worst go program maybe ever<commit_after>package main

import (
  "database/sql"
  _ "github.com/go-sql-driver/mysql"
  "github.com/codegangsta/martini"
  "encoding/json"
  "strconv"
)

func main() {
  m := martini.Classic()

  db, err := sql.Open("mysql", "root@127.0.0.1/ops")
  if err != nil { panic(err) }
  defer db.Close()

  m.Map(db)

  schoolOne := School{Id: 1, Name: "Millard North High School", CountyId: 1, DistrictId: 1}
  schoolTwo := School{Id: 2, Name: "Millard South High School", CountyId: 1, DistrictId: 1}
  schools := []School{schoolOne, schoolTwo}

  m.Get("/schools", func() string {
    llSchoolsJ, err := json.Marshal(schools)
    if err != nil { panic(err) }
    return string(llSchoolsJ[:])
  })

  m.Get("/schools/:id", func(params martini.Params) string {
    school := schoolFind(schools, params["id"])
    llSchoolJ, err := json.Marshal(school)
    if err != nil { panic(err) }
    return string(llSchoolJ[:])
  })

  m.Run()
}

func schoolFind(schools []School, id string) School {
  schoolId, err := strconv.ParseInt(id, 0, 64)
  if err != nil { panic(err) }

  for _, value := range schools {
    if value.Id == schoolId {
      return value
    }
  }

  return School{}
}

type School struct {
  Id          int64
  Name        string `sql:"size:255"`
  CountyId    int64
  DistrictId  int64
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/gen/route53"
	hh "github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/flynn/flynn/pkg/httphelper"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/flynn/flynn/pkg/random"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	_ "github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/lib/pq"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/speps/go-hashids"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/gopkg.in/macaroon.v1"
)

func main() {
	awsCreds, err := aws.EnvCreds()
	if err != nil {
		panic(err)
	}
	db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	api := &API{
		db:     db,
		domain: os.Getenv("DOMAIN"),
		domainHash: hashids.NewWithData(&hashids.HashIDData{
			Salt:      os.Getenv("DOMAIN_SALT"),
			Alphabet:  "abcdefghijklmnopqrstuvwxyz0123456789",
			MinLength: 2,
		}),
		zoneID: aws.String(os.Getenv("ZONE_ID")),
		r53:    route53.New(awsCreds, "us-east-1", nil),
	}

	router.POST("/domains", api.AllocateDomain)
	router.PUT("/domains/:id", api.AuthHandler(api.ProvisionDomain))
	router.GET("/domains/:id/status", api.AuthHandler(api.GetStatus))

	http.ListenAndServe(":"+os.Getenv("PORT"), router)
}

type API struct {
	db         *sql.DB
	domain     string
	domainHash *hashids.HashID
	zoneID     aws.StringValue
	r53        *route53.Route53
}

type DomainCreateRes struct {
	Domain string `json:"domain"`
	Token  []byte `json:"token"`
}

func (a *API) AllocateDomain(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	var id int
	if err := a.db.QueryRow("SELECT nextval('domain_seeds')").Scan(&id); err != nil {
		hh.Error(w, err)
		return
	}
	sub, _ := a.domainHash.Encode([]int{id})
	domain := fmt.Sprintf("%s.%s", sub, a.domain)
	key := random.Bytes(sha256.Size)

	var domainID string
	const insert = "INSERT INTO domains (domain, access_key, creator_ip) VALUES ($1, $2, $3) RETURNING domain_id"
	if err := a.db.QueryRow(insert, domain, key, sourceIP(req)).Scan(&domainID); err != nil {
		hh.Error(w, err)
		return
	}

	m, err := macaroon.New(key, domainID, "")
	if err != nil {
		hh.Error(w, err)
		return
	}
	res := &DomainCreateRes{Domain: domain}
	res.Token, err = m.MarshalBinary()
	if err != nil {
		hh.Error(w, err)
		return
	}

	hh.JSON(w, 200, res)
}

func nopChecker(caveat string) error {
	return fmt.Errorf("unexpected caveat %s", caveat)
}

func (a *API) AuthHandler(h httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		var domainID string
		var key []byte
		const get = "SELECT domain_id, access_key FROM domains WHERE domain = $1"
		if err := a.db.QueryRow(get, params.ByName("id")).Scan(&domainID, &key); err != nil {
			hh.Error(w, err)
			return
		}

		auth := req.Header.Get("Authorization")
		if !strings.HasPrefix(auth, "Token ") {
			hh.JSON(w, 401, struct{}{})
			return
		}
		serialized, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Token "))
		if err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}

		var m macaroon.Macaroon
		if err := m.UnmarshalBinary(serialized); err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}
		if err := m.Verify(key, nopChecker, nil); err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}

		h(w, req, params)
	}
}

type ProvisionReq struct {
	Nameservers []string `json:"nameservers"`
}

var nameserverPattern = regexp.MustCompile(`\Ans-?\d+\.((awsdns-\d+(\.[a-z]{1,3}){1,2})|(digitalocean\.com))\z`)

func (a *API) ProvisionDomain(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	domain := params.ByName("id")

	var reqData ProvisionReq
	if err := hh.DecodeJSON(req, &reqData); err != nil {
		hh.Error(w, err)
		return
	}
	if len(reqData.Nameservers) < 4 || len(reqData.Nameservers) > 10 {
		// TODO: log it
		hh.JSON(w, 400, struct{}{})
		return
	}
	for _, n := range reqData.Nameservers {
		if !nameserverPattern.MatchString(n) {
			// TODO: log it
			hh.JSON(w, 400, struct{}{})
			return
		}
	}

	nsData, _ := json.Marshal(reqData.Nameservers)
	const nsUpdate = "UPDATE domains SET nameservers = $2 WHERE domain = $1 AND nameservers IS NULL"
	updateRes, err := a.db.Exec(nsUpdate, domain, nsData)
	if err != nil {
		hh.Error(w, err)
		return
	}
	if n, _ := updateRes.RowsAffected(); n != 1 {
		// TODO(titanous): don't error if the nameservers are the same and there is no route
		hh.JSON(w, 400, struct{}{})
		return
	}

	records := make([]route53.ResourceRecord, len(reqData.Nameservers))
	for i, ns := range reqData.Nameservers {
		records[i].Value = aws.String(ns)
	}

	dnsReq := &route53.ChangeResourceRecordSetsRequest{
		HostedZoneID: a.zoneID,
		ChangeBatch: &route53.ChangeBatch{
			Changes: []route53.Change{{
				Action: aws.String(route53.ChangeActionCreate),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name:            aws.String(domain + "."),
					TTL:             aws.Long(3600),
					Type:            aws.String(route53.RRTypeNs),
					ResourceRecords: records,
				},
			}},
		},
	}
	dnsRes, err := a.r53.ChangeResourceRecordSets(dnsReq)
	if err != nil {
		hh.Error(w, err)
		return
	}

	const updateChange = "UPDATE domains SET external_change_id = $2 WHERE domain = $1"
	if _, err := a.db.Exec(updateChange, domain, dnsRes.ChangeInfo.ID); err != nil {
		hh.Error(w, err)
		return
	}

	hh.JSON(w, 200, struct{}{})
}

type StatusResponse struct {
	Status string `json:"status"`
}

var statusApplied = &StatusResponse{"applied"}
var statusPending = &StatusResponse{"pending"}

func (a *API) GetStatus(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	var changeID *string
	var applied bool
	domain := params.ByName("id")
	const get = "SELECT external_change_id, external_change_applied FROM domains WHERE domain = $1"
	if err := a.db.QueryRow(get, domain).Scan(&changeID, &applied); err != nil {
		hh.Error(w, err)
		return
	}
	if changeID == nil || *changeID == "" {
		hh.JSON(w, 404, struct{}{})
		return
	}
	if applied {
		hh.JSON(w, 200, statusApplied)
		return
	}

	*changeID = strings.TrimPrefix(*changeID, "/change/")
	res, err := a.r53.GetChange(&route53.GetChangeRequest{ID: changeID})
	if err != nil {
		// TODO(titanous): check NoSuchChange
		hh.Error(w, err)
		return
	}

	if *res.ChangeInfo.Status != route53.ChangeStatusInsync {
		hh.JSON(w, 200, statusPending)
		return
	}
	const update = "UPDATE domains SET external_change_applied = true WHERE domain = $1"
	if _, err := a.db.Exec(update, domain); err != nil {
		hh.Error(w, err)
		return
	}
	hh.JSON(w, 200, statusApplied)
}

func sourceIP(req *http.Request) string {
	if xff := req.Header.Get("X-Forwarded-For"); xff != "" {
		ips := strings.Split(xff, ",")
		return strings.TrimSpace(ips[len(ips)-1])
	}
	ip, _, _ := net.SplitHostPort(req.RemoteAddr)
	return ip
}
<commit_msg>Lower min name servers to 3<commit_after>package main

import (
	"crypto/sha256"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net"
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/gen/route53"
	hh "github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/flynn/flynn/pkg/httphelper"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/flynn/flynn/pkg/random"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/julienschmidt/httprouter"
	_ "github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/lib/pq"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/github.com/speps/go-hashids"
	"github.com/flynn/subdomainer/Godeps/_workspace/src/gopkg.in/macaroon.v1"
)

func main() {
	awsCreds, err := aws.EnvCreds()
	if err != nil {
		panic(err)
	}
	db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
	if err != nil {
		panic(err)
	}

	router := httprouter.New()
	api := &API{
		db:     db,
		domain: os.Getenv("DOMAIN"),
		domainHash: hashids.NewWithData(&hashids.HashIDData{
			Salt:      os.Getenv("DOMAIN_SALT"),
			Alphabet:  "abcdefghijklmnopqrstuvwxyz0123456789",
			MinLength: 2,
		}),
		zoneID: aws.String(os.Getenv("ZONE_ID")),
		r53:    route53.New(awsCreds, "us-east-1", nil),
	}

	router.POST("/domains", api.AllocateDomain)
	router.PUT("/domains/:id", api.AuthHandler(api.ProvisionDomain))
	router.GET("/domains/:id/status", api.AuthHandler(api.GetStatus))

	http.ListenAndServe(":"+os.Getenv("PORT"), router)
}

type API struct {
	db         *sql.DB
	domain     string
	domainHash *hashids.HashID
	zoneID     aws.StringValue
	r53        *route53.Route53
}

type DomainCreateRes struct {
	Domain string `json:"domain"`
	Token  []byte `json:"token"`
}

func (a *API) AllocateDomain(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	var id int
	if err := a.db.QueryRow("SELECT nextval('domain_seeds')").Scan(&id); err != nil {
		hh.Error(w, err)
		return
	}
	sub, _ := a.domainHash.Encode([]int{id})
	domain := fmt.Sprintf("%s.%s", sub, a.domain)
	key := random.Bytes(sha256.Size)

	var domainID string
	const insert = "INSERT INTO domains (domain, access_key, creator_ip) VALUES ($1, $2, $3) RETURNING domain_id"
	if err := a.db.QueryRow(insert, domain, key, sourceIP(req)).Scan(&domainID); err != nil {
		hh.Error(w, err)
		return
	}

	m, err := macaroon.New(key, domainID, "")
	if err != nil {
		hh.Error(w, err)
		return
	}
	res := &DomainCreateRes{Domain: domain}
	res.Token, err = m.MarshalBinary()
	if err != nil {
		hh.Error(w, err)
		return
	}

	hh.JSON(w, 200, res)
}

func nopChecker(caveat string) error {
	return fmt.Errorf("unexpected caveat %s", caveat)
}

func (a *API) AuthHandler(h httprouter.Handle) httprouter.Handle {
	return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
		var domainID string
		var key []byte
		const get = "SELECT domain_id, access_key FROM domains WHERE domain = $1"
		if err := a.db.QueryRow(get, params.ByName("id")).Scan(&domainID, &key); err != nil {
			hh.Error(w, err)
			return
		}

		auth := req.Header.Get("Authorization")
		if !strings.HasPrefix(auth, "Token ") {
			hh.JSON(w, 401, struct{}{})
			return
		}
		serialized, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Token "))
		if err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}

		var m macaroon.Macaroon
		if err := m.UnmarshalBinary(serialized); err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}
		if err := m.Verify(key, nopChecker, nil); err != nil {
			hh.JSON(w, 400, struct{}{})
			return
		}

		h(w, req, params)
	}
}

type ProvisionReq struct {
	Nameservers []string `json:"nameservers"`
}

var nameserverPattern = regexp.MustCompile(`\Ans-?\d+\.((awsdns-\d+(\.[a-z]{1,3}){1,2})|(digitalocean\.com))\z`)

func (a *API) ProvisionDomain(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	domain := params.ByName("id")

	var reqData ProvisionReq
	if err := hh.DecodeJSON(req, &reqData); err != nil {
		hh.Error(w, err)
		return
	}
	if len(reqData.Nameservers) < 3 || len(reqData.Nameservers) > 10 {
		// TODO: log it
		hh.JSON(w, 400, struct{}{})
		return
	}
	for _, n := range reqData.Nameservers {
		if !nameserverPattern.MatchString(n) {
			// TODO: log it
			hh.JSON(w, 400, struct{}{})
			return
		}
	}

	nsData, _ := json.Marshal(reqData.Nameservers)
	const nsUpdate = "UPDATE domains SET nameservers = $2 WHERE domain = $1 AND nameservers IS NULL"
	updateRes, err := a.db.Exec(nsUpdate, domain, nsData)
	if err != nil {
		hh.Error(w, err)
		return
	}
	if n, _ := updateRes.RowsAffected(); n != 1 {
		// TODO(titanous): don't error if the nameservers are the same and there is no route
		hh.JSON(w, 400, struct{}{})
		return
	}

	records := make([]route53.ResourceRecord, len(reqData.Nameservers))
	for i, ns := range reqData.Nameservers {
		records[i].Value = aws.String(ns)
	}

	dnsReq := &route53.ChangeResourceRecordSetsRequest{
		HostedZoneID: a.zoneID,
		ChangeBatch: &route53.ChangeBatch{
			Changes: []route53.Change{{
				Action: aws.String(route53.ChangeActionCreate),
				ResourceRecordSet: &route53.ResourceRecordSet{
					Name:            aws.String(domain + "."),
					TTL:             aws.Long(3600),
					Type:            aws.String(route53.RRTypeNs),
					ResourceRecords: records,
				},
			}},
		},
	}
	dnsRes, err := a.r53.ChangeResourceRecordSets(dnsReq)
	if err != nil {
		hh.Error(w, err)
		return
	}

	const updateChange = "UPDATE domains SET external_change_id = $2 WHERE domain = $1"
	if _, err := a.db.Exec(updateChange, domain, dnsRes.ChangeInfo.ID); err != nil {
		hh.Error(w, err)
		return
	}

	hh.JSON(w, 200, struct{}{})
}

type StatusResponse struct {
	Status string `json:"status"`
}

var statusApplied = &StatusResponse{"applied"}
var statusPending = &StatusResponse{"pending"}

func (a *API) GetStatus(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	var changeID *string
	var applied bool
	domain := params.ByName("id")
	const get = "SELECT external_change_id, external_change_applied FROM domains WHERE domain = $1"
	if err := a.db.QueryRow(get, domain).Scan(&changeID, &applied); err != nil {
		hh.Error(w, err)
		return
	}
	if changeID == nil || *changeID == "" {
		hh.JSON(w, 404, struct{}{})
		return
	}
	if applied {
		hh.JSON(w, 200, statusApplied)
		return
	}

	*changeID = strings.TrimPrefix(*changeID, "/change/")
	res, err := a.r53.GetChange(&route53.GetChangeRequest{ID: changeID})
	if err != nil {
		// TODO(titanous): check NoSuchChange
		hh.Error(w, err)
		return
	}

	if *res.ChangeInfo.Status != route53.ChangeStatusInsync {
		hh.JSON(w, 200, statusPending)
		return
	}
	const update = "UPDATE domains SET external_change_applied = true WHERE domain = $1"
	if _, err := a.db.Exec(update, domain); err != nil {
		hh.Error(w, err)
		return
	}
	hh.JSON(w, 200, statusApplied)
}

func sourceIP(req *http.Request) string {
	if xff := req.Header.Get("X-Forwarded-For"); xff != "" {
		ips := strings.Split(xff, ",")
		return strings.TrimSpace(ips[len(ips)-1])
	}
	ip, _, _ := net.SplitHostPort(req.RemoteAddr)
	return ip
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	redirectC := controllers.NewRedirectController(c)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	// Redirect old podcast URLs
	getRouter.HandleFunc("/uryplayer/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/ontap/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/podcasts/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		redirectC.Redirect(w, r, fmt.Sprintf("/podcasts/%d/", id), 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/player/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		redirectC.Redirect(w, r, fmt.Sprintf("/podcasts/%d/player/", id), 301)
	})

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)

	// End routes

	s.UseHandler(router)

	return &s, nil

}
<commit_msg>Redirect plain schedule url to this week.<commit_after>package main

import (
	"fmt"
	"net/http"
	"strconv"

	"github.com/UniversityRadioYork/2016-site/controllers"
	"github.com/UniversityRadioYork/2016-site/structs"
	"github.com/UniversityRadioYork/myradio-go"
	"github.com/codegangsta/negroni"
	"github.com/gorilla/mux"
)

// Server is the type of the main 2016site web application.
type Server struct {
	*negroni.Negroni
}

// NewServer creates a 2016site server based on the config c.
func NewServer(c *structs.Config) (*Server, error) {

	s := Server{negroni.Classic()}

	session, err := myradio.NewSessionFromKeyFile()

	if err != nil {
		return &s, err
	}

	router := mux.NewRouter().StrictSlash(true)

	getRouter := router.Methods("GET").Subrouter()
	postRouter := router.Methods("POST").Subrouter()

	// Routes go in here
	nfc := controllers.NewNotFoundController(c)
	router.NotFoundHandler = http.HandlerFunc(nfc.Get)

	redirectC := controllers.NewRedirectController(c)

	ic := controllers.NewIndexController(session, c)
	getRouter.HandleFunc("/", ic.Get)

	sc := controllers.NewSearchController(session, c)
	getRouter.HandleFunc("/search/", sc.Get)

	showC := controllers.NewShowController(session, c)
	getRouter.HandleFunc("/schedule/shows/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	getRouter.HandleFunc("/schedule/shows/{id:[0-9]+}/", showC.GetShow).Name("show")
	getRouter.HandleFunc("/schedule/shows/timeslots/{id:[0-9]+}/", showC.GetTimeslot).Name("timeslot")
	getRouter.HandleFunc("/schedule/shows/seasons/{id:[0-9]+}/", showC.GetSeason).Name("season")

	getRouter.HandleFunc("/schedule/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/schedule/thisweek/", 301)
	})
	// NOTE: NewScheduleWeekController assumes 'timeslot' is installed BEFORE it is called.
	schedWeekC := controllers.NewScheduleWeekController(session, getRouter, c)
	getRouter.HandleFunc("/schedule/thisweek/", schedWeekC.GetThisWeek).Name("schedule-thisweek")

	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/", schedWeekC.GetByYearWeek).Name("schedule-week")
	// This route exists so that day schedule links from the previous website aren't broken.
	getRouter.HandleFunc("/schedule/{year:[1-9][0-9][0-9][0-9]}/w{week:[0-5]?[0-9]}/{day:[1-7]}/", schedWeekC.GetByYearWeek).Name("schedule-week-day-compat")

	// Redirect old podcast URLsc
	getRouter.HandleFunc("/uryplayer/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/ontap/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/", func(w http.ResponseWriter, r *http.Request) {
		redirectC.Redirect(w, r, "/podcasts/", 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		redirectC.Redirect(w, r, fmt.Sprintf("/podcasts/%d/", id), 301)
	})
	getRouter.HandleFunc("/uryplayer/podcasts/{id:[0-9]+}/player/", func(w http.ResponseWriter, r *http.Request) {
		vars := mux.Vars(r)
		id, _ := strconv.Atoi(vars["id"])
		redirectC.Redirect(w, r, fmt.Sprintf("/podcasts/%d/player/", id), 301)
	})

	pc := controllers.NewPeopleController(session, c)
	getRouter.HandleFunc("/people/{id:[0-9]+}/", pc.Get)

	teamC := controllers.NewTeamController(session, c)
	getRouter.HandleFunc("/teams/", teamC.GetAll)
	getRouter.HandleFunc("/teams/{alias}/", teamC.Get)

	getinvolvedC := controllers.NewGetInvolvedController(session, c)
	getRouter.HandleFunc("/getinvolved/", getinvolvedC.Get)

	signupC := controllers.NewSignUpController(session, c)
	postRouter.HandleFunc("/signup/", signupC.Post)

	staticC := controllers.NewStaticController(c)
	getRouter.HandleFunc("/about/", staticC.GetAbout)
	getRouter.HandleFunc("/contact/", staticC.GetContact)
	getRouter.HandleFunc("/competitions/", staticC.GetCompetitions)

	// End routes

	s.UseHandler(router)

	return &s, nil

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	//"io/ioutil"
	"log"
	"net/http"
	"os"
	//"strings"
)

func receive(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Hello world!")
}

func main() {
	// Read the port from the file.
	//fileContents, err := ioutil.ReadFile("port.txt")
	//if err != nil {
	//	log.Fatal(err)
	//}
	//port := strings.TrimSpace(string(fileContents))
	if len(os.Args) != 2 {
		log.Fatal("usage: server.go port")
	}
	port := os.Args[1]

	// Start the server.
	fmt.Printf("Starting TxtRoulette server on port %s...\n", port)
	http.HandleFunc("/receive", receive)
	log.Fatal(http.ListenAndServe(port, nil))
}
<commit_msg>Fix arg<commit_after>package main

import (
	"fmt"
	"io"
	//"io/ioutil"
	"log"
	"net/http"
	"os"
	//"strings"
)

func receive(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Hello world!")
}

func main() {
	// Read the port from the file.
	//fileContents, err := ioutil.ReadFile("port.txt")
	//if err != nil {
	//	log.Fatal(err)
	//}
	//port := strings.TrimSpace(string(fileContents))
	if len(os.Args) != 2 {
		log.Fatal("usage: server.go port")
	}
	port := ":" + os.Args[1]

	// Start the server.
	fmt.Printf("Starting TxtRoulette server on port %s...\n", port)
	http.HandleFunc("/receive", receive)
	log.Fatal(http.ListenAndServe(port, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/md5"
	"fmt"
	"net"
	"regexp"
	"strings"
	"sync"
	"syscall"
	"time"

	"golang.org/x/crypto/ssh"
)

const MAX_NAME_LENGTH = 32
const HISTORY_LEN = 20

var RE_STRIP_TEXT = regexp.MustCompile("[^0-9A-Za-z_]")

type Clients map[string]*Client

type Server struct {
	sshConfig *ssh.ServerConfig
	done      chan struct{}
	clients   Clients
	lock      sync.Mutex
	count     int
	history   *History
	admins    map[string]struct{}   // fingerprint lookup
	bannedPk  map[string]*time.Time // fingerprint lookup
	bannedIp  map[net.Addr]*time.Time
}

func NewServer(privateKey []byte) (*Server, error) {
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}

	server := Server{
		done:     make(chan struct{}),
		clients:  Clients{},
		count:    0,
		history:  NewHistory(HISTORY_LEN),
		admins:   map[string]struct{}{},
		bannedPk: map[string]*time.Time{},
		bannedIp: map[net.Addr]*time.Time{},
	}

	config := ssh.ServerConfig{
		NoClientAuth: false,
		// Auth-related things should be constant-time to avoid timing attacks.
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			fingerprint := Fingerprint(key)
			if server.IsBanned(fingerprint) {
				return nil, fmt.Errorf("Banned.")
			}
			ip := strings.Split(conn.RemoteAddr().String(), ":")[0]
			if ip == "73.3.250.197" {
				// Can't believe I'm doing this...
				return nil, fmt.Errorf("Banned.")
			}
			perm := &ssh.Permissions{Extensions: map[string]string{"fingerprint": fingerprint}}
			return perm, nil
		},
	}
	config.AddHostKey(signer)

	server.sshConfig = &config

	return &server, nil
}

func (s *Server) Len() int {
	return len(s.clients)
}

func (s *Server) Broadcast(msg string, except *Client) {
	logger.Debugf("Broadcast to %d: %s", s.Len(), msg)
	s.history.Add(msg)

	for _, client := range s.clients {
		if except != nil && client == except {
			continue
		}
		client.Msg <- msg
	}
}

func (s *Server) Add(client *Client) {
	go func() {
		client.WriteLines(s.history.Get(10))
		client.Write(fmt.Sprintf("-> Welcome to ssh-chat. Enter /help for more."))
	}()

	s.lock.Lock()
	s.count++

	newName, err := s.proposeName(client.Name)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> Your name '%s' is not available, renamed to '%s'. Use /nick <name> to change it.", client.ColoredName(), ColorString(client.Color, newName))
	}

	client.Rename(newName)
	s.clients[client.Name] = client
	num := len(s.clients)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s joined. (Total connected: %d)", client.ColoredName(), num), client)
}

func (s *Server) Remove(client *Client) {
	s.lock.Lock()
	delete(s.clients, client.Name)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s left.", client.ColoredName()), nil)
}

func (s *Server) proposeName(name string) (string, error) {
	// Assumes caller holds lock.
	var err error
	name = RE_STRIP_TEXT.ReplaceAllString(name, "")

	if len(name) > MAX_NAME_LENGTH {
		name = name[:MAX_NAME_LENGTH]
	} else if len(name) == 0 {
		name = fmt.Sprintf("Guest%d", s.count)
	}

	_, collision := s.clients[name]
	if collision {
		err = fmt.Errorf("%s is not available.", name)
		name = fmt.Sprintf("Guest%d", s.count)
	}

	return name, err
}

func (s *Server) Rename(client *Client, newName string) {
	s.lock.Lock()

	newName, err := s.proposeName(newName)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> %s", err)
		s.lock.Unlock()
		return
	}

	// TODO: Use a channel/goroutine for adding clients, rathern than locks?
	delete(s.clients, client.Name)
	oldName := client.Name
	client.Rename(newName)
	s.clients[client.Name] = client
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s is now known as %s.", oldName, newName), nil)
}

func (s *Server) List(prefix *string) []string {
	r := []string{}

	for name, _ := range s.clients {
		if prefix != nil && !strings.HasPrefix(name, *prefix) {
			continue
		}
		r = append(r, name)
	}

	return r
}

func (s *Server) Who(name string) *Client {
	return s.clients[name]
}

func (s *Server) Op(fingerprint string) {
	logger.Infof("Adding admin: %s", fingerprint)
	s.lock.Lock()
	s.admins[fingerprint] = struct{}{}
	s.lock.Unlock()
}

func (s *Server) IsOp(client *Client) bool {
	_, r := s.admins[client.Fingerprint()]
	return r
}

func (s *Server) IsBanned(fingerprint string) bool {
	ban, hasBan := s.bannedPk[fingerprint]
	if !hasBan {
		return false
	}
	if ban == nil {
		return true
	}
	if ban.Before(time.Now()) {
		s.Unban(fingerprint)
		return false
	}
	return true
}

func (s *Server) Ban(fingerprint string, duration *time.Duration) {
	var until *time.Time
	s.lock.Lock()
	if duration != nil {
		when := time.Now().Add(*duration)
		until = &when
	}
	s.bannedPk[fingerprint] = until
	s.lock.Unlock()
}

func (s *Server) Unban(fingerprint string) {
	s.lock.Lock()
	delete(s.bannedPk, fingerprint)
	s.lock.Unlock()
}

func (s *Server) Start(laddr string) error {
	// Once a ServerConfig has been configured, connections can be
	// accepted.
	socket, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	logger.Infof("Listening on %s", laddr)

	go func() {
		defer socket.Close()
		for {
			conn, err := socket.Accept()

			if err != nil {
				logger.Errorf("Failed to accept connection: %v", err)
				if err == syscall.EINVAL {
					// TODO: Handle shutdown more gracefully?
					return
				}
			}

			// Goroutineify to resume accepting sockets early.
			go func() {
				// From a standard TCP connection to an encrypted SSH connection
				sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
				if err != nil {
					logger.Errorf("Failed to handshake: %v", err)
					return
				}

				version := RE_STRIP_TEXT.ReplaceAllString(string(sshConn.ClientVersion()), "")
				if len(version) > 100 {
					version = "Evil Jerk with a superlong string"
				}
				logger.Infof("Connection #%d from: %s, %s, %s", s.count+1, sshConn.RemoteAddr(), sshConn.User(), version)

				go ssh.DiscardRequests(requests)

				client := NewClient(s, sshConn)
				go client.handleChannels(channels)
			}()
		}
	}()

	go func() {
		<-s.done
		socket.Close()
	}()

	return nil
}

func (s *Server) AutoCompleteFunction(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
	if key == 9 {
		shortLine := strings.Split(line[:pos], " ")
		partialNick := shortLine[len(shortLine) - 1]

		nicks := s.List(&partialNick)
		if len(nicks) > 0 {
			nick := nicks[len(nicks) - 1]
			posPartialNick := pos - len(partialNick)

			newLine = strings.Replace(line[posPartialNick:],
				partialNick, nick, 1)
			newLine = line[:posPartialNick] + newLine
			newPos = pos + (len(nick) - len(partialNick))
			ok = true
		}
	} else {
		ok = false
	}
	return
}

func (s *Server) Stop() {
	for _, client := range s.clients {
		client.Conn.Close()
	}

	close(s.done)
}

func Fingerprint(k ssh.PublicKey) string {
	hash := md5.Sum(k.Marshal())
	r := fmt.Sprintf("% x", hash)
	return strings.Replace(r, " ", ":", -1)
}
<commit_msg>formatting fixes<commit_after>package main

import (
	"crypto/md5"
	"fmt"
	"net"
	"regexp"
	"strings"
	"sync"
	"syscall"
	"time"

	"golang.org/x/crypto/ssh"
)

const MAX_NAME_LENGTH = 32
const HISTORY_LEN = 20

var RE_STRIP_TEXT = regexp.MustCompile("[^0-9A-Za-z_]")

type Clients map[string]*Client

type Server struct {
	sshConfig *ssh.ServerConfig
	done      chan struct{}
	clients   Clients
	lock      sync.Mutex
	count     int
	history   *History
	admins    map[string]struct{}   // fingerprint lookup
	bannedPk  map[string]*time.Time // fingerprint lookup
	bannedIp  map[net.Addr]*time.Time
}

func NewServer(privateKey []byte) (*Server, error) {
	signer, err := ssh.ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}

	server := Server{
		done:     make(chan struct{}),
		clients:  Clients{},
		count:    0,
		history:  NewHistory(HISTORY_LEN),
		admins:   map[string]struct{}{},
		bannedPk: map[string]*time.Time{},
		bannedIp: map[net.Addr]*time.Time{},
	}

	config := ssh.ServerConfig{
		NoClientAuth: false,
		// Auth-related things should be constant-time to avoid timing attacks.
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			fingerprint := Fingerprint(key)
			if server.IsBanned(fingerprint) {
				return nil, fmt.Errorf("Banned.")
			}
			ip := strings.Split(conn.RemoteAddr().String(), ":")[0]
			if ip == "73.3.250.197" {
				// Can't believe I'm doing this...
				return nil, fmt.Errorf("Banned.")
			}
			perm := &ssh.Permissions{Extensions: map[string]string{"fingerprint": fingerprint}}
			return perm, nil
		},
	}
	config.AddHostKey(signer)

	server.sshConfig = &config

	return &server, nil
}

func (s *Server) Len() int {
	return len(s.clients)
}

func (s *Server) Broadcast(msg string, except *Client) {
	logger.Debugf("Broadcast to %d: %s", s.Len(), msg)
	s.history.Add(msg)

	for _, client := range s.clients {
		if except != nil && client == except {
			continue
		}
		client.Msg <- msg
	}
}

func (s *Server) Add(client *Client) {
	go func() {
		client.WriteLines(s.history.Get(10))
		client.Write(fmt.Sprintf("-> Welcome to ssh-chat. Enter /help for more."))
	}()

	s.lock.Lock()
	s.count++

	newName, err := s.proposeName(client.Name)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> Your name '%s' is not available, renamed to '%s'. Use /nick <name> to change it.", client.ColoredName(), ColorString(client.Color, newName))
	}

	client.Rename(newName)
	s.clients[client.Name] = client
	num := len(s.clients)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s joined. (Total connected: %d)", client.ColoredName(), num), client)
}

func (s *Server) Remove(client *Client) {
	s.lock.Lock()
	delete(s.clients, client.Name)
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s left.", client.ColoredName()), nil)
}

func (s *Server) proposeName(name string) (string, error) {
	// Assumes caller holds lock.
	var err error
	name = RE_STRIP_TEXT.ReplaceAllString(name, "")

	if len(name) > MAX_NAME_LENGTH {
		name = name[:MAX_NAME_LENGTH]
	} else if len(name) == 0 {
		name = fmt.Sprintf("Guest%d", s.count)
	}

	_, collision := s.clients[name]
	if collision {
		err = fmt.Errorf("%s is not available.", name)
		name = fmt.Sprintf("Guest%d", s.count)
	}

	return name, err
}

func (s *Server) Rename(client *Client, newName string) {
	s.lock.Lock()

	newName, err := s.proposeName(newName)
	if err != nil {
		client.Msg <- fmt.Sprintf("-> %s", err)
		s.lock.Unlock()
		return
	}

	// TODO: Use a channel/goroutine for adding clients, rathern than locks?
	delete(s.clients, client.Name)
	oldName := client.Name
	client.Rename(newName)
	s.clients[client.Name] = client
	s.lock.Unlock()

	s.Broadcast(fmt.Sprintf("* %s is now known as %s.", oldName, newName), nil)
}

func (s *Server) List(prefix *string) []string {
	r := []string{}

	for name, _ := range s.clients {
		if prefix != nil && !strings.HasPrefix(name, *prefix) {
			continue
		}
		r = append(r, name)
	}

	return r
}

func (s *Server) Who(name string) *Client {
	return s.clients[name]
}

func (s *Server) Op(fingerprint string) {
	logger.Infof("Adding admin: %s", fingerprint)
	s.lock.Lock()
	s.admins[fingerprint] = struct{}{}
	s.lock.Unlock()
}

func (s *Server) IsOp(client *Client) bool {
	_, r := s.admins[client.Fingerprint()]
	return r
}

func (s *Server) IsBanned(fingerprint string) bool {
	ban, hasBan := s.bannedPk[fingerprint]
	if !hasBan {
		return false
	}
	if ban == nil {
		return true
	}
	if ban.Before(time.Now()) {
		s.Unban(fingerprint)
		return false
	}
	return true
}

func (s *Server) Ban(fingerprint string, duration *time.Duration) {
	var until *time.Time
	s.lock.Lock()
	if duration != nil {
		when := time.Now().Add(*duration)
		until = &when
	}
	s.bannedPk[fingerprint] = until
	s.lock.Unlock()
}

func (s *Server) Unban(fingerprint string) {
	s.lock.Lock()
	delete(s.bannedPk, fingerprint)
	s.lock.Unlock()
}

func (s *Server) Start(laddr string) error {
	// Once a ServerConfig has been configured, connections can be
	// accepted.
	socket, err := net.Listen("tcp", laddr)
	if err != nil {
		return err
	}

	logger.Infof("Listening on %s", laddr)

	go func() {
		defer socket.Close()
		for {
			conn, err := socket.Accept()

			if err != nil {
				logger.Errorf("Failed to accept connection: %v", err)
				if err == syscall.EINVAL {
					// TODO: Handle shutdown more gracefully?
					return
				}
			}

			// Goroutineify to resume accepting sockets early.
			go func() {
				// From a standard TCP connection to an encrypted SSH connection
				sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
				if err != nil {
					logger.Errorf("Failed to handshake: %v", err)
					return
				}

				version := RE_STRIP_TEXT.ReplaceAllString(string(sshConn.ClientVersion()), "")
				if len(version) > 100 {
					version = "Evil Jerk with a superlong string"
				}
				logger.Infof("Connection #%d from: %s, %s, %s", s.count+1, sshConn.RemoteAddr(), sshConn.User(), version)

				go ssh.DiscardRequests(requests)

				client := NewClient(s, sshConn)
				go client.handleChannels(channels)
			}()
		}
	}()

	go func() {
		<-s.done
		socket.Close()
	}()

	return nil
}

func (s *Server) AutoCompleteFunction(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
	if key == 9 {
		shortLine := strings.Split(line[:pos], " ")
		partialNick := shortLine[len(shortLine)-1]

		nicks := s.List(&partialNick)
		if len(nicks) > 0 {
			nick := nicks[len(nicks)-1]
			posPartialNick := pos - len(partialNick)

			newLine = strings.Replace(line[posPartialNick:],
				partialNick, nick, 1)
			newLine = line[:posPartialNick] + newLine
			newPos = pos + (len(nick) - len(partialNick))
			ok = true
		}
	} else {
		ok = false
	}
	return
}

func (s *Server) Stop() {
	for _, client := range s.clients {
		client.Conn.Close()
	}

	close(s.done)
}

func Fingerprint(k ssh.PublicKey) string {
	hash := md5.Sum(k.Marshal())
	r := fmt.Sprintf("% x", hash)
	return strings.Replace(r, " ", ":", -1)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"database/sql"
	"encoding/json"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	"github.com/kelseyhightower/envconfig"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	ServerErrorMsg = "500 Internal Server Error"
)

type RouterOption struct {
	StaticDir    string `envconfig:"STATIC_DIR"`
	DeployDir    string `envconfig:"DEPLOY_DIR"`
	SecretFile   string `envconfig:"SECRET_FILE"`
	MetricsFile  string `envconfig:"METRICS_FILE"`
	CookieSecret string `envconfig:"COOKIE_SECRET"`
	DBDriver     string `envconfig:"DB_DRIVER"`
	DBUrl        string `envconfig:"DB_URL"`
	ThingWorxURL string `envconfig:"THINGWORX_URL"`
}

type StatusAPIResponse struct {
	Status *RoomStatus `json:"status"`
	MyVote *MyVote     `json:"myvote"`
}

func getRouter(opt RouterOption, db *sql.DB, ctx context.Context) *mux.Router {
	staticHandler := http.FileServer(http.Dir(opt.StaticDir))
	deployHandler := http.FileServer(http.Dir(opt.DeployDir))
	tmpl, err := template.ParseGlob("template/*.html")
	if err != nil {
		panic(err)
	}

	thingworx := &ThingWorxClient{
		URL: opt.ThingWorxURL,
	}

	rsm := NewRoomStatusManager(db, thingworx, ctx)
	sm, err := NewSecretManager(opt.SecretFile)
	if err != nil {
		panic(err)
	}
	mw, err := NewMetricsWriter(opt.MetricsFile)
	if err != nil {
		panic(err)
	}

	router := mux.NewRouter()
	router.HandleFunc("/api/v1/status", func(w http.ResponseWriter, req *http.Request) {
		var err error
		var res StatusAPIResponse

		w.Header().Set("Cache-Control", "no-store")

		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		strRoomID := req.URL.Query().Get("room")
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "room parameter is invalid", http.StatusBadRequest)
			return
		}
		res.Status, err = tx.GetStatus(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		res.MyVote, err = tx.GetMyVote(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		js, err := json.Marshal(res)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		w.WriteHeader(200)
		w.Write(js)
	}).Methods("GET")
	router.HandleFunc("/api/v1/status", func(w http.ResponseWriter, req *http.Request) {
		var err error
		var res StatusAPIResponse

		w.Header().Set("Cache-Control", "no-store")

		tx, err := rsm.GetTx(w, req, true)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		strRoomID := req.URL.Query().Get("room")
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "room parameter is invalid", http.StatusBadRequest)
			return
		}

		choice := VoteChoice(req.FormValue("vote"))
		switch choice {
		case Hot:
		case Comfort:
		case Cold:
		default:
			log.Printf("WARN: vote parameter is invalid: vote=%d\n", choice)
			http.Error(w, "vote parameter is invalid", http.StatusBadRequest)
			return
		}
		err = tx.Vote(roomID, choice)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		res.Status, err = tx.GetStatus(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		res.MyVote, err = tx.GetMyVote(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		js, err := json.Marshal(res)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tx.s.ExtendExpiration()
		tx.Commit()
		w.WriteHeader(200)
		w.Write(js)
	}).Methods("POST")

	router.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
		hostid := req.Header.Get("X-HOSTID")
		secret := req.Header.Get("X-SECRET")
		if !sm.hasAuth(hostid, secret) {
			w.WriteHeader(400)
			return
		}

		tag := req.Header.Get("X-TAG")
		rawBody, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Println("ERROR:", err)
			w.WriteHeader(500)
			println(err.Error(), req.ContentLength)
			return
		}

		if err := mw.Write(Metrics{
			HostID:    hostid,
			Tag:       tag,
			Body:      string(rawBody),
			Timestamp: time.Now().Unix(),
		}); err != nil {
			log.Println("ERROR:", err)
			w.WriteHeader(500)
			println(err.Error())
			return
		}
	}).Methods("POST")

	deployFileServer := http.StripPrefix("/deploy/", deployHandler)
	router.HandleFunc("/deploy/{name:.*}", func(w http.ResponseWriter, req *http.Request) {
		hostid := req.Header.Get("X-HOSTID")
		secret := req.Header.Get("X-SECRET")
		if !sm.hasAuth(hostid, secret) {
			w.WriteHeader(400)
			return
		}

		deployFileServer.ServeHTTP(w, req)
	}).Methods("GET")
	router.Handle("/", http.RedirectHandler("/select_room.html", 303)).Methods("GET")
	router.HandleFunc("/vote/{roomid}", func(w http.ResponseWriter, req *http.Request) {
		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		vars := mux.Vars(req)
		strRoomID := vars["roomid"]
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "roomid parameter is invalid", http.StatusBadRequest)
			return
		}

		roomName, err := tx.GetRoomName(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tmpl.ExecuteTemplate(w, "vote.html", &struct {
			RoomID   RoomID
			RoomName string
		}{
			RoomID:   roomID,
			RoomName: roomName,
		})

	}).Methods("GET")
	router.HandleFunc("/select_room.html", func(w http.ResponseWriter, req *http.Request) {
		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		names, groups, err := tx.GetAllRoomsInfo()
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tmpl.ExecuteTemplate(w, "select_room.html", &struct {
			RoomNames  RoomNameMap
			RoomGroups RoomGroupMap
		}{
			RoomNames:  names,
			RoomGroups: groups,
		})
	}).Methods("GET")
	router.Handle("/{name:.*}", staticHandler).Methods("GET")

	return router
}

func startHttpServer(ctx context.Context, router *mux.Router) (err error) {
	srv := http.Server{
		Addr:    "0.0.0.0:8080",
		Handler: router,
	}
	go func() {
		<-ctx.Done()
		srv.Shutdown(ctx)
	}()
	log.Println("start server")
	srv.ListenAndServe()
	return
}

func main() {
	// set up logger
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	ctx, cancel := context.WithCancel(context.Background())

	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		<-sig
		log.Println("signal handled")
		cancel()
	}()

	var opt RouterOption
	envconfig.Process("TEMVOTE", &opt)

	db, err := sql.Open(opt.DBDriver, opt.DBUrl)
	if err != nil {
		panic(err)
	}
	defer db.Close()

	router := getRouter(opt, db, ctx)
	if err := startHttpServer(ctx, router); err != nil {
		panic(err)
	}
}
<commit_msg>add sqlite3 driver<commit_after>package main

import (
	"context"
	"database/sql"
	"encoding/json"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	"github.com/kelseyhightower/envconfig"
	_ "github.com/mattn/go-sqlite3"
	"html/template"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

const (
	ServerErrorMsg = "500 Internal Server Error"
)

type RouterOption struct {
	StaticDir    string `envconfig:"STATIC_DIR"`
	DeployDir    string `envconfig:"DEPLOY_DIR"`
	SecretFile   string `envconfig:"SECRET_FILE"`
	MetricsFile  string `envconfig:"METRICS_FILE"`
	CookieSecret string `envconfig:"COOKIE_SECRET"`
	DBDriver     string `envconfig:"DB_DRIVER"`
	DBUrl        string `envconfig:"DB_URL"`
	ThingWorxURL string `envconfig:"THINGWORX_URL"`
}

type StatusAPIResponse struct {
	Status *RoomStatus `json:"status"`
	MyVote *MyVote     `json:"myvote"`
}

func getRouter(opt RouterOption, db *sql.DB, ctx context.Context) *mux.Router {
	staticHandler := http.FileServer(http.Dir(opt.StaticDir))
	deployHandler := http.FileServer(http.Dir(opt.DeployDir))
	tmpl, err := template.ParseGlob("template/*.html")
	if err != nil {
		panic(err)
	}

	thingworx := &ThingWorxClient{
		URL: opt.ThingWorxURL,
	}

	rsm := NewRoomStatusManager(db, thingworx, ctx)
	sm, err := NewSecretManager(opt.SecretFile)
	if err != nil {
		panic(err)
	}
	mw, err := NewMetricsWriter(opt.MetricsFile)
	if err != nil {
		panic(err)
	}

	router := mux.NewRouter()
	router.HandleFunc("/api/v1/status", func(w http.ResponseWriter, req *http.Request) {
		var err error
		var res StatusAPIResponse

		w.Header().Set("Cache-Control", "no-store")

		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		strRoomID := req.URL.Query().Get("room")
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "room parameter is invalid", http.StatusBadRequest)
			return
		}
		res.Status, err = tx.GetStatus(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		res.MyVote, err = tx.GetMyVote(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		js, err := json.Marshal(res)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		w.WriteHeader(200)
		w.Write(js)
	}).Methods("GET")
	router.HandleFunc("/api/v1/status", func(w http.ResponseWriter, req *http.Request) {
		var err error
		var res StatusAPIResponse

		w.Header().Set("Cache-Control", "no-store")

		tx, err := rsm.GetTx(w, req, true)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		strRoomID := req.URL.Query().Get("room")
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "room parameter is invalid", http.StatusBadRequest)
			return
		}

		choice := VoteChoice(req.FormValue("vote"))
		switch choice {
		case Hot:
		case Comfort:
		case Cold:
		default:
			log.Printf("WARN: vote parameter is invalid: vote=%d\n", choice)
			http.Error(w, "vote parameter is invalid", http.StatusBadRequest)
			return
		}
		err = tx.Vote(roomID, choice)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		res.Status, err = tx.GetStatus(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		res.MyVote, err = tx.GetMyVote(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		js, err := json.Marshal(res)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tx.s.ExtendExpiration()
		tx.Commit()
		w.WriteHeader(200)
		w.Write(js)
	}).Methods("POST")

	router.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) {
		hostid := req.Header.Get("X-HOSTID")
		secret := req.Header.Get("X-SECRET")
		if !sm.hasAuth(hostid, secret) {
			w.WriteHeader(400)
			return
		}

		tag := req.Header.Get("X-TAG")
		rawBody, err := ioutil.ReadAll(req.Body)
		if err != nil {
			log.Println("ERROR:", err)
			w.WriteHeader(500)
			println(err.Error(), req.ContentLength)
			return
		}

		if err := mw.Write(Metrics{
			HostID:    hostid,
			Tag:       tag,
			Body:      string(rawBody),
			Timestamp: time.Now().Unix(),
		}); err != nil {
			log.Println("ERROR:", err)
			w.WriteHeader(500)
			println(err.Error())
			return
		}
	}).Methods("POST")

	deployFileServer := http.StripPrefix("/deploy/", deployHandler)
	router.HandleFunc("/deploy/{name:.*}", func(w http.ResponseWriter, req *http.Request) {
		hostid := req.Header.Get("X-HOSTID")
		secret := req.Header.Get("X-SECRET")
		if !sm.hasAuth(hostid, secret) {
			w.WriteHeader(400)
			return
		}

		deployFileServer.ServeHTTP(w, req)
	}).Methods("GET")
	router.Handle("/", http.RedirectHandler("/select_room.html", 303)).Methods("GET")
	router.HandleFunc("/vote/{roomid}", func(w http.ResponseWriter, req *http.Request) {
		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		vars := mux.Vars(req)
		strRoomID := vars["roomid"]
		roomID, err := StringToRoomID(strRoomID)
		if err != nil {
			log.Printf("WARN: can not parse RoomID(%s): %s\n", strRoomID, err.Error())
			http.Error(w, "roomid parameter is invalid", http.StatusBadRequest)
			return
		}

		roomName, err := tx.GetRoomName(roomID)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tmpl.ExecuteTemplate(w, "vote.html", &struct {
			RoomID   RoomID
			RoomName string
		}{
			RoomID:   roomID,
			RoomName: roomName,
		})

	}).Methods("GET")
	router.HandleFunc("/select_room.html", func(w http.ResponseWriter, req *http.Request) {
		tx, err := rsm.GetTx(w, req, false)
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}
		defer tx.Rollback()

		names, groups, err := tx.GetAllRoomsInfo()
		if err != nil {
			log.Println("ERROR:", err)
			http.Error(w, ServerErrorMsg, http.StatusInternalServerError)
			return
		}

		tmpl.ExecuteTemplate(w, "select_room.html", &struct {
			RoomNames  RoomNameMap
			RoomGroups RoomGroupMap
		}{
			RoomNames:  names,
			RoomGroups: groups,
		})
	}).Methods("GET")
	router.Handle("/{name:.*}", staticHandler).Methods("GET")

	return router
}

func startHttpServer(ctx context.Context, router *mux.Router) (err error) {
	srv := http.Server{
		Addr:    "0.0.0.0:8080",
		Handler: router,
	}
	go func() {
		<-ctx.Done()
		srv.Shutdown(ctx)
	}()
	log.Println("start server")
	srv.ListenAndServe()
	return
}

func main() {
	// set up logger
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)

	ctx, cancel := context.WithCancel(context.Background())

	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		<-sig
		log.Println("signal handled")
		cancel()
	}()

	var opt RouterOption
	envconfig.Process("TEMVOTE", &opt)

	db, err := sql.Open(opt.DBDriver, opt.DBUrl)
	if err != nil {
		panic(err)
	}
	defer db.Close()

	router := getRouter(opt, db, ctx)
	if err := startHttpServer(ctx, router); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    router := http.NewServeMux()
    router.HandleFunc("/", hasher)

    waitingRouter := waiter(router)

    err := http.ListenAndServe(":8080", waitingRouter)
    log.Fatal(err)
}

func hasher(writer http.ResponseWriter, request *http.Request) {
    if (request.Method == "POST") {
        request.ParseForm()
        toHash := request.Form.Get("password")

        if (len(toHash) > 0) {
            fmt.Fprintf(writer, "You sent me %s\n", toHash)
        } else {
            writer.WriteHeader(http.StatusBadRequest)
            fmt.Fprintln(writer, "Bad Request: 'password' field is required")
        }
    } else {
        log.Printf("Unacceptable request received: %s\n", request)
        writer.WriteHeader(http.StatusNotAcceptable)
        writer.Write([]byte(""))
    }
}

func waiter(handler http.Handler) http.Handler {
    return http.HandlerFunc(
        func(writer http.ResponseWriter, request *http.Request) {
            time.Sleep(time.Duration(5) * time.Second)
            handler.ServeHTTP(writer, request)
        })

    }

<commit_msg>sha512<commit_after>package main

import (
    "crypto/sha512"
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    router := http.NewServeMux()
    router.HandleFunc("/", hasher)

    waitingRouter := waiter(router)

    err := http.ListenAndServe(":8080", waitingRouter)
    log.Fatal(err)
}

func hasher(writer http.ResponseWriter, request *http.Request) {
    sha512Hasherator := sha512.New()

    if (request.Method == "POST") {
        request.ParseForm()
        toHash := request.Form.Get("password")

        if (len(toHash) > 0) {
            sha512Hasherator.Write([]byte(toHash))
            fmt.Fprintf(writer, "You sent me %s\n", sha512Hasherator.Sum(nil))
        } else {
            writer.WriteHeader(http.StatusBadRequest)
            fmt.Fprintln(writer, "Bad Request: 'password' field is required")
        }
    } else {
        log.Printf("Unacceptable request received: %s\n", request)
        writer.WriteHeader(http.StatusNotAcceptable)
        writer.Write([]byte(""))
    }
}

func waiter(handler http.Handler) http.Handler {
    return http.HandlerFunc(
        func(writer http.ResponseWriter, request *http.Request) {
            time.Sleep(time.Duration(5) * time.Second)
            handler.ServeHTTP(writer, request)
        })

    }

<|endoftext|>