From 67395bfcd164d5c4ef0e134e9fcf35e94139bce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=C3=A1n=20C=20McCord?= Date: Tue, 12 May 2020 13:20:29 -0400 Subject: [PATCH] restructure API service --- http.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 68 ++--------------------------------------------------- 2 files changed, 74 insertions(+), 66 deletions(-) create mode 100644 http.go diff --git a/http.go b/http.go new file mode 100644 index 0000000..1ebc391 --- /dev/null +++ b/http.go @@ -0,0 +1,72 @@ +package main + +import ( + "context" + "encoding/json" + "log" + "net/http" + "strconv" + "strings" +) + +func (s *dispatcherSets) startHTTP(ctx context.Context, addr string) { + + http.HandleFunc("/check/", s.handleIPCheckRequest) + http.HandleFunc("/dispatcher/", s.handleListSetRequest) + http.HandleFunc("/dispatchers/", s.handleListSetRequest) + + log.Fatalln(http.ListenAndServe(addr, nil)) +} + +// Check IP address for membership in a dispatcher set. +// URL: /check// +func (s *dispatcherSets) handleIPCheckRequest(w http.ResponseWriter, r *http.Request) { + pieces := strings.Split(strings.TrimPrefix(r.URL.Path, "/check/"), "/") + if len(pieces) != 2 { + w.WriteHeader(http.StatusBadRequest) + return + } + + setID, err := strconv.Atoi(pieces[0]) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + if s.validateSetMember(setID, pieces[1]) { + w.WriteHeader(http.StatusOK) + return + } + + w.WriteHeader(http.StatusNotFound) + return + +} + +// Return a given dispatcher set +// URL: /dispatcher/ +func (s *dispatcherSets) handleListSetRequest(w http.ResponseWriter, r *http.Request) { + pieces := strings.Split(strings.TrimPrefix(r.URL.Path, "/dispatcher/"), "/") + if len(pieces) != 1 { + w.WriteHeader(http.StatusBadRequest) + return + } + + setID, err := strconv.Atoi(pieces[0]) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + selectedSet := s.getDispatcherSet(setID) + if selectedSet != nil { + w.Header().Add("Content-Type", "application/json") + + if err = json.NewEncoder(w).Encode(selectedSet); err != nil { + w.WriteHeader(http.StatusInternalServerError) + } + return + } + + w.WriteHeader(http.StatusNotFound) +} diff --git a/main.go b/main.go index ab8cc5a..baeb796 100644 --- a/main.go +++ b/main.go @@ -2,17 +2,13 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "io" "io/ioutil" "log" - "net/http" "os" "os/signal" - "strconv" - "strings" "syscall" "time" @@ -157,52 +153,6 @@ func (s *dispatcherSets) maintain(ctx context.Context) error { return ctx.Err() } -// ServeHTTP offers a web service by which clients may validate membership of an IP address within a dispatcher set or fetch a dispatcher set -func (s *dispatcherSets) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Handle requests for /check// to validate membership of an IP to a dispatcher set - if strings.HasPrefix(r.URL.Path, "/check/") { - pieces := strings.Split(strings.TrimPrefix(r.URL.Path, "/check/"), "/") - if len(pieces) != 2 { - w.WriteHeader(http.StatusBadRequest) - return - } - setID, err := strconv.Atoi(pieces[0]) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - return - } - if s.validateSetMember(setID, pieces[1]) { - w.WriteHeader(http.StatusOK) - return - } - w.WriteHeader(http.StatusNotFound) - return - } else if strings.HasPrefix(r.URL.Path, "/dispatcher/") { // Handle requests for /dispatcher/ to fetch a dispatcher set - pieces := strings.Split(strings.TrimPrefix(r.URL.Path, "/dispatcher/"), "/") - if len(pieces) != 1 { - w.WriteHeader(http.StatusBadRequest) - return - } - setID, err := strconv.Atoi(pieces[0]) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - return - } - selectedSet := s.getDispatcherSet(setID) - if selectedSet != nil { - js, err := json.Marshal(selectedSet) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - w.Write(js) //If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK) before writing the data - return - } - } - - w.WriteHeader(http.StatusNotFound) -} - func (s *dispatcherSets) validateSetMember(id int, addr string) bool { selectedSet, ok := s.sets[id] if !ok { @@ -298,23 +248,9 @@ func run() error { } }) - // Run a web service to offer IP checks for each member of the dispatcher set and fetch a dispatcher set + // Run HTTP API service if apiAddr != "" { - var srv http.Server - srv.Addr = apiAddr - srv.Handler = s - - go func() { - <-ctx.Done() - if err := srv.Shutdown(ctx); err != nil { - log.Fatalln("failed to shut down HTTP server:", err) - } - }() - go func() { - if err := srv.ListenAndServe(); err != http.ErrServerClosed { - log.Fatalln("failed to start HTTP server:", err) - } - }() + go s.startHTTP(ctx, apiAddr) } for ctx.Err() == nil {