github.com/prebid/prebid-server/v2@v2.18.0/hooks/repo.go (about)

     1  package hooks
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/prebid/prebid-server/v2/hooks/hookstage"
     7  )
     8  
     9  // HookRepository is the interface that exposes methods
    10  // that return instance of the certain hook interface.
    11  //
    12  // Each method accepts hook ID and returns hook interface
    13  // registered under this ID and true if hook found
    14  // otherwise nil value returned with the false,
    15  // indicating not found hook for this ID.
    16  type HookRepository interface {
    17  	GetEntrypointHook(id string) (hookstage.Entrypoint, bool)
    18  	GetRawAuctionHook(id string) (hookstage.RawAuctionRequest, bool)
    19  	GetProcessedAuctionHook(id string) (hookstage.ProcessedAuctionRequest, bool)
    20  	GetBidderRequestHook(id string) (hookstage.BidderRequest, bool)
    21  	GetRawBidderResponseHook(id string) (hookstage.RawBidderResponse, bool)
    22  	GetAllProcessedBidResponsesHook(id string) (hookstage.AllProcessedBidResponses, bool)
    23  	GetAuctionResponseHook(id string) (hookstage.AuctionResponse, bool)
    24  }
    25  
    26  // NewHookRepository returns a new instance of the HookRepository interface.
    27  //
    28  // The hooks argument represents a mapping of hook IDs to types
    29  // implementing at least one of the available hook interfaces, see [hookstage] pkg.
    30  //
    31  // Error returned if provided interface doesn't implement any hook interface
    32  // or hook with same ID already exists.
    33  func NewHookRepository(hooks map[string]interface{}) (HookRepository, error) {
    34  	repo := new(hookRepository)
    35  	for id, hook := range hooks {
    36  		if err := repo.add(id, hook); err != nil {
    37  			return nil, err
    38  		}
    39  	}
    40  
    41  	return repo, nil
    42  }
    43  
    44  type hookRepository struct {
    45  	entrypointHooks              map[string]hookstage.Entrypoint
    46  	rawAuctionHooks              map[string]hookstage.RawAuctionRequest
    47  	processedAuctionHooks        map[string]hookstage.ProcessedAuctionRequest
    48  	bidderRequestHooks           map[string]hookstage.BidderRequest
    49  	rawBidderResponseHooks       map[string]hookstage.RawBidderResponse
    50  	allProcessedBidResponseHooks map[string]hookstage.AllProcessedBidResponses
    51  	auctionResponseHooks         map[string]hookstage.AuctionResponse
    52  }
    53  
    54  func (r *hookRepository) GetEntrypointHook(id string) (hookstage.Entrypoint, bool) {
    55  	return getHook(r.entrypointHooks, id)
    56  }
    57  
    58  func (r *hookRepository) GetRawAuctionHook(id string) (hookstage.RawAuctionRequest, bool) {
    59  	return getHook(r.rawAuctionHooks, id)
    60  }
    61  
    62  func (r *hookRepository) GetProcessedAuctionHook(id string) (hookstage.ProcessedAuctionRequest, bool) {
    63  	return getHook(r.processedAuctionHooks, id)
    64  }
    65  
    66  func (r *hookRepository) GetBidderRequestHook(id string) (hookstage.BidderRequest, bool) {
    67  	return getHook(r.bidderRequestHooks, id)
    68  }
    69  
    70  func (r *hookRepository) GetRawBidderResponseHook(id string) (hookstage.RawBidderResponse, bool) {
    71  	return getHook(r.rawBidderResponseHooks, id)
    72  }
    73  
    74  func (r *hookRepository) GetAllProcessedBidResponsesHook(id string) (hookstage.AllProcessedBidResponses, bool) {
    75  	return getHook(r.allProcessedBidResponseHooks, id)
    76  }
    77  
    78  func (r *hookRepository) GetAuctionResponseHook(id string) (hookstage.AuctionResponse, bool) {
    79  	return getHook(r.auctionResponseHooks, id)
    80  }
    81  
    82  func (r *hookRepository) add(id string, hook interface{}) error {
    83  	var hasAnyHooks bool
    84  	var err error
    85  
    86  	if h, ok := hook.(hookstage.Entrypoint); ok {
    87  		hasAnyHooks = true
    88  		if r.entrypointHooks, err = addHook(r.entrypointHooks, h, id); err != nil {
    89  			return err
    90  		}
    91  	}
    92  
    93  	if h, ok := hook.(hookstage.RawAuctionRequest); ok {
    94  		hasAnyHooks = true
    95  		if r.rawAuctionHooks, err = addHook(r.rawAuctionHooks, h, id); err != nil {
    96  			return err
    97  		}
    98  	}
    99  
   100  	if h, ok := hook.(hookstage.ProcessedAuctionRequest); ok {
   101  		hasAnyHooks = true
   102  		if r.processedAuctionHooks, err = addHook(r.processedAuctionHooks, h, id); err != nil {
   103  			return err
   104  		}
   105  	}
   106  
   107  	if h, ok := hook.(hookstage.BidderRequest); ok {
   108  		hasAnyHooks = true
   109  		if r.bidderRequestHooks, err = addHook(r.bidderRequestHooks, h, id); err != nil {
   110  			return err
   111  		}
   112  	}
   113  
   114  	if h, ok := hook.(hookstage.RawBidderResponse); ok {
   115  		hasAnyHooks = true
   116  		if r.rawBidderResponseHooks, err = addHook(r.rawBidderResponseHooks, h, id); err != nil {
   117  			return err
   118  		}
   119  	}
   120  
   121  	if h, ok := hook.(hookstage.AllProcessedBidResponses); ok {
   122  		hasAnyHooks = true
   123  		if r.allProcessedBidResponseHooks, err = addHook(r.allProcessedBidResponseHooks, h, id); err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	if h, ok := hook.(hookstage.AuctionResponse); ok {
   129  		hasAnyHooks = true
   130  		if r.auctionResponseHooks, err = addHook(r.auctionResponseHooks, h, id); err != nil {
   131  			return err
   132  		}
   133  	}
   134  
   135  	if !hasAnyHooks {
   136  		return fmt.Errorf(`hook "%s" does not implement any supported hook interface`, id)
   137  	}
   138  
   139  	return nil
   140  }
   141  
   142  func getHook[T any](hooks map[string]T, id string) (T, bool) {
   143  	hook, ok := hooks[id]
   144  	return hook, ok
   145  }
   146  
   147  func addHook[T any](hooks map[string]T, hook T, id string) (map[string]T, error) {
   148  	if hooks == nil {
   149  		hooks = make(map[string]T)
   150  	}
   151  
   152  	if _, ok := hooks[id]; ok {
   153  		return nil, fmt.Errorf(`hook of type "%T" with id "%s" already registered`, new(T), id)
   154  	}
   155  
   156  	hooks[id] = hook
   157  
   158  	return hooks, nil
   159  }