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  }