GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

main.go 3.01 KB
Newer Older
1 2 3 4 5 6 7 8
package main

import (
	"flag"
	"io"
	"log"
	"net/http"
	"os"
9 10
	"os/signal"
	"syscall"
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
	"time"

	"git.torproject.org/pluggable-transports/snowflake.git/common/safelog"
	"github.com/gorilla/mux"
)

type Route struct {
	Name        string
	Method      string
	Pattern     string
	HandlerFunc http.HandlerFunc
}

type Routes []Route

var routes = Routes{
	Route{
28 29 30 31
		"BridgeState",
		"GET",
		"/bridge-state",
		BridgeState,
32
	},
33 34 35 36 37 38
	Route{
		"BridgeStateWeb",
		"GET",
		"/result",
		BridgeStateWeb,
	},
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
}

// Logger logs when we receive requests, and the execution time of handling
// these requests.  We don't log client IP addresses or the given obfs4
// parameters.
func Logger(inner http.Handler, name string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()

		inner.ServeHTTP(w, r)

		log.Printf(
			"%s\t%s\t%s\t%s",
			r.Method,
			r.RequestURI,
			name,
			time.Since(start),
		)
	})
}

// NewRouter creates and returns a new request router.
func NewRouter() *mux.Router {

	router := mux.NewRouter().StrictSlash(true)
	for _, route := range routes {
		var handler http.Handler

		handler = route.HandlerFunc
		handler = Logger(handler, route.Name)

		router.
			Methods(route.Method).
			Path(route.Pattern).
			Name(route.Name).
			Handler(handler)
	}

	return router
}

func main() {

	var addr string
83
	var web bool
84
	var certFilename, keyFilename string
85
	var cacheFile string
86
	var templatesDir string
87

Philipp Winter's avatar
Philipp Winter committed
88
	flag.StringVar(&addr, "addr", ":5000", "Address to listen on.")
89
	flag.BoolVar(&web, "web", false, "Enable the web interface (in addition to the JSON API).")
90 91
	flag.StringVar(&certFilename, "cert", "", "TLS certificate file.")
	flag.StringVar(&keyFilename, "key", "", "TLS private key file.")
92
	flag.StringVar(&cacheFile, "cache", "bridgestrap-cache.bin", "Cache file that contains test results.")
93
	flag.StringVar(&templatesDir, "templates", "templates", "Path to directory that contains our web templates.")
94 95 96 97 98 99 100
	flag.Parse()

	var logOutput io.Writer = os.Stderr
	// Send the log output through our scrubber first.
	log.SetOutput(&safelog.LogScrubber{Output: logOutput})
	log.SetFlags(log.LstdFlags | log.LUTC)

101 102
	LoadHtmlTemplates(templatesDir)

103 104 105 106 107 108 109 110 111 112 113
	if web {
		log.Println("Enabling web interface.")
		routes = append(routes,
			Route{
				"Index",
				"GET",
				"/",
				Index,
			})
	}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	if err := cache.ReadFromDisk(cacheFile); err != nil {
		log.Printf("Could not read cache because: %s", err)
	}
	// When catching SIGINT or SIGTERM, write our cache to disk before exiting.
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT)
	signal.Notify(signalChan, syscall.SIGTERM)
	go func() {
		<-signalChan
		if err := cache.WriteToDisk(cacheFile); err != nil {
			log.Printf("Could not write cache because: %s", err)
		}
		os.Exit(1)
	}()

129
	router := NewRouter()
Philipp Winter's avatar
Philipp Winter committed
130
	log.Printf("Starting service on port %s.", addr)
131 132 133 134 135
	if certFilename != "" && keyFilename != "" {
		log.Fatal(http.ListenAndServeTLS(addr, certFilename, keyFilename, router))
	} else {
		log.Fatal(http.ListenAndServe(addr, router))
	}
136
}