diff options
Diffstat (limited to 'src/hub')
-rw-r--r-- | src/hub/src/spreadspace.org/sfive/s5srvWeb.go | 194 |
1 files changed, 107 insertions, 87 deletions
diff --git a/src/hub/src/spreadspace.org/sfive/s5srvWeb.go b/src/hub/src/spreadspace.org/sfive/s5srvWeb.go index 3593f62..2379078 100644 --- a/src/hub/src/spreadspace.org/sfive/s5srvWeb.go +++ b/src/hub/src/spreadspace.org/sfive/s5srvWeb.go @@ -37,10 +37,9 @@ import ( // "io" "net" "net/http" - "time" - // "strconv" - "fmt" "path" + "strconv" + "time" ) type webErrorResponse struct { @@ -56,7 +55,6 @@ func webNotFound(srv *Server, w http.ResponseWriter, r *http.Request) { // /healthz type webHealthzResponse struct { - Error string `json:"error,omitempty"` Status string `json:"status"` HubId string `json:"hub-uuid"` } @@ -76,8 +74,7 @@ func webHealthz(srv *Server, w http.ResponseWriter, r *http.Request) { // /hubs type webHubsResponse struct { - Error string `json:"error,omitempty"` - Hubs []string `json:"hubs"` + Hubs []string `json:"hubs"` } func webHubs(srv *Server, w http.ResponseWriter, r *http.Request) { @@ -89,7 +86,8 @@ func webHubs(srv *Server, w http.ResponseWriter, r *http.Request) { var err error resp := webHubsResponse{} if resp.Hubs, err = srv.store.GetHubs(); err != nil { - resp.Error = fmt.Sprintf("%v", err) + sendWebResponse(w, http.StatusInternalServerError, webErrorResponse{err.Error()}) + return } sendWebResponse(w, http.StatusOK, resp) } @@ -97,7 +95,6 @@ func webHubs(srv *Server, w http.ResponseWriter, r *http.Request) { // /sources type webSourcesResponse struct { - Error string `json:"error,omitempty"` Sources []SourceId `json:"sources"` } @@ -110,69 +107,91 @@ func webSources(srv *Server, w http.ResponseWriter, r *http.Request) { var err error resp := webSourcesResponse{} if resp.Sources, err = srv.store.GetSources(); err != nil { - resp.Error = fmt.Sprintf("%v", err) + sendWebResponse(w, http.StatusInternalServerError, webErrorResponse{err.Error()}) + return } sendWebResponse(w, http.StatusOK, resp) } -// func (srv Server) webGetUpdateList(c web.C, w http.ResponseWriter, r *http.Request) { -// const resourceName = "updates" -// from := 0 -// if fromStr := r.FormValue("from"); fromStr != "" { -// fromInt, err := strconv.Atoi(fromStr) -// if err != nil { -// http.Error(w, fmt.Sprintf("failed to parse from field: %v", err), http.StatusBadRequest) -// return -// } -// from = fromInt -// } +// /updates/:ID -// limit := -1 -// if limitStr := r.FormValue("limit"); limitStr != "" { -// limitInt, err := strconv.Atoi(limitStr) -// if err != nil { -// http.Error(w, fmt.Sprintf("failed to parse limit field: %v", err), http.StatusBadRequest) -// return -// } -// limit = limitInt -// } +func webUpdate(srv *Server, w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + sendInvalidMethod(w, r.Method) + return + } -// values, err := srv.GetUpdatesAfter(from, limit) -// if err != nil { -// http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) -// return -// } -// jsonString, err := json.Marshal(GenericDataContainer{values}) -// if err != nil { -// http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) -// return -// } -// fmt.Fprintf(w, "%s", jsonString) -// } + if matched, err := path.Match("/updates/?*", r.URL.Path); err != nil || !matched { + sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid update id"}) + return + } + id, err := strconv.Atoi(path.Base(r.URL.Path)) + if err != nil { + sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid update id: " + err.Error()}) + return + } + var upd DataUpdateFull + if upd, err = srv.store.GetUpdate(id); err != nil { + status := http.StatusInternalServerError + if err == ErrNotFound { + status = http.StatusNotFound + } + sendWebResponse(w, status, webErrorResponse{err.Error()}) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + encoder := NewStatelessEncoder(w) + encoder.Encode(upd) // TODO: handle error +} -// func (srv Server) webGetUpdate(c web.C, w http.ResponseWriter, r *http.Request) { -// const resourceName = "updates" -// id, err := strconv.Atoi(c.URLParams["id"]) -// if err != nil { -// http.Error(w, fmt.Sprintf("invalid id: %s: %v", resourceName, err), http.StatusBadRequest) -// return -// } -// value, err := srv.store.GetUpdate(int(id)) -// if err != nil { -// if err == ErrNotFound { -// http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusNotFound) -// } else { -// http.Error(w, fmt.Sprintf("failed to retrieve %s: %v", resourceName, err), http.StatusInternalServerError) -// } -// return -// } -// jsonString, err := json.Marshal(value) -// if err != nil { -// http.Error(w, fmt.Sprintf("failed to marshal %s: %v", resourceName, err), http.StatusInternalServerError) -// return -// } -// fmt.Fprintf(w, "%s", jsonString) -// } +// /updates + +func webUpdates(srv *Server, w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + webUpdatesGet(srv, w, r) + //case "POST": + // TODO: call webPostUpdate(s) + default: + sendInvalidMethod(w, r.Method) + } +} + +func webUpdatesGet(srv *Server, w http.ResponseWriter, r *http.Request) { + from := 0 + limit := -1 + + q := r.URL.Query() + var err error + + fromStr := q.Get("from") + if fromStr != "" { + if from, err = strconv.Atoi(fromStr); err != nil { + sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid from value: " + err.Error()}) + return + } + } + limitStr := q.Get("limit") + if limitStr != "" { + if limit, err = strconv.Atoi(limitStr); err != nil { + sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid limit value: " + err.Error()}) + return + } + } + + var upds []DataUpdateFull + if upds, err = srv.store.GetUpdatesAfter(from, limit); err != nil { + sendWebResponse(w, http.StatusInternalServerError, webErrorResponse{err.Error()}) + return + } + w.Header().Set("Content-Type", "application/json") // this is actually multiple json documents... + w.WriteHeader(http.StatusOK) + encoder := NewStatelessEncoder(w) + for _, upd := range upds { // TODO: inside container? + encoder.Encode(upd) // TODO: handle error + } +} // func (srv Server) webPostUpdateBulk(c web.C, w http.ResponseWriter, r *http.Request) { // decoder, err := NewStatefulDecoder(r.Body) @@ -225,53 +244,53 @@ func webSources(srv *Server, w http.ResponseWriter, r *http.Request) { // } // } -// /lastupdate +// /lastupdate/:UUID -type webLastUpdateIdResponse struct { - Error string `json:"error,omitempty"` +type webLastUpdateIdForUuidResponse struct { HubUuid string `json:"hub-uuid"` LastUpdateId int `json:"lastupdate"` } -func webLastUpdateId(srv *Server, w http.ResponseWriter, r *http.Request) { +func webLastUpdateIdForUuid(srv *Server, w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { sendInvalidMethod(w, r.Method) return } + if matched, err := path.Match("/lastupdate/?*", r.URL.Path); err != nil || !matched { + sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid uuid"}) + return + } + var err error - resp := webLastUpdateIdResponse{} - resp.HubUuid = srv.GetHubId() - if resp.LastUpdateId, err = srv.store.GetLastUpdateId(); err != nil { - resp.Error = fmt.Sprintf("%v", err) + resp := webLastUpdateIdForUuidResponse{} + resp.HubUuid = path.Base(r.URL.Path) + if resp.LastUpdateId, err = srv.store.GetLastUpdateIdForUuid(resp.HubUuid); err != nil { + sendWebResponse(w, http.StatusInternalServerError, webErrorResponse{err.Error()}) + return } sendWebResponse(w, http.StatusOK, resp) } -// /lastupdate/:UUID +// /lastupdate -type webLastUpdateIdForUuidResponse struct { - Error string `json:"error,omitempty"` +type webLastUpdateIdResponse struct { HubUuid string `json:"hub-uuid"` LastUpdateId int `json:"lastupdate"` } -func webLastUpdateIdForUuid(srv *Server, w http.ResponseWriter, r *http.Request) { +func webLastUpdateId(srv *Server, w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { sendInvalidMethod(w, r.Method) return } - if matched, err := path.Match("/lastupdate/*", r.URL.Path); err != nil || !matched { - sendWebResponse(w, http.StatusBadRequest, webErrorResponse{"invalid uuid"}) - return - } - var err error - resp := webLastUpdateIdForUuidResponse{} - _, resp.HubUuid = path.Split(r.URL.Path) - if resp.LastUpdateId, err = srv.store.GetLastUpdateIdForUuid(resp.HubUuid); err != nil { - resp.Error = fmt.Sprintf("%v", err) + resp := webLastUpdateIdResponse{} + resp.HubUuid = srv.GetHubId() + if resp.LastUpdateId, err = srv.store.GetLastUpdateId(); err != nil { + sendWebResponse(w, http.StatusInternalServerError, webErrorResponse{err.Error()}) + return } sendWebResponse(w, http.StatusOK, resp) } @@ -320,9 +339,10 @@ func webRun(listener *net.TCPListener, srv *Server) (err error) { mux.Handle("/healthz", webHandler{srv, webHealthz}) mux.Handle("/hubs", webHandler{srv, webHubs}) mux.Handle("/sources", webHandler{srv, webSources}) - // mux.Handle("/updates", webHandler{srv, webUpdates}) - mux.Handle("/lastupdate", webHandler{srv, webLastUpdateId}) + mux.Handle("/updates/", webHandler{srv, webUpdate}) + mux.Handle("/updates", webHandler{srv, webUpdates}) mux.Handle("/lastupdate/", webHandler{srv, webLastUpdateIdForUuid}) + mux.Handle("/lastupdate", webHandler{srv, webLastUpdateId}) // mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir( ..staticDir.. )))) mux.Handle("/", webHandler{srv, webNotFound}) |