package main
import (
"encoding/json"
"errors"
"io"
"net/http"
"os"
"path"
"strings"
"github.com/labstack/echo/v4"
"github.com/nyudlts/bytemath"
)
// GET /
func MainHandle(c echo.Context) error {
m := map[string]any{
"cod": 200,
"id": "JGoServer",
"version": "1.0-dev",
}
ents, err := os.ReadDir("storage")
if errors.Is(err, os.ErrNotExist) {
err2 := os.Mkdir("storage", 0775)
if err2 != nil {
m["cod"] = 500
m["dirs"] = nil // This is what we were trying to populate
m["err"] = err2.Error()
m["cause"] = err.Error()
return c.JSON(m["cod"].(int), m)
}
} else if err != nil {
m["cod"] = 500
m["dirs"] = nil // This is what we were trying to populate
m["err"] = err.Error()
return c.JSON(m["cod"].(int), m)
}
dirs := []string{}
for _, e := range ents {
if e.IsDir() {
dirs = append(dirs, e.Name())
}
}
m["dirs"] = dirs
return c.JSON(m["cod"].(int), m)
}
// Sanitizes directory name so it's a little safe
func CleanDirName(raw string) string {
return strings.ToLower(strings.Trim(raw, " .\r\n\t"))
}
// GET /dir?q=
func GetDirHandle(c echo.Context) error {
m := map[string]any{
"cod": 200,
}
target := CleanDirName(c.QueryParam("q")) // Directory to list
if len(target) == 0 || target == "" {
// Nothing todo?
m["cod"] = http.StatusBadRequest
m["q"] = c.QueryParam("q")
return c.JSON(m["cod"].(int), m)
}
// Verify the directory at least exists
_, err := os.Stat(path.Join("storage", target))
if errors.Is(err, os.ErrNotExist) {
err2 := os.MkdirAll(path.Join("storage", target), 0775)
if err2 != nil {
m["cod"] = 500
m["files"] = nil
m["dirs"] = nil
m["err"] = err2.Error()
m["cause"] = err.Error()
return c.JSON(m["cod"].(int), m)
}
} else if err != nil {
m["cod"] = 500
m["files"] = nil
m["dirs"] = nil
m["err"] = err.Error()
return c.JSON(m["cod"].(int), m)
}
// Scan the dirs looking for files (won't include ones that start with .)
var scanDir func(string) ([]string, []string, error)
scanDir = func(dir string) ([]string, []string, error) {
ents, err := os.ReadDir(dir)
if err != nil {
return nil, nil, err
}
fs := []string{}
ds := []string{}
for _, e := range ents {
if strings.HasPrefix(e.Name(), ".") { // Keep hidden files/dirs hidden
continue
}
if e.IsDir() {
ds = append(ds, path.Join(dir, e.Name()))
f, d, err := scanDir(path.Join(dir, e.Name()))
if err != nil {
return nil, nil, err
}
fs = append(fs, f...)
ds = append(ds, d...)
} else {
fs = append(fs, path.Join(dir, e.Name()))
}
}
return fs, ds, nil
}
files, dirs, err2 := scanDir(path.Join("storage", target))
if err2 != nil {
m["cod"] = 500
m["files"] = nil
m["dirs"] = nil
m["err"] = err.Error()
return c.JSON(m["cod"].(int), m)
}
m["files"] = files
m["dirs"] = dirs
return c.JSON(m["cod"].(int), m)
}
// POST/PUT /up?q=
func UploadJData(c echo.Context) error {
// e.g. test/dir1/pkt001.json
targetDir := CleanDirName(path.Dir(c.QueryParam("q"))) // e.g. test/dir1
targetName := path.Base(c.QueryParam("q")) // e.g. pkt001.json
_, err := os.Stat(path.Join("storage", targetDir))
if errors.Is(err, os.ErrNotExist) {
err2 := os.MkdirAll(path.Join("storage", targetDir), 0775)
if err2 != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err2.Error(),
"cause": err.Error(),
})
}
} else if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
fh, err := os.Create(path.Join("storage", targetDir, targetName))
if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
body := c.Request().Body
defer body.Close()
written, err := io.Copy(fh, body)
fh.Close()
if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
// Check that it is in fact really JSON
data, err := os.ReadFile(path.Join("storage", targetDir, targetName))
if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
var test any
err = json.Unmarshal(data, &test)
if err != nil {
// Not json!
err2 := os.Remove(path.Join("storage", targetDir, targetName))
if err2 != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err2.Error(),
"cause": err.Error(),
})
}
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
// Ok we're good
return c.JSON(200, map[string]any{
"cod": 200,
"size": bytemath.ConvertBytesToHumanReadable(written),
})
}
// GET /down?q=
func DownloadJData(c echo.Context) error {
// e.g. test/dir1/pkt001.json
targetDir := CleanDirName(path.Dir(c.QueryParam("q"))) // e.g. test/dir1
targetName := path.Base(c.QueryParam("q")) // e.g. pkt001.json
_, err := os.ReadDir(path.Join("storage", targetDir))
if errors.Is(err, os.ErrNotExist) {
err2 := os.MkdirAll(path.Join("storage", targetDir), 0775)
if err2 != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err2.Error(),
"cause": err.Error(),
})
}
} else if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": err.Error(),
})
}
// File contents must be JSON, we live in JSON so it must be JSON data
fh, err := os.ReadFile(path.Join("storage", targetDir, targetName))
if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": "ReadFile: " + err.Error(),
"data": nil,
})
}
var data any
err = json.Unmarshal(fh, &data)
if err != nil {
return c.JSON(500, map[string]any{
"cod": 500,
"err": "json.Unmarshal: " + err.Error(),
"data": nil,
})
}
return c.JSON(200, map[string]any{
"cod": 200,
"data": data,
"size": bytemath.ConvertBytesToHumanReadable(int64(len(fh))),
})
}