This commit is contained in:
Max Richter
2025-09-24 22:39:14 +02:00
parent 733ae876b9
commit 3f0d25f935
18 changed files with 2 additions and 145 deletions

View File

@@ -0,0 +1,20 @@
package handler
import (
"encoding/json"
"net/http"
)
type ErrorResponse struct {
Error string `json:"error"`
}
func writeError(w http.ResponseWriter, code int, err error) {
writeJSON(w, code, ErrorResponse{Error: err.Error()})
}
func writeJSON(w http.ResponseWriter, code int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
_ = json.NewEncoder(w).Encode(v)
}

View File

@@ -0,0 +1,104 @@
// Package handler provides the HTTP handler for the marka server
package handler
import (
"errors"
"net/http"
"time"
"git.max-richter.dev/max/marka/parser"
"git.max-richter.dev/max/marka/server-new/internal/adapters"
)
type ResponseItem struct {
Name string `json:"name"`
Content any `json:"content,omitempty"`
Type string `json:"type,omitempty"`
IsDir bool `json:"isDir"`
Size int64 `json:"size,omitempty"`
ModTime time.Time `json:"modTime"`
}
type Handler struct {
adapter adapters.FileAdapter
}
func (h *Handler) get(w http.ResponseWriter, target string) {
fsEntry, err := h.adapter.Read(target)
if err != nil {
writeError(w, 500, err)
return
}
if fsEntry.File != nil {
if fsEntry.File.Content != nil && fsEntry.File.Type == "application/markdown" {
data, err := parser.ParseFile(string(fsEntry.File.Content))
if err != nil {
writeError(w, 500, err)
return
}
res := ResponseItem{
Name: fsEntry.File.Name,
Type: fsEntry.File.Type,
Content: data,
IsDir: false,
Size: int64(len(fsEntry.File.Content)),
ModTime: fsEntry.File.ModTime,
}
writeJSON(w, 200, res)
return
}
res := ResponseItem{
Name: fsEntry.File.Name,
Content: fsEntry.File.Content,
Type: fsEntry.File.Type,
IsDir: false,
Size: int64(len(fsEntry.File.Content)),
ModTime: fsEntry.File.ModTime,
}
writeJSON(w, 200, res)
return
}
if fsEntry.Dir != nil {
res := ResponseItem{
Name: fsEntry.Dir.Name,
Content: fsEntry.Dir.Files,
IsDir: true,
ModTime: fsEntry.Dir.ModTime,
}
writeJSON(w, 200, res)
return
}
}
func (h *Handler) post(w http.ResponseWriter, target string) {
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reqPath := r.URL.Path
if reqPath == "" {
reqPath = "/"
}
target := cleanURLLike(reqPath)
switch r.Method {
case http.MethodGet:
h.get(w, target)
case http.MethodPost:
h.post(w, target)
default:
writeError(w, http.StatusMethodNotAllowed, errors.New("method not allowed"))
}
}
func NewHandler(adapter adapters.FileAdapter) http.Handler {
return &Handler{
adapter: adapter,
}
}

View File

@@ -0,0 +1,24 @@
package handler
import "strings"
func cleanURLLike(p string) string {
p = strings.TrimSpace(p)
if p == "" || p == "/" {
return "/"
}
parts := []string{}
for seg := range strings.SplitSeq(p, "/") {
switch seg {
case "", ".":
continue
case "..":
if len(parts) > 0 {
parts = parts[:len(parts)-1]
}
default:
parts = append(parts, seg)
}
}
return "/" + strings.Join(parts, "/")
}