diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 3584adc7..6944b34b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -110,3 +110,21 @@ updates:
automerged_updates:
- match:
dependency_name: "gofiber/fiber/*"
+ - package-ecosystem: "gomod"
+ directory: "/s3/" # Location of package manifests
+ default_labels:
+ - "🤖 Dependencies"
+ schedule:
+ interval: "daily"
+ automerged_updates:
+ - match:
+ dependency_name: "gofiber/fiber/*"
+ - package-ecosystem: "gomod"
+ directory: "/bbolt/" # Location of package manifests
+ default_labels:
+ - "🤖 Dependencies"
+ schedule:
+ interval: "daily"
+ automerged_updates:
+ - match:
+ dependency_name: "gofiber/fiber/*"
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index c7a089b9..94f5cfd4 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -13,10 +13,10 @@ jobs:
- name: Install Gosec
run: |
export PATH=${PATH}:`go env GOPATH`/bin
- go get -u github.com/securego/gosec/v2/cmd/gosec
+ go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Run Gosec (root)
working-directory: .
- run: "`go env GOPATH`/bin/gosec -exclude-dir=internal -exclude-dir=arangodb -exclude-dir=badger -exclude-dir=dynamodb -exclude-dir=memcache -exclude-dir=memory -exclude-dir=mongodb -exclude-dir=mysql -exclude-dir=postgres -exclude-dir=redis -exclude-dir=ristretto -exclude-dir=sqlite3 ./..."
+ run: "`go env GOPATH`/bin/gosec -exclude-dir=internal -exclude-dir=arangodb -exclude-dir=badger -exclude-dir=dynamodb -exclude-dir=memcache -exclude-dir=memory -exclude-dir=mongodb -exclude-dir=mysql -exclude-dir=postgres -exclude-dir=redis -exclude-dir=ristretto -exclude-dir=sqlite3 -exclude-dir=s3 -exclude-dir=bbolt ./..."
# -----
- name: Run Gosec (arangodb)
working-directory: ./arangodb
@@ -58,7 +58,15 @@ jobs:
working-directory: ./sqlite3
run: "`go env GOPATH`/bin/gosec -exclude-dir=internal ./..."
# -----
+ - name: Run Gosec (s3)
+ working-directory: ./s3
+ run: "`go env GOPATH`/bin/gosec -exclude-dir=internal ./..."
+ # -----
- name: Run Gosec (ristretto)
working-directory: ./ristretto
run: "`go env GOPATH`/bin/gosec -exclude-dir=internal ./..."
# -----
+ - name: Run Gosec (bbolt)
+ working-directory: ./bbolt
+ run: "`go env GOPATH`/bin/gosec -exclude-dir=internal ./..."
+ # -----
diff --git a/.github/workflows/test-bbolt.yml b/.github/workflows/test-bbolt.yml
new file mode 100644
index 00000000..65cc04aa
--- /dev/null
+++ b/.github/workflows/test-bbolt.yml
@@ -0,0 +1,24 @@
+'on':
+ - push
+ - pull_request
+name: Bbolt
+jobs:
+ Tests:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go-version:
+ - 1.16.x
+ - 1.17.x
+ platform:
+ - ubuntu-latest
+ - windows-latest
+ steps:
+ - name: Install Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '${{ matrix.go-version }}'
+ - name: Fetch Repository
+ uses: actions/checkout@v2
+ - name: Run Test
+ run: cd ./bbolt && go mod tidy && go test ./... -v -race
diff --git a/.github/workflows/test-dynamodb.yml b/.github/workflows/test-dynamodb.yml
new file mode 100644
index 00000000..1dc2398c
--- /dev/null
+++ b/.github/workflows/test-dynamodb.yml
@@ -0,0 +1,31 @@
+'on':
+ - push
+ - pull_request
+name: DynamoDB
+jobs:
+ Tests:
+ runs-on: ubuntu-latest
+ services:
+ mongo:
+ image: 'amazon/dynamodb-local:latest'
+ ports:
+ - '8000:8000'
+ strategy:
+ matrix:
+ go-version:
+ - 1.14.x
+ - 1.15.x
+ - 1.16.x
+ - 1.17.x
+ platform:
+ - ubuntu-latest
+ - windows-latest
+ steps:
+ - name: Install Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '${{ matrix.go-version }}'
+ - name: Fetch Repository
+ uses: actions/checkout@v2
+ - name: Run Test
+ run: cd ./dynamodb && go test ./... -v -race
diff --git a/.github/workflows/test-s3.yml b/.github/workflows/test-s3.yml
new file mode 100644
index 00000000..06a6cc05
--- /dev/null
+++ b/.github/workflows/test-s3.yml
@@ -0,0 +1,35 @@
+'on':
+ - push
+ - pull_request
+name: S3
+jobs:
+ Tests:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ go-version:
+ - 1.14.x
+ - 1.15.x
+ - 1.16.x
+ - 1.17.x
+ platform:
+ - ubuntu-latest
+ - windows-latest
+ steps:
+ - name: Install MinIO
+ run: |
+ docker run -d -p 9000:9000 --name minio minio/minio server /data
+
+ export AWS_ACCESS_KEY_ID=minioadmin
+ export AWS_SECRET_ACCESS_KEY=minioadmin
+ export AWS_EC2_METADATA_DISABLED=true
+
+ aws --endpoint-url http://127.0.0.1:9000/ s3 mb s3://testbucket
+ - name: Install Go
+ uses: actions/setup-go@v1
+ with:
+ go-version: '${{ matrix.go-version }}'
+ - name: Fetch Repository
+ uses: actions/checkout@v2
+ - name: Run Test
+ run: cd ./s3 && go test ./... -v -race
diff --git a/README.md b/README.md
index ff69ad59..4291cf5d 100644
--- a/README.md
+++ b/README.md
@@ -81,3 +81,9 @@ type Storage interface {
* [SQLite3](/sqlite3)
+* [S3](/s3)
+
+
+* [Bbolt](/bbolt)
+
+
\ No newline at end of file
diff --git a/arangodb/go.mod b/arangodb/go.mod
index 0e932cbd..0b084a0a 100644
--- a/arangodb/go.mod
+++ b/arangodb/go.mod
@@ -3,6 +3,6 @@ module github.com/gofiber/storage/arangodb
go 1.14
require (
- github.com/arangodb/go-driver v1.2.1
+ github.com/arangodb/go-driver v1.3.1
github.com/gofiber/utils v0.1.2
)
diff --git a/arangodb/go.sum b/arangodb/go.sum
index 26d98a39..5fd285fb 100644
--- a/arangodb/go.sum
+++ b/arangodb/go.sum
@@ -1,5 +1,5 @@
-github.com/arangodb/go-driver v1.2.1 h1:HREDHhDmzdIWxHmfkfTESbYUnRjESjPh4WUuXq7FZa8=
-github.com/arangodb/go-driver v1.2.1/go.mod h1:zdDkJJnCj8DAkfbtIjIXnsTrWIiy6VhP3Vy14p+uQeY=
+github.com/arangodb/go-driver v1.3.1 h1:ypwg9uwahiUekuwdDOttoLR7F5DmK5BzpSXt92poCyQ=
+github.com/arangodb/go-driver v1.3.1/go.mod h1:5GAx3XvK72DJPhJgyjZOtYAGc4SpY7rZDb3LyhCvLcQ=
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e h1:Xg+hGrY2LcQBbxd0ZFdbGSyRKTYMZCfBbw/pMJFOk1g=
github.com/arangodb/go-velocypack v0.0.0-20200318135517-5af53c29c67e/go.mod h1:mq7Shfa/CaixoDxiyAAc5jZ6CVBAyPaNQCGS7mkj4Ho=
github.com/coreos/go-iptables v0.4.3/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
diff --git a/bbolt/README.md b/bbolt/README.md
new file mode 100644
index 00000000..b00a548f
--- /dev/null
+++ b/bbolt/README.md
@@ -0,0 +1,92 @@
+# Bbolt
+A Bbolt storage driver using [etcd-io/bbolt](https://github.com/etcd-io/bbolt). Bolt is a pure Go key/value store inspired by [Howard Chu's](https://twitter.com/hyc_symas) [LMDB project](https://www.symas.com/symas-embedded-database-lmdb). The goal of the project is to provide a simple, fast, and reliable database for projects that don't require a full database server such as Postgres or MySQL.
+
+
+### Table of Contents
+- [Signatures](#signatures)
+- [Installation](#installation)
+- [Examples](#examples)
+- [Config](#config)
+- [Default Config](#default-config)
+
+### Signatures
+```go
+func New(config ...Config) Storage
+func (s *Storage) Get(key string) ([]byte, error)
+func (s *Storage) Set(key string, val []byte, exp time.Duration) error
+func (s *Storage) Delete(key string) error
+func (s *Storage) Reset() error
+func (s *Storage) Close() error
+```
+### Installation
+Bbolt is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
+```bash
+go mod init github.com//
+```
+And then install the s3 implementation:
+```bash
+go get github.com/gofiber/storage/bbolt
+```
+
+### Examples
+Import the storage package.
+```go
+import "github.com/gofiber/storage/bbolt"
+```
+
+You can use the following possibilities to create a storage:
+```go
+// Initialize default config
+store := bbolt.New()
+
+// Initialize custom config
+store := bbolt.New(bbolt.Config{
+ Database: "my_database.db",
+ Bucket: "my-bucket",
+ Reset: false,
+})
+```
+
+### Config
+```go
+// Config defines the config for storage.
+type Config struct {
+ // Database path
+ //
+ // Optional. Default is "fiber.db"
+ Database string
+
+ // Bbolt bucket name
+ //
+ // Optional. Default is "fiber_storage"
+ Bucket string
+
+ // Timeout is the amount of time to wait to obtain a file lock.
+ // Only available on Darwin and Linux.
+ //
+ // Optional. Default is 0 (no timeout)
+ Timeout time.Duration
+
+ // Open database in read-only mode.
+ //
+ // Optional. Default is false
+ ReadOnly bool
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
+}
+```
+
+### Default Config
+```go
+// ConfigDefault is the default config
+var ConfigDefault = Config{
+ Database: "fiber.db",
+ Bucket: "fiber_storage",
+ Timeout: 0,
+ ReadOnly: false,
+ Reset: false,
+}
+```
diff --git a/bbolt/bbolt.go b/bbolt/bbolt.go
new file mode 100644
index 00000000..b93253eb
--- /dev/null
+++ b/bbolt/bbolt.go
@@ -0,0 +1,106 @@
+package bbolt
+
+import (
+ "time"
+
+ "github.com/gofiber/utils"
+ "go.etcd.io/bbolt"
+)
+
+// Storage interface that is implemented by storage providers
+type Storage struct {
+ conn *bbolt.DB
+ bucket string
+}
+
+// New creates a new storage
+func New(config ...Config) *Storage {
+ // Set default config
+ cfg := configDefault(config...)
+
+ conn, err := bbolt.Open(cfg.Database, 0666, &bbolt.Options{
+ Timeout: cfg.Timeout,
+ ReadOnly: cfg.ReadOnly,
+ })
+ if err != nil {
+ panic(err)
+ }
+
+ // Reset bucket if field selected
+ if cfg.Reset {
+ if err := removeBucket(cfg, conn); err != nil {
+ panic(err)
+ }
+ }
+
+ // Create bucket if not exists
+ if err := createBucket(cfg, conn); err != nil {
+ panic(err)
+ }
+
+ return &Storage{
+ conn: conn,
+ bucket: cfg.Bucket,
+ }
+
+}
+
+// Get value by key
+func (s *Storage) Get(key string) ([]byte, error) {
+ if len(key) <= 0 {
+ return nil, nil
+ }
+
+ var value []byte
+
+ err := s.conn.View(func(tx *bbolt.Tx) error {
+ b := tx.Bucket(utils.UnsafeBytes(s.bucket))
+ value = b.Get(utils.UnsafeBytes(key))
+
+ return nil
+ })
+
+ return value, err
+}
+
+// Set key with value
+func (s *Storage) Set(key string, value []byte, exp time.Duration) error {
+ if len(key) <= 0 || len(value) <= 0 {
+ return nil
+ }
+
+ return s.conn.Update(func(tx *bbolt.Tx) error {
+ b := tx.Bucket(utils.UnsafeBytes(s.bucket))
+
+ return b.Put(utils.UnsafeBytes(key), value)
+ })
+}
+
+// Delete entry by key
+func (s *Storage) Delete(key string) error {
+ if len(key) <= 0 {
+ return nil
+ }
+
+ return s.conn.Update(func(tx *bbolt.Tx) error {
+ b := tx.Bucket(utils.UnsafeBytes(s.bucket))
+
+ return b.Delete(utils.UnsafeBytes(key))
+ })
+}
+
+// Reset all entries
+func (s *Storage) Reset() error {
+ return s.conn.Update(func(tx *bbolt.Tx) error {
+ b := tx.Bucket(utils.UnsafeBytes(s.bucket))
+
+ return b.ForEach(func(k, _ []byte) error {
+ return b.Delete(k)
+ })
+ })
+}
+
+// Close the database
+func (s *Storage) Close() error {
+ return s.conn.Close()
+}
diff --git a/bbolt/bbolt_test.go b/bbolt/bbolt_test.go
new file mode 100644
index 00000000..f703a93a
--- /dev/null
+++ b/bbolt/bbolt_test.go
@@ -0,0 +1,97 @@
+package bbolt
+
+import (
+ "testing"
+
+ "github.com/gofiber/utils"
+)
+
+var testStore = New()
+
+func Test_Bbolt_Set(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_Bbolt_Set_Override(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_Bbolt_Get(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, val, result)
+}
+
+func Test_Bbolt_Get_NotExist(t *testing.T) {
+
+ result, err := testStore.Get("notexist")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_Bbolt_Delete(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Delete(key)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_Bbolt_Reset(t *testing.T) {
+ var (
+ val = []byte("doe")
+ )
+
+ err := testStore.Set("john1", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set("john2", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Reset()
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get("john1")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+
+ result, err = testStore.Get("john2")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_Bbolt_Close(t *testing.T) {
+ utils.AssertEqual(t, nil, testStore.Close())
+}
diff --git a/bbolt/config.go b/bbolt/config.go
new file mode 100644
index 00000000..5cf21ddb
--- /dev/null
+++ b/bbolt/config.go
@@ -0,0 +1,63 @@
+package bbolt
+
+import "time"
+
+// Config defines the config for storage.
+type Config struct {
+ // Database path
+ //
+ // Optional. Default is "fiber.db"
+ Database string
+
+ // Bbolt bucket name
+ //
+ // Optional. Default is "fiber_storage"
+ Bucket string
+
+ // Timeout is the amount of time to wait to obtain a file lock.
+ // Only available on Darwin and Linux.
+ //
+ // Optional. Default is 0 (no timeout)
+ Timeout time.Duration
+
+ // Open database in read-only mode.
+ //
+ // Optional. Default is false
+ ReadOnly bool
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
+}
+
+// ConfigDefault is the default config
+var ConfigDefault = Config{
+ Database: "fiber.db",
+ Bucket: "fiber_storage",
+ Timeout: 0,
+ ReadOnly: false,
+ Reset: false,
+}
+
+// Helper function to set default values
+func configDefault(config ...Config) Config {
+ // Return default config if nothing provided
+ if len(config) < 1 {
+ return ConfigDefault
+ }
+
+ // Override default config
+ cfg := config[0]
+
+ // Set default values
+ if cfg.Database == "" {
+ cfg.Database = ConfigDefault.Database
+ }
+
+ if cfg.Bucket == "" {
+ cfg.Bucket = ConfigDefault.Bucket
+ }
+
+ return cfg
+}
diff --git a/bbolt/go.mod b/bbolt/go.mod
new file mode 100644
index 00000000..65153a36
--- /dev/null
+++ b/bbolt/go.mod
@@ -0,0 +1,10 @@
+module github.com/gofiber/storage/bbolt
+
+go 1.16
+
+require (
+ github.com/gofiber/utils v0.1.2
+ go.etcd.io/bbolt v1.3.6
+)
+
+require golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a // indirect
diff --git a/bbolt/go.sum b/bbolt/go.sum
new file mode 100644
index 00000000..a4e257fa
--- /dev/null
+++ b/bbolt/go.sum
@@ -0,0 +1,7 @@
+github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
+github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
+go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
+go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
+golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/bbolt/utils.go b/bbolt/utils.go
new file mode 100644
index 00000000..f920dd05
--- /dev/null
+++ b/bbolt/utils.go
@@ -0,0 +1,20 @@
+package bbolt
+
+import (
+ "github.com/gofiber/utils"
+ "go.etcd.io/bbolt"
+)
+
+func createBucket(cfg Config, conn *bbolt.DB) error {
+ return conn.Update(func(tx *bbolt.Tx) error {
+ _, err := tx.CreateBucketIfNotExists(utils.UnsafeBytes(cfg.Bucket))
+
+ return err
+ })
+}
+
+func removeBucket(cfg Config, conn *bbolt.DB) error {
+ return conn.Update(func(tx *bbolt.Tx) error {
+ return tx.DeleteBucket(utils.UnsafeBytes(cfg.Bucket))
+ })
+}
diff --git a/dynamodb/README.md b/dynamodb/README.md
index d905ed73..a7ee9b75 100644
--- a/dynamodb/README.md
+++ b/dynamodb/README.md
@@ -1,4 +1,7 @@
-# âš DynamoDB is still in development, do not use in production!
+# DynamoDB
+A DynamoDB storage driver using [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2).
+
+**Note:** If config fields of credentials not given, credentials are using from the environment variables, ~/.aws/credentials, or EC2 instance role. If config fields of credentials given, credentials are using from config. Look at: [specifying credentials](https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#specifying-credentials)
....
@@ -60,28 +63,70 @@ type Config struct {
// Optional ("fiber_storage" by default).
Table string
- // AWS access key ID (part of the credentials).
- // Optional (read from shared credentials file or environment variable if not set).
- // Environment variable: "AWS_ACCESS_KEY_ID".
- AWSaccessKeyID string
-
- // AWS secret access key (part of the credentials).
- // Optional (read from shared credentials file or environment variable if not set).
- // Environment variable: "AWS_SECRET_ACCESS_KEY".
- AWSsecretAccessKey string
-
// CustomEndpoint allows you to set a custom DynamoDB service endpoint.
// This is especially useful if you're running a "DynamoDB local" Docker container for local testing.
// Typical value for the Docker container: "http://localhost:8000".
// See https://hub.docker.com/r/amazon/dynamodb-local/.
// Optional ("" by default)
- CustomEndpoint string
+ Endpoint string
+
+ // Credentials overrides AWS access key and AWS secret access key. Not recommended.
+ //
+ // Optional. Default is Credentials{}
+ Credentials Credentials
+
+ // The maximum number of times requests that encounter retryable failures should be attempted.
+ //
+ // Optional. Default is 3
+ MaxAttempts int
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
+
+ // ReadCapacityUnits of the table.
+ // Only required when the table doesn't exist yet and is created by gokv.
+ // Optional (5 by default, which is the same default value as when creating a table in the web console)
+ // 25 RCUs are included in the free tier (across all tables).
+ // For example calculations, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/HowItWorks.ProvisionedThroughput.
+ // For limits, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/Limits.md#capacity-units-and-provisioned-throughput.md#provisioned-throughput.
+ ReadCapacityUnits int64
+
+ // ReadCapacityUnits of the table.
+ // Only required when the table doesn't exist yet and is created by gokv.
+ // Optional (5 by default, which is the same default value as when creating a table in the web console)
+ // 25 RCUs are included in the free tier (across all tables).
+ // For example calculations, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/HowItWorks.ProvisionedThroughput.
+ // For limits, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/Limits.md#capacity-units-and-provisioned-throughput.md#provisioned-throughput.
+ WriteCapacityUnits int64
+
+ // If the table doesn't exist yet, gokv creates it.
+ // If WaitForTableCreation is true, gokv will block until the table is created, with a timeout of 15 seconds.
+ // If the table still doesn't exist after 15 seconds, an error is returned.
+ // If WaitForTableCreation is false, gokv returns the client immediately.
+ // In the latter case you need to make sure that you don't read from or write to the table before it's created,
+ // because otherwise you will get ResourceNotFoundException errors.
+ // Optional (true by default).
+ WaitForTableCreation *bool
}
+
+type Credentials struct {
+ AccessKey string
+ SecretAccessKey string
+}
+
```
### Default Config
```go
var ConfigDefault = Config{
- Table: "fiber_storage",
+ Table: "fiber_storage",
+ Credentials: Credentials{},
+ MaxAttempts: 3,
+ Reset: false,
+ ReadCapacityUnits: 5,
+ WriteCapacityUnits: 5,
+ WaitForTableCreation: aws.Bool(true),
}
```
diff --git a/dynamodb/config.go b/dynamodb/config.go
index e28f656a..07375cae 100644
--- a/dynamodb/config.go
+++ b/dynamodb/config.go
@@ -1,6 +1,6 @@
package dynamodb
-import "github.com/aws/aws-sdk-go/aws"
+import "github.com/aws/aws-sdk-go-v2/aws"
// Config defines the config for storage.
type Config struct {
@@ -15,22 +15,27 @@ type Config struct {
// Optional ("fiber_storage" by default).
Table string
- // AWS access key ID (part of the credentials).
- // Optional (read from shared credentials file or environment variable if not set).
- // Environment variable: "AWS_ACCESS_KEY_ID".
- AWSaccessKeyID string
-
- // AWS secret access key (part of the credentials).
- // Optional (read from shared credentials file or environment variable if not set).
- // Environment variable: "AWS_SECRET_ACCESS_KEY".
- AWSsecretAccessKey string
-
// CustomEndpoint allows you to set a custom DynamoDB service endpoint.
// This is especially useful if you're running a "DynamoDB local" Docker container for local testing.
// Typical value for the Docker container: "http://localhost:8000".
// See https://hub.docker.com/r/amazon/dynamodb-local/.
// Optional ("" by default)
- CustomEndpoint string
+ Endpoint string
+
+ // Credentials overrides AWS access key and AWS secret access key. Not recommended.
+ //
+ // Optional. Default is Credentials{}
+ Credentials Credentials
+
+ // The maximum number of times requests that encounter retryable failures should be attempted.
+ //
+ // Optional. Default is 3
+ MaxAttempts int
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
// ReadCapacityUnits of the table.
// Only required when the table doesn't exist yet and is created by gokv.
@@ -38,14 +43,16 @@ type Config struct {
// 25 RCUs are included in the free tier (across all tables).
// For example calculations, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/HowItWorks.ProvisionedThroughput.
// For limits, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/Limits.md#capacity-units-and-provisioned-throughput.md#provisioned-throughput.
- readCapacityUnits int64
+ ReadCapacityUnits int64
+
// ReadCapacityUnits of the table.
// Only required when the table doesn't exist yet and is created by gokv.
// Optional (5 by default, which is the same default value as when creating a table in the web console)
// 25 RCUs are included in the free tier (across all tables).
// For example calculations, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/HowItWorks.ProvisionedThroughput.
// For limits, see https://github.com/awsdocs/amazon-dynamodb-developer-guide/blob/c420420a59040c5b3dd44a6e59f7c9e55fc922ef/doc_source/Limits.md#capacity-units-and-provisioned-throughput.md#provisioned-throughput.
- writeCapacityUnits int64
+ WriteCapacityUnits int64
+
// If the table doesn't exist yet, gokv creates it.
// If WaitForTableCreation is true, gokv will block until the table is created, with a timeout of 15 seconds.
// If the table still doesn't exist after 15 seconds, an error is returned.
@@ -53,15 +60,23 @@ type Config struct {
// In the latter case you need to make sure that you don't read from or write to the table before it's created,
// because otherwise you will get ResourceNotFoundException errors.
// Optional (true by default).
- waitForTableCreation *bool
+ WaitForTableCreation *bool
+}
+
+type Credentials struct {
+ AccessKey string
+ SecretAccessKey string
}
// ConfigDefault is the default config
var ConfigDefault = Config{
Table: "fiber_storage",
- readCapacityUnits: 5,
- writeCapacityUnits: 5,
- waitForTableCreation: aws.Bool(true),
+ Credentials: Credentials{},
+ MaxAttempts: 3,
+ Reset: false,
+ ReadCapacityUnits: 5,
+ WriteCapacityUnits: 5,
+ WaitForTableCreation: aws.Bool(true),
}
// configDefault is a helper function to set default values
@@ -78,5 +93,18 @@ func configDefault(config ...Config) Config {
if cfg.Table == "" {
cfg.Table = ConfigDefault.Table
}
+ if cfg.MaxAttempts == 0 {
+ cfg.MaxAttempts = ConfigDefault.MaxAttempts
+ }
+ if cfg.ReadCapacityUnits == 0 {
+ cfg.ReadCapacityUnits = ConfigDefault.ReadCapacityUnits
+ }
+ if cfg.WriteCapacityUnits == 0 {
+ cfg.WriteCapacityUnits = ConfigDefault.WriteCapacityUnits
+ }
+ if cfg.WaitForTableCreation == nil {
+ cfg.WaitForTableCreation = ConfigDefault.WaitForTableCreation
+ }
+
return cfg
}
diff --git a/dynamodb/dynamodb.go b/dynamodb/dynamodb.go
index e4ec9229..fa25bb71 100644
--- a/dynamodb/dynamodb.go
+++ b/dynamodb/dynamodb.go
@@ -3,90 +3,23 @@ package dynamodb
import (
"context"
"errors"
+ "fmt"
"time"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/awserr"
- "github.com/aws/aws-sdk-go/aws/credentials"
- "github.com/aws/aws-sdk-go/aws/session"
- awsdynamodb "github.com/aws/aws-sdk-go/service/dynamodb"
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/aws/retry"
+ awsconfig "github.com/aws/aws-sdk-go-v2/config"
+ "github.com/aws/aws-sdk-go-v2/credentials"
+ "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
+ awsdynamodb "github.com/aws/aws-sdk-go-v2/service/dynamodb"
+ "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
// Storage interface that is implemented by storage providers
type Storage struct {
- db *awsdynamodb.DynamoDB
- table string
-}
-
-// New creates a new storage
-func New(config Config) *Storage {
- // Set default config
- cfg := configDefault(config)
-
- // Create db
- var creds *credentials.Credentials
- if (cfg.AWSaccessKeyID != "" && cfg.AWSsecretAccessKey == "") || (cfg.AWSaccessKeyID == "" && cfg.AWSsecretAccessKey != "") {
- panic("[DynamoDB] You need to set BOTH AWSaccessKeyID AND AWSsecretAccessKey")
- } else if cfg.AWSaccessKeyID != "" {
- // Due to the previous check we can be sure that in this case AWSsecretAccessKey is not empty as well.
- creds = credentials.NewStaticCredentials(cfg.AWSaccessKeyID, cfg.AWSsecretAccessKey, "")
- }
-
- // Set database options
- opt := aws.NewConfig()
- if cfg.Region != "" {
- opt = opt.WithRegion(cfg.Region)
- }
- if creds != nil {
- opt = opt.WithCredentials(creds)
- }
- if cfg.CustomEndpoint != "" {
- opt = opt.WithEndpoint(cfg.CustomEndpoint)
- }
-
- sessionOpt := session.Options{
- SharedConfigState: session.SharedConfigEnable,
- }
-
- // ...but allow overwrite of region and credentials if they are set in the options.
- sessionOpt.Config.MergeIn(opt)
- session, err := session.NewSessionWithOptions(sessionOpt)
- if err != nil {
- panic(err)
- }
- svc := awsdynamodb.New(session)
-
- timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
- defer cancel()
- describeTableInput := awsdynamodb.DescribeTableInput{
- TableName: &cfg.Table,
- }
-
- _, err = svc.DescribeTableWithContext(timeoutCtx, &describeTableInput)
- if err != nil {
- awsErr, ok := err.(awserr.Error)
- if !ok {
- panic(err)
- } else if awsErr.Code() == awsdynamodb.ErrCodeResourceNotFoundException {
- err = createTable(cfg.Table, cfg.readCapacityUnits, cfg.writeCapacityUnits, *cfg.waitForTableCreation, describeTableInput, svc)
- if err != nil {
- panic(err)
- }
- } else {
- panic(err)
- }
- }
-
- // Create storage
- store := &Storage{
- db: svc,
- table: cfg.Table,
- }
-
- // Start garbage collector
- //go store.gc()
-
- return store
+ db *awsdynamodb.Client
+ table string
+ requestTimeout time.Duration
}
// "k" is used as table column name for the key.
@@ -95,126 +28,182 @@ var keyAttrName = "k"
// "v" is used as table column name for the value.
var valAttrName = "v"
+type table struct {
+ K string
+ V []byte
+}
+
+// New creates a new storage
+func New(config Config) *Storage {
+ // Set default config
+ cfg := configDefault(config)
+
+ awscfg, err := returnAWSConfig(cfg)
+ if err != nil {
+ panic(fmt.Sprintf("unable to load SDK config, %v", err))
+ }
+
+ // Create db
+ sess := awsdynamodb.NewFromConfig(awscfg)
+
+ timeoutCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+ describeTableInput := awsdynamodb.DescribeTableInput{
+ TableName: &cfg.Table,
+ }
+
+ // Create storage
+ store := &Storage{
+ db: sess,
+ table: cfg.Table,
+ }
+
+ // Create table
+ _, err = sess.DescribeTable(timeoutCtx, &describeTableInput)
+ if err != nil {
+ var rnfe *types.ResourceNotFoundException
+ if errors.As(err, &rnfe) {
+ err := store.createTable(cfg, describeTableInput)
+ if err != nil {
+ panic(err)
+ }
+ } else {
+ panic(err)
+ }
+ }
+
+ return store
+}
+
// Get value by key
func (s *Storage) Get(key string) ([]byte, error) {
- k := make(map[string]*awsdynamodb.AttributeValue)
- k[keyAttrName] = &awsdynamodb.AttributeValue{
- S: &key,
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
+ k := make(map[string]types.AttributeValue)
+ k[keyAttrName] = &types.AttributeValueMemberS{
+ Value: key,
}
getItemInput := awsdynamodb.GetItemInput{
TableName: &s.table,
Key: k,
}
- getItemOutput, err := s.db.GetItem(&getItemInput)
+ getItemOutput, err := s.db.GetItem(ctx, &getItemInput)
if err != nil {
+ var rnfe *types.ResourceNotFoundException
+ if errors.As(err, &rnfe) {
+ return nil, nil
+ }
+
return nil, err
} else if getItemOutput.Item == nil {
return nil, nil
}
- attributeVal := getItemOutput.Item[valAttrName]
- if attributeVal == nil {
- return nil, nil
- }
- return attributeVal.B, nil
+
+ item := &table{}
+ err = attributevalue.UnmarshalMap(getItemOutput.Item, &item)
+
+ return item.V, err
}
-// Set key with value
// Set key with value
func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
// Ain't Nobody Got Time For That
if len(key) <= 0 || len(val) <= 0 {
return nil
}
- item := make(map[string]*awsdynamodb.AttributeValue)
- item[keyAttrName] = &awsdynamodb.AttributeValue{
- S: &key,
+
+ item := make(map[string]types.AttributeValue)
+ item[keyAttrName] = &types.AttributeValueMemberS{
+ Value: key,
}
- item[valAttrName] = &awsdynamodb.AttributeValue{
- B: val,
+ item[valAttrName] = &types.AttributeValueMemberB{
+ Value: val,
}
putItemInput := awsdynamodb.PutItemInput{
TableName: &s.table,
Item: item,
}
- _, err := s.db.PutItem(&putItemInput)
+
+ _, err := s.db.PutItem(ctx, &putItemInput)
return err
}
// Delete entry by key
func (s *Storage) Delete(key string) error {
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
// Ain't Nobody Got Time For That
if len(key) <= 0 {
return nil
}
- k := make(map[string]*awsdynamodb.AttributeValue)
- k[keyAttrName] = &awsdynamodb.AttributeValue{
- S: &key,
+
+ k := make(map[string]types.AttributeValue)
+ k[keyAttrName] = &types.AttributeValueMemberS{
+ Value: key,
}
deleteItemInput := awsdynamodb.DeleteItemInput{
TableName: &s.table,
Key: k,
}
- _, err := s.db.DeleteItem(&deleteItemInput)
+
+ _, err := s.db.DeleteItem(ctx, &deleteItemInput)
return err
}
// Reset all entries, including unexpired
func (s *Storage) Reset() error {
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
deleteTableInput := awsdynamodb.DeleteTableInput{
TableName: &s.table,
}
- _, err := s.db.DeleteTable(&deleteTableInput)
+ _, err := s.db.DeleteTable(ctx, &deleteTableInput)
return err
}
// Close the database
func (s *Storage) Close() error {
- // In the DynamoDB implementation this doesn't have any effect.
return nil
}
-// GC deletes all expired entries
-// func (s *Storage) gc() {
-// ticker := time.NewTicker(s.gcInterval)
-// defer ticker.Stop()
-// for {
-// select {
-// case <-s.done:
-// return
-// case t := <-ticker.C:
-// _, _ = s.db.Exec(s.sqlGC, t.Unix())
-// }
-// }
-// }
+func (s *Storage) createTable(cfg Config, describeTableInput awsdynamodb.DescribeTableInput) error {
+ ctx, cancel := s.requestContext()
+ defer cancel()
-func createTable(tableName string, readCapacityUnits, writeCapacityUnits int64, waitForTableCreation bool, describeTableInput awsdynamodb.DescribeTableInput, svc *awsdynamodb.DynamoDB) error {
keyAttrType := "S" // For "string"
keyType := "HASH" // As opposed to "RANGE"
+
createTableInput := awsdynamodb.CreateTableInput{
- TableName: &tableName,
- AttributeDefinitions: []*awsdynamodb.AttributeDefinition{{
+ TableName: &s.table,
+ AttributeDefinitions: []types.AttributeDefinition{{
AttributeName: &keyAttrName,
- AttributeType: &keyAttrType,
+ AttributeType: types.ScalarAttributeType(keyAttrType),
}},
- KeySchema: []*awsdynamodb.KeySchemaElement{{
+ KeySchema: []types.KeySchemaElement{{
AttributeName: &keyAttrName,
- KeyType: &keyType,
+ KeyType: types.KeyType(keyType),
}},
- ProvisionedThroughput: &awsdynamodb.ProvisionedThroughput{
- ReadCapacityUnits: &readCapacityUnits,
- WriteCapacityUnits: &writeCapacityUnits,
+ ProvisionedThroughput: &types.ProvisionedThroughput{
+ ReadCapacityUnits: &cfg.ReadCapacityUnits,
+ WriteCapacityUnits: &cfg.WriteCapacityUnits,
},
}
- _, err := svc.CreateTable(&createTableInput)
+ _, err := s.db.CreateTable(ctx, &createTableInput)
if err != nil {
return err
}
// If configured (true by default), block until the table is created.
// Typical table creation duration is 10 seconds.
- if waitForTableCreation {
+ if *cfg.WaitForTableCreation {
for try := 1; try < 16; try++ {
- describeTableOutput, err := svc.DescribeTable(&describeTableInput)
- if err != nil || *describeTableOutput.Table.TableStatus == "CREATING" {
+ describeTableOutput, err := s.db.DescribeTable(ctx, &describeTableInput)
+ if err != nil || describeTableOutput.Table.TableStatus == "CREATING" {
time.Sleep(1 * time.Second)
} else {
break
@@ -222,14 +211,56 @@ func createTable(tableName string, readCapacityUnits, writeCapacityUnits int64,
}
// Last try (16th) after 15 seconds of waiting.
// Now handle error as such.
- describeTableOutput, err := svc.DescribeTable(&describeTableInput)
+ describeTableOutput, err := s.db.DescribeTable(ctx, &describeTableInput)
if err != nil {
- return errors.New("The DynamoDB table couldn't be created")
+ return errors.New("dynamodb: the table couldn't be created")
}
- if *describeTableOutput.Table.TableStatus == "CREATING" {
- return errors.New("The DynamoDB table took too long to be created")
+ if describeTableOutput.Table.TableStatus == "CREATING" {
+ return errors.New("dynamodb: the table took too long to be created")
}
}
return nil
}
+
+// Context for making requests will timeout if a non-zero timeout is configured
+func (s *Storage) requestContext() (context.Context, context.CancelFunc) {
+ if s.requestTimeout > 0 {
+ return context.WithTimeout(context.Background(), s.requestTimeout)
+ }
+ return context.Background(), func() {}
+}
+
+func returnAWSConfig(cfg Config) (aws.Config, error) {
+ endpoint := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
+ if cfg.Endpoint != "" {
+ return aws.Endpoint{
+ PartitionID: "aws",
+ URL: cfg.Endpoint,
+ SigningRegion: cfg.Region,
+ HostnameImmutable: true,
+ }, nil
+ }
+ return aws.Endpoint{}, &aws.EndpointNotFoundError{}
+ })
+
+ if cfg.Credentials != (Credentials{}) {
+ credentials := credentials.NewStaticCredentialsProvider(cfg.Credentials.AccessKey, cfg.Credentials.SecretAccessKey, "")
+ return awsconfig.LoadDefaultConfig(context.TODO(),
+ awsconfig.WithRegion(cfg.Region),
+ awsconfig.WithEndpointResolverWithOptions(endpoint),
+ awsconfig.WithCredentialsProvider(credentials),
+ awsconfig.WithRetryer(func() aws.Retryer {
+ return retry.AddWithMaxAttempts(retry.NewStandard(), cfg.MaxAttempts)
+ }),
+ )
+ }
+
+ return awsconfig.LoadDefaultConfig(context.TODO(),
+ awsconfig.WithRegion(cfg.Region),
+ awsconfig.WithEndpointResolverWithOptions(endpoint),
+ awsconfig.WithRetryer(func() aws.Retryer {
+ return retry.AddWithMaxAttempts(retry.NewStandard(), cfg.MaxAttempts)
+ }),
+ )
+}
diff --git a/dynamodb/dynamodb_test.go b/dynamodb/dynamodb_test.go
index eeacc196..d70278a2 100644
--- a/dynamodb/dynamodb_test.go
+++ b/dynamodb/dynamodb_test.go
@@ -1 +1,107 @@
package dynamodb
+
+import (
+ "testing"
+
+ "github.com/gofiber/utils"
+)
+
+var testStore = New(
+ Config{
+ Table: "fiber_storage",
+ Endpoint: "http://localhost:8000/",
+ Region: "us-east-1",
+ Credentials: Credentials{
+ AccessKey: "dummy",
+ SecretAccessKey: "dummy",
+ },
+ },
+)
+
+func Test_DynamoDB_Set(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_DynamoDB_Set_Override(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_DynamoDB_Get(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, val, result)
+}
+
+func Test_DynamoDB_Get_NotExist(t *testing.T) {
+
+ result, err := testStore.Get("notexist")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_DynamoDB_Delete(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Delete(key)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_DynamoDB_Reset(t *testing.T) {
+ var (
+ val = []byte("doe")
+ )
+
+ err := testStore.Set("john1", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set("john2", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Reset()
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get("john1")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+
+ result, err = testStore.Get("john2")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_DynamoDB_Close(t *testing.T) {
+ utils.AssertEqual(t, nil, testStore.Close())
+}
diff --git a/dynamodb/go.mod b/dynamodb/go.mod
index 801166b2..f711eba6 100644
--- a/dynamodb/go.mod
+++ b/dynamodb/go.mod
@@ -2,4 +2,11 @@ module github.com/gofiber/storage/dynamodb
go 1.14
-require github.com/aws/aws-sdk-go v1.42.46
+require (
+ github.com/aws/aws-sdk-go-v2 v1.16.3
+ github.com/aws/aws-sdk-go-v2/config v1.15.4
+ github.com/aws/aws-sdk-go-v2/credentials v1.12.0
+ github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1
+ github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4
+ github.com/gofiber/utils v0.1.2
+)
diff --git a/dynamodb/go.sum b/dynamodb/go.sum
index 3ee04b05..a9e87c44 100644
--- a/dynamodb/go.sum
+++ b/dynamodb/go.sum
@@ -1,23 +1,50 @@
-github.com/aws/aws-sdk-go v1.42.46 h1:Uehqm39VwQ+t0T7PeoFfsT1SjYRmazuTd9LMdN1JszE=
-github.com/aws/aws-sdk-go v1.42.46/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc=
+github.com/aws/aws-sdk-go-v2 v1.16.3 h1:0W1TSJ7O6OzwuEvIXAtJGvOeQ0SGAhcpxPN2/NK5EhM=
+github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
+github.com/aws/aws-sdk-go-v2/config v1.15.4 h1:P4mesY1hYUxru4f9SU0XxNKXmzfxsD0FtMIPRBjkH7Q=
+github.com/aws/aws-sdk-go-v2/config v1.15.4/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.0/go.mod h1:9YWk7VW+eyKsoIL6/CljkTrNVWBSK9pkqOPUuijid4A=
+github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1 h1:W5OvMA6XTRXs/voHKPOCSVyzhV07GzHKn5GKTDzjKx0=
+github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.9.1/go.mod h1:47xITY/Q+OIf25Z5Z3EbJkG2WxCllBjKxreRmJECDMI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4 h1:cnsvEKSoHN4oAN7spMMr0zhEW2MHnhAVpmqQg8E6UcM=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U=
+github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4 h1:M65DLU8yF7OT8h66B5ULgCdqDx3aq6KZTB2viHozSyM=
+github.com/aws/aws-sdk-go-v2/service/dynamodb v1.15.4/go.mod h1:lBz+dFsiLZcTCnIdWKUmNQLGX4CidaQqb706AIJ652M=
+github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.4 h1:q8C+UWoUI/PWVy/qaA8anr8rNeqdQKmVKN6x8zpj+6o=
+github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.13.4/go.mod h1:Ldxp5sLfT8Is7fZOIqTJ8oaVoDo+Rxu0xAYhZqnN6y8=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 h1:T4pFel53bkHjL2mMo+4DKE6r6AuoZnM0fg7k1/ratr4=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
+github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.4 h1:kkIspXTzCx1Mo8sF/UrzGkb5FmUsAnRy09DCjOKO03g=
+github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.7.4/go.mod h1:EjdPGnmBHOi9ieyuR9ck5Nguyb32/fdjoxDPVrYWYAA=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 h1:b16QW0XWl0jWjLABFc1A+uh145Oqv+xDcObNk0iQgUk=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4/go.mod h1:uKkN7qmSIsNJVyMtxNQoCEYMvFEXbOg9fwCJPdfp2u8=
+github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 h1:Uw5wBybFQ1UeA9ts0Y07gbv0ncZnIAyw858tDW0NP2o=
+github.com/aws/aws-sdk-go-v2/service/sso v1.11.4/go.mod h1:cPDwJwsP4Kff9mldCXAmddjJL6JGQqtA3Mzer2zyr88=
+github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 h1:+xtV90n3abQmgzk1pS++FdxZTrPEDgQng6e4/56WR2A=
+github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsViglqlG9eEFYxNryTZS5rn3QE=
+github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE=
+github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
+github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
+github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
-golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
diff --git a/mongodb/go.mod b/mongodb/go.mod
index e994783e..9baf543f 100644
--- a/mongodb/go.mod
+++ b/mongodb/go.mod
@@ -7,7 +7,7 @@ require (
github.com/gofiber/utils v0.1.2
github.com/golang/snappy v0.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
- go.mongodb.org/mongo-driver v1.8.3
+ go.mongodb.org/mongo-driver v1.9.1
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/text v0.3.7 // indirect
diff --git a/mongodb/go.sum b/mongodb/go.sum
index 364da9cc..b3a6a259 100644
--- a/mongodb/go.sum
+++ b/mongodb/go.sum
@@ -37,8 +37,8 @@ github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
-go.mongodb.org/mongo-driver v1.8.3 h1:TDKlTkGDKm9kkJVUOAXDK5/fkqKHJVwYQSpoRfB43R4=
-go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
+go.mongodb.org/mongo-driver v1.9.1 h1:m078y9v7sBItkt1aaoe2YlvWEXcD263e1a4E1fBrJ1c=
+go.mongodb.org/mongo-driver v1.9.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
diff --git a/postgres/go.mod b/postgres/go.mod
index 0e804cdd..b7575326 100644
--- a/postgres/go.mod
+++ b/postgres/go.mod
@@ -14,4 +14,5 @@ require (
golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
+ github.com/lib/pq v1.10.5
)
diff --git a/postgres/go.sum b/postgres/go.sum
index f63e2577..bd4ad919 100644
--- a/postgres/go.sum
+++ b/postgres/go.sum
@@ -200,3 +200,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
\ No newline at end of file
diff --git a/postgres/postgres.go b/postgres/postgres.go
index ac0dc6b9..37f96117 100644
--- a/postgres/postgres.go
+++ b/postgres/postgres.go
@@ -56,12 +56,16 @@ func New(config ...Config) *Storage {
if cfg.Username != "" || cfg.Password != "" {
dsn += "@"
}
- dsn += fmt.Sprintf("%s:%d", url.QueryEscape(cfg.Host), cfg.Port)
+ // unix socket host path
+ if strings.HasPrefix(cfg.Host, "/") {
+ dsn += fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
+ } else {
+ dsn += fmt.Sprintf("%s:%d", url.QueryEscape(cfg.Host), cfg.Port)
+ }
dsn += fmt.Sprintf("/%s?connect_timeout=%d&sslmode=%s",
url.QueryEscape(cfg.Database),
int64(cfg.timeout.Seconds()),
- cfg.SslMode,
- )
+ cfg.SslMode)
// Create db
db, err := sql.Open("postgres", dsn)
diff --git a/redis/README.md b/redis/README.md
index 4bedeca8..16f12bbc 100644
--- a/redis/README.md
+++ b/redis/README.md
@@ -68,7 +68,7 @@ type Config struct {
// Port where the DB is listening on
//
- // Optional. Default is 3306
+ // Optional. Default is 6379
Port int
// Server username
diff --git a/redis/config.go b/redis/config.go
index 4734e22b..1a0876d6 100644
--- a/redis/config.go
+++ b/redis/config.go
@@ -11,7 +11,7 @@ type Config struct {
// Port where the DB is listening on
//
- // Optional. Default is 3306
+ // Optional. Default is 6379
Port int
// Server username
diff --git a/redis/go.mod b/redis/go.mod
index ce4dae19..60d30a4f 100644
--- a/redis/go.mod
+++ b/redis/go.mod
@@ -3,6 +3,7 @@ module github.com/gofiber/storage/redis
go 1.14
require (
- github.com/go-redis/redis/v8 v8.11.4
+ github.com/go-redis/redis/v8 v8.11.5
github.com/gofiber/utils v0.1.2
+ github.com/google/go-cmp v0.5.6 // indirect
)
diff --git a/redis/go.sum b/redis/go.sum
index 00141442..56028444 100644
--- a/redis/go.sum
+++ b/redis/go.sum
@@ -1,5 +1,8 @@
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
@@ -7,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
-github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
@@ -28,18 +31,24 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
+github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
+github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
-github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
-github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -64,12 +73,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/ristretto/ristretto_test.go b/ristretto/ristretto_test.go
index 807ba067..b424273b 100644
--- a/ristretto/ristretto_test.go
+++ b/ristretto/ristretto_test.go
@@ -42,6 +42,9 @@ func Test_Ristretto_Get(t *testing.T) {
err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err)
+ // stabilize with some delay in between -> bug already communicated
+ time.Sleep(10000)
+
result, err := testStore.Get(key)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, val, result)
@@ -86,6 +89,9 @@ func Test_Ristretto_Delete(t *testing.T) {
err := testStore.Set(key, val, 0)
utils.AssertEqual(t, nil, err)
+ // stabilize with some delay in between -> bug already communicated
+ time.Sleep(10000)
+
err = testStore.Delete(key)
utils.AssertEqual(t, nil, err)
diff --git a/s3/README.md b/s3/README.md
new file mode 100644
index 00000000..78bce204
--- /dev/null
+++ b/s3/README.md
@@ -0,0 +1,108 @@
+# S3
+
+A S3 storage driver using [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2).
+
+**Note:** If config fields of credentials not given, credentials are using from the environment variables, ~/.aws/credentials, or EC2 instance role. If config fields of credentials given, credentials are using from config. Look at: [specifying credentials](https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#specifying-credentials)
+
+
+### Table of Contents
+- [Signatures](#signatures)
+- [Installation](#installation)
+- [Examples](#examples)
+- [Config](#config)
+- [Default Config](#default-config)
+
+### Signatures
+```go
+func New(config ...Config) Storage
+func (s *Storage) Get(key string) ([]byte, error)
+func (s *Storage) Set(key string, val []byte, exp time.Duration) error
+func (s *Storage) Delete(key string) error
+func (s *Storage) Reset() error
+func (s *Storage) Close() error
+```
+### Installation
+S3 is tested on the 2 last [Go versions](https://golang.org/dl/) with support for modules. So make sure to initialize one first if you didn't do that yet:
+```bash
+go mod init github.com//
+```
+And then install the s3 implementation:
+```bash
+go get github.com/gofiber/storage/s3
+```
+
+### Examples
+Import the storage package.
+```go
+import "github.com/gofiber/storage/s3"
+```
+
+You can use the following possibilities to create a storage:
+```go
+// Initialize default config
+store := s3.New()
+
+// Initialize custom config
+store := s3.New(s3.Config{
+ Bucket: "my-bucket-url",
+ Endpoint: "my-endpoint",
+ Region: "my-region",
+ Reset: false,
+})
+```
+
+### Config
+```go
+// Config defines the config for storage.
+type Config struct {
+ // S3 bucket name
+ Bucket string
+
+ // AWS endpoint
+ Endpoint string
+
+ // AWS region
+ Region string
+
+ // Request timeout
+ //
+ // Optional. Default is 0 (no timeout)
+ RequestTimeout time.Duration
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
+
+ // Credentials overrides AWS access key and AWS secret access key. Not recommended.
+ //
+ // Optional. Default is Credentials{}
+ Credentials Credentials
+
+ // The maximum number of times requests that encounter retryable failures should be attempted.
+ //
+ // Optional. Default is 3
+ MaxAttempts int
+
+}
+
+type Credentials struct {
+ AccessKey string
+ SecretAccessKey string
+}
+```
+
+### Default Config
+The default configuration lacks Bucket, Region, and Endpoint which are all required and must be overwritten:
+```go
+// ConfigDefault is the default config
+var ConfigDefault = Config{
+ Bucket: "",
+ Region: "",
+ Endpoint: "",
+ Credentials: Credentials{},
+ MaxAttempts: 3,
+ RequestTimeout: 0,
+ Reset: false,
+}
+```
diff --git a/s3/config.go b/s3/config.go
new file mode 100644
index 00000000..fadb1777
--- /dev/null
+++ b/s3/config.go
@@ -0,0 +1,69 @@
+package s3
+
+import "time"
+
+// Config defines the config for storage.
+type Config struct {
+ // S3 bucket name
+ Bucket string
+
+ // AWS endpoint
+ Endpoint string
+
+ // AWS region
+ Region string
+
+ // Request timeout
+ //
+ // Optional. Default is 0 (no timeout)
+ RequestTimeout time.Duration
+
+ // Reset clears any existing keys in existing Bucket
+ //
+ // Optional. Default is false
+ Reset bool
+
+ // Credentials overrides AWS access key and AWS secret access key. Not recommended.
+ //
+ // Optional. Default is Credentials{}
+ Credentials Credentials
+
+ // The maximum number of times requests that encounter retryable failures should be attempted.
+ //
+ // Optional. Default is 3
+ MaxAttempts int
+}
+
+type Credentials struct {
+ AccessKey string
+ SecretAccessKey string
+}
+
+// ConfigDefault is the default config
+var ConfigDefault = Config{
+ Bucket: "",
+ Region: "",
+ Endpoint: "",
+ Credentials: Credentials{},
+ MaxAttempts: 3,
+ RequestTimeout: 0,
+ Reset: false,
+}
+
+// Helper function to set default values
+func configDefault(config ...Config) Config {
+ // Return default config if nothing provided
+ if len(config) < 1 {
+ return ConfigDefault
+ }
+
+ // Override default config
+ cfg := config[0]
+
+ // Set default values
+ if cfg.Bucket == "" {
+ cfg.Bucket = ConfigDefault.Bucket
+ }
+
+ return cfg
+}
diff --git a/s3/go.mod b/s3/go.mod
new file mode 100644
index 00000000..ab274bf9
--- /dev/null
+++ b/s3/go.mod
@@ -0,0 +1,12 @@
+module github.com/gofiber/storage/s3
+
+go 1.16
+
+require (
+ github.com/aws/aws-sdk-go-v2 v1.13.0
+ github.com/aws/aws-sdk-go-v2/config v1.13.1
+ github.com/aws/aws-sdk-go-v2/credentials v1.8.0
+ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.24.1
+ github.com/gofiber/utils v0.1.2
+)
diff --git a/s3/go.sum b/s3/go.sum
new file mode 100644
index 00000000..3803e843
--- /dev/null
+++ b/s3/go.sum
@@ -0,0 +1,51 @@
+github.com/aws/aws-sdk-go-v2 v1.13.0 h1:1XIXAfxsEmbhbj5ry3D3vX+6ZcUYvIqSm4CWWEuGZCA=
+github.com/aws/aws-sdk-go-v2 v1.13.0/go.mod h1:L6+ZpqHaLbAaxsqV0L4cvxZY7QupWJB4fhkf8LXvC7w=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.2.0 h1:scBthy70MB3m4LCMFaBcmYCyR2XWOz6MxSfdSu/+fQo=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.2.0/go.mod h1:oZHzg1OVbuCiRTY0oRPM+c2HQvwnFCGJwKeSqqAJ/yM=
+github.com/aws/aws-sdk-go-v2/config v1.13.1 h1:yLv8bfNoT4r+UvUKQKqRtdnvuWGMK5a82l4ru9Jvnuo=
+github.com/aws/aws-sdk-go-v2/config v1.13.1/go.mod h1:Ba5Z4yL/UGbjQUzsiaN378YobhFo0MLfueXGiOsYtEs=
+github.com/aws/aws-sdk-go-v2/credentials v1.8.0 h1:8Ow0WcyDesGNL0No11jcgb1JAtE+WtubqXjgxau+S0o=
+github.com/aws/aws-sdk-go-v2/credentials v1.8.0/go.mod h1:gnMo58Vwx3Mu7hj1wpcG8DI0s57c9o42UQ6wgTQT5to=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0 h1:NITDuUZO34mqtOwFWZiXo7yAHj7kf+XPE+EiKuCBNUI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.10.0/go.mod h1:I6/fHT/fH460v09eg2gVrd8B/IqskhNdpcLH0WNO3QI=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1 h1:oUCLhAKNaXyTqdJyw+KEjDVVBs1V5mCy8YDLMi08LL8=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.9.1/go.mod h1:pB38jI+AdaPoLAgaL9bwxDdy6rjwO6LIArBZDLjq6zs=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4 h1:CRiQJ4E2RhfDdqbie1ZYDo8QtIo75Mk7oTdJSfwJTMQ=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.4/go.mod h1:XHgQ7Hz2WY2GAn//UXHofLfPXWh+s62MbMOijrg12Lw=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0 h1:3ADoioDMOtF4uiK59vCpplpCwugEU+v4ZFD29jDL3RQ=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.2.0/go.mod h1:BsCSJHx5DnDXIrOcqB8KN1/B+hXLG/bi4Y6Vjcx/x9E=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5 h1:ixotxbfTCFpqbuwFv/RcZwyzhkxPSYDYEMcj4niB5Uk=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.5/go.mod h1:R3sWUqPcfXSiF/LSFJhjyJmpg9uV6yP2yv3YZZjldVI=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.7.0 h1:F1diQIOkNn8jcez4173r+PLPdkWK7chy74r3fKpDrLI=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.7.0/go.mod h1:8ctElVINyp+SjhoZZceUAZw78glZH6R8ox5MVNu5j2s=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0 h1:4QAOB3KrvI1ApJK14sliGr3Ie2pjyvNypn/lfzDHfUw=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.7.0/go.mod h1:K/qPe6AP2TGYv4l6n7c88zh9jWBDf6nHhvg1fx/EWfU=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.11.0 h1:XAe+PDnaBELHr25qaJKfB415V4CKFWE8H+prUreql8k=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.11.0/go.mod h1:RMlgnt1LbOT2BxJ3cdw+qVz7KL84714LFkWtF6sLI7A=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.24.1 h1:zAU2P99CLTz8kUGl+IptU2ycAXuMaLAvgIv+UH4U8pY=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.24.1/go.mod h1:oIUXg/5F0x0gy6nkwEnlxZboueddwPEKO6Xl+U6/3a0=
+github.com/aws/aws-sdk-go-v2/service/sso v1.9.0 h1:1qLJeQGBmNQW3mBNzK2CFmrQNmoXWrscPqsrAaU1aTA=
+github.com/aws/aws-sdk-go-v2/service/sso v1.9.0/go.mod h1:vCV4glupK3tR7pw7ks7Y4jYRL86VvxS+g5qk04YeWrU=
+github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 h1:ksiDXhvNYg0D2/UFkLejsaz3LqpW5yjNQ8Nx9Sn2c0E=
+github.com/aws/aws-sdk-go-v2/service/sts v1.14.0/go.mod h1:u0xMJKDvvfocRjiozsoZglVNXRG19043xzp3r2ivLIk=
+github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w=
+github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
+github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/s3/s3.go b/s3/s3.go
new file mode 100644
index 00000000..da328a51
--- /dev/null
+++ b/s3/s3.go
@@ -0,0 +1,202 @@
+package s3
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/aws/aws-sdk-go-v2/aws"
+ "github.com/aws/aws-sdk-go-v2/aws/retry"
+ awsconfig "github.com/aws/aws-sdk-go-v2/config"
+ "github.com/aws/aws-sdk-go-v2/credentials"
+ "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
+ "github.com/aws/aws-sdk-go-v2/service/s3"
+ "github.com/aws/aws-sdk-go-v2/service/s3/types"
+)
+
+// Storage interface that is implemented by storage providers
+type Storage struct {
+ svc *s3.Client
+ downloader *manager.Downloader
+ uploader *manager.Uploader
+ requestTimeout time.Duration
+ bucket string
+}
+
+// New creates a new storage
+func New(config ...Config) *Storage {
+ // Set default config
+ cfg := configDefault(config...)
+
+ // Create s3 session
+ // If config fields of credentials not given, credentials are using from the environment variables, ~/.aws/credentials, or EC2 instance role.
+ // If config fields of credentials given, credentials are using from config.
+ //
+ // Look at: https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/#specifying-credentials
+ awscfg, err := returnAWSConfig(cfg)
+ if err != nil {
+ panic(fmt.Sprintf("unable to load SDK config, %v", err))
+ }
+
+ sess := s3.NewFromConfig(awscfg)
+ storage := &Storage{
+ svc: sess,
+ downloader: manager.NewDownloader(sess),
+ uploader: manager.NewUploader(sess),
+ requestTimeout: cfg.RequestTimeout,
+ bucket: cfg.Bucket,
+ }
+
+ // Reset all entries if set to true
+ if cfg.Reset {
+ if err := storage.Reset(); err != nil {
+ panic(err)
+ }
+ }
+
+ return storage
+}
+
+// Get value by key
+func (s *Storage) Get(key string) ([]byte, error) {
+ var nsk *types.NoSuchKey
+
+ if len(key) <= 0 {
+ return nil, nil
+ }
+
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
+ buf := manager.NewWriteAtBuffer([]byte{})
+
+ _, err := s.downloader.Download(ctx, buf, &s3.GetObjectInput{
+ Bucket: &s.bucket,
+ Key: aws.String(key),
+ })
+ if errors.As(err, &nsk) {
+ return nil, nil
+ }
+
+ return buf.Bytes(), err
+}
+
+// Set key with value
+func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
+ if len(key) <= 0 {
+ return nil
+ }
+
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
+ _, err := s.uploader.Upload(ctx, &s3.PutObjectInput{
+ Bucket: &s.bucket,
+ Key: aws.String(key),
+ Body: bytes.NewReader(val),
+ })
+
+ return err
+}
+
+// Delete entry by key
+func (s *Storage) Delete(key string) error {
+ if len(key) <= 0 {
+ return nil
+ }
+
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
+ _, err := s.svc.DeleteObject(ctx, &s3.DeleteObjectInput{
+ Bucket: &s.bucket,
+ Key: aws.String(key),
+ })
+
+ return err
+}
+
+// Reset all entries, including unexpired
+func (s *Storage) Reset() error {
+ ctx, cancel := s.requestContext()
+ defer cancel()
+
+ paginator := s3.NewListObjectsV2Paginator(s.svc, &s3.ListObjectsV2Input{
+ Bucket: &s.bucket,
+ })
+
+ for paginator.HasMorePages() {
+ page, err := paginator.NextPage(ctx)
+ if err != nil {
+ return err
+ }
+
+ var objects []types.ObjectIdentifier
+ for _, object := range page.Contents {
+ objects = append(objects, types.ObjectIdentifier{
+ Key: object.Key,
+ })
+ }
+
+ _, err = s.svc.DeleteObjects(ctx, &s3.DeleteObjectsInput{
+ Bucket: &s.bucket,
+ Delete: &types.Delete{
+ Objects: objects,
+ },
+ })
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Close the database
+func (s *Storage) Close() error {
+ return nil
+}
+
+// Context for making requests will timeout if a non-zero timeout is configured
+func (s *Storage) requestContext() (context.Context, context.CancelFunc) {
+ if s.requestTimeout > 0 {
+ return context.WithTimeout(context.Background(), s.requestTimeout)
+ }
+ return context.Background(), func() {}
+}
+
+func returnAWSConfig(cfg Config) (aws.Config, error) {
+ endpoint := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
+ if cfg.Endpoint != "" {
+ return aws.Endpoint{
+ PartitionID: "aws",
+ URL: cfg.Endpoint,
+ SigningRegion: cfg.Region,
+ HostnameImmutable: true,
+ }, nil
+ }
+ return aws.Endpoint{}, &aws.EndpointNotFoundError{}
+ })
+
+ if cfg.Credentials != (Credentials{}) {
+ credentials := credentials.NewStaticCredentialsProvider(cfg.Credentials.AccessKey, cfg.Credentials.SecretAccessKey, "")
+ return awsconfig.LoadDefaultConfig(context.TODO(),
+ awsconfig.WithRegion(cfg.Region),
+ awsconfig.WithEndpointResolverWithOptions(endpoint),
+ awsconfig.WithCredentialsProvider(credentials),
+ awsconfig.WithRetryer(func() aws.Retryer {
+ return retry.AddWithMaxAttempts(retry.NewStandard(), cfg.MaxAttempts)
+ }),
+ )
+ }
+
+ return awsconfig.LoadDefaultConfig(context.TODO(),
+ awsconfig.WithRegion(cfg.Region),
+ awsconfig.WithEndpointResolverWithOptions(endpoint),
+ awsconfig.WithRetryer(func() aws.Retryer {
+ return retry.AddWithMaxAttempts(retry.NewStandard(), cfg.MaxAttempts)
+ }),
+ )
+}
diff --git a/s3/s3_test.go b/s3/s3_test.go
new file mode 100644
index 00000000..7b3f27fe
--- /dev/null
+++ b/s3/s3_test.go
@@ -0,0 +1,107 @@
+package s3
+
+import (
+ "testing"
+
+ "github.com/gofiber/utils"
+)
+
+var testStore = New(
+ Config{
+ Bucket: "testbucket",
+ Endpoint: "http://127.0.0.1:9000/",
+ Region: "us-east-1",
+ Credentials: Credentials{
+ AccessKey: "minioadmin",
+ SecretAccessKey: "minioadmin",
+ },
+ },
+)
+
+func Test_S3_Set(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_S3_Set_Override(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+}
+
+func Test_S3_Get(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, val, result)
+}
+
+func Test_S3_Get_NotExist(t *testing.T) {
+
+ result, err := testStore.Get("notexist")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_S3_Delete(t *testing.T) {
+ var (
+ key = "john"
+ val = []byte("doe")
+ )
+
+ err := testStore.Set(key, val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Delete(key)
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get(key)
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_S3_Reset(t *testing.T) {
+ var (
+ val = []byte("doe")
+ )
+
+ err := testStore.Set("john1", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Set("john2", val, 0)
+ utils.AssertEqual(t, nil, err)
+
+ err = testStore.Reset()
+ utils.AssertEqual(t, nil, err)
+
+ result, err := testStore.Get("john1")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+
+ result, err = testStore.Get("john2")
+ utils.AssertEqual(t, nil, err)
+ utils.AssertEqual(t, true, len(result) == 0)
+}
+
+func Test_S3_Close(t *testing.T) {
+ utils.AssertEqual(t, nil, testStore.Close())
+}
diff --git a/sqlite3/go.mod b/sqlite3/go.mod
index a09d283e..842364e9 100644
--- a/sqlite3/go.mod
+++ b/sqlite3/go.mod
@@ -4,5 +4,5 @@ go 1.14
require (
github.com/gofiber/utils v0.1.2
- github.com/mattn/go-sqlite3 v1.14.11
+ github.com/mattn/go-sqlite3 v1.14.13
)
diff --git a/sqlite3/go.sum b/sqlite3/go.sum
index 2c69d84e..7b24a1d3 100644
--- a/sqlite3/go.sum
+++ b/sqlite3/go.sum
@@ -1,4 +1,4 @@
github.com/gofiber/utils v0.1.2 h1:1SH2YEz4RlNS0tJlMJ0bGwO0JkqPqvq6TbHK9tXZKtk=
github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc=
-github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
-github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
+github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
+github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=