step_build.go (6107B)
1 package middleware 2 3 import ( 4 "context" 5 ) 6 7 // BuildInput provides the input parameters for the BuildMiddleware to consume. 8 // BuildMiddleware may modify the Request value before forwarding the input 9 // along to the next BuildHandler. 10 type BuildInput struct { 11 Request interface{} 12 } 13 14 // BuildOutput provides the result returned by the next BuildHandler. 15 type BuildOutput struct { 16 Result interface{} 17 } 18 19 // BuildHandler provides the interface for the next handler the 20 // BuildMiddleware will call in the middleware chain. 21 type BuildHandler interface { 22 HandleBuild(ctx context.Context, in BuildInput) ( 23 out BuildOutput, metadata Metadata, err error, 24 ) 25 } 26 27 // BuildMiddleware provides the interface for middleware specific to the 28 // serialize step. Delegates to the next BuildHandler for further 29 // processing. 30 type BuildMiddleware interface { 31 // Unique ID for the middleware in theBuildStep. The step does not allow 32 // duplicate IDs. 33 ID() string 34 35 // Invokes the middleware behavior which must delegate to the next handler 36 // for the middleware chain to continue. The method must return a result or 37 // error to its caller. 38 HandleBuild(ctx context.Context, in BuildInput, next BuildHandler) ( 39 out BuildOutput, metadata Metadata, err error, 40 ) 41 } 42 43 // BuildMiddlewareFunc returns a BuildMiddleware with the unique ID provided, 44 // and the func to be invoked. 45 func BuildMiddlewareFunc(id string, fn func(context.Context, BuildInput, BuildHandler) (BuildOutput, Metadata, error)) BuildMiddleware { 46 return buildMiddlewareFunc{ 47 id: id, 48 fn: fn, 49 } 50 } 51 52 type buildMiddlewareFunc struct { 53 // Unique ID for the middleware. 54 id string 55 56 // Middleware function to be called. 57 fn func(context.Context, BuildInput, BuildHandler) (BuildOutput, Metadata, error) 58 } 59 60 // ID returns the unique ID for the middleware. 61 func (s buildMiddlewareFunc) ID() string { return s.id } 62 63 // HandleBuild invokes the middleware Fn. 64 func (s buildMiddlewareFunc) HandleBuild(ctx context.Context, in BuildInput, next BuildHandler) ( 65 out BuildOutput, metadata Metadata, err error, 66 ) { 67 return s.fn(ctx, in, next) 68 } 69 70 var _ BuildMiddleware = (buildMiddlewareFunc{}) 71 72 // BuildStep provides the ordered grouping of BuildMiddleware to be invoked on 73 // a handler. 74 type BuildStep struct { 75 ids *orderedIDs 76 } 77 78 // NewBuildStep returns a BuildStep ready to have middleware for 79 // initialization added to it. 80 func NewBuildStep() *BuildStep { 81 return &BuildStep{ 82 ids: newOrderedIDs(), 83 } 84 } 85 86 var _ Middleware = (*BuildStep)(nil) 87 88 // ID returns the unique name of the step as a middleware. 89 func (s *BuildStep) ID() string { 90 return "Build stack step" 91 } 92 93 // HandleMiddleware invokes the middleware by decorating the next handler 94 // provided. Returns the result of the middleware and handler being invoked. 95 // 96 // Implements Middleware interface. 97 func (s *BuildStep) HandleMiddleware(ctx context.Context, in interface{}, next Handler) ( 98 out interface{}, metadata Metadata, err error, 99 ) { 100 order := s.ids.GetOrder() 101 102 var h BuildHandler = buildWrapHandler{Next: next} 103 for i := len(order) - 1; i >= 0; i-- { 104 h = decoratedBuildHandler{ 105 Next: h, 106 With: order[i].(BuildMiddleware), 107 } 108 } 109 110 sIn := BuildInput{ 111 Request: in, 112 } 113 114 res, metadata, err := h.HandleBuild(ctx, sIn) 115 return res.Result, metadata, err 116 } 117 118 // Get retrieves the middleware identified by id. If the middleware is not present, returns false. 119 func (s *BuildStep) Get(id string) (BuildMiddleware, bool) { 120 get, ok := s.ids.Get(id) 121 if !ok { 122 return nil, false 123 } 124 return get.(BuildMiddleware), ok 125 } 126 127 // Add injects the middleware to the relative position of the middleware group. 128 // Returns an error if the middleware already exists. 129 func (s *BuildStep) Add(m BuildMiddleware, pos RelativePosition) error { 130 return s.ids.Add(m, pos) 131 } 132 133 // Insert injects the middleware relative to an existing middleware id. 134 // Returns an error if the original middleware does not exist, or the middleware 135 // being added already exists. 136 func (s *BuildStep) Insert(m BuildMiddleware, relativeTo string, pos RelativePosition) error { 137 return s.ids.Insert(m, relativeTo, pos) 138 } 139 140 // Swap removes the middleware by id, replacing it with the new middleware. 141 // Returns the middleware removed, or an error if the middleware to be removed 142 // doesn't exist. 143 func (s *BuildStep) Swap(id string, m BuildMiddleware) (BuildMiddleware, error) { 144 removed, err := s.ids.Swap(id, m) 145 if err != nil { 146 return nil, err 147 } 148 149 return removed.(BuildMiddleware), nil 150 } 151 152 // Remove removes the middleware by id. Returns error if the middleware 153 // doesn't exist. 154 func (s *BuildStep) Remove(id string) (BuildMiddleware, error) { 155 removed, err := s.ids.Remove(id) 156 if err != nil { 157 return nil, err 158 } 159 160 return removed.(BuildMiddleware), nil 161 } 162 163 // List returns a list of the middleware in the step. 164 func (s *BuildStep) List() []string { 165 return s.ids.List() 166 } 167 168 // Clear removes all middleware in the step. 169 func (s *BuildStep) Clear() { 170 s.ids.Clear() 171 } 172 173 type buildWrapHandler struct { 174 Next Handler 175 } 176 177 var _ BuildHandler = (*buildWrapHandler)(nil) 178 179 // Implements BuildHandler, converts types and delegates to underlying 180 // generic handler. 181 func (w buildWrapHandler) HandleBuild(ctx context.Context, in BuildInput) ( 182 out BuildOutput, metadata Metadata, err error, 183 ) { 184 res, metadata, err := w.Next.Handle(ctx, in.Request) 185 return BuildOutput{ 186 Result: res, 187 }, metadata, err 188 } 189 190 type decoratedBuildHandler struct { 191 Next BuildHandler 192 With BuildMiddleware 193 } 194 195 var _ BuildHandler = (*decoratedBuildHandler)(nil) 196 197 func (h decoratedBuildHandler) HandleBuild(ctx context.Context, in BuildInput) ( 198 out BuildOutput, metadata Metadata, err error, 199 ) { 200 return h.With.HandleBuild(ctx, in, h.Next) 201 } 202 203 // BuildHandlerFunc provides a wrapper around a function to be used as a build middleware handler. 204 type BuildHandlerFunc func(context.Context, BuildInput) (BuildOutput, Metadata, error) 205 206 // HandleBuild invokes the wrapped function with the provided arguments. 207 func (b BuildHandlerFunc) HandleBuild(ctx context.Context, in BuildInput) (BuildOutput, Metadata, error) { 208 return b(ctx, in) 209 } 210 211 var _ BuildHandler = BuildHandlerFunc(nil)