summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--main.go32
-rw-r--r--objectstore/file_backend.go110
-rw-r--r--objectstore/objecstore.go2
4 files changed, 134 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index c5a22e2..2cea1dc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
storehouse
+data/
diff --git a/main.go b/main.go
index c4104e3..36f51e4 100644
--- a/main.go
+++ b/main.go
@@ -5,9 +5,11 @@
package main
import (
+ "errors"
"io/ioutil"
"log"
"net/http"
+ "os"
"github.com/labstack/echo/v4"
"github.com/pablombg/storehouse/objectstore"
@@ -18,7 +20,8 @@ type storehouse struct {
}
func InitStorehouse() *storehouse {
- objects := objectstore.NewMemBackend()
+ // objects := objectstore.NewMemBackend()
+ objects := objectstore.NewFileBackend("data")
return &storehouse{objects: objects}
}
@@ -26,16 +29,15 @@ func (s *storehouse) putObject(c echo.Context) error {
bucketId := c.Param("bucketId")
objectId := c.Param("objectId")
- // Get body as a string
+ // Get request body
bodyBytes, err := ioutil.ReadAll(c.Request().Body)
if err != nil {
log.Printf("Error reading body: %v", err)
m := &errorJSON{Error: "Error reading body"}
return c.JSON(http.StatusInternalServerError, m)
}
- content := string(bodyBytes)
- err = s.objects.CreateObject(bucketId, objectId, content)
+ err = s.objects.CreateObject(bucketId, objectId, bodyBytes)
// Check errors creating the object
if err != nil {
log.Printf("Error creating the object: %v", err)
@@ -61,10 +63,15 @@ func (s *storehouse) getObject(c echo.Context) error {
objectId := c.Param("objectId")
object, err := s.objects.GetObject(bucketId, objectId)
- if err != nil {
- log.Println(err)
- m := &errorJSON{Error: "Object not found"}
+ if errors.Is(err, os.ErrNotExist) {
+ msg := "Object not found"
+ log.Println(msg)
+ m := &errorJSON{Error: msg}
return c.JSON(http.StatusNotFound, m)
+ } else if err != nil {
+ log.Println(err)
+ m := &errorJSON{Error: "Internal error"}
+ return c.JSON(http.StatusInternalServerError, m)
}
return c.String(http.StatusOK, object)
@@ -75,10 +82,15 @@ func (s *storehouse) deleteObject(c echo.Context) error {
objectId := c.Param("objectId")
err := s.objects.DeleteObject(bucketId, objectId)
- if err != nil {
- log.Println(err)
- m := &errorJSON{Error: "Object not found"}
+ if errors.Is(err, os.ErrNotExist) {
+ msg := "Object not found"
+ log.Println(msg)
+ m := &errorJSON{Error: msg}
return c.JSON(http.StatusNotFound, m)
+ } else if err != nil {
+ log.Println(err)
+ m := &errorJSON{Error: "Internal error"}
+ return c.JSON(http.StatusInternalServerError, m)
}
m := &infoJSON{Info: "Object deleted"}
diff --git a/objectstore/file_backend.go b/objectstore/file_backend.go
new file mode 100644
index 0000000..df2d6bd
--- /dev/null
+++ b/objectstore/file_backend.go
@@ -0,0 +1,110 @@
+// Basic in-memory object store
+//
+// Licensed under CC0 1.0 Universal:
+// https://creativecommons.org/publicdomain/zero/1.0/legalcode
+package objectstore
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "sync"
+)
+
+type FileObjectStore struct {
+ sync.Mutex
+ dataPath string
+}
+
+func NewFileBackend(dataPath string) *FileObjectStore {
+ err := os.MkdirAll(dataPath, 0755)
+ if err != nil {
+ panic(err)
+ }
+ fos := &FileObjectStore{dataPath: dataPath}
+ return fos
+}
+
+func (fos *FileObjectStore) CreateObject(bucketId string, objectId string, payload []byte) error {
+ fos.Lock()
+ defer fos.Unlock()
+
+ // Check if the bucket exists
+ buckets, err := ioutil.ReadDir(fos.dataPath)
+ if err != nil {
+ return fmt.Errorf("Error reading data directory")
+ }
+
+ bucketFound := false
+ for _, f := range buckets {
+ if f.Name() == bucketId && f.IsDir() {
+ bucketFound = true
+ break
+ }
+ }
+
+ // Create bucket if it doesn't exist
+ if !bucketFound {
+ err := os.Mkdir(path.Join(fos.dataPath, bucketId), 0755)
+ if err != nil {
+ return fmt.Errorf("Error creating bucket directory: %v", bucketId)
+ }
+ }
+
+ // Store the object
+ err = os.WriteFile(path.Join(fos.dataPath, bucketId, objectId), payload, 0644)
+ if err != nil {
+ return fmt.Errorf("Error creating the object file %v", bucketId)
+ }
+
+ return nil
+}
+
+func (fos *FileObjectStore) GetObject(bucketId string, objectId string) (string, error) {
+ fos.Lock()
+ defer fos.Unlock()
+
+ objectPath := path.Join(fos.dataPath, bucketId, objectId)
+ object, err := os.ReadFile(objectPath)
+ if err != nil {
+ return "", os.ErrNotExist
+ }
+
+ return string(object), nil
+}
+
+func (fos *FileObjectStore) DeleteObject(bucketId string, objectId string) error {
+ fos.Lock()
+ defer fos.Unlock()
+
+ objectPath := path.Join(fos.dataPath, bucketId, objectId)
+
+ // Check whether the file exists
+ _, err := os.Stat(objectPath)
+ if errors.Is(err, os.ErrNotExist) {
+ return err
+ }
+
+ // Delete file
+ err = os.Remove(objectPath)
+ if err != nil {
+ return err
+ }
+
+ // Delete the bucket directory if it's empty
+ bucketPath := path.Join(fos.dataPath, bucketId)
+ entries, err := ioutil.ReadDir(bucketPath)
+ if err != nil {
+ fmt.Println(err)
+ }
+ if len(entries) == 0 {
+ err := os.Remove(bucketPath)
+ if err != nil {
+ fmt.Println(err)
+ }
+ }
+
+ return nil
+}
diff --git a/objectstore/objecstore.go b/objectstore/objecstore.go
index f4985c9..7cbb481 100644
--- a/objectstore/objecstore.go
+++ b/objectstore/objecstore.go
@@ -9,7 +9,7 @@ import (
)
type ObjectStore interface {
- CreateObject(bucketId string, objectId string, content string) error
+ CreateObject(bucketId string, objectId string, content []byte) error
GetObject(bucketId string, objectId string) (string, error)
DeleteObject(bucketId string, objectId string) error
}