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  }