12 "git.curoverse.com/arvados.git/sdk/go/config"
15 const defaultCfgPath = "/etc/arvados/boot/boot.yml"
20 cfgPath := flag.String("config", defaultCfgPath, "`path` to config file")
23 if err := config.LoadFile(&cfg, *cfgPath); os.IsNotExist(err) && *cfgPath == defaultCfgPath {
24 log.Printf("WARNING: No config file specified or found, starting fresh!")
25 } else if err != nil {
30 log.Printf("starting server at %s", cfg.WebListen)
31 log.Fatal(http.ListenAndServe(cfg.WebListen, stack(logger, apiOrAssets)))
34 ticker := time.NewTicker(5 * time.Second)
36 runTasks(&cfg, ctlTasks)
40 <-(chan struct{})(nil)
43 type middleware func(http.Handler) http.Handler
45 var notFound = http.NotFoundHandler()
47 // returns a handler that implements a stack of middlewares.
48 func stack(m ...middleware) http.Handler {
52 return m[0](stack(m[1:]...))
56 func logger(next http.Handler) http.Handler {
57 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
60 log.Printf("%.6f %q %q %q", time.Since(t).Seconds(), r.RemoteAddr, r.Method, r.URL.Path)
64 // dispatches /api/ to the API stack, everything else to the static
66 func apiOrAssets(next http.Handler) http.Handler {
67 mux := http.NewServeMux()
68 mux.Handle("/api/", stack(apiHeaders, apiRoutes))
69 mux.Handle("/", http.FileServer(assetFS()))
73 // adds response headers suitable for API responses
74 func apiHeaders(next http.Handler) http.Handler {
75 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
76 w.Header().Set("Content-Type", "application/json")
81 // dispatches API routes
82 func apiRoutes(http.Handler) http.Handler {
83 mux := http.NewServeMux()
84 mux.HandleFunc("/api/ping", func(w http.ResponseWriter, r *http.Request) {
85 json.NewEncoder(w).Encode(map[string]interface{}{"time": time.Now().UTC()})
87 mux.HandleFunc("/api/tasks/ctl", func(w http.ResponseWriter, r *http.Request) {
88 timeout := time.Minute
89 if v, err := strconv.ParseInt(r.FormValue("timeout"), 10, 64); err == nil {
90 timeout = time.Duration(v) * time.Second
92 if v, err := strconv.ParseInt(r.FormValue("newerThan"), 10, 64); err == nil {
93 TaskState.Wait(version(v), timeout, r.Context())
95 rep, v := report(ctlTasks)
96 json.NewEncoder(w).Encode(map[string]interface{}{
101 mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
102 w.WriteHeader(http.StatusNotFound)
103 json.NewEncoder(w).Encode(map[string]string{"error": "not found"})