dev privileges, db
[arvados.git] / services / boot / webgui.go
1 package main
2
3 import (
4         "encoding/json"
5         "log"
6         "net/http"
7         "strconv"
8         "time"
9 )
10
11 func runWebGUI(cfg *Config) {
12         if cfg.WebGUI.Listen == "" {
13                 return
14         }
15         log.Printf("starting webgui at %s", cfg.WebGUI.Listen)
16         log.Fatal(http.ListenAndServe(cfg.WebGUI.Listen, stack(cfg.logger, cfg.apiOrAssets)))
17 }
18
19 type middleware func(http.Handler) http.Handler
20
21 var notFound = http.NotFoundHandler()
22
23 // returns a handler that implements a stack of middlewares.
24 func stack(m ...middleware) http.Handler {
25         if len(m) == 0 {
26                 return notFound
27         }
28         return m[0](stack(m[1:]...))
29 }
30
31 // logs each request.
32 func (cfg *Config) logger(next http.Handler) http.Handler {
33         return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
34                 t := time.Now()
35                 next.ServeHTTP(w, r)
36                 log.Printf("%.6f %q %q %q", time.Since(t).Seconds(), r.RemoteAddr, r.Method, r.URL.Path)
37         })
38 }
39
40 // dispatches /api/ to the API stack, everything else to the static
41 // assets stack.
42 func (cfg *Config) apiOrAssets(next http.Handler) http.Handler {
43         mux := http.NewServeMux()
44         mux.Handle("/api/", stack(cfg.apiHeaders, cfg.apiRoutes))
45         mux.Handle("/", http.FileServer(assetFS()))
46         return mux
47 }
48
49 // adds response headers suitable for API responses
50 func (cfg *Config) apiHeaders(next http.Handler) http.Handler {
51         return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
52                 w.Header().Set("Content-Type", "application/json")
53                 next.ServeHTTP(w, r)
54         })
55 }
56
57 // dispatches API routes
58 func (cfg *Config) apiRoutes(http.Handler) http.Handler {
59         mux := http.NewServeMux()
60         mux.HandleFunc("/api/ping", func(w http.ResponseWriter, r *http.Request) {
61                 json.NewEncoder(w).Encode(map[string]interface{}{"time": time.Now().UTC()})
62         })
63         mux.HandleFunc("/api/status/controller", func(w http.ResponseWriter, r *http.Request) {
64                 timeout := time.Minute
65                 if v, err := strconv.ParseInt(r.FormValue("timeout"), 10, 64); err == nil {
66                         timeout = time.Duration(v) * time.Second
67                 }
68                 if v, err := strconv.ParseInt(r.FormValue("newerThan"), 10, 64); err == nil {
69                         log.Println(v, timeout)
70                         // TODO: wait
71                         // TaskState.Wait(version(v), timeout, r.Context())
72                 }
73                 // TODO:
74                 // rep, v := report(ctlTasks)
75                 json.NewEncoder(w).Encode(map[string]interface{}{
76                         // "Version": v,
77                         // "Tasks":   rep,
78                         // TODO:
79                         "Version": 1,
80                         "Tasks":   []int{},
81                 })
82         })
83         mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
84                 w.WriteHeader(http.StatusNotFound)
85                 json.NewEncoder(w).Encode(map[string]string{"error": "not found"})
86         })
87         return mux
88 }