Skip to content
This repository was archived by the owner on Sep 2, 2024. It is now read-only.

Commit 5985909

Browse files
committed
created storage abstration, local and s3 impl fix #6
1 parent 2b9e331 commit 5985909

File tree

7 files changed

+148
-35
lines changed

7 files changed

+148
-35
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ deploy:
1212
scp staticbackend sb-poc:/home/dstpierre/sb
1313

1414
test:
15-
@JWT_SECRET=okdevmode go test --race --cover
15+
@JWT_SECRET=okdevmode go test --race --cover ./...

internal/storer.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package internal
2+
3+
import "io"
4+
5+
const (
6+
StorageProviderLocal = "local"
7+
StorageProviderS3 = "s3"
8+
)
9+
10+
type UploadFileData struct {
11+
FileKey string
12+
File io.ReadSeeker
13+
}
14+
15+
type Storer interface {
16+
Save(UploadFileData) (string, error)
17+
Delete(string) error
18+
}

server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"staticbackend/internal"
1212
"staticbackend/middleware"
1313
"staticbackend/realtime"
14+
"staticbackend/storage"
1415
"strings"
1516
"time"
1617

@@ -31,6 +32,7 @@ var (
3132
client *mongo.Client
3233
volatile *cache.Cache
3334
emailer internal.Mailer
35+
storer internal.Storer
3436
AppEnv = os.Getenv("APP_ENV")
3537
)
3638

@@ -146,6 +148,13 @@ func initServices(dbHost string) {
146148
} else {
147149
emailer = email.Dev{}
148150
}
151+
152+
sp := os.Getenv("STORAGE_PROVIDER")
153+
if strings.EqualFold(sp, internal.StorageProviderS3) {
154+
storer = storage.S3{}
155+
} else {
156+
storer = storage.Local{}
157+
}
149158
}
150159
func openDatabase(dbHost string) error {
151160
uri := os.Getenv("DATABASE_URL")

storage.go

Lines changed: 4 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ import (
99
"staticbackend/middleware"
1010
"time"
1111

12-
"github.com/aws/aws-sdk-go/aws"
13-
"github.com/aws/aws-sdk-go/aws/session"
14-
"github.com/aws/aws-sdk-go/service/s3"
1512
"go.mongodb.org/mongo-driver/bson"
1613
"go.mongodb.org/mongo-driver/bson/primitive"
1714
)
@@ -52,36 +49,20 @@ func upload(w http.ResponseWriter, r *http.Request) {
5249
name = primitive.NewObjectID().Hex()
5350
}
5451

55-
sess, err := session.NewSession(&aws.Config{Region: aws.String("ca-central-1")})
56-
if err != nil {
57-
http.Error(w, err.Error(), http.StatusInternalServerError)
58-
return
59-
}
60-
6152
fileKey := fmt.Sprintf("%s/%s/%s%s",
6253
auth.AccountID.Hex(),
6354
config.Name,
6455
name,
6556
ext,
6657
)
6758

68-
svc := s3.New(sess)
69-
obj := &s3.PutObjectInput{}
70-
obj.Body = file
71-
obj.ACL = aws.String(s3.ObjectCannedACLPublicRead)
72-
obj.Bucket = aws.String("files.staticbackend.com")
73-
obj.Key = aws.String(fileKey)
74-
75-
if _, err := svc.PutObject(obj); err != nil {
59+
upData := internal.UploadFileData{FileKey: fileKey, File: file}
60+
url, err := storer.Save(upData)
61+
if err != nil {
7662
http.Error(w, err.Error(), http.StatusInternalServerError)
7763
return
7864
}
7965

80-
url := fmt.Sprintf(
81-
"https://cdn.staticbackend.com/%s",
82-
fileKey,
83-
)
84-
8566
doc := bson.M{
8667
"accountId": auth.AccountID,
8768
"key": fileKey,
@@ -148,18 +129,7 @@ func deleteFile(w http.ResponseWriter, r *http.Request) {
148129
return
149130
}
150131

151-
sess, err := session.NewSession(&aws.Config{Region: aws.String("ca-central-1")})
152-
if err != nil {
153-
http.Error(w, err.Error(), http.StatusInternalServerError)
154-
return
155-
}
156-
157-
svc := s3.New(sess)
158-
obj := &s3.DeleteObjectInput{
159-
Bucket: aws.String("files.staticbackend.com"),
160-
Key: aws.String(fileKey),
161-
}
162-
if _, err := svc.DeleteObject(obj); err != nil {
132+
if err := storer.Delete(fileKey); err != nil {
163133
http.Error(w, err.Error(), http.StatusInternalServerError)
164134
return
165135
}

storage/local.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package storage
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
"path"
8+
"staticbackend/internal"
9+
)
10+
11+
type Local struct{}
12+
13+
func (Local) Save(data internal.UploadFileData) (string, error) {
14+
dir := path.Join(os.TempDir(), path.Dir(data.FileKey))
15+
if err := os.MkdirAll(dir, 0755); err != nil {
16+
return "", err
17+
}
18+
19+
b, err := io.ReadAll(data.File)
20+
if err != nil {
21+
return "", err
22+
}
23+
24+
filename := path.Join(os.TempDir(), data.FileKey)
25+
if err := os.WriteFile(filename, b, 0044); err != nil {
26+
return "", err
27+
}
28+
29+
url := fmt.Sprintf("%s/tmp/%s", os.Getenv("LOCAL_STORAGE_URL"), data.FileKey)
30+
return url, nil
31+
}
32+
33+
func (Local) Delete(fileKey string) error {
34+
filename := path.Join(os.TempDir(), fileKey)
35+
return os.Remove(filename)
36+
}

storage/local_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package storage
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"staticbackend/internal"
7+
"strings"
8+
"testing"
9+
)
10+
11+
func TestLocalSave(t *testing.T) {
12+
rdr := bytes.NewReader([]byte("unit test"))
13+
14+
local := Local{}
15+
16+
data := internal.UploadFileData{FileKey: "unit/test/file.txt", File: rdr}
17+
url, err := local.Save(data)
18+
if err != nil {
19+
t.Fatal(err)
20+
} else if !strings.Contains(url, "/unit/test/file.txt") {
21+
fmt.Errorf("expected ~/tmp/unit/test/file.txt got %s", url)
22+
}
23+
}

storage/s3.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package storage
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"staticbackend/internal"
7+
8+
"github.com/aws/aws-sdk-go/aws"
9+
"github.com/aws/aws-sdk-go/aws/session"
10+
"github.com/aws/aws-sdk-go/service/s3"
11+
)
12+
13+
type S3 struct{}
14+
15+
func (S3) Save(data internal.UploadFileData) (string, error) {
16+
sess, err := session.NewSession(&aws.Config{Region: aws.String("ca-central-1")})
17+
if err != nil {
18+
return "", err
19+
}
20+
21+
svc := s3.New(sess)
22+
obj := &s3.PutObjectInput{}
23+
obj.Body = data.File
24+
obj.ACL = aws.String(s3.ObjectCannedACLPublicRead)
25+
obj.Bucket = aws.String(os.Getenv("AWS_S3_BUCKET"))
26+
obj.Key = aws.String(data.FileKey)
27+
28+
if _, err := svc.PutObject(obj); err != nil {
29+
return "", err
30+
}
31+
32+
url := fmt.Sprintf(
33+
"%s/%s",
34+
os.Getenv("AWS_CDN_URL"),
35+
data.FileKey,
36+
)
37+
38+
return url, nil
39+
}
40+
41+
func (S3) Delete(fileKey string) error {
42+
sess, err := session.NewSession(&aws.Config{Region: aws.String("ca-central-1")})
43+
if err != nil {
44+
return err
45+
}
46+
47+
svc := s3.New(sess)
48+
obj := &s3.DeleteObjectInput{
49+
Bucket: aws.String(os.Getenv("AWS_S3_BUCKET")),
50+
Key: aws.String(fileKey),
51+
}
52+
if _, err := svc.DeleteObject(obj); err != nil {
53+
return err
54+
}
55+
56+
return nil
57+
}

0 commit comments

Comments
 (0)