Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Storage Service 추가 #17

Merged
merged 5 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
ENV=local
FIREBASE_AUTH_EMULATOR_HOST=firebase-emulator:9099
GCLOUD_PROJECT=fluentify-test
FIREBASE_AUTH_EMULATOR_HOST=firebase-emulator:9099
FIREBASE_STORAGE_EMULATOR_HOST=firebase-emulator:9199
DEFAULT_STORAGE_BUCKET=default-bucket
18 changes: 17 additions & 1 deletion config/firebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ import (
"context"
firebase "firebase.google.com/go/v4"
"firebase.google.com/go/v4/auth"
"firebase.google.com/go/v4/storage"
"log"
"os"
)

func InitializeFirebaseApp() *firebase.App {
firebaseApp, err := firebase.NewApp(context.Background(), nil)
defaultBucketName := os.Getenv("DEFAULT_STORAGE_BUCKET")
config := &firebase.Config{
StorageBucket: defaultBucketName + ".appspot.com",
}

firebaseApp, err := firebase.NewApp(context.Background(), config)
if err != nil {
log.Fatalf("error initializing firebase app: %v\n", err)
}
Expand All @@ -24,3 +31,12 @@ func NewFirebaseAuthClient(app *firebase.App) *auth.Client {

return authClient
}

func NewFirebaseStorageClient(app *firebase.App) *storage.Client {
storageClient, err := app.Storage(context.Background())
if err != nil {
log.Fatalf("error getting firebase storage client: %v", err)
}

return storageClient
}
7 changes: 6 additions & 1 deletion config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,22 @@ import (

type Initialization struct {
AuthMiddleware middleware.AuthMiddleware

UserService service.UserService
UserHandler handler.UserHandler
StorageService service.StorageService

UserHandler handler.UserHandler
}

func NewInitialization(
authMiddleware middleware.AuthMiddleware,
storageService service.StorageService,
userService service.UserService,
userHandler handler.UserHandler,
) *Initialization {
return &Initialization{
AuthMiddleware: authMiddleware,
StorageService: storageService,
UserService: userService,
UserHandler: userHandler,
}
Expand Down
13 changes: 12 additions & 1 deletion config/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ import (

var firebaseApp = wire.NewSet(InitializeFirebaseApp)
var firebaseAuthClient = wire.NewSet(NewFirebaseAuthClient)
var firebaseStorageClient = wire.NewSet(NewFirebaseStorageClient)
var authMiddlewareSet = wire.NewSet(middleware.AuthMiddlewareInit, wire.Bind(new(middleware.AuthMiddleware), new(*middleware.AuthMiddlewareImpl)))
var userServiceSet = wire.NewSet(service.UserServiceInit, wire.Bind(new(service.UserService), new(*service.UserServiceImpl)))
var storageServiceSet = wire.NewSet(service.StorageServiceInit, wire.Bind(new(service.StorageService), new(*service.StorageServiceImpl)))
var userHandlerSet = wire.NewSet(handler.UserHandlerInit, wire.Bind(new(handler.UserHandler), new(*handler.UserHandlerImpl)))

func Init() *Initialization {
wire.Build(NewInitialization, firebaseApp, firebaseAuthClient, authMiddlewareSet, userServiceSet, userHandlerSet)
wire.Build(
NewInitialization,
firebaseApp,
firebaseAuthClient,
firebaseStorageClient,
authMiddlewareSet,
userServiceSet,
storageServiceSet,
userHandlerSet,
)
return nil
}
8 changes: 7 additions & 1 deletion config/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions firebase-emulator/storage.rules
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ rules_version = '2';
// /databases/(default)/documents/users/$(request.auth.uid)).data.isAdmin;
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false;
match /public/{allPaths=**} {
allow read;
allow write: if false;
}
match /private/{userId}/{allPaths=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21.4

require (
firebase.google.com/go/v4 v4.13.0
github.com/google/uuid v1.6.0
github.com/google/wire v0.6.0
github.com/joho/godotenv v1.5.1
github.com/labstack/echo/v4 v4.11.4
Expand All @@ -29,7 +30,6 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.1 // indirect
github.com/labstack/gommon v0.4.2 // indirect
Expand Down
83 changes: 83 additions & 0 deletions src/service/storage.service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package service

import (
"bytes"
"context"
"firebase.google.com/go/v4/storage"
"github.com/google/uuid"
"io"
"time"
)

type StorageService interface {
UploadFile(file []byte, userId string) (string, error)
GetFile(filePath string) ([]byte, error)
}

type StorageServiceImpl struct {
storageClient *storage.Client
}

const (
publicPath = "public/"
privatePath = "private/"
defaultTransferTimeout = 5 * time.Second
)

func (service *StorageServiceImpl) UploadFile(file []byte, userId string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultTransferTimeout)
defer cancel()

bucket, err := service.storageClient.DefaultBucket()
if err != nil {
return "", err
}

fileName := uuid.New().String()
path := privatePath + userId + "/" + fileName
object := bucket.Object(path)
writer := object.NewWriter(ctx)
//Set the attribute
//writer.ObjectAttrs.Metadata = map[string]string{"firebaseStorageDownloadTokens": id.String()}
defer writer.Close()

if _, err := io.Copy(writer, bytes.NewReader(file)); err != nil {
return "", err
}
// Set access control if needed
//if err := object.ACL().Set(context.Background(), storage.AllUsers, storage.RoleReader); err != nil {
// return "", err
//}

return path, nil
}

func (service *StorageServiceImpl) GetFile(filePath string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultTransferTimeout)
defer cancel()

bucket, err := service.storageClient.DefaultBucket()
if err != nil {
return nil, err
}

object := bucket.Object(filePath)
reader, err := object.NewReader(ctx)
if err != nil {
return nil, err
}
defer reader.Close()

buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(reader); err != nil {
return nil, err
}

return buf.Bytes(), nil
}

func StorageServiceInit(storageClient *storage.Client) *StorageServiceImpl {
return &StorageServiceImpl{
storageClient: storageClient,
}
}
Loading