This commit is contained in:
205
main.go
Normal file
205
main.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"git.tornberg.me/go-persist/pkg/storage"
|
||||
)
|
||||
|
||||
type Folder struct {
|
||||
Id string
|
||||
parent *Folder
|
||||
Storage storage.Storage
|
||||
Children map[string]*Folder
|
||||
}
|
||||
|
||||
func (f *Folder) GetId() string {
|
||||
return f.Id
|
||||
}
|
||||
func (f *Folder) GetPathIds() []string {
|
||||
p := f.parent
|
||||
ids := make([]string, 0)
|
||||
ids = append(ids, f.GetId())
|
||||
for p != nil {
|
||||
ids = append(ids, p.GetId())
|
||||
p = p.parent
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
type App struct {
|
||||
Root *Folder
|
||||
spawnStorage func(path []string) (storage.Storage, error)
|
||||
}
|
||||
|
||||
func (app *App) GetFolder(pth []string) (*Folder, bool) {
|
||||
current := app.Root
|
||||
for _, id := range pth {
|
||||
if child, exists := current.Children[id]; exists {
|
||||
current = child
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
return current, true
|
||||
}
|
||||
|
||||
func (app *App) GetOrSpawn(pth []string) (*Folder, error) {
|
||||
current := app.Root
|
||||
level := []string{}
|
||||
for _, id := range pth {
|
||||
if child, exists := current.Children[id]; exists {
|
||||
current = child
|
||||
level = append(level, id)
|
||||
} else {
|
||||
level = append(level, id)
|
||||
s, err := app.spawnStorage(level)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
child := &Folder{
|
||||
Id: id,
|
||||
parent: current,
|
||||
Storage: s,
|
||||
Children: make(map[string]*Folder),
|
||||
}
|
||||
current.Children[id] = child
|
||||
current = child
|
||||
}
|
||||
}
|
||||
return current, nil
|
||||
}
|
||||
|
||||
func (app *App) AddFolder(id string, parent *Folder) (*Folder, error) {
|
||||
strg, err := app.spawnStorage(parent.GetPathIds())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
folder := &Folder{
|
||||
Id: id,
|
||||
parent: parent,
|
||||
Storage: strg,
|
||||
Children: make(map[string]*Folder),
|
||||
}
|
||||
if parent != nil {
|
||||
parent.Children[id] = folder
|
||||
}
|
||||
return folder, nil
|
||||
}
|
||||
|
||||
func GetPathAndFileFromUrl(u *url.URL) ([]string, string) {
|
||||
if u == nil {
|
||||
return []string{}, ""
|
||||
}
|
||||
parts := strings.Split(u.Path, "/")[1:]
|
||||
fileName := parts[len(parts)-1]
|
||||
return parts[:len(parts)-1], fileName
|
||||
}
|
||||
|
||||
func esimateMimeType(filename string) string {
|
||||
if strings.HasSuffix(filename, ".jpg") {
|
||||
return "image/jpeg"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".png") {
|
||||
return "image/png"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".gif") {
|
||||
return "image/gif"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".bmp") {
|
||||
return "image/bmp"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".webp") {
|
||||
return "image/webp"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".json") {
|
||||
return "application/json"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".html") || strings.HasSuffix(filename, ".htm") {
|
||||
return "text/html"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".css") {
|
||||
return "text/css"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".txt") {
|
||||
return "text/plain"
|
||||
}
|
||||
return "application/octet-stream"
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize the application
|
||||
rootDir, err := storage.NewDiskStorage([]string{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
app := &App{
|
||||
Root: &Folder{
|
||||
Id: "data",
|
||||
Storage: rootDir,
|
||||
Children: make(map[string]*Folder),
|
||||
},
|
||||
spawnStorage: func(path []string) (storage.Storage, error) {
|
||||
if path[0] == "tmp" {
|
||||
return storage.NewMemoryStorage(path)
|
||||
}
|
||||
return storage.NewDiskStorage(path)
|
||||
},
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
pth, fileName := GetPathAndFileFromUrl(r.URL)
|
||||
log.Printf("Request path parts: %+v, fileName:%s", pth, fileName)
|
||||
folder, err := app.GetOrSpawn(pth)
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Printf("Retrieved folder: %+v, exists: %v", folder)
|
||||
if fileName == "" {
|
||||
content, err := folder.Storage.List("")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(content)
|
||||
} else {
|
||||
if r.Method == "GET" {
|
||||
content, err := folder.Storage.Get(fileName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", esimateMimeType(fileName))
|
||||
w.Header().Set("Cache-Control", "public; max-age=60")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename=\""+fileName+"\"")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(content)
|
||||
} else {
|
||||
defer r.Body.Close()
|
||||
data, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
}
|
||||
folder.Storage.Put(fileName, data)
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
if err := http.ListenAndServe(":8080", mux); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user