impl entities except for PATCH
This commit is contained in:
150
.view/json.go
Normal file
150
.view/json.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package view
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"local/dndex/config"
|
||||
"local/dndex/storage"
|
||||
"local/gziphttp"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
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.RateLimitedGraph) http.Handler {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
routes := []struct {
|
||||
path string
|
||||
foo func(g storage.RateLimitedGraph, w http.ResponseWriter, r *http.Request) error
|
||||
noauth bool
|
||||
}{
|
||||
{
|
||||
path: "/port",
|
||||
foo: port,
|
||||
},
|
||||
{
|
||||
path: "/who",
|
||||
foo: who,
|
||||
},
|
||||
{
|
||||
path: "/register",
|
||||
foo: register,
|
||||
noauth: true,
|
||||
},
|
||||
{
|
||||
path: config.New().FilePrefix + "/",
|
||||
foo: files,
|
||||
},
|
||||
{
|
||||
path: "/version",
|
||||
foo: version,
|
||||
noauth: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
foo := route.foo
|
||||
auth := !route.noauth
|
||||
mux.HandleFunc(route.path, func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := delay(w, r); err != nil {
|
||||
http.Error(w, err.Error(), 499)
|
||||
}
|
||||
|
||||
if auth {
|
||||
if err := Auth(g, w, r); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := foo(g, w, r); err != nil {
|
||||
status := http.StatusInternalServerError
|
||||
if strings.Contains(err.Error(), "collision") {
|
||||
status = http.StatusConflict
|
||||
}
|
||||
b, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
http.Error(w, string(b), status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return rateLimited(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if gziphttp.Can(r) {
|
||||
gz := gziphttp.New(w)
|
||||
defer gz.Close()
|
||||
w = gz
|
||||
}
|
||||
r.Body = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{
|
||||
Reader: io.LimitReader(r.Body, config.New().MaxFileSize),
|
||||
Closer: r.Body,
|
||||
}
|
||||
mux.ServeHTTP(w, r)
|
||||
}))
|
||||
}
|
||||
|
||||
func rateLimited(foo http.HandlerFunc) http.HandlerFunc {
|
||||
sysRPS := config.New().SysRPS
|
||||
limiter := rate.NewLimiter(rate.Limit(sysRPS), sysRPS)
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := limiter.Wait(r.Context()); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusTooManyRequests)
|
||||
}
|
||||
foo(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func getAuthNamespace(r *http.Request) (string, error) {
|
||||
namespace, err := getNamespace(r)
|
||||
return strings.Join([]string{namespace, AuthKey}, "."), err
|
||||
}
|
||||
|
||||
func getNamespace(r *http.Request) (string, error) {
|
||||
if strings.HasPrefix(r.URL.Path, config.New().FilePrefix) {
|
||||
path := strings.TrimPrefix(r.URL.Path, config.New().FilePrefix+"/")
|
||||
if path == r.URL.Path {
|
||||
return "", errors.New("no namespace on files")
|
||||
}
|
||||
path = strings.Split(path, "/")[0]
|
||||
if path == "" {
|
||||
return "", errors.New("empty namespace on files")
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
namespace := r.URL.Query().Get("namespace")
|
||||
if len(namespace) == 0 {
|
||||
return "", errors.New("no namespace found")
|
||||
}
|
||||
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})
|
||||
}
|
||||
|
||||
func delay(w http.ResponseWriter, r *http.Request) error {
|
||||
select {
|
||||
case <-time.After(config.New().Delay):
|
||||
case <-r.Context().Done():
|
||||
return errors.New("client DCd")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user