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))), }) }