github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/contract.go (about)

     1  package kit
     2  
     3  // RouteSelector holds information about how this Contract is going to be selected. Each
     4  // Gateway may need different information to route the request to the right Contract.
     5  // RouteSelector is actually a base interface and Gateway implementors usually implement
     6  // either RESTRouteSelector, RPCRouteSelector or both. It is an interface that provides methods
     7  // for querying and getting the encoding of a routing object. Implementations of RouteSelector are
     8  // used by Gateway to handle different types of request routing based on the method and protocol. The
     9  // Query method is for searching specific routes with a query string, and GetEncoding is for
    10  // returning the encoding format required for communication between the gateway and the target contract.
    11  type RouteSelector interface {
    12  	Query(q string) any
    13  	GetEncoding() Encoding
    14  }
    15  
    16  // RESTRouteSelector is an interface that extends RouteSelector with methods specific to REST operations,
    17  // primarily used by REST-based gateways. With GetMethod and GetPath methods, this interface provides
    18  // the HTTP method and path information necessary for routing REST requests to the appropriate contract.
    19  // Implementations of this interface are expected to provide their own GetMethod and GetPath methods that
    20  // return the desired method and path as strings.
    21  type RESTRouteSelector interface {
    22  	RouteSelector
    23  	GetMethod() string
    24  	GetPath() string
    25  }
    26  
    27  // RPCRouteSelector defines the RouteSelector which could be used in RPC operations.
    28  // Gateway implementation which handle RPC requests could check the selector if it supports RPC.
    29  // It is an interface that extends RouteSelector with a method specific to RPC operations. It is primarily
    30  // used by RPC-based gateways for routing RPC requests to the appropriate contract. Implementations of this
    31  // interface should provide their own GetPredicate method, which returns a string representing a predicate
    32  // used to evaluate the route. In this context, a predicate is a condition or criteria that helps in
    33  // selecting the proper handler for the RPC request.
    34  type RPCRouteSelector interface {
    35  	RouteSelector
    36  	GetPredicate() string
    37  }
    38  
    39  // EdgeSelectorFunc returns the target EdgeServer's ID in the Cluster. If you have
    40  // multiple instances of the EdgeServer, and you want to forward some requests to a specific
    41  // instance, you can set up this function in desc.Contract's SetCoordinator method, then, the
    42  // receiving EdgeServer will detect the target instance by calling this function and forwards
    43  // the request to the returned instance.
    44  // From the external client point of view this forwarding request is not observable.
    45  type EdgeSelectorFunc func(ctx *LimitedContext) (string, error)
    46  
    47  // Contract defines the set of Handlers based on the Query. Query is different per bundles,
    48  // hence, this is the implementor's task to make sure return correct value based on 'q'.
    49  // In other words, Contract 'r' must return valid response for 'q's required by Gateway 'gw' in
    50  // order to be usable by Gateway 'gw' otherwise it panics.
    51  type Contract interface {
    52  	// ID identifies the contract. This MUST be unique per Service. This MUST NOT be a runtime
    53  	// random number. Since this is used in RemoteExecute method of ClusterMember to execute the
    54  	// right set of handlers on remote EdgeServer.
    55  	ID() string
    56  	// RouteSelector returns a RouteSelector function which selects this Contract based on the
    57  	// client requests.
    58  	RouteSelector() RouteSelector
    59  	// EdgeSelector returns an EdgeSelectorFunc function which selects the EdgeServer instance
    60  	// that the request should forward to for execution.
    61  	EdgeSelector() EdgeSelectorFunc
    62  	Encoding() Encoding
    63  	Input() Message
    64  	Output() Message
    65  	Handlers() []HandlerFunc
    66  	Modifiers() []ModifierFunc
    67  }
    68  
    69  // ContractWrapper is like an interceptor which can add Pre- and Post- handlers to all
    70  // the Contracts of the Contract.
    71  type ContractWrapper interface {
    72  	Wrap(c Contract) Contract
    73  }
    74  
    75  // ContractWrapperFunc implements ContractWrapper interface.
    76  type ContractWrapperFunc func(Contract) Contract
    77  
    78  func (sw ContractWrapperFunc) Wrap(svc Contract) Contract {
    79  	return sw(svc)
    80  }
    81  
    82  // WrapContract wraps a contract, this is useful for adding middlewares to the contract.
    83  // Some middlewares like OpenTelemetry, Logger, ... could be added to the contract using
    84  // this function.
    85  func WrapContract(c Contract, wrappers ...ContractWrapper) Contract {
    86  	for _, w := range wrappers {
    87  		c = w.Wrap(c)
    88  	}
    89  
    90  	return c
    91  }
    92  
    93  // contractWrap implements Contract interface and is useful when we need to wrap another
    94  // contract.
    95  type contractWrap struct {
    96  	Contract
    97  	h     []HandlerFunc
    98  	preM  []ModifierFunc
    99  	postM []ModifierFunc
   100  }
   101  
   102  var _ Contract = (*contractWrap)(nil)
   103  
   104  func (c contractWrap) Handlers() []HandlerFunc {
   105  	h := make([]HandlerFunc, 0, len(c.h)+len(c.Contract.Handlers()))
   106  	h = append(h, c.h...)
   107  	h = append(h, c.Contract.Handlers()...)
   108  
   109  	return h
   110  }
   111  
   112  func (c contractWrap) Modifiers() []ModifierFunc {
   113  	m := make([]ModifierFunc, 0, len(c.preM)+len(c.postM)+len(c.Contract.Modifiers()))
   114  	m = append(m, c.preM...)
   115  	m = append(m, c.Contract.Modifiers()...)
   116  	m = append(m, c.postM...)
   117  
   118  	return m
   119  }