github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/queue/queue.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 package queue 7 8 import ( 9 "context" 10 "fmt" 11 "time" 12 ) 13 14 // ErrInvalidConfiguration is called when there is invalid configuration for a queue 15 type ErrInvalidConfiguration struct { 16 cfg interface{} 17 err error 18 } 19 20 func (err ErrInvalidConfiguration) Error() string { 21 if err.err != nil { 22 return fmt.Sprintf("Invalid Configuration Argument: %v: Error: %v", err.cfg, err.err) 23 } 24 return fmt.Sprintf("Invalid Configuration Argument: %v", err.cfg) 25 } 26 27 // IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration 28 func IsErrInvalidConfiguration(err error) bool { 29 _, ok := err.(ErrInvalidConfiguration) 30 return ok 31 } 32 33 // Type is a type of Queue 34 type Type string 35 36 // Data defines an type of queuable data 37 type Data interface{} 38 39 // HandlerFunc is a function that takes a variable amount of data and processes it 40 type HandlerFunc func(...Data) (unhandled []Data) 41 42 // NewQueueFunc is a function that creates a queue 43 type NewQueueFunc func(handler HandlerFunc, config, exemplar interface{}) (Queue, error) 44 45 // Shutdownable represents a queue that can be shutdown 46 type Shutdownable interface { 47 Shutdown() 48 Terminate() 49 } 50 51 // Named represents a queue with a name 52 type Named interface { 53 Name() string 54 } 55 56 // Queue defines an interface of a queue-like item 57 // 58 // Queues will handle their own contents in the Run method 59 type Queue interface { 60 Flushable 61 Run(atShutdown, atTerminate func(func())) 62 Push(Data) error 63 } 64 65 // PushBackable queues can be pushed back to 66 type PushBackable interface { 67 // PushBack pushes data back to the top of the fifo 68 PushBack(Data) error 69 } 70 71 // DummyQueueType is the type for the dummy queue 72 const DummyQueueType Type = "dummy" 73 74 // NewDummyQueue creates a new DummyQueue 75 func NewDummyQueue(handler HandlerFunc, opts, exemplar interface{}) (Queue, error) { 76 return &DummyQueue{}, nil 77 } 78 79 // DummyQueue represents an empty queue 80 type DummyQueue struct{} 81 82 // Run does nothing 83 func (*DummyQueue) Run(_, _ func(func())) {} 84 85 // Push fakes a push of data to the queue 86 func (*DummyQueue) Push(Data) error { 87 return nil 88 } 89 90 // PushFunc fakes a push of data to the queue with a function. The function is never run. 91 func (*DummyQueue) PushFunc(Data, func() error) error { 92 return nil 93 } 94 95 // Has always returns false as this queue never does anything 96 func (*DummyQueue) Has(Data) (bool, error) { 97 return false, nil 98 } 99 100 // Flush always returns nil 101 func (*DummyQueue) Flush(time.Duration) error { 102 return nil 103 } 104 105 // FlushWithContext always returns nil 106 func (*DummyQueue) FlushWithContext(context.Context) error { 107 return nil 108 } 109 110 // IsEmpty asserts that the queue is empty 111 func (*DummyQueue) IsEmpty() bool { 112 return true 113 } 114 115 // ImmediateType is the type to execute the function when push 116 const ImmediateType Type = "immediate" 117 118 // NewImmediate creates a new false queue to execute the function when push 119 func NewImmediate(handler HandlerFunc, opts, exemplar interface{}) (Queue, error) { 120 return &Immediate{ 121 handler: handler, 122 }, nil 123 } 124 125 // Immediate represents an direct execution queue 126 type Immediate struct { 127 handler HandlerFunc 128 } 129 130 // Run does nothing 131 func (*Immediate) Run(_, _ func(func())) {} 132 133 // Push fakes a push of data to the queue 134 func (q *Immediate) Push(data Data) error { 135 return q.PushFunc(data, nil) 136 } 137 138 // PushFunc fakes a push of data to the queue with a function. The function is never run. 139 func (q *Immediate) PushFunc(data Data, f func() error) error { 140 if f != nil { 141 if err := f(); err != nil { 142 return err 143 } 144 } 145 q.handler(data) 146 return nil 147 } 148 149 // Has always returns false as this queue never does anything 150 func (*Immediate) Has(Data) (bool, error) { 151 return false, nil 152 } 153 154 // Flush always returns nil 155 func (*Immediate) Flush(time.Duration) error { 156 return nil 157 } 158 159 // FlushWithContext always returns nil 160 func (*Immediate) FlushWithContext(context.Context) error { 161 return nil 162 } 163 164 // IsEmpty asserts that the queue is empty 165 func (*Immediate) IsEmpty() bool { 166 return true 167 } 168 169 var queuesMap = map[Type]NewQueueFunc{ 170 DummyQueueType: NewDummyQueue, 171 ImmediateType: NewImmediate, 172 } 173 174 // RegisteredTypes provides the list of requested types of queues 175 func RegisteredTypes() []Type { 176 types := make([]Type, len(queuesMap)) 177 i := 0 178 for key := range queuesMap { 179 types[i] = key 180 i++ 181 } 182 return types 183 } 184 185 // RegisteredTypesAsString provides the list of requested types of queues 186 func RegisteredTypesAsString() []string { 187 types := make([]string, len(queuesMap)) 188 i := 0 189 for key := range queuesMap { 190 types[i] = string(key) 191 i++ 192 } 193 return types 194 } 195 196 // NewQueue takes a queue Type, HandlerFunc, some options and possibly an exemplar and returns a Queue or an error 197 func NewQueue(queueType Type, handlerFunc HandlerFunc, opts, exemplar interface{}) (Queue, error) { 198 newFn, ok := queuesMap[queueType] 199 if !ok { 200 return nil, fmt.Errorf("unsupported queue type: %v", queueType) 201 } 202 return newFn(handlerFunc, opts, exemplar) 203 }