github.com/jlowellwofford/u-root@v1.0.0/pkg/sos/server.go (about) 1 // Copyright 2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package sos 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "html/template" 11 "io/ioutil" 12 "log" 13 "net/http" 14 "path/filepath" 15 16 "github.com/gorilla/mux" 17 ) 18 19 const ( 20 PortNum = "8000" 21 DefHtmlPage = ` 22 <head> 23 <style> 24 table { 25 font-family: arial, sans-serif; 26 border-collapse: collapse; 27 width: 100%; 28 } 29 30 td, th { 31 border: 1px solid #dddddd; 32 text-align: left; 33 padding: 8px; 34 } 35 </style> 36 <script> 37 </script> 38 </head> 39 <body> 40 <h1>Current Services (html embedded)</h1> 41 <table style="width:100%"> 42 <tr> 43 <th>Service</th> 44 <th>Port Number</th> 45 <th></th> 46 </tr> 47 {{range $key, $value := .}} 48 <tr> 49 <td>{{$key}}</td> 50 <td>{{$value}}</td> 51 <td><a href="http://localhost:{{$value}}" target="_blank">Go there!</td> 52 </tr> 53 {{else}} 54 <tr> 55 <td colspan="3" style="text-align:center">No services</td> 56 </tr> 57 {{end}} 58 </table> 59 </body> 60 ` 61 ) 62 63 // default path 64 var htmlRoot = "/etc/sos/html" 65 66 type SosServer struct { 67 service *SosService 68 } 69 70 type RegisterReqJson struct { 71 Service string 72 Port uint 73 } 74 75 // set htmlRoot var to array of dirs p 76 func SetHTMLRoot(p ...string) { 77 if len(p) > 0 { 78 htmlRoot = filepath.Join(p...) 79 } 80 } 81 82 // HTMLPath returns the HTMLPath formed by joining the arguments together. 83 // If there are no arguments, it simply returns the HTML root directory. 84 func HTMLPath(n ...string) string { 85 return filepath.Join(htmlRoot, filepath.Join(n...)) 86 } 87 88 func (s SosServer) registerHandle(w http.ResponseWriter, r *http.Request) { 89 var msg RegisterReqJson 90 decoder := json.NewDecoder(r.Body) 91 defer r.Body.Close() 92 if err := decoder.Decode(&msg); err != nil { 93 log.Printf("error: %v", err) 94 w.WriteHeader(http.StatusBadRequest) 95 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 96 return 97 } 98 99 if err := s.service.Register(msg.Service, msg.Port); err != nil { 100 log.Printf("error: %v", err) 101 w.WriteHeader(http.StatusInternalServerError) 102 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 103 return 104 } 105 json.NewEncoder(w).Encode(nil) 106 } 107 108 type UnRegisterReqJson struct { 109 ServiceName string 110 } 111 112 func (s SosServer) unregisterHandle(w http.ResponseWriter, r *http.Request) { 113 var msg UnRegisterReqJson 114 decoder := json.NewDecoder(r.Body) 115 defer r.Body.Close() 116 if err := decoder.Decode(&msg); err != nil { 117 log.Printf("error: %v", err) 118 w.WriteHeader(http.StatusBadRequest) 119 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 120 return 121 } 122 s.service.Unregister(msg.ServiceName) 123 json.NewEncoder(w).Encode(nil) 124 } 125 126 type GetServiceResJson struct { 127 Port uint 128 } 129 130 func (s SosServer) getServiceHandle(w http.ResponseWriter, r *http.Request) { 131 vars := mux.Vars(r) 132 port, err := s.service.Read(vars["service"]) 133 if err != nil { 134 log.Printf("error: %v", err) 135 w.WriteHeader(http.StatusNotFound) 136 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 137 return 138 } 139 json.NewEncoder(w).Encode(GetServiceResJson{port}) 140 } 141 142 func (s SosServer) redirectToResourceHandle(w http.ResponseWriter, r *http.Request) { 143 vars := mux.Vars(r) 144 port, err := s.service.Read(vars["service"]) 145 if err != nil { 146 log.Printf("error: %v", err) 147 w.WriteHeader(http.StatusNotFound) 148 json.NewEncoder(w).Encode(struct{ Error string }{err.Error()}) 149 return 150 } 151 http.Redirect(w, r, fmt.Sprintf("http://localhost:%v/", port), http.StatusTemporaryRedirect) 152 } 153 154 func (s SosServer) displaySosHandle(w http.ResponseWriter, r *http.Request) { 155 snap := s.service.SnapshotRegistry() 156 var tmpl *template.Template 157 file, err := ioutil.ReadFile(HTMLPath("sos.html")) 158 if err == nil { 159 html := string(file) 160 tmpl = template.Must(template.New("SoS").Parse(html)) 161 } else { 162 tmpl = template.Must(template.New("SoS").Parse(DefHtmlPage)) 163 } 164 tmpl.Execute(w, snap) 165 } 166 167 func (s SosServer) buildRouter() http.Handler { 168 r := mux.NewRouter() 169 r.HandleFunc("/", s.displaySosHandle).Methods("GET") 170 r.HandleFunc("/register", s.registerHandle).Methods("POST") 171 r.HandleFunc("/unregister", s.unregisterHandle).Methods("POST") 172 r.HandleFunc("/service/{service}", s.getServiceHandle).Methods("GET") 173 r.HandleFunc("/go/{service}", s.redirectToResourceHandle).Methods("GET") 174 r.PathPrefix("/css/").Handler(http.StripPrefix("/css/", http.FileServer(http.Dir(HTMLPath("css"))))) 175 return r 176 } 177 178 func StartServer(service *SosService) { 179 server := SosServer{service} 180 fmt.Println(http.ListenAndServe(fmt.Sprintf(":%s", PortNum), server.buildRouter())) 181 }