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

Implement Storage Context with Driver-Agnostic Design (Local File Storage as Initial Implementation) #29

Merged
merged 3 commits into from
Sep 1, 2023
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
3 changes: 3 additions & 0 deletions cmd/app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ func init() {
if err := env.Parse(&Config.Nats); err != nil {
panic(err)
}
if err := env.Parse(&Config.Storage); err != nil {
panic(err)
}
}
5 changes: 5 additions & 0 deletions cmd/app/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,9 @@ type config struct {
Nats struct {
URL string `env:"NATS_URL" envDefault:"nats://localhost:4222"`
}

// Storage provides the storage configuration.
Storage struct {
Driver string `env:"STORAGE_DRIVER" envDefault:"file"`
}
}
2 changes: 2 additions & 0 deletions cmd/app/context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/iammuho/natternet/pkg/logger"
"github.com/iammuho/natternet/pkg/mongodb"
"github.com/iammuho/natternet/pkg/nats"
"github.com/iammuho/natternet/pkg/storage"
"github.com/iammuho/natternet/pkg/utils"
)

Expand All @@ -19,6 +20,7 @@ type AppContext interface {
GetJwtContext() jwt.JwtContext
GetMongoContext() mongodb.MongoDBContext
GetNatsContext() nats.NatsContext
GetStorageContext() storage.StorageContext
GetHashingFactory() hashing.HashingFactory
GetUUID() utils.UUID
GetTimer() utils.Timer
Expand Down
15 changes: 15 additions & 0 deletions cmd/app/context/mocks/mock_app_contexter.go

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

9 changes: 8 additions & 1 deletion cmd/app/context/real_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/iammuho/natternet/pkg/logger"
"github.com/iammuho/natternet/pkg/mongodb"
"github.com/iammuho/natternet/pkg/nats"
"github.com/iammuho/natternet/pkg/storage"
"github.com/iammuho/natternet/pkg/utils"
)

Expand All @@ -18,11 +19,12 @@ type appContext struct {
mongoContext mongodb.MongoDBContext
hashingFactory hashing.HashingFactory
natsContext nats.NatsContext
storageContext storage.StorageContext
UUID utils.UUID
Timer utils.Timer
}

func NewAppContext(logger *logger.Logger, jwt jwt.JwtContext, mongoContext mongodb.MongoDBContext, natsContext nats.NatsContext) AppContext {
func NewAppContext(logger *logger.Logger, jwt jwt.JwtContext, mongoContext mongodb.MongoDBContext, natsContext nats.NatsContext, storageContext storage.StorageContext) AppContext {
ctx := context.Background()

// Set the UUID
Expand All @@ -41,6 +43,7 @@ func NewAppContext(logger *logger.Logger, jwt jwt.JwtContext, mongoContext mongo
mongoContext: mongoContext,
hashingFactory: hashingFactory,
natsContext: natsContext,
storageContext: storageContext,
UUID: uuid,
Timer: timer,
}
Expand Down Expand Up @@ -77,3 +80,7 @@ func (c *appContext) GetHashingFactory() hashing.HashingFactory {
func (c *appContext) GetNatsContext() nats.NatsContext {
return c.natsContext
}

func (c *appContext) GetStorageContext() storage.StorageContext {
return c.storageContext
}
13 changes: 12 additions & 1 deletion cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"github.com/iammuho/natternet/pkg/logger"
"github.com/iammuho/natternet/pkg/mongodb"
"github.com/iammuho/natternet/pkg/nats"
"github.com/iammuho/natternet/pkg/storage"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/swagger"
Expand Down Expand Up @@ -94,8 +95,18 @@ func main() {
l.Panic("NATS Client failed to connect: %v", zap.Error(err))
}

// Add the storage
l.Info("Creating Storage", zap.String("driver", config.Config.Storage.Driver))
storageContext, err := storage.NewStorage(
storage.WithStorageDriver(config.Config.Storage.Driver),
)

if err != nil {
l.Panic("Storage failed to initialize: %v", zap.Error(err))
}

// Create the app context
ctx := context.NewAppContext(l, jwtContext, mongodbContext, natsContext)
ctx := context.NewAppContext(l, jwtContext, mongodbContext, natsContext, storageContext)

// Register the routes
v1 := httpServer.App.Group("/api/v1")
Expand Down
111 changes: 111 additions & 0 deletions pkg/storage/drivers/file/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package file

import (
"os"

"github.com/iammuho/natternet/pkg/storage/drivers"
)

type file struct{}

// NewFileStorage returns a new file storage
func NewFileStorage() drivers.DriverContext {
return &file{}
}

// Get returns a file
func (f *file) Get(fileName string) ([]byte, error) {
// open the file
file, err := os.Open(fileName)

if err != nil {
return nil, err
}

// close the file
defer file.Close()

// get the file info
fileInfo, err := file.Stat()

if err != nil {
return nil, err
}

// prepare the buffer
buffer := make([]byte, fileInfo.Size())

// read the file
_, err = file.Read(buffer)

if err != nil {
return nil, err
}

return buffer, nil
}

// Put puts a file
func (f *file) Put(fileName string, content []byte) error {
// create the file
file, err := os.Create(fileName)

if err != nil {
return err
}

// close the file
defer file.Close()

// write the content
_, err = file.Write(content)

if err != nil {
return err
}

return nil
}

// Delete deletes a file
func (f *file) Delete(fileName string) error {
// delete the file
err := os.Remove(fileName)

if err != nil {
return err
}

return nil
}

// List lists files
func (f *file) List(path string) ([]string, error) {
// list all files in a directory
dir, err := os.Open(path)
if err != nil {
return nil, err
}

// close the directory
defer dir.Close()

// get the list of files
files, err := dir.Readdir(0)

if err != nil {
return nil, err
}

// prepare the list of files
var fileList []string

// loop through the files
for _, file := range files {
// append the file name to the list
fileList = append(fileList, file.Name())
}

// return the list of files
return fileList, nil
}
10 changes: 10 additions & 0 deletions pkg/storage/drivers/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package drivers

// DriverContext is the interface for the storage driver
// TODO: add/refactor methods
type DriverContext interface {
Get(string) ([]byte, error)
Put(string, []byte) error
Delete(string) error
List(string) ([]string, error)
}
8 changes: 8 additions & 0 deletions pkg/storage/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package storage

import "github.com/iammuho/natternet/pkg/storage/drivers"

// StorageContext is the interface for the storage
type StorageContext interface {
Driver() drivers.DriverContext
}
25 changes: 25 additions & 0 deletions pkg/storage/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package storage

// Option is the func interface to assign options
type Option func(*StorageOptions)

type Driver string

const (
// DriverFile is the file driver
DriverFile Driver = "file"
// DriverAWS is the AWS driver
DriverAWS Driver = "aws"
)

// StorageOptions defines the options for the storage
type StorageOptions struct {
Driver Driver
}

// WithStorageDriver sets the storage driver
func WithStorageDriver(driver string) Option {
return func(o *StorageOptions) {
o.Driver = Driver(driver)
}
}
33 changes: 33 additions & 0 deletions pkg/storage/storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package storage

import (
"github.com/iammuho/natternet/pkg/storage/drivers"
"github.com/iammuho/natternet/pkg/storage/drivers/file"
)

type storage struct {
driver drivers.DriverContext
options StorageOptions
}

func NewStorage(opts ...Option) (StorageContext, error) {
// Setup the driver
options := StorageOptions{}
for _, o := range opts {
o(&options)
}

switch options.Driver {
case DriverFile:
return &storage{
driver: file.NewFileStorage(),
options: options,
}, nil
}

return &storage{}, nil
}

func (s *storage) Driver() drivers.DriverContext {
return s.driver
}