Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

251 рядки
5.4KB

  1. package cache
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. )
  7. // Option for get/set/delete methods.
  8. type Option func(*Item)
  9. // Configure configure cache.
  10. type Configure func(*Cache)
  11. // WithDataOption sets cache default data options.
  12. func WithDataOption(do ...Option) Configure {
  13. return func(c *Cache) {
  14. factory := c.dataFactory
  15. c.dataFactory = func(key, value interface{}, opts ...Option) *Item {
  16. return factory(key, value, append(do, opts...)...)
  17. }
  18. }
  19. }
  20. // WithHandleDelete sets handlers delete.
  21. func WithHandleDelete(h ...Handle) Configure {
  22. return func(m *Cache) {
  23. m.delete = chain(m.delete, h...)
  24. }
  25. }
  26. // WithHandle sets get/set/delete handler.
  27. func WithHandle(get, set, delete Handle) Configure {
  28. return func(c *Cache) {
  29. if set != nil {
  30. c.set = chain(c.set, set)
  31. }
  32. if get != nil {
  33. c.get = chain(c.get, get)
  34. }
  35. if delete != nil {
  36. c.delete = chain(c.delete, delete)
  37. }
  38. }
  39. }
  40. // WithHandleCache add handler by cache operation type.
  41. func WithHandleCache(handlers ...func() (Operation, func(ctx context.Context, c *Cache, item *Item, next Init) error)) Configure {
  42. return func(c *Cache) {
  43. for _, factory := range handlers {
  44. op, h := factory()
  45. switch op {
  46. case OperationSet:
  47. c.set = chain(c.set, func(ctx context.Context, item *Item, next Init) error {
  48. return h(ctx, c, item, next)
  49. })
  50. case OperationGet:
  51. c.get = chain(c.get, func(ctx context.Context, item *Item, next Init) error {
  52. return h(ctx, c, item, next)
  53. })
  54. case OperationDelete:
  55. c.delete = chain(c.delete, func(ctx context.Context, item *Item, next Init) error {
  56. return h(ctx, c, item, next)
  57. })
  58. }
  59. }
  60. }
  61. }
  62. // WithHandleSet sets handlers set.
  63. func WithHandleSet(h ...Handle) Configure {
  64. return func(m *Cache) {
  65. m.set = chain(m.set, h...)
  66. }
  67. }
  68. // WithHandleGet sets handlers get.
  69. func WithHandleGet(h ...Handle) Configure {
  70. return func(m *Cache) {
  71. m.get = chain(m.get, h...)
  72. }
  73. }
  74. // WithNamespace sets prefix and separator.
  75. func WithNamespace(prefix, sep string) Option {
  76. return func(d *Item) {
  77. d.Key.Prefix = prefix
  78. d.Key.Separator = sep
  79. }
  80. }
  81. // WithTTL sets ttl.
  82. func WithTTL(ttl time.Duration) Option {
  83. return func(d *Item) {
  84. d.TTL = ttl
  85. }
  86. }
  87. // New creates new cache by provider.
  88. func New(prov Provider, opts ...Configure) *Cache {
  89. c := &Cache{
  90. get: prov.Get,
  91. set: prov.Set,
  92. delete: prov.Delete,
  93. dataFactory: NewItem,
  94. }
  95. for _, o := range opts {
  96. o(c)
  97. }
  98. return c
  99. }
  100. // Provider cache.
  101. type Provider interface {
  102. Delete(ctx context.Context, d *Item) error
  103. Get(ctx context.Context, d *Item) error
  104. Set(ctx context.Context, d *Item) error
  105. }
  106. // Cache base cache.
  107. type Cache struct {
  108. dataFactory func(key, value interface{}, opts ...Option) *Item
  109. set Init
  110. get Init
  111. delete Init
  112. }
  113. // Init func for get/set/delete.
  114. type Init func(ctx context.Context, item *Item) error
  115. // Handle middlewaare brfore/after init method.
  116. type Handle func(ctx context.Context, item *Item, next Init) error
  117. // Set handles middlewares and sets value by key and options.
  118. func (c *Cache) Set(ctx context.Context, key, value interface{}, opts ...Option) error {
  119. return c.set(ctx, c.dataFactory(key, value, opts...))
  120. }
  121. // Get handles middlewares and gets value by key and options.
  122. func (c *Cache) Get(ctx context.Context, key, value interface{}, opts ...Option) error {
  123. return c.get(ctx, c.dataFactory(key, value, opts...))
  124. }
  125. // Delete handles middlewares and delete value by key and options.
  126. func (c *Cache) Delete(ctx context.Context, key interface{}, opts ...Option) error {
  127. return c.delete(ctx, c.dataFactory(key, nil, opts...))
  128. }
  129. // NewItem creates new item and configure them for provider.
  130. func NewItem(key, value interface{}, opts ...Option) *Item {
  131. d := &Item{
  132. Key: Key{
  133. Key: key,
  134. },
  135. Value: value,
  136. }
  137. for _, o := range opts {
  138. o(d)
  139. }
  140. return d
  141. }
  142. // Item to get/set/delete in provider.
  143. type Item struct {
  144. Key Key
  145. Value interface{}
  146. TTL time.Duration
  147. }
  148. // CopyTo copy iyem to target.
  149. func (i *Item) CopyTo(target *Item) error {
  150. target.TTL = i.TTL
  151. return TypeAssert(i.Value, target.Value)
  152. }
  153. // IsExpired checks expired item.
  154. func (i *Item) IsExpired() bool {
  155. return i.TTL < 0
  156. }
  157. // Options gets item options.
  158. func (i *Item) Options() []Option {
  159. opts := []Option{
  160. WithTTL(i.TTL),
  161. }
  162. if i.Key.Prefix != "" {
  163. opts = append(opts, WithNamespace(i.Key.Prefix, i.Key.Separator))
  164. }
  165. return opts
  166. }
  167. // TTLInSecond sets ttl by seconds.
  168. func (i *Item) TTLInSecond(in int64) {
  169. i.TTL = time.Second * time.Duration(in)
  170. }
  171. // Expired gets expired time by ttl.
  172. func (i *Item) Expired() time.Time {
  173. return time.Now().Add(i.TTL)
  174. }
  175. // Key with prefix and separator.
  176. type Key struct {
  177. Key interface{}
  178. Prefix string
  179. Separator string
  180. }
  181. // String return prefix+separator+key for key.
  182. func (k Key) String() string {
  183. return fmt.Sprint(k.Prefix, k.Separator, k.Key)
  184. }
  185. func chain(init Init, handleFunc ...Handle) Init {
  186. n := len(handleFunc)
  187. if n > 0 {
  188. lastI := n - 1
  189. return func(ctx context.Context, d *Item) error {
  190. var (
  191. chainHandler func(ctx context.Context, d *Item) error
  192. curI int
  193. )
  194. chainHandler = func(currentCtx context.Context, currentData *Item) error {
  195. if curI == lastI {
  196. return init(currentCtx, currentData)
  197. }
  198. curI++
  199. err := handleFunc[curI](currentCtx, currentData, chainHandler)
  200. curI--
  201. return err
  202. }
  203. return handleFunc[0](ctx, d, chainHandler)
  204. }
  205. }
  206. return init
  207. }