From 21fa9630853472b929a275abf58996dc6f089d5b Mon Sep 17 00:00:00 2001 From: breel Date: Thu, 30 Jul 2020 16:20:51 -0600 Subject: [PATCH] Actually use rate limited storage, add /version with -dirty --- deploy.sh | 20 ++++++++++++++++++-- main.go | 5 ++++- view/auth.go | 10 +++++----- view/auth_test.go | 2 +- view/files.go | 2 +- view/files_test.go | 2 +- view/json.go | 19 ++++++++++++++++--- view/json_test.go | 35 +++++++++++++++++++++++++++++++++++ view/port.go | 6 +++--- view/port_test.go | 2 +- view/register.go | 4 ++-- view/register_test.go | 2 +- view/who.go | 16 ++++++++-------- view/who_test.go | 4 ++-- 14 files changed, 98 insertions(+), 31 deletions(-) diff --git a/deploy.sh b/deploy.sh index 7bd35b1..1fcf968 100644 --- a/deploy.sh +++ b/deploy.sh @@ -7,21 +7,37 @@ function main() { if [ -z "$NOTEST" ]; then go test ./... fi - GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=0 go build -o $exec -a -installsuffix cgo + GOARCH=arm GOARM=5 gobuild $exec for authed in dndex dndex-auth; do scp ./public/swagger/* zach@tickle.lan:./$authed/files/swagger/ scp $exec zach@tickle.lan:./$authed/dndex.new ssh zach@tickle.lan bash -c "true; while [ -e ./$authed/dndex.new ]; do printf '.'; sleep 3; done; echo" done & wait - GOOS=linux CGO_ENABLED=0 go build -o $exec -a -installsuffix cgo + gobuild $exec scp $exec bel@remote.blapointe.com:/home/bel/services/bin/dndex.new + ssh bel@remote.blapointe.com bash -c 'true; md5sum ./services/bin/dndex*; while [ -e ./services/bin/dndex.new ]; do printf "."; sleep 3; done; md5sum ./services/bin/dndex*' rm $exec if [ -n "$BIG" ]; then big fi } +function gobuild() { + GOOS=linux CGO_ENABLED=0 go build \ + -o $1 \ + -a \ + -installsuffix cgo \ + -ldflags "-s -w -X main.GitCommit=$( + ( + git rev-list -1 HEAD + if git diff | grep . > /dev/null; then + echo "-dirty" + fi + ) | tr -d '\n' + )" +} + function big() { pushd ./public/vue/dndex-ui git checkout master diff --git a/main.go b/main.go index c463224..f07d20c 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,13 @@ import ( "log" ) +var GitCommit string + func main() { c := config.New() log.Println(c) - g := storage.NewGraph() + g := storage.NewRateLimitedGraph() + view.GitCommit = GitCommit if err := view.JSON(g); err != nil { panic(err) } diff --git a/view/auth.go b/view/auth.go index d1a549e..e4f3136 100644 --- a/view/auth.go +++ b/view/auth.go @@ -24,7 +24,7 @@ const ( UserKey = "DnDex-User" ) -func Auth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func Auth(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { if !config.New().Auth { return nil } @@ -35,7 +35,7 @@ func Auth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { return nil } -func auth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func auth(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { if isPublic(g, r) { return nil } @@ -45,7 +45,7 @@ func auth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { return checkAuth(g, w, r) } -func isPublic(g storage.Graph, r *http.Request) bool { +func isPublic(g storage.RateLimitedGraph, r *http.Request) bool { namespace, err := getAuthNamespace(r) if err != nil { return false @@ -65,7 +65,7 @@ func hasAuth(r *http.Request) bool { return err == nil } -func checkAuth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func checkAuth(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getAuthNamespace(r) if err != nil { return err @@ -85,7 +85,7 @@ func checkAuth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { return nil } -func requestAuth(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func requestAuth(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getAuthNamespace(r) if err != nil { http.Error(w, `{"error": "namespace required"}`, http.StatusBadRequest) diff --git a/view/auth_test.go b/view/auth_test.go index 32aea13..6443dd1 100644 --- a/view/auth_test.go +++ b/view/auth_test.go @@ -28,7 +28,7 @@ func TestAuth(t *testing.T) { os.Setenv("AUTH", "true") defer os.Setenv("AUTH", "false") - g := storage.NewGraph() + g := storage.NewRateLimitedGraph() handler := jsonHandler(g) if err := g.Insert(context.TODO(), "col."+AuthKey, entity.One{Name: UserKey, Title: "password"}); err != nil { diff --git a/view/files.go b/view/files.go index e676610..c222792 100644 --- a/view/files.go +++ b/view/files.go @@ -16,7 +16,7 @@ import ( "strings" ) -func files(_ storage.Graph, w http.ResponseWriter, r *http.Request) error { +func files(_ storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getNamespace(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/view/files_test.go b/view/files_test.go index f5b9a44..ef353b9 100644 --- a/view/files_test.go +++ b/view/files_test.go @@ -36,7 +36,7 @@ func TestFiles(t *testing.T) { os.Setenv("FILEROOT", d) t.Logf("config: %+v", config.New()) - handler := jsonHandler(storage.Graph{}) + handler := jsonHandler(storage.RateLimitedGraph{}) prefix := path.Join(config.New().FilePrefix, "col") diff --git a/view/json.go b/view/json.go index f2534b3..14179cc 100644 --- a/view/json.go +++ b/view/json.go @@ -15,19 +15,21 @@ import ( "golang.org/x/time/rate" ) -func JSON(g storage.Graph) error { +var GitCommit string + +func JSON(g storage.RateLimitedGraph) error { port := config.New().Port log.Println("listening on", port) err := http.ListenAndServe(fmt.Sprintf(":%d", port), jsonHandler(g)) return err } -func jsonHandler(g storage.Graph) http.Handler { +func jsonHandler(g storage.RateLimitedGraph) http.Handler { mux := http.NewServeMux() routes := []struct { path string - foo func(g storage.Graph, w http.ResponseWriter, r *http.Request) error + foo func(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error noauth bool }{ { @@ -47,6 +49,11 @@ func jsonHandler(g storage.Graph) http.Handler { path: config.New().FilePrefix + "/", foo: files, }, + { + path: "/version", + foo: version, + noauth: true, + }, } for _, route := range routes { @@ -121,3 +128,9 @@ func getNamespace(r *http.Request) (string, error) { } return namespace, nil } + +func version(_ storage.RateLimitedGraph, w http.ResponseWriter, _ *http.Request) error { + enc := json.NewEncoder(w) + enc.SetIndent("", " ") + return enc.Encode(map[string]string{"version": GitCommit}) +} diff --git a/view/json_test.go b/view/json_test.go index a1d9300..595b8b9 100644 --- a/view/json_test.go +++ b/view/json_test.go @@ -2,7 +2,9 @@ package view import ( "context" + "encoding/json" "local/dndex/config" + "local/dndex/storage" "net/http" "net/http/httptest" "net/url" @@ -90,3 +92,36 @@ func TestRateLimited(t *testing.T) { t.Fatal(ok, tooMany) } } + +func TestVersion(t *testing.T) { + t.Run("no version set", func(t *testing.T) { + w := httptest.NewRecorder() + if err := version(storage.RateLimitedGraph{}, w, nil); err != nil { + t.Fatal(err) + } + var resp struct { + Version string `json:"version"` + } + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatal(err) + } else if resp.Version != "" { + t.Fatal(resp) + } + }) + + t.Run("version set", func(t *testing.T) { + GitCommit = "my-git-commit" + w := httptest.NewRecorder() + if err := version(storage.RateLimitedGraph{}, w, nil); err != nil { + t.Fatal(err) + } + var resp struct { + Version string `json:"version"` + } + if err := json.NewDecoder(w.Body).Decode(&resp); err != nil { + t.Fatal(err) + } else if resp.Version != "my-git-commit" { + t.Fatal(resp) + } + }) +} diff --git a/view/port.go b/view/port.go index ce6c9c3..a2b9be1 100644 --- a/view/port.go +++ b/view/port.go @@ -10,7 +10,7 @@ import ( "github.com/buger/jsonparser" ) -func port(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func port(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { switch r.Method { case http.MethodGet: return portGet(g, w, r) @@ -22,7 +22,7 @@ func port(g storage.Graph, w http.ResponseWriter, r *http.Request) error { } } -func portGet(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func portGet(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getNamespace(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -37,7 +37,7 @@ func portGet(g storage.Graph, w http.ResponseWriter, r *http.Request) error { return json.NewEncoder(w).Encode(map[string]interface{}{namespace: ones}) } -func portPost(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func portPost(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getNamespace(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/view/port_test.go b/view/port_test.go index b5349f7..7fa8980 100644 --- a/view/port_test.go +++ b/view/port_test.go @@ -25,7 +25,7 @@ func TestPort(t *testing.T) { os.Setenv("DBURI", f.Name()) os.Setenv("AUTH", "false") - g := storage.NewGraph() + g := storage.NewRateLimitedGraph() reset := func() { if err := g.Delete(context.TODO(), "col", map[string]string{}); err != nil { t.Fatal(err) diff --git a/view/register.go b/view/register.go index eba5ec0..aef1f48 100644 --- a/view/register.go +++ b/view/register.go @@ -7,7 +7,7 @@ import ( "net/http" ) -func register(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func register(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { switch r.Method { case http.MethodPost: return registerPost(g, w, r) @@ -17,7 +17,7 @@ func register(g storage.Graph, w http.ResponseWriter, r *http.Request) error { } } -func registerPost(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func registerPost(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getAuthNamespace(r) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) diff --git a/view/register_test.go b/view/register_test.go index d77a7df..e64db0c 100644 --- a/view/register_test.go +++ b/view/register_test.go @@ -26,7 +26,7 @@ func TestRegister(t *testing.T) { os.Setenv("AUTH", "true") defer os.Setenv("AUTH", "false") - g := storage.NewGraph() + g := storage.NewRateLimitedGraph() handler := jsonHandler(g) t.Run("register: wrong method", func(t *testing.T) { diff --git a/view/who.go b/view/who.go index ce8b255..fd22c92 100644 --- a/view/who.go +++ b/view/who.go @@ -25,7 +25,7 @@ const ( queryOrder = "order" ) -func who(g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func who(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { namespace, err := getNamespace(r) if err != nil { http.NotFound(w, r) @@ -51,7 +51,7 @@ func who(g storage.Graph, w http.ResponseWriter, r *http.Request) error { } } -func whoGet(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoGet(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getCleanID(r) if err != nil { return whoTrace(namespace, g, w, r) @@ -108,7 +108,7 @@ func whoGet(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Re return err } -func whoPut(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoPut(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getID(r) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -151,7 +151,7 @@ func whoPut(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Re return whoGet(namespace, g, w, r) } -func whoPost(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoPost(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getID(r) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -174,7 +174,7 @@ func whoPost(namespace string, g storage.Graph, w http.ResponseWriter, r *http.R return whoGet(namespace, g, w, r) } -func whoDelete(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoDelete(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getCleanID(r) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -193,7 +193,7 @@ func whoDelete(namespace string, g storage.Graph, w http.ResponseWriter, r *http return json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) } -func whoDeleteConnections(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoDeleteConnections(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getID(r) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -218,7 +218,7 @@ func whoDeleteConnections(namespace string, g storage.Graph, w http.ResponseWrit return whoGet(namespace, g, w, r) } -func whoPatch(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoPatch(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { id, err := getID(r) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -246,7 +246,7 @@ func whoPatch(namespace string, g storage.Graph, w http.ResponseWriter, r *http. return whoGet(namespace, g, w, r) } -func whoTrace(namespace string, g storage.Graph, w http.ResponseWriter, r *http.Request) error { +func whoTrace(namespace string, g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error { ones, err := g.ListCaseInsensitive(r.Context(), namespace) if err != nil { return err diff --git a/view/who_test.go b/view/who_test.go index 0a6e852..7a3df51 100644 --- a/view/who_test.go +++ b/view/who_test.go @@ -36,7 +36,7 @@ func TestWho(t *testing.T) { t.Logf("config: %+v", config.New()) - g := storage.NewGraph() + g := storage.NewRateLimitedGraph() ones := fillDB(t, g) want := ones[len(ones)-1] @@ -632,7 +632,7 @@ func TestWho(t *testing.T) { }) } -func fillDB(t *testing.T, g storage.Graph) []entity.One { +func fillDB(t *testing.T, g storage.RateLimitedGraph) []entity.One { ones := make([]entity.One, 13) for i := range ones { ones[i] = randomOne()