<commit_before>package server

// Based on http://blog.extramaster.net/2014/05/creating-static-server-in-go-for-google.html
import (
	"net/http"
)

func init() {
	http.HandleFunc("/", static)
}

func static(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "public/"+r.URL.Path)
}
<commit_msg>fixing mime type for svg<commit_after>package server

// Based on http://blog.extramaster.net/2014/05/creating-static-server-in-go-for-google.html
import (
	"mime"
	"net/http"
)

func init() {
	http.HandleFunc("/", static)
}

func static(w http.ResponseWriter, r *http.Request) {
	mime.AddExtensionType(".svg", "image/svg+xml")
	http.ServeFile(w, r, "public/"+r.URL.Path)
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	"github.com/jessemillar/stalks/accessors"
	"github.com/jessemillar/stalks/controllers"
	"github.com/jessemillar/stalks/helpers"
	"github.com/robfig/cron"
	"github.com/zenazn/goji"
)

func main() {
	// Construct the dsn used for the database
	dsn := os.Getenv("DATABASE_USERNAME") + ":" + os.Getenv("DATABASE_PASSWORD") + "@tcp(" + os.Getenv("DATABASE_HOST") + ":" + os.Getenv("DATABASE_PORT") + ")/" + os.Getenv("DATABASE_NAME")

	// Construct a new AccessorGroup and connects it to the database
	ag := new(accessors.AccessorGroup)
	ag.ConnectToDB("mysql", dsn)

	// Constructs a new ControllerGroup and gives it the AccessorGroup
	cg := new(controllers.ControllerGroup)
	cg.Accessors = ag

	c := cron.New()
	c.AddFunc("0 0 21 * * 1-5", func() { // Run at 2:00pm MST (which is 21:00 UTC) Monday through Friday
		helpers.Webhook(helpers.ReportLeaders(ag))
	})
	c.Start()

	goji.Get("/health", cg.Health)
	goji.Get("/leaderboard", cg.ReportLeaders)
	goji.Post("/slack", cg.Slack) // The main endpoint that Slack hits
	goji.Post("/play", cg.User)
	goji.Post("/portfolio", cg.Portfolio)
	goji.Get("/check/:symbol", cg.Check)
	goji.Post("/buy/:quantity/:symbol", cg.Buy)
	goji.Post("/sell/:quantity/:symbol", cg.Sell)
	goji.Serve()
}
<commit_msg>Ghetto-fixing daylight savings time<commit_after>package main

import (
	"os"

	"github.com/jessemillar/stalks/accessors"
	"github.com/jessemillar/stalks/controllers"
	"github.com/jessemillar/stalks/helpers"
	"github.com/robfig/cron"
	"github.com/zenazn/goji"
)

func main() {
	// Construct the dsn used for the database
	dsn := os.Getenv("DATABASE_USERNAME") + ":" + os.Getenv("DATABASE_PASSWORD") + "@tcp(" + os.Getenv("DATABASE_HOST") + ":" + os.Getenv("DATABASE_PORT") + ")/" + os.Getenv("DATABASE_NAME")

	// Construct a new AccessorGroup and connects it to the database
	ag := new(accessors.AccessorGroup)
	ag.ConnectToDB("mysql", dsn)

	// Constructs a new ControllerGroup and gives it the AccessorGroup
	cg := new(controllers.ControllerGroup)
	cg.Accessors = ag

	c := cron.New()
	c.AddFunc("0 0 20 * * 1-5", func() { // Run at 2:00pm MST (which is 21:00 UTC) Monday through Friday
		helpers.Webhook(helpers.ReportLeaders(ag))
	})
	c.Start()

	goji.Get("/health", cg.Health)
	goji.Get("/leaderboard", cg.ReportLeaders)
	goji.Post("/slack", cg.Slack) // The main endpoint that Slack hits
	goji.Post("/play", cg.User)
	goji.Post("/portfolio", cg.Portfolio)
	goji.Get("/check/:symbol", cg.Check)
	goji.Post("/buy/:quantity/:symbol", cg.Buy)
	goji.Post("/sell/:quantity/:symbol", cg.Sell)
	goji.Serve()
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)
import (
	"github.com/satori/go.uuid"
	"github.com/speps/go-hashids"
)

var rooms = make(map[int]*Room)
var counter int = 0
var cards []Card
var HashID *hashids.HashID
var colors = []string{"Magenta", "LightSlateGray", "PaleVioletRed", "Peru", "RebeccaPurple", "LightSeaGreen", "Tomato", "SeaGreen", "Maroon", "GoldenRod", "DarkSlateBlue"}

type Card struct {
	Name string `json:"name"`
	Path string `json:"path"`
}

type PageLobby struct {
	ID    int
	Code  string
	Admin bool
}

type PageGame struct {
	Spy       bool
	Location  int
	Cards     []Card
	Countdown int
}

type Room struct {
	ID        int
	Players   []Player `json:"players"`
	Started   bool     `json:"started"`
	Location  int
	Countdown int
}

type Player struct {
	Name  string `json:"name"`
	Color string `json:"color"`
	Admin bool   `json:"-"`
	UUID  string `json:"-"`
	Spy   bool
}

func (r Room) playerForUUID(uuid string) Player {
	for _, value := range r.Players {
		if value.UUID == uuid {
			return value
		}
	}
	return Player{"Grey", "grey", false, "", false} // TODO: return error
}

func (r *Room) setup() {
	// select location
	r.Location = rand.Intn(len(cards))
	// assign a spy
	spy := rand.Intn(len(r.Players))
	r.Players[spy].Spy = true

	// set the countdown
	t := int(time.Now().Unix())
	t = t + (60 * 10)
	r.Countdown = t
	r.Started = true

}

func main() {
	cardsJSON, _ := ioutil.ReadFile("static/cards/cards.json")
	json.Unmarshal([]byte(cardsJSON), &cards)

	hd := hashids.NewData()
	hd.Salt = "super secret salt"
	hd.MinLength = 4
	HashID = hashids.NewWithData(hd)

	http.HandleFunc("/room/new", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			http.NotFound(w, r)
			return
		}
		c, _ := HashID.Encode([]int{counter})

		// create new room
		uuidS := uuid.NewV4().String()
		admin := Player{colors[0], colors[0], true, uuidS, false}
		players := []Player{admin}
		rooms[counter] = &Room{ID: counter, Players: players, Started: false}

		// give admin a cookie with UUID
		expiration := time.Now().Add(365 * 24 * time.Hour)
		cookie := http.Cookie{Name: "spyfall", Value: uuidS, Path: "/", Expires: expiration}
		http.SetCookie(w, &cookie)

		t, _ := template.ParseFiles("static/room.html")
		p := &PageLobby{Code: c, ID: counter, Admin: true}
		t.Execute(w, p)
		fmt.Println("created new room", c, counter)

		counter++
	})

	http.HandleFunc("/room/join", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.NotFound(w, r)
			return
		}
		r.ParseForm()
		c := r.Form["Code"][0]
		d := HashID.Decode(c)
		roomID := d[0]
		if room, ok := rooms[roomID]; ok {
			if room.Started {
				http.Redirect(w, r, "/", 303) // TODO: show message that room started
				return
			}

			// create player, with unused color
			uuidS := uuid.NewV4().String()
			color := colors[len(room.Players)]
			player := Player{color, color, false, uuidS, false}

			// set cookie with uuid
			expiration := time.Now().Add(365 * 24 * time.Hour)
			cookie := http.Cookie{Name: "spyfall", Value: uuidS, Path: "/", Expires: expiration}
			http.SetCookie(w, &cookie)

			// add player to the room
			room.Players = append(room.Players, player)

			t, _ := template.ParseFiles("static/room.html")
			p := &PageLobby{Code: c, ID: roomID, Admin: false}
			t.Execute(w, p)
		} else {
			http.Redirect(w, r, "/", 303)
			return
		}
	})

	http.HandleFunc("/game", func(w http.ResponseWriter, r *http.Request) {
		roomIDStr := r.URL.Query().Get("id")
		roomID, err := strconv.Atoi(roomIDStr)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		if room, ok := rooms[roomID]; ok {
			if room.Started == false {
				room.setup()
				fmt.Println("Started room", roomID)
			}
			t, _ := template.ParseFiles("static/game.html")
			cookie := r.Cookies()[0]
			uuid := cookie.Value
			player := room.playerForUUID(uuid)

			p := &PageGame{Spy: player.Spy, Location: room.Location, Cards: cards, Countdown: room.Countdown}
			t.Execute(w, p)
		} else {
			http.NotFound(w, r)
			return
		}
	})

	http.HandleFunc("/players.json", func(w http.ResponseWriter, r *http.Request) {
		roomIDStr := r.URL.Query().Get("id")
		roomID, err := strconv.Atoi(roomIDStr)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		if room, ok := rooms[roomID]; ok {
			js, err := json.Marshal(room)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(js)
		} else {
			http.NotFound(w, r)
			return
		}
	})

	http.Handle("/", http.FileServer(http.Dir("./static")))
	http.ListenAndServe(":3000", nil)
}
<commit_msg>hiding data in the JSON output<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"html/template"
	"io/ioutil"
	"math/rand"
	"net/http"
	"strconv"
	"time"
)
import (
	"github.com/satori/go.uuid"
	"github.com/speps/go-hashids"
)

var rooms = make(map[int]*Room)
var counter int = 0
var cards []Card
var HashID *hashids.HashID
var colors = []string{"Magenta", "LightSlateGray", "PaleVioletRed", "Peru", "RebeccaPurple", "LightSeaGreen", "Tomato", "SeaGreen", "Maroon", "GoldenRod", "DarkSlateBlue"}

type Card struct {
	Name string `json:"name"`
	Path string `json:"path"`
}

type PageLobby struct {
	ID    int
	Code  string
	Admin bool
}

type PageGame struct {
	Spy       bool
	Location  int
	Cards     []Card
	Countdown int
}

type Room struct {
	ID        int
	Players   []Player `json:"players"`
	Started   bool     `json:"started"`
	Location  int      `json:"-"`
	Countdown int      `json:"-"`
}

type Player struct {
	Name  string `json:"name"`
	Color string `json:"color"`
	Admin bool   `json:"-"`
	UUID  string `json:"-"`
	Spy   bool   `json:"-"`
}

func (r Room) playerForUUID(uuid string) Player {
	for _, value := range r.Players {
		if value.UUID == uuid {
			return value
		}
	}
	return Player{"Grey", "grey", false, "", false} // TODO: return error
}

func (r *Room) setup() {
	// select location
	r.Location = rand.Intn(len(cards))
	// assign a spy
	spy := rand.Intn(len(r.Players))
	r.Players[spy].Spy = true

	// set the countdown
	t := int(time.Now().Unix())
	t = t + (60 * 10)
	r.Countdown = t
	r.Started = true

}

func main() {
	cardsJSON, _ := ioutil.ReadFile("static/cards/cards.json")
	json.Unmarshal([]byte(cardsJSON), &cards)

	hd := hashids.NewData()
	hd.Salt = "super secret salt"
	hd.MinLength = 4
	HashID = hashids.NewWithData(hd)

	http.HandleFunc("/room/new", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "GET" {
			http.NotFound(w, r)
			return
		}
		c, _ := HashID.Encode([]int{counter})

		// create new room
		uuidS := uuid.NewV4().String()
		admin := Player{colors[0], colors[0], true, uuidS, false}
		players := []Player{admin}
		rooms[counter] = &Room{ID: counter, Players: players, Started: false}

		// give admin a cookie with UUID
		expiration := time.Now().Add(365 * 24 * time.Hour)
		cookie := http.Cookie{Name: "spyfall", Value: uuidS, Path: "/", Expires: expiration}
		http.SetCookie(w, &cookie)

		t, _ := template.ParseFiles("static/room.html")
		p := &PageLobby{Code: c, ID: counter, Admin: true}
		t.Execute(w, p)
		fmt.Println("created new room", c, counter)

		counter++
	})

	http.HandleFunc("/room/join", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.NotFound(w, r)
			return
		}
		r.ParseForm()
		c := r.Form["Code"][0]
		d := HashID.Decode(c)
		roomID := d[0]
		if room, ok := rooms[roomID]; ok {
			if room.Started {
				http.Redirect(w, r, "/", 303) // TODO: show message that room started
				return
			}

			// create player, with unused color
			uuidS := uuid.NewV4().String()
			color := colors[len(room.Players)]
			player := Player{color, color, false, uuidS, false}

			// set cookie with uuid
			expiration := time.Now().Add(365 * 24 * time.Hour)
			cookie := http.Cookie{Name: "spyfall", Value: uuidS, Path: "/", Expires: expiration}
			http.SetCookie(w, &cookie)

			// add player to the room
			room.Players = append(room.Players, player)

			t, _ := template.ParseFiles("static/room.html")
			p := &PageLobby{Code: c, ID: roomID, Admin: false}
			t.Execute(w, p)
		} else {
			http.Redirect(w, r, "/", 303)
			return
		}
	})

	http.HandleFunc("/game", func(w http.ResponseWriter, r *http.Request) {
		roomIDStr := r.URL.Query().Get("id")
		roomID, err := strconv.Atoi(roomIDStr)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		if room, ok := rooms[roomID]; ok {
			if room.Started == false {
				room.setup()
				fmt.Println("Started room", roomID)
			}
			t, _ := template.ParseFiles("static/game.html")
			cookie := r.Cookies()[0]
			uuid := cookie.Value
			player := room.playerForUUID(uuid)

			p := &PageGame{Spy: player.Spy, Location: room.Location, Cards: cards, Countdown: room.Countdown}
			t.Execute(w, p)
		} else {
			http.NotFound(w, r)
			return
		}
	})

	http.HandleFunc("/players.json", func(w http.ResponseWriter, r *http.Request) {
		roomIDStr := r.URL.Query().Get("id")
		roomID, err := strconv.Atoi(roomIDStr)
		if err != nil {
			http.NotFound(w, r)
			return
		}
		if room, ok := rooms[roomID]; ok {
			js, err := json.Marshal(room)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.Write(js)
		} else {
			http.NotFound(w, r)
			return
		}
	})

	http.Handle("/", http.FileServer(http.Dir("./static")))
	http.ListenAndServe(":3000", nil)
}
<|endoftext|>


<commit_before>package gfs

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"path"
)

const (
	// The running version of GFS
	GFSVersion string = "0.0.1"
)

func RunServer(config *Config) {
	handlerFunc, err := getHandler(config)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/", handlerFunc)

	loginHandlerFunc, err := getLoginHandler(config, handlerFunc)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/login", loginHandlerFunc)

	uploadHandlerFunc, err := getUploadHandlerFunc(config, handlerFunc)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/upload", uploadHandlerFunc)

	log.Fatal(http.ListenAndServe(":"+config.Port, nil))
}

func getHandler(config *Config) (f http.HandlerFunc, err error) {

	notFoundHandler, err := GetNotFoundHandler()
	if err != nil {
		return nil, err
	}
	internalServerErrorHandler, err := GetInternalServerErrorHandler()
	if err != nil {
		return nil, err
	}
	clientErrorHandler, err := GetClientErrorHandler()
	if err != nil {
		return nil, err
	}
	directoryResponseHandler, err := GetDirectoryResponseHandler()
	if err != nil {
		return nil, err
	}
	fileResponserHandler, err := GetFileResponseHandler()
	if err != nil {
		return nil, err
	}
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}

	f = func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)
		responseFormat := getResponseFormat(request)

		if request.Method == "GET" {
			authorized := false
			err := authorizationHandler.CheckAuthenticated(request)
			if err == nil {
				authorized = true
			}
			if config.LoginRequiredForRead && !authorized {
				log.Println("authentication error", err)
				clientErrorHandler.Handle(writer, errors.New("Not authenticated"), responseFormat, http.StatusUnauthorized)
				return
			}

			p := request.URL.Path
			fullpath := path.Join(config.Serve, p)

			directory, err := isDirectory(fullpath)
			if err != nil {
				if os.IsNotExist(err) {
					notFoundHandler.Handle(writer, p, responseFormat)
					return
				}
				log.Println("Error when detecting directory", err)
				internalServerErrorHandler.Handle(writer, err, responseFormat)
				return
			}

			if directory {
				stats, err := GetDirectoryStats(fullpath, p)
				if err != nil {
					internalServerErrorHandler.Handle(writer, err, responseFormat)
				}
				stats.Authorized = authorized
				directoryResponseHandler.Handle(writer, stats, responseFormat)
			} else {
				err := fileResponserHandler.Handle(writer, fullpath, p, responseFormat)
				if err != nil {
					log.Println("Something went wrong when serving file:", err.Error())
				}
			}
			return
		}

		clientErrorHandler.Handle(writer, errors.New(fmt.Sprintf("Unsupported method: '%s'", request.Method)), responseFormat, http.StatusMethodNotAllowed)
	}
	return f, nil
}

func getLoginHandler(config *Config, defaultHandler http.HandlerFunc) (http.HandlerFunc, error) {
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}

	f := func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)

		if request.Method == "POST" {

			responseFormat := getResponseFormat(request)

			err := authorizationHandler.Login(writer, request, responseFormat)
			if err != nil {
				log.Println("Something went wrong during authentication", err)
			} else {
				log.Println("Login successful")
			}
		} else {
			defaultHandler(writer, request)
		}
	}

	return f, nil
}

func getUploadHandlerFunc(config *Config, defaultHandler http.HandlerFunc) (http.HandlerFunc, error) {
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}
	uploadHandler, err := GetUploadHandler(config)
	if err != nil {
		return nil, err
	}
	clientErrorHandler, err := GetClientErrorHandler()
	if err != nil {
		return nil, err
	}
	internalServerErrorHandler, err := GetInternalServerErrorHandler()
	if err != nil {
		return nil, err
	}

	f := func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)
		if request.Method == "POST" {
			responseFormat := getResponseFormat(request)

			err := authorizationHandler.CheckAuthenticated(request)
			if err != nil {
				clientErrorHandler.Handle(writer, err, responseFormat, http.StatusUnauthorized)
				return
			}

			err = uploadHandler.Handle(writer, request)
			if err != nil {
				if err == ErrNoUploadingUp {
					clientErrorHandler.Handle(writer, err, responseFormat, http.StatusBadRequest)
					return
				}
				internalServerErrorHandler.Handle(writer, err, responseFormat)
			}

		} else {
			defaultHandler(writer, request)
		}
	}

	return f, nil
}
<commit_msg>Update version<commit_after>package gfs

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"path"
)

const (
	// The running version of GFS
	GFSVersion string = "0.0.2"
)

func RunServer(config *Config) {
	handlerFunc, err := getHandler(config)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/", handlerFunc)

	loginHandlerFunc, err := getLoginHandler(config, handlerFunc)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/login", loginHandlerFunc)

	uploadHandlerFunc, err := getUploadHandlerFunc(config, handlerFunc)
	if err != nil {
		log.Fatalln(err)
	}
	http.HandleFunc("/upload", uploadHandlerFunc)

	log.Fatal(http.ListenAndServe(":"+config.Port, nil))
}

func getHandler(config *Config) (f http.HandlerFunc, err error) {

	notFoundHandler, err := GetNotFoundHandler()
	if err != nil {
		return nil, err
	}
	internalServerErrorHandler, err := GetInternalServerErrorHandler()
	if err != nil {
		return nil, err
	}
	clientErrorHandler, err := GetClientErrorHandler()
	if err != nil {
		return nil, err
	}
	directoryResponseHandler, err := GetDirectoryResponseHandler()
	if err != nil {
		return nil, err
	}
	fileResponserHandler, err := GetFileResponseHandler()
	if err != nil {
		return nil, err
	}
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}

	f = func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)
		responseFormat := getResponseFormat(request)

		if request.Method == "GET" {
			authorized := false
			err := authorizationHandler.CheckAuthenticated(request)
			if err == nil {
				authorized = true
			}
			if config.LoginRequiredForRead && !authorized {
				log.Println("authentication error", err)
				clientErrorHandler.Handle(writer, errors.New("Not authenticated"), responseFormat, http.StatusUnauthorized)
				return
			}

			p := request.URL.Path
			fullpath := path.Join(config.Serve, p)

			directory, err := isDirectory(fullpath)
			if err != nil {
				if os.IsNotExist(err) {
					notFoundHandler.Handle(writer, p, responseFormat)
					return
				}
				log.Println("Error when detecting directory", err)
				internalServerErrorHandler.Handle(writer, err, responseFormat)
				return
			}

			if directory {
				stats, err := GetDirectoryStats(fullpath, p)
				if err != nil {
					internalServerErrorHandler.Handle(writer, err, responseFormat)
				}
				stats.Authorized = authorized
				directoryResponseHandler.Handle(writer, stats, responseFormat)
			} else {
				err := fileResponserHandler.Handle(writer, fullpath, p, responseFormat)
				if err != nil {
					log.Println("Something went wrong when serving file:", err.Error())
				}
			}
			return
		}

		clientErrorHandler.Handle(writer, errors.New(fmt.Sprintf("Unsupported method: '%s'", request.Method)), responseFormat, http.StatusMethodNotAllowed)
	}
	return f, nil
}

func getLoginHandler(config *Config, defaultHandler http.HandlerFunc) (http.HandlerFunc, error) {
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}

	f := func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)

		if request.Method == "POST" {

			responseFormat := getResponseFormat(request)

			err := authorizationHandler.Login(writer, request, responseFormat)
			if err != nil {
				log.Println("Something went wrong during authentication", err)
			} else {
				log.Println("Login successful")
			}
		} else {
			defaultHandler(writer, request)
		}
	}

	return f, nil
}

func getUploadHandlerFunc(config *Config, defaultHandler http.HandlerFunc) (http.HandlerFunc, error) {
	authorizationHandler, err := GetAuthorizationHandler(config)
	if err != nil {
		return nil, err
	}
	uploadHandler, err := GetUploadHandler(config)
	if err != nil {
		return nil, err
	}
	clientErrorHandler, err := GetClientErrorHandler()
	if err != nil {
		return nil, err
	}
	internalServerErrorHandler, err := GetInternalServerErrorHandler()
	if err != nil {
		return nil, err
	}

	f := func(writer http.ResponseWriter, request *http.Request) {
		writer.Header().Set("gfs-version", GFSVersion)
		if request.Method == "POST" {
			responseFormat := getResponseFormat(request)

			err := authorizationHandler.CheckAuthenticated(request)
			if err != nil {
				clientErrorHandler.Handle(writer, err, responseFormat, http.StatusUnauthorized)
				return
			}

			err = uploadHandler.Handle(writer, request)
			if err != nil {
				if err == ErrNoUploadingUp {
					clientErrorHandler.Handle(writer, err, responseFormat, http.StatusBadRequest)
					return
				}
				internalServerErrorHandler.Handle(writer, err, responseFormat)
			}

		} else {
			defaultHandler(writer, request)
		}
	}

	return f, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"encoding/gob"
	"github.com/BenLubar/bindiff"
	"github.com/Rnoadm/wdvn/res"
	"log"
	"net"
	"sync/atomic"
	"time"
)

func Listen(l net.Listener, world *World) {
	defer quitWait.Done()
	defer l.Close()

	var (
		broadcast  = make(chan *res.Packet)
		register   = make(chan chan<- *res.Packet)
		unregister = make(chan chan<- *res.Packet)
		input      = make(chan *res.Packet)
		state      = make(chan (<-chan []byte))
		connection = make(chan bool)
		accept     = make(chan net.Conn)
	)
	defer close(register)
	quitWait.Add(2)
	go Multicast(broadcast, register, unregister)
	go Manager(input, state, connection, broadcast, world)

	var connected [res.Man_count]uint64

	go func() {
		defer close(accept)
		for {
			conn, err := l.Accept()
			if err == nil {
				accept <- conn
			} else {
				log.Print(err)
				if ne, ok := err.(net.Error); !ok || !ne.Temporary() {
					return
				}
			}
		}
	}()

	for {
		select {
		case conn := <-accept:
			ch := make(chan *res.Packet)
			register <- ch
			connection <- true

			quitWait.Add(1)
			go Serve(conn, ch, broadcast, state, world, input, &connected, func() {
				go func() {
					for _ = range ch {
						// discard
					}
				}()
				unregister <- ch
				connection <- false
				quitWait.Done()
			})

		case <-quitRequest:
			return
		}
	}
}

func Multicast(broadcast <-chan *res.Packet, register, unregister <-chan chan<- *res.Packet) {
	defer quitWait.Done()
	writers := make(map[chan<- *res.Packet]struct{})

	for {
		select {
		case ch, ok := <-register:
			if !ok {
				return
			}
			writers[ch] = struct{}{}

		case ch := <-unregister:
			delete(writers, ch)
			close(ch)

		case packet := <-broadcast:
			for ch := range writers {
				go Send(ch, packet)
			}
		}
	}
}

func Serve(conn net.Conn, in <-chan *res.Packet, out chan<- *res.Packet, state <-chan <-chan []byte, world *World, input chan<- *res.Packet, connected *[res.Man_count]uint64, disconnect func()) {
	defer disconnect()
	defer conn.Close()

	read, write, errors := make(chan *res.Packet), make(chan *res.Packet), make(chan error, 2)
	defer close(write)
	go Read(conn, read, errors)
	go Write(conn, write, errors)

	var man res.Man
	// check for an empty slot
	for man = 0; man < res.Man_count; man++ {
		if atomic.CompareAndSwapUint64(&(*connected)[man], 0, 1) {
			break
		}
	}
	// multiple people control normal man as a last resort
	if man == res.Man_count {
		man = res.Man_Normal
		atomic.AddUint64(&(*connected)[man], 1)
	}
	pman := man.Enum()
	// leave the character when we disconnect
	defer func() {
		atomic.AddUint64(&(*connected)[man], ^uint64(0))
	}()

	log.Println(conn.RemoteAddr(), "connected for", man)

	// tell the client which man they are
	write <- &res.Packet{
		Type: Type_SelectMan,
		Man:  pman,
	}

	// send the world
	{
		var buf bytes.Buffer

		err := gob.NewEncoder(&buf).Encode(world)
		if err != nil {
			panic(err)
		}

		write <- &res.Packet{
			Type: Type_World,
			Data: buf.Bytes(),
		}
	}

	// send full state to the client
	write <- &res.Packet{
		Type: Type_FullState,
		Data: <-<-state,
	}

	ping := time.NewTicker(time.Second)
	defer ping.Stop()
	lastPing := time.Now()

	for {
		select {
		case p := <-in:
			write <- p

		case p, ok := <-read:
			if !ok {
				// we will return from the error channel. stop checking for new packets
				// so we don't busy wait on a closed channel.
				read = nil
				continue
			}

			switch p.GetType() {
			case res.Type_Ping:
				lastPing = time.Now()

			case res.Type_SelectMan:
				if atomic.CompareAndSwapUint64(&(*connected)[p.GetMan()], 0, 1) {
					log.Println(conn.RemoteAddr(), "switched from", man, "to", p.GetMan())

					atomic.AddUint64(&(*connected)[man], ^uint64(0))
					man, pman = p.GetMan(), p.Man
					go Send(write, p)
				}

			case res.Type_Input:
				p.Man = pman
				go Send(input, p)

			case res.Type_FullState:
				log.Println(conn.RemoteAddr(), "requested full state update")

				go Send(write, &res.Packet{
					Type: Type_FullState,
					Data: <-<-state,
				})
			}

		case <-ping.C:
			go Send(out, &res.Packet{
				Type: Type_Ping,
			})

			if time.Since(lastPing) > time.Second*5 {
				log.Println(conn.RemoteAddr(), man, "disconnected: ping timeout")
				return
			}

		case err := <-errors:
			log.Println(conn.RemoteAddr(), man, "disconnected:", err)
			return
		}
	}
}

func Manager(in <-chan *res.Packet, out chan<- <-chan []byte, connection <-chan bool, broadcast chan<- *res.Packet, world *World) {
	defer quitWait.Done()

	var (
		state            = NewState(world)
		input            [res.Man_count]res.Packet
		connection_count int
		prev             []byte
		tick             = time.NewTicker(time.Second / TicksPerSecond)
		ch               = make(chan []byte)
	)
	defer tick.Stop()

	if replay != nil {
		var buf bytes.Buffer
		err := buf.WriteByte(0)
		if err != nil {
			panic(err)
		}
		err = gob.NewEncoder(&buf).Encode(world)
		if err != nil {
			panic(err)
		}
		err = gob.NewEncoder(&buf).Encode(state)
		if err != nil {
			panic(err)
		}

		replay <- buf.Bytes()
	}

	for {
		if connection_count == 0 {
			if b := <-connection; b {
				connection_count++
			} else {
				panic("connection count underflow")
			}
		}

		select {
		case p := <-in:
			switch p.GetType() {
			case res.Type_Input:
				proto.Merge(&input[p.GetMan()], p)
			}

		case out <- ch:
			var buf bytes.Buffer
			err := gob.NewEncoder(&buf).Encode(state)
			if err != nil {
				panic(err)
			}
			ch <- buf.Bytes()

		case <-tick.C:
			t := state.Tick

			state.Update(&input)

			var buf bytes.Buffer
			err := gob.NewEncoder(&buf).Encode(state)
			if err != nil {
				panic(err)
			}
			diff := bindiff.Diff(prev, buf.Bytes(), 5)
			if replay != nil {
				replay <- append([]byte{1}, diff...)
			}
			prev = buf.Bytes()

			go Send(broadcast, &res.Packet{
				Type: Type_StateDiff,
				Tick: proto.Uint64(t),
				Data: diff,
			})

		case b := <-connection:
			if b {
				connection_count++
				if connection_count < 0 {
					panic("connection count overflow")
				}
			} else {
				connection_count--
				if connection_count < 0 {
					panic("connection count underflow")
				}
			}

		case <-quitRequest:
			return
		}
	}
}
<commit_msg>fix server quit while hibernating<commit_after>package main

import (
	"bytes"
	"code.google.com/p/goprotobuf/proto"
	"encoding/gob"
	"github.com/BenLubar/bindiff"
	"github.com/Rnoadm/wdvn/res"
	"log"
	"net"
	"sync/atomic"
	"time"
)

func Listen(l net.Listener, world *World) {
	defer quitWait.Done()
	defer l.Close()

	var (
		broadcast  = make(chan *res.Packet)
		register   = make(chan chan<- *res.Packet)
		unregister = make(chan chan<- *res.Packet)
		input      = make(chan *res.Packet)
		state      = make(chan (<-chan []byte))
		connection = make(chan bool)
		accept     = make(chan net.Conn)
	)
	defer close(register)
	quitWait.Add(2)
	go Multicast(broadcast, register, unregister)
	go Manager(input, state, connection, broadcast, world)

	var connected [res.Man_count]uint64

	go func() {
		defer close(accept)
		for {
			conn, err := l.Accept()
			if err == nil {
				accept <- conn
			} else {
				log.Print(err)
				if ne, ok := err.(net.Error); !ok || !ne.Temporary() {
					return
				}
			}
		}
	}()

	for {
		select {
		case conn := <-accept:
			ch := make(chan *res.Packet)
			register <- ch
			connection <- true

			quitWait.Add(1)
			go Serve(conn, ch, broadcast, state, world, input, &connected, func() {
				go func() {
					for _ = range ch {
						// discard
					}
				}()
				unregister <- ch
				connection <- false
				quitWait.Done()
			})

		case <-quitRequest:
			return
		}
	}
}

func Multicast(broadcast <-chan *res.Packet, register, unregister <-chan chan<- *res.Packet) {
	defer quitWait.Done()
	writers := make(map[chan<- *res.Packet]struct{})

	for {
		select {
		case ch, ok := <-register:
			if !ok {
				return
			}
			writers[ch] = struct{}{}

		case ch := <-unregister:
			delete(writers, ch)
			close(ch)

		case packet := <-broadcast:
			for ch := range writers {
				go Send(ch, packet)
			}
		}
	}
}

func Serve(conn net.Conn, in <-chan *res.Packet, out chan<- *res.Packet, state <-chan <-chan []byte, world *World, input chan<- *res.Packet, connected *[res.Man_count]uint64, disconnect func()) {
	defer disconnect()
	defer conn.Close()

	read, write, errors := make(chan *res.Packet), make(chan *res.Packet), make(chan error, 2)
	defer close(write)
	go Read(conn, read, errors)
	go Write(conn, write, errors)

	var man res.Man
	// check for an empty slot
	for man = 0; man < res.Man_count; man++ {
		if atomic.CompareAndSwapUint64(&(*connected)[man], 0, 1) {
			break
		}
	}
	// multiple people control normal man as a last resort
	if man == res.Man_count {
		man = res.Man_Normal
		atomic.AddUint64(&(*connected)[man], 1)
	}
	pman := man.Enum()
	// leave the character when we disconnect
	defer func() {
		atomic.AddUint64(&(*connected)[man], ^uint64(0))
	}()

	log.Println(conn.RemoteAddr(), "connected for", man)

	// tell the client which man they are
	write <- &res.Packet{
		Type: Type_SelectMan,
		Man:  pman,
	}

	// send the world
	{
		var buf bytes.Buffer

		err := gob.NewEncoder(&buf).Encode(world)
		if err != nil {
			panic(err)
		}

		write <- &res.Packet{
			Type: Type_World,
			Data: buf.Bytes(),
		}
	}

	// send full state to the client
	write <- &res.Packet{
		Type: Type_FullState,
		Data: <-<-state,
	}

	ping := time.NewTicker(time.Second)
	defer ping.Stop()
	lastPing := time.Now()

	for {
		select {
		case p := <-in:
			write <- p

		case p, ok := <-read:
			if !ok {
				// we will return from the error channel. stop checking for new packets
				// so we don't busy wait on a closed channel.
				read = nil
				continue
			}

			switch p.GetType() {
			case res.Type_Ping:
				lastPing = time.Now()

			case res.Type_SelectMan:
				if atomic.CompareAndSwapUint64(&(*connected)[p.GetMan()], 0, 1) {
					log.Println(conn.RemoteAddr(), "switched from", man, "to", p.GetMan())

					atomic.AddUint64(&(*connected)[man], ^uint64(0))
					man, pman = p.GetMan(), p.Man
					go Send(write, p)
				}

			case res.Type_Input:
				p.Man = pman
				go Send(input, p)

			case res.Type_FullState:
				log.Println(conn.RemoteAddr(), "requested full state update")

				go Send(write, &res.Packet{
					Type: Type_FullState,
					Data: <-<-state,
				})
			}

		case <-ping.C:
			go Send(out, &res.Packet{
				Type: Type_Ping,
			})

			if time.Since(lastPing) > time.Second*5 {
				log.Println(conn.RemoteAddr(), man, "disconnected: ping timeout")
				return
			}

		case err := <-errors:
			log.Println(conn.RemoteAddr(), man, "disconnected:", err)
			return
		}
	}
}

func Manager(in <-chan *res.Packet, out chan<- <-chan []byte, connection <-chan bool, broadcast chan<- *res.Packet, world *World) {
	defer quitWait.Done()

	var (
		state            = NewState(world)
		input            [res.Man_count]res.Packet
		connection_count int
		prev             []byte
		tick             = time.NewTicker(time.Second / TicksPerSecond)
		ch               = make(chan []byte)
	)
	defer tick.Stop()

	if replay != nil {
		var buf bytes.Buffer
		err := buf.WriteByte(0)
		if err != nil {
			panic(err)
		}
		err = gob.NewEncoder(&buf).Encode(world)
		if err != nil {
			panic(err)
		}
		err = gob.NewEncoder(&buf).Encode(state)
		if err != nil {
			panic(err)
		}

		replay <- buf.Bytes()
	}

	for {
		if connection_count == 0 {
			select {
			case b := <-connection:
				if b {
					connection_count++
				} else {
					panic("connection count underflow")
				}
			case <-quitRequest:
				return
			}
		}

		select {
		case p := <-in:
			switch p.GetType() {
			case res.Type_Input:
				proto.Merge(&input[p.GetMan()], p)
			}

		case out <- ch:
			var buf bytes.Buffer
			err := gob.NewEncoder(&buf).Encode(state)
			if err != nil {
				panic(err)
			}
			ch <- buf.Bytes()

		case <-tick.C:
			t := state.Tick

			state.Update(&input)

			var buf bytes.Buffer
			err := gob.NewEncoder(&buf).Encode(state)
			if err != nil {
				panic(err)
			}
			diff := bindiff.Diff(prev, buf.Bytes(), 5)
			if replay != nil {
				replay <- append([]byte{1}, diff...)
			}
			prev = buf.Bytes()

			go Send(broadcast, &res.Packet{
				Type: Type_StateDiff,
				Tick: proto.Uint64(t),
				Data: diff,
			})

		case b := <-connection:
			if b {
				connection_count++
				if connection_count < 0 {
					panic("connection count overflow")
				}
			} else {
				connection_count--
				if connection_count < 0 {
					panic("connection count underflow")
				}
			}

		case <-quitRequest:
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/didip/tollbooth"
)

// Server is the dispatch server
type Server struct {
	dispatch *Dispatch
}

// NewServer creates a new dispatch server
func NewServer(dispatch *Dispatch, limitMax int64, limitTTL time.Duration) *Server {
	s := new(Server)
	s.dispatch = dispatch

	// setup a rate limiter if needed
	if limitMax != math.MaxInt64 {
		log.Infof("setting webserver rate-limit to %d/%s", limitMax, limitTTL)
		limiter := tollbooth.NewLimiter(limitMax, limitTTL)
		limiter.IPLookups = []string{"X-Forwarded-For", "RemoteAddr", "X-Real-IP"}
		limiter.Methods = []string{"POST"}

		// setup endpoints
		http.Handle("/send", tollbooth.LimitFuncHandler(limiter, send))
	} else {

		http.HandleFunc("/send", send)
	}
	http.HandleFunc("/", defaultAction)

	return s
}

// Run the server
func (s Server) Run(address string) {
	log.Infof("starting webserver on %s", address)
	log.Fatal(http.ListenAndServe(address, WriteLog(http.DefaultServeMux)))
}

type statusWriter struct {
	http.ResponseWriter
	statusCode int
	length     int
}

func (w *statusWriter) WriteHeader(status int) {
	w.statusCode = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *statusWriter) Write(b []byte) (int, error) {
	if w.statusCode == 0 {
		w.statusCode = 200
	}
	w.length = len(b)
	return w.ResponseWriter.Write(b)
}

// WriteLog returns a server log handler
func WriteLog(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := statusWriter{w, 0, 0}

		// calculate the latency
		t := time.Now()
		handler.ServeHTTP(&writer, r)
		latency := time.Since(t)

		clientIP := r.RemoteAddr
		statusCode := writer.statusCode
		path := r.URL.Path
		method := r.Method
		log.Printf("%s - %s %s %d %v", clientIP, method, path, statusCode, latency)
	})
}

func send(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		respondError(w, r, 404, "page not found")
		return
	}

	if r.Body == nil {
		respondError(w, r, 400, "request body missing")
		return
	}
	var msg DispatchRequest
	err := json.NewDecoder(r.Body).Decode(&msg)
	if err != nil {
		respondError(w, r, 400, "message format: %v", err)
		return
	}

	if len(msg.AuthToken) == 0 {
		respondError(w, r, 400, "field 'auth-token' missing")
		return
	}

	err = dispatch.Send(msg)
	if err != nil {
		respondError(w, r, 400, "%v", err)
		return
	}

	respondSuccess(w, r)
}

func defaultAction(w http.ResponseWriter, r *http.Request) {
	respondError(w, r, 404, "page not found")
}

func respondError(w http.ResponseWriter, r *http.Request, code int, message string, a ...interface{}) {
	var msg string
	if r.Header.Get("Content-Type") == "application/json" {
		m := fmt.Sprintf(message, a...)
		msg = fmt.Sprintf("{\"status\": \"error\", \"message\": \"%s\"}", m)
		w.Header().Add("Content-Type", "application/json")
	} else { // default is text response
		m := fmt.Sprintf(message, a...)
		msg = fmt.Sprintf("%d %s", code, m)
		w.Header().Add("Content-Type", "text/plain")
	}

	w.WriteHeader(code)
	w.Write([]byte(msg))
}

func respondSuccess(w http.ResponseWriter, r *http.Request) {
	var msg string
	if r.Header.Get("Content-Type") == "application/json" {
		msg = "{\"status\": \"success\"}"
		w.Header().Add("Content-Type", "application/json")
	} else { // default is text response
		msg = "200 success"
		w.Header().Add("Content-Type", "text/plain")
	}

	w.WriteHeader(200)
	w.Write([]byte(msg))
}
<commit_msg>add custom limit handler<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"math"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/didip/tollbooth"
	"github.com/didip/tollbooth/config"
)

// Server is the dispatch server
type Server struct {
	dispatch *Dispatch
}

// NewServer creates a new dispatch server
func NewServer(dispatch *Dispatch, limitMax int64, limitTTL time.Duration) *Server {
	s := new(Server)
	s.dispatch = dispatch

	// setup a rate limiter if needed
	if limitMax != math.MaxInt64 {
		log.Infof("setting webserver rate-limit to %d/%s", limitMax, limitTTL)
		limiter := tollbooth.NewLimiter(limitMax, limitTTL)
		limiter.IPLookups = []string{"X-Forwarded-For", "RemoteAddr", "X-Real-IP"}
		limiter.Methods = []string{"POST"}

		// setup endpoints
		http.Handle("/send", LimitFuncHandler(limiter, send))
	} else {

		http.HandleFunc("/send", send)
	}
	http.HandleFunc("/", defaultAction)

	return s
}

// Run the server
func (s Server) Run(address string) {
	log.Infof("starting webserver on %s", address)
	log.Fatal(http.ListenAndServe(address, WriteLogHandler(http.DefaultServeMux)))
}

type statusWriter struct {
	http.ResponseWriter
	statusCode int
	length     int
}

func (w *statusWriter) WriteHeader(status int) {
	w.statusCode = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *statusWriter) Write(b []byte) (int, error) {
	if w.statusCode == 0 {
		w.statusCode = 200
	}
	w.length = len(b)
	return w.ResponseWriter.Write(b)
}

// WriteLogHandler returns a server log handler
func WriteLogHandler(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		writer := statusWriter{w, 0, 0}

		// calculate the latency
		t := time.Now()
		handler.ServeHTTP(&writer, r)
		latency := time.Since(t)

		clientIP := r.RemoteAddr
		statusCode := writer.statusCode
		path := r.URL.Path
		method := r.Method
		log.Printf("%s - %s %s %d %v", clientIP, method, path, statusCode, latency)
	})
}

// LimitHandler is a middleware that performs rate-limiting given http.Handler struct.
func LimitHandler(limiter *config.Limiter, next http.Handler) http.Handler {
	middle := func(w http.ResponseWriter, r *http.Request) {
		tollbooth.SetResponseHeaders(limiter, w)

		httpError := tollbooth.LimitByRequest(limiter, r)
		if httpError != nil {
			respondError(w, r, httpError.StatusCode, httpError.Message)
			return
		}

		// There's no rate-limit error, serve the next handler.
		next.ServeHTTP(w, r)
	}

	return http.HandlerFunc(middle)
}

// LimitFuncHandler is a middleware that performs rate-limiting given request handler function.
func LimitFuncHandler(limiter *config.Limiter, nextFunc func(http.ResponseWriter, *http.Request)) http.Handler {
	return LimitHandler(limiter, http.HandlerFunc(nextFunc))
}

func send(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		respondError(w, r, 404, "page not found")
		return
	}

	if r.Body == nil {
		respondError(w, r, 400, "request body missing")
		return
	}
	var msg DispatchRequest
	err := json.NewDecoder(r.Body).Decode(&msg)
	if err != nil {
		respondError(w, r, 400, "message format: %v", err)
		return
	}

	if len(msg.AuthToken) == 0 {
		respondError(w, r, 400, "field 'auth-token' missing")
		return
	}

	err = dispatch.Send(msg)
	if err != nil {
		respondError(w, r, 400, "%v", err)
		return
	}

	respondSuccess(w, r)
}

func defaultAction(w http.ResponseWriter, r *http.Request) {
	respondError(w, r, 404, "page not found")
}

func respondError(w http.ResponseWriter, r *http.Request, code int, message string, a ...interface{}) {
	var msg string
	if r.Header.Get("Content-Type") == "application/json" {
		m := fmt.Sprintf(message, a...)
		msg = fmt.Sprintf("{\"status\": \"error\", \"message\": \"%s\"}", m)
		w.Header().Add("Content-Type", "application/json")
	} else { // default is text response
		m := fmt.Sprintf(message, a...)
		msg = fmt.Sprintf("%d %s", code, m)
		w.Header().Add("Content-Type", "text/plain")
	}

	w.WriteHeader(code)
	w.Write([]byte(msg))
}

func respondSuccess(w http.ResponseWriter, r *http.Request) {
	var msg string
	if r.Header.Get("Content-Type") == "application/json" {
		msg = "{\"status\": \"success\"}"
		w.Header().Add("Content-Type", "application/json")
	} else { // default is text response
		msg = "200 success"
		w.Header().Add("Content-Type", "text/plain")
	}

	w.WriteHeader(200)
	w.Write([]byte(msg))
}
<|endoftext|>


<commit_before>package syslog

import (
	"bufio"
	"errors"
	"net"
	"sync"
	"time"

	"gopkg.in/mcuadros/go-syslog.v2/format"
)

var (
	RFC3164 = &format.RFC3164{} // RFC3164: http://www.ietf.org/rfc/rfc3164.txt
	RFC5424 = &format.RFC5424{} // RFC5424: http://www.ietf.org/rfc/rfc5424.txt
	RFC6587 = &format.RFC6587{} // RFC6587: http://www.ietf.org/rfc/rfc6587.txt
)

const (
	datagramChannelBufferSize = 10
	datagramReadBufferSize    = 64 * 1024
)

type Server struct {
	listeners               []*net.TCPListener
	connections             []net.Conn
	wait                    sync.WaitGroup
	doneTcp                 chan bool
	datagramChannel         chan DatagramMessage
	format                  format.Format
	handler                 Handler
	lastError               error
	readTimeoutMilliseconds int64
}

//NewServer returns a new Server
func NewServer() *Server {
	return &Server{}
}

//Sets the syslog format (RFC3164 or RFC5424 or RFC6587)
func (s *Server) SetFormat(f format.Format) {
	s.format = f
}

//Sets the handler, this handler with receive every syslog entry
func (s *Server) SetHandler(handler Handler) {
	s.handler = handler
}

//Sets the connection timeout for TCP connections, in milliseconds
func (s *Server) SetTimeout(millseconds int64) {
	s.readTimeoutMilliseconds = millseconds
}

//Configure the server for listen on an UDP addr
func (s *Server) ListenUDP(addr string) error {
	udpAddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return err
	}

	connection, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}
	connection.SetReadBuffer(datagramReadBufferSize)

	s.connections = append(s.connections, connection)
	return nil
}

//Configure the server for listen on an unix socket
func (s *Server) ListenUnixgram(addr string) error {
	unixAddr, err := net.ResolveUnixAddr("unixgram", addr)
	if err != nil {
		return err
	}

	connection, err := net.ListenUnixgram("unixgram", unixAddr)
	if err != nil {
		return err
	}
	connection.SetReadBuffer(datagramReadBufferSize)

	s.connections = append(s.connections, connection)
	return nil
}

//Configure the server for listen on a TCP addr
func (s *Server) ListenTCP(addr string) error {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return err
	}

	s.doneTcp = make(chan bool)
	s.listeners = append(s.listeners, listener)
	return nil
}

//Starts the server, all the go routines goes to live
func (s *Server) Boot() error {
	if s.format == nil {
		return errors.New("please set a valid format")
	}

	if s.handler == nil {
		return errors.New("please set a valid handler")
	}

	for _, listener := range s.listeners {
		s.goAcceptConnection(listener)
	}

	if len(s.connections) > 0 {
		s.goParseDatagrams()
	}

	for _, connection := range s.connections {
		s.goReceiveDatagrams(connection)
	}

	return nil
}

func (s *Server) goAcceptConnection(listener *net.TCPListener) {
	s.wait.Add(1)
	go func(listener *net.TCPListener) {
	loop:
		for {
			select {
			case <-s.doneTcp:
				break loop
			default:
			}
			connection, err := listener.Accept()
			if err != nil {
				continue
			}

			s.goScanConnection(connection)
		}

		s.wait.Done()
	}(listener)
}

func (s *Server) goScanConnection(connection net.Conn) {
	scanner := bufio.NewScanner(connection)
	if sf := s.format.GetSplitFunc(); sf != nil {
		scanner.Split(sf)
	}

	var scanCloser *ScanCloser
	scanCloser = &ScanCloser{scanner, connection}

	s.wait.Add(1)
	go s.scan(scanCloser)
}

func (s *Server) scan(scanCloser *ScanCloser) {
loop:
	for {
		select {
		case <-s.doneTcp:
			break loop
		default:
		}
		if s.readTimeoutMilliseconds > 0 {
			scanCloser.closer.SetReadDeadline(time.Now().Add(time.Duration(s.readTimeoutMilliseconds) * time.Millisecond))
		}
		if scanCloser.Scan() {
			s.parser([]byte(scanCloser.Text()))
		} else {
			break loop
		}
	}
	scanCloser.closer.Close()

	s.wait.Done()
}

func (s *Server) parser(line []byte) {
	parser := s.format.GetParser(line)
	err := parser.Parse()
	if err != nil {
		s.lastError = err
	}

	go s.handler.Handle(parser.Dump(), int64(len(line)), err)
}

//Returns the last error
func (s *Server) GetLastError() error {
	return s.lastError
}

//Kill the server
func (s *Server) Kill() error {
	for _, connection := range s.connections {
		err := connection.Close()
		if err != nil {
			return err
		}
	}

	for _, listener := range s.listeners {
		err := listener.Close()
		if err != nil {
			return err
		}
	}
	// Only need to close channel once to broadcast to all waiting
	if s.doneTcp != nil {
		close(s.doneTcp)
	}
	if s.datagramChannel != nil {
		close(s.datagramChannel)
	}
	return nil
}

//Waits until the server stops
func (s *Server) Wait() {
	s.wait.Wait()
}

type TimeoutCloser interface {
	Close() error
	SetReadDeadline(t time.Time) error
}

type ScanCloser struct {
	*bufio.Scanner
	closer TimeoutCloser
}

type DatagramMessage struct {
	message []byte
	client  string
}

func (s *Server) goReceiveDatagrams(connection net.Conn) {
	packetconn, ok := connection.(net.PacketConn)
	if !ok {
		panic("Connection is not a packet connection")
	}
	s.wait.Add(1)
	go func() {
		defer s.wait.Done()
		for {
			buf := make([]byte, 65536)
			n, addr, err := packetconn.ReadFrom(buf)
			if err == nil {
				// Ignore trailing control characters and NULs
				for ; (n > 0) && (buf[n-1] < 32); n-- {
				}
				if n > 0 {
					s.datagramChannel <- DatagramMessage{buf[:n], addr.String()}
				}
			} else {
				// there has been an error. Either the server has been killed
				// or may be getting a transitory error due to (e.g.) the
				// interface being shutdown in which case sleep() to avoid busy wait.
				opError, ok := err.(*net.OpError)
				if (ok) && !opError.Temporary() && !opError.Timeout() {
					return
				}
				time.Sleep(10 * time.Millisecond)
			}
		}
	}()
}

func (s *Server) goParseDatagrams() {
	s.datagramChannel = make(chan DatagramMessage, datagramChannelBufferSize)

	s.wait.Add(1)
	go func() {
		defer s.wait.Done()
		for {
			select {
			case msg, ok := (<-s.datagramChannel):
				if !ok {
					return
				}
				s.parser(msg.message)
			}
		}
	}()
}
<commit_msg>Pass the client address to the handler as an additional field<commit_after>package syslog

import (
	"bufio"
	"errors"
	"net"
	"sync"
	"time"

	"gopkg.in/mcuadros/go-syslog.v2/format"
)

var (
	RFC3164 = &format.RFC3164{} // RFC3164: http://www.ietf.org/rfc/rfc3164.txt
	RFC5424 = &format.RFC5424{} // RFC5424: http://www.ietf.org/rfc/rfc5424.txt
	RFC6587 = &format.RFC6587{} // RFC6587: http://www.ietf.org/rfc/rfc6587.txt
)

const (
	datagramChannelBufferSize = 10
	datagramReadBufferSize    = 64 * 1024
)

type Server struct {
	listeners               []*net.TCPListener
	connections             []net.Conn
	wait                    sync.WaitGroup
	doneTcp                 chan bool
	datagramChannel         chan DatagramMessage
	format                  format.Format
	handler                 Handler
	lastError               error
	readTimeoutMilliseconds int64
}

//NewServer returns a new Server
func NewServer() *Server {
	return &Server{}
}

//Sets the syslog format (RFC3164 or RFC5424 or RFC6587)
func (s *Server) SetFormat(f format.Format) {
	s.format = f
}

//Sets the handler, this handler with receive every syslog entry
func (s *Server) SetHandler(handler Handler) {
	s.handler = handler
}

//Sets the connection timeout for TCP connections, in milliseconds
func (s *Server) SetTimeout(millseconds int64) {
	s.readTimeoutMilliseconds = millseconds
}

//Configure the server for listen on an UDP addr
func (s *Server) ListenUDP(addr string) error {
	udpAddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		return err
	}

	connection, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		return err
	}
	connection.SetReadBuffer(datagramReadBufferSize)

	s.connections = append(s.connections, connection)
	return nil
}

//Configure the server for listen on an unix socket
func (s *Server) ListenUnixgram(addr string) error {
	unixAddr, err := net.ResolveUnixAddr("unixgram", addr)
	if err != nil {
		return err
	}

	connection, err := net.ListenUnixgram("unixgram", unixAddr)
	if err != nil {
		return err
	}
	connection.SetReadBuffer(datagramReadBufferSize)

	s.connections = append(s.connections, connection)
	return nil
}

//Configure the server for listen on a TCP addr
func (s *Server) ListenTCP(addr string) error {
	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
	if err != nil {
		return err
	}

	listener, err := net.ListenTCP("tcp", tcpAddr)
	if err != nil {
		return err
	}

	s.doneTcp = make(chan bool)
	s.listeners = append(s.listeners, listener)
	return nil
}

//Starts the server, all the go routines goes to live
func (s *Server) Boot() error {
	if s.format == nil {
		return errors.New("please set a valid format")
	}

	if s.handler == nil {
		return errors.New("please set a valid handler")
	}

	for _, listener := range s.listeners {
		s.goAcceptConnection(listener)
	}

	if len(s.connections) > 0 {
		s.goParseDatagrams()
	}

	for _, connection := range s.connections {
		s.goReceiveDatagrams(connection)
	}

	return nil
}

func (s *Server) goAcceptConnection(listener *net.TCPListener) {
	s.wait.Add(1)
	go func(listener *net.TCPListener) {
	loop:
		for {
			select {
			case <-s.doneTcp:
				break loop
			default:
			}
			connection, err := listener.Accept()
			if err != nil {
				continue
			}

			s.goScanConnection(connection)
		}

		s.wait.Done()
	}(listener)
}

func (s *Server) goScanConnection(connection net.Conn) {
	scanner := bufio.NewScanner(connection)
	if sf := s.format.GetSplitFunc(); sf != nil {
		scanner.Split(sf)
	}

	var scanCloser *ScanCloser
	scanCloser = &ScanCloser{scanner, connection}

	remoteAddr := connection.RemoteAddr()
	var client string
	if remoteAddr != nil {
		client = remoteAddr.String()
	}

	s.wait.Add(1)
	go s.scan(scanCloser, client)
}

func (s *Server) scan(scanCloser *ScanCloser, client string) {
loop:
	for {
		select {
		case <-s.doneTcp:
			break loop
		default:
		}
		if s.readTimeoutMilliseconds > 0 {
			scanCloser.closer.SetReadDeadline(time.Now().Add(time.Duration(s.readTimeoutMilliseconds) * time.Millisecond))
		}
		if scanCloser.Scan() {
			s.parser([]byte(scanCloser.Text()), client)
		} else {
			break loop
		}
	}
	scanCloser.closer.Close()

	s.wait.Done()
}

func (s *Server) parser(line []byte, client string) {
	parser := s.format.GetParser(line)
	err := parser.Parse()
	if err != nil {
		s.lastError = err
	}

	logParts := parser.Dump()
	logParts["client"] = client

	go s.handler.Handle(logParts, int64(len(line)), err)
}

//Returns the last error
func (s *Server) GetLastError() error {
	return s.lastError
}

//Kill the server
func (s *Server) Kill() error {
	for _, connection := range s.connections {
		err := connection.Close()
		if err != nil {
			return err
		}
	}

	for _, listener := range s.listeners {
		err := listener.Close()
		if err != nil {
			return err
		}
	}
	// Only need to close channel once to broadcast to all waiting
	if s.doneTcp != nil {
		close(s.doneTcp)
	}
	if s.datagramChannel != nil {
		close(s.datagramChannel)
	}
	return nil
}

//Waits until the server stops
func (s *Server) Wait() {
	s.wait.Wait()
}

type TimeoutCloser interface {
	Close() error
	SetReadDeadline(t time.Time) error
}

type ScanCloser struct {
	*bufio.Scanner
	closer TimeoutCloser
}

type DatagramMessage struct {
	message []byte
	client  string
}

func (s *Server) goReceiveDatagrams(connection net.Conn) {
	packetconn, ok := connection.(net.PacketConn)
	if !ok {
		panic("Connection is not a packet connection")
	}
	s.wait.Add(1)
	go func() {
		defer s.wait.Done()
		for {
			buf := make([]byte, 65536)
			n, addr, err := packetconn.ReadFrom(buf)
			if err == nil {
				// Ignore trailing control characters and NULs
				for ; (n > 0) && (buf[n-1] < 32); n-- {
				}
				if n > 0 {
					s.datagramChannel <- DatagramMessage{buf[:n], addr.String()}
				}
			} else {
				// there has been an error. Either the server has been killed
				// or may be getting a transitory error due to (e.g.) the
				// interface being shutdown in which case sleep() to avoid busy wait.
				opError, ok := err.(*net.OpError)
				if (ok) && !opError.Temporary() && !opError.Timeout() {
					return
				}
				time.Sleep(10 * time.Millisecond)
			}
		}
	}()
}

func (s *Server) goParseDatagrams() {
	s.datagramChannel = make(chan DatagramMessage, datagramChannelBufferSize)

	s.wait.Add(1)
	go func() {
		defer s.wait.Done()
		for {
			select {
			case msg, ok := (<-s.datagramChannel):
				if !ok {
					return
				}
				s.parser(msg.message, msg.client)
			}
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Initializing database")
	db := initDB()

	router := initRouter(db)
	http.Handle("/", router)

	fmt.Println("Starting server")
	http.ListenAndServe(":1123", nil)
}
<commit_msg>Updated server.go to use a http.Server manually<commit_after>package main

import (
	"fmt"
	"net/http"
)

func main() {
	fmt.Println("Initializing database")
	db := initDB()

	router := initRouter(db)

	server := &http.Server{
		Addr:    ":1123",
		Handler: router,
	}

	fmt.Println("Starting server")
	server.ListenAndServe()
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"net/http"
)

func initializeWebServer() {
	http.HandleFunc("/confirmations", confirmationServer)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func confirmationServer(w http.ResponseWriter, req *http.Request) {
	io.WriteString(w, "Confirmed!\n")
}
<commit_msg>Receive confirmation request<commit_after>package main

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

func initializeWebServer() {
	http.HandleFunc("/confirmations", confirmationServer)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func confirmationServer(w http.ResponseWriter, req *http.Request) {
	if strings.ToUpper(req.Method) == "POST" {
		err := req.ParseForm()
		if err == nil {
			nameField, nameOk := req.PostForm["name"]
			confirmationCodeField, confirmationCodeOk := req.PostForm["confirmation-code"]
			companionsField, companionsOk := req.PostForm["companions"]
			if !(nameOk && confirmationCodeOk && companionsOk) {
				w.WriteHeader(http.StatusBadRequest)
				return
			}
			name := nameField[0]
			confirmationCode := confirmationCodeField[0]
			companions := companionsField[0]

			fmt.Fprintf(w, "%v: %v: %v\n", name, confirmationCode, companions)
			return
		}
	}
	w.WriteHeader(http.StatusBadRequest)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"sync"
	"io"
	"log"
	"net/http"
	"os"
	"path"
)

type Config struct {
	Listen      string `json:"listen"`
	StaticKey   string `json:"static_key"`
	DeleteKey   string `json:"static_delete_key"`
	MaxFileSize int64  `json:"maximum_file_size"`

	Http struct {
		Enabled bool `json:"enabled"`
		Listen string `json:"listen"`
	} `json:"http"`

	Https struct {
		Enabled bool `json:"enabled"`
		Listen string `json:"listen"`
		Cert string `json:"cert"`
		Key string `json:"key"`
	} `json:"https"`

	CfCacheInvalidate struct {
		Enabled bool `json:"enabled"`
		Token string `json:"token"`
		Email string `json:"email"`
		Domain string `json:"domain"`
	} `json:"cloudflare-cache-invalidate"`
}

var config Config

type ErrorMessage struct {
	Error string `json:"error"`
	Code  int    `json:"code"`
}

type SuccessMessage struct {
	Delkey string `json:"delkey"`
}

func readConfig() Config {
	file, _ := os.Open("server.conf")
	decoder := json.NewDecoder(file)
	config := Config{}
	err := decoder.Decode(&config)
	if err != nil {
		fmt.Println("Error reading config: ", err)
	}
	return config
}

func validateConfig(config Config) {
	if (!config.Http.Enabled && !config.Https.Enabled) {
		log.Fatal("At least one of http or https must be enabled!")
	}
	if (len(config.StaticKey) == 0) {
		log.Fatal("A static key must be defined in the configuration!")
	}
	if (len(config.DeleteKey) == 0) {
		log.Fatal("A static delete key must be defined in the configuration!")
	}
}

func makeDelkey(ident string) string {
	key := []byte(config.DeleteKey)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(ident))
	return hex.EncodeToString(h.Sum(nil))
}

func index(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.ServeFile(w, r, "index.html")
	} else {
		http.NotFound(w, r)
	}
}

func upload(w http.ResponseWriter, r *http.Request) {
	if r.ContentLength > config.MaxFileSize {
		msg, _ := json.Marshal(&ErrorMessage{Error: "File size too large", Code: 1})
		w.Write(msg)
		return
	}

	r.ParseMultipartForm(50000000)
	file, _, err := r.FormFile("file")

	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 5})
		w.Write(msg)
		return
	}

	defer file.Close()

	privkey := r.FormValue("privkey")
	if privkey != config.StaticKey {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Static key doesn't match", Code: 2})
		w.Write(msg)
		return
	}

	ident := r.FormValue("ident")
	if len(ident) != 22 {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident filename length is incorrect", Code: 3})
		w.Write(msg)
		return
	}

	identPath := path.Join("i", ident)
	if _, err := os.Stat(identPath); err == nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident is already taken.", Code: 4})
		w.Write(msg)
		return
	}

	out, err := os.Create(identPath)
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 6})
		w.Write(msg)
		return
	}

	defer out.Close()

	_, err = io.Copy(out, file)
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 7})
		w.Write(msg)
		return
	}

	delkey := makeDelkey(ident)

	result, err := json.Marshal(&SuccessMessage{Delkey: delkey})
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 8})
		w.Write(msg)
	}
	w.Write(result)
}

func delfile(w http.ResponseWriter, r *http.Request) {
	ident := r.FormValue("ident")
	delkey := r.FormValue("delkey")

	if len(ident) != 22 {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident filename length is incorrect", Code: 3})
		w.Write(msg)
		return
	}

	identPath := path.Join("i", ident)
	if _, err := os.Stat(identPath); os.IsNotExist(err) {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident does not exist.", Code: 9})
		w.Write(msg)
		return
	}

	if delkey != makeDelkey(ident) {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Incorrect delete key", Code: 10})
		w.Write(msg)
		return
	}

	os.Remove(identPath)
	http.Redirect(w, r, "/", 301)
}

func main() {
	http.HandleFunc("/", index)
	http.HandleFunc("/up", upload)
	http.HandleFunc("/del", delfile)
	http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("static"))))
	http.Handle("/i/", http.StripPrefix("/i", http.FileServer(http.Dir("i"))))
	config = readConfig()
	validateConfig(config)

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		log.Printf("Starting HTTP server on %s\n", config.Http.Listen)
		log.Println(http.ListenAndServe(config.Http.Listen, nil))
	}()

	go func() {
		defer wg.Done()
		log.Printf("Starting HTTPS server on %s\n", config.Https.Listen)
		log.Println(http.ListenAndServeTLS(config.Https.Listen, config.Https.Cert, config.Https.Key, nil))
	}()

	wg.Wait()
}
<commit_msg>Actually check if servers are enabled<commit_after>package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path"
	"sync"
)

type Config struct {
	Listen      string `json:"listen"`
	StaticKey   string `json:"static_key"`
	DeleteKey   string `json:"static_delete_key"`
	MaxFileSize int64  `json:"maximum_file_size"`

	Http struct {
		Enabled bool   `json:"enabled"`
		Listen  string `json:"listen"`
	} `json:"http"`

	Https struct {
		Enabled bool   `json:"enabled"`
		Listen  string `json:"listen"`
		Cert    string `json:"cert"`
		Key     string `json:"key"`
	} `json:"https"`

	CfCacheInvalidate struct {
		Enabled bool   `json:"enabled"`
		Token   string `json:"token"`
		Email   string `json:"email"`
		Domain  string `json:"domain"`
	} `json:"cloudflare-cache-invalidate"`
}

var config Config

type ErrorMessage struct {
	Error string `json:"error"`
	Code  int    `json:"code"`
}

type SuccessMessage struct {
	Delkey string `json:"delkey"`
}

func readConfig() Config {
	file, _ := os.Open("server.conf")
	decoder := json.NewDecoder(file)
	config := Config{}
	err := decoder.Decode(&config)
	if err != nil {
		fmt.Println("Error reading config: ", err)
	}
	return config
}

func validateConfig(config Config) {
	if !config.Http.Enabled && !config.Https.Enabled {
		log.Fatal("At least one of http or https must be enabled!")
	}
	if len(config.StaticKey) == 0 {
		log.Fatal("A static key must be defined in the configuration!")
	}
	if len(config.DeleteKey) == 0 {
		log.Fatal("A static delete key must be defined in the configuration!")
	}
}

func makeDelkey(ident string) string {
	key := []byte(config.DeleteKey)
	h := hmac.New(sha256.New, key)
	h.Write([]byte(ident))
	return hex.EncodeToString(h.Sum(nil))
}

func index(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path == "/" {
		http.ServeFile(w, r, "index.html")
	} else {
		http.NotFound(w, r)
	}
}

func upload(w http.ResponseWriter, r *http.Request) {
	if r.ContentLength > config.MaxFileSize {
		msg, _ := json.Marshal(&ErrorMessage{Error: "File size too large", Code: 1})
		w.Write(msg)
		return
	}

	r.ParseMultipartForm(50000000)
	file, _, err := r.FormFile("file")

	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 5})
		w.Write(msg)
		return
	}

	defer file.Close()

	privkey := r.FormValue("privkey")
	if privkey != config.StaticKey {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Static key doesn't match", Code: 2})
		w.Write(msg)
		return
	}

	ident := r.FormValue("ident")
	if len(ident) != 22 {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident filename length is incorrect", Code: 3})
		w.Write(msg)
		return
	}

	identPath := path.Join("i", ident)
	if _, err := os.Stat(identPath); err == nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident is already taken.", Code: 4})
		w.Write(msg)
		return
	}

	out, err := os.Create(identPath)
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 6})
		w.Write(msg)
		return
	}

	defer out.Close()

	_, err = io.Copy(out, file)
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 7})
		w.Write(msg)
		return
	}

	delkey := makeDelkey(ident)

	result, err := json.Marshal(&SuccessMessage{Delkey: delkey})
	if err != nil {
		msg, _ := json.Marshal(&ErrorMessage{Error: err.Error(), Code: 8})
		w.Write(msg)
	}
	w.Write(result)
}

func delfile(w http.ResponseWriter, r *http.Request) {
	ident := r.FormValue("ident")
	delkey := r.FormValue("delkey")

	if len(ident) != 22 {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident filename length is incorrect", Code: 3})
		w.Write(msg)
		return
	}

	identPath := path.Join("i", ident)
	if _, err := os.Stat(identPath); os.IsNotExist(err) {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Ident does not exist.", Code: 9})
		w.Write(msg)
		return
	}

	if delkey != makeDelkey(ident) {
		msg, _ := json.Marshal(&ErrorMessage{Error: "Incorrect delete key", Code: 10})
		w.Write(msg)
		return
	}

	os.Remove(identPath)
	http.Redirect(w, r, "/", 301)
}

func main() {
	http.HandleFunc("/", index)
	http.HandleFunc("/up", upload)
	http.HandleFunc("/del", delfile)
	http.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir("static"))))
	http.Handle("/i/", http.StripPrefix("/i", http.FileServer(http.Dir("i"))))
	config = readConfig()
	validateConfig(config)

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		defer wg.Done()
		if config.Http.Enabled {
			log.Printf("Starting HTTP server on %s\n", config.Http.Listen)
			log.Println(http.ListenAndServe(config.Http.Listen, nil))
		}
	}()

	go func() {
		defer wg.Done()
		if config.Https.Enabled {
			log.Printf("Starting HTTPS server on %s\n", config.Https.Listen)
			log.Println(http.ListenAndServeTLS(config.Https.Listen, config.Https.Cert, config.Https.Key, nil))
		}
	}()

	wg.Wait()
}
<|endoftext|>


<commit_before>// Copyright 2018 Jigsaw Operations LLC
//
// 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
//
//     https://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 (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	"github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
	"github.com/op/go-logging"
	"github.com/oschwald/geoip2-golang"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/shadowsocks/go-shadowsocks2/core"
	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"gopkg.in/yaml.v2"
)

var logger *logging.Logger

func init() {
	logging.SetFormatter(logging.MustStringFormatter("%{color}%{level:.1s}%{time:2006-01-02T15:04:05.000Z07:00} %{pid} %{shortfile}]%{color:reset} %{message}"))
	logging.SetBackend(logging.NewLogBackend(os.Stderr, "", 0))
	logger = logging.MustGetLogger("")
}

type SSPort struct {
	listener   *net.TCPListener
	packetConn net.PacketConn
	keys       map[string]shadowaead.Cipher
}

// Listen on addr for incoming connections.
func (port *SSPort) run(natTimeout time.Duration, m metrics.ShadowsocksMetrics) {
	// TODO: Register initial data metrics at zero.
	go shadowsocks.RunUDPService(natTimeout, port.packetConn, &port.keys, m)
	shadowsocks.RunTCPService(port.listener, &port.keys, m)
}

type SSServer struct {
	natTimeout time.Duration
	m          metrics.ShadowsocksMetrics
	ports      map[int]*SSPort
}

func (s *SSServer) startPort(portNum int) error {
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{Port: portNum})
	if err != nil {
		return fmt.Errorf("Failed to start TCP on port %v: %v", portNum, err)
	}
	packetConn, err := net.ListenUDP("udp", &net.UDPAddr{Port: portNum})
	if err != nil {
		return fmt.Errorf("Failed to start UDP on port %v: %v", portNum, err)
	}
	logger.Infof("Listening TCP and UDP on port %v", portNum)
	port := &SSPort{listener: listener, packetConn: packetConn, keys: make(map[string]shadowaead.Cipher)}
	s.ports[portNum] = port
	go port.run(s.natTimeout, s.m)
	return nil
}

func (s *SSServer) removePort(portNum int) error {
	port, ok := s.ports[portNum]
	if !ok {
		return fmt.Errorf("Port %v doesn't exist", portNum)
	}
	tcpErr := port.listener.Close()
	udpErr := port.packetConn.Close()
	delete(s.ports, portNum)
	if tcpErr != nil {
		return fmt.Errorf("Failed to close listener on %v: %v", portNum, tcpErr)
	}
	if udpErr != nil {
		return fmt.Errorf("Failed to close packetConn on %v: %v", portNum, udpErr)
	}
	logger.Infof("Stopped TCP and UDP on port %v", portNum)
	return nil
}

func (s *SSServer) loadConfig(filename string) error {
	config, err := readConfig(filename)
	if err != nil {
		return fmt.Errorf("Failed to read config file %v: %v", filename, err)
	}

	portChanges := make(map[int]int)
	portKeys := make(map[int]map[string]shadowaead.Cipher)
	for _, keyConfig := range config.Keys {
		portChanges[keyConfig.Port] = 1
		keys, ok := portKeys[keyConfig.Port]
		if !ok {
			keys = make(map[string]shadowaead.Cipher)
			portKeys[keyConfig.Port] = keys
		}
		cipher, err := core.PickCipher(keyConfig.Cipher, nil, keyConfig.Secret)
		if err != nil {
			if err == core.ErrCipherNotSupported {
				return fmt.Errorf("Cipher %v for key %v is not supported", keyConfig.Cipher, keyConfig.ID)
			}
			return fmt.Errorf("Failed to create cipher for key %v: %v", keyConfig.ID, err)
		}
		aead, ok := cipher.(shadowaead.Cipher)
		if !ok {
			return fmt.Errorf("Only AEAD ciphers are supported. Found %v", keyConfig.Cipher)
		}
		keys[keyConfig.ID] = aead
	}
	for port := range s.ports {
		portChanges[port] = portChanges[port] - 1
	}
	for portNum, count := range portChanges {
		if count == -1 {
			if err := s.removePort(portNum); err != nil {
				return fmt.Errorf("Failed to remove port %v: %v", portNum, err)
			}
		} else if count == +1 {
			if err := s.startPort(portNum); err != nil {
				return fmt.Errorf("Failed to start port %v: %v", portNum, err)
			}
		}
	}
	for portNum, keys := range portKeys {
		s.ports[portNum].keys = keys
	}
	logger.Infof("Loaded %v access keys", len(config.Keys))
	s.m.SetNumAccessKeys(len(config.Keys), len(portKeys))
	return nil
}

func runSSServer(filename string, natTimeout time.Duration, sm metrics.ShadowsocksMetrics) error {
	server := &SSServer{natTimeout: natTimeout, m: sm, ports: make(map[int]*SSPort)}
	err := server.loadConfig(filename)
	if err != nil {
		return fmt.Errorf("Failed to load config file %v: %v", filename, err)
	}
	sigHup := make(chan os.Signal, 1)
	signal.Notify(sigHup, syscall.SIGHUP)
	go func() {
		for range sigHup {
			logger.Info("Updating config")
			if err := server.loadConfig(filename); err != nil {
				logger.Errorf("Could not reload config: %v", err)
			}
		}
	}()
	return nil
}

type Config struct {
	Keys []struct {
		ID     string
		Port   int
		Cipher string
		Secret string
	}
}

func readConfig(filename string) (*Config, error) {
	config := Config{}
	configData, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(configData, &config)
	return &config, err
}

func main() {
	var flags struct {
		ConfigFile  string
		MetricsAddr string
		IPCountryDB string
		Verbose     bool
		natTimeout  time.Duration
	}
	flag.StringVar(&flags.ConfigFile, "config", "", "Configuration filename")
	flag.StringVar(&flags.MetricsAddr, "metrics", "", "Address for the Prometheus metrics")
	flag.StringVar(&flags.IPCountryDB, "ip_country_db", "", "Path to the GeoLite2-Country.mmdb file")
	flag.DurationVar(&flags.natTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
	flag.BoolVar(&flags.Verbose, "verbose", false, "Enables verbose logging output")

	flag.Parse()

	if flags.Verbose {
		logging.SetLevel(logging.DEBUG, "")
	} else {
		logging.SetLevel(logging.INFO, "")
	}

	if flags.ConfigFile == "" {
		flag.Usage()
		return
	}

	if flags.MetricsAddr != "" {
		http.Handle("/metrics", promhttp.Handler())
		go func() {
			logger.Fatal(http.ListenAndServe(flags.MetricsAddr, nil))
		}()
		logger.Infof("Metrics on http://%v/metrics", flags.MetricsAddr)
	}

	var ipCountryDB *geoip2.Reader
	var err error
	if flags.IPCountryDB != "" {
		logger.Infof("Using IP-Country database at %v", flags.IPCountryDB)
		ipCountryDB, err = geoip2.Open(flags.IPCountryDB)
		if err != nil {
			log.Fatalf("Could not open geoip database at %v: %v", flags.IPCountryDB, err)
		}
		defer ipCountryDB.Close()
	}
	err = runSSServer(flags.ConfigFile, flags.natTimeout, metrics.NewShadowsocksMetrics(ipCountryDB))
	if err != nil {
		logger.Fatal(err)
	}

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
}
<commit_msg>Only add color to logging if it's the terminal<commit_after>// Copyright 2018 Jigsaw Operations LLC
//
// 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
//
//     https://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 (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/Jigsaw-Code/outline-ss-server/metrics"
	"github.com/Jigsaw-Code/outline-ss-server/shadowsocks"
	"github.com/op/go-logging"
	"github.com/oschwald/geoip2-golang"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/shadowsocks/go-shadowsocks2/core"
	"github.com/shadowsocks/go-shadowsocks2/shadowaead"
	"golang.org/x/crypto/ssh/terminal"
	"gopkg.in/yaml.v2"
)

var logger *logging.Logger

func init() {
	var prefix = "%{level:.1s}%{time:2006-01-02T15:04:05.000Z07:00} %{pid} %{shortfile}]"
	if terminal.IsTerminal(int(os.Stderr.Fd())) {
		// Add color only if the output is the terminal
		prefix = strings.Join([]string{"%{color}", prefix, "%{color:reset}"}, "")
	}
	logging.SetFormatter(logging.MustStringFormatter(strings.Join([]string{prefix, " %{message}"}, "")))
	logging.SetBackend(logging.NewLogBackend(os.Stderr, "", 0))
	logger = logging.MustGetLogger("")
}

type SSPort struct {
	listener   *net.TCPListener
	packetConn net.PacketConn
	keys       map[string]shadowaead.Cipher
}

// Listen on addr for incoming connections.
func (port *SSPort) run(natTimeout time.Duration, m metrics.ShadowsocksMetrics) {
	// TODO: Register initial data metrics at zero.
	go shadowsocks.RunUDPService(natTimeout, port.packetConn, &port.keys, m)
	shadowsocks.RunTCPService(port.listener, &port.keys, m)
}

type SSServer struct {
	natTimeout time.Duration
	m          metrics.ShadowsocksMetrics
	ports      map[int]*SSPort
}

func (s *SSServer) startPort(portNum int) error {
	listener, err := net.ListenTCP("tcp", &net.TCPAddr{Port: portNum})
	if err != nil {
		return fmt.Errorf("Failed to start TCP on port %v: %v", portNum, err)
	}
	packetConn, err := net.ListenUDP("udp", &net.UDPAddr{Port: portNum})
	if err != nil {
		return fmt.Errorf("Failed to start UDP on port %v: %v", portNum, err)
	}
	logger.Infof("Listening TCP and UDP on port %v", portNum)
	port := &SSPort{listener: listener, packetConn: packetConn, keys: make(map[string]shadowaead.Cipher)}
	s.ports[portNum] = port
	go port.run(s.natTimeout, s.m)
	return nil
}

func (s *SSServer) removePort(portNum int) error {
	port, ok := s.ports[portNum]
	if !ok {
		return fmt.Errorf("Port %v doesn't exist", portNum)
	}
	tcpErr := port.listener.Close()
	udpErr := port.packetConn.Close()
	delete(s.ports, portNum)
	if tcpErr != nil {
		return fmt.Errorf("Failed to close listener on %v: %v", portNum, tcpErr)
	}
	if udpErr != nil {
		return fmt.Errorf("Failed to close packetConn on %v: %v", portNum, udpErr)
	}
	logger.Infof("Stopped TCP and UDP on port %v", portNum)
	return nil
}

func (s *SSServer) loadConfig(filename string) error {
	config, err := readConfig(filename)
	if err != nil {
		return fmt.Errorf("Failed to read config file %v: %v", filename, err)
	}

	portChanges := make(map[int]int)
	portKeys := make(map[int]map[string]shadowaead.Cipher)
	for _, keyConfig := range config.Keys {
		portChanges[keyConfig.Port] = 1
		keys, ok := portKeys[keyConfig.Port]
		if !ok {
			keys = make(map[string]shadowaead.Cipher)
			portKeys[keyConfig.Port] = keys
		}
		cipher, err := core.PickCipher(keyConfig.Cipher, nil, keyConfig.Secret)
		if err != nil {
			if err == core.ErrCipherNotSupported {
				return fmt.Errorf("Cipher %v for key %v is not supported", keyConfig.Cipher, keyConfig.ID)
			}
			return fmt.Errorf("Failed to create cipher for key %v: %v", keyConfig.ID, err)
		}
		aead, ok := cipher.(shadowaead.Cipher)
		if !ok {
			return fmt.Errorf("Only AEAD ciphers are supported. Found %v", keyConfig.Cipher)
		}
		keys[keyConfig.ID] = aead
	}
	for port := range s.ports {
		portChanges[port] = portChanges[port] - 1
	}
	for portNum, count := range portChanges {
		if count == -1 {
			if err := s.removePort(portNum); err != nil {
				return fmt.Errorf("Failed to remove port %v: %v", portNum, err)
			}
		} else if count == +1 {
			if err := s.startPort(portNum); err != nil {
				return fmt.Errorf("Failed to start port %v: %v", portNum, err)
			}
		}
	}
	for portNum, keys := range portKeys {
		s.ports[portNum].keys = keys
	}
	logger.Infof("Loaded %v access keys", len(config.Keys))
	s.m.SetNumAccessKeys(len(config.Keys), len(portKeys))
	return nil
}

func runSSServer(filename string, natTimeout time.Duration, sm metrics.ShadowsocksMetrics) error {
	server := &SSServer{natTimeout: natTimeout, m: sm, ports: make(map[int]*SSPort)}
	err := server.loadConfig(filename)
	if err != nil {
		return fmt.Errorf("Failed to load config file %v: %v", filename, err)
	}
	sigHup := make(chan os.Signal, 1)
	signal.Notify(sigHup, syscall.SIGHUP)
	go func() {
		for range sigHup {
			logger.Info("Updating config")
			if err := server.loadConfig(filename); err != nil {
				logger.Errorf("Could not reload config: %v", err)
			}
		}
	}()
	return nil
}

type Config struct {
	Keys []struct {
		ID     string
		Port   int
		Cipher string
		Secret string
	}
}

func readConfig(filename string) (*Config, error) {
	config := Config{}
	configData, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(configData, &config)
	return &config, err
}

func main() {
	var flags struct {
		ConfigFile  string
		MetricsAddr string
		IPCountryDB string
		Verbose     bool
		natTimeout  time.Duration
	}
	flag.StringVar(&flags.ConfigFile, "config", "", "Configuration filename")
	flag.StringVar(&flags.MetricsAddr, "metrics", "", "Address for the Prometheus metrics")
	flag.StringVar(&flags.IPCountryDB, "ip_country_db", "", "Path to the GeoLite2-Country.mmdb file")
	flag.DurationVar(&flags.natTimeout, "udptimeout", 5*time.Minute, "UDP tunnel timeout")
	flag.BoolVar(&flags.Verbose, "verbose", false, "Enables verbose logging output")

	flag.Parse()

	if flags.Verbose {
		logging.SetLevel(logging.DEBUG, "")
	} else {
		logging.SetLevel(logging.INFO, "")
	}

	if flags.ConfigFile == "" {
		flag.Usage()
		return
	}

	if flags.MetricsAddr != "" {
		http.Handle("/metrics", promhttp.Handler())
		go func() {
			logger.Fatal(http.ListenAndServe(flags.MetricsAddr, nil))
		}()
		logger.Infof("Metrics on http://%v/metrics", flags.MetricsAddr)
	}

	var ipCountryDB *geoip2.Reader
	var err error
	if flags.IPCountryDB != "" {
		logger.Infof("Using IP-Country database at %v", flags.IPCountryDB)
		ipCountryDB, err = geoip2.Open(flags.IPCountryDB)
		if err != nil {
			log.Fatalf("Could not open geoip database at %v: %v", flags.IPCountryDB, err)
		}
		defer ipCountryDB.Close()
	}
	err = runSSServer(flags.ConfigFile, flags.natTimeout, metrics.NewShadowsocksMetrics(ipCountryDB))
	if err != nil {
		logger.Fatal(err)
	}

	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Zack Scholl. All rights reserved.
// Use of this source code is governed by a AGPL
// license that can be found in the LICENSE file.

// server.go handles Flag parsing and starts the Gin-Tonic webserver.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
)

// RuntimeArgs contains all runtime
// arguments available
var RuntimeArgs struct {
	ExternalIP        string
	Port              string
	ServerCRT         string
	ServerKey         string
	SourcePath        string
	Socket            string
	Cwd               string
	MqttServer        string
	MqttAdmin         string
	MosquittoPID      string
	MqttAdminPassword string
	Dump              string
	Message           string
	Mqtt              bool
	Svm               bool
}

// VersionNum keeps track of the version
var VersionNum string

// init initiates the paths in RuntimeArgs
func init() {
	cwd, _ := os.Getwd()
	RuntimeArgs.SourcePath = path.Join(cwd, "data")
	RuntimeArgs.Cwd = cwd
	RuntimeArgs.Message = ""
}

func main() {
	VersionNum = "2.0"
	// _, executableFile, _, _ := runtime.Caller(0) // get full path of this file

	// Bing flags for changing parameters of FIND
	flag.StringVar(&RuntimeArgs.Port, "p", ":8003", "port to bind")
	flag.StringVar(&RuntimeArgs.Socket, "s", "", "unix socket")
	flag.StringVar(&RuntimeArgs.ServerCRT, "crt", "", "location of ssl crt")
	flag.StringVar(&RuntimeArgs.ServerKey, "key", "", "location of ssl key")
	flag.StringVar(&RuntimeArgs.MqttServer, "mqtt", "", "turn on MQTT message passing")
	flag.StringVar(&RuntimeArgs.MqttAdmin, "mqttadmin", "", "admin to read all messages")
	flag.StringVar(&RuntimeArgs.MqttAdminPassword, "mqttadminpass", "", "admin to read all messages")
	flag.StringVar(&RuntimeArgs.MosquittoPID, "mosquitto", "", "mosquitto PID")
	flag.StringVar(&RuntimeArgs.Dump, "dump", "", "group to dump to folder")
	flag.StringVar(&RuntimeArgs.Message, "message", "", "message to display to all userse")
	flag.CommandLine.Usage = func() {
		fmt.Println(`find (version ` + VersionNum + `)
run this to start the server and then visit localhost at the port you specify
(see parameters).
Example: 'find yourserver.com'
Example: 'find -p :8080 localhost:8080'
Example: 'find -s /var/run/find.sock'
Example: 'find -db /var/lib/find/db.bolt localhost:8003'
Example: 'find -p :8080 -crt ssl/server.crt -key ssl/server.key localhost:8080'
Options:`)
		flag.CommandLine.PrintDefaults()
	}
	flag.Parse()
	RuntimeArgs.ExternalIP = flag.Arg(0)
	if RuntimeArgs.ExternalIP == "" {
		RuntimeArgs.ExternalIP = GetLocalIP() + RuntimeArgs.Port
	}

	// Check whether all the MQTT variables are passed to initiate the MQTT routines
	if len(RuntimeArgs.MqttServer) > 0 && len(RuntimeArgs.MqttAdmin) > 0 && len(RuntimeArgs.MosquittoPID) > 0 {
		RuntimeArgs.Mqtt = true
		setupMqtt()
	} else {
		RuntimeArgs.Mqtt = false
	}

	// Check whether we are just dumping the database
	if len(RuntimeArgs.Dump) > 0 {
		err := dumpFingerprints(strings.ToLower(RuntimeArgs.Dump))
		if err == nil {
			fmt.Println("Successfully dumped.")
		} else {
			log.Fatal(err)
		}
		os.Exit(1)
	}

	// Check whether SVM libraries are available
	cmdOut, _ := exec.Command("svm-scale", "").CombinedOutput()
	if len(cmdOut) == 0 {
		RuntimeArgs.Svm = false
		fmt.Println("SVM is not detected.")
		fmt.Println(`To install:
sudo apt-get install g++
wget http://www.csie.ntu.edu.tw/~cjlin/cgi-bin/libsvm.cgi?+http://www.csie.ntu.edu.tw/~cjlin/libsvm+tar.gz
tar -xvf libsvm-3.18.tar.gz
cd libsvm-3.18
make
cp svm-scale ../
cp svm-predict ../
cp svm-train ../`)
	} else {
		RuntimeArgs.Svm = true
	}

	// Setup Gin-Gonic
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()

	// Load templates
	r.LoadHTMLGlob(path.Join(RuntimeArgs.Cwd, "templates/*"))

	// Load static files (if they are not hosted by external service)
	r.Static("static/", path.Join(RuntimeArgs.Cwd, "static/"))

	// Create cookie store to keep track of logged in user
	store := sessions.NewCookieStore([]byte("secret"))
	r.Use(sessions.Sessions("mysession", store))

	// 404-page redirects to login
	r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusOK, "login.tmpl", gin.H{
			"ErrorMessage": "Please login first.",
		})
	})

	// r.PUT("/message", putMessage)

	// Routes for logging in and viewing dashboards (routes.go)
	r.GET("/", slash)
	r.GET("/login", slashLogin)
	r.POST("/login", slashLoginPOST)
	r.GET("/logout", slashLogout)
	r.GET("/dashboard/:group", slashDashboard)
	r.GET("/explore/:group/:network/:location", slashExplore2)
	r.GET("/pie/:group/:network/:location", slashPie)

	// Routes for performing fingerprinting (fingerprint.go)
	r.POST("/learn", learnFingerprintPOST)
	r.POST("/track", trackFingerprintPOST)

	// Routes for MQTT (mqtt.go)
	r.PUT("/mqtt", putMQTT)

	// Routes for API access (api.go)
	r.GET("/location", getUserLocations)
	r.GET("/editname", editName)
	r.GET("/editusername", editUserName)
	r.GET("/editnetworkname", editNetworkName)
	r.DELETE("/location", deleteLocation)
	r.DELETE("/locations", deleteLocations)
	r.DELETE("/user", deleteUser)
	r.GET("/calculate", calculate)
	r.GET("/status", getStatus)
	r.GET("/userlocs", userLocations) // to be deprecated
	r.GET("/whereami", whereAmI)      // to be deprecated
	r.PUT("/mixin", putMixinOverride)

	// Load and display the logo
	dat, _ := ioutil.ReadFile("./static/logo.txt")
	fmt.Println(string(dat))

	// Check whether user is providing certificates
	if RuntimeArgs.Socket != "" {
		r.RunUnix(RuntimeArgs.Socket)
	} else if RuntimeArgs.ServerCRT != "" && RuntimeArgs.ServerKey != "" {
		fmt.Println("(version " + VersionNum + ") is up and running on https://" + RuntimeArgs.ExternalIP)
		fmt.Println("-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----")
		r.RunTLS(RuntimeArgs.Port, RuntimeArgs.ServerCRT, RuntimeArgs.ServerKey)
	} else {
		fmt.Println("(version " + VersionNum + ") is up and running on http://" + RuntimeArgs.ExternalIP)
		fmt.Println("-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----")
		r.Run(RuntimeArgs.Port)
	}
}

// // putMessage usage: curl -G -X PUT "http://localhost:8003/message" --data-urlencode "text=hello world"
// func putMessage(c *gin.Context) {
// 	newText := c.DefaultQuery("text", "none")
// 	if newText != "none" {
// 		RuntimeArgs.Message = newText
// 		c.JSON(http.StatusOK, gin.H{"success": true, "message": "Message set as '" + newText + "'"})
// 	} else {
// 		c.JSON(http.StatusOK, gin.H{"success": false, "message": "Error parsing request"})
// 	}
// }
<commit_msg>Added easier messaging<commit_after>// Copyright 2015-2016 Zack Scholl. All rights reserved.
// Use of this source code is governed by a AGPL
// license that can be found in the LICENSE file.

// server.go handles Flag parsing and starts the Gin-Tonic webserver.

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"
	"strings"

	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
)

// RuntimeArgs contains all runtime
// arguments available
var RuntimeArgs struct {
	ExternalIP        string
	Port              string
	ServerCRT         string
	ServerKey         string
	SourcePath        string
	Socket            string
	Cwd               string
	MqttServer        string
	MqttAdmin         string
	MosquittoPID      string
	MqttAdminPassword string
	Dump              string
	Message           string
	Mqtt              bool
	Svm               bool
}

// VersionNum keeps track of the version
var VersionNum string

// init initiates the paths in RuntimeArgs
func init() {
	cwd, _ := os.Getwd()
	RuntimeArgs.SourcePath = path.Join(cwd, "data")
	RuntimeArgs.Cwd = cwd
	RuntimeArgs.Message = ""
}

func main() {
	VersionNum = "2.0"
	// _, executableFile, _, _ := runtime.Caller(0) // get full path of this file

	// Bing flags for changing parameters of FIND
	flag.StringVar(&RuntimeArgs.Port, "p", ":8003", "port to bind")
	flag.StringVar(&RuntimeArgs.Socket, "s", "", "unix socket")
	flag.StringVar(&RuntimeArgs.ServerCRT, "crt", "", "location of ssl crt")
	flag.StringVar(&RuntimeArgs.ServerKey, "key", "", "location of ssl key")
	flag.StringVar(&RuntimeArgs.MqttServer, "mqtt", "", "turn on MQTT message passing")
	flag.StringVar(&RuntimeArgs.MqttAdmin, "mqttadmin", "", "admin to read all messages")
	flag.StringVar(&RuntimeArgs.MqttAdminPassword, "mqttadminpass", "", "admin to read all messages")
	flag.StringVar(&RuntimeArgs.MosquittoPID, "mosquitto", "", "mosquitto PID")
	flag.StringVar(&RuntimeArgs.Dump, "dump", "", "group to dump to folder")
	flag.StringVar(&RuntimeArgs.Message, "message", "", "message to display to all users")
	flag.CommandLine.Usage = func() {
		fmt.Println(`find (version ` + VersionNum + `)
run this to start the server and then visit localhost at the port you specify
(see parameters).
Example: 'find yourserver.com'
Example: 'find -p :8080 localhost:8080'
Example: 'find -s /var/run/find.sock'
Example: 'find -db /var/lib/find/db.bolt localhost:8003'
Example: 'find -p :8080 -crt ssl/server.crt -key ssl/server.key localhost:8080'
Options:`)
		flag.CommandLine.PrintDefaults()
	}
	flag.Parse()
	RuntimeArgs.ExternalIP = flag.Arg(0)
	if RuntimeArgs.ExternalIP == "" {
		RuntimeArgs.ExternalIP = GetLocalIP() + RuntimeArgs.Port
	}

	// Check whether all the MQTT variables are passed to initiate the MQTT routines
	if len(RuntimeArgs.MqttServer) > 0 && len(RuntimeArgs.MqttAdmin) > 0 && len(RuntimeArgs.MosquittoPID) > 0 {
		RuntimeArgs.Mqtt = true
		setupMqtt()
	} else {
		RuntimeArgs.Mqtt = false
	}

	// Check whether we are just dumping the database
	if len(RuntimeArgs.Dump) > 0 {
		err := dumpFingerprints(strings.ToLower(RuntimeArgs.Dump))
		if err == nil {
			fmt.Println("Successfully dumped.")
		} else {
			log.Fatal(err)
		}
		os.Exit(1)
	}

	// Check if there is a message from the admin
	if _, err := os.Stat(path.Join(RuntimeArgs.Cwd, "message.txt")); err == nil {
		messageByte, _ := ioutil.ReadFile(path.Join(RuntimeArgs.Cwd, "message.txt"))
		RuntimeArgs.Message = string(messageByte)
	}

	// Check whether SVM libraries are available
	cmdOut, _ := exec.Command("svm-scale", "").CombinedOutput()
	if len(cmdOut) == 0 {
		RuntimeArgs.Svm = false
		fmt.Println("SVM is not detected.")
		fmt.Println(`To install:
sudo apt-get install g++
wget http://www.csie.ntu.edu.tw/~cjlin/cgi-bin/libsvm.cgi?+http://www.csie.ntu.edu.tw/~cjlin/libsvm+tar.gz
tar -xvf libsvm-3.18.tar.gz
cd libsvm-3.18
make
cp svm-scale ../
cp svm-predict ../
cp svm-train ../`)
	} else {
		RuntimeArgs.Svm = true
	}

	// Setup Gin-Gonic
	gin.SetMode(gin.ReleaseMode)
	r := gin.Default()

	// Load templates
	r.LoadHTMLGlob(path.Join(RuntimeArgs.Cwd, "templates/*"))

	// Load static files (if they are not hosted by external service)
	r.Static("static/", path.Join(RuntimeArgs.Cwd, "static/"))

	// Create cookie store to keep track of logged in user
	store := sessions.NewCookieStore([]byte("secret"))
	r.Use(sessions.Sessions("mysession", store))

	// 404-page redirects to login
	r.NoRoute(func(c *gin.Context) {
		c.HTML(http.StatusOK, "login.tmpl", gin.H{
			"ErrorMessage": "Please login first.",
		})
	})

	// r.PUT("/message", putMessage)

	// Routes for logging in and viewing dashboards (routes.go)
	r.GET("/", slash)
	r.GET("/login", slashLogin)
	r.POST("/login", slashLoginPOST)
	r.GET("/logout", slashLogout)
	r.GET("/dashboard/:group", slashDashboard)
	r.GET("/explore/:group/:network/:location", slashExplore2)
	r.GET("/pie/:group/:network/:location", slashPie)

	// Routes for performing fingerprinting (fingerprint.go)
	r.POST("/learn", learnFingerprintPOST)
	r.POST("/track", trackFingerprintPOST)

	// Routes for MQTT (mqtt.go)
	r.PUT("/mqtt", putMQTT)

	// Routes for API access (api.go)
	r.GET("/location", getUserLocations)
	r.GET("/editname", editName)
	r.GET("/editusername", editUserName)
	r.GET("/editnetworkname", editNetworkName)
	r.DELETE("/location", deleteLocation)
	r.DELETE("/locations", deleteLocations)
	r.DELETE("/user", deleteUser)
	r.GET("/calculate", calculate)
	r.GET("/status", getStatus)
	r.GET("/userlocs", userLocations) // to be deprecated
	r.GET("/whereami", whereAmI)      // to be deprecated
	r.PUT("/mixin", putMixinOverride)

	// Load and display the logo
	dat, _ := ioutil.ReadFile("./static/logo.txt")
	fmt.Println(string(dat))

	// Check whether user is providing certificates
	if RuntimeArgs.Socket != "" {
		r.RunUnix(RuntimeArgs.Socket)
	} else if RuntimeArgs.ServerCRT != "" && RuntimeArgs.ServerKey != "" {
		fmt.Println("(version " + VersionNum + ") is up and running on https://" + RuntimeArgs.ExternalIP)
		fmt.Println("-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----")
		r.RunTLS(RuntimeArgs.Port, RuntimeArgs.ServerCRT, RuntimeArgs.ServerKey)
	} else {
		fmt.Println("(version " + VersionNum + ") is up and running on http://" + RuntimeArgs.ExternalIP)
		fmt.Println("-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----")
		r.Run(RuntimeArgs.Port)
	}
}

// // putMessage usage: curl -G -X PUT "http://localhost:8003/message" --data-urlencode "text=hello world"
// func putMessage(c *gin.Context) {
// 	newText := c.DefaultQuery("text", "none")
// 	if newText != "none" {
// 		RuntimeArgs.Message = newText
// 		c.JSON(http.StatusOK, gin.H{"success": true, "message": "Message set as '" + newText + "'"})
// 	} else {
// 		c.JSON(http.StatusOK, gin.H{"success": false, "message": "Error parsing request"})
// 	}
// }
<|endoftext|>


<commit_before>package main

import (
    "net"
    "fmt"
    "os"
    "bufio"
)

const (
    CONNECTION_TYPE = "tcp"
    CONNECTION_HOST = "localhost"
    CONNECTION_PORT = "7010"
)

func main() {
    fmt.Println("Server initializing...")
    ln, err := net.Listen(CONNECTION_TYPE, CONNECTION_HOST + ":" + CONNECTION_PORT)
    if (err != nil) {
        fmt.Println("Error (LISTEN): ", err.Error())
        os.Exit(1)
    }
    defer ln.Close()

    fmt.Println("Server listening " + CONNECTION_HOST + ":" + CONNECTION_PORT + "...")

    conn, err := ln.Accept()
    if (err != nil) {
        fmt.Println("Error (ACCEPT): ", err.Error())
        os.Exit(1)
    }

    reader := bufio.NewReader(conn)
    writerConn := bufio.NewWriter(conn)
    writerStdo := bufio.NewWriter(os.Stdout)

    for {
        message, err := reader.ReadString('\n')
        if (err != nil) {
            fmt.Println("Error (READ): ", err.Error())
            os.Exit(1)
        }

        writerStdo.WriteString("Message Received: " + message)
        writerStdo.Flush()

        writerConn.WriteString(message)
        writerConn.Flush()
    }
}
<commit_msg>feature: server broadcasts messages to all clients<commit_after>package main

import (
    "net"
    "bufio"
    "fmt"
    "os"
)

type Client struct {
    in chan string
    out chan string
    reader *bufio.Reader
    writer *bufio.Writer
}

type Hub struct {
    clients []*Client
    connections chan net.Conn
    in chan string
    out chan string
    writer *bufio.Writer
}

const (
    CONNECTION_TYPE = "tcp"
    CONNECTION_HOST = "localhost"
    CONNECTION_PORT = "7010"
)

func (client *Client) Read() {
    for {
        line, err := client.reader.ReadString('\n')
        if (err != nil) {
            fmt.Println("Error (READ): ", err.Error())
            os.Exit(1)
        }
        client.in <- line
    }
}

func (client *Client) Write() {
    for data := range client.out {
        client.writer.WriteString(data)
        client.writer.Flush()
    }
}

func (client *Client) Listen() {
    go client.Read()
    go client.Write()
}

func CreateClient(connection net.Conn) *Client {
    writer := bufio.NewWriter(connection)
    reader := bufio.NewReader(connection)

    client := &Client{
        in: make(chan string),
        out: make(chan string),
        reader: reader,
        writer: writer,
    }

    client.Listen()

    return client
}

func (hub *Hub) Broadcast(data string) {
    for _, client := range hub.clients {
        client.out <- data
    }
}

func (hub *Hub) Join(connection net.Conn) {
    client := CreateClient(connection)
    hub.clients = append(hub.clients, client)
    go func() {
        for {
            hub.in <- <-client.in
        }
    }()
}

func (hub *Hub) Write(data string) {
    hub.writer.WriteString(data)
    hub.writer.Flush()
}

func (hub *Hub) Listen() {
    go func() {
        for {
            select {
            case data := <-hub.in:
                hub.Broadcast(data)
                hub.Write(data)
                break
            case conn := <-hub.connections:
                hub.Join(conn)
                break
            }
        }
    }()
}

func CreateHub() *Hub {
    writer := bufio.NewWriter(os.Stdout)

    hub := &Hub{
        clients: make([]*Client, 0),
        connections: make(chan net.Conn),
        in: make(chan string),
        out: make(chan string),
        writer: writer,
    }

    hub.Listen()

    return hub
}

func main() {
    fmt.Println("Server initializing...")
    hub := CreateHub()

    listener, err := net.Listen(CONNECTION_TYPE, CONNECTION_HOST + ":" + CONNECTION_PORT)
    if (err != nil) {
        fmt.Println("Error (LISTEN): ", err.Error())
        os.Exit(1)
    }

    for {
        conn, err := listener.Accept()
        if (err != nil) {
            fmt.Println("Error (LISTEN): ", err.Error())
            os.Exit(1)
        }
        hub.connections <- conn
    }
}

<|endoftext|>