add "download consul binary" task
[arvados.git] / services / boot / server.go
1 package main
2
3 import (
4         "encoding/json"
5         "flag"
6         "log"
7         "net/http"
8         "time"
9 )
10
11 func main() {
12         listen := flag.String("listen", ":80", "addr:port or :port to listen on")
13         flag.Parse()
14         go func() {
15                 log.Printf("starting server at %s", *listen)
16                 log.Fatal(http.ListenAndServe(*listen, stack(logger, apiOrAssets)))
17         }()
18         go runTasks(ctlTasks)
19         <-(chan struct{})(nil)
20 }
21
22 type middleware func(http.Handler) http.Handler
23
24 var notFound = http.NotFoundHandler()
25
26 // returns a handler that implements a stack of middlewares.
27 func stack(m ...middleware) http.Handler {
28         if len(m) == 0 {
29                 return notFound
30         }
31         return m[0](stack(m[1:]...))
32 }
33
34 // logs each request.
35 func logger(next http.Handler) http.Handler {
36         return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
37                 t := time.Now()
38                 next.ServeHTTP(w, r)
39                 log.Printf("%.6f %q %q %q", time.Since(t).Seconds(), r.RemoteAddr, r.Method, r.URL.Path)
40         })
41 }
42
43 // dispatches /api/ to the API stack, everything else to the static
44 // assets stack.
45 func apiOrAssets(next http.Handler) http.Handler {
46         mux := http.NewServeMux()
47         mux.Handle("/api/", stack(apiHeaders, apiRoutes))
48         mux.Handle("/", http.FileServer(assetFS()))
49         return mux
50 }
51
52 // adds response headers suitable for API responses
53 func apiHeaders(next http.Handler) http.Handler {
54         return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
55                 w.Header().Set("Content-Type", "application/json")
56                 next.ServeHTTP(w, r)
57         })
58 }
59
60 // dispatches API routes
61 func apiRoutes(http.Handler) http.Handler {
62         mux := http.NewServeMux()
63         mux.HandleFunc("/api/ping", func(w http.ResponseWriter, r *http.Request) {
64                 json.NewEncoder(w).Encode(map[string]interface{}{"time": time.Now().UTC()})
65         })
66         mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
67                 w.WriteHeader(http.StatusNotFound)
68                 json.NewEncoder(w).Encode(map[string]string{"error": "not found"})
69         })
70         return mux
71 }