almost there

master
Bel LaPointe 2022-02-09 12:30:12 -07:00
parent c4b63825aa
commit f41b34aa5c
3 changed files with 142 additions and 45 deletions

View File

@ -10,6 +10,7 @@ import (
"local/router" "local/router"
"local/simpleserve/simpleserve" "local/simpleserve/simpleserve"
"net/http" "net/http"
"net/url"
"os" "os"
"path" "path"
"regexp" "regexp"
@ -72,26 +73,8 @@ func (server *Server) tryCatchHttpHandler(handler func(http.ResponseWriter, *htt
} }
func (server *Server) apiV0TreeHandler(w http.ResponseWriter, r *http.Request) error { func (server *Server) apiV0TreeHandler(w http.ResponseWriter, r *http.Request) error {
_, pretty := r.URL.Query()["pretty"]
if pretty {
return server.apiV0TreePrettyHandler(w, r)
}
return server.apiV0TreePlainHandler(w, r)
}
func (server *Server) apiV0TreePrettyHandler(w http.ResponseWriter, r *http.Request) error {
tree := server.tree() tree := server.tree()
//branches, err := tree.GetPretty() branches, err := tree.GetRootMeta()
branches, err := tree.GetRoot()
if err != nil {
return err
}
return json.NewEncoder(w).Encode(branches)
}
func (server *Server) apiV0TreePlainHandler(w http.ResponseWriter, r *http.Request) error {
tree := server.tree()
branches, err := tree.GetRoot()
if err != nil { if err != nil {
return err return err
} }
@ -106,7 +89,8 @@ func ensureAndWrite(p string, b []byte) error {
} }
func (server *Server) apiV0MediaHandler(w http.ResponseWriter, r *http.Request) error { func (server *Server) apiV0MediaHandler(w http.ResponseWriter, r *http.Request) error {
id, err := server.postContentHandler(path.Dir(server.diskMediaPath("id")), w, r) id := uuid.New().String()
id, err := server.postContentHandler(server.diskMediaPath(id), w, r)
if err != nil { if err != nil {
return err return err
} }
@ -157,11 +141,10 @@ func (server *Server) getContentHandler(filePath string, w http.ResponseWriter,
return nil return nil
} }
func (server *Server) postContentHandler(fileDir string, w http.ResponseWriter, r *http.Request) (string, error) { func (server *Server) postContentHandler(filePath string, w http.ResponseWriter, r *http.Request) (string, error) {
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
return "", errors.New("not found") return "", errors.New("not found")
} }
id := strings.Split(uuid.New().String(), "-")[0]
if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") { if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
kb := int64(1 << 10) kb := int64(1 << 10)
mb := kb << 10 mb := kb << 10
@ -179,7 +162,7 @@ func (server *Server) postContentHandler(fileDir string, w http.ResponseWriter,
if h, ok := infos[0].Header["Content-Type"]; ok { if h, ok := infos[0].Header["Content-Type"]; ok {
ext = path.Base(h[0]) ext = path.Base(h[0])
} }
id += "." + ext filePath += "." + ext
f, err := infos[0].Open() f, err := infos[0].Open()
if err != nil { if err != nil {
return "", err return "", err
@ -193,8 +176,7 @@ func (server *Server) postContentHandler(fileDir string, w http.ResponseWriter,
} }
return "", fmt.Errorf("parse form: %+v", r.PostForm) return "", fmt.Errorf("parse form: %+v", r.PostForm)
} }
filePath := path.Join(fileDir, id) return filePath, server.putContentHandler(filePath, w, r)
return id, server.putContentHandler(filePath, w, r)
} }
func (server *Server) putContentHandler(filePath string, w http.ResponseWriter, r *http.Request) error { func (server *Server) putContentHandler(filePath string, w http.ResponseWriter, r *http.Request) error {
@ -210,8 +192,8 @@ func (server *Server) rootHandler(w http.ResponseWriter, r *http.Request) error
return server.getContentHandler(path.Join(server.root, "index.html"), w, r) return server.getContentHandler(path.Join(server.root, "index.html"), w, r)
} }
func (server *Server) tree() *Tree { func (server *Server) tree() Tree {
return nil return NewTree(path.Join(server.root, "files"))
} }
func (server *Server) diskMediaPath(id string) string { func (server *Server) diskMediaPath(id string) string {
@ -223,7 +205,80 @@ func (server *Server) apiV0FilesHandler(w http.ResponseWriter, r *http.Request)
} }
func (server *Server) apiV0FilesIDHandler(w http.ResponseWriter, r *http.Request) error { func (server *Server) apiV0FilesIDHandler(w http.ResponseWriter, r *http.Request) error {
return errors.New("not impl") switch r.Method {
case http.MethodGet:
return server.apiV0FilesIDGetHandler(w, r)
case http.MethodPut:
return server.apiV0FilesIDPutHandler(w, r)
case http.MethodDelete:
return server.apiV0FilesIDDelHandler(w, r)
}
http.NotFound(w, r)
return nil
}
func (server *Server) apiV0FilesIDGetHandler(w http.ResponseWriter, r *http.Request) error {
id := server.fileId(r)
leaf, err := server.tree().Get(id)
if os.IsNotExist(err) {
http.NotFound(w, r)
return nil
} else if err != nil {
return err
}
w.Header().Set("Title", leaf.Title)
_, err = w.Write([]byte(leaf.Content))
return err
}
func (server *Server) apiV0FilesIDDelHandler(w http.ResponseWriter, r *http.Request) error {
id := server.fileId(r)
leaf, err := server.tree().Get(id)
if os.IsNotExist(err) {
return nil
} else if err != nil {
return err
}
leaf.Deleted = true
return server.tree().Put(id, leaf)
}
func (server *Server) urlFileId(id []string) string {
if len(id) == 0 {
return ""
}
for i := 1; i < len(id); i++ {
id[0] = strings.Join([]string{id[0], url.PathEscape(id[i])}, "/")
}
return id[0]
}
func (server *Server) fileId(r *http.Request) []string {
return strings.Split(strings.TrimPrefix(r.URL.Path, "/api/v0/files/"), "/")
}
func (server *Server) apiV0FilesIDPutHandler(w http.ResponseWriter, r *http.Request) error {
id := server.fileId(r)
leaf, err := server.tree().Get(id)
if os.IsNotExist(err) {
} else if err != nil {
return err
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
leaf.Content = string(b)
leaf.Title = r.Header.Get("Title")
leaf.Deleted = false
return server.tree().Put(id, leaf)
} }
func (server *Server) apiV0SearchHandler(w http.ResponseWriter, r *http.Request) error { func (server *Server) apiV0SearchHandler(w http.ResponseWriter, r *http.Request) error {
@ -245,5 +300,21 @@ func (server *Server) apiV0SearchHandler(w http.ResponseWriter, r *http.Request)
w.Write([]byte(`[]`)) w.Write([]byte(`[]`))
return nil return nil
} }
return errors.New("not impl") tree, err := server.tree().GetRoot()
if err != nil {
return err
}
result := []string{}
if err := tree.ForEach(func(id []string, leaf Leaf) error {
for _, pattern := range patterns {
if !pattern.MatchString(leaf.Content) && !pattern.MatchString(fmt.Sprint(id)) {
return nil
}
}
result = append(result, server.urlFileId(id))
return nil
}); err != nil {
return err
}
return json.NewEncoder(w).Encode(result)
} }

View File

@ -1,6 +1,13 @@
package main package main
/* import (
"net/http"
"net/http/httptest"
"path"
"strings"
"testing"
)
func TestServerRoutes(t *testing.T) { func TestServerRoutes(t *testing.T) {
server := NewServer(t.TempDir()) server := NewServer(t.TempDir())
if err := server.Routes(); err != nil { if err := server.Routes(); err != nil {
@ -11,15 +18,16 @@ func TestServerRoutes(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
ensureAndWrite(server.diskMediaPath("delid"), []byte("hi")) ensureAndWrite(server.diskMediaPath("delid"), []byte("hi"))
ensureAndWrite(server.diskFilePath("getfid"), []byte("getfid body"))
ensureAndWrite(server.diskFilePath("putfid"), []byte("initial putfid body")) tree := server.tree()
ensureAndWrite(server.diskFilePath("delfid"), []byte("delfid body")) if err := tree.Put([]string{"getfid"}, Leaf{Title: "", Content: "getfid body"}); err != nil {
ensureAndWrite(path.Join(server.root, "index.html"), []byte("mom"))
if err := server.tree().Put("putfid", Branch{}); err != nil {
t.Fatal(err) t.Fatal(err)
} }
server.tree().Put("delfid", Branch{Title: "delfid title"}) tree.Put([]string{"putfid"}, Leaf{Title: "putfid title", Content: "initial putfid body"})
server.tree().Put("getfid", Branch{Title: "getfid title"}) tree.Put([]string{"delfid"}, Leaf{Title: "delfid title", Content: "delfid body"})
t.Log(tree.GetRoot())
ensureAndWrite(path.Join(server.root, "index.html"), []byte("mom"))
cases := map[string]struct { cases := map[string]struct {
path string path string
@ -37,15 +45,10 @@ func TestServerRoutes(t *testing.T) {
method: http.MethodGet, method: http.MethodGet,
want: `["getfid"]`, want: `["getfid"]`,
}, },
"v0: tree: get pretty": {
path: "/api/v0/tree?pretty",
method: http.MethodGet,
want: `"getfid":{"Children":{`,
},
"v0: tree: get": { "v0: tree: get": {
path: "/api/v0/tree", path: "/api/v0/tree",
method: http.MethodGet, method: http.MethodGet,
want: `":{"Title":"getfid title",`, want: `"Title":"Untitled",`,
}, },
"v0: media: post": { "v0: media: post": {
path: "/api/v0/media", path: "/api/v0/media",
@ -101,6 +104,7 @@ func TestServerRoutes(t *testing.T) {
} }
} }
/*
func TestServerPutTreeGetFile(t *testing.T) { func TestServerPutTreeGetFile(t *testing.T) {
server := NewServer(t.TempDir()) server := NewServer(t.TempDir())
if err := server.Routes(); err != nil { if err := server.Routes(); err != nil {

View File

@ -9,8 +9,8 @@ import (
) )
type Branch struct { type Branch struct {
Leaf Leaf Leaf Leaf `json:"Leaf,omitempty"`
Branches map[string]Branch Branches map[string]Branch `json:"Branches,omitempty"`
} }
func (branch Branch) IsZero() bool { func (branch Branch) IsZero() bool {
@ -29,6 +29,24 @@ func (branch Branch) Find(baseId string) ([]string, bool) {
return nil, false return nil, false
} }
func (branch Branch) ForEach(foo func([]string, Leaf) error) error {
return branch.forEach([]string{}, foo)
}
func (branch Branch) forEach(preid []string, foo func([]string, Leaf) error) error {
if err := foo(preid, branch.Leaf); err != nil {
return err
}
postid := append(preid, "")
for id, child := range branch.Branches {
postid[len(postid)-1] = id
if err := child.forEach(postid, foo); err != nil {
return err
}
}
return nil
}
type Leaf struct { type Leaf struct {
Title string Title string
Deleted bool Deleted bool
@ -39,6 +57,9 @@ func (base Leaf) Merge(updated Leaf) Leaf {
if updated.Title != "" { if updated.Title != "" {
base.Title = updated.Title base.Title = updated.Title
} }
if base.Title == "" {
base.Title = "Untitled"
}
base.Deleted = updated.Deleted base.Deleted = updated.Deleted
base.Content = updated.Content base.Content = updated.Content
return base return base
@ -55,6 +76,7 @@ func NewTree(root string) Tree {
func (tree Tree) WithRoot(root string) Tree { func (tree Tree) WithRoot(root string) Tree {
tree.root = root tree.root = root
tree.cachedRoot = Branch{}
return tree return tree
} }