Skip to content

Commit

Permalink
Merge pull request #29 from iammuho/19-implement-service-agnostic-sto…
Browse files Browse the repository at this point in the history
…rage-context

Implement Storage Context with Driver-Agnostic Design (Local File Storage as Initial Implementation)
  • Loading branch information
iammuho authored Sep 1, 2023
2 parents d6d9d3b + 7b25920 commit 9cb16bd
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 2 deletions.
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
}

0 comments on commit 9cb16bd

Please sign in to comment.