-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathconfig.go
125 lines (97 loc) · 3.05 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package idempotency
import (
"errors"
"fmt"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/internal/storage/memory"
)
var ErrInvalidIdempotencyKey = errors.New("invalid idempotency key")
// Config defines the config for middleware.
type Config struct {
// Lock locks an idempotency key.
//
// Optional. Default: an in-memory locker for this process only.
Lock Locker
// Storage stores response data by idempotency key.
//
// Optional. Default: an in-memory storage for this process only.
Storage fiber.Storage
// Next defines a function to skip this middleware when returned true.
//
// Optional. Default: a function which skips the middleware on safe HTTP request method.
Next func(c fiber.Ctx) bool
// KeyHeaderValidate defines a function to validate the syntax of the idempotency header.
//
// Optional. Default: a function which ensures the header is 36 characters long (the size of an UUID).
KeyHeaderValidate func(string) error
// KeyHeader is the name of the header that contains the idempotency key.
//
// Optional. Default: X-Idempotency-Key
KeyHeader string
// KeepResponseHeaders is a list of headers that should be kept from the original response.
//
// Optional. Default: nil (to keep all headers)
KeepResponseHeaders []string
// Lifetime is the maximum lifetime of an idempotency key.
//
// Optional. Default: 30 * time.Minute
Lifetime time.Duration
}
// ConfigDefault is the default config
var ConfigDefault = Config{
Next: func(c fiber.Ctx) bool {
// Skip middleware if the request was done using a safe HTTP method
return fiber.IsMethodSafe(c.Method())
},
Lifetime: 30 * time.Minute,
KeyHeader: "X-Idempotency-Key",
KeyHeaderValidate: func(k string) error {
if l, wl := len(k), 36; l != wl { // UUID length is 36 chars
return fmt.Errorf("%w: invalid length: %d != %d", ErrInvalidIdempotencyKey, l, wl)
}
return nil
},
KeepResponseHeaders: nil,
Lock: nil, // Set in configDefault so we don't allocate data here.
Storage: nil, // Set in configDefault so we don't allocate data here.
}
// Helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
cfg := ConfigDefault
cfg.Lock = NewMemoryLock()
cfg.Storage = memory.New(memory.Config{
GCInterval: cfg.Lifetime / 2, // Half the lifetime interval
})
return cfg
}
// Override default config
cfg := config[0]
// Set default values
if cfg.Next == nil {
cfg.Next = ConfigDefault.Next
}
if cfg.Lifetime.Nanoseconds() == 0 {
cfg.Lifetime = ConfigDefault.Lifetime
}
if cfg.KeyHeader == "" {
cfg.KeyHeader = ConfigDefault.KeyHeader
}
if cfg.KeyHeaderValidate == nil {
cfg.KeyHeaderValidate = ConfigDefault.KeyHeaderValidate
}
if cfg.KeepResponseHeaders != nil && len(cfg.KeepResponseHeaders) == 0 {
cfg.KeepResponseHeaders = ConfigDefault.KeepResponseHeaders
}
if cfg.Lock == nil {
cfg.Lock = NewMemoryLock()
}
if cfg.Storage == nil {
cfg.Storage = memory.New(memory.Config{
GCInterval: cfg.Lifetime / 2,
})
}
return cfg
}