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 }